view clojure/com/aurellem/assembly.clj @ 129:5e4feb77f2d8

removed literal 0xFFs from assembly code since they interfere with the item-list.
author Robert McIntyre <rlm@mit.edu>
date Sat, 17 Mar 2012 19:25:38 -0500
parents 203d64e16156
children 69f241de436d
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))))
467 (defn d2 []
468 (->
469 (write-mem-dyl)
470 (view-memory 0xD31F)
471 step step step step step
472 (view-memory 0xD31F)))
474 (defn dylan []
475 (->
476 (write-mem-dyl)
477 (tick)
478 (tick)
479 (tick)
480 (tick)
481 (tick)
482 (tick)
483 (tick)
484 (tick)
485 (tick)
486 (tick)
487 (tick)
488 (tick)
490 (tick)
491 (tick)
492 (tick)
493 (tick)
494 (tick)
496 (d-tick)
497 (view-register "A" A)
498 (view-register "B" B)
499 (view-register "C" C)
501 ))
506 (defn write-memory-assembly* []
507 [
508 0x18 ;; D31D
509 0x02
510 0x00 ;; frame-count D31F
511 0x00 ;; v-blank-prev D320
513 0xFA ;; load modes into A
514 0x41
515 0xFF
517 0x47
519 0xCB
520 0x2F
521 0x2F
523 0xA0
524 0xE6
525 0x01
526 0x47 ;; now B contains (VB==1)
528 0xFA ;; load v-blank-prev
529 0x20
530 0xD3
532 0x2F
534 0xA0
535 0x4F ;; now C contains increment?
537 0xFA ;; load frame count
538 0x1F
539 0xD3
541 0x81 ;; add A+C->A
542 0xEA ;; spit A --> fc
543 0x1F
544 0xD3
546 0x78 ;; B->A
548 0xEA ;; spit A --> vbprev
549 0x20
550 0xD3
552 0xC3 ;D40F ; go back to beginning
553 0x1D ;D410
554 0xD3 ;D411
555 ]
556 )
558 (defn write-mem-dyl []
559 (-> (tick (mid-game))
560 (IE! 0)
561 (inject-item-assembly (write-memory-assembly*))))
565 (defn write-memory-assembly []
566 [
567 ;; Main Timing Loop
568 ;; Constantly check for v-blank and Trigger main state machine on
569 ;; every transtion from v-blank to non-v-blank.
571 0x18 ; D31D ; Variable declaration
572 0x02 ; D31E
573 0x00 ; D31F ; frame-count
574 0x00 ; D320 ; v-blank-prev
576 0xF0 ; D321 ; load v-blank mode flags into A
577 0x41
578 0x00
581 ;; Branch dependent on v-blank. v-blank happens when the last two
582 ;; bits in A are "01"
583 0xCB ; D324
584 0x4F ; D325
586 0xC2 ; D326 ; if bit-1 is not 0, then
587 0x3E ; D327 ; GOTO non-v-blank.
588 0xD3 ; D328
590 0xCB ; D329
591 0x47 ; D32A
593 0xCA ; D32B ; if bit-0 is not 1, then
594 0x3E ; D32C ; GOTO non-v-blank.
595 0xD3 ; D32D
597 ;; V-Blank
598 ;; Activate state-machine if this is a transition event.
600 0xFA ; D32E ; load v-bank-prev into A
601 0x20 ; D32F
602 0xD3 ; D330
604 0xFE ; D331 ; compare A to 0. >--------\
605 0x00 ; D332 \
606 ; |
607 ;; set v-blank-prev to 1. |
608 0x3E ; D333 ; load 1 into A. |
609 0x01 ; D334 |
610 ; |
611 0xEA ; D335 ; load A into v-blank-prev |
612 0x20 ; D336 |
613 0xD3 ; D337 |
614 ; /
615 ;; if v-blank-prev was 0, activate state-machine <------/
616 0xCA ; D338 ; if v-blank-prev
617 0x46 ; D339 ; was 0,
618 0xD3 ; D33A ; GOTO state-machine
620 0xC3 ; D33B
621 0x1D ; D33C
622 0xD3 ; D33D ; GOTO beginning
623 ;; END V-blank
625 ;; Non-V-Blank
626 ;; Set v-blank-prev to 0
627 0x3E ; D33E ; load 0 into A
628 0x00 ; D33F
630 0xEA ; D340 ; load A into v-blank-prev
631 0x20 ; D341
632 0xD3 ; D342
634 0xC3 ; D343
635 0x1D ; D344
636 0xD3 ; D345 ; GOTO beginning
637 ;; END Not-V-Blank
640 ;; Main State Machine -- Input Section
641 ;; This is called once every frame.
642 ;; It collects input and uses it to drive the
643 ;; state transitions.
645 ;; Increment frame-count
646 0xFA ; D346 ; load frame-count into A
647 0x1F ; D347
648 0xD3 ; D348
650 0x3C ; D349 ; inc A
652 0xEA ; D34A
653 0x1F ; D34B ; load A into frame-count
654 0xD3 ; D34C
656 0x00 ; D34D ; glue :)
658 0x18 ;D34E ; skip next 3 bytes
659 0x03 ;D34F
660 ;D350
661 (Integer/parseInt "00100000" 2) ; select directional pad
662 ;D351
663 (Integer/parseInt "00010000" 2) ; select buttons
664 0x00 ;D352 ; input-number
666 ;; select directional pad; store low bits in B
668 0xFA ;D353 ; load (D350) into A
669 0x50 ;D354 -->
670 0xD3 ;D355 --> D350
672 0xE0 ;D356 ; load (A), which is
673 0x00 ;D357 --> ; 00010000, into FF00
674 0x00 ;D358 --> FF00 ;; NO-OP
676 0x06 ;D359
677 ;D35A
678 (Integer/parseInt "11110000" 2) ; "11110000" -> B
679 0xF0 ;D35B ; (FF00) -> A
680 0x00 ;D35C
681 0x00 ;D35D ;; NO-OP
683 0xCB ;D35E ; swap nybbles on A
684 0x37 ;D35F
685 0xA0 ;D360 ; (AND A B) -> A
686 0x47 ;D361 ; A -> B
688 ;; select buttons; store bottom bits in C
690 0xFA ;D362 ; load (D351) into A
691 0x51 ;D363 -->
692 0xD3 ;D364 --> D351
694 0xE0 ;D365 ; load (A), which is
695 0x00 ;D366 --> ; 00001000, into FF00
696 0x00 ;D367 --> FF00 ;; NO-OP
698 0x0E ;D368
699 ;D369
700 (Integer/parseInt "00001111" 2) ; "00001111" -> C
702 0xF0 ;D36A ; (FF00) -> A
703 0x00 ;D36B
704 0x00 ;D36C
706 0xA1 ;D36D ; (AND A C) -> A
707 0x4F ;D36E ; A -> C
709 ;; combine the B and C registers into the input number
710 0x79 ;D36F ; C -> A
711 0xB0 ;D370 ; (OR A B) -> A
712 0x2F ;D371 ; negate A
714 0xEA ;D372 ; store A into input-number
715 0x52 ;D373
716 0xD3 ;D374
718 0x00 ;D375
719 0x00 ;D376
720 0x00 ;D377
721 0x00 ;D378
722 0x00 ;D379
723 0x00 ;D37A
724 0x00 ;D37B ; these are here because
725 0x00 ;D37C ; I messed up :(
726 0x00 ;D37D
727 0x00 ;D37E
728 0x00 ;D37F
730 ;; beginning of main state machine
731 0x18 ;D380 ; Declaration of variables
732 0x05 ;D381 ; 5 variables:
733 0x00 ;D382 ; current-mode
734 0x00 ;D383 ; bytes-to-write
735 0x00 ;D384 ; bytes-written
736 0x00 ;D385 ; start-point-high
737 0x00 ;D386 ; start-point-low
740 ;; banch on current mode
741 0xFA ;D387 ; load current-mode (0xD382)
742 0x82 ;D388 ; into A
743 0xD3 ;D389
744 0x00 ;D38A
747 ;; GOTO Mode 0 (input-mode) if current-mode is 0
748 0xFE ;D38B
749 0x00 ;D38C ; compare A with 0x00
751 0xCA ;D38D ; goto Mode 0 if A == 0
752 0xA8 ;D38E
753 0xD3 ;D38F
755 ;; GOTO Mode 1 (set-length) if current-mode is 1
756 0xFE ;D390
757 0x01 ;D391 ; compare A with 0x01
759 0xCA ;D392
760 0xB1 ;D393
761 0xD3 ;D394 ; goto Mode 1 if A == 1
763 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
764 0xFE ;D395
765 0x02 ;D396 ; compare A with 0x02
767 0xCA ;D397
768 0xBF ;D398
769 0xD3 ;D399 ; goto Mode 2 if A == 2
771 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
772 0xFE ;D39A
773 0x03 ;D39B
775 0xCA ;D39C
776 0xCD ;D39D
777 0xD3 ;D39E ; goto Mode 3 if A == 3
779 ;; GOTO Mode 4 (write-memory) if current mode is 4
780 0xFE ;D39F
781 0x04 ;D3A0
783 0xCA ;D3A1
784 0xDB ;D3A2
785 0xD3 ;D3A3
787 0x00 ;D3A4
788 ;; End of Mode checking, goto beginning
789 0xC3 ;D3A5
790 0x1D ;D3A6
791 0xD3 ;D3A7
794 ;; Mode 0 -- input-mode mode
795 ;; means that we are waiting for a mode, so set the mode to
796 ;; whatever is currently in input-number. If nothing is
797 ;; entered, then the program stays in input-mode mode
799 ;; set current-mode to input-number
800 0xFA ;D3A8 ; load input-number (0xD352)
801 0x52 ;D3A9 ; into A
802 0xD3 ;D3AA
804 0xEA ;D3AB ; load A into current-mode
805 0x82 ;D3AC ; (0xD382)
806 0xD3 ;D3AD
808 0xC3 ;D3AE ; go back to beginning
809 0x1D ;D3AF
810 0xD3 ;D3B0
811 ;; End Mode 0
814 ;; Mode 1 -- set-length mode
815 ;; This is the header for writing things to memory.
816 ;; User specifies the number of bytes to write.
817 ;; Mode is auto advanced to Mode 2 after this mode
818 ;; completes.
820 ;; Set bytes left to write to input-number;
821 ;; set current-mode to 0x02.
822 0xFA ;D3B1 ; load input-number (0xD352)
823 0x52 ;D3B2 ; into A
824 0xD3 ;D3B3
826 0xEA ;D3B4 ; load A into bytes-left-to-write
827 0x83 ;D3B5 ; (0xD383)
828 0xD3 ;D3B6
830 0x3E ;D3B7 ; load 0x02 into A.
831 0x02 ;D3B8
833 0xEA ;D3B9 ; load A to current-mode
834 0x82 ;D3BA ; advancing from Mode 1 to
835 0xD3 ;D3BB ; Mode 2
837 0xC3 ;D3BC ; go back to beginning
838 0x1D ;D3BD
839 0xD3 ;D3BE
840 ;; End Mode 1
843 ;; Mode 2 -- set start-point-high mode
844 ;; Middle part of the header for writing things to memory.
845 ;; User specifies the start location in RAM to which
846 ;; data will be written.
847 ;; Mode is auto advanced to Mode 3 after this mode completes.
849 ;; Set start-point-high to input-number;
850 ;; set current mode to 0x03.
851 0xFA ;D3BF ; load input-number (0xD352)
852 0x52 ;D3C0 ; into A
853 0xD3 ;D3C1
855 0xEA ;D3C2 ; load A into start-point-high
856 0x85 ;D3C3 ; (0xD385)
857 0xD3 ;D3C4
859 0x3E ;D3C5 ; load 0x03 into A.
860 0x03 ;D3C6
862 0xEA ;D3C7 ; load A to current-mode,
863 0x82 ;D3C8 ; advancing from Mode 2 to
864 0xD3 ;D3C9 ; Mode 3.
866 0xC3 ;D3CA ; go back to beginning
867 0x1D ;D3CB
868 0xD3 ;D3CC
869 ;;End Mode 2
872 ;; Mode 3 -- set-start-point-low mode
873 ;; Final part of header for writing things to memory.
874 ;; User specifies the low bytes of 16 bit start-point.
876 ;; Set start-point-low to input-number;
877 ;; set current mode to 0x04
878 0xFA ;D3CD ; load input-number into A
879 0x52 ;D3CE
880 0xD3 ;D3CF
882 0xEA ;D3D0 ; load A into start-point-low
883 0x86 ;D3D1
884 0xD3 ;D3D2
886 0x3E ;D3D3 ; load 0x04 into A.
887 0x04 ;D3D4
889 0xEA ;D3D5 ; load A to current-mode,
890 0x82 ;D3D6 ; advancing from Mode 3 to
891 0xD3 ;D3D7 ; Mode 4.
893 0xC3 ;D3D8 ; go back to beginning
894 0x1D ;D3D9
895 0xD3 ;D3DA
897 ;; Mode 4 -- write bytes mode
899 ;; This is where RAM manipulation happens. User supplies
900 ;; bytes every frame, which are written sequentially to
901 ;; start-point until bytes-to-write have been written. Once
902 ;; bytes-to-write have been written, the mode is reset to 0.
904 ;; compare bytes-written with bytes-to-write.
905 ;; if they are the same, then reset mode to 0
907 0xFA ;D3DB ; load bytes-to-write into A
908 0x83 ;D3DC
909 0xD3 ;D3DD
911 0x47 ;D3DE ; load A into B
913 0xFA ;D3DF ; load bytes-written into A
914 0x84 ;D3E0
915 0xD3 ;D3E1
917 0xB8 ;D3E2 ; compare A with B
919 0xCA ;D3E3 ; if they are equal, go to cleanup
920 0x07 ;D3E4
921 0xD4 ;D3E5
923 ;; Write Memory Section
924 ;; Write the input-number, interpreted as an 8-bit number,
925 ;; into the current target register, determined by
926 ;; (+ start-point bytes-written).
927 ;; Then, increment bytes-written by 1.
929 0xFA ;D3E6 ; load start-point-high into A
930 0x85 ;D3E7
931 0xD3 ;D3E8
933 0x67 ;D3E9 ; load A into H
935 0xFA ;D3EA ; load start-point-low into A
936 0x86 ;D3EB
937 0xD3 ;D3EC
939 0x6F ;D3ED ; load A into L
941 0xFA ;D3EE ; load bytes-written into A
942 0x84 ;D3EF
943 0xD3 ;D3F0
945 0x00 ;D3F1 ; These are here because
946 0x00 ;D3F2 ; I screwed up again.
947 0x00 ;D3F3
949 0x85 ;D3F4 ; add L to A; store A in L.
950 0x6F ;D3F5
952 0x30 ;D3F6 ; If the addition overflowed,
953 0x01 ;D3F7
954 0x24 ;D3F8 ; increment H.
956 ;; Now, HL points to the correct place in memory
958 0xFA ;D3F9 ; load input-number into A
959 0x52 ;D3FA
960 0xD3 ;D3FB
962 0x77 ;D3FC ; load A into (HL)
964 0xFA ;D3FD ; load bytes-written into A
965 0x84 ;D3FE
966 0xD3 ;D3FF
968 0x3C ;D400 ; increment A
970 0xEA ;D401 ; load A into bytes-written
971 0x84 ;D402
972 0xD3 ;D403
974 0xC3 ;D404 ; go back to beginning.
975 0x1D ;D405
976 0xD3 ;D406
977 ;; End Write Memory Section
979 ;; Mode 4 Cleanup Section
980 ;; reset bytes-written to 0
981 ;; set mode to 0
982 0x3E ;D407 ; load 0 into A
983 0x00 ;D408
985 0xEA ;D409 ; load A into bytes-written
986 0x84 ;D40A
987 0xD3 ;D40B
989 0xEA ;D40C ; load A into current-mode
990 0x82 ;D40D
991 0xD3 ;D40E
993 0xC3 ;D40F ; go back to beginning
994 0x1D ;D410
995 0xD3 ;D411
997 ;; End Mode 4
999 ])
1003 (def frame-count 0xD31F)
1004 (def input 0xD352)
1005 (def current-mode 0xD382)
1006 (def bytes-to-write 0xD383)
1007 (def bytes-written 0xD384)
1008 (def start-point-high 0xD385)
1009 (def start-point-low 0xD386)
1013 (defn write-memory []
1014 (-> (tick (mid-game))
1015 (IE! 0) ; disable interrupts
1016 (inject-item-assembly (write-memory-assembly))))
1018 (defn test-write-memory []
1019 (set-state! (write-memory))
1020 (dorun
1021 (dotimes [_ 5000]
1022 (view-memory (step @current-state) current-mode))))
1024 (def bytes-to-write 0xD383)
1025 (def start-point 0xD384)
1027 (defn print-blank-assembly
1028 [start end]
1029 (dorun
1030 (map
1031 #(println (format "0x00 ;%04X " %))
1032 (range start end))))
1034 (defn test-mode-2 []
1035 (->
1036 (write-memory)
1037 (view-memory frame-count)
1038 (step)
1039 (step [:a])
1040 (step [:b])
1041 (step [:start])
1042 (step [])
1043 (view-memory frame-count)))
1045 (defn test-mode-4
1046 ([] (test-mode-4 (write-memory)))
1047 ([target-state]
1048 (->
1049 target-state
1050 (#(do (println "memory from 0xC00F to 0xC01F:"
1051 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1052 (view-memory current-mode)
1053 (step [])
1054 (step [])
1055 (step [])
1056 (#(do (println "after three steps") %))
1057 (view-memory current-mode)
1059 ;; Activate memory writing mode
1061 (#(do (println "step with [:a]") %))
1062 (step [:a])
1063 (view-memory current-mode)
1064 (view-memory bytes-to-write)
1065 (view-memory start-point-high)
1066 (view-memory start-point-low)
1068 ;; Specify four bytes to be written
1070 (#(do (println "step with [:select]")%))
1071 (step [:select])
1072 (view-memory current-mode)
1073 (view-memory bytes-to-write)
1074 (view-memory start-point-high)
1075 (view-memory start-point-low)
1077 ;; Specify target memory address as 0xC00F
1079 (#(do (println "step with [:u :d]")%))
1080 (step [:u :d])
1081 (view-memory current-mode)
1082 (view-memory bytes-to-write)
1083 (view-memory start-point-high)
1084 (view-memory start-point-low)
1086 (#(do (println "step with [:a :b :start :select]")%))
1087 (step [:a :b :start :select])
1088 (view-memory current-mode)
1089 (view-memory bytes-to-write)
1090 (view-memory start-point-high)
1091 (view-memory start-point-low)
1093 ;; Start reprogramming memory
1095 (#(do (println "step with [:a]")%))
1096 (step [:a])
1097 (view-memory current-mode)
1098 (view-memory bytes-written)
1100 (#(do (println "step with [:b]")%))
1101 (step [:b])
1102 (view-memory current-mode)
1103 (view-memory bytes-written)
1105 (#(do (println "step with [:a :b]")%))
1106 (step [:a :b])
1107 (view-memory current-mode)
1108 (view-memory bytes-written)
1110 (#(do (println "step with [:select]")%))
1111 (step [:select])
1112 (view-memory current-mode)
1113 (view-memory bytes-written)
1115 ;; Reprogramming done, program ready for more commands.
1117 (#(do (println "step with []")%))
1118 (step [])
1119 (view-memory current-mode)
1120 (view-memory bytes-written)
1122 (#(do (println "memory from 0xC00F to 0xC01F:"
1123 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))