Mercurial > vba-clojure
view clojure/com/aurellem/gb/assembly.clj @ 180:4f5ea93cbaca
determined location of pokemon types; added functions for reading/setting them.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Thu, 22 Mar 2012 01:25:39 -0500 |
parents | 95b2758dd517 |
children | 5e34473ac774 |
line wrap: on
line source
1 (ns com.aurellem.gb.assembly2 (:use (com.aurellem.gb gb-driver vbm util items))3 (:import [com.aurellem.gb.gb_driver SaveState]))5 (defn inject-assembly6 ([^SaveState state7 program-counter registers8 assembly-code]9 (let [scratch-memory (memory state)]10 ;; inject assembly code11 (dorun (map (fn [index val]12 (aset scratch-memory index val))13 (range program-counter14 (+ program-counter (count assembly-code)))15 assembly-code))16 (-> state17 (write-memory! scratch-memory)18 (write-registers! registers)19 (PC! program-counter)))))21 (defn inject-item-assembly22 ([^SaveState state assembly-code]23 (inject-assembly state (inc item-list-start)24 (registers state)25 assembly-code))26 ([assembly-code]27 (inject-item-assembly @current-state assembly-code)))29 (defn run-assembly30 ([info-fn assembly n]31 (let [final-state32 (reduce (fn [state _]33 (tick (info-fn state)))34 (inject-item-assembly35 (mid-game) assembly)36 (range n))]37 final-state))38 ([assembly n]39 (run-assembly d-tick assembly n)))41 (def buttons-port 0xFF00)43 (defn trace [state]44 (loop [program-counters [(first (registers @current-state)) ]45 opcodes [(aget (memory @current-state) (PC @current-state))]]46 (let [frame-boundary?47 (com.aurellem.gb.Gb/tick)]48 (if frame-boundary?49 [program-counters opcodes]50 (recur51 (conj program-counters52 (first (registers @current-state)))53 (conj opcodes54 (aget (memory @current-state)55 (PC @current-state))))))))57 (defn print-trace [state n]58 (let [[program-counters opcodes] (trace state)]59 (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op)))60 (take n program-counters)61 (take n opcodes)))))63 (defn good-trace []64 (-> (mid-game) (tick) (IE! 0)65 (set-inv-mem [0x00 0x00 0X00 0x00])66 (PC! item-list-start)(print-interrupt)67 (d-tick) (tick) (d-tick) (tick) (d-tick)))69 (defn read-down-button []70 (-> (tick (mid-game))71 (IE! 0) ; disable interrupts72 (inject-item-assembly73 ;; write 00010000 to 0xFF00 to select joypad74 [0x18 ;D31D ; jump over75 0x01 ;D31E ; the next 8 bits76 ;D31F77 (Integer/parseInt "00100000" 2) ; data section79 0xFA ;D320 ; load (D31F) into A80 0x1F ;D321 -->81 0xD3 ;D322 --> D31F83 0xEA ;D323 ; load (A), which is84 0x00 ;D324 --> ; 00010000, into FF0085 0xFF ;D325 --> FF0087 0x18 ;D326 ; this is the place where88 0x01 ;D327 ; we will store whether89 0x00 ;D328 ; "down" is pressed.91 0xFA ;D329 ; (FF00) -> A92 0x00 ;D32A93 0xFF ;D32B95 0xCB ;D32C ; Test whether "down"96 0x5F ;D32D ; is pressed.98 0x28 ;D32E ; if down is pressed,99 0x03 ;D32F ; skip the next section100 ; of code.101 ;; down-is-not-pressed102 0xC3 ;D330103 0x1D ;D331 ; return to beginning104 0xD3 ;D332106 ;; down-is-pressed107 0xEA ;D334 ; write A to D328 if108 0x28 ;D335 ; "down" was pressed109 0xD3 ;D336111 0xC3 ;D330112 0x1D ;D331 ; return to beginning113 0xD3 ;D332114 ])))116 (defn test-read-down []117 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)118 (view-memory (step (step (read-down-button))) 0xD328)))120 (defn count-frames []121 (-> (tick (mid-game))122 (IE! 0) ; disable interrupts123 (inject-item-assembly124 [0x18 ;D31D ; jump over125 0x02 ;D31E ; the next 2 bytes126 0x00 ;D31F ; frame-count127 0x00 ;D320 ; v-blank-prev129 0xFA ;D321130 0x41 ;D322 ; load (FF41) into A131 0xFF ;D323 ; this contains mode flags133 ;; if we're in v-blank, the bit-1 is 0134 ;; and bit-2 is 1 Otherwise, it is not v-blank.135 0xCB ;D324 ; test bit-1 of A136 0x4F ;D325138 0xC2 ;D326 ; if bit-1 is not 0139 0x44 ;D327 ; GOTO not-v-blank140 0xD3 ;D328142 0xCB ;D329 ; test bit-0 of A143 0x47 ;D32A145 0xCA ;D32B ; if bit-0 is not 1146 0x44 ;D32C ; GOTO not-v-blank147 0xD3 ;D32D148 ;;; in v-blank mode149 ;; if v-blank-prev was 0,150 ;; increment frame-count152 0xFA ;D32E ; load v-blank-prev to A153 0x20 ;D32F154 0xD3 ;D330156 0xCB ;D331157 0x47 ;D332 ; test bit-0 of A159 0x20 ;D333 ; skip next section160 0x07 ;D334 ; if v-blank-prev was not zero162 ;; v-blank was 0, increment frame-count163 0xFA ;D335 ; load frame-count into A164 0x1F ;D336165 0xD3 ;D337167 0x3C ;D338 ; inc A169 0xEA ;D339 ; load A into frame-count170 0x1F ;D33A171 0xD3 ;D33B173 ;; set v-blank-prev to 1174 0x3E ;D33C ; load 1 into A175 0x01 ;D33D177 0xEA ;D33E ; load A into v-blank-prev178 0x20 ;D33F179 0xD3 ;D340181 0xC3 ;D341 ; return to beginning182 0x1D ;D342183 0xD3 ;D343185 ;;; not in v-blank mode186 ;; set v-blank-prev to 0187 0x3E ;D344 ; load 0 into A188 0x00 ;D345190 0xEA ;D346 ; load A into v-blank-prev191 0x20 ;D347192 0xD3 ;D348194 0xC3 ;D349 ; return to beginning195 0x1D ;D34A196 0xD3 ;D34B197 ])))199 (defn step-count-frames []200 (-> (read-down-button)201 (d-tick)202 (tick) ;; skip over data section203 (d-tick)204 (view-register "Register A" A)205 (tick) ;; load-data into A206 (view-register "Register A" A)207 (d-tick)208 (view-memory 0xFF00)209 (tick) ;; load A into 0xFF00210 (view-memory 0xFF00)211 (d-tick)212 (tick)213 (d-tick)214 (tick)215 (d-tick)216 (tick)217 (d-tick)218 (tick)219 (d-tick)220 (tick)221 (d-tick)222 (tick)223 (print-inventory)))225 (defn test-count-frames []226 (= 255 (aget (memory ((apply comp (repeat 255 step))227 (count-frames)))228 0xD31F)))230 ;; specs for main bootstrap program231 ;; starts in "mode-select" mode232 ;; Each button press takes place in a single frame.233 ;; mode-select-mode takes one of the main buttons234 ;; which selects one of up to eight modes235 ;; mode 1 activated by the "A" button236 ;; the next two button presses indicates the start237 ;; memory location which to which the bootstrap238 ;; program will write.239 ;; This is done by using each of the eight buttons to240 ;; spell out an 8 bit number. The order of buttons is241 ;; [:d :u :l :r :start :select :b :a]242 ;; [:a :start :l] --> 00101001244 ;; the next button press determines how many bytes are to be245 ;; written, starting at the start position.247 ;; then, the actual bytes are entered and are written to the248 ;; start address in sequence.250 (defn input-number-assembly []251 [0x18 ;D31D ; jump over252 0x02 ;D31E ; the next 2 bytes253 0x00 ;D31F ; frame-count254 0x00 ;D320 ; v-blank-prev256 0xFA ;D321257 0x41 ;D322 ; load (FF41) into A258 0xFF ;D323 ; this contains mode flags260 ;; if we're in v-blank, the bit-1 is 0261 ;; and bit-2 is 1 Otherwise, it is not v-blank.262 0xCB ;D324 ; test bit-1 of A263 0x4F ;D325265 0xC2 ;D326 ; if bit-1 is not 0266 0x44 ;D327 ; GOTO not-v-blank267 0xD3 ;D328269 0xCB ;D329 ; test bit-0 of A270 0x47 ;D32A272 0xCA ;D32B ; if bit-0 is not 1273 0x44 ;D32C ; GOTO not-v-blank274 0xD3 ;D32D276 ;;; in v-blank mode278 ;; if v-blank-prev was 0,279 ;; increment frame-count281 0xFA ;D32E ; load v-blank-prev to A282 0x20 ;D32F283 0xD3 ;D330285 0xCB ;D331286 0x47 ;D332 ; test bit-0 of A288 0x20 ;D333 ; skip next section289 0x07 ;D334 ; if v-blank-prev was not zero291 ;; v-blank was 0, increment frame-count292 0xFA ;D335 ; load frame-count into A293 0x1F ;D336294 0xD3 ;D337296 0x3C ;D338 ; inc A298 0xEA ;D339 ; load A into frame-count299 0x1F ;D33A300 0xD3 ;D33B302 ;; set v-blank-prev to 1303 0x3E ;D33C ; load 1 into A304 0x01 ;D33D306 0xEA ;D33E ; load A into v-blank-prev307 0x20 ;D33F308 0xD3 ;D340310 0xC3 ;D341 ; GOTO input handling code311 0x4E ;D342312 0xD3 ;D343314 ;;; not in v-blank mode315 ;; set v-blank-prev to 0316 0x3E ;D344 ; load 0 into A317 0x00 ;D345319 0xEA ;D346 ; load A into v-blank-prev320 0x20 ;D347321 0xD3 ;D348323 0xC3 ;D349 ; return to beginning324 0x1D ;D34A325 0xD3 ;D34B327 0x00 ;D34C ; these are here328 0x00 ;D34D ; for glue331 ;;; calculate input number based on button presses332 0x18 ;D34E ; skip next 3 bytes333 0x03 ;D34F334 ;D350335 (Integer/parseInt "00100000" 2) ; select directional pad336 ;D351337 (Integer/parseInt "00010000" 2) ; select buttons338 0x00 ;D352 ; input-number340 ;; select directional pad, store low bits in B342 0xFA ;D353 ; load (D350) into A343 0x50 ;D354 -->344 0xD3 ;D355 --> D31F346 0xEA ;D356 ; load A, which is347 0x00 ;D357 --> ; 00010000, into FF00348 0xFF ;D358 --> FF00350 0x06 ;D359351 ;D35A352 (Integer/parseInt "11110000" 2) ; "11110000" -> B353 0xFA ;D35B ; (FF00) -> A354 0x00 ;D35C355 0xFF ;D35D357 0xCB ;D35E ; swap nybbles on A358 0x37 ;D35F359 0xA0 ;D360 ; (AND A B) -> A360 0x47 ;D361 ; A -> B362 ;; select buttons store bottom bits in C364 0xFA ; ; load (D351) into A365 0x51 ; -->366 0xD3 ; --> D31F368 0xEA ; ; load (A), which is369 0x00 ; --> ; 00001000, into FF00370 0xFF ; --> FF00372 0x0E ;373 (Integer/parseInt "00001111" 2) ; "00001111" -> C375 0xFA ; ; (FF00) -> A376 0x00 ;377 0xFF ;379 0xA1 ; ; (AND A C) -> A380 0x4F ; ; A -> C382 ;; combine the B and C registers into the input number383 0x79 ; ; C -> A384 0xB0 ; ; (OR A B) -> A385 0x2F ; ; negate A387 0xEA ; ; store A into input-number388 0x52 ;389 0xD3 ;391 0xC3 ; ; return to beginning392 0x1D ;393 0xD3 ;394 ])398 (defn input-number []399 (-> (tick (mid-game))400 (IE! 0) ; disable interrupts401 (inject-item-assembly (input-number-assembly))))403 (defn test-input-number404 "Input freestyle buttons and observe the effects at the repl."405 []406 (set-state! (input-number))407 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))409 (defn write-memory-assembly*410 "A program for altering in-game memory by pressing buttons."411 []412 [413 0xF3 ; stop interrupts414 ;; --------- CLEANUP415 0xAF ; zero A [D31E]416 0x57 ; A->D; makes D=0.418 ;; --------- FRAME METRONOME419 0xF1 ;; pop AF (vblank prev) [D320]421 0x2F ;; invert A422 0x47 ;; A -> B424 0xF0 ;; copy STAT into A425 0x41427 0xCB ;; swap A nybbles; now A_0 is (VB==1).428 0x37430 0xF5 ;; push AF (vbprev)432 0xA0 ;; A & B --> A. Now A_0 contains "increment?"434 0xCB ;; test A_0. this result will be used twice.435 0x47436 0x28 ;; end frame (JUMP) if A_0 = 0.437 0x00 ;; TODO: set jump length439 ;; -------- GET BUTTON INPUT441 ;; btw, Z bit is now 1442 ;; prepare to select bits444 0x3E ;; load 0x20 into A, to measure dpad445 0x20447 0x06 ;; load 0x00 into B448 0x00 ;; to initialize for "OR" loop450 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]451 0x00453 0xF0 ;; load A from [FF00]454 0x00456 0xE6 ;; bitmask 00001111457 0x0F459 0xB0 ;; A or B --> A461 0x28 ;; JUMP forward if Z=0462 0x08464 0x47 ;; A -> B465 0xCB ;; swap B nybbles466 0x30468 0x3E ;; load 0x10 into A, to measure btns469 0x10471 0xBF ;; compare(A,A) sets Z=0473 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]474 0xED477 ;; ------ TAKE ACTION BASED ON USER INPUT479 ;; "input mode"480 ;; mode 0x00 : select mode481 ;; mode 0x08 : select bytes-to-write482 ;; mode 0x10 : select hi-bit483 ;; mode 0x18 : select lo-bit485 ;; "output mode"486 ;; mode 0x20 : write bytes487 ;; mode 0xFF : jump PC490 ;; registers491 ;; D : mode select492 ;; E : count of bytes to write493 ;; H : address-high494 ;; L : address-low496 ;; now A contains the pressed keys497 0x2F ; complement A, by request. [D34F]499 0x47 ; A->B ;; now B contains the pressed keys501 0xCB ; test bit 5 of D (are we in o/p mode?)502 0x6A503 0x28 ; if test == 0, skip this o/p section504 0x13 ; JUMP506 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)507 0x42508 0x28 ; if test == 0, skip the following command509 0x01511 ;; output mode I: moving the program counter512 0xE9 ; ** move PC to (HL)514 ;; output mode II: writing bytes515 0xAF ; zero A516 0xBB ; compare count to zero. finished writing?517 0x28 ; if we are finished, jump back to cleanup518 0x00 ; TODO: set jump length backwards.520 ;; continue writing bytes521 0x78 ;; B->A522 0x22 ;; copy A to (HL) and increment HL.523 0x18 ;; end frame. [goto D31F]524 0xB6 ;; JUMP527 ;; ---- end of o/p section529 ;; i/p mode530 ;; adhere to the mode discipline:531 ;; D must be one of 0x00 0x08 0x10 0x18.533 0x3E ;; load the constant 57 into A. [D369]534 0x57535 0x82 ;; add the mode to A536 0xEA ;; store A into "thing to execute"537 0x74538 0xD3540 0x3E ;; load the constant 8 into A541 0x08542 0x82 ;; add the mode to A544 0x57 ;; store the incremented mode into D545 0x78 ;; B->A; now A contains the pressed keys547 0x00 ;; var: thing to execute [D374]549 0x18 ;; end frame550 0xA8 ;; JUMP551 ]552 )554 (defn write-mem-dyl []555 (-> (tick (mid-game))556 (IE! 0)557 (inject-item-assembly (write-memory-assembly*))))560 (defn dylan* []561 (->562 (write-mem-dyl)564 (tick)565 (tick)566 (tick)567 (tick)568 (tick)569 (tick)570 (tick)571 (tick)572 (tick)573 (tick)574 (tick)575 (tick)576 (tick)577 (tick)578 (tick)579 (tick)580 (tick)581 (tick)582 (tick)583 (tick)584 (tick)585 (tick)586 (tick)587 (tick)588 (tick)589 (tick)590 (tick)591 (tick)592 (tick)593 (tick)594 (tick)595 (tick)596 (tick)597 (tick)598 (tick)599 (tick)601 ;;(view-memory 0xD374)602 (tick)603 (tick)604 (tick)605 (tick)606 (tick)607 (tick)608 (tick)609 (tick)610 (tick)611 (tick)612 (tick)613 (tick)614 (tick)615 (tick)616 (tick)617 ;;(view-memory 0xD374)618 (d-tick)620 (view-register "A" A)621 (view-register "B" B)622 (view-register "C" C))624 )627 (defn dylan []628 (->629 (write-mem-dyl)630 (tick)631 (tick)632 (tick)633 (tick)634 (tick)635 (tick)636 (tick)637 (tick)638 (tick)639 (tick)640 (tick)641 (tick)642 (tick)643 (tick)644 (tick) ;; first loop647 (tick)648 (tick)649 (tick)650 (tick)651 (tick)652 (tick)653 (tick)654 (tick)655 (tick)656 (tick)657 (tick)658 (tick)659 (tick) ;; dpad bits661 (tick)662 (tick)663 (tick)664 (tick)665 (tick)666 (tick)667 (tick)668 (tick)669 (d-tick)673 (view-register "A" A)674 (view-register "B" B)675 (view-register "C" C)677 ))682 (defn d2 []683 (->684 (write-mem-dyl)685 (view-memory 0xD31F)686 step step step step step687 (view-memory 0xD31F)))708 (defn write-memory-assembly []709 [710 ;; Main Timing Loop711 ;; Constantly check for v-blank and Trigger main state machine on712 ;; every transtion from v-blank to non-v-blank.714 0x18 ; D31D ; Variable declaration715 0x02 ; D31E716 0x00 ; D31F ; frame-count717 0x00 ; D320 ; v-blank-prev719 0xF0 ; D321 ; load v-blank mode flags into A720 0x41721 0x00724 ;; Branch dependent on v-blank. v-blank happens when the last two725 ;; bits in A are "01"726 0xCB ; D324727 0x4F ; D325729 0xC2 ; D326 ; if bit-1 is not 0, then730 0x3E ; D327 ; GOTO non-v-blank.731 0xD3 ; D328733 0xCB ; D329734 0x47 ; D32A736 0xCA ; D32B ; if bit-0 is not 1, then737 0x3E ; D32C ; GOTO non-v-blank.738 0xD3 ; D32D740 ;; V-Blank741 ;; Activate state-machine if this is a transition event.743 0xFA ; D32E ; load v-bank-prev into A744 0x20 ; D32F745 0xD3 ; D330747 0xFE ; D331 ; compare A to 0. >--------\748 0x00 ; D332 \749 ; |750 ;; set v-blank-prev to 1. |751 0x3E ; D333 ; load 1 into A. |752 0x01 ; D334 |753 ; |754 0xEA ; D335 ; load A into v-blank-prev |755 0x20 ; D336 |756 0xD3 ; D337 |757 ; /758 ;; if v-blank-prev was 0, activate state-machine <------/759 0xCA ; D338 ; if v-blank-prev760 0x46 ; D339 ; was 0,761 0xD3 ; D33A ; GOTO state-machine763 0xC3 ; D33B764 0x1D ; D33C765 0xD3 ; D33D ; GOTO beginning766 ;; END V-blank768 ;; Non-V-Blank769 ;; Set v-blank-prev to 0770 0x3E ; D33E ; load 0 into A771 0x00 ; D33F773 0xEA ; D340 ; load A into v-blank-prev774 0x20 ; D341775 0xD3 ; D342777 0xC3 ; D343778 0x1D ; D344779 0xD3 ; D345 ; GOTO beginning780 ;; END Not-V-Blank783 ;; Main State Machine -- Input Section784 ;; This is called once every frame.785 ;; It collects input and uses it to drive the786 ;; state transitions.788 ;; Increment frame-count789 0xFA ; D346 ; load frame-count into A790 0x1F ; D347791 0xD3 ; D348793 0x3C ; D349 ; inc A795 0xEA ; D34A796 0x1F ; D34B ; load A into frame-count797 0xD3 ; D34C799 0x00 ; D34D ; glue :)801 0x18 ;D34E ; skip next 3 bytes802 0x03 ;D34F803 ;D350804 (Integer/parseInt "00100000" 2) ; select directional pad805 ;D351806 (Integer/parseInt "00010000" 2) ; select buttons807 0x00 ;D352 ; input-number809 ;; select directional pad; store low bits in B811 0xFA ;D353 ; load (D350) into A812 0x50 ;D354 -->813 0xD3 ;D355 --> D350815 0xE0 ;D356 ; load (A), which is816 0x00 ;D357 --> ; 00010000, into FF00817 0x00 ;D358 --> FF00 ;; NO-OP819 0x06 ;D359820 ;D35A821 (Integer/parseInt "11110000" 2) ; "11110000" -> B822 0xF0 ;D35B ; (FF00) -> A823 0x00 ;D35C824 0x00 ;D35D ;; NO-OP826 0xCB ;D35E ; swap nybbles on A827 0x37 ;D35F828 0xA0 ;D360 ; (AND A B) -> A829 0x47 ;D361 ; A -> B831 ;; select buttons; store bottom bits in C833 0xFA ;D362 ; load (D351) into A834 0x51 ;D363 -->835 0xD3 ;D364 --> D351837 0xE0 ;D365 ; load (A), which is838 0x00 ;D366 --> ; 00001000, into FF00839 0x00 ;D367 --> FF00 ;; NO-OP841 0x0E ;D368842 ;D369843 (Integer/parseInt "00001111" 2) ; "00001111" -> C845 0xF0 ;D36A ; (FF00) -> A846 0x00 ;D36B847 0x00 ;D36C849 0xA1 ;D36D ; (AND A C) -> A850 0x4F ;D36E ; A -> C852 ;; combine the B and C registers into the input number853 0x79 ;D36F ; C -> A854 0xB0 ;D370 ; (OR A B) -> A855 0x2F ;D371 ; negate A857 0xEA ;D372 ; store A into input-number858 0x52 ;D373859 0xD3 ;D374861 0x00 ;D375862 0x00 ;D376863 0x00 ;D377864 0x00 ;D378865 0x00 ;D379866 0x00 ;D37A867 0x00 ;D37B ; these are here because868 0x00 ;D37C ; I messed up :(869 0x00 ;D37D870 0x00 ;D37E871 0x00 ;D37F873 ;; beginning of main state machine874 0x18 ;D380 ; Declaration of variables875 0x05 ;D381 ; 5 variables:876 0x00 ;D382 ; current-mode877 0x00 ;D383 ; bytes-to-write878 0x00 ;D384 ; bytes-written879 0x00 ;D385 ; start-point-high880 0x00 ;D386 ; start-point-low883 ;; banch on current mode884 0xFA ;D387 ; load current-mode (0xD382)885 0x82 ;D388 ; into A886 0xD3 ;D389887 0x00 ;D38A890 ;; GOTO Mode 0 (input-mode) if current-mode is 0891 0xFE ;D38B892 0x00 ;D38C ; compare A with 0x00894 0xCA ;D38D ; goto Mode 0 if A == 0895 0xA8 ;D38E896 0xD3 ;D38F898 ;; GOTO Mode 1 (set-length) if current-mode is 1899 0xFE ;D390900 0x01 ;D391 ; compare A with 0x01902 0xCA ;D392903 0xB1 ;D393904 0xD3 ;D394 ; goto Mode 1 if A == 1906 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2907 0xFE ;D395908 0x02 ;D396 ; compare A with 0x02910 0xCA ;D397911 0xBF ;D398912 0xD3 ;D399 ; goto Mode 2 if A == 2914 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3915 0xFE ;D39A916 0x03 ;D39B918 0xCA ;D39C919 0xCD ;D39D920 0xD3 ;D39E ; goto Mode 3 if A == 3922 ;; GOTO Mode 4 (write-memory) if current mode is 4923 0xFE ;D39F924 0x04 ;D3A0926 0xCA ;D3A1927 0xDB ;D3A2928 0xD3 ;D3A3930 0x00 ;D3A4931 ;; End of Mode checking, goto beginning932 0xC3 ;D3A5933 0x1D ;D3A6934 0xD3 ;D3A7937 ;; Mode 0 -- input-mode mode938 ;; means that we are waiting for a mode, so set the mode to939 ;; whatever is currently in input-number. If nothing is940 ;; entered, then the program stays in input-mode mode942 ;; set current-mode to input-number943 0xFA ;D3A8 ; load input-number (0xD352)944 0x52 ;D3A9 ; into A945 0xD3 ;D3AA947 0xEA ;D3AB ; load A into current-mode948 0x82 ;D3AC ; (0xD382)949 0xD3 ;D3AD951 0xC3 ;D3AE ; go back to beginning952 0x1D ;D3AF953 0xD3 ;D3B0954 ;; End Mode 0957 ;; Mode 1 -- set-length mode958 ;; This is the header for writing things to memory.959 ;; User specifies the number of bytes to write.960 ;; Mode is auto advanced to Mode 2 after this mode961 ;; completes.963 ;; Set bytes left to write to input-number;964 ;; set current-mode to 0x02.965 0xFA ;D3B1 ; load input-number (0xD352)966 0x52 ;D3B2 ; into A967 0xD3 ;D3B3969 0xEA ;D3B4 ; load A into bytes-left-to-write970 0x83 ;D3B5 ; (0xD383)971 0xD3 ;D3B6973 0x3E ;D3B7 ; load 0x02 into A.974 0x02 ;D3B8976 0xEA ;D3B9 ; load A to current-mode977 0x82 ;D3BA ; advancing from Mode 1 to978 0xD3 ;D3BB ; Mode 2980 0xC3 ;D3BC ; go back to beginning981 0x1D ;D3BD982 0xD3 ;D3BE983 ;; End Mode 1986 ;; Mode 2 -- set start-point-high mode987 ;; Middle part of the header for writing things to memory.988 ;; User specifies the start location in RAM to which989 ;; data will be written.990 ;; Mode is auto advanced to Mode 3 after this mode completes.992 ;; Set start-point-high to input-number;993 ;; set current mode to 0x03.994 0xFA ;D3BF ; load input-number (0xD352)995 0x52 ;D3C0 ; into A996 0xD3 ;D3C1998 0xEA ;D3C2 ; load A into start-point-high999 0x85 ;D3C3 ; (0xD385)1000 0xD3 ;D3C41002 0x3E ;D3C5 ; load 0x03 into A.1003 0x03 ;D3C61005 0xEA ;D3C7 ; load A to current-mode,1006 0x82 ;D3C8 ; advancing from Mode 2 to1007 0xD3 ;D3C9 ; Mode 3.1009 0xC3 ;D3CA ; go back to beginning1010 0x1D ;D3CB1011 0xD3 ;D3CC1012 ;;End Mode 21015 ;; Mode 3 -- set-start-point-low mode1016 ;; Final part of header for writing things to memory.1017 ;; User specifies the low bytes of 16 bit start-point.1019 ;; Set start-point-low to input-number;1020 ;; set current mode to 0x041021 0xFA ;D3CD ; load input-number into A1022 0x52 ;D3CE1023 0xD3 ;D3CF1025 0xEA ;D3D0 ; load A into start-point-low1026 0x86 ;D3D11027 0xD3 ;D3D21029 0x3E ;D3D3 ; load 0x04 into A.1030 0x04 ;D3D41032 0xEA ;D3D5 ; load A to current-mode,1033 0x82 ;D3D6 ; advancing from Mode 3 to1034 0xD3 ;D3D7 ; Mode 4.1036 0xC3 ;D3D8 ; go back to beginning1037 0x1D ;D3D91038 0xD3 ;D3DA1040 ;; Mode 4 -- write bytes mode1042 ;; This is where RAM manipulation happens. User supplies1043 ;; bytes every frame, which are written sequentially to1044 ;; start-point until bytes-to-write have been written. Once1045 ;; bytes-to-write have been written, the mode is reset to 0.1047 ;; compare bytes-written with bytes-to-write.1048 ;; if they are the same, then reset mode to 01050 0xFA ;D3DB ; load bytes-to-write into A1051 0x83 ;D3DC1052 0xD3 ;D3DD1054 0x47 ;D3DE ; load A into B1056 0xFA ;D3DF ; load bytes-written into A1057 0x84 ;D3E01058 0xD3 ;D3E11060 0xB8 ;D3E2 ; compare A with B1062 0xCA ;D3E3 ; if they are equal, go to cleanup1063 0x07 ;D3E41064 0xD4 ;D3E51066 ;; Write Memory Section1067 ;; Write the input-number, interpreted as an 8-bit number,1068 ;; into the current target register, determined by1069 ;; (+ start-point bytes-written).1070 ;; Then, increment bytes-written by 1.1072 0xFA ;D3E6 ; load start-point-high into A1073 0x85 ;D3E71074 0xD3 ;D3E81076 0x67 ;D3E9 ; load A into H1078 0xFA ;D3EA ; load start-point-low into A1079 0x86 ;D3EB1080 0xD3 ;D3EC1082 0x6F ;D3ED ; load A into L1084 0xFA ;D3EE ; load bytes-written into A1085 0x84 ;D3EF1086 0xD3 ;D3F01088 0x00 ;D3F1 ; These are here because1089 0x00 ;D3F2 ; I screwed up again.1090 0x00 ;D3F31092 0x85 ;D3F4 ; add L to A; store A in L.1093 0x6F ;D3F51095 0x30 ;D3F6 ; If the addition overflowed,1096 0x01 ;D3F71097 0x24 ;D3F8 ; increment H.1099 ;; Now, HL points to the correct place in memory1101 0xFA ;D3F9 ; load input-number into A1102 0x52 ;D3FA1103 0xD3 ;D3FB1105 0x77 ;D3FC ; load A into (HL)1107 0xFA ;D3FD ; load bytes-written into A1108 0x84 ;D3FE1109 0xD3 ;D3FF1111 0x3C ;D400 ; increment A1113 0xEA ;D401 ; load A into bytes-written1114 0x84 ;D4021115 0xD3 ;D4031117 0xC3 ;D404 ; go back to beginning.1118 0x1D ;D4051119 0xD3 ;D4061120 ;; End Write Memory Section1122 ;; Mode 4 Cleanup Section1123 ;; reset bytes-written to 01124 ;; set mode to 01125 0x3E ;D407 ; load 0 into A1126 0x00 ;D4081128 0xEA ;D409 ; load A into bytes-written1129 0x84 ;D40A1130 0xD3 ;D40B1132 0xEA ;D40C ; load A into current-mode1133 0x82 ;D40D1134 0xD3 ;D40E1136 0xC3 ;D40F ; go back to beginning1137 0x1D ;D4101138 0xD3 ;D4111140 ;; End Mode 41142 ])1146 (def frame-count 0xD31F)1147 (def input 0xD352)1148 (def current-mode 0xD382)1149 (def bytes-to-write 0xD383)1150 (def bytes-written 0xD384)1151 (def start-point-high 0xD385)1152 (def start-point-low 0xD386)1156 (defn write-memory []1157 (-> (tick (mid-game))1158 (IE! 0) ; disable interrupts1159 (inject-item-assembly (write-memory-assembly))))1161 (defn test-write-memory []1162 (set-state! (write-memory))1163 (dorun1164 (dotimes [_ 5000]1165 (view-memory (step @current-state) current-mode))))1167 (def bytes-to-write 0xD383)1168 (def start-point 0xD384)1170 (defn print-blank-assembly1171 [start end]1172 (dorun1173 (map1174 #(println (format "0x00 ;%04X " %))1175 (range start end))))1177 (defn test-mode-2 []1178 (->1179 (write-memory)1180 (view-memory frame-count)1181 (step)1182 (step [:a])1183 (step [:b])1184 (step [:start])1185 (step [])1186 (view-memory frame-count)))1190 (defn dylan-test-mode1191 ([] (dylan-test-mode (write-mem-dyl)))1192 ([target-state]1193 (let [1194 v-blank-prev 540461195 btn-register 652801196 eggs 0xD3741197 ]1199 (->1200 target-state1202 (tick)1203 (tick)1204 (tick)1205 (tick);; jumps back to beginning1207 (tick)1208 (tick)1209 (tick)1210 (tick)1211 (tick)1212 (tick)1213 (tick)1214 (tick)1215 (tick)1216 (tick)1217 (tick)1218 (tick)1221 (tick)1222 (tick)1223 (tick)1224 (tick)1225 (tick)1226 (tick)1227 (tick)1228 (tick)1229 (tick)1230 (tick)1231 (tick)1232 (tick)1233 (tick)1234 (tick)1235 (tick)1236 (tick)1237 (tick)1238 (tick)1239 (tick)1240 (tick)1241 (tick) ;; just complemented A1243 (tick)1244 (DE! 0x1800)1245 (AF! 0x7700) ;; change inputs @ A1246 (tick)1247 (tick)1248 (tick)1249 (tick)1250 (tick)1252 ;;(view-memory eggs)1253 (tick)1254 (tick)1255 ;;(view-memory eggs)1256 (tick)1257 (tick)1258 (tick)1259 (tick)1260 (tick)1261 (tick)1262 (d-tick)1265 ;;(view-memory btn-register)1266 (view-register "A" A)1267 (view-register "B" B)1269 ;;(view-register "C" C)1270 (view-register "D" D)1271 (view-register "E" E)1272 (view-register "H" H)1273 (view-register "L" L)1274 ))))1278 (defn drive-dylan []1279 (-> (write-mem-dyl)1280 (#(do (println "memory from 0xC00F to 0xC01F:"1281 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1282 (step [])1283 (step [])1284 (step [])1285 (step [:start])1286 (step [:select])1287 (step [:u :d])1288 (step [:a :b :start :select])1289 (step [:a])1290 (step [:b])1291 (step [:a :b])1292 (step [:select])1293 (step [])1294 (step [])1295 (step [])1296 (#(do (println "memory from 0xC00F to 0xC01F:"1297 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1298 ))1300 (defn test-mode-41301 ([] (test-mode-4 (write-memory)))1302 ([target-state]1303 (->1304 target-state1305 (#(do (println "memory from 0xC00F to 0xC01F:"1306 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1307 (view-memory current-mode)1308 (step [])1309 (step [])1310 (step [])1311 (#(do (println "after three steps") %))1312 (view-memory current-mode)1314 ;; Activate memory writing mode1316 (#(do (println "step with [:a]") %))1317 (step [:a])1318 (view-memory current-mode)1319 (view-memory bytes-to-write)1320 (view-memory start-point-high)1321 (view-memory start-point-low)1323 ;; Specify four bytes to be written1325 (#(do (println "step with [:select]")%))1326 (step [:select])1327 (view-memory current-mode)1328 (view-memory bytes-to-write)1329 (view-memory start-point-high)1330 (view-memory start-point-low)1332 ;; Specify target memory address as 0xC00F1334 (#(do (println "step with [:u :d]")%))1335 (step [:u :d])1336 (view-memory current-mode)1337 (view-memory bytes-to-write)1338 (view-memory start-point-high)1339 (view-memory start-point-low)1341 (#(do (println "step with [:a :b :start :select]")%))1342 (step [:a :b :start :select])1343 (view-memory current-mode)1344 (view-memory bytes-to-write)1345 (view-memory start-point-high)1346 (view-memory start-point-low)1348 ;; Start reprogramming memory1350 (#(do (println "step with [:a]")%))1351 (step [:a])1352 (view-memory current-mode)1353 (view-memory bytes-written)1355 (#(do (println "step with [:b]")%))1356 (step [:b])1357 (view-memory current-mode)1358 (view-memory bytes-written)1360 (#(do (println "step with [:a :b]")%))1361 (step [:a :b])1362 (view-memory current-mode)1363 (view-memory bytes-written)1365 (#(do (println "step with [:select]")%))1366 (step [:select])1367 (view-memory current-mode)1368 (view-memory bytes-written)1370 ;; Reprogramming done, program ready for more commands.1372 (#(do (println "step with []")%))1373 (step [])1374 (view-memory current-mode)1375 (view-memory bytes-written)1377 (#(do (println "memory from 0xC00F to 0xC01F:"1378 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))