Mercurial > vba-clojure
view clojure/com/aurellem/assembly.clj @ 139:74ec1ac044bb
write-memory-assembly* confirmed...stage one.
author | Dylan Holmes <ocsenave@gmail.com> |
---|---|
date | Mon, 19 Mar 2012 05:12:05 -0500 |
parents | 2b69cbe8a5b9 |
children | aa5b5927e5fe |
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 D [state]73 (bit-shift-right (bit-and 0x0000FF00 (DE state)) 8))75 (defn H [state]76 (bit-shift-right (bit-and 0x0000FF00 (HL state)) 8))78 (defn C [state]79 (bit-and 0xFF (BC state)))80 (defn F [state]81 (bit-and 0xFF (AF state)))82 (defn E [state]83 (bit-and 0xFF (DE state)))84 (defn L [state]85 (bit-and 0xFF (HL state)))91 (defn binary-str [num]92 (format "%08d"93 (Integer/parseInt94 (Integer/toBinaryString num) 10)))96 (defn view-register [state name reg-fn]97 (println (format "%s: %s" name98 (binary-str (reg-fn state))))99 state)101 (defn view-memory [state mem]102 (println (format "mem 0x%04X = %s" mem103 (binary-str (aget (memory state) mem))))104 state)106 (defn trace [state]107 (loop [program-counters [(first (registers @current-state)) ]108 opcodes [(aget (memory @current-state) (PC @current-state))]]109 (let [frame-boundary?110 (com.aurellem.gb.Gb/tick)]111 (if frame-boundary?112 [program-counters opcodes]113 (recur114 (conj program-counters115 (first (registers @current-state)))116 (conj opcodes117 (aget (memory @current-state)118 (PC @current-state))))))))120 (defn print-trace [state n]121 (let [[program-counters opcodes] (trace state)]122 (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op)))123 (take n program-counters)124 (take n opcodes)))))126 (defn good-trace []127 (-> (mid-game) (tick) (IE! 0)128 (set-inv-mem [0x00 0x00 0X00 0x00])129 (PC! item-list-start)(print-interrupt)130 (info) (tick) (info) (tick) (info)))132 (defn read-down-button []133 (-> (tick (mid-game))134 (IE! 0) ; disable interrupts135 (inject-item-assembly136 ;; write 00010000 to 0xFF00 to select joypad137 [0x18 ;D31D ; jump over138 0x01 ;D31E ; the next 8 bits139 ;D31F140 (Integer/parseInt "00100000" 2) ; data section142 0xFA ;D320 ; load (D31F) into A143 0x1F ;D321 -->144 0xD3 ;D322 --> D31F146 0xEA ;D323 ; load (A), which is147 0x00 ;D324 --> ; 00010000, into FF00148 0xFF ;D325 --> FF00150 0x18 ;D326 ; this is the place where151 0x01 ;D327 ; we will store whether152 0x00 ;D328 ; "down" is pressed.154 0xFA ;D329 ; (FF00) -> A155 0x00 ;D32A156 0xFF ;D32B158 0xCB ;D32C ; Test whether "down"159 0x5F ;D32D ; is pressed.161 0x28 ;D32E ; if down is pressed,162 0x03 ;D32F ; skip the next section163 ; of code.164 ;; down-is-not-pressed165 0xC3 ;D330166 0x1D ;D331 ; return to beginning167 0xD3 ;D332169 ;; down-is-pressed170 0xEA ;D334 ; write A to D328 if171 0x28 ;D335 ; "down" was pressed172 0xD3 ;D336174 0xC3 ;D330175 0x1D ;D331 ; return to beginning176 0xD3 ;D332177 ])))179 (defn test-read-down []180 (= (view-memory (step (step (read-down-button) [:d])) 0xD328)181 (view-memory (step (step (read-down-button))) 0xD328)))183 (defn count-frames []184 (-> (tick (mid-game))185 (IE! 0) ; disable interrupts186 (inject-item-assembly187 [0x18 ;D31D ; jump over188 0x02 ;D31E ; the next 2 bytes189 0x00 ;D31F ; frame-count190 0x00 ;D320 ; v-blank-prev192 0xFA ;D321193 0x41 ;D322 ; load (FF41) into A194 0xFF ;D323 ; this contains mode flags196 ;; if we're in v-blank, the bit-1 is 0197 ;; and bit-2 is 1 Otherwise, it is not v-blank.198 0xCB ;D324 ; test bit-1 of A199 0x4F ;D325201 0xC2 ;D326 ; if bit-1 is not 0202 0x44 ;D327 ; GOTO not-v-blank203 0xD3 ;D328205 0xCB ;D329 ; test bit-0 of A206 0x47 ;D32A208 0xCA ;D32B ; if bit-0 is not 1209 0x44 ;D32C ; GOTO not-v-blank210 0xD3 ;D32D211 ;;; in v-blank mode212 ;; if v-blank-prev was 0,213 ;; increment frame-count215 0xFA ;D32E ; load v-blank-prev to A216 0x20 ;D32F217 0xD3 ;D330219 0xCB ;D331220 0x47 ;D332 ; test bit-0 of A222 0x20 ;D333 ; skip next section223 0x07 ;D334 ; if v-blank-prev was not zero225 ;; v-blank was 0, increment frame-count226 0xFA ;D335 ; load frame-count into A227 0x1F ;D336228 0xD3 ;D337230 0x3C ;D338 ; inc A232 0xEA ;D339 ; load A into frame-count233 0x1F ;D33A234 0xD3 ;D33B236 ;; set v-blank-prev to 1237 0x3E ;D33C ; load 1 into A238 0x01 ;D33D240 0xEA ;D33E ; load A into v-blank-prev241 0x20 ;D33F242 0xD3 ;D340244 0xC3 ;D341 ; return to beginning245 0x1D ;D342246 0xD3 ;D343248 ;;; not in v-blank mode249 ;; set v-blank-prev to 0250 0x3E ;D344 ; load 0 into A251 0x00 ;D345253 0xEA ;D346 ; load A into v-blank-prev254 0x20 ;D347255 0xD3 ;D348257 0xC3 ;D349 ; return to beginning258 0x1D ;D34A259 0xD3 ;D34B260 ])))262 (defn step-count-frames []263 (-> (read-down-button)264 (info)265 (tick) ;; skip over data section266 (info)267 (view-register "Register A" A)268 (tick) ;; load-data into A269 (view-register "Register A" A)270 (info)271 (view-memory 0xFF00)272 (tick) ;; load A into 0xFF00273 (view-memory 0xFF00)274 (info)275 (tick)276 (info)277 (tick)278 (info)279 (tick)280 (info)281 (tick)282 (info)283 (tick)284 (info)285 (tick)286 (print-inventory)))288 (defn test-count-frames []289 (= 255 (aget (memory ((apply comp (repeat 255 step))290 (count-frames)))291 0xD31F)))293 ;; specs for main bootstrap program294 ;; starts in "mode-select" mode295 ;; Each button press takes place in a single frame.296 ;; mode-select-mode takes one of the main buttons297 ;; which selects one of up to eight modes298 ;; mode 1 activated by the "A" button299 ;; the next two button presses indicates the start300 ;; memory location which to which the bootstrap301 ;; program will write.302 ;; This is done by using each of the eight buttons to303 ;; spell out an 8 bit number. The order of buttons is304 ;; [:d :u :l :r :start :select :b :a]305 ;; [:a :start :l] --> 00101001307 ;; the next button press determines how many bytes are to be308 ;; written, starting at the start position.310 ;; then, the actual bytes are entered and are written to the311 ;; start address in sequence.313 (defn input-number-assembly []314 [0x18 ;D31D ; jump over315 0x02 ;D31E ; the next 2 bytes316 0x00 ;D31F ; frame-count317 0x00 ;D320 ; v-blank-prev319 0xFA ;D321320 0x41 ;D322 ; load (FF41) into A321 0xFF ;D323 ; this contains mode flags323 ;; if we're in v-blank, the bit-1 is 0324 ;; and bit-2 is 1 Otherwise, it is not v-blank.325 0xCB ;D324 ; test bit-1 of A326 0x4F ;D325328 0xC2 ;D326 ; if bit-1 is not 0329 0x44 ;D327 ; GOTO not-v-blank330 0xD3 ;D328332 0xCB ;D329 ; test bit-0 of A333 0x47 ;D32A335 0xCA ;D32B ; if bit-0 is not 1336 0x44 ;D32C ; GOTO not-v-blank337 0xD3 ;D32D339 ;;; in v-blank mode341 ;; if v-blank-prev was 0,342 ;; increment frame-count344 0xFA ;D32E ; load v-blank-prev to A345 0x20 ;D32F346 0xD3 ;D330348 0xCB ;D331349 0x47 ;D332 ; test bit-0 of A351 0x20 ;D333 ; skip next section352 0x07 ;D334 ; if v-blank-prev was not zero354 ;; v-blank was 0, increment frame-count355 0xFA ;D335 ; load frame-count into A356 0x1F ;D336357 0xD3 ;D337359 0x3C ;D338 ; inc A361 0xEA ;D339 ; load A into frame-count362 0x1F ;D33A363 0xD3 ;D33B365 ;; set v-blank-prev to 1366 0x3E ;D33C ; load 1 into A367 0x01 ;D33D369 0xEA ;D33E ; load A into v-blank-prev370 0x20 ;D33F371 0xD3 ;D340373 0xC3 ;D341 ; GOTO input handling code374 0x4E ;D342375 0xD3 ;D343377 ;;; not in v-blank mode378 ;; set v-blank-prev to 0379 0x3E ;D344 ; load 0 into A380 0x00 ;D345382 0xEA ;D346 ; load A into v-blank-prev383 0x20 ;D347384 0xD3 ;D348386 0xC3 ;D349 ; return to beginning387 0x1D ;D34A388 0xD3 ;D34B390 0x00 ;D34C ; these are here391 0x00 ;D34D ; for glue394 ;;; calculate input number based on button presses395 0x18 ;D34E ; skip next 3 bytes396 0x03 ;D34F397 ;D350398 (Integer/parseInt "00100000" 2) ; select directional pad399 ;D351400 (Integer/parseInt "00010000" 2) ; select buttons401 0x00 ;D352 ; input-number403 ;; select directional pad, store low bits in B405 0xFA ;D353 ; load (D350) into A406 0x50 ;D354 -->407 0xD3 ;D355 --> D31F409 0xEA ;D356 ; load A, which is410 0x00 ;D357 --> ; 00010000, into FF00411 0xFF ;D358 --> FF00413 0x06 ;D359414 ;D35A415 (Integer/parseInt "11110000" 2) ; "11110000" -> B416 0xFA ;D35B ; (FF00) -> A417 0x00 ;D35C418 0xFF ;D35D420 0xCB ;D35E ; swap nybbles on A421 0x37 ;D35F422 0xA0 ;D360 ; (AND A B) -> A423 0x47 ;D361 ; A -> B425 ;; select buttons store bottom bits in C427 0xFA ; ; load (D351) into A428 0x51 ; -->429 0xD3 ; --> D31F431 0xEA ; ; load (A), which is432 0x00 ; --> ; 00001000, into FF00433 0xFF ; --> FF00435 0x0E ;436 (Integer/parseInt "00001111" 2) ; "00001111" -> C438 0xFA ; ; (FF00) -> A439 0x00 ;440 0xFF ;442 0xA1 ; ; (AND A C) -> A443 0x4F ; ; A -> C445 ;; combine the B and C registers into the input number446 0x79 ; ; C -> A447 0xB0 ; ; (OR A B) -> A448 0x2F ; ; negate A450 0xEA ; ; store A into input-number451 0x52 ;452 0xD3 ;454 0xC3 ; ; return to beginning455 0x1D ;456 0xD3 ;457 ])460 (defn print-pc [state]461 (println (format "PC: 0x%04X" (PC state)))462 state)464 (defn print-op [state]465 (println (format "OP: 0x%02X" (aget (memory state) (PC state))))466 state)468 (defn d-tick469 ([state]470 (-> state print-pc print-op tick)))472 (defn input-number []473 (-> (tick (mid-game))474 (IE! 0) ; disable interrupts475 (inject-item-assembly (input-number-assembly))))477 (defn test-input-number478 "Input freestyle buttons and observe the effects at the repl."479 []480 (set-state! (input-number))481 (dotimes [_ 90000] (step (view-memory @current-state 0xD352))))511 (defn write-memory-assembly*512 "Currently, grabs input from the user each frame."513 []514 [515 ;; --------- FRAME METRONOME516 0x18 ;; jump ahead to cleanup. first time only.517 0x40 ;; v-blank-prev [D31E]519 0xFA ;; load modes into A [D31F]520 0x41521 0xFF523 0x47 ;; A -> B524 0xCB ;; rotate A525 0x2F526 0x2F ;; invert A528 0xA0529 0x47 ;; now B_0 contains (VB==1)531 0xFA ;; load v-blank-prev532 0x1E533 0xD3535 0x2F ;; complement v-blank-prev537 0xA0 ;; A & B --> A538 0x4F ;; now C_0 contains increment?541 0x78 ;; B->A542 0xEA ;; spit A --> vbprev543 0x1E544 0xD3546 0xCB ;test C_0547 0x41548 0x20 ; JUMP ahead to button input if nonzero549 0x02550 0x18 ; JUMP back to frame metronome (D31F)551 0xE7553 ;; -------- GET BUTTON INPUT555 ;; btw, C_0 is now 1556 ;; prepare to select bits558 0x06 ;; load 0x00 into B559 0x00 ;; to initialize for "OR" loop561 0x3E ;; load 0x20 into A, to measure dpad562 0x20565 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]566 0x00568 0xF0 ;; load A from [FF00]569 0x00571 0xE6 ;; bitmask 00001111572 0x0F574 0xB0 ;; A or B --> A575 0xCB576 0x41 ;; test bit 0 of C577 0x28 ;; JUMP forward if 0578 0x08580 0x47 ;; A -> B581 0xCB ;; swap B nybbles582 0x30583 0x0C ;; increment C584 0x3E ;; load 0x10 into A, to measure btns585 0x10586 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]587 0xED590 ;; ------ TAKE ACTION BASED ON USER INPUT592 ;; "input mode"593 ;; mode 0x00 : select mode594 ;; mode 0x08 : select bytes-to-write595 ;; mode 0x10 : select hi-bit596 ;; mode 0x18 : select lo-bit598 ;; "output mode"599 ;; mode 0x20 : write bytes600 ;; mode 0xFF : jump PC603 ;; registers604 ;; D : mode select605 ;; E : count of bytes to write606 ;; H : address-high607 ;; L : address-low609 ;; now A contains the pressed keys610 0x2F ; complement A, by request. [D34F]612 0x47 ; A->B ;; now B contains the pressed keys613 0x7B ; E->A ;; now A contains the count.615 0xCB ; test bit 5 of D (are we in o/p mode?)616 0x6A617 0x28 ; if test == 0, skip this o/p section618 0x13 ; JUMP620 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)621 0x42622 0x28 ; if test == 0, skip the following command623 0x01625 ;; output mode I: moving the program counter626 0xE9 ; ** move PC to (HL)628 ;; output mode II: writing bytes629 0xFE ; A compare 0. finished writing?630 0x00631 0x20 ; if we are not finished, skip cleanup632 0x04 ; JUMP634 ;; CLEANUP635 ;; btw, A is already zero.636 0xAF ; zero A [D35F]637 0x57 ; A->D; makes D=0.638 0x18 ; end of frame639 0xBC641 ;; ---- end of cleanup644 ;; continue writing bytes645 0x1D ;; decrement E, the number of bytes to write [D363]646 0x78 ;; B->A; now A contains the pressed keys647 0x77 ;; copy A to (HL)648 0x23 ;; increment HL649 0x18 ;; end frame. [goto D31F]650 0xB6 ;; TODO: set skip length backwards653 ;; ---- end of o/p section655 ;; i/p mode656 ;; adhere to the mode discipline:657 ;; D must be one of 0x00 0x08 0x10 0x18.659 0x3E ;; load the constant 57 into A. [D369]660 0x57661 0x82 ;; add the mode to A662 0xEA ;; store A into "thing to execute"663 0x74664 0xD3666 0x3E ;; load the constant 8 into A667 0x08668 0x82 ;; add the mode to A670 0x57 ;; store the incremented mode into D671 0x78 ;; B->A; now A contains the pressed keys673 0x00 ;; var: thing to execute [D374]675 0x18 ;; end frame676 0xA8 ;; TODO: set jump correctly677 ]678 )680 (defn write-mem-dyl []681 (-> (tick (mid-game))682 (IE! 0)683 (inject-item-assembly (write-memory-assembly*))))686 (defn dylan* []687 (->688 (write-mem-dyl)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)704 (tick)705 (tick)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 (tick)722 (tick)723 (tick)724 (tick)725 (tick)727 ;;(view-memory 0xD374)728 (tick)729 (tick)730 (tick)731 (tick)732 (tick)733 (tick)734 (tick)735 (tick)736 (tick)737 (tick)738 (tick)739 (tick)740 (tick)741 (tick)742 (tick)743 ;;(view-memory 0xD374)744 (d-tick)746 (view-register "A" A)747 (view-register "B" B)748 (view-register "C" C))750 )753 (defn dylan []754 (->755 (write-mem-dyl)756 (tick)757 (tick)758 (tick)759 (tick)760 (tick)761 (tick)762 (tick)763 (tick)764 (tick)765 (tick)766 (tick)767 (tick)768 (tick)769 (tick)770 (tick) ;; first loop773 (tick)774 (tick)775 (tick)776 (tick)777 (tick)778 (tick)779 (tick)780 (tick)781 (tick)782 (tick)783 (tick)784 (tick)785 (tick) ;; dpad bits787 (tick)788 (tick)789 (tick)790 (tick)791 (tick)792 (tick)793 (tick)794 (tick)795 (d-tick)799 (view-register "A" A)800 (view-register "B" B)801 (view-register "C" C)803 ))808 (defn d2 []809 (->810 (write-mem-dyl)811 (view-memory 0xD31F)812 step step step step step813 (view-memory 0xD31F)))834 (defn write-memory-assembly []835 [836 ;; Main Timing Loop837 ;; Constantly check for v-blank and Trigger main state machine on838 ;; every transtion from v-blank to non-v-blank.840 0x18 ; D31D ; Variable declaration841 0x02 ; D31E842 0x00 ; D31F ; frame-count843 0x00 ; D320 ; v-blank-prev845 0xF0 ; D321 ; load v-blank mode flags into A846 0x41847 0x00850 ;; Branch dependent on v-blank. v-blank happens when the last two851 ;; bits in A are "01"852 0xCB ; D324853 0x4F ; D325855 0xC2 ; D326 ; if bit-1 is not 0, then856 0x3E ; D327 ; GOTO non-v-blank.857 0xD3 ; D328859 0xCB ; D329860 0x47 ; D32A862 0xCA ; D32B ; if bit-0 is not 1, then863 0x3E ; D32C ; GOTO non-v-blank.864 0xD3 ; D32D866 ;; V-Blank867 ;; Activate state-machine if this is a transition event.869 0xFA ; D32E ; load v-bank-prev into A870 0x20 ; D32F871 0xD3 ; D330873 0xFE ; D331 ; compare A to 0. >--------\874 0x00 ; D332 \875 ; |876 ;; set v-blank-prev to 1. |877 0x3E ; D333 ; load 1 into A. |878 0x01 ; D334 |879 ; |880 0xEA ; D335 ; load A into v-blank-prev |881 0x20 ; D336 |882 0xD3 ; D337 |883 ; /884 ;; if v-blank-prev was 0, activate state-machine <------/885 0xCA ; D338 ; if v-blank-prev886 0x46 ; D339 ; was 0,887 0xD3 ; D33A ; GOTO state-machine889 0xC3 ; D33B890 0x1D ; D33C891 0xD3 ; D33D ; GOTO beginning892 ;; END V-blank894 ;; Non-V-Blank895 ;; Set v-blank-prev to 0896 0x3E ; D33E ; load 0 into A897 0x00 ; D33F899 0xEA ; D340 ; load A into v-blank-prev900 0x20 ; D341901 0xD3 ; D342903 0xC3 ; D343904 0x1D ; D344905 0xD3 ; D345 ; GOTO beginning906 ;; END Not-V-Blank909 ;; Main State Machine -- Input Section910 ;; This is called once every frame.911 ;; It collects input and uses it to drive the912 ;; state transitions.914 ;; Increment frame-count915 0xFA ; D346 ; load frame-count into A916 0x1F ; D347917 0xD3 ; D348919 0x3C ; D349 ; inc A921 0xEA ; D34A922 0x1F ; D34B ; load A into frame-count923 0xD3 ; D34C925 0x00 ; D34D ; glue :)927 0x18 ;D34E ; skip next 3 bytes928 0x03 ;D34F929 ;D350930 (Integer/parseInt "00100000" 2) ; select directional pad931 ;D351932 (Integer/parseInt "00010000" 2) ; select buttons933 0x00 ;D352 ; input-number935 ;; select directional pad; store low bits in B937 0xFA ;D353 ; load (D350) into A938 0x50 ;D354 -->939 0xD3 ;D355 --> D350941 0xE0 ;D356 ; load (A), which is942 0x00 ;D357 --> ; 00010000, into FF00943 0x00 ;D358 --> FF00 ;; NO-OP945 0x06 ;D359946 ;D35A947 (Integer/parseInt "11110000" 2) ; "11110000" -> B948 0xF0 ;D35B ; (FF00) -> A949 0x00 ;D35C950 0x00 ;D35D ;; NO-OP952 0xCB ;D35E ; swap nybbles on A953 0x37 ;D35F954 0xA0 ;D360 ; (AND A B) -> A955 0x47 ;D361 ; A -> B957 ;; select buttons; store bottom bits in C959 0xFA ;D362 ; load (D351) into A960 0x51 ;D363 -->961 0xD3 ;D364 --> D351963 0xE0 ;D365 ; load (A), which is964 0x00 ;D366 --> ; 00001000, into FF00965 0x00 ;D367 --> FF00 ;; NO-OP967 0x0E ;D368968 ;D369969 (Integer/parseInt "00001111" 2) ; "00001111" -> C971 0xF0 ;D36A ; (FF00) -> A972 0x00 ;D36B973 0x00 ;D36C975 0xA1 ;D36D ; (AND A C) -> A976 0x4F ;D36E ; A -> C978 ;; combine the B and C registers into the input number979 0x79 ;D36F ; C -> A980 0xB0 ;D370 ; (OR A B) -> A981 0x2F ;D371 ; negate A983 0xEA ;D372 ; store A into input-number984 0x52 ;D373985 0xD3 ;D374987 0x00 ;D375988 0x00 ;D376989 0x00 ;D377990 0x00 ;D378991 0x00 ;D379992 0x00 ;D37A993 0x00 ;D37B ; these are here because994 0x00 ;D37C ; I messed up :(995 0x00 ;D37D996 0x00 ;D37E997 0x00 ;D37F999 ;; beginning of main state machine1000 0x18 ;D380 ; Declaration of variables1001 0x05 ;D381 ; 5 variables:1002 0x00 ;D382 ; current-mode1003 0x00 ;D383 ; bytes-to-write1004 0x00 ;D384 ; bytes-written1005 0x00 ;D385 ; start-point-high1006 0x00 ;D386 ; start-point-low1009 ;; banch on current mode1010 0xFA ;D387 ; load current-mode (0xD382)1011 0x82 ;D388 ; into A1012 0xD3 ;D3891013 0x00 ;D38A1016 ;; GOTO Mode 0 (input-mode) if current-mode is 01017 0xFE ;D38B1018 0x00 ;D38C ; compare A with 0x001020 0xCA ;D38D ; goto Mode 0 if A == 01021 0xA8 ;D38E1022 0xD3 ;D38F1024 ;; GOTO Mode 1 (set-length) if current-mode is 11025 0xFE ;D3901026 0x01 ;D391 ; compare A with 0x011028 0xCA ;D3921029 0xB1 ;D3931030 0xD3 ;D394 ; goto Mode 1 if A == 11032 ;; GOTO Mode 2 (set-start-point-high) if current mode is 21033 0xFE ;D3951034 0x02 ;D396 ; compare A with 0x021036 0xCA ;D3971037 0xBF ;D3981038 0xD3 ;D399 ; goto Mode 2 if A == 21040 ;; GOTO Mode 3 (set-start-point-low) if current mode is 31041 0xFE ;D39A1042 0x03 ;D39B1044 0xCA ;D39C1045 0xCD ;D39D1046 0xD3 ;D39E ; goto Mode 3 if A == 31048 ;; GOTO Mode 4 (write-memory) if current mode is 41049 0xFE ;D39F1050 0x04 ;D3A01052 0xCA ;D3A11053 0xDB ;D3A21054 0xD3 ;D3A31056 0x00 ;D3A41057 ;; End of Mode checking, goto beginning1058 0xC3 ;D3A51059 0x1D ;D3A61060 0xD3 ;D3A71063 ;; Mode 0 -- input-mode mode1064 ;; means that we are waiting for a mode, so set the mode to1065 ;; whatever is currently in input-number. If nothing is1066 ;; entered, then the program stays in input-mode mode1068 ;; set current-mode to input-number1069 0xFA ;D3A8 ; load input-number (0xD352)1070 0x52 ;D3A9 ; into A1071 0xD3 ;D3AA1073 0xEA ;D3AB ; load A into current-mode1074 0x82 ;D3AC ; (0xD382)1075 0xD3 ;D3AD1077 0xC3 ;D3AE ; go back to beginning1078 0x1D ;D3AF1079 0xD3 ;D3B01080 ;; End Mode 01083 ;; Mode 1 -- set-length mode1084 ;; This is the header for writing things to memory.1085 ;; User specifies the number of bytes to write.1086 ;; Mode is auto advanced to Mode 2 after this mode1087 ;; completes.1089 ;; Set bytes left to write to input-number;1090 ;; set current-mode to 0x02.1091 0xFA ;D3B1 ; load input-number (0xD352)1092 0x52 ;D3B2 ; into A1093 0xD3 ;D3B31095 0xEA ;D3B4 ; load A into bytes-left-to-write1096 0x83 ;D3B5 ; (0xD383)1097 0xD3 ;D3B61099 0x3E ;D3B7 ; load 0x02 into A.1100 0x02 ;D3B81102 0xEA ;D3B9 ; load A to current-mode1103 0x82 ;D3BA ; advancing from Mode 1 to1104 0xD3 ;D3BB ; Mode 21106 0xC3 ;D3BC ; go back to beginning1107 0x1D ;D3BD1108 0xD3 ;D3BE1109 ;; End Mode 11112 ;; Mode 2 -- set start-point-high mode1113 ;; Middle part of the header for writing things to memory.1114 ;; User specifies the start location in RAM to which1115 ;; data will be written.1116 ;; Mode is auto advanced to Mode 3 after this mode completes.1118 ;; Set start-point-high to input-number;1119 ;; set current mode to 0x03.1120 0xFA ;D3BF ; load input-number (0xD352)1121 0x52 ;D3C0 ; into A1122 0xD3 ;D3C11124 0xEA ;D3C2 ; load A into start-point-high1125 0x85 ;D3C3 ; (0xD385)1126 0xD3 ;D3C41128 0x3E ;D3C5 ; load 0x03 into A.1129 0x03 ;D3C61131 0xEA ;D3C7 ; load A to current-mode,1132 0x82 ;D3C8 ; advancing from Mode 2 to1133 0xD3 ;D3C9 ; Mode 3.1135 0xC3 ;D3CA ; go back to beginning1136 0x1D ;D3CB1137 0xD3 ;D3CC1138 ;;End Mode 21141 ;; Mode 3 -- set-start-point-low mode1142 ;; Final part of header for writing things to memory.1143 ;; User specifies the low bytes of 16 bit start-point.1145 ;; Set start-point-low to input-number;1146 ;; set current mode to 0x041147 0xFA ;D3CD ; load input-number into A1148 0x52 ;D3CE1149 0xD3 ;D3CF1151 0xEA ;D3D0 ; load A into start-point-low1152 0x86 ;D3D11153 0xD3 ;D3D21155 0x3E ;D3D3 ; load 0x04 into A.1156 0x04 ;D3D41158 0xEA ;D3D5 ; load A to current-mode,1159 0x82 ;D3D6 ; advancing from Mode 3 to1160 0xD3 ;D3D7 ; Mode 4.1162 0xC3 ;D3D8 ; go back to beginning1163 0x1D ;D3D91164 0xD3 ;D3DA1166 ;; Mode 4 -- write bytes mode1168 ;; This is where RAM manipulation happens. User supplies1169 ;; bytes every frame, which are written sequentially to1170 ;; start-point until bytes-to-write have been written. Once1171 ;; bytes-to-write have been written, the mode is reset to 0.1173 ;; compare bytes-written with bytes-to-write.1174 ;; if they are the same, then reset mode to 01176 0xFA ;D3DB ; load bytes-to-write into A1177 0x83 ;D3DC1178 0xD3 ;D3DD1180 0x47 ;D3DE ; load A into B1182 0xFA ;D3DF ; load bytes-written into A1183 0x84 ;D3E01184 0xD3 ;D3E11186 0xB8 ;D3E2 ; compare A with B1188 0xCA ;D3E3 ; if they are equal, go to cleanup1189 0x07 ;D3E41190 0xD4 ;D3E51192 ;; Write Memory Section1193 ;; Write the input-number, interpreted as an 8-bit number,1194 ;; into the current target register, determined by1195 ;; (+ start-point bytes-written).1196 ;; Then, increment bytes-written by 1.1198 0xFA ;D3E6 ; load start-point-high into A1199 0x85 ;D3E71200 0xD3 ;D3E81202 0x67 ;D3E9 ; load A into H1204 0xFA ;D3EA ; load start-point-low into A1205 0x86 ;D3EB1206 0xD3 ;D3EC1208 0x6F ;D3ED ; load A into L1210 0xFA ;D3EE ; load bytes-written into A1211 0x84 ;D3EF1212 0xD3 ;D3F01214 0x00 ;D3F1 ; These are here because1215 0x00 ;D3F2 ; I screwed up again.1216 0x00 ;D3F31218 0x85 ;D3F4 ; add L to A; store A in L.1219 0x6F ;D3F51221 0x30 ;D3F6 ; If the addition overflowed,1222 0x01 ;D3F71223 0x24 ;D3F8 ; increment H.1225 ;; Now, HL points to the correct place in memory1227 0xFA ;D3F9 ; load input-number into A1228 0x52 ;D3FA1229 0xD3 ;D3FB1231 0x77 ;D3FC ; load A into (HL)1233 0xFA ;D3FD ; load bytes-written into A1234 0x84 ;D3FE1235 0xD3 ;D3FF1237 0x3C ;D400 ; increment A1239 0xEA ;D401 ; load A into bytes-written1240 0x84 ;D4021241 0xD3 ;D4031243 0xC3 ;D404 ; go back to beginning.1244 0x1D ;D4051245 0xD3 ;D4061246 ;; End Write Memory Section1248 ;; Mode 4 Cleanup Section1249 ;; reset bytes-written to 01250 ;; set mode to 01251 0x3E ;D407 ; load 0 into A1252 0x00 ;D4081254 0xEA ;D409 ; load A into bytes-written1255 0x84 ;D40A1256 0xD3 ;D40B1258 0xEA ;D40C ; load A into current-mode1259 0x82 ;D40D1260 0xD3 ;D40E1262 0xC3 ;D40F ; go back to beginning1263 0x1D ;D4101264 0xD3 ;D4111266 ;; End Mode 41268 ])1272 (def frame-count 0xD31F)1273 (def input 0xD352)1274 (def current-mode 0xD382)1275 (def bytes-to-write 0xD383)1276 (def bytes-written 0xD384)1277 (def start-point-high 0xD385)1278 (def start-point-low 0xD386)1282 (defn write-memory []1283 (-> (tick (mid-game))1284 (IE! 0) ; disable interrupts1285 (inject-item-assembly (write-memory-assembly))))1287 (defn test-write-memory []1288 (set-state! (write-memory))1289 (dorun1290 (dotimes [_ 5000]1291 (view-memory (step @current-state) current-mode))))1293 (def bytes-to-write 0xD383)1294 (def start-point 0xD384)1296 (defn print-blank-assembly1297 [start end]1298 (dorun1299 (map1300 #(println (format "0x00 ;%04X " %))1301 (range start end))))1303 (defn test-mode-2 []1304 (->1305 (write-memory)1306 (view-memory frame-count)1307 (step)1308 (step [:a])1309 (step [:b])1310 (step [:start])1311 (step [])1312 (view-memory frame-count)))1316 (defn dylan-test-mode1317 ([] (dylan-test-mode (write-mem-dyl)))1318 ([target-state]1319 (let [1320 v-blank-prev 540461321 btn-register 652801322 eggs 0xD3741323 ]1325 (->1326 target-state1328 (tick)1329 (tick)1330 (tick)1331 (tick);; jumps back to beginning1333 (tick)1334 (tick)1335 (tick)1336 (tick)1337 (tick)1338 (tick)1339 (tick)1340 (tick)1341 (tick)1342 (tick)1343 (tick)1344 (tick)1347 (tick)1348 (tick)1349 (tick)1350 (tick)1351 (tick)1352 (tick)1353 (tick)1354 (tick)1355 (tick)1356 (tick)1357 (tick)1358 (tick)1359 (tick)1360 (tick)1361 (tick)1362 (tick)1363 (tick)1364 (tick)1365 (tick)1366 (tick)1367 (tick) ;; just complemented A1369 (tick)1370 (DE! 0x0800)1371 (AF! 0xCF00) ;; change inputs @ A1372 (tick)1373 (tick)1374 (tick)1375 (tick)1376 (tick)1378 ;;(view-memory eggs)1379 (tick)1380 (tick)1381 ;;(view-memory eggs)1382 (tick)1383 (tick)1384 (tick)1385 (tick)1387 (d-tick)1390 ;;(view-memory btn-register)1391 (view-register "A" A)1392 (view-register "B" B)1394 ;;(view-register "C" C)1395 (view-register "D" D)1396 (view-register "E" E)1397 (view-register "H" H)1398 (view-register "L" L)1399 ))))1406 (defn test-mode-41407 ([] (test-mode-4 (write-memory)))1408 ([target-state]1409 (->1410 target-state1411 (#(do (println "memory from 0xC00F to 0xC01F:"1412 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1413 (view-memory current-mode)1414 (step [])1415 (step [])1416 (step [])1417 (#(do (println "after three steps") %))1418 (view-memory current-mode)1420 ;; Activate memory writing mode1422 (#(do (println "step with [:a]") %))1423 (step [:a])1424 (view-memory current-mode)1425 (view-memory bytes-to-write)1426 (view-memory start-point-high)1427 (view-memory start-point-low)1429 ;; Specify four bytes to be written1431 (#(do (println "step with [:select]")%))1432 (step [:select])1433 (view-memory current-mode)1434 (view-memory bytes-to-write)1435 (view-memory start-point-high)1436 (view-memory start-point-low)1438 ;; Specify target memory address as 0xC00F1440 (#(do (println "step with [:u :d]")%))1441 (step [:u :d])1442 (view-memory current-mode)1443 (view-memory bytes-to-write)1444 (view-memory start-point-high)1445 (view-memory start-point-low)1447 (#(do (println "step with [:a :b :start :select]")%))1448 (step [:a :b :start :select])1449 (view-memory current-mode)1450 (view-memory bytes-to-write)1451 (view-memory start-point-high)1452 (view-memory start-point-low)1454 ;; Start reprogramming memory1456 (#(do (println "step with [:a]")%))1457 (step [:a])1458 (view-memory current-mode)1459 (view-memory bytes-written)1461 (#(do (println "step with [:b]")%))1462 (step [:b])1463 (view-memory current-mode)1464 (view-memory bytes-written)1466 (#(do (println "step with [:a :b]")%))1467 (step [:a :b])1468 (view-memory current-mode)1469 (view-memory bytes-written)1471 (#(do (println "step with [:select]")%))1472 (step [:select])1473 (view-memory current-mode)1474 (view-memory bytes-written)1476 ;; Reprogramming done, program ready for more commands.1478 (#(do (println "step with []")%))1479 (step [])1480 (view-memory current-mode)1481 (view-memory bytes-written)1483 (#(do (println "memory from 0xC00F to 0xC01F:"1484 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))