view clojure/com/aurellem/assembly.clj @ 128:203d64e16156

dylan added some code
author Robert McIntyre <rlm@mit.edu>
date Sat, 17 Mar 2012 19:18:01 -0500
parents 901ee6b648da
children 5e4feb77f2d8
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 0xFA ; D321 ; load v-blank mode flags into A
577 0x41 ; D322
578 0xFF ; D323
580 ;; Branch dependent on v-blank. v-blank happens when the last two
581 ;; bits in A are "01"
582 0xCB ; D324
583 0x4F ; D325
585 0xC2 ; D326 ; if bit-1 is not 0, then
586 0x3E ; D327 ; GOTO non-v-blank.
587 0xD3 ; D328
589 0xCB ; D329
590 0x47 ; D32A
592 0xCA ; D32B ; if bit-0 is not 1, then
593 0x3E ; D32C ; GOTO non-v-blank.
594 0xD3 ; D32D
596 ;; V-Blank
597 ;; Activate state-machine if this is a transition event.
599 0xFA ; D32E ; load v-bank-prev into A
600 0x20 ; D32F
601 0xD3 ; D330
603 0xFE ; D331 ; compare A to 0. >--------\
604 0x00 ; D332 \
605 ; |
606 ;; set v-blank-prev to 1. |
607 0x3E ; D333 ; load 1 into A. |
608 0x01 ; D334 |
609 ; |
610 0xEA ; D335 ; load A into v-blank-prev |
611 0x20 ; D336 |
612 0xD3 ; D337 |
613 ; /
614 ;; if v-blank-prev was 0, activate state-machine <------/
615 0xCA ; D338 ; if v-blank-prev
616 0x46 ; D339 ; was 0,
617 0xD3 ; D33A ; GOTO state-machine
619 0xC3 ; D33B
620 0x1D ; D33C
621 0xD3 ; D33D ; GOTO beginning
622 ;; END V-blank
624 ;; Non-V-Blank
625 ;; Set v-blank-prev to 0
626 0x3E ; D33E ; load 0 into A
627 0x00 ; D33F
629 0xEA ; D340 ; load A into v-blank-prev
630 0x20 ; D341
631 0xD3 ; D342
633 0xC3 ; D343
634 0x1D ; D344
635 0xD3 ; D345 ; GOTO beginning
636 ;; END Not-V-Blank
639 ;; Main State Machine -- Input Section
640 ;; This is called once every frame.
641 ;; It collects input and uses it to drive the
642 ;; state transitions.
644 ;; Increment frame-count
645 0xFA ; D346 ; load frame-count into A
646 0x1F ; D347
647 0xD3 ; D348
649 0x3C ; D349 ; inc A
651 0xEA ; D34A
652 0x1F ; D34B ; load A into frame-count
653 0xD3 ; D34C
655 0x00 ; D34D ; glue :)
657 0x18 ;D34E ; skip next 3 bytes
658 0x03 ;D34F
659 ;D350
660 (Integer/parseInt "00100000" 2) ; select directional pad
661 ;D351
662 (Integer/parseInt "00010000" 2) ; select buttons
663 0x00 ;D352 ; input-number
665 ;; select directional pad; store low bits in B
667 0xFA ;D353 ; load (D350) into A
668 0x50 ;D354 -->
669 0xD3 ;D355 --> D350
671 0xEA ;D356 ; load (A), which is
672 0x00 ;D357 --> ; 00010000, into FF00
673 0xFF ;D358 --> FF00
675 0x06 ;D359
676 ;D35A
677 (Integer/parseInt "11110000" 2) ; "11110000" -> B
678 0xFA ;D35B ; (FF00) -> A
679 0x00 ;D35C
680 0xFF ;D35D
682 0xCB ;D35E ; swap nybbles on A
683 0x37 ;D35F
684 0xA0 ;D360 ; (AND A B) -> A
685 0x47 ;D361 ; A -> B
687 ;; select buttons; store bottom bits in C
689 0xFA ;D362 ; load (D351) into A
690 0x51 ;D363 -->
691 0xD3 ;D364 --> D351
693 0xEA ;D365 ; load (A), which is
694 0x00 ;D366 --> ; 00001000, into FF00
695 0xFF ;D367 --> FF00
697 0x0E ;D368
698 ;D369
699 (Integer/parseInt "00001111" 2) ; "00001111" -> C
701 0xFA ;D36A ; (FF00) -> A
702 0x00 ;D36B
703 0xFF ;D36C
705 0xA1 ;D36D ; (AND A C) -> A
706 0x4F ;D36E ; A -> C
708 ;; combine the B and C registers into the input number
709 0x79 ;D36F ; C -> A
710 0xB0 ;D370 ; (OR A B) -> A
711 0x2F ;D371 ; negate A
713 0xEA ;D372 ; store A into input-number
714 0x52 ;D373
715 0xD3 ;D374
717 0x00 ;D375
718 0x00 ;D376
719 0x00 ;D377
720 0x00 ;D378
721 0x00 ;D379
722 0x00 ;D37A
723 0x00 ;D37B ; these are here because
724 0x00 ;D37C ; I messed up :(
725 0x00 ;D37D
726 0x00 ;D37E
727 0x00 ;D37F
729 ;; beginning of main state machine
730 0x18 ;D380 ; Declaration of variables
731 0x05 ;D381 ; 5 variables:
732 0x00 ;D382 ; current-mode
733 0x00 ;D383 ; bytes-to-write
734 0x00 ;D384 ; bytes-written
735 0x00 ;D385 ; start-point-high
736 0x00 ;D386 ; start-point-low
739 ;; banch on current mode
740 0xFA ;D387 ; load current-mode (0xD382)
741 0x82 ;D388 ; into A
742 0xD3 ;D389
743 0x00 ;D38A
746 ;; GOTO Mode 0 (input-mode) if current-mode is 0
747 0xFE ;D38B
748 0x00 ;D38C ; compare A with 0x00
750 0xCA ;D38D ; goto Mode 0 if A == 0
751 0xA8 ;D38E
752 0xD3 ;D38F
754 ;; GOTO Mode 1 (set-length) if current-mode is 1
755 0xFE ;D390
756 0x01 ;D391 ; compare A with 0x01
758 0xCA ;D392
759 0xB1 ;D393
760 0xD3 ;D394 ; goto Mode 1 if A == 1
762 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
763 0xFE ;D395
764 0x02 ;D396 ; compare A with 0x02
766 0xCA ;D397
767 0xBF ;D398
768 0xD3 ;D399 ; goto Mode 2 if A == 2
770 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
771 0xFE ;D39A
772 0x03 ;D39B
774 0xCA ;D39C
775 0xCD ;D39D
776 0xD3 ;D39E ; goto Mode 3 if A == 3
778 ;; GOTO Mode 4 (write-memory) if current mode is 4
779 0xFE ;D39F
780 0x04 ;D3A0
782 0xCA ;D3A1
783 0xDB ;D3A2
784 0xD3 ;D3A3
786 0x00 ;D3A4
787 ;; End of Mode checking, goto beginning
788 0xC3 ;D3A5
789 0x1D ;D3A6
790 0xD3 ;D3A7
793 ;; Mode 0 -- input-mode mode
794 ;; means that we are waiting for a mode, so set the mode to
795 ;; whatever is currently in input-number. If nothing is
796 ;; entered, then the program stays in input-mode mode
798 ;; set current-mode to input-number
799 0xFA ;D3A8 ; load input-number (0xD352)
800 0x52 ;D3A9 ; into A
801 0xD3 ;D3AA
803 0xEA ;D3AB ; load A into current-mode
804 0x82 ;D3AC ; (0xD382)
805 0xD3 ;D3AD
807 0xC3 ;D3AE ; go back to beginning
808 0x1D ;D3AF
809 0xD3 ;D3B0
810 ;; End Mode 0
813 ;; Mode 1 -- set-length mode
814 ;; This is the header for writing things to memory.
815 ;; User specifies the number of bytes to write.
816 ;; Mode is auto advanced to Mode 2 after this mode
817 ;; completes.
819 ;; Set bytes left to write to input-number;
820 ;; set current-mode to 0x02.
821 0xFA ;D3B1 ; load input-number (0xD352)
822 0x52 ;D3B2 ; into A
823 0xD3 ;D3B3
825 0xEA ;D3B4 ; load A into bytes-left-to-write
826 0x83 ;D3B5 ; (0xD383)
827 0xD3 ;D3B6
829 0x3E ;D3B7 ; load 0x02 into A.
830 0x02 ;D3B8
832 0xEA ;D3B9 ; load A to current-mode
833 0x82 ;D3BA ; advancing from Mode 1 to
834 0xD3 ;D3BB ; Mode 2
836 0xC3 ;D3BC ; go back to beginning
837 0x1D ;D3BD
838 0xD3 ;D3BE
839 ;; End Mode 1
842 ;; Mode 2 -- set start-point-high mode
843 ;; Middle part of the header for writing things to memory.
844 ;; User specifies the start location in RAM to which
845 ;; data will be written.
846 ;; Mode is auto advanced to Mode 3 after this mode completes.
848 ;; Set start-point-high to input-number;
849 ;; set current mode to 0x03.
850 0xFA ;D3BF ; load input-number (0xD352)
851 0x52 ;D3C0 ; into A
852 0xD3 ;D3C1
854 0xEA ;D3C2 ; load A into start-point-high
855 0x85 ;D3C3 ; (0xD385)
856 0xD3 ;D3C4
858 0x3E ;D3C5 ; load 0x03 into A.
859 0x03 ;D3C6
861 0xEA ;D3C7 ; load A to current-mode,
862 0x82 ;D3C8 ; advancing from Mode 2 to
863 0xD3 ;D3C9 ; Mode 3.
865 0xC3 ;D3CA ; go back to beginning
866 0x1D ;D3CB
867 0xD3 ;D3CC
868 ;;End Mode 2
871 ;; Mode 3 -- set-start-point-low mode
872 ;; Final part of header for writing things to memory.
873 ;; User specifies the low bytes of 16 bit start-point.
875 ;; Set start-point-low to input-number;
876 ;; set current mode to 0x04
877 0xFA ;D3CD ; load input-number into A
878 0x52 ;D3CE
879 0xD3 ;D3CF
881 0xEA ;D3D0 ; load A into start-point-low
882 0x86 ;D3D1
883 0xD3 ;D3D2
885 0x3E ;D3D3 ; load 0x04 into A.
886 0x04 ;D3D4
888 0xEA ;D3D5 ; load A to current-mode,
889 0x82 ;D3D6 ; advancing from Mode 3 to
890 0xD3 ;D3D7 ; Mode 4.
892 0xC3 ;D3D8 ; go back to beginning
893 0x1D ;D3D9
894 0xD3 ;D3DA
896 ;; Mode 4 -- write bytes mode
898 ;; This is where RAM manipulation happens. User supplies
899 ;; bytes every frame, which are written sequentially to
900 ;; start-point until bytes-to-write have been written. Once
901 ;; bytes-to-write have been written, the mode is reset to 0.
903 ;; compare bytes-written with bytes-to-write.
904 ;; if they are the same, then reset mode to 0
906 0xFA ;D3DB ; load bytes-to-write into A
907 0x83 ;D3DC
908 0xD3 ;D3DD
910 0x47 ;D3DE ; load A into B
912 0xFA ;D3DF ; load bytes-written into A
913 0x84 ;D3E0
914 0xD3 ;D3E1
916 0xB8 ;D3E2 ; compare A with B
918 0xCA ;D3E3 ; if they are equal, go to cleanup
919 0x07 ;D3E4
920 0xD4 ;D3E5
922 ;; Write Memory Section
923 ;; Write the input-number, interpreted as an 8-bit number,
924 ;; into the current target register, determined by
925 ;; (+ start-point bytes-written).
926 ;; Then, increment bytes-written by 1.
928 0xFA ;D3E6 ; load start-point-high into A
929 0x85 ;D3E7
930 0xD3 ;D3E8
932 0x67 ;D3E9 ; load A into H
934 0xFA ;D3EA ; load start-point-low into A
935 0x86 ;D3EB
936 0xD3 ;D3EC
938 0x6F ;D3ED ; load A into L
940 0xFA ;D3EE ; load bytes-written into A
941 0x84 ;D3EF
942 0xD3 ;D3F0
944 0x00 ;D3F1 ; These are here because
945 0x00 ;D3F2 ; I screwed up again.
946 0x00 ;D3F3
948 0x85 ;D3F4 ; add L to A; store A in L.
949 0x6F ;D3F5
951 0x30 ;D3F6 ; If the addition overflowed,
952 0x01 ;D3F7
953 0x24 ;D3F8 ; increment H.
955 ;; Now, HL points to the correct place in memory
957 0xFA ;D3F9 ; load input-number into A
958 0x52 ;D3FA
959 0xD3 ;D3FB
961 0x77 ;D3FC ; load A into (HL)
963 0xFA ;D3FD ; load bytes-written into A
964 0x84 ;D3FE
965 0xD3 ;D3FF
967 0x3C ;D400 ; increment A
969 0xEA ;D401 ; load A into bytes-written
970 0x84 ;D402
971 0xD3 ;D403
973 0xC3 ;D404 ; go back to beginning.
974 0x1D ;D405
975 0xD3 ;D406
976 ;; End Write Memory Section
978 ;; Mode 4 Cleanup Section
979 ;; reset bytes-written to 0
980 ;; set mode to 0
981 0x3E ;D407 ; load 0 into A
982 0x00 ;D408
984 0xEA ;D409 ; load A into bytes-written
985 0x84 ;D40A
986 0xD3 ;D40B
988 0xEA ;D40C ; load A into current-mode
989 0x82 ;D40D
990 0xD3 ;D40E
992 0xC3 ;D40F ; go back to beginning
993 0x1D ;D410
994 0xD3 ;D411
996 ;; End Mode 4
998 ])
1002 (def frame-count 0xD31F)
1003 (def input 0xD352)
1004 (def current-mode 0xD382)
1005 (def bytes-to-write 0xD383)
1006 (def bytes-written 0xD384)
1007 (def start-point-high 0xD385)
1008 (def start-point-low 0xD386)
1012 (defn write-memory []
1013 (-> (tick (mid-game))
1014 (IE! 0) ; disable interrupts
1015 (inject-item-assembly (write-memory-assembly))))
1017 (defn test-write-memory []
1018 (set-state! (write-memory))
1019 (dorun
1020 (dotimes [_ 5000]
1021 (view-memory (step @current-state) current-mode))))
1023 (def bytes-to-write 0xD383)
1024 (def start-point 0xD384)
1026 (defn print-blank-assembly
1027 [start end]
1028 (dorun
1029 (map
1030 #(println (format "0x00 ;%04X " %))
1031 (range start end))))
1033 (defn test-mode-2 []
1034 (->
1035 (write-memory)
1036 (view-memory frame-count)
1037 (step)
1038 (step [:a])
1039 (step [:b])
1040 (step [:start])
1041 (step [])
1042 (view-memory frame-count)))
1044 (defn test-mode-4
1045 ([] (test-mode-4 (write-memory)))
1046 ([target-state]
1047 (->
1048 target-state
1049 (#(do (println "memory from 0xC00F to 0xC01F:"
1050 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1051 (view-memory current-mode)
1052 (step [])
1053 (step [])
1054 (step [])
1055 (#(do (println "after three steps") %))
1056 (view-memory current-mode)
1058 ;; Activate memory writing mode
1060 (#(do (println "step with [:a]") %))
1061 (step [:a])
1062 (view-memory current-mode)
1063 (view-memory bytes-to-write)
1064 (view-memory start-point-high)
1065 (view-memory start-point-low)
1067 ;; Specify four bytes to be written
1069 (#(do (println "step with [:select]")%))
1070 (step [:select])
1071 (view-memory current-mode)
1072 (view-memory bytes-to-write)
1073 (view-memory start-point-high)
1074 (view-memory start-point-low)
1076 ;; Specify target memory address as 0xC00F
1078 (#(do (println "step with [:u :d]")%))
1079 (step [:u :d])
1080 (view-memory current-mode)
1081 (view-memory bytes-to-write)
1082 (view-memory start-point-high)
1083 (view-memory start-point-low)
1085 (#(do (println "step with [:a :b :start :select]")%))
1086 (step [:a :b :start :select])
1087 (view-memory current-mode)
1088 (view-memory bytes-to-write)
1089 (view-memory start-point-high)
1090 (view-memory start-point-low)
1092 ;; Start reprogramming memory
1094 (#(do (println "step with [:a]")%))
1095 (step [:a])
1096 (view-memory current-mode)
1097 (view-memory bytes-written)
1099 (#(do (println "step with [:b]")%))
1100 (step [:b])
1101 (view-memory current-mode)
1102 (view-memory bytes-written)
1104 (#(do (println "step with [:a :b]")%))
1105 (step [:a :b])
1106 (view-memory current-mode)
1107 (view-memory bytes-written)
1109 (#(do (println "step with [:select]")%))
1110 (step [:select])
1111 (view-memory current-mode)
1112 (view-memory bytes-written)
1114 ;; Reprogramming done, program ready for more commands.
1116 (#(do (println "step with []")%))
1117 (step [])
1118 (view-memory current-mode)
1119 (view-memory bytes-written)
1121 (#(do (println "memory from 0xC00F to 0xC01F:"
1122 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))