view clojure/com/aurellem/assembly.clj @ 139:74ec1ac044bb

write-memory-assembly* confirmed...stage one.
author Dylan Holmes <ocsenave@gmail.com>
date Mon, 19 Mar 2012 05:12:05 -0500
parents 2b69cbe8a5b9
children aa5b5927e5fe
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 D [state]
73 (bit-shift-right (bit-and 0x0000FF00 (DE state)) 8))
75 (defn H [state]
76 (bit-shift-right (bit-and 0x0000FF00 (HL state)) 8))
78 (defn C [state]
79 (bit-and 0xFF (BC state)))
80 (defn F [state]
81 (bit-and 0xFF (AF state)))
82 (defn E [state]
83 (bit-and 0xFF (DE state)))
84 (defn L [state]
85 (bit-and 0xFF (HL state)))
91 (defn binary-str [num]
92 (format "%08d"
93 (Integer/parseInt
94 (Integer/toBinaryString num) 10)))
96 (defn view-register [state name reg-fn]
97 (println (format "%s: %s" name
98 (binary-str (reg-fn state))))
99 state)
101 (defn view-memory [state mem]
102 (println (format "mem 0x%04X = %s" mem
103 (binary-str (aget (memory state) mem))))
104 state)
106 (defn trace [state]
107 (loop [program-counters [(first (registers @current-state)) ]
108 opcodes [(aget (memory @current-state) (PC @current-state))]]
109 (let [frame-boundary?
110 (com.aurellem.gb.Gb/tick)]
111 (if frame-boundary?
112 [program-counters opcodes]
113 (recur
114 (conj program-counters
115 (first (registers @current-state)))
116 (conj opcodes
117 (aget (memory @current-state)
118 (PC @current-state))))))))
120 (defn print-trace [state n]
121 (let [[program-counters opcodes] (trace state)]
122 (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op)))
123 (take n program-counters)
124 (take n opcodes)))))
126 (defn good-trace []
127 (-> (mid-game) (tick) (IE! 0)
128 (set-inv-mem [0x00 0x00 0X00 0x00])
129 (PC! item-list-start)(print-interrupt)
130 (info) (tick) (info) (tick) (info)))
132 (defn read-down-button []
133 (-> (tick (mid-game))
134 (IE! 0) ; disable interrupts
135 (inject-item-assembly
136 ;; write 00010000 to 0xFF00 to select joypad
137 [0x18 ;D31D ; jump over
138 0x01 ;D31E ; the next 8 bits
139 ;D31F
140 (Integer/parseInt "00100000" 2) ; data section
142 0xFA ;D320 ; load (D31F) into A
143 0x1F ;D321 -->
144 0xD3 ;D322 --> D31F
146 0xEA ;D323 ; load (A), which is
147 0x00 ;D324 --> ; 00010000, into FF00
148 0xFF ;D325 --> FF00
150 0x18 ;D326 ; this is the place where
151 0x01 ;D327 ; we will store whether
152 0x00 ;D328 ; "down" is pressed.
154 0xFA ;D329 ; (FF00) -> A
155 0x00 ;D32A
156 0xFF ;D32B
158 0xCB ;D32C ; Test whether "down"
159 0x5F ;D32D ; is pressed.
161 0x28 ;D32E ; if down is pressed,
162 0x03 ;D32F ; skip the next section
163 ; of code.
164 ;; down-is-not-pressed
165 0xC3 ;D330
166 0x1D ;D331 ; return to beginning
167 0xD3 ;D332
169 ;; down-is-pressed
170 0xEA ;D334 ; write A to D328 if
171 0x28 ;D335 ; "down" was pressed
172 0xD3 ;D336
174 0xC3 ;D330
175 0x1D ;D331 ; return to beginning
176 0xD3 ;D332
177 ])))
179 (defn test-read-down []
180 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
181 (view-memory (step (step (read-down-button))) 0xD328)))
183 (defn count-frames []
184 (-> (tick (mid-game))
185 (IE! 0) ; disable interrupts
186 (inject-item-assembly
187 [0x18 ;D31D ; jump over
188 0x02 ;D31E ; the next 2 bytes
189 0x00 ;D31F ; frame-count
190 0x00 ;D320 ; v-blank-prev
192 0xFA ;D321
193 0x41 ;D322 ; load (FF41) into A
194 0xFF ;D323 ; this contains mode flags
196 ;; if we're in v-blank, the bit-1 is 0
197 ;; and bit-2 is 1 Otherwise, it is not v-blank.
198 0xCB ;D324 ; test bit-1 of A
199 0x4F ;D325
201 0xC2 ;D326 ; if bit-1 is not 0
202 0x44 ;D327 ; GOTO not-v-blank
203 0xD3 ;D328
205 0xCB ;D329 ; test bit-0 of A
206 0x47 ;D32A
208 0xCA ;D32B ; if bit-0 is not 1
209 0x44 ;D32C ; GOTO not-v-blank
210 0xD3 ;D32D
211 ;;; in v-blank mode
212 ;; if v-blank-prev was 0,
213 ;; increment frame-count
215 0xFA ;D32E ; load v-blank-prev to A
216 0x20 ;D32F
217 0xD3 ;D330
219 0xCB ;D331
220 0x47 ;D332 ; test bit-0 of A
222 0x20 ;D333 ; skip next section
223 0x07 ;D334 ; if v-blank-prev was not zero
225 ;; v-blank was 0, increment frame-count
226 0xFA ;D335 ; load frame-count into A
227 0x1F ;D336
228 0xD3 ;D337
230 0x3C ;D338 ; inc A
232 0xEA ;D339 ; load A into frame-count
233 0x1F ;D33A
234 0xD3 ;D33B
236 ;; set v-blank-prev to 1
237 0x3E ;D33C ; load 1 into A
238 0x01 ;D33D
240 0xEA ;D33E ; load A into v-blank-prev
241 0x20 ;D33F
242 0xD3 ;D340
244 0xC3 ;D341 ; return to beginning
245 0x1D ;D342
246 0xD3 ;D343
248 ;;; not in v-blank mode
249 ;; set v-blank-prev to 0
250 0x3E ;D344 ; load 0 into A
251 0x00 ;D345
253 0xEA ;D346 ; load A into v-blank-prev
254 0x20 ;D347
255 0xD3 ;D348
257 0xC3 ;D349 ; return to beginning
258 0x1D ;D34A
259 0xD3 ;D34B
260 ])))
262 (defn step-count-frames []
263 (-> (read-down-button)
264 (info)
265 (tick) ;; skip over data section
266 (info)
267 (view-register "Register A" A)
268 (tick) ;; load-data into A
269 (view-register "Register A" A)
270 (info)
271 (view-memory 0xFF00)
272 (tick) ;; load A into 0xFF00
273 (view-memory 0xFF00)
274 (info)
275 (tick)
276 (info)
277 (tick)
278 (info)
279 (tick)
280 (info)
281 (tick)
282 (info)
283 (tick)
284 (info)
285 (tick)
286 (print-inventory)))
288 (defn test-count-frames []
289 (= 255 (aget (memory ((apply comp (repeat 255 step))
290 (count-frames)))
291 0xD31F)))
293 ;; specs for main bootstrap program
294 ;; starts in "mode-select" mode
295 ;; Each button press takes place in a single frame.
296 ;; mode-select-mode takes one of the main buttons
297 ;; which selects one of up to eight modes
298 ;; mode 1 activated by the "A" button
299 ;; the next two button presses indicates the start
300 ;; memory location which to which the bootstrap
301 ;; program will write.
302 ;; This is done by using each of the eight buttons to
303 ;; spell out an 8 bit number. The order of buttons is
304 ;; [:d :u :l :r :start :select :b :a]
305 ;; [:a :start :l] --> 00101001
307 ;; the next button press determines how many bytes are to be
308 ;; written, starting at the start position.
310 ;; then, the actual bytes are entered and are written to the
311 ;; start address in sequence.
313 (defn input-number-assembly []
314 [0x18 ;D31D ; jump over
315 0x02 ;D31E ; the next 2 bytes
316 0x00 ;D31F ; frame-count
317 0x00 ;D320 ; v-blank-prev
319 0xFA ;D321
320 0x41 ;D322 ; load (FF41) into A
321 0xFF ;D323 ; this contains mode flags
323 ;; if we're in v-blank, the bit-1 is 0
324 ;; and bit-2 is 1 Otherwise, it is not v-blank.
325 0xCB ;D324 ; test bit-1 of A
326 0x4F ;D325
328 0xC2 ;D326 ; if bit-1 is not 0
329 0x44 ;D327 ; GOTO not-v-blank
330 0xD3 ;D328
332 0xCB ;D329 ; test bit-0 of A
333 0x47 ;D32A
335 0xCA ;D32B ; if bit-0 is not 1
336 0x44 ;D32C ; GOTO not-v-blank
337 0xD3 ;D32D
339 ;;; in v-blank mode
341 ;; if v-blank-prev was 0,
342 ;; increment frame-count
344 0xFA ;D32E ; load v-blank-prev to A
345 0x20 ;D32F
346 0xD3 ;D330
348 0xCB ;D331
349 0x47 ;D332 ; test bit-0 of A
351 0x20 ;D333 ; skip next section
352 0x07 ;D334 ; if v-blank-prev was not zero
354 ;; v-blank was 0, increment frame-count
355 0xFA ;D335 ; load frame-count into A
356 0x1F ;D336
357 0xD3 ;D337
359 0x3C ;D338 ; inc A
361 0xEA ;D339 ; load A into frame-count
362 0x1F ;D33A
363 0xD3 ;D33B
365 ;; set v-blank-prev to 1
366 0x3E ;D33C ; load 1 into A
367 0x01 ;D33D
369 0xEA ;D33E ; load A into v-blank-prev
370 0x20 ;D33F
371 0xD3 ;D340
373 0xC3 ;D341 ; GOTO input handling code
374 0x4E ;D342
375 0xD3 ;D343
377 ;;; not in v-blank mode
378 ;; set v-blank-prev to 0
379 0x3E ;D344 ; load 0 into A
380 0x00 ;D345
382 0xEA ;D346 ; load A into v-blank-prev
383 0x20 ;D347
384 0xD3 ;D348
386 0xC3 ;D349 ; return to beginning
387 0x1D ;D34A
388 0xD3 ;D34B
390 0x00 ;D34C ; these are here
391 0x00 ;D34D ; for glue
394 ;;; calculate input number based on button presses
395 0x18 ;D34E ; skip next 3 bytes
396 0x03 ;D34F
397 ;D350
398 (Integer/parseInt "00100000" 2) ; select directional pad
399 ;D351
400 (Integer/parseInt "00010000" 2) ; select buttons
401 0x00 ;D352 ; input-number
403 ;; select directional pad, store low bits in B
405 0xFA ;D353 ; load (D350) into A
406 0x50 ;D354 -->
407 0xD3 ;D355 --> D31F
409 0xEA ;D356 ; load A, which is
410 0x00 ;D357 --> ; 00010000, into FF00
411 0xFF ;D358 --> FF00
413 0x06 ;D359
414 ;D35A
415 (Integer/parseInt "11110000" 2) ; "11110000" -> B
416 0xFA ;D35B ; (FF00) -> A
417 0x00 ;D35C
418 0xFF ;D35D
420 0xCB ;D35E ; swap nybbles on A
421 0x37 ;D35F
422 0xA0 ;D360 ; (AND A B) -> A
423 0x47 ;D361 ; A -> B
425 ;; select buttons store bottom bits in C
427 0xFA ; ; load (D351) into A
428 0x51 ; -->
429 0xD3 ; --> D31F
431 0xEA ; ; load (A), which is
432 0x00 ; --> ; 00001000, into FF00
433 0xFF ; --> FF00
435 0x0E ;
436 (Integer/parseInt "00001111" 2) ; "00001111" -> C
438 0xFA ; ; (FF00) -> A
439 0x00 ;
440 0xFF ;
442 0xA1 ; ; (AND A C) -> A
443 0x4F ; ; A -> C
445 ;; combine the B and C registers into the input number
446 0x79 ; ; C -> A
447 0xB0 ; ; (OR A B) -> A
448 0x2F ; ; negate A
450 0xEA ; ; store A into input-number
451 0x52 ;
452 0xD3 ;
454 0xC3 ; ; return to beginning
455 0x1D ;
456 0xD3 ;
457 ])
460 (defn print-pc [state]
461 (println (format "PC: 0x%04X" (PC state)))
462 state)
464 (defn print-op [state]
465 (println (format "OP: 0x%02X" (aget (memory state) (PC state))))
466 state)
468 (defn d-tick
469 ([state]
470 (-> state print-pc print-op tick)))
472 (defn input-number []
473 (-> (tick (mid-game))
474 (IE! 0) ; disable interrupts
475 (inject-item-assembly (input-number-assembly))))
477 (defn test-input-number
478 "Input freestyle buttons and observe the effects at the repl."
479 []
480 (set-state! (input-number))
481 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))
511 (defn write-memory-assembly*
512 "Currently, grabs input from the user each frame."
513 []
514 [
515 ;; --------- FRAME METRONOME
516 0x18 ;; jump ahead to cleanup. first time only.
517 0x40 ;; v-blank-prev [D31E]
519 0xFA ;; load modes into A [D31F]
520 0x41
521 0xFF
523 0x47 ;; A -> B
524 0xCB ;; rotate A
525 0x2F
526 0x2F ;; invert A
528 0xA0
529 0x47 ;; now B_0 contains (VB==1)
531 0xFA ;; load v-blank-prev
532 0x1E
533 0xD3
535 0x2F ;; complement v-blank-prev
537 0xA0 ;; A & B --> A
538 0x4F ;; now C_0 contains increment?
541 0x78 ;; B->A
542 0xEA ;; spit A --> vbprev
543 0x1E
544 0xD3
546 0xCB ;test C_0
547 0x41
548 0x20 ; JUMP ahead to button input if nonzero
549 0x02
550 0x18 ; JUMP back to frame metronome (D31F)
551 0xE7
553 ;; -------- GET BUTTON INPUT
555 ;; btw, C_0 is now 1
556 ;; prepare to select bits
558 0x06 ;; load 0x00 into B
559 0x00 ;; to initialize for "OR" loop
561 0x3E ;; load 0x20 into A, to measure dpad
562 0x20
565 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]
566 0x00
568 0xF0 ;; load A from [FF00]
569 0x00
571 0xE6 ;; bitmask 00001111
572 0x0F
574 0xB0 ;; A or B --> A
575 0xCB
576 0x41 ;; test bit 0 of C
577 0x28 ;; JUMP forward if 0
578 0x08
580 0x47 ;; A -> B
581 0xCB ;; swap B nybbles
582 0x30
583 0x0C ;; increment C
584 0x3E ;; load 0x10 into A, to measure btns
585 0x10
586 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]
587 0xED
590 ;; ------ TAKE ACTION BASED ON USER INPUT
592 ;; "input mode"
593 ;; mode 0x00 : select mode
594 ;; mode 0x08 : select bytes-to-write
595 ;; mode 0x10 : select hi-bit
596 ;; mode 0x18 : select lo-bit
598 ;; "output mode"
599 ;; mode 0x20 : write bytes
600 ;; mode 0xFF : jump PC
603 ;; registers
604 ;; D : mode select
605 ;; E : count of bytes to write
606 ;; H : address-high
607 ;; L : address-low
609 ;; now A contains the pressed keys
610 0x2F ; complement A, by request. [D34F]
612 0x47 ; A->B ;; now B contains the pressed keys
613 0x7B ; E->A ;; now A contains the count.
615 0xCB ; test bit 5 of D (are we in o/p mode?)
616 0x6A
617 0x28 ; if test == 0, skip this o/p section
618 0x13 ; JUMP
620 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)
621 0x42
622 0x28 ; if test == 0, skip the following command
623 0x01
625 ;; output mode I: moving the program counter
626 0xE9 ; ** move PC to (HL)
628 ;; output mode II: writing bytes
629 0xFE ; A compare 0. finished writing?
630 0x00
631 0x20 ; if we are not finished, skip cleanup
632 0x04 ; JUMP
634 ;; CLEANUP
635 ;; btw, A is already zero.
636 0xAF ; zero A [D35F]
637 0x57 ; A->D; makes D=0.
638 0x18 ; end of frame
639 0xBC
641 ;; ---- end of cleanup
644 ;; continue writing bytes
645 0x1D ;; decrement E, the number of bytes to write [D363]
646 0x78 ;; B->A; now A contains the pressed keys
647 0x77 ;; copy A to (HL)
648 0x23 ;; increment HL
649 0x18 ;; end frame. [goto D31F]
650 0xB6 ;; TODO: set skip length backwards
653 ;; ---- end of o/p section
655 ;; i/p mode
656 ;; adhere to the mode discipline:
657 ;; D must be one of 0x00 0x08 0x10 0x18.
659 0x3E ;; load the constant 57 into A. [D369]
660 0x57
661 0x82 ;; add the mode to A
662 0xEA ;; store A into "thing to execute"
663 0x74
664 0xD3
666 0x3E ;; load the constant 8 into A
667 0x08
668 0x82 ;; add the mode to A
670 0x57 ;; store the incremented mode into D
671 0x78 ;; B->A; now A contains the pressed keys
673 0x00 ;; var: thing to execute [D374]
675 0x18 ;; end frame
676 0xA8 ;; TODO: set jump correctly
677 ]
678 )
680 (defn write-mem-dyl []
681 (-> (tick (mid-game))
682 (IE! 0)
683 (inject-item-assembly (write-memory-assembly*))))
686 (defn dylan* []
687 (->
688 (write-mem-dyl)
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)
704 (tick)
705 (tick)
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 (tick)
722 (tick)
723 (tick)
724 (tick)
725 (tick)
727 ;;(view-memory 0xD374)
728 (tick)
729 (tick)
730 (tick)
731 (tick)
732 (tick)
733 (tick)
734 (tick)
735 (tick)
736 (tick)
737 (tick)
738 (tick)
739 (tick)
740 (tick)
741 (tick)
742 (tick)
743 ;;(view-memory 0xD374)
744 (d-tick)
746 (view-register "A" A)
747 (view-register "B" B)
748 (view-register "C" C))
750 )
753 (defn dylan []
754 (->
755 (write-mem-dyl)
756 (tick)
757 (tick)
758 (tick)
759 (tick)
760 (tick)
761 (tick)
762 (tick)
763 (tick)
764 (tick)
765 (tick)
766 (tick)
767 (tick)
768 (tick)
769 (tick)
770 (tick) ;; first loop
773 (tick)
774 (tick)
775 (tick)
776 (tick)
777 (tick)
778 (tick)
779 (tick)
780 (tick)
781 (tick)
782 (tick)
783 (tick)
784 (tick)
785 (tick) ;; dpad bits
787 (tick)
788 (tick)
789 (tick)
790 (tick)
791 (tick)
792 (tick)
793 (tick)
794 (tick)
795 (d-tick)
799 (view-register "A" A)
800 (view-register "B" B)
801 (view-register "C" C)
803 ))
808 (defn d2 []
809 (->
810 (write-mem-dyl)
811 (view-memory 0xD31F)
812 step step step step step
813 (view-memory 0xD31F)))
834 (defn write-memory-assembly []
835 [
836 ;; Main Timing Loop
837 ;; Constantly check for v-blank and Trigger main state machine on
838 ;; every transtion from v-blank to non-v-blank.
840 0x18 ; D31D ; Variable declaration
841 0x02 ; D31E
842 0x00 ; D31F ; frame-count
843 0x00 ; D320 ; v-blank-prev
845 0xF0 ; D321 ; load v-blank mode flags into A
846 0x41
847 0x00
850 ;; Branch dependent on v-blank. v-blank happens when the last two
851 ;; bits in A are "01"
852 0xCB ; D324
853 0x4F ; D325
855 0xC2 ; D326 ; if bit-1 is not 0, then
856 0x3E ; D327 ; GOTO non-v-blank.
857 0xD3 ; D328
859 0xCB ; D329
860 0x47 ; D32A
862 0xCA ; D32B ; if bit-0 is not 1, then
863 0x3E ; D32C ; GOTO non-v-blank.
864 0xD3 ; D32D
866 ;; V-Blank
867 ;; Activate state-machine if this is a transition event.
869 0xFA ; D32E ; load v-bank-prev into A
870 0x20 ; D32F
871 0xD3 ; D330
873 0xFE ; D331 ; compare A to 0. >--------\
874 0x00 ; D332 \
875 ; |
876 ;; set v-blank-prev to 1. |
877 0x3E ; D333 ; load 1 into A. |
878 0x01 ; D334 |
879 ; |
880 0xEA ; D335 ; load A into v-blank-prev |
881 0x20 ; D336 |
882 0xD3 ; D337 |
883 ; /
884 ;; if v-blank-prev was 0, activate state-machine <------/
885 0xCA ; D338 ; if v-blank-prev
886 0x46 ; D339 ; was 0,
887 0xD3 ; D33A ; GOTO state-machine
889 0xC3 ; D33B
890 0x1D ; D33C
891 0xD3 ; D33D ; GOTO beginning
892 ;; END V-blank
894 ;; Non-V-Blank
895 ;; Set v-blank-prev to 0
896 0x3E ; D33E ; load 0 into A
897 0x00 ; D33F
899 0xEA ; D340 ; load A into v-blank-prev
900 0x20 ; D341
901 0xD3 ; D342
903 0xC3 ; D343
904 0x1D ; D344
905 0xD3 ; D345 ; GOTO beginning
906 ;; END Not-V-Blank
909 ;; Main State Machine -- Input Section
910 ;; This is called once every frame.
911 ;; It collects input and uses it to drive the
912 ;; state transitions.
914 ;; Increment frame-count
915 0xFA ; D346 ; load frame-count into A
916 0x1F ; D347
917 0xD3 ; D348
919 0x3C ; D349 ; inc A
921 0xEA ; D34A
922 0x1F ; D34B ; load A into frame-count
923 0xD3 ; D34C
925 0x00 ; D34D ; glue :)
927 0x18 ;D34E ; skip next 3 bytes
928 0x03 ;D34F
929 ;D350
930 (Integer/parseInt "00100000" 2) ; select directional pad
931 ;D351
932 (Integer/parseInt "00010000" 2) ; select buttons
933 0x00 ;D352 ; input-number
935 ;; select directional pad; store low bits in B
937 0xFA ;D353 ; load (D350) into A
938 0x50 ;D354 -->
939 0xD3 ;D355 --> D350
941 0xE0 ;D356 ; load (A), which is
942 0x00 ;D357 --> ; 00010000, into FF00
943 0x00 ;D358 --> FF00 ;; NO-OP
945 0x06 ;D359
946 ;D35A
947 (Integer/parseInt "11110000" 2) ; "11110000" -> B
948 0xF0 ;D35B ; (FF00) -> A
949 0x00 ;D35C
950 0x00 ;D35D ;; NO-OP
952 0xCB ;D35E ; swap nybbles on A
953 0x37 ;D35F
954 0xA0 ;D360 ; (AND A B) -> A
955 0x47 ;D361 ; A -> B
957 ;; select buttons; store bottom bits in C
959 0xFA ;D362 ; load (D351) into A
960 0x51 ;D363 -->
961 0xD3 ;D364 --> D351
963 0xE0 ;D365 ; load (A), which is
964 0x00 ;D366 --> ; 00001000, into FF00
965 0x00 ;D367 --> FF00 ;; NO-OP
967 0x0E ;D368
968 ;D369
969 (Integer/parseInt "00001111" 2) ; "00001111" -> C
971 0xF0 ;D36A ; (FF00) -> A
972 0x00 ;D36B
973 0x00 ;D36C
975 0xA1 ;D36D ; (AND A C) -> A
976 0x4F ;D36E ; A -> C
978 ;; combine the B and C registers into the input number
979 0x79 ;D36F ; C -> A
980 0xB0 ;D370 ; (OR A B) -> A
981 0x2F ;D371 ; negate A
983 0xEA ;D372 ; store A into input-number
984 0x52 ;D373
985 0xD3 ;D374
987 0x00 ;D375
988 0x00 ;D376
989 0x00 ;D377
990 0x00 ;D378
991 0x00 ;D379
992 0x00 ;D37A
993 0x00 ;D37B ; these are here because
994 0x00 ;D37C ; I messed up :(
995 0x00 ;D37D
996 0x00 ;D37E
997 0x00 ;D37F
999 ;; beginning of main state machine
1000 0x18 ;D380 ; Declaration of variables
1001 0x05 ;D381 ; 5 variables:
1002 0x00 ;D382 ; current-mode
1003 0x00 ;D383 ; bytes-to-write
1004 0x00 ;D384 ; bytes-written
1005 0x00 ;D385 ; start-point-high
1006 0x00 ;D386 ; start-point-low
1009 ;; banch on current mode
1010 0xFA ;D387 ; load current-mode (0xD382)
1011 0x82 ;D388 ; into A
1012 0xD3 ;D389
1013 0x00 ;D38A
1016 ;; GOTO Mode 0 (input-mode) if current-mode is 0
1017 0xFE ;D38B
1018 0x00 ;D38C ; compare A with 0x00
1020 0xCA ;D38D ; goto Mode 0 if A == 0
1021 0xA8 ;D38E
1022 0xD3 ;D38F
1024 ;; GOTO Mode 1 (set-length) if current-mode is 1
1025 0xFE ;D390
1026 0x01 ;D391 ; compare A with 0x01
1028 0xCA ;D392
1029 0xB1 ;D393
1030 0xD3 ;D394 ; goto Mode 1 if A == 1
1032 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
1033 0xFE ;D395
1034 0x02 ;D396 ; compare A with 0x02
1036 0xCA ;D397
1037 0xBF ;D398
1038 0xD3 ;D399 ; goto Mode 2 if A == 2
1040 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
1041 0xFE ;D39A
1042 0x03 ;D39B
1044 0xCA ;D39C
1045 0xCD ;D39D
1046 0xD3 ;D39E ; goto Mode 3 if A == 3
1048 ;; GOTO Mode 4 (write-memory) if current mode is 4
1049 0xFE ;D39F
1050 0x04 ;D3A0
1052 0xCA ;D3A1
1053 0xDB ;D3A2
1054 0xD3 ;D3A3
1056 0x00 ;D3A4
1057 ;; End of Mode checking, goto beginning
1058 0xC3 ;D3A5
1059 0x1D ;D3A6
1060 0xD3 ;D3A7
1063 ;; Mode 0 -- input-mode mode
1064 ;; means that we are waiting for a mode, so set the mode to
1065 ;; whatever is currently in input-number. If nothing is
1066 ;; entered, then the program stays in input-mode mode
1068 ;; set current-mode to input-number
1069 0xFA ;D3A8 ; load input-number (0xD352)
1070 0x52 ;D3A9 ; into A
1071 0xD3 ;D3AA
1073 0xEA ;D3AB ; load A into current-mode
1074 0x82 ;D3AC ; (0xD382)
1075 0xD3 ;D3AD
1077 0xC3 ;D3AE ; go back to beginning
1078 0x1D ;D3AF
1079 0xD3 ;D3B0
1080 ;; End Mode 0
1083 ;; Mode 1 -- set-length mode
1084 ;; This is the header for writing things to memory.
1085 ;; User specifies the number of bytes to write.
1086 ;; Mode is auto advanced to Mode 2 after this mode
1087 ;; completes.
1089 ;; Set bytes left to write to input-number;
1090 ;; set current-mode to 0x02.
1091 0xFA ;D3B1 ; load input-number (0xD352)
1092 0x52 ;D3B2 ; into A
1093 0xD3 ;D3B3
1095 0xEA ;D3B4 ; load A into bytes-left-to-write
1096 0x83 ;D3B5 ; (0xD383)
1097 0xD3 ;D3B6
1099 0x3E ;D3B7 ; load 0x02 into A.
1100 0x02 ;D3B8
1102 0xEA ;D3B9 ; load A to current-mode
1103 0x82 ;D3BA ; advancing from Mode 1 to
1104 0xD3 ;D3BB ; Mode 2
1106 0xC3 ;D3BC ; go back to beginning
1107 0x1D ;D3BD
1108 0xD3 ;D3BE
1109 ;; End Mode 1
1112 ;; Mode 2 -- set start-point-high mode
1113 ;; Middle part of the header for writing things to memory.
1114 ;; User specifies the start location in RAM to which
1115 ;; data will be written.
1116 ;; Mode is auto advanced to Mode 3 after this mode completes.
1118 ;; Set start-point-high to input-number;
1119 ;; set current mode to 0x03.
1120 0xFA ;D3BF ; load input-number (0xD352)
1121 0x52 ;D3C0 ; into A
1122 0xD3 ;D3C1
1124 0xEA ;D3C2 ; load A into start-point-high
1125 0x85 ;D3C3 ; (0xD385)
1126 0xD3 ;D3C4
1128 0x3E ;D3C5 ; load 0x03 into A.
1129 0x03 ;D3C6
1131 0xEA ;D3C7 ; load A to current-mode,
1132 0x82 ;D3C8 ; advancing from Mode 2 to
1133 0xD3 ;D3C9 ; Mode 3.
1135 0xC3 ;D3CA ; go back to beginning
1136 0x1D ;D3CB
1137 0xD3 ;D3CC
1138 ;;End Mode 2
1141 ;; Mode 3 -- set-start-point-low mode
1142 ;; Final part of header for writing things to memory.
1143 ;; User specifies the low bytes of 16 bit start-point.
1145 ;; Set start-point-low to input-number;
1146 ;; set current mode to 0x04
1147 0xFA ;D3CD ; load input-number into A
1148 0x52 ;D3CE
1149 0xD3 ;D3CF
1151 0xEA ;D3D0 ; load A into start-point-low
1152 0x86 ;D3D1
1153 0xD3 ;D3D2
1155 0x3E ;D3D3 ; load 0x04 into A.
1156 0x04 ;D3D4
1158 0xEA ;D3D5 ; load A to current-mode,
1159 0x82 ;D3D6 ; advancing from Mode 3 to
1160 0xD3 ;D3D7 ; Mode 4.
1162 0xC3 ;D3D8 ; go back to beginning
1163 0x1D ;D3D9
1164 0xD3 ;D3DA
1166 ;; Mode 4 -- write bytes mode
1168 ;; This is where RAM manipulation happens. User supplies
1169 ;; bytes every frame, which are written sequentially to
1170 ;; start-point until bytes-to-write have been written. Once
1171 ;; bytes-to-write have been written, the mode is reset to 0.
1173 ;; compare bytes-written with bytes-to-write.
1174 ;; if they are the same, then reset mode to 0
1176 0xFA ;D3DB ; load bytes-to-write into A
1177 0x83 ;D3DC
1178 0xD3 ;D3DD
1180 0x47 ;D3DE ; load A into B
1182 0xFA ;D3DF ; load bytes-written into A
1183 0x84 ;D3E0
1184 0xD3 ;D3E1
1186 0xB8 ;D3E2 ; compare A with B
1188 0xCA ;D3E3 ; if they are equal, go to cleanup
1189 0x07 ;D3E4
1190 0xD4 ;D3E5
1192 ;; Write Memory Section
1193 ;; Write the input-number, interpreted as an 8-bit number,
1194 ;; into the current target register, determined by
1195 ;; (+ start-point bytes-written).
1196 ;; Then, increment bytes-written by 1.
1198 0xFA ;D3E6 ; load start-point-high into A
1199 0x85 ;D3E7
1200 0xD3 ;D3E8
1202 0x67 ;D3E9 ; load A into H
1204 0xFA ;D3EA ; load start-point-low into A
1205 0x86 ;D3EB
1206 0xD3 ;D3EC
1208 0x6F ;D3ED ; load A into L
1210 0xFA ;D3EE ; load bytes-written into A
1211 0x84 ;D3EF
1212 0xD3 ;D3F0
1214 0x00 ;D3F1 ; These are here because
1215 0x00 ;D3F2 ; I screwed up again.
1216 0x00 ;D3F3
1218 0x85 ;D3F4 ; add L to A; store A in L.
1219 0x6F ;D3F5
1221 0x30 ;D3F6 ; If the addition overflowed,
1222 0x01 ;D3F7
1223 0x24 ;D3F8 ; increment H.
1225 ;; Now, HL points to the correct place in memory
1227 0xFA ;D3F9 ; load input-number into A
1228 0x52 ;D3FA
1229 0xD3 ;D3FB
1231 0x77 ;D3FC ; load A into (HL)
1233 0xFA ;D3FD ; load bytes-written into A
1234 0x84 ;D3FE
1235 0xD3 ;D3FF
1237 0x3C ;D400 ; increment A
1239 0xEA ;D401 ; load A into bytes-written
1240 0x84 ;D402
1241 0xD3 ;D403
1243 0xC3 ;D404 ; go back to beginning.
1244 0x1D ;D405
1245 0xD3 ;D406
1246 ;; End Write Memory Section
1248 ;; Mode 4 Cleanup Section
1249 ;; reset bytes-written to 0
1250 ;; set mode to 0
1251 0x3E ;D407 ; load 0 into A
1252 0x00 ;D408
1254 0xEA ;D409 ; load A into bytes-written
1255 0x84 ;D40A
1256 0xD3 ;D40B
1258 0xEA ;D40C ; load A into current-mode
1259 0x82 ;D40D
1260 0xD3 ;D40E
1262 0xC3 ;D40F ; go back to beginning
1263 0x1D ;D410
1264 0xD3 ;D411
1266 ;; End Mode 4
1268 ])
1272 (def frame-count 0xD31F)
1273 (def input 0xD352)
1274 (def current-mode 0xD382)
1275 (def bytes-to-write 0xD383)
1276 (def bytes-written 0xD384)
1277 (def start-point-high 0xD385)
1278 (def start-point-low 0xD386)
1282 (defn write-memory []
1283 (-> (tick (mid-game))
1284 (IE! 0) ; disable interrupts
1285 (inject-item-assembly (write-memory-assembly))))
1287 (defn test-write-memory []
1288 (set-state! (write-memory))
1289 (dorun
1290 (dotimes [_ 5000]
1291 (view-memory (step @current-state) current-mode))))
1293 (def bytes-to-write 0xD383)
1294 (def start-point 0xD384)
1296 (defn print-blank-assembly
1297 [start end]
1298 (dorun
1299 (map
1300 #(println (format "0x00 ;%04X " %))
1301 (range start end))))
1303 (defn test-mode-2 []
1304 (->
1305 (write-memory)
1306 (view-memory frame-count)
1307 (step)
1308 (step [:a])
1309 (step [:b])
1310 (step [:start])
1311 (step [])
1312 (view-memory frame-count)))
1316 (defn dylan-test-mode
1317 ([] (dylan-test-mode (write-mem-dyl)))
1318 ([target-state]
1319 (let [
1320 v-blank-prev 54046
1321 btn-register 65280
1322 eggs 0xD374
1325 (->
1326 target-state
1328 (tick)
1329 (tick)
1330 (tick)
1331 (tick);; jumps back to beginning
1333 (tick)
1334 (tick)
1335 (tick)
1336 (tick)
1337 (tick)
1338 (tick)
1339 (tick)
1340 (tick)
1341 (tick)
1342 (tick)
1343 (tick)
1344 (tick)
1347 (tick)
1348 (tick)
1349 (tick)
1350 (tick)
1351 (tick)
1352 (tick)
1353 (tick)
1354 (tick)
1355 (tick)
1356 (tick)
1357 (tick)
1358 (tick)
1359 (tick)
1360 (tick)
1361 (tick)
1362 (tick)
1363 (tick)
1364 (tick)
1365 (tick)
1366 (tick)
1367 (tick) ;; just complemented A
1369 (tick)
1370 (DE! 0x0800)
1371 (AF! 0xCF00) ;; change inputs @ A
1372 (tick)
1373 (tick)
1374 (tick)
1375 (tick)
1376 (tick)
1378 ;;(view-memory eggs)
1379 (tick)
1380 (tick)
1381 ;;(view-memory eggs)
1382 (tick)
1383 (tick)
1384 (tick)
1385 (tick)
1387 (d-tick)
1390 ;;(view-memory btn-register)
1391 (view-register "A" A)
1392 (view-register "B" B)
1394 ;;(view-register "C" C)
1395 (view-register "D" D)
1396 (view-register "E" E)
1397 (view-register "H" H)
1398 (view-register "L" L)
1399 ))))
1406 (defn test-mode-4
1407 ([] (test-mode-4 (write-memory)))
1408 ([target-state]
1409 (->
1410 target-state
1411 (#(do (println "memory from 0xC00F to 0xC01F:"
1412 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1413 (view-memory current-mode)
1414 (step [])
1415 (step [])
1416 (step [])
1417 (#(do (println "after three steps") %))
1418 (view-memory current-mode)
1420 ;; Activate memory writing mode
1422 (#(do (println "step with [:a]") %))
1423 (step [:a])
1424 (view-memory current-mode)
1425 (view-memory bytes-to-write)
1426 (view-memory start-point-high)
1427 (view-memory start-point-low)
1429 ;; Specify four bytes to be written
1431 (#(do (println "step with [:select]")%))
1432 (step [:select])
1433 (view-memory current-mode)
1434 (view-memory bytes-to-write)
1435 (view-memory start-point-high)
1436 (view-memory start-point-low)
1438 ;; Specify target memory address as 0xC00F
1440 (#(do (println "step with [:u :d]")%))
1441 (step [:u :d])
1442 (view-memory current-mode)
1443 (view-memory bytes-to-write)
1444 (view-memory start-point-high)
1445 (view-memory start-point-low)
1447 (#(do (println "step with [:a :b :start :select]")%))
1448 (step [:a :b :start :select])
1449 (view-memory current-mode)
1450 (view-memory bytes-to-write)
1451 (view-memory start-point-high)
1452 (view-memory start-point-low)
1454 ;; Start reprogramming memory
1456 (#(do (println "step with [:a]")%))
1457 (step [:a])
1458 (view-memory current-mode)
1459 (view-memory bytes-written)
1461 (#(do (println "step with [:b]")%))
1462 (step [:b])
1463 (view-memory current-mode)
1464 (view-memory bytes-written)
1466 (#(do (println "step with [:a :b]")%))
1467 (step [:a :b])
1468 (view-memory current-mode)
1469 (view-memory bytes-written)
1471 (#(do (println "step with [:select]")%))
1472 (step [:select])
1473 (view-memory current-mode)
1474 (view-memory bytes-written)
1476 ;; Reprogramming done, program ready for more commands.
1478 (#(do (println "step with []")%))
1479 (step [])
1480 (view-memory current-mode)
1481 (view-memory bytes-written)
1483 (#(do (println "memory from 0xC00F to 0xC01F:"
1484 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))