view clojure/com/aurellem/assembly.clj @ 138:2b69cbe8a5b9

saving progress on state machine; 240 ops -> 90 ops (provided it withstands debugging)
author Dylan Holmes <ocsenave@gmail.com>
date Mon, 19 Mar 2012 03:05:42 -0500
parents 1c58fa3cfc68
children 74ec1ac044bb
line wrap: on
line source
1 (ns com.aurellem.assembly
2 (:use (com.aurellem gb-driver vbm title items))
3 (:import [com.aurellem.gb_driver SaveState]))
5 (defn mid-game []
6 (read-state "mid-game"))
8 (defn inject-assembly
9 ([^SaveState state
10 program-counter registers
11 assembly-code]
12 (let [scratch-memory (memory state)]
13 ;; inject assembly code
14 (dorun (map (fn [index val]
15 (aset scratch-memory index val))
16 (range program-counter
17 (+ program-counter (count assembly-code)))
18 assembly-code))
19 (-> state
20 (write-memory! scratch-memory)
21 (write-registers! registers)
22 (PC! program-counter)))))
24 (defn inject-item-assembly
25 ([^SaveState state assembly-code]
26 (inject-assembly state (inc item-list-start)
27 (registers state)
28 assembly-code))
29 ([assembly-code]
30 (inject-item-assembly @current-state assembly-code)))
32 (defn info
33 ([^SaveState state]
34 (println (format "PC: 0x%04X" (PC state)))
35 (println "Instruction:"
36 (format "0x%02X" (aget (memory state) (PC state))))
37 state))
39 (defn print-interrupt
40 [^SaveState state]
41 (println (format "IE: %d" (IE state)))
42 state)
44 (defn print-listing [state begin end]
45 (dorun (map
46 (fn [opcode line]
47 (println (format "0x%04X: 0x%02X" line opcode)))
48 (subvec (vec (memory state)) begin end)
49 (range begin end)))
50 state)
52 (defn run-assembly
53 ([info-fn assembly n]
54 (let [final-state
55 (reduce (fn [state _]
56 (tick (info-fn state)))
57 (inject-item-assembly
58 (mid-game) assembly)
59 (range n))]
60 final-state))
61 ([assembly n]
62 (run-assembly info assembly n)))
64 (def buttons-port 0xFF00)
66 (defn A [state]
67 (bit-shift-right (bit-and 0x0000FF00 (AF state)) 8))
69 (defn B [state]
70 (bit-shift-right (bit-and 0x0000FF00 (BC state)) 8))
72 (defn C [state]
73 (bit-and 0xFF (BC state)))
75 (defn binary-str [num]
76 (format "%08d"
77 (Integer/parseInt
78 (Integer/toBinaryString num) 10)))
80 (defn view-register [state name reg-fn]
81 (println (format "%s: %s" name
82 (binary-str (reg-fn state))))
83 state)
85 (defn view-memory [state mem]
86 (println (format "mem 0x%04X = %s" mem
87 (binary-str (aget (memory state) mem))))
88 state)
90 (defn trace [state]
91 (loop [program-counters [(first (registers @current-state)) ]
92 opcodes [(aget (memory @current-state) (PC @current-state))]]
93 (let [frame-boundary?
94 (com.aurellem.gb.Gb/tick)]
95 (if frame-boundary?
96 [program-counters opcodes]
97 (recur
98 (conj program-counters
99 (first (registers @current-state)))
100 (conj opcodes
101 (aget (memory @current-state)
102 (PC @current-state))))))))
104 (defn print-trace [state n]
105 (let [[program-counters opcodes] (trace state)]
106 (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op)))
107 (take n program-counters)
108 (take n opcodes)))))
110 (defn good-trace []
111 (-> (mid-game) (tick) (IE! 0)
112 (set-inv-mem [0x00 0x00 0X00 0x00])
113 (PC! item-list-start)(print-interrupt)
114 (info) (tick) (info) (tick) (info)))
116 (defn read-down-button []
117 (-> (tick (mid-game))
118 (IE! 0) ; disable interrupts
119 (inject-item-assembly
120 ;; write 00010000 to 0xFF00 to select joypad
121 [0x18 ;D31D ; jump over
122 0x01 ;D31E ; the next 8 bits
123 ;D31F
124 (Integer/parseInt "00100000" 2) ; data section
126 0xFA ;D320 ; load (D31F) into A
127 0x1F ;D321 -->
128 0xD3 ;D322 --> D31F
130 0xEA ;D323 ; load (A), which is
131 0x00 ;D324 --> ; 00010000, into FF00
132 0xFF ;D325 --> FF00
134 0x18 ;D326 ; this is the place where
135 0x01 ;D327 ; we will store whether
136 0x00 ;D328 ; "down" is pressed.
138 0xFA ;D329 ; (FF00) -> A
139 0x00 ;D32A
140 0xFF ;D32B
142 0xCB ;D32C ; Test whether "down"
143 0x5F ;D32D ; is pressed.
145 0x28 ;D32E ; if down is pressed,
146 0x03 ;D32F ; skip the next section
147 ; of code.
148 ;; down-is-not-pressed
149 0xC3 ;D330
150 0x1D ;D331 ; return to beginning
151 0xD3 ;D332
153 ;; down-is-pressed
154 0xEA ;D334 ; write A to D328 if
155 0x28 ;D335 ; "down" was pressed
156 0xD3 ;D336
158 0xC3 ;D330
159 0x1D ;D331 ; return to beginning
160 0xD3 ;D332
161 ])))
163 (defn test-read-down []
164 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
165 (view-memory (step (step (read-down-button))) 0xD328)))
167 (defn count-frames []
168 (-> (tick (mid-game))
169 (IE! 0) ; disable interrupts
170 (inject-item-assembly
171 [0x18 ;D31D ; jump over
172 0x02 ;D31E ; the next 2 bytes
173 0x00 ;D31F ; frame-count
174 0x00 ;D320 ; v-blank-prev
176 0xFA ;D321
177 0x41 ;D322 ; load (FF41) into A
178 0xFF ;D323 ; this contains mode flags
180 ;; if we're in v-blank, the bit-1 is 0
181 ;; and bit-2 is 1 Otherwise, it is not v-blank.
182 0xCB ;D324 ; test bit-1 of A
183 0x4F ;D325
185 0xC2 ;D326 ; if bit-1 is not 0
186 0x44 ;D327 ; GOTO not-v-blank
187 0xD3 ;D328
189 0xCB ;D329 ; test bit-0 of A
190 0x47 ;D32A
192 0xCA ;D32B ; if bit-0 is not 1
193 0x44 ;D32C ; GOTO not-v-blank
194 0xD3 ;D32D
195 ;;; in v-blank mode
196 ;; if v-blank-prev was 0,
197 ;; increment frame-count
199 0xFA ;D32E ; load v-blank-prev to A
200 0x20 ;D32F
201 0xD3 ;D330
203 0xCB ;D331
204 0x47 ;D332 ; test bit-0 of A
206 0x20 ;D333 ; skip next section
207 0x07 ;D334 ; if v-blank-prev was not zero
209 ;; v-blank was 0, increment frame-count
210 0xFA ;D335 ; load frame-count into A
211 0x1F ;D336
212 0xD3 ;D337
214 0x3C ;D338 ; inc A
216 0xEA ;D339 ; load A into frame-count
217 0x1F ;D33A
218 0xD3 ;D33B
220 ;; set v-blank-prev to 1
221 0x3E ;D33C ; load 1 into A
222 0x01 ;D33D
224 0xEA ;D33E ; load A into v-blank-prev
225 0x20 ;D33F
226 0xD3 ;D340
228 0xC3 ;D341 ; return to beginning
229 0x1D ;D342
230 0xD3 ;D343
232 ;;; not in v-blank mode
233 ;; set v-blank-prev to 0
234 0x3E ;D344 ; load 0 into A
235 0x00 ;D345
237 0xEA ;D346 ; load A into v-blank-prev
238 0x20 ;D347
239 0xD3 ;D348
241 0xC3 ;D349 ; return to beginning
242 0x1D ;D34A
243 0xD3 ;D34B
244 ])))
246 (defn step-count-frames []
247 (-> (read-down-button)
248 (info)
249 (tick) ;; skip over data section
250 (info)
251 (view-register "Register A" A)
252 (tick) ;; load-data into A
253 (view-register "Register A" A)
254 (info)
255 (view-memory 0xFF00)
256 (tick) ;; load A into 0xFF00
257 (view-memory 0xFF00)
258 (info)
259 (tick)
260 (info)
261 (tick)
262 (info)
263 (tick)
264 (info)
265 (tick)
266 (info)
267 (tick)
268 (info)
269 (tick)
270 (print-inventory)))
272 (defn test-count-frames []
273 (= 255 (aget (memory ((apply comp (repeat 255 step))
274 (count-frames)))
275 0xD31F)))
277 ;; specs for main bootstrap program
278 ;; starts in "mode-select" mode
279 ;; Each button press takes place in a single frame.
280 ;; mode-select-mode takes one of the main buttons
281 ;; which selects one of up to eight modes
282 ;; mode 1 activated by the "A" button
283 ;; the next two button presses indicates the start
284 ;; memory location which to which the bootstrap
285 ;; program will write.
286 ;; This is done by using each of the eight buttons to
287 ;; spell out an 8 bit number. The order of buttons is
288 ;; [:d :u :l :r :start :select :b :a]
289 ;; [:a :start :l] --> 00101001
291 ;; the next button press determines how many bytes are to be
292 ;; written, starting at the start position.
294 ;; then, the actual bytes are entered and are written to the
295 ;; start address in sequence.
297 (defn input-number-assembly []
298 [0x18 ;D31D ; jump over
299 0x02 ;D31E ; the next 2 bytes
300 0x00 ;D31F ; frame-count
301 0x00 ;D320 ; v-blank-prev
303 0xFA ;D321
304 0x41 ;D322 ; load (FF41) into A
305 0xFF ;D323 ; this contains mode flags
307 ;; if we're in v-blank, the bit-1 is 0
308 ;; and bit-2 is 1 Otherwise, it is not v-blank.
309 0xCB ;D324 ; test bit-1 of A
310 0x4F ;D325
312 0xC2 ;D326 ; if bit-1 is not 0
313 0x44 ;D327 ; GOTO not-v-blank
314 0xD3 ;D328
316 0xCB ;D329 ; test bit-0 of A
317 0x47 ;D32A
319 0xCA ;D32B ; if bit-0 is not 1
320 0x44 ;D32C ; GOTO not-v-blank
321 0xD3 ;D32D
323 ;;; in v-blank mode
325 ;; if v-blank-prev was 0,
326 ;; increment frame-count
328 0xFA ;D32E ; load v-blank-prev to A
329 0x20 ;D32F
330 0xD3 ;D330
332 0xCB ;D331
333 0x47 ;D332 ; test bit-0 of A
335 0x20 ;D333 ; skip next section
336 0x07 ;D334 ; if v-blank-prev was not zero
338 ;; v-blank was 0, increment frame-count
339 0xFA ;D335 ; load frame-count into A
340 0x1F ;D336
341 0xD3 ;D337
343 0x3C ;D338 ; inc A
345 0xEA ;D339 ; load A into frame-count
346 0x1F ;D33A
347 0xD3 ;D33B
349 ;; set v-blank-prev to 1
350 0x3E ;D33C ; load 1 into A
351 0x01 ;D33D
353 0xEA ;D33E ; load A into v-blank-prev
354 0x20 ;D33F
355 0xD3 ;D340
357 0xC3 ;D341 ; GOTO input handling code
358 0x4E ;D342
359 0xD3 ;D343
361 ;;; not in v-blank mode
362 ;; set v-blank-prev to 0
363 0x3E ;D344 ; load 0 into A
364 0x00 ;D345
366 0xEA ;D346 ; load A into v-blank-prev
367 0x20 ;D347
368 0xD3 ;D348
370 0xC3 ;D349 ; return to beginning
371 0x1D ;D34A
372 0xD3 ;D34B
374 0x00 ;D34C ; these are here
375 0x00 ;D34D ; for glue
378 ;;; calculate input number based on button presses
379 0x18 ;D34E ; skip next 3 bytes
380 0x03 ;D34F
381 ;D350
382 (Integer/parseInt "00100000" 2) ; select directional pad
383 ;D351
384 (Integer/parseInt "00010000" 2) ; select buttons
385 0x00 ;D352 ; input-number
387 ;; select directional pad, store low bits in B
389 0xFA ;D353 ; load (D350) into A
390 0x50 ;D354 -->
391 0xD3 ;D355 --> D31F
393 0xEA ;D356 ; load A, which is
394 0x00 ;D357 --> ; 00010000, into FF00
395 0xFF ;D358 --> FF00
397 0x06 ;D359
398 ;D35A
399 (Integer/parseInt "11110000" 2) ; "11110000" -> B
400 0xFA ;D35B ; (FF00) -> A
401 0x00 ;D35C
402 0xFF ;D35D
404 0xCB ;D35E ; swap nybbles on A
405 0x37 ;D35F
406 0xA0 ;D360 ; (AND A B) -> A
407 0x47 ;D361 ; A -> B
409 ;; select buttons store bottom bits in C
411 0xFA ; ; load (D351) into A
412 0x51 ; -->
413 0xD3 ; --> D31F
415 0xEA ; ; load (A), which is
416 0x00 ; --> ; 00001000, into FF00
417 0xFF ; --> FF00
419 0x0E ;
420 (Integer/parseInt "00001111" 2) ; "00001111" -> C
422 0xFA ; ; (FF00) -> A
423 0x00 ;
424 0xFF ;
426 0xA1 ; ; (AND A C) -> A
427 0x4F ; ; A -> C
429 ;; combine the B and C registers into the input number
430 0x79 ; ; C -> A
431 0xB0 ; ; (OR A B) -> A
432 0x2F ; ; negate A
434 0xEA ; ; store A into input-number
435 0x52 ;
436 0xD3 ;
438 0xC3 ; ; return to beginning
439 0x1D ;
440 0xD3 ;
441 ])
444 (defn print-pc [state]
445 (println (format "PC: 0x%04X" (PC state)))
446 state)
448 (defn print-op [state]
449 (println (format "OP: 0x%02X" (aget (memory state) (PC state))))
450 state)
452 (defn d-tick
453 ([state]
454 (-> state print-pc print-op tick)))
456 (defn input-number []
457 (-> (tick (mid-game))
458 (IE! 0) ; disable interrupts
459 (inject-item-assembly (input-number-assembly))))
461 (defn test-input-number
462 "Input freestyle buttons and observe the effects at the repl."
463 []
464 (set-state! (input-number))
465 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))
495 (defn write-memory-assembly*
496 "Currently, grabs input from the user each frame."
497 []
498 [
499 ;; --------- FRAME METRONOME
500 0x18 ;; jump ahead to cleanup. first time only.
501 0x40 ;; v-blank-prev [D31E]
503 0xFA ;; load modes into A [D31F]
504 0x41
505 0xFF
507 0x47 ;; A -> B
508 0xCB ;; rotate A
509 0x2F
510 0x2F ;; invert A
512 0xA0
513 0x47 ;; now B_0 contains (VB==1)
515 0xFA ;; load v-blank-prev
516 0x1E
517 0xD3
519 0x2F ;; complement v-blank-prev
521 0xA0 ;; A & B --> A
522 0x4F ;; now C_0 contains increment?
525 0x78 ;; B->A
526 0xEA ;; spit A --> vbprev
527 0x1E
528 0xD3
530 0xCB ;test C_0
531 0x41
532 0x20 ; JUMP ahead to button input if nonzero
533 0x02
534 0x18 ; JUMP back to frame metronome (D31F)
535 0xE6 ; todo: verify this jump length
537 ;; -------- GET BUTTON INPUT
539 ;; btw, C_0 is now 1
540 ;; prepare to select bits
542 0x06 ;; load 0x00 into B
543 0x00 ;; to initialize for "OR" loop
545 0x3E ;; load 0x20 into A, to measure dpad
546 0x20
549 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]
550 0x00
552 0xF0 ;; load A from [FF00]
553 0x00
555 0xE6 ;; bitmask 00001111
556 0x0F
558 0xB0 ;; A or B --> A
559 0xCB
560 0x41 ;; test bit 0 of C
561 0x28 ;; JUMP forward if 0
562 0x08
564 0x47 ;; A -> B
565 0xCB ;; swap B nybbles
566 0x30
567 0x0C ;; increment C
568 0x3E ;; load 0x10 into A, to measure btns
569 0x10
570 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]
571 0xED
574 ;; ------ TAKE ACTION BASED ON USER INPUT
576 ;; mode 0x00 : select mode
577 ;; mode 0x08 : select bytes-to-write
578 ;; mode 0x10 : select hi-bit
579 ;; mode 0x18 : select lo-bit
581 ;; mode 0xF0 : write bytes
582 ;; mode 0xFF : jump PC
585 ;; registers
586 ;; D : mode select
587 ;; E : count of bytes to write
588 ;; H : address-high
589 ;; L : address-low
591 ;; now A contains the pressed keys
592 0x2F ; complement A, by request. [D34F]
594 0x47 ; A->B ;; now B contains the pressed keys
595 0x7B ; E->A ;; now A contains the count.
597 0xCB ; test bit 4 of D (are we in o/p mode?)
598 0x26
599 0x28 ; if test == 0, skip this o/p section
600 0x13 ; JUMP
602 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)
603 0x42
604 0x28 ; if test == 0, skip the following command
605 0x01
607 ;; output mode I: moving the program counter
608 0xE9 ; ** move PC to (HL)
610 ;; output mode II: writing bytes
611 0xFE ; A compare 0. finished writing?
612 0x00
613 0x28 ; if we are not finished, skip cleanup
614 0x04 ; JUMP
616 ;; CLEANUP
617 ;; btw, A is already zero.
618 0xAF ; zero A [D35F]
619 0x57 ; A->D; makes D=0.
620 0x18 ; end of frame
621 0xBC
623 ;; ---- end of cleanup
626 ;; continue writing bytes
627 0x1D ;; decrement E, the number of bytes to write
628 0x78 ;; B->A; now A contains the pressed keys
629 0x77 ;; copy A to (HL)
630 0x23 ;; increment HL
631 0x18 ;; end frame.
632 0xC2 ;; TODO: set skip length backwards
635 ;; ---- end of o/p section
637 ;; get data
638 0x3E ;; load the constant 57 into A. [D369]
639 0x57
640 0x82 ;; add the mode to A
641 0xEA ;; store A into "thing to execute"
642 0x74
643 0xD3
645 0x3E ;; load the constant 8 into A
646 0x08
647 0x82 ;; add the mode to A
648 0x57 ;; store the incremented mode into D
649 0x78 ;; B->A; now A contains the pressed keys
651 0x00 ;; var: thing to execute [D374]
653 0x18 ;; end frame
654 0xA8 ;; JUMP
655 ]
656 )
658 (defn write-mem-dyl []
659 (-> (tick (mid-game))
660 (IE! 0)
661 (inject-item-assembly (write-memory-assembly*))))
664 (defn dylan* []
665 (->
666 (write-mem-dyl)
668 (tick)
669 (tick)
670 (tick)
671 (tick)
672 (tick)
673 (tick)
674 (tick)
675 (tick)
676 (tick)
677 (tick)
678 (tick)
679 (tick)
680 (tick)
681 (tick)
682 (tick)
683 (tick)
684 (tick)
685 (tick)
686 (tick)
687 (tick)
688 (tick)
689 (tick)
690 (tick)
691 (tick)
692 (tick)
693 (tick)
694 (tick)
695 (tick)
696 (tick)
697 (tick)
698 (tick)
699 (tick)
700 (tick)
701 (tick)
702 (tick)
703 (tick)
705 ;;(view-memory 0xD374)
706 (tick)
707 (tick)
708 (tick)
709 (tick)
710 (tick)
711 (tick)
712 (tick)
713 (tick)
714 (tick)
715 (tick)
716 (tick)
717 (tick)
718 (tick)
719 (tick)
720 (tick)
721 ;;(view-memory 0xD374)
722 (d-tick)
724 (view-register "A" A)
725 (view-register "B" B)
726 (view-register "C" C))
728 )
731 (defn dylan []
732 (->
733 (write-mem-dyl)
734 (tick)
735 (tick)
736 (tick)
737 (tick)
738 (tick)
739 (tick)
740 (tick)
741 (tick)
742 (tick)
743 (tick)
744 (tick)
745 (tick)
746 (tick)
747 (tick)
748 (tick) ;; first loop
751 (tick)
752 (tick)
753 (tick)
754 (tick)
755 (tick)
756 (tick)
757 (tick)
758 (tick)
759 (tick)
760 (tick)
761 (tick)
762 (tick)
763 (tick) ;; dpad bits
765 (tick)
766 (tick)
767 (tick)
768 (tick)
769 (tick)
770 (tick)
771 (tick)
772 (tick)
773 (d-tick)
777 (view-register "A" A)
778 (view-register "B" B)
779 (view-register "C" C)
781 ))
786 (defn d2 []
787 (->
788 (write-mem-dyl)
789 (view-memory 0xD31F)
790 step step step step step
791 (view-memory 0xD31F)))
812 (defn write-memory-assembly []
813 [
814 ;; Main Timing Loop
815 ;; Constantly check for v-blank and Trigger main state machine on
816 ;; every transtion from v-blank to non-v-blank.
818 0x18 ; D31D ; Variable declaration
819 0x02 ; D31E
820 0x00 ; D31F ; frame-count
821 0x00 ; D320 ; v-blank-prev
823 0xF0 ; D321 ; load v-blank mode flags into A
824 0x41
825 0x00
828 ;; Branch dependent on v-blank. v-blank happens when the last two
829 ;; bits in A are "01"
830 0xCB ; D324
831 0x4F ; D325
833 0xC2 ; D326 ; if bit-1 is not 0, then
834 0x3E ; D327 ; GOTO non-v-blank.
835 0xD3 ; D328
837 0xCB ; D329
838 0x47 ; D32A
840 0xCA ; D32B ; if bit-0 is not 1, then
841 0x3E ; D32C ; GOTO non-v-blank.
842 0xD3 ; D32D
844 ;; V-Blank
845 ;; Activate state-machine if this is a transition event.
847 0xFA ; D32E ; load v-bank-prev into A
848 0x20 ; D32F
849 0xD3 ; D330
851 0xFE ; D331 ; compare A to 0. >--------\
852 0x00 ; D332 \
853 ; |
854 ;; set v-blank-prev to 1. |
855 0x3E ; D333 ; load 1 into A. |
856 0x01 ; D334 |
857 ; |
858 0xEA ; D335 ; load A into v-blank-prev |
859 0x20 ; D336 |
860 0xD3 ; D337 |
861 ; /
862 ;; if v-blank-prev was 0, activate state-machine <------/
863 0xCA ; D338 ; if v-blank-prev
864 0x46 ; D339 ; was 0,
865 0xD3 ; D33A ; GOTO state-machine
867 0xC3 ; D33B
868 0x1D ; D33C
869 0xD3 ; D33D ; GOTO beginning
870 ;; END V-blank
872 ;; Non-V-Blank
873 ;; Set v-blank-prev to 0
874 0x3E ; D33E ; load 0 into A
875 0x00 ; D33F
877 0xEA ; D340 ; load A into v-blank-prev
878 0x20 ; D341
879 0xD3 ; D342
881 0xC3 ; D343
882 0x1D ; D344
883 0xD3 ; D345 ; GOTO beginning
884 ;; END Not-V-Blank
887 ;; Main State Machine -- Input Section
888 ;; This is called once every frame.
889 ;; It collects input and uses it to drive the
890 ;; state transitions.
892 ;; Increment frame-count
893 0xFA ; D346 ; load frame-count into A
894 0x1F ; D347
895 0xD3 ; D348
897 0x3C ; D349 ; inc A
899 0xEA ; D34A
900 0x1F ; D34B ; load A into frame-count
901 0xD3 ; D34C
903 0x00 ; D34D ; glue :)
905 0x18 ;D34E ; skip next 3 bytes
906 0x03 ;D34F
907 ;D350
908 (Integer/parseInt "00100000" 2) ; select directional pad
909 ;D351
910 (Integer/parseInt "00010000" 2) ; select buttons
911 0x00 ;D352 ; input-number
913 ;; select directional pad; store low bits in B
915 0xFA ;D353 ; load (D350) into A
916 0x50 ;D354 -->
917 0xD3 ;D355 --> D350
919 0xE0 ;D356 ; load (A), which is
920 0x00 ;D357 --> ; 00010000, into FF00
921 0x00 ;D358 --> FF00 ;; NO-OP
923 0x06 ;D359
924 ;D35A
925 (Integer/parseInt "11110000" 2) ; "11110000" -> B
926 0xF0 ;D35B ; (FF00) -> A
927 0x00 ;D35C
928 0x00 ;D35D ;; NO-OP
930 0xCB ;D35E ; swap nybbles on A
931 0x37 ;D35F
932 0xA0 ;D360 ; (AND A B) -> A
933 0x47 ;D361 ; A -> B
935 ;; select buttons; store bottom bits in C
937 0xFA ;D362 ; load (D351) into A
938 0x51 ;D363 -->
939 0xD3 ;D364 --> D351
941 0xE0 ;D365 ; load (A), which is
942 0x00 ;D366 --> ; 00001000, into FF00
943 0x00 ;D367 --> FF00 ;; NO-OP
945 0x0E ;D368
946 ;D369
947 (Integer/parseInt "00001111" 2) ; "00001111" -> C
949 0xF0 ;D36A ; (FF00) -> A
950 0x00 ;D36B
951 0x00 ;D36C
953 0xA1 ;D36D ; (AND A C) -> A
954 0x4F ;D36E ; A -> C
956 ;; combine the B and C registers into the input number
957 0x79 ;D36F ; C -> A
958 0xB0 ;D370 ; (OR A B) -> A
959 0x2F ;D371 ; negate A
961 0xEA ;D372 ; store A into input-number
962 0x52 ;D373
963 0xD3 ;D374
965 0x00 ;D375
966 0x00 ;D376
967 0x00 ;D377
968 0x00 ;D378
969 0x00 ;D379
970 0x00 ;D37A
971 0x00 ;D37B ; these are here because
972 0x00 ;D37C ; I messed up :(
973 0x00 ;D37D
974 0x00 ;D37E
975 0x00 ;D37F
977 ;; beginning of main state machine
978 0x18 ;D380 ; Declaration of variables
979 0x05 ;D381 ; 5 variables:
980 0x00 ;D382 ; current-mode
981 0x00 ;D383 ; bytes-to-write
982 0x00 ;D384 ; bytes-written
983 0x00 ;D385 ; start-point-high
984 0x00 ;D386 ; start-point-low
987 ;; banch on current mode
988 0xFA ;D387 ; load current-mode (0xD382)
989 0x82 ;D388 ; into A
990 0xD3 ;D389
991 0x00 ;D38A
994 ;; GOTO Mode 0 (input-mode) if current-mode is 0
995 0xFE ;D38B
996 0x00 ;D38C ; compare A with 0x00
998 0xCA ;D38D ; goto Mode 0 if A == 0
999 0xA8 ;D38E
1000 0xD3 ;D38F
1002 ;; GOTO Mode 1 (set-length) if current-mode is 1
1003 0xFE ;D390
1004 0x01 ;D391 ; compare A with 0x01
1006 0xCA ;D392
1007 0xB1 ;D393
1008 0xD3 ;D394 ; goto Mode 1 if A == 1
1010 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
1011 0xFE ;D395
1012 0x02 ;D396 ; compare A with 0x02
1014 0xCA ;D397
1015 0xBF ;D398
1016 0xD3 ;D399 ; goto Mode 2 if A == 2
1018 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
1019 0xFE ;D39A
1020 0x03 ;D39B
1022 0xCA ;D39C
1023 0xCD ;D39D
1024 0xD3 ;D39E ; goto Mode 3 if A == 3
1026 ;; GOTO Mode 4 (write-memory) if current mode is 4
1027 0xFE ;D39F
1028 0x04 ;D3A0
1030 0xCA ;D3A1
1031 0xDB ;D3A2
1032 0xD3 ;D3A3
1034 0x00 ;D3A4
1035 ;; End of Mode checking, goto beginning
1036 0xC3 ;D3A5
1037 0x1D ;D3A6
1038 0xD3 ;D3A7
1041 ;; Mode 0 -- input-mode mode
1042 ;; means that we are waiting for a mode, so set the mode to
1043 ;; whatever is currently in input-number. If nothing is
1044 ;; entered, then the program stays in input-mode mode
1046 ;; set current-mode to input-number
1047 0xFA ;D3A8 ; load input-number (0xD352)
1048 0x52 ;D3A9 ; into A
1049 0xD3 ;D3AA
1051 0xEA ;D3AB ; load A into current-mode
1052 0x82 ;D3AC ; (0xD382)
1053 0xD3 ;D3AD
1055 0xC3 ;D3AE ; go back to beginning
1056 0x1D ;D3AF
1057 0xD3 ;D3B0
1058 ;; End Mode 0
1061 ;; Mode 1 -- set-length mode
1062 ;; This is the header for writing things to memory.
1063 ;; User specifies the number of bytes to write.
1064 ;; Mode is auto advanced to Mode 2 after this mode
1065 ;; completes.
1067 ;; Set bytes left to write to input-number;
1068 ;; set current-mode to 0x02.
1069 0xFA ;D3B1 ; load input-number (0xD352)
1070 0x52 ;D3B2 ; into A
1071 0xD3 ;D3B3
1073 0xEA ;D3B4 ; load A into bytes-left-to-write
1074 0x83 ;D3B5 ; (0xD383)
1075 0xD3 ;D3B6
1077 0x3E ;D3B7 ; load 0x02 into A.
1078 0x02 ;D3B8
1080 0xEA ;D3B9 ; load A to current-mode
1081 0x82 ;D3BA ; advancing from Mode 1 to
1082 0xD3 ;D3BB ; Mode 2
1084 0xC3 ;D3BC ; go back to beginning
1085 0x1D ;D3BD
1086 0xD3 ;D3BE
1087 ;; End Mode 1
1090 ;; Mode 2 -- set start-point-high mode
1091 ;; Middle part of the header for writing things to memory.
1092 ;; User specifies the start location in RAM to which
1093 ;; data will be written.
1094 ;; Mode is auto advanced to Mode 3 after this mode completes.
1096 ;; Set start-point-high to input-number;
1097 ;; set current mode to 0x03.
1098 0xFA ;D3BF ; load input-number (0xD352)
1099 0x52 ;D3C0 ; into A
1100 0xD3 ;D3C1
1102 0xEA ;D3C2 ; load A into start-point-high
1103 0x85 ;D3C3 ; (0xD385)
1104 0xD3 ;D3C4
1106 0x3E ;D3C5 ; load 0x03 into A.
1107 0x03 ;D3C6
1109 0xEA ;D3C7 ; load A to current-mode,
1110 0x82 ;D3C8 ; advancing from Mode 2 to
1111 0xD3 ;D3C9 ; Mode 3.
1113 0xC3 ;D3CA ; go back to beginning
1114 0x1D ;D3CB
1115 0xD3 ;D3CC
1116 ;;End Mode 2
1119 ;; Mode 3 -- set-start-point-low mode
1120 ;; Final part of header for writing things to memory.
1121 ;; User specifies the low bytes of 16 bit start-point.
1123 ;; Set start-point-low to input-number;
1124 ;; set current mode to 0x04
1125 0xFA ;D3CD ; load input-number into A
1126 0x52 ;D3CE
1127 0xD3 ;D3CF
1129 0xEA ;D3D0 ; load A into start-point-low
1130 0x86 ;D3D1
1131 0xD3 ;D3D2
1133 0x3E ;D3D3 ; load 0x04 into A.
1134 0x04 ;D3D4
1136 0xEA ;D3D5 ; load A to current-mode,
1137 0x82 ;D3D6 ; advancing from Mode 3 to
1138 0xD3 ;D3D7 ; Mode 4.
1140 0xC3 ;D3D8 ; go back to beginning
1141 0x1D ;D3D9
1142 0xD3 ;D3DA
1144 ;; Mode 4 -- write bytes mode
1146 ;; This is where RAM manipulation happens. User supplies
1147 ;; bytes every frame, which are written sequentially to
1148 ;; start-point until bytes-to-write have been written. Once
1149 ;; bytes-to-write have been written, the mode is reset to 0.
1151 ;; compare bytes-written with bytes-to-write.
1152 ;; if they are the same, then reset mode to 0
1154 0xFA ;D3DB ; load bytes-to-write into A
1155 0x83 ;D3DC
1156 0xD3 ;D3DD
1158 0x47 ;D3DE ; load A into B
1160 0xFA ;D3DF ; load bytes-written into A
1161 0x84 ;D3E0
1162 0xD3 ;D3E1
1164 0xB8 ;D3E2 ; compare A with B
1166 0xCA ;D3E3 ; if they are equal, go to cleanup
1167 0x07 ;D3E4
1168 0xD4 ;D3E5
1170 ;; Write Memory Section
1171 ;; Write the input-number, interpreted as an 8-bit number,
1172 ;; into the current target register, determined by
1173 ;; (+ start-point bytes-written).
1174 ;; Then, increment bytes-written by 1.
1176 0xFA ;D3E6 ; load start-point-high into A
1177 0x85 ;D3E7
1178 0xD3 ;D3E8
1180 0x67 ;D3E9 ; load A into H
1182 0xFA ;D3EA ; load start-point-low into A
1183 0x86 ;D3EB
1184 0xD3 ;D3EC
1186 0x6F ;D3ED ; load A into L
1188 0xFA ;D3EE ; load bytes-written into A
1189 0x84 ;D3EF
1190 0xD3 ;D3F0
1192 0x00 ;D3F1 ; These are here because
1193 0x00 ;D3F2 ; I screwed up again.
1194 0x00 ;D3F3
1196 0x85 ;D3F4 ; add L to A; store A in L.
1197 0x6F ;D3F5
1199 0x30 ;D3F6 ; If the addition overflowed,
1200 0x01 ;D3F7
1201 0x24 ;D3F8 ; increment H.
1203 ;; Now, HL points to the correct place in memory
1205 0xFA ;D3F9 ; load input-number into A
1206 0x52 ;D3FA
1207 0xD3 ;D3FB
1209 0x77 ;D3FC ; load A into (HL)
1211 0xFA ;D3FD ; load bytes-written into A
1212 0x84 ;D3FE
1213 0xD3 ;D3FF
1215 0x3C ;D400 ; increment A
1217 0xEA ;D401 ; load A into bytes-written
1218 0x84 ;D402
1219 0xD3 ;D403
1221 0xC3 ;D404 ; go back to beginning.
1222 0x1D ;D405
1223 0xD3 ;D406
1224 ;; End Write Memory Section
1226 ;; Mode 4 Cleanup Section
1227 ;; reset bytes-written to 0
1228 ;; set mode to 0
1229 0x3E ;D407 ; load 0 into A
1230 0x00 ;D408
1232 0xEA ;D409 ; load A into bytes-written
1233 0x84 ;D40A
1234 0xD3 ;D40B
1236 0xEA ;D40C ; load A into current-mode
1237 0x82 ;D40D
1238 0xD3 ;D40E
1240 0xC3 ;D40F ; go back to beginning
1241 0x1D ;D410
1242 0xD3 ;D411
1244 ;; End Mode 4
1246 ])
1250 (def frame-count 0xD31F)
1251 (def input 0xD352)
1252 (def current-mode 0xD382)
1253 (def bytes-to-write 0xD383)
1254 (def bytes-written 0xD384)
1255 (def start-point-high 0xD385)
1256 (def start-point-low 0xD386)
1260 (defn write-memory []
1261 (-> (tick (mid-game))
1262 (IE! 0) ; disable interrupts
1263 (inject-item-assembly (write-memory-assembly))))
1265 (defn test-write-memory []
1266 (set-state! (write-memory))
1267 (dorun
1268 (dotimes [_ 5000]
1269 (view-memory (step @current-state) current-mode))))
1271 (def bytes-to-write 0xD383)
1272 (def start-point 0xD384)
1274 (defn print-blank-assembly
1275 [start end]
1276 (dorun
1277 (map
1278 #(println (format "0x00 ;%04X " %))
1279 (range start end))))
1281 (defn test-mode-2 []
1282 (->
1283 (write-memory)
1284 (view-memory frame-count)
1285 (step)
1286 (step [:a])
1287 (step [:b])
1288 (step [:start])
1289 (step [])
1290 (view-memory frame-count)))
1292 (defn test-mode-4
1293 ([] (test-mode-4 (write-memory)))
1294 ([target-state]
1295 (->
1296 target-state
1297 (#(do (println "memory from 0xC00F to 0xC01F:"
1298 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1299 (view-memory current-mode)
1300 (step [])
1301 (step [])
1302 (step [])
1303 (#(do (println "after three steps") %))
1304 (view-memory current-mode)
1306 ;; Activate memory writing mode
1308 (#(do (println "step with [:a]") %))
1309 (step [:a])
1310 (view-memory current-mode)
1311 (view-memory bytes-to-write)
1312 (view-memory start-point-high)
1313 (view-memory start-point-low)
1315 ;; Specify four bytes to be written
1317 (#(do (println "step with [:select]")%))
1318 (step [:select])
1319 (view-memory current-mode)
1320 (view-memory bytes-to-write)
1321 (view-memory start-point-high)
1322 (view-memory start-point-low)
1324 ;; Specify target memory address as 0xC00F
1326 (#(do (println "step with [:u :d]")%))
1327 (step [:u :d])
1328 (view-memory current-mode)
1329 (view-memory bytes-to-write)
1330 (view-memory start-point-high)
1331 (view-memory start-point-low)
1333 (#(do (println "step with [:a :b :start :select]")%))
1334 (step [:a :b :start :select])
1335 (view-memory current-mode)
1336 (view-memory bytes-to-write)
1337 (view-memory start-point-high)
1338 (view-memory start-point-low)
1340 ;; Start reprogramming memory
1342 (#(do (println "step with [:a]")%))
1343 (step [:a])
1344 (view-memory current-mode)
1345 (view-memory bytes-written)
1347 (#(do (println "step with [:b]")%))
1348 (step [:b])
1349 (view-memory current-mode)
1350 (view-memory bytes-written)
1352 (#(do (println "step with [:a :b]")%))
1353 (step [:a :b])
1354 (view-memory current-mode)
1355 (view-memory bytes-written)
1357 (#(do (println "step with [:select]")%))
1358 (step [:select])
1359 (view-memory current-mode)
1360 (view-memory bytes-written)
1362 ;; Reprogramming done, program ready for more commands.
1364 (#(do (println "step with []")%))
1365 (step [])
1366 (view-memory current-mode)
1367 (view-memory bytes-written)
1369 (#(do (println "memory from 0xC00F to 0xC01F:"
1370 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))