Mercurial > vba-clojure
view clojure/com/aurellem/assembly.clj @ 138:2b69cbe8a5b9
saving progress on state machine; 240 ops -> 90 ops (provided it withstands debugging)
author | Dylan Holmes <ocsenave@gmail.com> |
---|---|
date | Mon, 19 Mar 2012 03:05:42 -0500 |
parents | 1c58fa3cfc68 |
children | 74ec1ac044bb |
line wrap: on
line source
1 (ns com.aurellem.assembly2 (: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-assembly9 ([^SaveState state10 program-counter registers11 assembly-code]12 (let [scratch-memory (memory state)]13 ;; inject assembly code14 (dorun (map (fn [index val]15 (aset scratch-memory index val))16 (range program-counter17 (+ program-counter (count assembly-code)))18 assembly-code))19 (-> state20 (write-memory! scratch-memory)21 (write-registers! registers)22 (PC! program-counter)))))24 (defn inject-item-assembly25 ([^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 info33 ([^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-interrupt40 [^SaveState state]41 (println (format "IE: %d" (IE state)))42 state)44 (defn print-listing [state begin end]45 (dorun (map46 (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-assembly53 ([info-fn assembly n]54 (let [final-state55 (reduce (fn [state _]56 (tick (info-fn state)))57 (inject-item-assembly58 (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/parseInt78 (Integer/toBinaryString num) 10)))80 (defn view-register [state name reg-fn]81 (println (format "%s: %s" name82 (binary-str (reg-fn state))))83 state)85 (defn view-memory [state mem]86 (println (format "mem 0x%04X = %s" mem87 (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 (recur98 (conj program-counters99 (first (registers @current-state)))100 (conj opcodes101 (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 interrupts119 (inject-item-assembly120 ;; write 00010000 to 0xFF00 to select joypad121 [0x18 ;D31D ; jump over122 0x01 ;D31E ; the next 8 bits123 ;D31F124 (Integer/parseInt "00100000" 2) ; data section126 0xFA ;D320 ; load (D31F) into A127 0x1F ;D321 -->128 0xD3 ;D322 --> D31F130 0xEA ;D323 ; load (A), which is131 0x00 ;D324 --> ; 00010000, into FF00132 0xFF ;D325 --> FF00134 0x18 ;D326 ; this is the place where135 0x01 ;D327 ; we will store whether136 0x00 ;D328 ; "down" is pressed.138 0xFA ;D329 ; (FF00) -> A139 0x00 ;D32A140 0xFF ;D32B142 0xCB ;D32C ; Test whether "down"143 0x5F ;D32D ; is pressed.145 0x28 ;D32E ; if down is pressed,146 0x03 ;D32F ; skip the next section147 ; of code.148 ;; down-is-not-pressed149 0xC3 ;D330150 0x1D ;D331 ; return to beginning151 0xD3 ;D332153 ;; down-is-pressed154 0xEA ;D334 ; write A to D328 if155 0x28 ;D335 ; "down" was pressed156 0xD3 ;D336158 0xC3 ;D330159 0x1D ;D331 ; return to beginning160 0xD3 ;D332161 ])))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 interrupts170 (inject-item-assembly171 [0x18 ;D31D ; jump over172 0x02 ;D31E ; the next 2 bytes173 0x00 ;D31F ; frame-count174 0x00 ;D320 ; v-blank-prev176 0xFA ;D321177 0x41 ;D322 ; load (FF41) into A178 0xFF ;D323 ; this contains mode flags180 ;; if we're in v-blank, the bit-1 is 0181 ;; and bit-2 is 1 Otherwise, it is not v-blank.182 0xCB ;D324 ; test bit-1 of A183 0x4F ;D325185 0xC2 ;D326 ; if bit-1 is not 0186 0x44 ;D327 ; GOTO not-v-blank187 0xD3 ;D328189 0xCB ;D329 ; test bit-0 of A190 0x47 ;D32A192 0xCA ;D32B ; if bit-0 is not 1193 0x44 ;D32C ; GOTO not-v-blank194 0xD3 ;D32D195 ;;; in v-blank mode196 ;; if v-blank-prev was 0,197 ;; increment frame-count199 0xFA ;D32E ; load v-blank-prev to A200 0x20 ;D32F201 0xD3 ;D330203 0xCB ;D331204 0x47 ;D332 ; test bit-0 of A206 0x20 ;D333 ; skip next section207 0x07 ;D334 ; if v-blank-prev was not zero209 ;; v-blank was 0, increment frame-count210 0xFA ;D335 ; load frame-count into A211 0x1F ;D336212 0xD3 ;D337214 0x3C ;D338 ; inc A216 0xEA ;D339 ; load A into frame-count217 0x1F ;D33A218 0xD3 ;D33B220 ;; set v-blank-prev to 1221 0x3E ;D33C ; load 1 into A222 0x01 ;D33D224 0xEA ;D33E ; load A into v-blank-prev225 0x20 ;D33F226 0xD3 ;D340228 0xC3 ;D341 ; return to beginning229 0x1D ;D342230 0xD3 ;D343232 ;;; not in v-blank mode233 ;; set v-blank-prev to 0234 0x3E ;D344 ; load 0 into A235 0x00 ;D345237 0xEA ;D346 ; load A into v-blank-prev238 0x20 ;D347239 0xD3 ;D348241 0xC3 ;D349 ; return to beginning242 0x1D ;D34A243 0xD3 ;D34B244 ])))246 (defn step-count-frames []247 (-> (read-down-button)248 (info)249 (tick) ;; skip over data section250 (info)251 (view-register "Register A" A)252 (tick) ;; load-data into A253 (view-register "Register A" A)254 (info)255 (view-memory 0xFF00)256 (tick) ;; load A into 0xFF00257 (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 program278 ;; starts in "mode-select" mode279 ;; Each button press takes place in a single frame.280 ;; mode-select-mode takes one of the main buttons281 ;; which selects one of up to eight modes282 ;; mode 1 activated by the "A" button283 ;; the next two button presses indicates the start284 ;; memory location which to which the bootstrap285 ;; program will write.286 ;; This is done by using each of the eight buttons to287 ;; spell out an 8 bit number. The order of buttons is288 ;; [:d :u :l :r :start :select :b :a]289 ;; [:a :start :l] --> 00101001291 ;; the next button press determines how many bytes are to be292 ;; written, starting at the start position.294 ;; then, the actual bytes are entered and are written to the295 ;; start address in sequence.297 (defn input-number-assembly []298 [0x18 ;D31D ; jump over299 0x02 ;D31E ; the next 2 bytes300 0x00 ;D31F ; frame-count301 0x00 ;D320 ; v-blank-prev303 0xFA ;D321304 0x41 ;D322 ; load (FF41) into A305 0xFF ;D323 ; this contains mode flags307 ;; if we're in v-blank, the bit-1 is 0308 ;; and bit-2 is 1 Otherwise, it is not v-blank.309 0xCB ;D324 ; test bit-1 of A310 0x4F ;D325312 0xC2 ;D326 ; if bit-1 is not 0313 0x44 ;D327 ; GOTO not-v-blank314 0xD3 ;D328316 0xCB ;D329 ; test bit-0 of A317 0x47 ;D32A319 0xCA ;D32B ; if bit-0 is not 1320 0x44 ;D32C ; GOTO not-v-blank321 0xD3 ;D32D323 ;;; in v-blank mode325 ;; if v-blank-prev was 0,326 ;; increment frame-count328 0xFA ;D32E ; load v-blank-prev to A329 0x20 ;D32F330 0xD3 ;D330332 0xCB ;D331333 0x47 ;D332 ; test bit-0 of A335 0x20 ;D333 ; skip next section336 0x07 ;D334 ; if v-blank-prev was not zero338 ;; v-blank was 0, increment frame-count339 0xFA ;D335 ; load frame-count into A340 0x1F ;D336341 0xD3 ;D337343 0x3C ;D338 ; inc A345 0xEA ;D339 ; load A into frame-count346 0x1F ;D33A347 0xD3 ;D33B349 ;; set v-blank-prev to 1350 0x3E ;D33C ; load 1 into A351 0x01 ;D33D353 0xEA ;D33E ; load A into v-blank-prev354 0x20 ;D33F355 0xD3 ;D340357 0xC3 ;D341 ; GOTO input handling code358 0x4E ;D342359 0xD3 ;D343361 ;;; not in v-blank mode362 ;; set v-blank-prev to 0363 0x3E ;D344 ; load 0 into A364 0x00 ;D345366 0xEA ;D346 ; load A into v-blank-prev367 0x20 ;D347368 0xD3 ;D348370 0xC3 ;D349 ; return to beginning371 0x1D ;D34A372 0xD3 ;D34B374 0x00 ;D34C ; these are here375 0x00 ;D34D ; for glue378 ;;; calculate input number based on button presses379 0x18 ;D34E ; skip next 3 bytes380 0x03 ;D34F381 ;D350382 (Integer/parseInt "00100000" 2) ; select directional pad383 ;D351384 (Integer/parseInt "00010000" 2) ; select buttons385 0x00 ;D352 ; input-number387 ;; select directional pad, store low bits in B389 0xFA ;D353 ; load (D350) into A390 0x50 ;D354 -->391 0xD3 ;D355 --> D31F393 0xEA ;D356 ; load A, which is394 0x00 ;D357 --> ; 00010000, into FF00395 0xFF ;D358 --> FF00397 0x06 ;D359398 ;D35A399 (Integer/parseInt "11110000" 2) ; "11110000" -> B400 0xFA ;D35B ; (FF00) -> A401 0x00 ;D35C402 0xFF ;D35D404 0xCB ;D35E ; swap nybbles on A405 0x37 ;D35F406 0xA0 ;D360 ; (AND A B) -> A407 0x47 ;D361 ; A -> B409 ;; select buttons store bottom bits in C411 0xFA ; ; load (D351) into A412 0x51 ; -->413 0xD3 ; --> D31F415 0xEA ; ; load (A), which is416 0x00 ; --> ; 00001000, into FF00417 0xFF ; --> FF00419 0x0E ;420 (Integer/parseInt "00001111" 2) ; "00001111" -> C422 0xFA ; ; (FF00) -> A423 0x00 ;424 0xFF ;426 0xA1 ; ; (AND A C) -> A427 0x4F ; ; A -> C429 ;; combine the B and C registers into the input number430 0x79 ; ; C -> A431 0xB0 ; ; (OR A B) -> A432 0x2F ; ; negate A434 0xEA ; ; store A into input-number435 0x52 ;436 0xD3 ;438 0xC3 ; ; return to beginning439 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-tick453 ([state]454 (-> state print-pc print-op tick)))456 (defn input-number []457 (-> (tick (mid-game))458 (IE! 0) ; disable interrupts459 (inject-item-assembly (input-number-assembly))))461 (defn test-input-number462 "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))))495 (defn write-memory-assembly*496 "Currently, grabs input from the user each frame."497 []498 [499 ;; --------- FRAME METRONOME500 0x18 ;; jump ahead to cleanup. first time only.501 0x40 ;; v-blank-prev [D31E]503 0xFA ;; load modes into A [D31F]504 0x41505 0xFF507 0x47 ;; A -> B508 0xCB ;; rotate A509 0x2F510 0x2F ;; invert A512 0xA0513 0x47 ;; now B_0 contains (VB==1)515 0xFA ;; load v-blank-prev516 0x1E517 0xD3519 0x2F ;; complement v-blank-prev521 0xA0 ;; A & B --> A522 0x4F ;; now C_0 contains increment?525 0x78 ;; B->A526 0xEA ;; spit A --> vbprev527 0x1E528 0xD3530 0xCB ;test C_0531 0x41532 0x20 ; JUMP ahead to button input if nonzero533 0x02534 0x18 ; JUMP back to frame metronome (D31F)535 0xE6 ; todo: verify this jump length537 ;; -------- GET BUTTON INPUT539 ;; btw, C_0 is now 1540 ;; prepare to select bits542 0x06 ;; load 0x00 into B543 0x00 ;; to initialize for "OR" loop545 0x3E ;; load 0x20 into A, to measure dpad546 0x20549 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]550 0x00552 0xF0 ;; load A from [FF00]553 0x00555 0xE6 ;; bitmask 00001111556 0x0F558 0xB0 ;; A or B --> A559 0xCB560 0x41 ;; test bit 0 of C561 0x28 ;; JUMP forward if 0562 0x08564 0x47 ;; A -> B565 0xCB ;; swap B nybbles566 0x30567 0x0C ;; increment C568 0x3E ;; load 0x10 into A, to measure btns569 0x10570 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]571 0xED574 ;; ------ TAKE ACTION BASED ON USER INPUT576 ;; mode 0x00 : select mode577 ;; mode 0x08 : select bytes-to-write578 ;; mode 0x10 : select hi-bit579 ;; mode 0x18 : select lo-bit581 ;; mode 0xF0 : write bytes582 ;; mode 0xFF : jump PC585 ;; registers586 ;; D : mode select587 ;; E : count of bytes to write588 ;; H : address-high589 ;; L : address-low591 ;; now A contains the pressed keys592 0x2F ; complement A, by request. [D34F]594 0x47 ; A->B ;; now B contains the pressed keys595 0x7B ; E->A ;; now A contains the count.597 0xCB ; test bit 4 of D (are we in o/p mode?)598 0x26599 0x28 ; if test == 0, skip this o/p section600 0x13 ; JUMP602 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)603 0x42604 0x28 ; if test == 0, skip the following command605 0x01607 ;; output mode I: moving the program counter608 0xE9 ; ** move PC to (HL)610 ;; output mode II: writing bytes611 0xFE ; A compare 0. finished writing?612 0x00613 0x28 ; if we are not finished, skip cleanup614 0x04 ; JUMP616 ;; CLEANUP617 ;; btw, A is already zero.618 0xAF ; zero A [D35F]619 0x57 ; A->D; makes D=0.620 0x18 ; end of frame621 0xBC623 ;; ---- end of cleanup626 ;; continue writing bytes627 0x1D ;; decrement E, the number of bytes to write628 0x78 ;; B->A; now A contains the pressed keys629 0x77 ;; copy A to (HL)630 0x23 ;; increment HL631 0x18 ;; end frame.632 0xC2 ;; TODO: set skip length backwards635 ;; ---- end of o/p section637 ;; get data638 0x3E ;; load the constant 57 into A. [D369]639 0x57640 0x82 ;; add the mode to A641 0xEA ;; store A into "thing to execute"642 0x74643 0xD3645 0x3E ;; load the constant 8 into A646 0x08647 0x82 ;; add the mode to A648 0x57 ;; store the incremented mode into D649 0x78 ;; B->A; now A contains the pressed keys651 0x00 ;; var: thing to execute [D374]653 0x18 ;; end frame654 0xA8 ;; JUMP655 ]656 )658 (defn write-mem-dyl []659 (-> (tick (mid-game))660 (IE! 0)661 (inject-item-assembly (write-memory-assembly*))))664 (defn dylan* []665 (->666 (write-mem-dyl)668 (tick)669 (tick)670 (tick)671 (tick)672 (tick)673 (tick)674 (tick)675 (tick)676 (tick)677 (tick)678 (tick)679 (tick)680 (tick)681 (tick)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)697 (tick)698 (tick)699 (tick)700 (tick)701 (tick)702 (tick)703 (tick)705 ;;(view-memory 0xD374)706 (tick)707 (tick)708 (tick)709 (tick)710 (tick)711 (tick)712 (tick)713 (tick)714 (tick)715 (tick)716 (tick)717 (tick)718 (tick)719 (tick)720 (tick)721 ;;(view-memory 0xD374)722 (d-tick)724 (view-register "A" A)725 (view-register "B" B)726 (view-register "C" C))728 )731 (defn dylan []732 (->733 (write-mem-dyl)734 (tick)735 (tick)736 (tick)737 (tick)738 (tick)739 (tick)740 (tick)741 (tick)742 (tick)743 (tick)744 (tick)745 (tick)746 (tick)747 (tick)748 (tick) ;; first loop751 (tick)752 (tick)753 (tick)754 (tick)755 (tick)756 (tick)757 (tick)758 (tick)759 (tick)760 (tick)761 (tick)762 (tick)763 (tick) ;; dpad bits765 (tick)766 (tick)767 (tick)768 (tick)769 (tick)770 (tick)771 (tick)772 (tick)773 (d-tick)777 (view-register "A" A)778 (view-register "B" B)779 (view-register "C" C)781 ))786 (defn d2 []787 (->788 (write-mem-dyl)789 (view-memory 0xD31F)790 step step step step step791 (view-memory 0xD31F)))812 (defn write-memory-assembly []813 [814 ;; Main Timing Loop815 ;; Constantly check for v-blank and Trigger main state machine on816 ;; every transtion from v-blank to non-v-blank.818 0x18 ; D31D ; Variable declaration819 0x02 ; D31E820 0x00 ; D31F ; frame-count821 0x00 ; D320 ; v-blank-prev823 0xF0 ; D321 ; load v-blank mode flags into A824 0x41825 0x00828 ;; Branch dependent on v-blank. v-blank happens when the last two829 ;; bits in A are "01"830 0xCB ; D324831 0x4F ; D325833 0xC2 ; D326 ; if bit-1 is not 0, then834 0x3E ; D327 ; GOTO non-v-blank.835 0xD3 ; D328837 0xCB ; D329838 0x47 ; D32A840 0xCA ; D32B ; if bit-0 is not 1, then841 0x3E ; D32C ; GOTO non-v-blank.842 0xD3 ; D32D844 ;; V-Blank845 ;; Activate state-machine if this is a transition event.847 0xFA ; D32E ; load v-bank-prev into A848 0x20 ; D32F849 0xD3 ; D330851 0xFE ; D331 ; compare A to 0. >--------\852 0x00 ; D332 \853 ; |854 ;; set v-blank-prev to 1. |855 0x3E ; D333 ; load 1 into A. |856 0x01 ; D334 |857 ; |858 0xEA ; D335 ; load A into v-blank-prev |859 0x20 ; D336 |860 0xD3 ; D337 |861 ; /862 ;; if v-blank-prev was 0, activate state-machine <------/863 0xCA ; D338 ; if v-blank-prev864 0x46 ; D339 ; was 0,865 0xD3 ; D33A ; GOTO state-machine867 0xC3 ; D33B868 0x1D ; D33C869 0xD3 ; D33D ; GOTO beginning870 ;; END V-blank872 ;; Non-V-Blank873 ;; Set v-blank-prev to 0874 0x3E ; D33E ; load 0 into A875 0x00 ; D33F877 0xEA ; D340 ; load A into v-blank-prev878 0x20 ; D341879 0xD3 ; D342881 0xC3 ; D343882 0x1D ; D344883 0xD3 ; D345 ; GOTO beginning884 ;; END Not-V-Blank887 ;; Main State Machine -- Input Section888 ;; This is called once every frame.889 ;; It collects input and uses it to drive the890 ;; state transitions.892 ;; Increment frame-count893 0xFA ; D346 ; load frame-count into A894 0x1F ; D347895 0xD3 ; D348897 0x3C ; D349 ; inc A899 0xEA ; D34A900 0x1F ; D34B ; load A into frame-count901 0xD3 ; D34C903 0x00 ; D34D ; glue :)905 0x18 ;D34E ; skip next 3 bytes906 0x03 ;D34F907 ;D350908 (Integer/parseInt "00100000" 2) ; select directional pad909 ;D351910 (Integer/parseInt "00010000" 2) ; select buttons911 0x00 ;D352 ; input-number913 ;; select directional pad; store low bits in B915 0xFA ;D353 ; load (D350) into A916 0x50 ;D354 -->917 0xD3 ;D355 --> D350919 0xE0 ;D356 ; load (A), which is920 0x00 ;D357 --> ; 00010000, into FF00921 0x00 ;D358 --> FF00 ;; NO-OP923 0x06 ;D359924 ;D35A925 (Integer/parseInt "11110000" 2) ; "11110000" -> B926 0xF0 ;D35B ; (FF00) -> A927 0x00 ;D35C928 0x00 ;D35D ;; NO-OP930 0xCB ;D35E ; swap nybbles on A931 0x37 ;D35F932 0xA0 ;D360 ; (AND A B) -> A933 0x47 ;D361 ; A -> B935 ;; select buttons; store bottom bits in C937 0xFA ;D362 ; load (D351) into A938 0x51 ;D363 -->939 0xD3 ;D364 --> D351941 0xE0 ;D365 ; load (A), which is942 0x00 ;D366 --> ; 00001000, into FF00943 0x00 ;D367 --> FF00 ;; NO-OP945 0x0E ;D368946 ;D369947 (Integer/parseInt "00001111" 2) ; "00001111" -> C949 0xF0 ;D36A ; (FF00) -> A950 0x00 ;D36B951 0x00 ;D36C953 0xA1 ;D36D ; (AND A C) -> A954 0x4F ;D36E ; A -> C956 ;; combine the B and C registers into the input number957 0x79 ;D36F ; C -> A958 0xB0 ;D370 ; (OR A B) -> A959 0x2F ;D371 ; negate A961 0xEA ;D372 ; store A into input-number962 0x52 ;D373963 0xD3 ;D374965 0x00 ;D375966 0x00 ;D376967 0x00 ;D377968 0x00 ;D378969 0x00 ;D379970 0x00 ;D37A971 0x00 ;D37B ; these are here because972 0x00 ;D37C ; I messed up :(973 0x00 ;D37D974 0x00 ;D37E975 0x00 ;D37F977 ;; beginning of main state machine978 0x18 ;D380 ; Declaration of variables979 0x05 ;D381 ; 5 variables:980 0x00 ;D382 ; current-mode981 0x00 ;D383 ; bytes-to-write982 0x00 ;D384 ; bytes-written983 0x00 ;D385 ; start-point-high984 0x00 ;D386 ; start-point-low987 ;; banch on current mode988 0xFA ;D387 ; load current-mode (0xD382)989 0x82 ;D388 ; into A990 0xD3 ;D389991 0x00 ;D38A994 ;; GOTO Mode 0 (input-mode) if current-mode is 0995 0xFE ;D38B996 0x00 ;D38C ; compare A with 0x00998 0xCA ;D38D ; goto Mode 0 if A == 0999 0xA8 ;D38E1000 0xD3 ;D38F1002 ;; GOTO Mode 1 (set-length) if current-mode is 11003 0xFE ;D3901004 0x01 ;D391 ; compare A with 0x011006 0xCA ;D3921007 0xB1 ;D3931008 0xD3 ;D394 ; goto Mode 1 if A == 11010 ;; GOTO Mode 2 (set-start-point-high) if current mode is 21011 0xFE ;D3951012 0x02 ;D396 ; compare A with 0x021014 0xCA ;D3971015 0xBF ;D3981016 0xD3 ;D399 ; goto Mode 2 if A == 21018 ;; GOTO Mode 3 (set-start-point-low) if current mode is 31019 0xFE ;D39A1020 0x03 ;D39B1022 0xCA ;D39C1023 0xCD ;D39D1024 0xD3 ;D39E ; goto Mode 3 if A == 31026 ;; GOTO Mode 4 (write-memory) if current mode is 41027 0xFE ;D39F1028 0x04 ;D3A01030 0xCA ;D3A11031 0xDB ;D3A21032 0xD3 ;D3A31034 0x00 ;D3A41035 ;; End of Mode checking, goto beginning1036 0xC3 ;D3A51037 0x1D ;D3A61038 0xD3 ;D3A71041 ;; Mode 0 -- input-mode mode1042 ;; means that we are waiting for a mode, so set the mode to1043 ;; whatever is currently in input-number. If nothing is1044 ;; entered, then the program stays in input-mode mode1046 ;; set current-mode to input-number1047 0xFA ;D3A8 ; load input-number (0xD352)1048 0x52 ;D3A9 ; into A1049 0xD3 ;D3AA1051 0xEA ;D3AB ; load A into current-mode1052 0x82 ;D3AC ; (0xD382)1053 0xD3 ;D3AD1055 0xC3 ;D3AE ; go back to beginning1056 0x1D ;D3AF1057 0xD3 ;D3B01058 ;; End Mode 01061 ;; Mode 1 -- set-length mode1062 ;; This is the header for writing things to memory.1063 ;; User specifies the number of bytes to write.1064 ;; Mode is auto advanced to Mode 2 after this mode1065 ;; completes.1067 ;; Set bytes left to write to input-number;1068 ;; set current-mode to 0x02.1069 0xFA ;D3B1 ; load input-number (0xD352)1070 0x52 ;D3B2 ; into A1071 0xD3 ;D3B31073 0xEA ;D3B4 ; load A into bytes-left-to-write1074 0x83 ;D3B5 ; (0xD383)1075 0xD3 ;D3B61077 0x3E ;D3B7 ; load 0x02 into A.1078 0x02 ;D3B81080 0xEA ;D3B9 ; load A to current-mode1081 0x82 ;D3BA ; advancing from Mode 1 to1082 0xD3 ;D3BB ; Mode 21084 0xC3 ;D3BC ; go back to beginning1085 0x1D ;D3BD1086 0xD3 ;D3BE1087 ;; End Mode 11090 ;; Mode 2 -- set start-point-high mode1091 ;; Middle part of the header for writing things to memory.1092 ;; User specifies the start location in RAM to which1093 ;; data will be written.1094 ;; Mode is auto advanced to Mode 3 after this mode completes.1096 ;; Set start-point-high to input-number;1097 ;; set current mode to 0x03.1098 0xFA ;D3BF ; load input-number (0xD352)1099 0x52 ;D3C0 ; into A1100 0xD3 ;D3C11102 0xEA ;D3C2 ; load A into start-point-high1103 0x85 ;D3C3 ; (0xD385)1104 0xD3 ;D3C41106 0x3E ;D3C5 ; load 0x03 into A.1107 0x03 ;D3C61109 0xEA ;D3C7 ; load A to current-mode,1110 0x82 ;D3C8 ; advancing from Mode 2 to1111 0xD3 ;D3C9 ; Mode 3.1113 0xC3 ;D3CA ; go back to beginning1114 0x1D ;D3CB1115 0xD3 ;D3CC1116 ;;End Mode 21119 ;; Mode 3 -- set-start-point-low mode1120 ;; Final part of header for writing things to memory.1121 ;; User specifies the low bytes of 16 bit start-point.1123 ;; Set start-point-low to input-number;1124 ;; set current mode to 0x041125 0xFA ;D3CD ; load input-number into A1126 0x52 ;D3CE1127 0xD3 ;D3CF1129 0xEA ;D3D0 ; load A into start-point-low1130 0x86 ;D3D11131 0xD3 ;D3D21133 0x3E ;D3D3 ; load 0x04 into A.1134 0x04 ;D3D41136 0xEA ;D3D5 ; load A to current-mode,1137 0x82 ;D3D6 ; advancing from Mode 3 to1138 0xD3 ;D3D7 ; Mode 4.1140 0xC3 ;D3D8 ; go back to beginning1141 0x1D ;D3D91142 0xD3 ;D3DA1144 ;; Mode 4 -- write bytes mode1146 ;; This is where RAM manipulation happens. User supplies1147 ;; bytes every frame, which are written sequentially to1148 ;; start-point until bytes-to-write have been written. Once1149 ;; bytes-to-write have been written, the mode is reset to 0.1151 ;; compare bytes-written with bytes-to-write.1152 ;; if they are the same, then reset mode to 01154 0xFA ;D3DB ; load bytes-to-write into A1155 0x83 ;D3DC1156 0xD3 ;D3DD1158 0x47 ;D3DE ; load A into B1160 0xFA ;D3DF ; load bytes-written into A1161 0x84 ;D3E01162 0xD3 ;D3E11164 0xB8 ;D3E2 ; compare A with B1166 0xCA ;D3E3 ; if they are equal, go to cleanup1167 0x07 ;D3E41168 0xD4 ;D3E51170 ;; Write Memory Section1171 ;; Write the input-number, interpreted as an 8-bit number,1172 ;; into the current target register, determined by1173 ;; (+ start-point bytes-written).1174 ;; Then, increment bytes-written by 1.1176 0xFA ;D3E6 ; load start-point-high into A1177 0x85 ;D3E71178 0xD3 ;D3E81180 0x67 ;D3E9 ; load A into H1182 0xFA ;D3EA ; load start-point-low into A1183 0x86 ;D3EB1184 0xD3 ;D3EC1186 0x6F ;D3ED ; load A into L1188 0xFA ;D3EE ; load bytes-written into A1189 0x84 ;D3EF1190 0xD3 ;D3F01192 0x00 ;D3F1 ; These are here because1193 0x00 ;D3F2 ; I screwed up again.1194 0x00 ;D3F31196 0x85 ;D3F4 ; add L to A; store A in L.1197 0x6F ;D3F51199 0x30 ;D3F6 ; If the addition overflowed,1200 0x01 ;D3F71201 0x24 ;D3F8 ; increment H.1203 ;; Now, HL points to the correct place in memory1205 0xFA ;D3F9 ; load input-number into A1206 0x52 ;D3FA1207 0xD3 ;D3FB1209 0x77 ;D3FC ; load A into (HL)1211 0xFA ;D3FD ; load bytes-written into A1212 0x84 ;D3FE1213 0xD3 ;D3FF1215 0x3C ;D400 ; increment A1217 0xEA ;D401 ; load A into bytes-written1218 0x84 ;D4021219 0xD3 ;D4031221 0xC3 ;D404 ; go back to beginning.1222 0x1D ;D4051223 0xD3 ;D4061224 ;; End Write Memory Section1226 ;; Mode 4 Cleanup Section1227 ;; reset bytes-written to 01228 ;; set mode to 01229 0x3E ;D407 ; load 0 into A1230 0x00 ;D4081232 0xEA ;D409 ; load A into bytes-written1233 0x84 ;D40A1234 0xD3 ;D40B1236 0xEA ;D40C ; load A into current-mode1237 0x82 ;D40D1238 0xD3 ;D40E1240 0xC3 ;D40F ; go back to beginning1241 0x1D ;D4101242 0xD3 ;D4111244 ;; End Mode 41246 ])1250 (def frame-count 0xD31F)1251 (def input 0xD352)1252 (def current-mode 0xD382)1253 (def bytes-to-write 0xD383)1254 (def bytes-written 0xD384)1255 (def start-point-high 0xD385)1256 (def start-point-low 0xD386)1260 (defn write-memory []1261 (-> (tick (mid-game))1262 (IE! 0) ; disable interrupts1263 (inject-item-assembly (write-memory-assembly))))1265 (defn test-write-memory []1266 (set-state! (write-memory))1267 (dorun1268 (dotimes [_ 5000]1269 (view-memory (step @current-state) current-mode))))1271 (def bytes-to-write 0xD383)1272 (def start-point 0xD384)1274 (defn print-blank-assembly1275 [start end]1276 (dorun1277 (map1278 #(println (format "0x00 ;%04X " %))1279 (range start end))))1281 (defn test-mode-2 []1282 (->1283 (write-memory)1284 (view-memory frame-count)1285 (step)1286 (step [:a])1287 (step [:b])1288 (step [:start])1289 (step [])1290 (view-memory frame-count)))1292 (defn test-mode-41293 ([] (test-mode-4 (write-memory)))1294 ([target-state]1295 (->1296 target-state1297 (#(do (println "memory from 0xC00F to 0xC01F:"1298 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1299 (view-memory current-mode)1300 (step [])1301 (step [])1302 (step [])1303 (#(do (println "after three steps") %))1304 (view-memory current-mode)1306 ;; Activate memory writing mode1308 (#(do (println "step with [:a]") %))1309 (step [:a])1310 (view-memory current-mode)1311 (view-memory bytes-to-write)1312 (view-memory start-point-high)1313 (view-memory start-point-low)1315 ;; Specify four bytes to be written1317 (#(do (println "step with [:select]")%))1318 (step [:select])1319 (view-memory current-mode)1320 (view-memory bytes-to-write)1321 (view-memory start-point-high)1322 (view-memory start-point-low)1324 ;; Specify target memory address as 0xC00F1326 (#(do (println "step with [:u :d]")%))1327 (step [:u :d])1328 (view-memory current-mode)1329 (view-memory bytes-to-write)1330 (view-memory start-point-high)1331 (view-memory start-point-low)1333 (#(do (println "step with [:a :b :start :select]")%))1334 (step [:a :b :start :select])1335 (view-memory current-mode)1336 (view-memory bytes-to-write)1337 (view-memory start-point-high)1338 (view-memory start-point-low)1340 ;; Start reprogramming memory1342 (#(do (println "step with [:a]")%))1343 (step [:a])1344 (view-memory current-mode)1345 (view-memory bytes-written)1347 (#(do (println "step with [:b]")%))1348 (step [:b])1349 (view-memory current-mode)1350 (view-memory bytes-written)1352 (#(do (println "step with [:a :b]")%))1353 (step [:a :b])1354 (view-memory current-mode)1355 (view-memory bytes-written)1357 (#(do (println "step with [:select]")%))1358 (step [:select])1359 (view-memory current-mode)1360 (view-memory bytes-written)1362 ;; Reprogramming done, program ready for more commands.1364 (#(do (println "step with []")%))1365 (step [])1366 (view-memory current-mode)1367 (view-memory bytes-written)1369 (#(do (println "memory from 0xC00F to 0xC01F:"1370 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))