view clojure/com/aurellem/gb/assembly.clj @ 176:95b2758dd517

wrote functions to read and write pokemon DV values and status
author Robert McIntyre <rlm@mit.edu>
date Wed, 21 Mar 2012 22:13:43 -0500
parents 5d9a7a0ca09a
children 5e34473ac774
line wrap: on
line source
1 (ns com.aurellem.gb.assembly
2 (:use (com.aurellem.gb gb-driver vbm util items))
3 (:import [com.aurellem.gb.gb_driver SaveState]))
5 (defn inject-assembly
6 ([^SaveState state
7 program-counter registers
8 assembly-code]
9 (let [scratch-memory (memory state)]
10 ;; inject assembly code
11 (dorun (map (fn [index val]
12 (aset scratch-memory index val))
13 (range program-counter
14 (+ program-counter (count assembly-code)))
15 assembly-code))
16 (-> state
17 (write-memory! scratch-memory)
18 (write-registers! registers)
19 (PC! program-counter)))))
21 (defn inject-item-assembly
22 ([^SaveState state assembly-code]
23 (inject-assembly state (inc item-list-start)
24 (registers state)
25 assembly-code))
26 ([assembly-code]
27 (inject-item-assembly @current-state assembly-code)))
29 (defn run-assembly
30 ([info-fn assembly n]
31 (let [final-state
32 (reduce (fn [state _]
33 (tick (info-fn state)))
34 (inject-item-assembly
35 (mid-game) assembly)
36 (range n))]
37 final-state))
38 ([assembly n]
39 (run-assembly d-tick assembly n)))
41 (def buttons-port 0xFF00)
43 (defn trace [state]
44 (loop [program-counters [(first (registers @current-state)) ]
45 opcodes [(aget (memory @current-state) (PC @current-state))]]
46 (let [frame-boundary?
47 (com.aurellem.gb.Gb/tick)]
48 (if frame-boundary?
49 [program-counters opcodes]
50 (recur
51 (conj program-counters
52 (first (registers @current-state)))
53 (conj opcodes
54 (aget (memory @current-state)
55 (PC @current-state))))))))
57 (defn print-trace [state n]
58 (let [[program-counters opcodes] (trace state)]
59 (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op)))
60 (take n program-counters)
61 (take n opcodes)))))
63 (defn good-trace []
64 (-> (mid-game) (tick) (IE! 0)
65 (set-inv-mem [0x00 0x00 0X00 0x00])
66 (PC! item-list-start)(print-interrupt)
67 (d-tick) (tick) (d-tick) (tick) (d-tick)))
69 (defn read-down-button []
70 (-> (tick (mid-game))
71 (IE! 0) ; disable interrupts
72 (inject-item-assembly
73 ;; write 00010000 to 0xFF00 to select joypad
74 [0x18 ;D31D ; jump over
75 0x01 ;D31E ; the next 8 bits
76 ;D31F
77 (Integer/parseInt "00100000" 2) ; data section
79 0xFA ;D320 ; load (D31F) into A
80 0x1F ;D321 -->
81 0xD3 ;D322 --> D31F
83 0xEA ;D323 ; load (A), which is
84 0x00 ;D324 --> ; 00010000, into FF00
85 0xFF ;D325 --> FF00
87 0x18 ;D326 ; this is the place where
88 0x01 ;D327 ; we will store whether
89 0x00 ;D328 ; "down" is pressed.
91 0xFA ;D329 ; (FF00) -> A
92 0x00 ;D32A
93 0xFF ;D32B
95 0xCB ;D32C ; Test whether "down"
96 0x5F ;D32D ; is pressed.
98 0x28 ;D32E ; if down is pressed,
99 0x03 ;D32F ; skip the next section
100 ; of code.
101 ;; down-is-not-pressed
102 0xC3 ;D330
103 0x1D ;D331 ; return to beginning
104 0xD3 ;D332
106 ;; down-is-pressed
107 0xEA ;D334 ; write A to D328 if
108 0x28 ;D335 ; "down" was pressed
109 0xD3 ;D336
111 0xC3 ;D330
112 0x1D ;D331 ; return to beginning
113 0xD3 ;D332
114 ])))
116 (defn test-read-down []
117 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
118 (view-memory (step (step (read-down-button))) 0xD328)))
120 (defn count-frames []
121 (-> (tick (mid-game))
122 (IE! 0) ; disable interrupts
123 (inject-item-assembly
124 [0x18 ;D31D ; jump over
125 0x02 ;D31E ; the next 2 bytes
126 0x00 ;D31F ; frame-count
127 0x00 ;D320 ; v-blank-prev
129 0xFA ;D321
130 0x41 ;D322 ; load (FF41) into A
131 0xFF ;D323 ; this contains mode flags
133 ;; if we're in v-blank, the bit-1 is 0
134 ;; and bit-2 is 1 Otherwise, it is not v-blank.
135 0xCB ;D324 ; test bit-1 of A
136 0x4F ;D325
138 0xC2 ;D326 ; if bit-1 is not 0
139 0x44 ;D327 ; GOTO not-v-blank
140 0xD3 ;D328
142 0xCB ;D329 ; test bit-0 of A
143 0x47 ;D32A
145 0xCA ;D32B ; if bit-0 is not 1
146 0x44 ;D32C ; GOTO not-v-blank
147 0xD3 ;D32D
148 ;;; in v-blank mode
149 ;; if v-blank-prev was 0,
150 ;; increment frame-count
152 0xFA ;D32E ; load v-blank-prev to A
153 0x20 ;D32F
154 0xD3 ;D330
156 0xCB ;D331
157 0x47 ;D332 ; test bit-0 of A
159 0x20 ;D333 ; skip next section
160 0x07 ;D334 ; if v-blank-prev was not zero
162 ;; v-blank was 0, increment frame-count
163 0xFA ;D335 ; load frame-count into A
164 0x1F ;D336
165 0xD3 ;D337
167 0x3C ;D338 ; inc A
169 0xEA ;D339 ; load A into frame-count
170 0x1F ;D33A
171 0xD3 ;D33B
173 ;; set v-blank-prev to 1
174 0x3E ;D33C ; load 1 into A
175 0x01 ;D33D
177 0xEA ;D33E ; load A into v-blank-prev
178 0x20 ;D33F
179 0xD3 ;D340
181 0xC3 ;D341 ; return to beginning
182 0x1D ;D342
183 0xD3 ;D343
185 ;;; not in v-blank mode
186 ;; set v-blank-prev to 0
187 0x3E ;D344 ; load 0 into A
188 0x00 ;D345
190 0xEA ;D346 ; load A into v-blank-prev
191 0x20 ;D347
192 0xD3 ;D348
194 0xC3 ;D349 ; return to beginning
195 0x1D ;D34A
196 0xD3 ;D34B
197 ])))
199 (defn step-count-frames []
200 (-> (read-down-button)
201 (d-tick)
202 (tick) ;; skip over data section
203 (d-tick)
204 (view-register "Register A" A)
205 (tick) ;; load-data into A
206 (view-register "Register A" A)
207 (d-tick)
208 (view-memory 0xFF00)
209 (tick) ;; load A into 0xFF00
210 (view-memory 0xFF00)
211 (d-tick)
212 (tick)
213 (d-tick)
214 (tick)
215 (d-tick)
216 (tick)
217 (d-tick)
218 (tick)
219 (d-tick)
220 (tick)
221 (d-tick)
222 (tick)
223 (print-inventory)))
225 (defn test-count-frames []
226 (= 255 (aget (memory ((apply comp (repeat 255 step))
227 (count-frames)))
228 0xD31F)))
230 ;; specs for main bootstrap program
231 ;; starts in "mode-select" mode
232 ;; Each button press takes place in a single frame.
233 ;; mode-select-mode takes one of the main buttons
234 ;; which selects one of up to eight modes
235 ;; mode 1 activated by the "A" button
236 ;; the next two button presses indicates the start
237 ;; memory location which to which the bootstrap
238 ;; program will write.
239 ;; This is done by using each of the eight buttons to
240 ;; spell out an 8 bit number. The order of buttons is
241 ;; [:d :u :l :r :start :select :b :a]
242 ;; [:a :start :l] --> 00101001
244 ;; the next button press determines how many bytes are to be
245 ;; written, starting at the start position.
247 ;; then, the actual bytes are entered and are written to the
248 ;; start address in sequence.
250 (defn input-number-assembly []
251 [0x18 ;D31D ; jump over
252 0x02 ;D31E ; the next 2 bytes
253 0x00 ;D31F ; frame-count
254 0x00 ;D320 ; v-blank-prev
256 0xFA ;D321
257 0x41 ;D322 ; load (FF41) into A
258 0xFF ;D323 ; this contains mode flags
260 ;; if we're in v-blank, the bit-1 is 0
261 ;; and bit-2 is 1 Otherwise, it is not v-blank.
262 0xCB ;D324 ; test bit-1 of A
263 0x4F ;D325
265 0xC2 ;D326 ; if bit-1 is not 0
266 0x44 ;D327 ; GOTO not-v-blank
267 0xD3 ;D328
269 0xCB ;D329 ; test bit-0 of A
270 0x47 ;D32A
272 0xCA ;D32B ; if bit-0 is not 1
273 0x44 ;D32C ; GOTO not-v-blank
274 0xD3 ;D32D
276 ;;; in v-blank mode
278 ;; if v-blank-prev was 0,
279 ;; increment frame-count
281 0xFA ;D32E ; load v-blank-prev to A
282 0x20 ;D32F
283 0xD3 ;D330
285 0xCB ;D331
286 0x47 ;D332 ; test bit-0 of A
288 0x20 ;D333 ; skip next section
289 0x07 ;D334 ; if v-blank-prev was not zero
291 ;; v-blank was 0, increment frame-count
292 0xFA ;D335 ; load frame-count into A
293 0x1F ;D336
294 0xD3 ;D337
296 0x3C ;D338 ; inc A
298 0xEA ;D339 ; load A into frame-count
299 0x1F ;D33A
300 0xD3 ;D33B
302 ;; set v-blank-prev to 1
303 0x3E ;D33C ; load 1 into A
304 0x01 ;D33D
306 0xEA ;D33E ; load A into v-blank-prev
307 0x20 ;D33F
308 0xD3 ;D340
310 0xC3 ;D341 ; GOTO input handling code
311 0x4E ;D342
312 0xD3 ;D343
314 ;;; not in v-blank mode
315 ;; set v-blank-prev to 0
316 0x3E ;D344 ; load 0 into A
317 0x00 ;D345
319 0xEA ;D346 ; load A into v-blank-prev
320 0x20 ;D347
321 0xD3 ;D348
323 0xC3 ;D349 ; return to beginning
324 0x1D ;D34A
325 0xD3 ;D34B
327 0x00 ;D34C ; these are here
328 0x00 ;D34D ; for glue
331 ;;; calculate input number based on button presses
332 0x18 ;D34E ; skip next 3 bytes
333 0x03 ;D34F
334 ;D350
335 (Integer/parseInt "00100000" 2) ; select directional pad
336 ;D351
337 (Integer/parseInt "00010000" 2) ; select buttons
338 0x00 ;D352 ; input-number
340 ;; select directional pad, store low bits in B
342 0xFA ;D353 ; load (D350) into A
343 0x50 ;D354 -->
344 0xD3 ;D355 --> D31F
346 0xEA ;D356 ; load A, which is
347 0x00 ;D357 --> ; 00010000, into FF00
348 0xFF ;D358 --> FF00
350 0x06 ;D359
351 ;D35A
352 (Integer/parseInt "11110000" 2) ; "11110000" -> B
353 0xFA ;D35B ; (FF00) -> A
354 0x00 ;D35C
355 0xFF ;D35D
357 0xCB ;D35E ; swap nybbles on A
358 0x37 ;D35F
359 0xA0 ;D360 ; (AND A B) -> A
360 0x47 ;D361 ; A -> B
362 ;; select buttons store bottom bits in C
364 0xFA ; ; load (D351) into A
365 0x51 ; -->
366 0xD3 ; --> D31F
368 0xEA ; ; load (A), which is
369 0x00 ; --> ; 00001000, into FF00
370 0xFF ; --> FF00
372 0x0E ;
373 (Integer/parseInt "00001111" 2) ; "00001111" -> C
375 0xFA ; ; (FF00) -> A
376 0x00 ;
377 0xFF ;
379 0xA1 ; ; (AND A C) -> A
380 0x4F ; ; A -> C
382 ;; combine the B and C registers into the input number
383 0x79 ; ; C -> A
384 0xB0 ; ; (OR A B) -> A
385 0x2F ; ; negate A
387 0xEA ; ; store A into input-number
388 0x52 ;
389 0xD3 ;
391 0xC3 ; ; return to beginning
392 0x1D ;
393 0xD3 ;
394 ])
398 (defn input-number []
399 (-> (tick (mid-game))
400 (IE! 0) ; disable interrupts
401 (inject-item-assembly (input-number-assembly))))
403 (defn test-input-number
404 "Input freestyle buttons and observe the effects at the repl."
405 []
406 (set-state! (input-number))
407 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))
409 (defn write-memory-assembly*
410 "A program for altering in-game memory by pressing buttons."
411 []
412 [
413 0xF3 ; stop interrupts
414 ;; --------- CLEANUP
415 0xAF ; zero A [D31E]
416 0x57 ; A->D; makes D=0.
418 ;; --------- FRAME METRONOME
419 0xF1 ;; pop AF (vblank prev) [D320]
421 0x2F ;; invert A
422 0x47 ;; A -> B
424 0xF0 ;; copy STAT into A
425 0x41
427 0xCB ;; swap A nybbles; now A_0 is (VB==1).
428 0x37
430 0xF5 ;; push AF (vbprev)
432 0xA0 ;; A & B --> A. Now A_0 contains "increment?"
434 0xCB ;; test A_0. this result will be used twice.
435 0x47
436 0x28 ;; end frame (JUMP) if A_0 = 0.
437 0x00 ;; TODO: set jump length
439 ;; -------- GET BUTTON INPUT
441 ;; btw, Z bit is now 1
442 ;; prepare to select bits
444 0x3E ;; load 0x20 into A, to measure dpad
445 0x20
447 0x06 ;; load 0x00 into B
448 0x00 ;; to initialize for "OR" loop
450 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]
451 0x00
453 0xF0 ;; load A from [FF00]
454 0x00
456 0xE6 ;; bitmask 00001111
457 0x0F
459 0xB0 ;; A or B --> A
461 0x28 ;; JUMP forward if Z=0
462 0x08
464 0x47 ;; A -> B
465 0xCB ;; swap B nybbles
466 0x30
468 0x3E ;; load 0x10 into A, to measure btns
469 0x10
471 0xBF ;; compare(A,A) sets Z=0
473 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]
474 0xED
477 ;; ------ TAKE ACTION BASED ON USER INPUT
479 ;; "input mode"
480 ;; mode 0x00 : select mode
481 ;; mode 0x08 : select bytes-to-write
482 ;; mode 0x10 : select hi-bit
483 ;; mode 0x18 : select lo-bit
485 ;; "output mode"
486 ;; mode 0x20 : write bytes
487 ;; mode 0xFF : jump PC
490 ;; registers
491 ;; D : mode select
492 ;; E : count of bytes to write
493 ;; H : address-high
494 ;; L : address-low
496 ;; now A contains the pressed keys
497 0x2F ; complement A, by request. [D34F]
499 0x47 ; A->B ;; now B contains the pressed keys
501 0xCB ; test bit 5 of D (are we in o/p mode?)
502 0x6A
503 0x28 ; if test == 0, skip this o/p section
504 0x13 ; JUMP
506 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)
507 0x42
508 0x28 ; if test == 0, skip the following command
509 0x01
511 ;; output mode I: moving the program counter
512 0xE9 ; ** move PC to (HL)
514 ;; output mode II: writing bytes
515 0xAF ; zero A
516 0xBB ; compare count to zero. finished writing?
517 0x28 ; if we are finished, jump back to cleanup
518 0x00 ; TODO: set jump length backwards.
520 ;; continue writing bytes
521 0x78 ;; B->A
522 0x22 ;; copy A to (HL) and increment HL.
523 0x18 ;; end frame. [goto D31F]
524 0xB6 ;; JUMP
527 ;; ---- end of o/p section
529 ;; i/p mode
530 ;; adhere to the mode discipline:
531 ;; D must be one of 0x00 0x08 0x10 0x18.
533 0x3E ;; load the constant 57 into A. [D369]
534 0x57
535 0x82 ;; add the mode to A
536 0xEA ;; store A into "thing to execute"
537 0x74
538 0xD3
540 0x3E ;; load the constant 8 into A
541 0x08
542 0x82 ;; add the mode to A
544 0x57 ;; store the incremented mode into D
545 0x78 ;; B->A; now A contains the pressed keys
547 0x00 ;; var: thing to execute [D374]
549 0x18 ;; end frame
550 0xA8 ;; JUMP
551 ]
552 )
554 (defn write-mem-dyl []
555 (-> (tick (mid-game))
556 (IE! 0)
557 (inject-item-assembly (write-memory-assembly*))))
560 (defn dylan* []
561 (->
562 (write-mem-dyl)
564 (tick)
565 (tick)
566 (tick)
567 (tick)
568 (tick)
569 (tick)
570 (tick)
571 (tick)
572 (tick)
573 (tick)
574 (tick)
575 (tick)
576 (tick)
577 (tick)
578 (tick)
579 (tick)
580 (tick)
581 (tick)
582 (tick)
583 (tick)
584 (tick)
585 (tick)
586 (tick)
587 (tick)
588 (tick)
589 (tick)
590 (tick)
591 (tick)
592 (tick)
593 (tick)
594 (tick)
595 (tick)
596 (tick)
597 (tick)
598 (tick)
599 (tick)
601 ;;(view-memory 0xD374)
602 (tick)
603 (tick)
604 (tick)
605 (tick)
606 (tick)
607 (tick)
608 (tick)
609 (tick)
610 (tick)
611 (tick)
612 (tick)
613 (tick)
614 (tick)
615 (tick)
616 (tick)
617 ;;(view-memory 0xD374)
618 (d-tick)
620 (view-register "A" A)
621 (view-register "B" B)
622 (view-register "C" C))
624 )
627 (defn dylan []
628 (->
629 (write-mem-dyl)
630 (tick)
631 (tick)
632 (tick)
633 (tick)
634 (tick)
635 (tick)
636 (tick)
637 (tick)
638 (tick)
639 (tick)
640 (tick)
641 (tick)
642 (tick)
643 (tick)
644 (tick) ;; first loop
647 (tick)
648 (tick)
649 (tick)
650 (tick)
651 (tick)
652 (tick)
653 (tick)
654 (tick)
655 (tick)
656 (tick)
657 (tick)
658 (tick)
659 (tick) ;; dpad bits
661 (tick)
662 (tick)
663 (tick)
664 (tick)
665 (tick)
666 (tick)
667 (tick)
668 (tick)
669 (d-tick)
673 (view-register "A" A)
674 (view-register "B" B)
675 (view-register "C" C)
677 ))
682 (defn d2 []
683 (->
684 (write-mem-dyl)
685 (view-memory 0xD31F)
686 step step step step step
687 (view-memory 0xD31F)))
708 (defn write-memory-assembly []
709 [
710 ;; Main Timing Loop
711 ;; Constantly check for v-blank and Trigger main state machine on
712 ;; every transtion from v-blank to non-v-blank.
714 0x18 ; D31D ; Variable declaration
715 0x02 ; D31E
716 0x00 ; D31F ; frame-count
717 0x00 ; D320 ; v-blank-prev
719 0xF0 ; D321 ; load v-blank mode flags into A
720 0x41
721 0x00
724 ;; Branch dependent on v-blank. v-blank happens when the last two
725 ;; bits in A are "01"
726 0xCB ; D324
727 0x4F ; D325
729 0xC2 ; D326 ; if bit-1 is not 0, then
730 0x3E ; D327 ; GOTO non-v-blank.
731 0xD3 ; D328
733 0xCB ; D329
734 0x47 ; D32A
736 0xCA ; D32B ; if bit-0 is not 1, then
737 0x3E ; D32C ; GOTO non-v-blank.
738 0xD3 ; D32D
740 ;; V-Blank
741 ;; Activate state-machine if this is a transition event.
743 0xFA ; D32E ; load v-bank-prev into A
744 0x20 ; D32F
745 0xD3 ; D330
747 0xFE ; D331 ; compare A to 0. >--------\
748 0x00 ; D332 \
749 ; |
750 ;; set v-blank-prev to 1. |
751 0x3E ; D333 ; load 1 into A. |
752 0x01 ; D334 |
753 ; |
754 0xEA ; D335 ; load A into v-blank-prev |
755 0x20 ; D336 |
756 0xD3 ; D337 |
757 ; /
758 ;; if v-blank-prev was 0, activate state-machine <------/
759 0xCA ; D338 ; if v-blank-prev
760 0x46 ; D339 ; was 0,
761 0xD3 ; D33A ; GOTO state-machine
763 0xC3 ; D33B
764 0x1D ; D33C
765 0xD3 ; D33D ; GOTO beginning
766 ;; END V-blank
768 ;; Non-V-Blank
769 ;; Set v-blank-prev to 0
770 0x3E ; D33E ; load 0 into A
771 0x00 ; D33F
773 0xEA ; D340 ; load A into v-blank-prev
774 0x20 ; D341
775 0xD3 ; D342
777 0xC3 ; D343
778 0x1D ; D344
779 0xD3 ; D345 ; GOTO beginning
780 ;; END Not-V-Blank
783 ;; Main State Machine -- Input Section
784 ;; This is called once every frame.
785 ;; It collects input and uses it to drive the
786 ;; state transitions.
788 ;; Increment frame-count
789 0xFA ; D346 ; load frame-count into A
790 0x1F ; D347
791 0xD3 ; D348
793 0x3C ; D349 ; inc A
795 0xEA ; D34A
796 0x1F ; D34B ; load A into frame-count
797 0xD3 ; D34C
799 0x00 ; D34D ; glue :)
801 0x18 ;D34E ; skip next 3 bytes
802 0x03 ;D34F
803 ;D350
804 (Integer/parseInt "00100000" 2) ; select directional pad
805 ;D351
806 (Integer/parseInt "00010000" 2) ; select buttons
807 0x00 ;D352 ; input-number
809 ;; select directional pad; store low bits in B
811 0xFA ;D353 ; load (D350) into A
812 0x50 ;D354 -->
813 0xD3 ;D355 --> D350
815 0xE0 ;D356 ; load (A), which is
816 0x00 ;D357 --> ; 00010000, into FF00
817 0x00 ;D358 --> FF00 ;; NO-OP
819 0x06 ;D359
820 ;D35A
821 (Integer/parseInt "11110000" 2) ; "11110000" -> B
822 0xF0 ;D35B ; (FF00) -> A
823 0x00 ;D35C
824 0x00 ;D35D ;; NO-OP
826 0xCB ;D35E ; swap nybbles on A
827 0x37 ;D35F
828 0xA0 ;D360 ; (AND A B) -> A
829 0x47 ;D361 ; A -> B
831 ;; select buttons; store bottom bits in C
833 0xFA ;D362 ; load (D351) into A
834 0x51 ;D363 -->
835 0xD3 ;D364 --> D351
837 0xE0 ;D365 ; load (A), which is
838 0x00 ;D366 --> ; 00001000, into FF00
839 0x00 ;D367 --> FF00 ;; NO-OP
841 0x0E ;D368
842 ;D369
843 (Integer/parseInt "00001111" 2) ; "00001111" -> C
845 0xF0 ;D36A ; (FF00) -> A
846 0x00 ;D36B
847 0x00 ;D36C
849 0xA1 ;D36D ; (AND A C) -> A
850 0x4F ;D36E ; A -> C
852 ;; combine the B and C registers into the input number
853 0x79 ;D36F ; C -> A
854 0xB0 ;D370 ; (OR A B) -> A
855 0x2F ;D371 ; negate A
857 0xEA ;D372 ; store A into input-number
858 0x52 ;D373
859 0xD3 ;D374
861 0x00 ;D375
862 0x00 ;D376
863 0x00 ;D377
864 0x00 ;D378
865 0x00 ;D379
866 0x00 ;D37A
867 0x00 ;D37B ; these are here because
868 0x00 ;D37C ; I messed up :(
869 0x00 ;D37D
870 0x00 ;D37E
871 0x00 ;D37F
873 ;; beginning of main state machine
874 0x18 ;D380 ; Declaration of variables
875 0x05 ;D381 ; 5 variables:
876 0x00 ;D382 ; current-mode
877 0x00 ;D383 ; bytes-to-write
878 0x00 ;D384 ; bytes-written
879 0x00 ;D385 ; start-point-high
880 0x00 ;D386 ; start-point-low
883 ;; banch on current mode
884 0xFA ;D387 ; load current-mode (0xD382)
885 0x82 ;D388 ; into A
886 0xD3 ;D389
887 0x00 ;D38A
890 ;; GOTO Mode 0 (input-mode) if current-mode is 0
891 0xFE ;D38B
892 0x00 ;D38C ; compare A with 0x00
894 0xCA ;D38D ; goto Mode 0 if A == 0
895 0xA8 ;D38E
896 0xD3 ;D38F
898 ;; GOTO Mode 1 (set-length) if current-mode is 1
899 0xFE ;D390
900 0x01 ;D391 ; compare A with 0x01
902 0xCA ;D392
903 0xB1 ;D393
904 0xD3 ;D394 ; goto Mode 1 if A == 1
906 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
907 0xFE ;D395
908 0x02 ;D396 ; compare A with 0x02
910 0xCA ;D397
911 0xBF ;D398
912 0xD3 ;D399 ; goto Mode 2 if A == 2
914 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
915 0xFE ;D39A
916 0x03 ;D39B
918 0xCA ;D39C
919 0xCD ;D39D
920 0xD3 ;D39E ; goto Mode 3 if A == 3
922 ;; GOTO Mode 4 (write-memory) if current mode is 4
923 0xFE ;D39F
924 0x04 ;D3A0
926 0xCA ;D3A1
927 0xDB ;D3A2
928 0xD3 ;D3A3
930 0x00 ;D3A4
931 ;; End of Mode checking, goto beginning
932 0xC3 ;D3A5
933 0x1D ;D3A6
934 0xD3 ;D3A7
937 ;; Mode 0 -- input-mode mode
938 ;; means that we are waiting for a mode, so set the mode to
939 ;; whatever is currently in input-number. If nothing is
940 ;; entered, then the program stays in input-mode mode
942 ;; set current-mode to input-number
943 0xFA ;D3A8 ; load input-number (0xD352)
944 0x52 ;D3A9 ; into A
945 0xD3 ;D3AA
947 0xEA ;D3AB ; load A into current-mode
948 0x82 ;D3AC ; (0xD382)
949 0xD3 ;D3AD
951 0xC3 ;D3AE ; go back to beginning
952 0x1D ;D3AF
953 0xD3 ;D3B0
954 ;; End Mode 0
957 ;; Mode 1 -- set-length mode
958 ;; This is the header for writing things to memory.
959 ;; User specifies the number of bytes to write.
960 ;; Mode is auto advanced to Mode 2 after this mode
961 ;; completes.
963 ;; Set bytes left to write to input-number;
964 ;; set current-mode to 0x02.
965 0xFA ;D3B1 ; load input-number (0xD352)
966 0x52 ;D3B2 ; into A
967 0xD3 ;D3B3
969 0xEA ;D3B4 ; load A into bytes-left-to-write
970 0x83 ;D3B5 ; (0xD383)
971 0xD3 ;D3B6
973 0x3E ;D3B7 ; load 0x02 into A.
974 0x02 ;D3B8
976 0xEA ;D3B9 ; load A to current-mode
977 0x82 ;D3BA ; advancing from Mode 1 to
978 0xD3 ;D3BB ; Mode 2
980 0xC3 ;D3BC ; go back to beginning
981 0x1D ;D3BD
982 0xD3 ;D3BE
983 ;; End Mode 1
986 ;; Mode 2 -- set start-point-high mode
987 ;; Middle part of the header for writing things to memory.
988 ;; User specifies the start location in RAM to which
989 ;; data will be written.
990 ;; Mode is auto advanced to Mode 3 after this mode completes.
992 ;; Set start-point-high to input-number;
993 ;; set current mode to 0x03.
994 0xFA ;D3BF ; load input-number (0xD352)
995 0x52 ;D3C0 ; into A
996 0xD3 ;D3C1
998 0xEA ;D3C2 ; load A into start-point-high
999 0x85 ;D3C3 ; (0xD385)
1000 0xD3 ;D3C4
1002 0x3E ;D3C5 ; load 0x03 into A.
1003 0x03 ;D3C6
1005 0xEA ;D3C7 ; load A to current-mode,
1006 0x82 ;D3C8 ; advancing from Mode 2 to
1007 0xD3 ;D3C9 ; Mode 3.
1009 0xC3 ;D3CA ; go back to beginning
1010 0x1D ;D3CB
1011 0xD3 ;D3CC
1012 ;;End Mode 2
1015 ;; Mode 3 -- set-start-point-low mode
1016 ;; Final part of header for writing things to memory.
1017 ;; User specifies the low bytes of 16 bit start-point.
1019 ;; Set start-point-low to input-number;
1020 ;; set current mode to 0x04
1021 0xFA ;D3CD ; load input-number into A
1022 0x52 ;D3CE
1023 0xD3 ;D3CF
1025 0xEA ;D3D0 ; load A into start-point-low
1026 0x86 ;D3D1
1027 0xD3 ;D3D2
1029 0x3E ;D3D3 ; load 0x04 into A.
1030 0x04 ;D3D4
1032 0xEA ;D3D5 ; load A to current-mode,
1033 0x82 ;D3D6 ; advancing from Mode 3 to
1034 0xD3 ;D3D7 ; Mode 4.
1036 0xC3 ;D3D8 ; go back to beginning
1037 0x1D ;D3D9
1038 0xD3 ;D3DA
1040 ;; Mode 4 -- write bytes mode
1042 ;; This is where RAM manipulation happens. User supplies
1043 ;; bytes every frame, which are written sequentially to
1044 ;; start-point until bytes-to-write have been written. Once
1045 ;; bytes-to-write have been written, the mode is reset to 0.
1047 ;; compare bytes-written with bytes-to-write.
1048 ;; if they are the same, then reset mode to 0
1050 0xFA ;D3DB ; load bytes-to-write into A
1051 0x83 ;D3DC
1052 0xD3 ;D3DD
1054 0x47 ;D3DE ; load A into B
1056 0xFA ;D3DF ; load bytes-written into A
1057 0x84 ;D3E0
1058 0xD3 ;D3E1
1060 0xB8 ;D3E2 ; compare A with B
1062 0xCA ;D3E3 ; if they are equal, go to cleanup
1063 0x07 ;D3E4
1064 0xD4 ;D3E5
1066 ;; Write Memory Section
1067 ;; Write the input-number, interpreted as an 8-bit number,
1068 ;; into the current target register, determined by
1069 ;; (+ start-point bytes-written).
1070 ;; Then, increment bytes-written by 1.
1072 0xFA ;D3E6 ; load start-point-high into A
1073 0x85 ;D3E7
1074 0xD3 ;D3E8
1076 0x67 ;D3E9 ; load A into H
1078 0xFA ;D3EA ; load start-point-low into A
1079 0x86 ;D3EB
1080 0xD3 ;D3EC
1082 0x6F ;D3ED ; load A into L
1084 0xFA ;D3EE ; load bytes-written into A
1085 0x84 ;D3EF
1086 0xD3 ;D3F0
1088 0x00 ;D3F1 ; These are here because
1089 0x00 ;D3F2 ; I screwed up again.
1090 0x00 ;D3F3
1092 0x85 ;D3F4 ; add L to A; store A in L.
1093 0x6F ;D3F5
1095 0x30 ;D3F6 ; If the addition overflowed,
1096 0x01 ;D3F7
1097 0x24 ;D3F8 ; increment H.
1099 ;; Now, HL points to the correct place in memory
1101 0xFA ;D3F9 ; load input-number into A
1102 0x52 ;D3FA
1103 0xD3 ;D3FB
1105 0x77 ;D3FC ; load A into (HL)
1107 0xFA ;D3FD ; load bytes-written into A
1108 0x84 ;D3FE
1109 0xD3 ;D3FF
1111 0x3C ;D400 ; increment A
1113 0xEA ;D401 ; load A into bytes-written
1114 0x84 ;D402
1115 0xD3 ;D403
1117 0xC3 ;D404 ; go back to beginning.
1118 0x1D ;D405
1119 0xD3 ;D406
1120 ;; End Write Memory Section
1122 ;; Mode 4 Cleanup Section
1123 ;; reset bytes-written to 0
1124 ;; set mode to 0
1125 0x3E ;D407 ; load 0 into A
1126 0x00 ;D408
1128 0xEA ;D409 ; load A into bytes-written
1129 0x84 ;D40A
1130 0xD3 ;D40B
1132 0xEA ;D40C ; load A into current-mode
1133 0x82 ;D40D
1134 0xD3 ;D40E
1136 0xC3 ;D40F ; go back to beginning
1137 0x1D ;D410
1138 0xD3 ;D411
1140 ;; End Mode 4
1142 ])
1146 (def frame-count 0xD31F)
1147 (def input 0xD352)
1148 (def current-mode 0xD382)
1149 (def bytes-to-write 0xD383)
1150 (def bytes-written 0xD384)
1151 (def start-point-high 0xD385)
1152 (def start-point-low 0xD386)
1156 (defn write-memory []
1157 (-> (tick (mid-game))
1158 (IE! 0) ; disable interrupts
1159 (inject-item-assembly (write-memory-assembly))))
1161 (defn test-write-memory []
1162 (set-state! (write-memory))
1163 (dorun
1164 (dotimes [_ 5000]
1165 (view-memory (step @current-state) current-mode))))
1167 (def bytes-to-write 0xD383)
1168 (def start-point 0xD384)
1170 (defn print-blank-assembly
1171 [start end]
1172 (dorun
1173 (map
1174 #(println (format "0x00 ;%04X " %))
1175 (range start end))))
1177 (defn test-mode-2 []
1178 (->
1179 (write-memory)
1180 (view-memory frame-count)
1181 (step)
1182 (step [:a])
1183 (step [:b])
1184 (step [:start])
1185 (step [])
1186 (view-memory frame-count)))
1190 (defn dylan-test-mode
1191 ([] (dylan-test-mode (write-mem-dyl)))
1192 ([target-state]
1193 (let [
1194 v-blank-prev 54046
1195 btn-register 65280
1196 eggs 0xD374
1199 (->
1200 target-state
1202 (tick)
1203 (tick)
1204 (tick)
1205 (tick);; jumps back to beginning
1207 (tick)
1208 (tick)
1209 (tick)
1210 (tick)
1211 (tick)
1212 (tick)
1213 (tick)
1214 (tick)
1215 (tick)
1216 (tick)
1217 (tick)
1218 (tick)
1221 (tick)
1222 (tick)
1223 (tick)
1224 (tick)
1225 (tick)
1226 (tick)
1227 (tick)
1228 (tick)
1229 (tick)
1230 (tick)
1231 (tick)
1232 (tick)
1233 (tick)
1234 (tick)
1235 (tick)
1236 (tick)
1237 (tick)
1238 (tick)
1239 (tick)
1240 (tick)
1241 (tick) ;; just complemented A
1243 (tick)
1244 (DE! 0x1800)
1245 (AF! 0x7700) ;; change inputs @ A
1246 (tick)
1247 (tick)
1248 (tick)
1249 (tick)
1250 (tick)
1252 ;;(view-memory eggs)
1253 (tick)
1254 (tick)
1255 ;;(view-memory eggs)
1256 (tick)
1257 (tick)
1258 (tick)
1259 (tick)
1260 (tick)
1261 (tick)
1262 (d-tick)
1265 ;;(view-memory btn-register)
1266 (view-register "A" A)
1267 (view-register "B" B)
1269 ;;(view-register "C" C)
1270 (view-register "D" D)
1271 (view-register "E" E)
1272 (view-register "H" H)
1273 (view-register "L" L)
1274 ))))
1278 (defn drive-dylan []
1279 (-> (write-mem-dyl)
1280 (#(do (println "memory from 0xC00F to 0xC01F:"
1281 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1282 (step [])
1283 (step [])
1284 (step [])
1285 (step [:start])
1286 (step [:select])
1287 (step [:u :d])
1288 (step [:a :b :start :select])
1289 (step [:a])
1290 (step [:b])
1291 (step [:a :b])
1292 (step [:select])
1293 (step [])
1294 (step [])
1295 (step [])
1296 (#(do (println "memory from 0xC00F to 0xC01F:"
1297 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1298 ))
1300 (defn test-mode-4
1301 ([] (test-mode-4 (write-memory)))
1302 ([target-state]
1303 (->
1304 target-state
1305 (#(do (println "memory from 0xC00F to 0xC01F:"
1306 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1307 (view-memory current-mode)
1308 (step [])
1309 (step [])
1310 (step [])
1311 (#(do (println "after three steps") %))
1312 (view-memory current-mode)
1314 ;; Activate memory writing mode
1316 (#(do (println "step with [:a]") %))
1317 (step [:a])
1318 (view-memory current-mode)
1319 (view-memory bytes-to-write)
1320 (view-memory start-point-high)
1321 (view-memory start-point-low)
1323 ;; Specify four bytes to be written
1325 (#(do (println "step with [:select]")%))
1326 (step [:select])
1327 (view-memory current-mode)
1328 (view-memory bytes-to-write)
1329 (view-memory start-point-high)
1330 (view-memory start-point-low)
1332 ;; Specify target memory address as 0xC00F
1334 (#(do (println "step with [:u :d]")%))
1335 (step [:u :d])
1336 (view-memory current-mode)
1337 (view-memory bytes-to-write)
1338 (view-memory start-point-high)
1339 (view-memory start-point-low)
1341 (#(do (println "step with [:a :b :start :select]")%))
1342 (step [:a :b :start :select])
1343 (view-memory current-mode)
1344 (view-memory bytes-to-write)
1345 (view-memory start-point-high)
1346 (view-memory start-point-low)
1348 ;; Start reprogramming memory
1350 (#(do (println "step with [:a]")%))
1351 (step [:a])
1352 (view-memory current-mode)
1353 (view-memory bytes-written)
1355 (#(do (println "step with [:b]")%))
1356 (step [:b])
1357 (view-memory current-mode)
1358 (view-memory bytes-written)
1360 (#(do (println "step with [:a :b]")%))
1361 (step [:a :b])
1362 (view-memory current-mode)
1363 (view-memory bytes-written)
1365 (#(do (println "step with [:select]")%))
1366 (step [:select])
1367 (view-memory current-mode)
1368 (view-memory bytes-written)
1370 ;; Reprogramming done, program ready for more commands.
1372 (#(do (println "step with []")%))
1373 (step [])
1374 (view-memory current-mode)
1375 (view-memory bytes-written)
1377 (#(do (println "memory from 0xC00F to 0xC01F:"
1378 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))