view clojure/com/aurellem/assembly.clj @ 132:d16cf9d829dd

converted rival-name letter-map to hexadecimal
author Robert McIntyre <rlm@mit.edu>
date Sat, 17 Mar 2012 21:32:29 -0500
parents 7f7cc8858d2e
children eb6ba88088d3
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))))
470 (defn write-memory-assembly* []
471 [
472 0x18 ;; D31D
473 0x02
474 0x00 ;; frame-count D31F
475 0x00 ;; v-blank-prev D320
477 0xFA ;; load modes into A
478 0x41
479 0xFF
481 0x47
483 0xCB
484 0x2F
485 0x2F
487 0xA0
488 0xE6
489 0x01
490 0x47 ;; now B contains (VB==1)
492 0xFA ;; load v-blank-prev
493 0x20
494 0xD3
496 0x2F
498 0xA0
499 0x4F ;; now C contains increment?
501 0xFA ;; load frame count
502 0x1F
503 0xD3
505 0x81 ;; add A+C->A
506 0xEA ;; spit A --> fc
507 0x1F
508 0xD3
510 0x78 ;; B->A
512 0xEA ;; spit A --> vbprev
513 0x20
514 0xD3
516 0xC3 ;D40F ; go back to beginning
517 0x1D ;D410
518 0xD3 ;D411
519 ]
520 )
522 (defn write-mem-dyl []
523 (-> (tick (mid-game))
524 (IE! 0)
525 (inject-item-assembly (write-memory-assembly*))))
528 (defn d2 []
529 (->
530 (write-mem-dyl)
531 (view-memory 0xD31F)
532 step step step step step
533 (view-memory 0xD31F)))
535 (defn dylan []
536 (->
537 (write-mem-dyl)
538 (tick)
539 (tick)
540 (tick)
541 (tick)
542 (tick)
543 (tick)
544 (tick)
545 (tick)
546 (tick)
547 (tick)
548 (tick)
549 (tick)
551 (tick)
552 (tick)
553 (tick)
554 (tick)
555 (tick)
557 (d-tick)
558 (view-register "A" A)
559 (view-register "B" B)
560 (view-register "C" C)
562 ))
567 (defn write-memory-assembly []
568 [
569 ;; Main Timing Loop
570 ;; Constantly check for v-blank and Trigger main state machine on
571 ;; every transtion from v-blank to non-v-blank.
573 0x18 ; D31D ; Variable declaration
574 0x02 ; D31E
575 0x00 ; D31F ; frame-count
576 0x00 ; D320 ; v-blank-prev
578 0xF0 ; D321 ; load v-blank mode flags into A
579 0x41
580 0x00
583 ;; Branch dependent on v-blank. v-blank happens when the last two
584 ;; bits in A are "01"
585 0xCB ; D324
586 0x4F ; D325
588 0xC2 ; D326 ; if bit-1 is not 0, then
589 0x3E ; D327 ; GOTO non-v-blank.
590 0xD3 ; D328
592 0xCB ; D329
593 0x47 ; D32A
595 0xCA ; D32B ; if bit-0 is not 1, then
596 0x3E ; D32C ; GOTO non-v-blank.
597 0xD3 ; D32D
599 ;; V-Blank
600 ;; Activate state-machine if this is a transition event.
602 0xFA ; D32E ; load v-bank-prev into A
603 0x20 ; D32F
604 0xD3 ; D330
606 0xFE ; D331 ; compare A to 0. >--------\
607 0x00 ; D332 \
608 ; |
609 ;; set v-blank-prev to 1. |
610 0x3E ; D333 ; load 1 into A. |
611 0x01 ; D334 |
612 ; |
613 0xEA ; D335 ; load A into v-blank-prev |
614 0x20 ; D336 |
615 0xD3 ; D337 |
616 ; /
617 ;; if v-blank-prev was 0, activate state-machine <------/
618 0xCA ; D338 ; if v-blank-prev
619 0x46 ; D339 ; was 0,
620 0xD3 ; D33A ; GOTO state-machine
622 0xC3 ; D33B
623 0x1D ; D33C
624 0xD3 ; D33D ; GOTO beginning
625 ;; END V-blank
627 ;; Non-V-Blank
628 ;; Set v-blank-prev to 0
629 0x3E ; D33E ; load 0 into A
630 0x00 ; D33F
632 0xEA ; D340 ; load A into v-blank-prev
633 0x20 ; D341
634 0xD3 ; D342
636 0xC3 ; D343
637 0x1D ; D344
638 0xD3 ; D345 ; GOTO beginning
639 ;; END Not-V-Blank
642 ;; Main State Machine -- Input Section
643 ;; This is called once every frame.
644 ;; It collects input and uses it to drive the
645 ;; state transitions.
647 ;; Increment frame-count
648 0xFA ; D346 ; load frame-count into A
649 0x1F ; D347
650 0xD3 ; D348
652 0x3C ; D349 ; inc A
654 0xEA ; D34A
655 0x1F ; D34B ; load A into frame-count
656 0xD3 ; D34C
658 0x00 ; D34D ; glue :)
660 0x18 ;D34E ; skip next 3 bytes
661 0x03 ;D34F
662 ;D350
663 (Integer/parseInt "00100000" 2) ; select directional pad
664 ;D351
665 (Integer/parseInt "00010000" 2) ; select buttons
666 0x00 ;D352 ; input-number
668 ;; select directional pad; store low bits in B
670 0xFA ;D353 ; load (D350) into A
671 0x50 ;D354 -->
672 0xD3 ;D355 --> D350
674 0xE0 ;D356 ; load (A), which is
675 0x00 ;D357 --> ; 00010000, into FF00
676 0x00 ;D358 --> FF00 ;; NO-OP
678 0x06 ;D359
679 ;D35A
680 (Integer/parseInt "11110000" 2) ; "11110000" -> B
681 0xF0 ;D35B ; (FF00) -> A
682 0x00 ;D35C
683 0x00 ;D35D ;; NO-OP
685 0xCB ;D35E ; swap nybbles on A
686 0x37 ;D35F
687 0xA0 ;D360 ; (AND A B) -> A
688 0x47 ;D361 ; A -> B
690 ;; select buttons; store bottom bits in C
692 0xFA ;D362 ; load (D351) into A
693 0x51 ;D363 -->
694 0xD3 ;D364 --> D351
696 0xE0 ;D365 ; load (A), which is
697 0x00 ;D366 --> ; 00001000, into FF00
698 0x00 ;D367 --> FF00 ;; NO-OP
700 0x0E ;D368
701 ;D369
702 (Integer/parseInt "00001111" 2) ; "00001111" -> C
704 0xF0 ;D36A ; (FF00) -> A
705 0x00 ;D36B
706 0x00 ;D36C
708 0xA1 ;D36D ; (AND A C) -> A
709 0x4F ;D36E ; A -> C
711 ;; combine the B and C registers into the input number
712 0x79 ;D36F ; C -> A
713 0xB0 ;D370 ; (OR A B) -> A
714 0x2F ;D371 ; negate A
716 0xEA ;D372 ; store A into input-number
717 0x52 ;D373
718 0xD3 ;D374
720 0x00 ;D375
721 0x00 ;D376
722 0x00 ;D377
723 0x00 ;D378
724 0x00 ;D379
725 0x00 ;D37A
726 0x00 ;D37B ; these are here because
727 0x00 ;D37C ; I messed up :(
728 0x00 ;D37D
729 0x00 ;D37E
730 0x00 ;D37F
732 ;; beginning of main state machine
733 0x18 ;D380 ; Declaration of variables
734 0x05 ;D381 ; 5 variables:
735 0x00 ;D382 ; current-mode
736 0x00 ;D383 ; bytes-to-write
737 0x00 ;D384 ; bytes-written
738 0x00 ;D385 ; start-point-high
739 0x00 ;D386 ; start-point-low
742 ;; banch on current mode
743 0xFA ;D387 ; load current-mode (0xD382)
744 0x82 ;D388 ; into A
745 0xD3 ;D389
746 0x00 ;D38A
749 ;; GOTO Mode 0 (input-mode) if current-mode is 0
750 0xFE ;D38B
751 0x00 ;D38C ; compare A with 0x00
753 0xCA ;D38D ; goto Mode 0 if A == 0
754 0xA8 ;D38E
755 0xD3 ;D38F
757 ;; GOTO Mode 1 (set-length) if current-mode is 1
758 0xFE ;D390
759 0x01 ;D391 ; compare A with 0x01
761 0xCA ;D392
762 0xB1 ;D393
763 0xD3 ;D394 ; goto Mode 1 if A == 1
765 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
766 0xFE ;D395
767 0x02 ;D396 ; compare A with 0x02
769 0xCA ;D397
770 0xBF ;D398
771 0xD3 ;D399 ; goto Mode 2 if A == 2
773 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
774 0xFE ;D39A
775 0x03 ;D39B
777 0xCA ;D39C
778 0xCD ;D39D
779 0xD3 ;D39E ; goto Mode 3 if A == 3
781 ;; GOTO Mode 4 (write-memory) if current mode is 4
782 0xFE ;D39F
783 0x04 ;D3A0
785 0xCA ;D3A1
786 0xDB ;D3A2
787 0xD3 ;D3A3
789 0x00 ;D3A4
790 ;; End of Mode checking, goto beginning
791 0xC3 ;D3A5
792 0x1D ;D3A6
793 0xD3 ;D3A7
796 ;; Mode 0 -- input-mode mode
797 ;; means that we are waiting for a mode, so set the mode to
798 ;; whatever is currently in input-number. If nothing is
799 ;; entered, then the program stays in input-mode mode
801 ;; set current-mode to input-number
802 0xFA ;D3A8 ; load input-number (0xD352)
803 0x52 ;D3A9 ; into A
804 0xD3 ;D3AA
806 0xEA ;D3AB ; load A into current-mode
807 0x82 ;D3AC ; (0xD382)
808 0xD3 ;D3AD
810 0xC3 ;D3AE ; go back to beginning
811 0x1D ;D3AF
812 0xD3 ;D3B0
813 ;; End Mode 0
816 ;; Mode 1 -- set-length mode
817 ;; This is the header for writing things to memory.
818 ;; User specifies the number of bytes to write.
819 ;; Mode is auto advanced to Mode 2 after this mode
820 ;; completes.
822 ;; Set bytes left to write to input-number;
823 ;; set current-mode to 0x02.
824 0xFA ;D3B1 ; load input-number (0xD352)
825 0x52 ;D3B2 ; into A
826 0xD3 ;D3B3
828 0xEA ;D3B4 ; load A into bytes-left-to-write
829 0x83 ;D3B5 ; (0xD383)
830 0xD3 ;D3B6
832 0x3E ;D3B7 ; load 0x02 into A.
833 0x02 ;D3B8
835 0xEA ;D3B9 ; load A to current-mode
836 0x82 ;D3BA ; advancing from Mode 1 to
837 0xD3 ;D3BB ; Mode 2
839 0xC3 ;D3BC ; go back to beginning
840 0x1D ;D3BD
841 0xD3 ;D3BE
842 ;; End Mode 1
845 ;; Mode 2 -- set start-point-high mode
846 ;; Middle part of the header for writing things to memory.
847 ;; User specifies the start location in RAM to which
848 ;; data will be written.
849 ;; Mode is auto advanced to Mode 3 after this mode completes.
851 ;; Set start-point-high to input-number;
852 ;; set current mode to 0x03.
853 0xFA ;D3BF ; load input-number (0xD352)
854 0x52 ;D3C0 ; into A
855 0xD3 ;D3C1
857 0xEA ;D3C2 ; load A into start-point-high
858 0x85 ;D3C3 ; (0xD385)
859 0xD3 ;D3C4
861 0x3E ;D3C5 ; load 0x03 into A.
862 0x03 ;D3C6
864 0xEA ;D3C7 ; load A to current-mode,
865 0x82 ;D3C8 ; advancing from Mode 2 to
866 0xD3 ;D3C9 ; Mode 3.
868 0xC3 ;D3CA ; go back to beginning
869 0x1D ;D3CB
870 0xD3 ;D3CC
871 ;;End Mode 2
874 ;; Mode 3 -- set-start-point-low mode
875 ;; Final part of header for writing things to memory.
876 ;; User specifies the low bytes of 16 bit start-point.
878 ;; Set start-point-low to input-number;
879 ;; set current mode to 0x04
880 0xFA ;D3CD ; load input-number into A
881 0x52 ;D3CE
882 0xD3 ;D3CF
884 0xEA ;D3D0 ; load A into start-point-low
885 0x86 ;D3D1
886 0xD3 ;D3D2
888 0x3E ;D3D3 ; load 0x04 into A.
889 0x04 ;D3D4
891 0xEA ;D3D5 ; load A to current-mode,
892 0x82 ;D3D6 ; advancing from Mode 3 to
893 0xD3 ;D3D7 ; Mode 4.
895 0xC3 ;D3D8 ; go back to beginning
896 0x1D ;D3D9
897 0xD3 ;D3DA
899 ;; Mode 4 -- write bytes mode
901 ;; This is where RAM manipulation happens. User supplies
902 ;; bytes every frame, which are written sequentially to
903 ;; start-point until bytes-to-write have been written. Once
904 ;; bytes-to-write have been written, the mode is reset to 0.
906 ;; compare bytes-written with bytes-to-write.
907 ;; if they are the same, then reset mode to 0
909 0xFA ;D3DB ; load bytes-to-write into A
910 0x83 ;D3DC
911 0xD3 ;D3DD
913 0x47 ;D3DE ; load A into B
915 0xFA ;D3DF ; load bytes-written into A
916 0x84 ;D3E0
917 0xD3 ;D3E1
919 0xB8 ;D3E2 ; compare A with B
921 0xCA ;D3E3 ; if they are equal, go to cleanup
922 0x07 ;D3E4
923 0xD4 ;D3E5
925 ;; Write Memory Section
926 ;; Write the input-number, interpreted as an 8-bit number,
927 ;; into the current target register, determined by
928 ;; (+ start-point bytes-written).
929 ;; Then, increment bytes-written by 1.
931 0xFA ;D3E6 ; load start-point-high into A
932 0x85 ;D3E7
933 0xD3 ;D3E8
935 0x67 ;D3E9 ; load A into H
937 0xFA ;D3EA ; load start-point-low into A
938 0x86 ;D3EB
939 0xD3 ;D3EC
941 0x6F ;D3ED ; load A into L
943 0xFA ;D3EE ; load bytes-written into A
944 0x84 ;D3EF
945 0xD3 ;D3F0
947 0x00 ;D3F1 ; These are here because
948 0x00 ;D3F2 ; I screwed up again.
949 0x00 ;D3F3
951 0x85 ;D3F4 ; add L to A; store A in L.
952 0x6F ;D3F5
954 0x30 ;D3F6 ; If the addition overflowed,
955 0x01 ;D3F7
956 0x24 ;D3F8 ; increment H.
958 ;; Now, HL points to the correct place in memory
960 0xFA ;D3F9 ; load input-number into A
961 0x52 ;D3FA
962 0xD3 ;D3FB
964 0x77 ;D3FC ; load A into (HL)
966 0xFA ;D3FD ; load bytes-written into A
967 0x84 ;D3FE
968 0xD3 ;D3FF
970 0x3C ;D400 ; increment A
972 0xEA ;D401 ; load A into bytes-written
973 0x84 ;D402
974 0xD3 ;D403
976 0xC3 ;D404 ; go back to beginning.
977 0x1D ;D405
978 0xD3 ;D406
979 ;; End Write Memory Section
981 ;; Mode 4 Cleanup Section
982 ;; reset bytes-written to 0
983 ;; set mode to 0
984 0x3E ;D407 ; load 0 into A
985 0x00 ;D408
987 0xEA ;D409 ; load A into bytes-written
988 0x84 ;D40A
989 0xD3 ;D40B
991 0xEA ;D40C ; load A into current-mode
992 0x82 ;D40D
993 0xD3 ;D40E
995 0xC3 ;D40F ; go back to beginning
996 0x1D ;D410
997 0xD3 ;D411
999 ;; End Mode 4
1001 ])
1005 (def frame-count 0xD31F)
1006 (def input 0xD352)
1007 (def current-mode 0xD382)
1008 (def bytes-to-write 0xD383)
1009 (def bytes-written 0xD384)
1010 (def start-point-high 0xD385)
1011 (def start-point-low 0xD386)
1015 (defn write-memory []
1016 (-> (tick (mid-game))
1017 (IE! 0) ; disable interrupts
1018 (inject-item-assembly (write-memory-assembly))))
1020 (defn test-write-memory []
1021 (set-state! (write-memory))
1022 (dorun
1023 (dotimes [_ 5000]
1024 (view-memory (step @current-state) current-mode))))
1026 (def bytes-to-write 0xD383)
1027 (def start-point 0xD384)
1029 (defn print-blank-assembly
1030 [start end]
1031 (dorun
1032 (map
1033 #(println (format "0x00 ;%04X " %))
1034 (range start end))))
1036 (defn test-mode-2 []
1037 (->
1038 (write-memory)
1039 (view-memory frame-count)
1040 (step)
1041 (step [:a])
1042 (step [:b])
1043 (step [:start])
1044 (step [])
1045 (view-memory frame-count)))
1047 (defn test-mode-4
1048 ([] (test-mode-4 (write-memory)))
1049 ([target-state]
1050 (->
1051 target-state
1052 (#(do (println "memory from 0xC00F to 0xC01F:"
1053 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1054 (view-memory current-mode)
1055 (step [])
1056 (step [])
1057 (step [])
1058 (#(do (println "after three steps") %))
1059 (view-memory current-mode)
1061 ;; Activate memory writing mode
1063 (#(do (println "step with [:a]") %))
1064 (step [:a])
1065 (view-memory current-mode)
1066 (view-memory bytes-to-write)
1067 (view-memory start-point-high)
1068 (view-memory start-point-low)
1070 ;; Specify four bytes to be written
1072 (#(do (println "step with [:select]")%))
1073 (step [:select])
1074 (view-memory current-mode)
1075 (view-memory bytes-to-write)
1076 (view-memory start-point-high)
1077 (view-memory start-point-low)
1079 ;; Specify target memory address as 0xC00F
1081 (#(do (println "step with [:u :d]")%))
1082 (step [:u :d])
1083 (view-memory current-mode)
1084 (view-memory bytes-to-write)
1085 (view-memory start-point-high)
1086 (view-memory start-point-low)
1088 (#(do (println "step with [:a :b :start :select]")%))
1089 (step [:a :b :start :select])
1090 (view-memory current-mode)
1091 (view-memory bytes-to-write)
1092 (view-memory start-point-high)
1093 (view-memory start-point-low)
1095 ;; Start reprogramming memory
1097 (#(do (println "step with [:a]")%))
1098 (step [:a])
1099 (view-memory current-mode)
1100 (view-memory bytes-written)
1102 (#(do (println "step with [:b]")%))
1103 (step [:b])
1104 (view-memory current-mode)
1105 (view-memory bytes-written)
1107 (#(do (println "step with [:a :b]")%))
1108 (step [:a :b])
1109 (view-memory current-mode)
1110 (view-memory bytes-written)
1112 (#(do (println "step with [:select]")%))
1113 (step [:select])
1114 (view-memory current-mode)
1115 (view-memory bytes-written)
1117 ;; Reprogramming done, program ready for more commands.
1119 (#(do (println "step with []")%))
1120 (step [])
1121 (view-memory current-mode)
1122 (view-memory bytes-written)
1124 (#(do (println "memory from 0xC00F to 0xC01F:"
1125 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))