comparison clojure/com/aurellem/gb/assembly.clj @ 145:412ca096a9ba

major refactoring complete.
author Robert McIntyre <rlm@mit.edu>
date Mon, 19 Mar 2012 21:23:46 -0500
parents
children 5d9a7a0ca09a
comparison
equal deleted inserted replaced
144:ec477931f077 145:412ca096a9ba
1 (ns com.aurellem.gb.assembly
2 (:use (com.aurellem.gb gb-driver vbm util items))
3 (:import [com.aurellem.gb.gb_driver SaveState]))
4
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)))))
20
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)))
28
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)))
40
41 (def buttons-port 0xFF00)
42
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))))))))
56
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)))))
62
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)))
68
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
78
79 0xFA ;D320 ; load (D31F) into A
80 0x1F ;D321 -->
81 0xD3 ;D322 --> D31F
82
83 0xEA ;D323 ; load (A), which is
84 0x00 ;D324 --> ; 00010000, into FF00
85 0xFF ;D325 --> FF00
86
87 0x18 ;D326 ; this is the place where
88 0x01 ;D327 ; we will store whether
89 0x00 ;D328 ; "down" is pressed.
90
91 0xFA ;D329 ; (FF00) -> A
92 0x00 ;D32A
93 0xFF ;D32B
94
95 0xCB ;D32C ; Test whether "down"
96 0x5F ;D32D ; is pressed.
97
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
105
106 ;; down-is-pressed
107 0xEA ;D334 ; write A to D328 if
108 0x28 ;D335 ; "down" was pressed
109 0xD3 ;D336
110
111 0xC3 ;D330
112 0x1D ;D331 ; return to beginning
113 0xD3 ;D332
114 ])))
115
116 (defn test-read-down []
117 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)
118 (view-memory (step (step (read-down-button))) 0xD328)))
119
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
128
129 0xFA ;D321
130 0x41 ;D322 ; load (FF41) into A
131 0xFF ;D323 ; this contains mode flags
132
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
137
138 0xC2 ;D326 ; if bit-1 is not 0
139 0x44 ;D327 ; GOTO not-v-blank
140 0xD3 ;D328
141
142 0xCB ;D329 ; test bit-0 of A
143 0x47 ;D32A
144
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
151
152 0xFA ;D32E ; load v-blank-prev to A
153 0x20 ;D32F
154 0xD3 ;D330
155
156 0xCB ;D331
157 0x47 ;D332 ; test bit-0 of A
158
159 0x20 ;D333 ; skip next section
160 0x07 ;D334 ; if v-blank-prev was not zero
161
162 ;; v-blank was 0, increment frame-count
163 0xFA ;D335 ; load frame-count into A
164 0x1F ;D336
165 0xD3 ;D337
166
167 0x3C ;D338 ; inc A
168
169 0xEA ;D339 ; load A into frame-count
170 0x1F ;D33A
171 0xD3 ;D33B
172
173 ;; set v-blank-prev to 1
174 0x3E ;D33C ; load 1 into A
175 0x01 ;D33D
176
177 0xEA ;D33E ; load A into v-blank-prev
178 0x20 ;D33F
179 0xD3 ;D340
180
181 0xC3 ;D341 ; return to beginning
182 0x1D ;D342
183 0xD3 ;D343
184
185 ;;; not in v-blank mode
186 ;; set v-blank-prev to 0
187 0x3E ;D344 ; load 0 into A
188 0x00 ;D345
189
190 0xEA ;D346 ; load A into v-blank-prev
191 0x20 ;D347
192 0xD3 ;D348
193
194 0xC3 ;D349 ; return to beginning
195 0x1D ;D34A
196 0xD3 ;D34B
197 ])))
198
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)))
224
225 (defn test-count-frames []
226 (= 255 (aget (memory ((apply comp (repeat 255 step))
227 (count-frames)))
228 0xD31F)))
229
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
243
244 ;; the next button press determines how many bytes are to be
245 ;; written, starting at the start position.
246
247 ;; then, the actual bytes are entered and are written to the
248 ;; start address in sequence.
249
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
255
256 0xFA ;D321
257 0x41 ;D322 ; load (FF41) into A
258 0xFF ;D323 ; this contains mode flags
259
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
264
265 0xC2 ;D326 ; if bit-1 is not 0
266 0x44 ;D327 ; GOTO not-v-blank
267 0xD3 ;D328
268
269 0xCB ;D329 ; test bit-0 of A
270 0x47 ;D32A
271
272 0xCA ;D32B ; if bit-0 is not 1
273 0x44 ;D32C ; GOTO not-v-blank
274 0xD3 ;D32D
275
276 ;;; in v-blank mode
277
278 ;; if v-blank-prev was 0,
279 ;; increment frame-count
280
281 0xFA ;D32E ; load v-blank-prev to A
282 0x20 ;D32F
283 0xD3 ;D330
284
285 0xCB ;D331
286 0x47 ;D332 ; test bit-0 of A
287
288 0x20 ;D333 ; skip next section
289 0x07 ;D334 ; if v-blank-prev was not zero
290
291 ;; v-blank was 0, increment frame-count
292 0xFA ;D335 ; load frame-count into A
293 0x1F ;D336
294 0xD3 ;D337
295
296 0x3C ;D338 ; inc A
297
298 0xEA ;D339 ; load A into frame-count
299 0x1F ;D33A
300 0xD3 ;D33B
301
302 ;; set v-blank-prev to 1
303 0x3E ;D33C ; load 1 into A
304 0x01 ;D33D
305
306 0xEA ;D33E ; load A into v-blank-prev
307 0x20 ;D33F
308 0xD3 ;D340
309
310 0xC3 ;D341 ; GOTO input handling code
311 0x4E ;D342
312 0xD3 ;D343
313
314 ;;; not in v-blank mode
315 ;; set v-blank-prev to 0
316 0x3E ;D344 ; load 0 into A
317 0x00 ;D345
318
319 0xEA ;D346 ; load A into v-blank-prev
320 0x20 ;D347
321 0xD3 ;D348
322
323 0xC3 ;D349 ; return to beginning
324 0x1D ;D34A
325 0xD3 ;D34B
326
327 0x00 ;D34C ; these are here
328 0x00 ;D34D ; for glue
329
330
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
339
340 ;; select directional pad, store low bits in B
341
342 0xFA ;D353 ; load (D350) into A
343 0x50 ;D354 -->
344 0xD3 ;D355 --> D31F
345
346 0xEA ;D356 ; load A, which is
347 0x00 ;D357 --> ; 00010000, into FF00
348 0xFF ;D358 --> FF00
349
350 0x06 ;D359
351 ;D35A
352 (Integer/parseInt "11110000" 2) ; "11110000" -> B
353 0xFA ;D35B ; (FF00) -> A
354 0x00 ;D35C
355 0xFF ;D35D
356
357 0xCB ;D35E ; swap nybbles on A
358 0x37 ;D35F
359 0xA0 ;D360 ; (AND A B) -> A
360 0x47 ;D361 ; A -> B
361
362 ;; select buttons store bottom bits in C
363
364 0xFA ; ; load (D351) into A
365 0x51 ; -->
366 0xD3 ; --> D31F
367
368 0xEA ; ; load (A), which is
369 0x00 ; --> ; 00001000, into FF00
370 0xFF ; --> FF00
371
372 0x0E ;
373 (Integer/parseInt "00001111" 2) ; "00001111" -> C
374
375 0xFA ; ; (FF00) -> A
376 0x00 ;
377 0xFF ;
378
379 0xA1 ; ; (AND A C) -> A
380 0x4F ; ; A -> C
381
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
386
387 0xEA ; ; store A into input-number
388 0x52 ;
389 0xD3 ;
390
391 0xC3 ; ; return to beginning
392 0x1D ;
393 0xD3 ;
394 ])
395
396
397
398 (defn input-number []
399 (-> (tick (mid-game))
400 (IE! 0) ; disable interrupts
401 (inject-item-assembly (input-number-assembly))))
402
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))))
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437 (defn write-memory-assembly*
438 "Currently, grabs input from the user each frame."
439 []
440 [
441 ;; --------- FRAME METRONOME
442 0x18 ;; jump ahead to cleanup. first time only.
443 0x40 ;; v-blank-prev [D31E]
444
445 0xFA ;; load modes into A [D31F]
446 0x41
447 0xFF
448
449 0x47 ;; A -> B
450 0xCB ;; rotate A
451 0x2F
452 0x2F ;; invert A
453
454 0xA0
455 0x47 ;; now B_0 contains (VB==1)
456
457 0xFA ;; load v-blank-prev
458 0x1E
459 0xD3
460
461 0x2F ;; complement v-blank-prev
462
463 0xA0 ;; A & B --> A
464 0x4F ;; now C_0 contains increment?
465
466
467 0x78 ;; B->A
468 0xEA ;; spit A --> vbprev
469 0x1E
470 0xD3
471
472 0xCB ;test C_0
473 0x41
474 0x20 ; JUMP ahead to button input if nonzero
475 0x02
476 0x18 ; JUMP back to frame metronome (D31F)
477 0xE7
478
479 ;; -------- GET BUTTON INPUT
480
481 ;; btw, C_0 is now 1
482 ;; prepare to select bits
483
484 0x06 ;; load 0x00 into B
485 0x00 ;; to initialize for "OR" loop
486
487 0x3E ;; load 0x20 into A, to measure dpad
488 0x20
489
490
491 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]
492 0x00
493
494 0xF0 ;; load A from [FF00]
495 0x00
496
497 0xE6 ;; bitmask 00001111
498 0x0F
499
500 0xB0 ;; A or B --> A
501 0xCB
502 0x41 ;; test bit 0 of C
503 0x28 ;; JUMP forward if 0
504 0x08
505
506 0x47 ;; A -> B
507 0xCB ;; swap B nybbles
508 0x30
509 0x0C ;; increment C
510 0x3E ;; load 0x10 into A, to measure btns
511 0x10
512 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]
513 0xED
514
515
516 ;; ------ TAKE ACTION BASED ON USER INPUT
517
518 ;; "input mode"
519 ;; mode 0x00 : select mode
520 ;; mode 0x08 : select bytes-to-write
521 ;; mode 0x10 : select hi-bit
522 ;; mode 0x18 : select lo-bit
523
524 ;; "output mode"
525 ;; mode 0x20 : write bytes
526 ;; mode 0xFF : jump PC
527
528
529 ;; registers
530 ;; D : mode select
531 ;; E : count of bytes to write
532 ;; H : address-high
533 ;; L : address-low
534
535 ;; now A contains the pressed keys
536 0x2F ; complement A, by request. [D34F]
537
538 0x47 ; A->B ;; now B contains the pressed keys
539 0x7B ; E->A ;; now A contains the count.
540
541 0xCB ; test bit 5 of D (are we in o/p mode?)
542 0x6A
543 0x28 ; if test == 0, skip this o/p section
544 0x13 ; JUMP
545
546 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)
547 0x42
548 0x28 ; if test == 0, skip the following command
549 0x01
550
551 ;; output mode I: moving the program counter
552 0xE9 ; ** move PC to (HL)
553
554 ;; output mode II: writing bytes
555 0xFE ; A compare 0. finished writing?
556 0x00
557 0x20 ; if we are not finished, skip cleanup
558 0x04 ; JUMP
559
560 ;; CLEANUP
561 ;; btw, A is already zero.
562 0xAF ; zero A [D35F]
563 0x57 ; A->D; makes D=0.
564 0x18 ; end of frame
565 0xBC
566
567 ;; ---- end of cleanup
568
569
570 ;; continue writing bytes
571 0x1D ;; decrement E, the number of bytes to write [D363]
572 0x78 ;; B->A; now A contains the pressed keys
573 0x77 ;; copy A to (HL)
574 0x23 ;; increment HL
575 0x18 ;; end frame. [goto D31F]
576 0xB6 ;; TODO: set skip length backwards
577
578
579 ;; ---- end of o/p section
580
581 ;; i/p mode
582 ;; adhere to the mode discipline:
583 ;; D must be one of 0x00 0x08 0x10 0x18.
584
585 0x3E ;; load the constant 57 into A. [D369]
586 0x57
587 0x82 ;; add the mode to A
588 0xEA ;; store A into "thing to execute"
589 0x74
590 0xD3
591
592 0x3E ;; load the constant 8 into A
593 0x08
594 0x82 ;; add the mode to A
595
596 0x57 ;; store the incremented mode into D
597 0x78 ;; B->A; now A contains the pressed keys
598
599 0x00 ;; var: thing to execute [D374]
600
601 0x18 ;; end frame
602 0xA8
603 ]
604 )
605
606 (defn write-mem-dyl []
607 (-> (tick (mid-game))
608 (IE! 0)
609 (inject-item-assembly (write-memory-assembly*))))
610
611
612 (defn dylan* []
613 (->
614 (write-mem-dyl)
615
616 (tick)
617 (tick)
618 (tick)
619 (tick)
620 (tick)
621 (tick)
622 (tick)
623 (tick)
624 (tick)
625 (tick)
626 (tick)
627 (tick)
628 (tick)
629 (tick)
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)
645 (tick)
646 (tick)
647 (tick)
648 (tick)
649 (tick)
650 (tick)
651 (tick)
652
653 ;;(view-memory 0xD374)
654 (tick)
655 (tick)
656 (tick)
657 (tick)
658 (tick)
659 (tick)
660 (tick)
661 (tick)
662 (tick)
663 (tick)
664 (tick)
665 (tick)
666 (tick)
667 (tick)
668 (tick)
669 ;;(view-memory 0xD374)
670 (d-tick)
671
672 (view-register "A" A)
673 (view-register "B" B)
674 (view-register "C" C))
675
676 )
677
678
679 (defn dylan []
680 (->
681 (write-mem-dyl)
682 (tick)
683 (tick)
684 (tick)
685 (tick)
686 (tick)
687 (tick)
688 (tick)
689 (tick)
690 (tick)
691 (tick)
692 (tick)
693 (tick)
694 (tick)
695 (tick)
696 (tick) ;; first loop
697
698
699 (tick)
700 (tick)
701 (tick)
702 (tick)
703 (tick)
704 (tick)
705 (tick)
706 (tick)
707 (tick)
708 (tick)
709 (tick)
710 (tick)
711 (tick) ;; dpad bits
712
713 (tick)
714 (tick)
715 (tick)
716 (tick)
717 (tick)
718 (tick)
719 (tick)
720 (tick)
721 (d-tick)
722
723
724
725 (view-register "A" A)
726 (view-register "B" B)
727 (view-register "C" C)
728
729 ))
730
731
732
733
734 (defn d2 []
735 (->
736 (write-mem-dyl)
737 (view-memory 0xD31F)
738 step step step step step
739 (view-memory 0xD31F)))
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760 (defn write-memory-assembly []
761 [
762 ;; Main Timing Loop
763 ;; Constantly check for v-blank and Trigger main state machine on
764 ;; every transtion from v-blank to non-v-blank.
765
766 0x18 ; D31D ; Variable declaration
767 0x02 ; D31E
768 0x00 ; D31F ; frame-count
769 0x00 ; D320 ; v-blank-prev
770
771 0xF0 ; D321 ; load v-blank mode flags into A
772 0x41
773 0x00
774
775
776 ;; Branch dependent on v-blank. v-blank happens when the last two
777 ;; bits in A are "01"
778 0xCB ; D324
779 0x4F ; D325
780
781 0xC2 ; D326 ; if bit-1 is not 0, then
782 0x3E ; D327 ; GOTO non-v-blank.
783 0xD3 ; D328
784
785 0xCB ; D329
786 0x47 ; D32A
787
788 0xCA ; D32B ; if bit-0 is not 1, then
789 0x3E ; D32C ; GOTO non-v-blank.
790 0xD3 ; D32D
791
792 ;; V-Blank
793 ;; Activate state-machine if this is a transition event.
794
795 0xFA ; D32E ; load v-bank-prev into A
796 0x20 ; D32F
797 0xD3 ; D330
798
799 0xFE ; D331 ; compare A to 0. >--------\
800 0x00 ; D332 \
801 ; |
802 ;; set v-blank-prev to 1. |
803 0x3E ; D333 ; load 1 into A. |
804 0x01 ; D334 |
805 ; |
806 0xEA ; D335 ; load A into v-blank-prev |
807 0x20 ; D336 |
808 0xD3 ; D337 |
809 ; /
810 ;; if v-blank-prev was 0, activate state-machine <------/
811 0xCA ; D338 ; if v-blank-prev
812 0x46 ; D339 ; was 0,
813 0xD3 ; D33A ; GOTO state-machine
814
815 0xC3 ; D33B
816 0x1D ; D33C
817 0xD3 ; D33D ; GOTO beginning
818 ;; END V-blank
819
820 ;; Non-V-Blank
821 ;; Set v-blank-prev to 0
822 0x3E ; D33E ; load 0 into A
823 0x00 ; D33F
824
825 0xEA ; D340 ; load A into v-blank-prev
826 0x20 ; D341
827 0xD3 ; D342
828
829 0xC3 ; D343
830 0x1D ; D344
831 0xD3 ; D345 ; GOTO beginning
832 ;; END Not-V-Blank
833
834
835 ;; Main State Machine -- Input Section
836 ;; This is called once every frame.
837 ;; It collects input and uses it to drive the
838 ;; state transitions.
839
840 ;; Increment frame-count
841 0xFA ; D346 ; load frame-count into A
842 0x1F ; D347
843 0xD3 ; D348
844
845 0x3C ; D349 ; inc A
846
847 0xEA ; D34A
848 0x1F ; D34B ; load A into frame-count
849 0xD3 ; D34C
850
851 0x00 ; D34D ; glue :)
852
853 0x18 ;D34E ; skip next 3 bytes
854 0x03 ;D34F
855 ;D350
856 (Integer/parseInt "00100000" 2) ; select directional pad
857 ;D351
858 (Integer/parseInt "00010000" 2) ; select buttons
859 0x00 ;D352 ; input-number
860
861 ;; select directional pad; store low bits in B
862
863 0xFA ;D353 ; load (D350) into A
864 0x50 ;D354 -->
865 0xD3 ;D355 --> D350
866
867 0xE0 ;D356 ; load (A), which is
868 0x00 ;D357 --> ; 00010000, into FF00
869 0x00 ;D358 --> FF00 ;; NO-OP
870
871 0x06 ;D359
872 ;D35A
873 (Integer/parseInt "11110000" 2) ; "11110000" -> B
874 0xF0 ;D35B ; (FF00) -> A
875 0x00 ;D35C
876 0x00 ;D35D ;; NO-OP
877
878 0xCB ;D35E ; swap nybbles on A
879 0x37 ;D35F
880 0xA0 ;D360 ; (AND A B) -> A
881 0x47 ;D361 ; A -> B
882
883 ;; select buttons; store bottom bits in C
884
885 0xFA ;D362 ; load (D351) into A
886 0x51 ;D363 -->
887 0xD3 ;D364 --> D351
888
889 0xE0 ;D365 ; load (A), which is
890 0x00 ;D366 --> ; 00001000, into FF00
891 0x00 ;D367 --> FF00 ;; NO-OP
892
893 0x0E ;D368
894 ;D369
895 (Integer/parseInt "00001111" 2) ; "00001111" -> C
896
897 0xF0 ;D36A ; (FF00) -> A
898 0x00 ;D36B
899 0x00 ;D36C
900
901 0xA1 ;D36D ; (AND A C) -> A
902 0x4F ;D36E ; A -> C
903
904 ;; combine the B and C registers into the input number
905 0x79 ;D36F ; C -> A
906 0xB0 ;D370 ; (OR A B) -> A
907 0x2F ;D371 ; negate A
908
909 0xEA ;D372 ; store A into input-number
910 0x52 ;D373
911 0xD3 ;D374
912
913 0x00 ;D375
914 0x00 ;D376
915 0x00 ;D377
916 0x00 ;D378
917 0x00 ;D379
918 0x00 ;D37A
919 0x00 ;D37B ; these are here because
920 0x00 ;D37C ; I messed up :(
921 0x00 ;D37D
922 0x00 ;D37E
923 0x00 ;D37F
924
925 ;; beginning of main state machine
926 0x18 ;D380 ; Declaration of variables
927 0x05 ;D381 ; 5 variables:
928 0x00 ;D382 ; current-mode
929 0x00 ;D383 ; bytes-to-write
930 0x00 ;D384 ; bytes-written
931 0x00 ;D385 ; start-point-high
932 0x00 ;D386 ; start-point-low
933
934
935 ;; banch on current mode
936 0xFA ;D387 ; load current-mode (0xD382)
937 0x82 ;D388 ; into A
938 0xD3 ;D389
939 0x00 ;D38A
940
941
942 ;; GOTO Mode 0 (input-mode) if current-mode is 0
943 0xFE ;D38B
944 0x00 ;D38C ; compare A with 0x00
945
946 0xCA ;D38D ; goto Mode 0 if A == 0
947 0xA8 ;D38E
948 0xD3 ;D38F
949
950 ;; GOTO Mode 1 (set-length) if current-mode is 1
951 0xFE ;D390
952 0x01 ;D391 ; compare A with 0x01
953
954 0xCA ;D392
955 0xB1 ;D393
956 0xD3 ;D394 ; goto Mode 1 if A == 1
957
958 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2
959 0xFE ;D395
960 0x02 ;D396 ; compare A with 0x02
961
962 0xCA ;D397
963 0xBF ;D398
964 0xD3 ;D399 ; goto Mode 2 if A == 2
965
966 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3
967 0xFE ;D39A
968 0x03 ;D39B
969
970 0xCA ;D39C
971 0xCD ;D39D
972 0xD3 ;D39E ; goto Mode 3 if A == 3
973
974 ;; GOTO Mode 4 (write-memory) if current mode is 4
975 0xFE ;D39F
976 0x04 ;D3A0
977
978 0xCA ;D3A1
979 0xDB ;D3A2
980 0xD3 ;D3A3
981
982 0x00 ;D3A4
983 ;; End of Mode checking, goto beginning
984 0xC3 ;D3A5
985 0x1D ;D3A6
986 0xD3 ;D3A7
987
988
989 ;; Mode 0 -- input-mode mode
990 ;; means that we are waiting for a mode, so set the mode to
991 ;; whatever is currently in input-number. If nothing is
992 ;; entered, then the program stays in input-mode mode
993
994 ;; set current-mode to input-number
995 0xFA ;D3A8 ; load input-number (0xD352)
996 0x52 ;D3A9 ; into A
997 0xD3 ;D3AA
998
999 0xEA ;D3AB ; load A into current-mode
1000 0x82 ;D3AC ; (0xD382)
1001 0xD3 ;D3AD
1002
1003 0xC3 ;D3AE ; go back to beginning
1004 0x1D ;D3AF
1005 0xD3 ;D3B0
1006 ;; End Mode 0
1007
1008
1009 ;; Mode 1 -- set-length mode
1010 ;; This is the header for writing things to memory.
1011 ;; User specifies the number of bytes to write.
1012 ;; Mode is auto advanced to Mode 2 after this mode
1013 ;; completes.
1014
1015 ;; Set bytes left to write to input-number;
1016 ;; set current-mode to 0x02.
1017 0xFA ;D3B1 ; load input-number (0xD352)
1018 0x52 ;D3B2 ; into A
1019 0xD3 ;D3B3
1020
1021 0xEA ;D3B4 ; load A into bytes-left-to-write
1022 0x83 ;D3B5 ; (0xD383)
1023 0xD3 ;D3B6
1024
1025 0x3E ;D3B7 ; load 0x02 into A.
1026 0x02 ;D3B8
1027
1028 0xEA ;D3B9 ; load A to current-mode
1029 0x82 ;D3BA ; advancing from Mode 1 to
1030 0xD3 ;D3BB ; Mode 2
1031
1032 0xC3 ;D3BC ; go back to beginning
1033 0x1D ;D3BD
1034 0xD3 ;D3BE
1035 ;; End Mode 1
1036
1037
1038 ;; Mode 2 -- set start-point-high mode
1039 ;; Middle part of the header for writing things to memory.
1040 ;; User specifies the start location in RAM to which
1041 ;; data will be written.
1042 ;; Mode is auto advanced to Mode 3 after this mode completes.
1043
1044 ;; Set start-point-high to input-number;
1045 ;; set current mode to 0x03.
1046 0xFA ;D3BF ; load input-number (0xD352)
1047 0x52 ;D3C0 ; into A
1048 0xD3 ;D3C1
1049
1050 0xEA ;D3C2 ; load A into start-point-high
1051 0x85 ;D3C3 ; (0xD385)
1052 0xD3 ;D3C4
1053
1054 0x3E ;D3C5 ; load 0x03 into A.
1055 0x03 ;D3C6
1056
1057 0xEA ;D3C7 ; load A to current-mode,
1058 0x82 ;D3C8 ; advancing from Mode 2 to
1059 0xD3 ;D3C9 ; Mode 3.
1060
1061 0xC3 ;D3CA ; go back to beginning
1062 0x1D ;D3CB
1063 0xD3 ;D3CC
1064 ;;End Mode 2
1065
1066
1067 ;; Mode 3 -- set-start-point-low mode
1068 ;; Final part of header for writing things to memory.
1069 ;; User specifies the low bytes of 16 bit start-point.
1070
1071 ;; Set start-point-low to input-number;
1072 ;; set current mode to 0x04
1073 0xFA ;D3CD ; load input-number into A
1074 0x52 ;D3CE
1075 0xD3 ;D3CF
1076
1077 0xEA ;D3D0 ; load A into start-point-low
1078 0x86 ;D3D1
1079 0xD3 ;D3D2
1080
1081 0x3E ;D3D3 ; load 0x04 into A.
1082 0x04 ;D3D4
1083
1084 0xEA ;D3D5 ; load A to current-mode,
1085 0x82 ;D3D6 ; advancing from Mode 3 to
1086 0xD3 ;D3D7 ; Mode 4.
1087
1088 0xC3 ;D3D8 ; go back to beginning
1089 0x1D ;D3D9
1090 0xD3 ;D3DA
1091
1092 ;; Mode 4 -- write bytes mode
1093
1094 ;; This is where RAM manipulation happens. User supplies
1095 ;; bytes every frame, which are written sequentially to
1096 ;; start-point until bytes-to-write have been written. Once
1097 ;; bytes-to-write have been written, the mode is reset to 0.
1098
1099 ;; compare bytes-written with bytes-to-write.
1100 ;; if they are the same, then reset mode to 0
1101
1102 0xFA ;D3DB ; load bytes-to-write into A
1103 0x83 ;D3DC
1104 0xD3 ;D3DD
1105
1106 0x47 ;D3DE ; load A into B
1107
1108 0xFA ;D3DF ; load bytes-written into A
1109 0x84 ;D3E0
1110 0xD3 ;D3E1
1111
1112 0xB8 ;D3E2 ; compare A with B
1113
1114 0xCA ;D3E3 ; if they are equal, go to cleanup
1115 0x07 ;D3E4
1116 0xD4 ;D3E5
1117
1118 ;; Write Memory Section
1119 ;; Write the input-number, interpreted as an 8-bit number,
1120 ;; into the current target register, determined by
1121 ;; (+ start-point bytes-written).
1122 ;; Then, increment bytes-written by 1.
1123
1124 0xFA ;D3E6 ; load start-point-high into A
1125 0x85 ;D3E7
1126 0xD3 ;D3E8
1127
1128 0x67 ;D3E9 ; load A into H
1129
1130 0xFA ;D3EA ; load start-point-low into A
1131 0x86 ;D3EB
1132 0xD3 ;D3EC
1133
1134 0x6F ;D3ED ; load A into L
1135
1136 0xFA ;D3EE ; load bytes-written into A
1137 0x84 ;D3EF
1138 0xD3 ;D3F0
1139
1140 0x00 ;D3F1 ; These are here because
1141 0x00 ;D3F2 ; I screwed up again.
1142 0x00 ;D3F3
1143
1144 0x85 ;D3F4 ; add L to A; store A in L.
1145 0x6F ;D3F5
1146
1147 0x30 ;D3F6 ; If the addition overflowed,
1148 0x01 ;D3F7
1149 0x24 ;D3F8 ; increment H.
1150
1151 ;; Now, HL points to the correct place in memory
1152
1153 0xFA ;D3F9 ; load input-number into A
1154 0x52 ;D3FA
1155 0xD3 ;D3FB
1156
1157 0x77 ;D3FC ; load A into (HL)
1158
1159 0xFA ;D3FD ; load bytes-written into A
1160 0x84 ;D3FE
1161 0xD3 ;D3FF
1162
1163 0x3C ;D400 ; increment A
1164
1165 0xEA ;D401 ; load A into bytes-written
1166 0x84 ;D402
1167 0xD3 ;D403
1168
1169 0xC3 ;D404 ; go back to beginning.
1170 0x1D ;D405
1171 0xD3 ;D406
1172 ;; End Write Memory Section
1173
1174 ;; Mode 4 Cleanup Section
1175 ;; reset bytes-written to 0
1176 ;; set mode to 0
1177 0x3E ;D407 ; load 0 into A
1178 0x00 ;D408
1179
1180 0xEA ;D409 ; load A into bytes-written
1181 0x84 ;D40A
1182 0xD3 ;D40B
1183
1184 0xEA ;D40C ; load A into current-mode
1185 0x82 ;D40D
1186 0xD3 ;D40E
1187
1188 0xC3 ;D40F ; go back to beginning
1189 0x1D ;D410
1190 0xD3 ;D411
1191
1192 ;; End Mode 4
1193
1194 ])
1195
1196
1197
1198 (def frame-count 0xD31F)
1199 (def input 0xD352)
1200 (def current-mode 0xD382)
1201 (def bytes-to-write 0xD383)
1202 (def bytes-written 0xD384)
1203 (def start-point-high 0xD385)
1204 (def start-point-low 0xD386)
1205
1206
1207
1208 (defn write-memory []
1209 (-> (tick (mid-game))
1210 (IE! 0) ; disable interrupts
1211 (inject-item-assembly (write-memory-assembly))))
1212
1213 (defn test-write-memory []
1214 (set-state! (write-memory))
1215 (dorun
1216 (dotimes [_ 5000]
1217 (view-memory (step @current-state) current-mode))))
1218
1219 (def bytes-to-write 0xD383)
1220 (def start-point 0xD384)
1221
1222 (defn print-blank-assembly
1223 [start end]
1224 (dorun
1225 (map
1226 #(println (format "0x00 ;%04X " %))
1227 (range start end))))
1228
1229 (defn test-mode-2 []
1230 (->
1231 (write-memory)
1232 (view-memory frame-count)
1233 (step)
1234 (step [:a])
1235 (step [:b])
1236 (step [:start])
1237 (step [])
1238 (view-memory frame-count)))
1239
1240
1241
1242 (defn dylan-test-mode
1243 ([] (dylan-test-mode (write-mem-dyl)))
1244 ([target-state]
1245 (let [
1246 v-blank-prev 54046
1247 btn-register 65280
1248 eggs 0xD374
1249 ]
1250
1251 (->
1252 target-state
1253
1254 (tick)
1255 (tick)
1256 (tick)
1257 (tick);; jumps back to beginning
1258
1259 (tick)
1260 (tick)
1261 (tick)
1262 (tick)
1263 (tick)
1264 (tick)
1265 (tick)
1266 (tick)
1267 (tick)
1268 (tick)
1269 (tick)
1270 (tick)
1271
1272
1273 (tick)
1274 (tick)
1275 (tick)
1276 (tick)
1277 (tick)
1278 (tick)
1279 (tick)
1280 (tick)
1281 (tick)
1282 (tick)
1283 (tick)
1284 (tick)
1285 (tick)
1286 (tick)
1287 (tick)
1288 (tick)
1289 (tick)
1290 (tick)
1291 (tick)
1292 (tick)
1293 (tick) ;; just complemented A
1294
1295 (tick)
1296 (DE! 0x1800)
1297 (AF! 0x7700) ;; change inputs @ A
1298 (tick)
1299 (tick)
1300 (tick)
1301 (tick)
1302 (tick)
1303
1304 ;;(view-memory eggs)
1305 (tick)
1306 (tick)
1307 ;;(view-memory eggs)
1308 (tick)
1309 (tick)
1310 (tick)
1311 (tick)
1312 (tick)
1313 (tick)
1314 (d-tick)
1315
1316
1317 ;;(view-memory btn-register)
1318 (view-register "A" A)
1319 (view-register "B" B)
1320
1321 ;;(view-register "C" C)
1322 (view-register "D" D)
1323 (view-register "E" E)
1324 (view-register "H" H)
1325 (view-register "L" L)
1326 ))))
1327
1328
1329
1330 (defn drive-dylan []
1331 (-> (write-mem-dyl)
1332 (#(do (println "memory from 0xC00F to 0xC01F:"
1333 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1334 (step [])
1335 (step [])
1336 (step [])
1337 (step [:start])
1338 (step [:select])
1339 (step [:u :d])
1340 (step [:a :b :start :select])
1341 (step [:a])
1342 (step [:b])
1343 (step [:a :b])
1344 (step [:select])
1345 (step [])
1346 (step [])
1347 (step [])
1348 (#(do (println "memory from 0xC00F to 0xC01F:"
1349 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1350 ))
1351
1352 (defn test-mode-4
1353 ([] (test-mode-4 (write-memory)))
1354 ([target-state]
1355 (->
1356 target-state
1357 (#(do (println "memory from 0xC00F to 0xC01F:"
1358 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))
1359 (view-memory current-mode)
1360 (step [])
1361 (step [])
1362 (step [])
1363 (#(do (println "after three steps") %))
1364 (view-memory current-mode)
1365
1366 ;; Activate memory writing mode
1367
1368 (#(do (println "step with [:a]") %))
1369 (step [:a])
1370 (view-memory current-mode)
1371 (view-memory bytes-to-write)
1372 (view-memory start-point-high)
1373 (view-memory start-point-low)
1374
1375 ;; Specify four bytes to be written
1376
1377 (#(do (println "step with [:select]")%))
1378 (step [:select])
1379 (view-memory current-mode)
1380 (view-memory bytes-to-write)
1381 (view-memory start-point-high)
1382 (view-memory start-point-low)
1383
1384 ;; Specify target memory address as 0xC00F
1385
1386 (#(do (println "step with [:u :d]")%))
1387 (step [:u :d])
1388 (view-memory current-mode)
1389 (view-memory bytes-to-write)
1390 (view-memory start-point-high)
1391 (view-memory start-point-low)
1392
1393 (#(do (println "step with [:a :b :start :select]")%))
1394 (step [:a :b :start :select])
1395 (view-memory current-mode)
1396 (view-memory bytes-to-write)
1397 (view-memory start-point-high)
1398 (view-memory start-point-low)
1399
1400 ;; Start reprogramming memory
1401
1402 (#(do (println "step with [:a]")%))
1403 (step [:a])
1404 (view-memory current-mode)
1405 (view-memory bytes-written)
1406
1407 (#(do (println "step with [:b]")%))
1408 (step [:b])
1409 (view-memory current-mode)
1410 (view-memory bytes-written)
1411
1412 (#(do (println "step with [:a :b]")%))
1413 (step [:a :b])
1414 (view-memory current-mode)
1415 (view-memory bytes-written)
1416
1417 (#(do (println "step with [:select]")%))
1418 (step [:select])
1419 (view-memory current-mode)
1420 (view-memory bytes-written)
1421
1422 ;; Reprogramming done, program ready for more commands.
1423
1424 (#(do (println "step with []")%))
1425 (step [])
1426 (view-memory current-mode)
1427 (view-memory bytes-written)
1428
1429 (#(do (println "memory from 0xC00F to 0xC01F:"
1430 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))
1431