Mercurial > vba-clojure
view clojure/com/aurellem/gb/assembly.clj @ 175:5d9a7a0ca09a
beginning test of latest assembly code. 240->70.
author | Dylan Holmes <ocsenave@gmail.com> |
---|---|
date | Wed, 21 Mar 2012 18:17:37 -0500 |
parents | 412ca096a9ba |
children | 95b2758dd517 |
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))))410 (defn write-memory-assembly*411 "A program for altering in-game memory by pressing buttons."412 []413 [414 0xF3 ; stop interrupts415 ;; --------- CLEANUP416 0xAF ; zero A [D31E]417 0x57 ; A->D; makes D=0.419 ;; --------- FRAME METRONOME420 0xF1 ;; pop AF (vblank prev) [D320]422 0x2F ;; invert A423 0x47 ;; A -> B425 0xF0 ;; copy STAT into A426 0x41428 0xCB ;; swap A nybbles; now A_0 is (VB==1).429 0x37431 0xF5 ;; push AF (vbprev)433 0xA0 ;; A & B --> A. Now A_0 contains "increment?"435 0xCB ;; test A_0. this result will be used twice.436 0x47437 0x28 ;; end frame (JUMP) if A_0 = 0.438 0x00 ;; TODO: set jump length440 ;; -------- GET BUTTON INPUT442 ;; btw, Z bit is now 1443 ;; prepare to select bits445 0x3E ;; load 0x20 into A, to measure dpad446 0x20448 0x06 ;; load 0x00 into B449 0x00 ;; to initialize for "OR" loop451 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]452 0x00454 0xF0 ;; load A from [FF00]455 0x00457 0xE6 ;; bitmask 00001111458 0x0F460 0xB0 ;; A or B --> A462 0x28 ;; JUMP forward if Z=0463 0x08465 0x47 ;; A -> B466 0xCB ;; swap B nybbles467 0x30469 0x3E ;; load 0x10 into A, to measure btns470 0x10472 0xBF ;; compare(A,A) sets Z=0474 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]475 0xED478 ;; ------ TAKE ACTION BASED ON USER INPUT480 ;; "input mode"481 ;; mode 0x00 : select mode482 ;; mode 0x08 : select bytes-to-write483 ;; mode 0x10 : select hi-bit484 ;; mode 0x18 : select lo-bit486 ;; "output mode"487 ;; mode 0x20 : write bytes488 ;; mode 0xFF : jump PC491 ;; registers492 ;; D : mode select493 ;; E : count of bytes to write494 ;; H : address-high495 ;; L : address-low497 ;; now A contains the pressed keys498 0x2F ; complement A, by request. [D34F]500 0x47 ; A->B ;; now B contains the pressed keys502 0xCB ; test bit 5 of D (are we in o/p mode?)503 0x6A504 0x28 ; if test == 0, skip this o/p section505 0x13 ; JUMP507 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)508 0x42509 0x28 ; if test == 0, skip the following command510 0x01512 ;; output mode I: moving the program counter513 0xE9 ; ** move PC to (HL)515 ;; output mode II: writing bytes516 0xAF ; zero A517 0xBB ; compare count to zero. finished writing?518 0x28 ; if we are finished, jump back to cleanup519 0x00 ; TODO: set jump length backwards.521 ;; continue writing bytes522 0x78 ;; B->A523 0x22 ;; copy A to (HL) and increment HL.524 0x18 ;; end frame. [goto D31F]525 0xB6 ;; JUMP528 ;; ---- end of o/p section530 ;; i/p mode531 ;; adhere to the mode discipline:532 ;; D must be one of 0x00 0x08 0x10 0x18.534 0x3E ;; load the constant 57 into A. [D369]535 0x57536 0x82 ;; add the mode to A537 0xEA ;; store A into "thing to execute"538 0x74539 0xD3541 0x3E ;; load the constant 8 into A542 0x08543 0x82 ;; add the mode to A545 0x57 ;; store the incremented mode into D546 0x78 ;; B->A; now A contains the pressed keys548 0x00 ;; var: thing to execute [D374]550 0x18 ;; end frame551 0xA8 ;; JUMP552 ]553 )555 (defn write-mem-dyl []556 (-> (tick (mid-game))557 (IE! 0)558 (inject-item-assembly (write-memory-assembly*))))561 (defn dylan* []562 (->563 (write-mem-dyl)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)600 (tick)602 ;;(view-memory 0xD374)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 (tick)618 ;;(view-memory 0xD374)619 (d-tick)621 (view-register "A" A)622 (view-register "B" B)623 (view-register "C" C))625 )628 (defn dylan []629 (->630 (write-mem-dyl)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) ;; first loop648 (tick)649 (tick)650 (tick)651 (tick)652 (tick)653 (tick)654 (tick)655 (tick)656 (tick)657 (tick)658 (tick)659 (tick)660 (tick) ;; dpad bits662 (tick)663 (tick)664 (tick)665 (tick)666 (tick)667 (tick)668 (tick)669 (tick)670 (d-tick)674 (view-register "A" A)675 (view-register "B" B)676 (view-register "C" C)678 ))683 (defn d2 []684 (->685 (write-mem-dyl)686 (view-memory 0xD31F)687 step step step step step688 (view-memory 0xD31F)))709 (defn write-memory-assembly []710 [711 ;; Main Timing Loop712 ;; Constantly check for v-blank and Trigger main state machine on713 ;; every transtion from v-blank to non-v-blank.715 0x18 ; D31D ; Variable declaration716 0x02 ; D31E717 0x00 ; D31F ; frame-count718 0x00 ; D320 ; v-blank-prev720 0xF0 ; D321 ; load v-blank mode flags into A721 0x41722 0x00725 ;; Branch dependent on v-blank. v-blank happens when the last two726 ;; bits in A are "01"727 0xCB ; D324728 0x4F ; D325730 0xC2 ; D326 ; if bit-1 is not 0, then731 0x3E ; D327 ; GOTO non-v-blank.732 0xD3 ; D328734 0xCB ; D329735 0x47 ; D32A737 0xCA ; D32B ; if bit-0 is not 1, then738 0x3E ; D32C ; GOTO non-v-blank.739 0xD3 ; D32D741 ;; V-Blank742 ;; Activate state-machine if this is a transition event.744 0xFA ; D32E ; load v-bank-prev into A745 0x20 ; D32F746 0xD3 ; D330748 0xFE ; D331 ; compare A to 0. >--------\749 0x00 ; D332 \750 ; |751 ;; set v-blank-prev to 1. |752 0x3E ; D333 ; load 1 into A. |753 0x01 ; D334 |754 ; |755 0xEA ; D335 ; load A into v-blank-prev |756 0x20 ; D336 |757 0xD3 ; D337 |758 ; /759 ;; if v-blank-prev was 0, activate state-machine <------/760 0xCA ; D338 ; if v-blank-prev761 0x46 ; D339 ; was 0,762 0xD3 ; D33A ; GOTO state-machine764 0xC3 ; D33B765 0x1D ; D33C766 0xD3 ; D33D ; GOTO beginning767 ;; END V-blank769 ;; Non-V-Blank770 ;; Set v-blank-prev to 0771 0x3E ; D33E ; load 0 into A772 0x00 ; D33F774 0xEA ; D340 ; load A into v-blank-prev775 0x20 ; D341776 0xD3 ; D342778 0xC3 ; D343779 0x1D ; D344780 0xD3 ; D345 ; GOTO beginning781 ;; END Not-V-Blank784 ;; Main State Machine -- Input Section785 ;; This is called once every frame.786 ;; It collects input and uses it to drive the787 ;; state transitions.789 ;; Increment frame-count790 0xFA ; D346 ; load frame-count into A791 0x1F ; D347792 0xD3 ; D348794 0x3C ; D349 ; inc A796 0xEA ; D34A797 0x1F ; D34B ; load A into frame-count798 0xD3 ; D34C800 0x00 ; D34D ; glue :)802 0x18 ;D34E ; skip next 3 bytes803 0x03 ;D34F804 ;D350805 (Integer/parseInt "00100000" 2) ; select directional pad806 ;D351807 (Integer/parseInt "00010000" 2) ; select buttons808 0x00 ;D352 ; input-number810 ;; select directional pad; store low bits in B812 0xFA ;D353 ; load (D350) into A813 0x50 ;D354 -->814 0xD3 ;D355 --> D350816 0xE0 ;D356 ; load (A), which is817 0x00 ;D357 --> ; 00010000, into FF00818 0x00 ;D358 --> FF00 ;; NO-OP820 0x06 ;D359821 ;D35A822 (Integer/parseInt "11110000" 2) ; "11110000" -> B823 0xF0 ;D35B ; (FF00) -> A824 0x00 ;D35C825 0x00 ;D35D ;; NO-OP827 0xCB ;D35E ; swap nybbles on A828 0x37 ;D35F829 0xA0 ;D360 ; (AND A B) -> A830 0x47 ;D361 ; A -> B832 ;; select buttons; store bottom bits in C834 0xFA ;D362 ; load (D351) into A835 0x51 ;D363 -->836 0xD3 ;D364 --> D351838 0xE0 ;D365 ; load (A), which is839 0x00 ;D366 --> ; 00001000, into FF00840 0x00 ;D367 --> FF00 ;; NO-OP842 0x0E ;D368843 ;D369844 (Integer/parseInt "00001111" 2) ; "00001111" -> C846 0xF0 ;D36A ; (FF00) -> A847 0x00 ;D36B848 0x00 ;D36C850 0xA1 ;D36D ; (AND A C) -> A851 0x4F ;D36E ; A -> C853 ;; combine the B and C registers into the input number854 0x79 ;D36F ; C -> A855 0xB0 ;D370 ; (OR A B) -> A856 0x2F ;D371 ; negate A858 0xEA ;D372 ; store A into input-number859 0x52 ;D373860 0xD3 ;D374862 0x00 ;D375863 0x00 ;D376864 0x00 ;D377865 0x00 ;D378866 0x00 ;D379867 0x00 ;D37A868 0x00 ;D37B ; these are here because869 0x00 ;D37C ; I messed up :(870 0x00 ;D37D871 0x00 ;D37E872 0x00 ;D37F874 ;; beginning of main state machine875 0x18 ;D380 ; Declaration of variables876 0x05 ;D381 ; 5 variables:877 0x00 ;D382 ; current-mode878 0x00 ;D383 ; bytes-to-write879 0x00 ;D384 ; bytes-written880 0x00 ;D385 ; start-point-high881 0x00 ;D386 ; start-point-low884 ;; banch on current mode885 0xFA ;D387 ; load current-mode (0xD382)886 0x82 ;D388 ; into A887 0xD3 ;D389888 0x00 ;D38A891 ;; GOTO Mode 0 (input-mode) if current-mode is 0892 0xFE ;D38B893 0x00 ;D38C ; compare A with 0x00895 0xCA ;D38D ; goto Mode 0 if A == 0896 0xA8 ;D38E897 0xD3 ;D38F899 ;; GOTO Mode 1 (set-length) if current-mode is 1900 0xFE ;D390901 0x01 ;D391 ; compare A with 0x01903 0xCA ;D392904 0xB1 ;D393905 0xD3 ;D394 ; goto Mode 1 if A == 1907 ;; GOTO Mode 2 (set-start-point-high) if current mode is 2908 0xFE ;D395909 0x02 ;D396 ; compare A with 0x02911 0xCA ;D397912 0xBF ;D398913 0xD3 ;D399 ; goto Mode 2 if A == 2915 ;; GOTO Mode 3 (set-start-point-low) if current mode is 3916 0xFE ;D39A917 0x03 ;D39B919 0xCA ;D39C920 0xCD ;D39D921 0xD3 ;D39E ; goto Mode 3 if A == 3923 ;; GOTO Mode 4 (write-memory) if current mode is 4924 0xFE ;D39F925 0x04 ;D3A0927 0xCA ;D3A1928 0xDB ;D3A2929 0xD3 ;D3A3931 0x00 ;D3A4932 ;; End of Mode checking, goto beginning933 0xC3 ;D3A5934 0x1D ;D3A6935 0xD3 ;D3A7938 ;; Mode 0 -- input-mode mode939 ;; means that we are waiting for a mode, so set the mode to940 ;; whatever is currently in input-number. If nothing is941 ;; entered, then the program stays in input-mode mode943 ;; set current-mode to input-number944 0xFA ;D3A8 ; load input-number (0xD352)945 0x52 ;D3A9 ; into A946 0xD3 ;D3AA948 0xEA ;D3AB ; load A into current-mode949 0x82 ;D3AC ; (0xD382)950 0xD3 ;D3AD952 0xC3 ;D3AE ; go back to beginning953 0x1D ;D3AF954 0xD3 ;D3B0955 ;; End Mode 0958 ;; Mode 1 -- set-length mode959 ;; This is the header for writing things to memory.960 ;; User specifies the number of bytes to write.961 ;; Mode is auto advanced to Mode 2 after this mode962 ;; completes.964 ;; Set bytes left to write to input-number;965 ;; set current-mode to 0x02.966 0xFA ;D3B1 ; load input-number (0xD352)967 0x52 ;D3B2 ; into A968 0xD3 ;D3B3970 0xEA ;D3B4 ; load A into bytes-left-to-write971 0x83 ;D3B5 ; (0xD383)972 0xD3 ;D3B6974 0x3E ;D3B7 ; load 0x02 into A.975 0x02 ;D3B8977 0xEA ;D3B9 ; load A to current-mode978 0x82 ;D3BA ; advancing from Mode 1 to979 0xD3 ;D3BB ; Mode 2981 0xC3 ;D3BC ; go back to beginning982 0x1D ;D3BD983 0xD3 ;D3BE984 ;; End Mode 1987 ;; Mode 2 -- set start-point-high mode988 ;; Middle part of the header for writing things to memory.989 ;; User specifies the start location in RAM to which990 ;; data will be written.991 ;; Mode is auto advanced to Mode 3 after this mode completes.993 ;; Set start-point-high to input-number;994 ;; set current mode to 0x03.995 0xFA ;D3BF ; load input-number (0xD352)996 0x52 ;D3C0 ; into A997 0xD3 ;D3C1999 0xEA ;D3C2 ; load A into start-point-high1000 0x85 ;D3C3 ; (0xD385)1001 0xD3 ;D3C41003 0x3E ;D3C5 ; load 0x03 into A.1004 0x03 ;D3C61006 0xEA ;D3C7 ; load A to current-mode,1007 0x82 ;D3C8 ; advancing from Mode 2 to1008 0xD3 ;D3C9 ; Mode 3.1010 0xC3 ;D3CA ; go back to beginning1011 0x1D ;D3CB1012 0xD3 ;D3CC1013 ;;End Mode 21016 ;; Mode 3 -- set-start-point-low mode1017 ;; Final part of header for writing things to memory.1018 ;; User specifies the low bytes of 16 bit start-point.1020 ;; Set start-point-low to input-number;1021 ;; set current mode to 0x041022 0xFA ;D3CD ; load input-number into A1023 0x52 ;D3CE1024 0xD3 ;D3CF1026 0xEA ;D3D0 ; load A into start-point-low1027 0x86 ;D3D11028 0xD3 ;D3D21030 0x3E ;D3D3 ; load 0x04 into A.1031 0x04 ;D3D41033 0xEA ;D3D5 ; load A to current-mode,1034 0x82 ;D3D6 ; advancing from Mode 3 to1035 0xD3 ;D3D7 ; Mode 4.1037 0xC3 ;D3D8 ; go back to beginning1038 0x1D ;D3D91039 0xD3 ;D3DA1041 ;; Mode 4 -- write bytes mode1043 ;; This is where RAM manipulation happens. User supplies1044 ;; bytes every frame, which are written sequentially to1045 ;; start-point until bytes-to-write have been written. Once1046 ;; bytes-to-write have been written, the mode is reset to 0.1048 ;; compare bytes-written with bytes-to-write.1049 ;; if they are the same, then reset mode to 01051 0xFA ;D3DB ; load bytes-to-write into A1052 0x83 ;D3DC1053 0xD3 ;D3DD1055 0x47 ;D3DE ; load A into B1057 0xFA ;D3DF ; load bytes-written into A1058 0x84 ;D3E01059 0xD3 ;D3E11061 0xB8 ;D3E2 ; compare A with B1063 0xCA ;D3E3 ; if they are equal, go to cleanup1064 0x07 ;D3E41065 0xD4 ;D3E51067 ;; Write Memory Section1068 ;; Write the input-number, interpreted as an 8-bit number,1069 ;; into the current target register, determined by1070 ;; (+ start-point bytes-written).1071 ;; Then, increment bytes-written by 1.1073 0xFA ;D3E6 ; load start-point-high into A1074 0x85 ;D3E71075 0xD3 ;D3E81077 0x67 ;D3E9 ; load A into H1079 0xFA ;D3EA ; load start-point-low into A1080 0x86 ;D3EB1081 0xD3 ;D3EC1083 0x6F ;D3ED ; load A into L1085 0xFA ;D3EE ; load bytes-written into A1086 0x84 ;D3EF1087 0xD3 ;D3F01089 0x00 ;D3F1 ; These are here because1090 0x00 ;D3F2 ; I screwed up again.1091 0x00 ;D3F31093 0x85 ;D3F4 ; add L to A; store A in L.1094 0x6F ;D3F51096 0x30 ;D3F6 ; If the addition overflowed,1097 0x01 ;D3F71098 0x24 ;D3F8 ; increment H.1100 ;; Now, HL points to the correct place in memory1102 0xFA ;D3F9 ; load input-number into A1103 0x52 ;D3FA1104 0xD3 ;D3FB1106 0x77 ;D3FC ; load A into (HL)1108 0xFA ;D3FD ; load bytes-written into A1109 0x84 ;D3FE1110 0xD3 ;D3FF1112 0x3C ;D400 ; increment A1114 0xEA ;D401 ; load A into bytes-written1115 0x84 ;D4021116 0xD3 ;D4031118 0xC3 ;D404 ; go back to beginning.1119 0x1D ;D4051120 0xD3 ;D4061121 ;; End Write Memory Section1123 ;; Mode 4 Cleanup Section1124 ;; reset bytes-written to 01125 ;; set mode to 01126 0x3E ;D407 ; load 0 into A1127 0x00 ;D4081129 0xEA ;D409 ; load A into bytes-written1130 0x84 ;D40A1131 0xD3 ;D40B1133 0xEA ;D40C ; load A into current-mode1134 0x82 ;D40D1135 0xD3 ;D40E1137 0xC3 ;D40F ; go back to beginning1138 0x1D ;D4101139 0xD3 ;D4111141 ;; End Mode 41143 ])1147 (def frame-count 0xD31F)1148 (def input 0xD352)1149 (def current-mode 0xD382)1150 (def bytes-to-write 0xD383)1151 (def bytes-written 0xD384)1152 (def start-point-high 0xD385)1153 (def start-point-low 0xD386)1157 (defn write-memory []1158 (-> (tick (mid-game))1159 (IE! 0) ; disable interrupts1160 (inject-item-assembly (write-memory-assembly))))1162 (defn test-write-memory []1163 (set-state! (write-memory))1164 (dorun1165 (dotimes [_ 5000]1166 (view-memory (step @current-state) current-mode))))1168 (def bytes-to-write 0xD383)1169 (def start-point 0xD384)1171 (defn print-blank-assembly1172 [start end]1173 (dorun1174 (map1175 #(println (format "0x00 ;%04X " %))1176 (range start end))))1178 (defn test-mode-2 []1179 (->1180 (write-memory)1181 (view-memory frame-count)1182 (step)1183 (step [:a])1184 (step [:b])1185 (step [:start])1186 (step [])1187 (view-memory frame-count)))1191 (defn dylan-test-mode1192 ([] (dylan-test-mode (write-mem-dyl)))1193 ([target-state]1194 (let [1195 v-blank-prev 540461196 btn-register 652801197 eggs 0xD3741198 ]1200 (->1201 target-state1203 (tick)1204 (tick)1205 (tick)1206 (tick);; jumps back to beginning1208 (tick)1209 (tick)1210 (tick)1211 (tick)1212 (tick)1213 (tick)1214 (tick)1215 (tick)1216 (tick)1217 (tick)1218 (tick)1219 (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)1242 (tick) ;; just complemented A1244 (tick)1245 (DE! 0x1800)1246 (AF! 0x7700) ;; change inputs @ A1247 (tick)1248 (tick)1249 (tick)1250 (tick)1251 (tick)1253 ;;(view-memory eggs)1254 (tick)1255 (tick)1256 ;;(view-memory eggs)1257 (tick)1258 (tick)1259 (tick)1260 (tick)1261 (tick)1262 (tick)1263 (d-tick)1266 ;;(view-memory btn-register)1267 (view-register "A" A)1268 (view-register "B" B)1270 ;;(view-register "C" C)1271 (view-register "D" D)1272 (view-register "E" E)1273 (view-register "H" H)1274 (view-register "L" L)1275 ))))1279 (defn drive-dylan []1280 (-> (write-mem-dyl)1281 (#(do (println "memory from 0xC00F to 0xC01F:"1282 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1283 (step [])1284 (step [])1285 (step [])1286 (step [:start])1287 (step [:select])1288 (step [:u :d])1289 (step [:a :b :start :select])1290 (step [:a])1291 (step [:b])1292 (step [:a :b])1293 (step [:select])1294 (step [])1295 (step [])1296 (step [])1297 (#(do (println "memory from 0xC00F to 0xC01F:"1298 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1299 ))1301 (defn test-mode-41302 ([] (test-mode-4 (write-memory)))1303 ([target-state]1304 (->1305 target-state1306 (#(do (println "memory from 0xC00F to 0xC01F:"1307 (subvec (vec (memory %)) 0xC00F 0xC01F)) %))1308 (view-memory current-mode)1309 (step [])1310 (step [])1311 (step [])1312 (#(do (println "after three steps") %))1313 (view-memory current-mode)1315 ;; Activate memory writing mode1317 (#(do (println "step with [:a]") %))1318 (step [:a])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 four bytes to be written1326 (#(do (println "step with [:select]")%))1327 (step [:select])1328 (view-memory current-mode)1329 (view-memory bytes-to-write)1330 (view-memory start-point-high)1331 (view-memory start-point-low)1333 ;; Specify target memory address as 0xC00F1335 (#(do (println "step with [:u :d]")%))1336 (step [:u :d])1337 (view-memory current-mode)1338 (view-memory bytes-to-write)1339 (view-memory start-point-high)1340 (view-memory start-point-low)1342 (#(do (println "step with [:a :b :start :select]")%))1343 (step [:a :b :start :select])1344 (view-memory current-mode)1345 (view-memory bytes-to-write)1346 (view-memory start-point-high)1347 (view-memory start-point-low)1349 ;; Start reprogramming memory1351 (#(do (println "step with [:a]")%))1352 (step [:a])1353 (view-memory current-mode)1354 (view-memory bytes-written)1356 (#(do (println "step with [:b]")%))1357 (step [:b])1358 (view-memory current-mode)1359 (view-memory bytes-written)1361 (#(do (println "step with [:a :b]")%))1362 (step [:a :b])1363 (view-memory current-mode)1364 (view-memory bytes-written)1366 (#(do (println "step with [:select]")%))1367 (step [:select])1368 (view-memory current-mode)1369 (view-memory bytes-written)1371 ;; Reprogramming done, program ready for more commands.1373 (#(do (println "step with []")%))1374 (step [])1375 (view-memory current-mode)1376 (view-memory bytes-written)1378 (#(do (println "memory from 0xC00F to 0xC01F:"1379 (subvec (vec (memory %)) 0xC00F 0xC01F)) %)))))