Mercurial > vba-clojure
view clojure/com/aurellem/gb/assembly.clj @ 157:da652c72e55d
discovered location of pokemon DV values.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 20 Mar 2012 03:28:18 -0500 |
parents | 412ca096a9ba |
children | 5d9a7a0ca09a |
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))))437 (defn write-memory-assembly*438 "Currently, grabs input from the user each frame."439 []440 [441 ;; --------- FRAME METRONOME442 0x18 ;; jump ahead to cleanup. first time only.443 0x40 ;; v-blank-prev [D31E]445 0xFA ;; load modes into A [D31F]446 0x41447 0xFF449 0x47 ;; A -> B450 0xCB ;; rotate A451 0x2F452 0x2F ;; invert A454 0xA0455 0x47 ;; now B_0 contains (VB==1)457 0xFA ;; load v-blank-prev458 0x1E459 0xD3461 0x2F ;; complement v-blank-prev463 0xA0 ;; A & B --> A464 0x4F ;; now C_0 contains increment?467 0x78 ;; B->A468 0xEA ;; spit A --> vbprev469 0x1E470 0xD3472 0xCB ;test C_0473 0x41474 0x20 ; JUMP ahead to button input if nonzero475 0x02476 0x18 ; JUMP back to frame metronome (D31F)477 0xE7479 ;; -------- GET BUTTON INPUT481 ;; btw, C_0 is now 1482 ;; prepare to select bits484 0x06 ;; load 0x00 into B485 0x00 ;; to initialize for "OR" loop487 0x3E ;; load 0x20 into A, to measure dpad488 0x20491 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]492 0x00494 0xF0 ;; load A from [FF00]495 0x00497 0xE6 ;; bitmask 00001111498 0x0F500 0xB0 ;; A or B --> A501 0xCB502 0x41 ;; test bit 0 of C503 0x28 ;; JUMP forward if 0504 0x08506 0x47 ;; A -> B507 0xCB ;; swap B nybbles508 0x30509 0x0C ;; increment C510 0x3E ;; load 0x10 into A, to measure btns511 0x10512 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]513 0xED516 ;; ------ TAKE ACTION BASED ON USER INPUT518 ;; "input mode"519 ;; mode 0x00 : select mode520 ;; mode 0x08 : select bytes-to-write521 ;; mode 0x10 : select hi-bit522 ;; mode 0x18 : select lo-bit524 ;; "output mode"525 ;; mode 0x20 : write bytes526 ;; mode 0xFF : jump PC529 ;; registers530 ;; D : mode select531 ;; E : count of bytes to write532 ;; H : address-high533 ;; L : address-low535 ;; now A contains the pressed keys536 0x2F ; complement A, by request. [D34F]538 0x47 ; A->B ;; now B contains the pressed keys539 0x7B ; E->A ;; now A contains the count.541 0xCB ; test bit 5 of D (are we in o/p mode?)542 0x6A543 0x28 ; if test == 0, skip this o/p section544 0x13 ; JUMP546 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)547 0x42548 0x28 ; if test == 0, skip the following command549 0x01551 ;; output mode I: moving the program counter552 0xE9 ; ** move PC to (HL)554 ;; output mode II: writing bytes555 0xFE ; A compare 0. finished writing?556 0x00557 0x20 ; if we are not finished, skip cleanup558 0x04 ; JUMP560 ;; CLEANUP561 ;; btw, A is already zero.562 0xAF ; zero A [D35F]563 0x57 ; A->D; makes D=0.564 0x18 ; end of frame565 0xBC567 ;; ---- end of cleanup570 ;; continue writing bytes571 0x1D ;; decrement E, the number of bytes to write [D363]572 0x78 ;; B->A; now A contains the pressed keys573 0x77 ;; copy A to (HL)574 0x23 ;; increment HL575 0x18 ;; end frame. [goto D31F]576 0xB6 ;; TODO: set skip length backwards579 ;; ---- end of o/p section581 ;; i/p mode582 ;; adhere to the mode discipline:583 ;; D must be one of 0x00 0x08 0x10 0x18.585 0x3E ;; load the constant 57 into A. [D369]586 0x57587 0x82 ;; add the mode to A588 0xEA ;; store A into "thing to execute"589 0x74590 0xD3592 0x3E ;; load the constant 8 into A593 0x08594 0x82 ;; add the mode to A596 0x57 ;; store the incremented mode into D597 0x78 ;; B->A; now A contains the pressed keys599 0x00 ;; var: thing to execute [D374]601 0x18 ;; end frame602 0xA8603 ]604 )606 (defn write-mem-dyl []607 (-> (tick (mid-game))608 (IE! 0)609 (inject-item-assembly (write-memory-assembly*))))612 (defn dylan* []613 (->614 (write-mem-dyl)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)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)672 (view-register "A" A)673 (view-register "B" B)674 (view-register "C" C))676 )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 loop699 (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 bits713 (tick)714 (tick)715 (tick)716 (tick)717 (tick)718 (tick)719 (tick)720 (tick)721 (d-tick)725 (view-register "A" A)726 (view-register "B" B)727 (view-register "C" C)729 ))734 (defn d2 []735 (->736 (write-mem-dyl)737 (view-memory 0xD31F)738 step step step step step739 (view-memory 0xD31F)))760 (defn write-memory-assembly []761 [762 ;; Main Timing Loop763 ;; Constantly check for v-blank and Trigger main state machine on764 ;; every transtion from v-blank to non-v-blank.766 0x18 ; D31D ; Variable declaration767 0x02 ; D31E768 0x00 ; D31F ; frame-count769 0x00 ; D320 ; v-blank-prev771 0xF0 ; D321 ; load v-blank mode flags into A772 0x41773 0x00776 ;; Branch dependent on v-blank. v-blank happens when the last two777 ;; bits in A are "01"778 0xCB ; D324779 0x4F ; D325781 0xC2 ; D326 ; if bit-1 is not 0, then782 0x3E ; D327 ; GOTO non-v-blank.783 0xD3 ; D328785 0xCB ; D329786 0x47 ; D32A788 0xCA ; D32B ; if bit-0 is not 1, then789 0x3E ; D32C ; GOTO non-v-blank.790 0xD3 ; D32D792 ;; V-Blank793 ;; Activate state-machine if this is a transition event.795 0xFA ; D32E ; load v-bank-prev into A796 0x20 ; D32F797 0xD3 ; D330799 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-prev812 0x46 ; D339 ; was 0,813 0xD3 ; D33A ; GOTO state-machine815 0xC3 ; D33B816 0x1D ; D33C817 0xD3 ; D33D ; GOTO beginning818 ;; END V-blank820 ;; Non-V-Blank821 ;; Set v-blank-prev to 0822 0x3E ; D33E ; load 0 into A823 0x00 ; D33F825 0xEA ; D340 ; load A into v-blank-prev826 0x20 ; D341827 0xD3 ; D342829 0xC3 ; D343830 0x1D ; D344831 0xD3 ; D345 ; GOTO beginning832 ;; END Not-V-Blank835 ;; Main State Machine -- Input Section836 ;; This is called once every frame.837 ;; It collects input and uses it to drive the838 ;; state transitions.840 ;; Increment frame-count841 0xFA ; D346 ; load frame-count into A842 0x1F ; D347843 0xD3 ; D348845 0x3C ; D349 ; inc A847 0xEA ; D34A848 0x1F ; D34B ; load A into frame-count849 0xD3 ; D34C851 0x00 ; D34D ; glue :)853 0x18 ;D34E ; skip next 3 bytes854 0x03 ;D34F855 ;D350856 (Integer/parseInt "00100000" 2) ; select directional pad857 ;D351858 (Integer/parseInt "00010000" 2) ; select buttons859 0x00 ;D352 ; input-number861 ;; select directional pad; store low bits in B863 0xFA ;D353 ; load (D350) into A864 0x50 ;D354 -->865 0xD3 ;D355 --> D350867 0xE0 ;D356 ; load (A), which is868 0x00 ;D357 --> ; 00010000, into FF00869 0x00 ;D358 --> FF00 ;; NO-OP871 0x06 ;D359872 ;D35A873 (Integer/parseInt "11110000" 2) ; "11110000" -> B874 0xF0 ;D35B ; (FF00) -> A875 0x00 ;D35C876 0x00 ;D35D ;; NO-OP878 0xCB ;D35E ; swap nybbles on A879 0x37 ;D35F880 0xA0 ;D360 ; (AND A B) -> A881 0x47 ;D361 ; A -> B883 ;; select buttons; store bottom bits in C885 0xFA ;D362 ; load (D351) into A886 0x51 ;D363 -->887 0xD3 ;D364 --> D351889 0xE0 ;D365 ; load (A), which is890 0x00 ;D366 --> ; 00001000, into FF00891 0x00 ;D367 --> FF00 ;; NO-OP893 0x0E ;D368894 ;D369895 (Integer/parseInt "00001111" 2) ; "00001111" -> C897 0xF0 ;D36A ; (FF00) -> A898 0x00 ;D36B899 0x00 ;D36C901 0xA1 ;D36D ; (AND A C) -> A902 0x4F ;D36E ; A -> C904 ;; combine the B and C registers into the input number905 0x79 ;D36F ; C -> A906 0xB0 ;D370 ; (OR A B) -> A907 0x2F ;D371 ; negate A909 0xEA ;D372 ; store A into input-number910 0x52 ;D373911 0xD3 ;D374913 0x00 ;D375914 0x00 ;D376915 0x00 ;D377916 0x00 ;D378917 0x00 ;D379918 0x00 ;D37A919 0x00 ;D37B ; these are here because920 0x00 ;D37C ; I messed up :(921 0x00 ;D37D922 0x00 ;D37E923 0x00 ;D37F925 ;; beginning of main state machine926 0x18 ;D380 ; Declaration of variables927 0x05 ;D381 ; 5 variables:928 0x00 ;D382 ; current-mode929 0x00 ;D383 ; bytes-to-write930 0x00 ;D384 ; bytes-written931 0x00 ;D385 ; start-point-high932 0x00 ;D386 ; start-point-low935 ;; banch on current mode936 0xFA ;D387 ; load current-mode (0xD382)937 0x82 ;D388 ; into A938 0xD3 ;D389939 0x00 ;D38A942 ;; GOTO Mode 0 (input-mode) if current-mode is 0943 0xFE ;D38B944 0x00 ;D38C ; compare A with 0x00946 0xCA ;D38D ; goto Mode 0 if A == 0947 0xA8 ;D38E948 0xD3 ;D38F950 ;; GOTO Mode 1 (set-length) if current-mode is 1951 0xFE ;D390952 0x01 ;D391 ; compare A with 0x01954 0xCA ;D392955 0xB1 ;D393956 0xD3 ;D394 ; goto Mode 1 if A == 1958 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2959 0xFE ;D395960 0x02 ;D396 ; compare A with 0x02962 0xCA ;D397963 0xBF ;D398964 0xD3 ;D399 ; goto Mode 2 if A == 2966 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3967 0xFE ;D39A968 0x03 ;D39B970 0xCA ;D39C971 0xCD ;D39D972 0xD3 ;D39E ; goto Mode 3 if A == 3974 ;; GOTO Mode 4 (write-memory) if current mode is 4975 0xFE ;D39F976 0x04 ;D3A0978 0xCA ;D3A1979 0xDB ;D3A2980 0xD3 ;D3A3982 0x00 ;D3A4983 ;; End of Mode checking, goto beginning984 0xC3 ;D3A5985 0x1D ;D3A6986 0xD3 ;D3A7989 ;; Mode 0 -- input-mode mode990 ;; means that we are waiting for a mode, so set the mode to991 ;; whatever is currently in input-number. If nothing is992 ;; entered, then the program stays in input-mode mode994 ;; set current-mode to input-number995 0xFA ;D3A8 ; load input-number (0xD352)996 0x52 ;D3A9 ; into A997 0xD3 ;D3AA999 0xEA ;D3AB ; load A into current-mode1000 0x82 ;D3AC ; (0xD382)1001 0xD3 ;D3AD1003 0xC3 ;D3AE ; go back to beginning1004 0x1D ;D3AF1005 0xD3 ;D3B01006 ;; End Mode 01009 ;; Mode 1 -- set-length mode1010 ;; 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 mode1013 ;; completes.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 A1019 0xD3 ;D3B31021 0xEA ;D3B4 ; load A into bytes-left-to-write1022 0x83 ;D3B5 ; (0xD383)1023 0xD3 ;D3B61025 0x3E ;D3B7 ; load 0x02 into A.1026 0x02 ;D3B81028 0xEA ;D3B9 ; load A to current-mode1029 0x82 ;D3BA ; advancing from Mode 1 to1030 0xD3 ;D3BB ; Mode 21032 0xC3 ;D3BC ; go back to beginning1033 0x1D ;D3BD1034 0xD3 ;D3BE1035 ;; End Mode 11038 ;; Mode 2 -- set start-point-high mode1039 ;; Middle part of the header for writing things to memory.1040 ;; User specifies the start location in RAM to which1041 ;; data will be written.1042 ;; Mode is auto advanced to Mode 3 after this mode completes.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 A1048 0xD3 ;D3C11050 0xEA ;D3C2 ; load A into start-point-high1051 0x85 ;D3C3 ; (0xD385)1052 0xD3 ;D3C41054 0x3E ;D3C5 ; load 0x03 into A.1055 0x03 ;D3C61057 0xEA ;D3C7 ; load A to current-mode,1058 0x82 ;D3C8 ; advancing from Mode 2 to1059 0xD3 ;D3C9 ; Mode 3.1061 0xC3 ;D3CA ; go back to beginning1062 0x1D ;D3CB1063 0xD3 ;D3CC1064 ;;End Mode 21067 ;; Mode 3 -- set-start-point-low mode1068 ;; Final part of header for writing things to memory.1069 ;; User specifies the low bytes of 16 bit start-point.1071 ;; Set start-point-low to input-number;1072 ;; set current mode to 0x041073 0xFA ;D3CD ; load input-number into A1074 0x52 ;D3CE1075 0xD3 ;D3CF1077 0xEA ;D3D0 ; load A into start-point-low1078 0x86 ;D3D11079 0xD3 ;D3D21081 0x3E ;D3D3 ; load 0x04 into A.1082 0x04 ;D3D41084 0xEA ;D3D5 ; load A to current-mode,1085 0x82 ;D3D6 ; advancing from Mode 3 to1086 0xD3 ;D3D7 ; Mode 4.1088 0xC3 ;D3D8 ; go back to beginning1089 0x1D ;D3D91090 0xD3 ;D3DA1092 ;; Mode 4 -- write bytes mode1094 ;; This is where RAM manipulation happens. User supplies1095 ;; bytes every frame, which are written sequentially to1096 ;; start-point until bytes-to-write have been written. Once1097 ;; bytes-to-write have been written, the mode is reset to 0.1099 ;; compare bytes-written with bytes-to-write.1100 ;; if they are the same, then reset mode to 01102 0xFA ;D3DB ; load bytes-to-write into A1103 0x83 ;D3DC1104 0xD3 ;D3DD1106 0x47 ;D3DE ; load A into B1108 0xFA ;D3DF ; load bytes-written into A1109 0x84 ;D3E01110 0xD3 ;D3E11112 0xB8 ;D3E2 ; compare A with B1114 0xCA ;D3E3 ; if they are equal, go to cleanup1115 0x07 ;D3E41116 0xD4 ;D3E51118 ;; Write Memory Section1119 ;; Write the input-number, interpreted as an 8-bit number,1120 ;; into the current target register, determined by1121 ;; (+ start-point bytes-written).1122 ;; Then, increment bytes-written by 1.1124 0xFA ;D3E6 ; load start-point-high into A1125 0x85 ;D3E71126 0xD3 ;D3E81128 0x67 ;D3E9 ; load A into H1130 0xFA ;D3EA ; load start-point-low into A1131 0x86 ;D3EB1132 0xD3 ;D3EC1134 0x6F ;D3ED ; load A into L1136 0xFA ;D3EE ; load bytes-written into A1137 0x84 ;D3EF1138 0xD3 ;D3F01140 0x00 ;D3F1 ; These are here because1141 0x00 ;D3F2 ; I screwed up again.1142 0x00 ;D3F31144 0x85 ;D3F4 ; add L to A; store A in L.1145 0x6F ;D3F51147 0x30 ;D3F6 ; If the addition overflowed,1148 0x01 ;D3F71149 0x24 ;D3F8 ; increment H.1151 ;; Now, HL points to the correct place in memory1153 0xFA ;D3F9 ; load input-number into A1154 0x52 ;D3FA1155 0xD3 ;D3FB1157 0x77 ;D3FC ; load A into (HL)1159 0xFA ;D3FD ; load bytes-written into A1160 0x84 ;D3FE1161 0xD3 ;D3FF1163 0x3C ;D400 ; increment A1165 0xEA ;D401 ; load A into bytes-written1166 0x84 ;D4021167 0xD3 ;D4031169 0xC3 ;D404 ; go back to beginning.1170 0x1D ;D4051171 0xD3 ;D4061172 ;; End Write Memory Section1174 ;; Mode 4 Cleanup Section1175 ;; reset bytes-written to 01176 ;; set mode to 01177 0x3E ;D407 ; load 0 into A1178 0x00 ;D4081180 0xEA ;D409 ; load A into bytes-written1181 0x84 ;D40A1182 0xD3 ;D40B1184 0xEA ;D40C ; load A into current-mode1185 0x82 ;D40D1186 0xD3 ;D40E1188 0xC3 ;D40F ; go back to beginning1189 0x1D ;D4101190 0xD3 ;D4111192 ;; End Mode 41194 ])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)1208 (defn write-memory []1209 (-> (tick (mid-game))1210 (IE! 0) ; disable interrupts1211 (inject-item-assembly (write-memory-assembly))))1213 (defn test-write-memory []1214 (set-state! (write-memory))1215 (dorun1216 (dotimes [_ 5000]1217 (view-memory (step @current-state) current-mode))))1219 (def bytes-to-write 0xD383)1220 (def start-point 0xD384)1222 (defn print-blank-assembly1223 [start end]1224 (dorun1225 (map1226 #(println (format "0x00 ;%04X " %))1227 (range start end))))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)))1242 (defn dylan-test-mode1243 ([] (dylan-test-mode (write-mem-dyl)))1244 ([target-state]1245 (let [1246 v-blank-prev 540461247 btn-register 652801248 eggs 0xD3741249 ]1251 (->1252 target-state1254 (tick)1255 (tick)1256 (tick)1257 (tick);; jumps back to beginning1259 (tick)1260 (tick)1261 (tick)1262 (tick)1263 (tick)1264 (tick)1265 (tick)1266 (tick)1267 (tick)1268 (tick)1269 (tick)1270 (tick)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 A1295 (tick)1296 (DE! 0x1800)1297 (AF! 0x7700) ;; change inputs @ A1298 (tick)1299 (tick)1300 (tick)1301 (tick)1302 (tick)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)1317 ;;(view-memory btn-register)1318 (view-register "A" A)1319 (view-register "B" B)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 ))))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 ))1352 (defn test-mode-41353 ([] (test-mode-4 (write-memory)))1354 ([target-state]1355 (->1356 target-state1357 (#(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)1366 ;; Activate memory writing mode1368 (#(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)1375 ;; Specify four bytes to be written1377 (#(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)1384 ;; Specify target memory address as 0xC00F1386 (#(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)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)1400 ;; Start reprogramming memory1402 (#(do (println "step with [:a]")%))1403 (step [:a])1404 (view-memory current-mode)1405 (view-memory bytes-written)1407 (#(do (println "step with [:b]")%))1408 (step [:b])1409 (view-memory current-mode)1410 (view-memory bytes-written)1412 (#(do (println "step with [:a :b]")%))1413 (step [:a :b])1414 (view-memory current-mode)1415 (view-memory bytes-written)1417 (#(do (println "step with [:select]")%))1418 (step [:select])1419 (view-memory current-mode)1420 (view-memory bytes-written)1422 ;; Reprogramming done, program ready for more commands.1424 (#(do (println "step with []")%))1425 (step [])1426 (view-memory current-mode)1427 (view-memory bytes-written)1429 (#(do (println "memory from 0xC00F to 0xC01F:"1430 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))