Mercurial > vba-clojure
view clojure/com/aurellem/gb/dylan_assembly.clj @ 438:067ea3f0d951
can now play midi files with two tracks.
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Wed, 25 Apr 2012 13:46:31 -0500 |
parents | 1f14c1b8af7e |
children |
line wrap: on
line source
1 (ns com.aurellem.gb.dylan-assembly2 "A much more compact version of write-memory-assembly"3 {:author "Dylan Holmes"}4 (:use (com.aurellem.gb gb-driver assembly util vbm))5 (:import [com.aurellem.gb.gb_driver SaveState]))7 ;; Specs for main bootstrap program9 ;; Number-Input10 ;; Number input works using all eight buttons to11 ;; spell out an 8 bit number. The order of buttons is12 ;; [:d :u :l :r :start :select :b :a] --> 1111111113 ;; [ :l :start :a] --> 0010100115 ;;; MODE-SELECT16 ;; The bootstrap program starts in MODE-SELECT mode.17 ;; MODE-SELECT transitions to one of three modes depending18 ;; on which buttons are pressed:19 ;; 0 (no-buttons) : MODE-SELECT20 ;; 8 [:start] : WRITE-BYTES21 ;; 0xFF (all-buttons) : JUMP24 ;;; WRITE-BYTES26 ;; WRITE-BYTES mode writes sequences of arbitray values to27 ;; arbitray memory locations. It expects you to enter a28 ;; header of three bytes describing what to write:30 ;; Byte 0 : Number of Bytes to Write31 ;; Byte 1 : Start Address High Byte32 ;; Byte 1 : Start Address Low Byte34 ;; Then, you enter the number of bytes specified in Byte 035 ;; they are written to the start address in36 ;; sequence. After the last byte is written control37 ;; returns to MODE-SELECT mode.39 ;; Example: to write the sequence [1 2 3 4] starting at40 ;; address 0xC01F enter41 ;; Byte 0 : 4 (will write four bytes)42 ;; Byte 1 : 0xC0 (high byte of 0xC01F)43 ;; Byte 2 : 0x1F (low byte of 0xC01F)44 ;; Byte 3 : 1 (write 1 to 0xC01F)45 ;; Byte 4 : 2 (write 2 to 0xC020)46 ;; Byte 5 : 3 (write 3 to 0xC021)47 ;; Byte 6 : 4 (write 4 to 0xC022)49 ;;; JUMP50 ;; JUMP mode jumps program control to any arbitray51 ;; location. It expects you to enter two bytes which52 ;; correspond to the high and low bytes of the memory53 ;; address to which you want to jump.54 ;; Byte 0 : Jump Address High Byte55 ;; Byte 1 : Jump Address Low Byte57 ;; Example: to jump to address 0x1234 enter58 ;; Byte 0 : 0x12 (high byte of 0x1234)59 ;; Byte 1 : 0x34 (low byte of 0x1234)62 (defn write-memory-assembly-compact63 "Currently, grabs input from the user each frame."64 []65 [66 ;; --------- FRAME METRONOME67 0x18 ;; jump ahead to cleanup. first time only.68 0x40 ;; v-blank-prev [D31E]70 0xFA ;; load modes into A [D31F]71 0x4172 0xFF74 0x47 ;; A -> B75 0xCB ;; rotate A76 0x2F77 0x2F ;; invert A79 0xA080 0x47 ;; now B_0 contains (VB==1)82 0xFA ;; load v-blank-prev83 0x1E84 0xD386 0x2F ;; complement v-blank-prev88 0xA0 ;; A & B --> A89 0x4F ;; now C_0 contains increment?92 0x78 ;; B->A93 0xEA ;; spit A --> vbprev94 0x1E95 0xD397 0xCB ;test C_098 0x4199 0x20 ; JUMP ahead to button input if nonzero100 0x02101 0x18 ; JUMP back to frame metronome (D31F)102 0xE7104 ;; -------- GET BUTTON INPUT106 ;; btw, C_0 is now 1107 ;; prepare to select bits109 0x06 ;; load 0x00 into B110 0x00 ;; to initialize for "OR" loop112 0x3E ;; load 0x20 into A, to measure dpad113 0x20116 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C]117 0x00119 0xF0 ;; load A from [FF00]120 0x00122 0xE6 ;; bitmask 00001111123 0x0F125 0xB0 ;; A or B --> A126 0xCB127 0x41 ;; test bit 0 of C128 0x28 ;; JUMP forward if 0129 0x08131 0x47 ;; A -> B132 0xCB ;; swap B nybbles133 0x30134 0x0C ;; increment C135 0x3E ;; load 0x10 into A, to measure btns136 0x10137 0x18 ;; JUMP back to "load A into [FF00]" [20 steps?]138 0xED141 ;; ------ TAKE ACTION BASED ON USER INPUT143 ;; "input mode"144 ;; mode 0x00 : select mode145 ;; mode 0x08 : select bytes-to-write146 ;; mode 0x10 : select hi-bit147 ;; mode 0x18 : select lo-bit149 ;; "output mode"150 ;; mode 0x20 : write bytes151 ;; mode 0xFF : jump PC154 ;; registers155 ;; D : mode select156 ;; E : count of bytes to write157 ;; H : address-high158 ;; L : address-low160 ;; now A contains the pressed keys161 0x2F ; complement A, by request. [D34F]163 0x47 ; A->B ;; now B contains the pressed keys164 0x7B ; E->A ;; now A contains the count.166 0xCB ; test bit 5 of D (are we in o/p mode?)167 0x6A168 0x28 ; if test == 0, skip this o/p section169 0x13 ; JUMP171 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?)172 0x42173 0x28 ; if test == 0, skip the following command174 0x01176 ;; output mode I: moving the program counter177 0xE9 ; ** move PC to (HL)179 ;; output mode II: writing bytes180 0xFE ; A compare 0. finished writing?181 0x00182 0x20 ; if we are not finished, skip cleanup183 0x04 ; JUMP185 ;; CLEANUP186 ;; btw, A is already zero.187 0xAF ; zero A [D35F]188 0x57 ; A->D; makes D=0.189 0x18 ; end of frame190 0xBC192 ;; ---- end of cleanup195 ;; continue writing bytes196 0x1D ;; decrement E, the number of bytes to write [D363]197 0x78 ;; B->A; now A contains the pressed keys198 0x77 ;; copy A to (HL)199 0x23 ;; increment HL200 0x18 ;; end frame. [goto D31F]201 0xB6 ;; TODO: set skip length backwards204 ;; ---- end of o/p section206 ;; i/p mode207 ;; adhere to the mode discipline:208 ;; D must be one of 0x00 0x08 0x10 0x18.210 0x3E ;; load the constant 57 into A. [D369]211 0x57212 0x82 ;; add the mode to A213 0xEA ;; store A into "thing to execute"214 0x74215 0xD3217 0x3E ;; load the constant 8 into A218 0x08219 0x82 ;; add the mode to A221 0x57 ;; store the incremented mode into D222 0x78 ;; B->A; now A contains the pressed keys224 0x00 ;; var: thing to execute [D374]226 0x18 ;; end frame227 0xA8])229 (defn write-mem-compact []230 (-> (tick (mid-game))231 (IE! 0)232 (inject-item-assembly (write-memory-assembly-compact))))234 (defn test-write-bytes-mode []235 (let [target-address 0xD135236 [target-high target-low] (disect-bytes-2 target-address)237 assembly [0xF3 0x18 0xFE 0x12]238 get-mem-region #(subvec (vec (memory %))239 target-address (+ target-address 20))240 before (write-mem-compact)241 after242 (-> before243 (step []) ; make sure it can handle blanks244 (step []) ; at the beginning.245 (step [])246 (step [:start]) ; select WRITE-BYTES mode247 (step (buttons 4)) ; write 4 bytes248 (step (buttons target-high))249 (step (buttons target-low))250 (step (buttons (nth assembly 0)))251 (step (buttons (nth assembly 1)))252 (step (buttons (nth assembly 2)))253 (step (buttons (nth assembly 3)))254 (step [])255 (step [])256 (step []))]257 (println "before :" (get-mem-region before))258 (println "after :" (get-mem-region after))259 (assert (= assembly (take 4 (get-mem-region after))))260 after))262 (defn test-jump-mode []263 (let [target-address 0xC01F264 [target-high target-low] (disect-bytes-2 target-address)265 post-jump266 (-> (test-write-bytes-mode)267 (step [])268 (step [])269 (step [])270 (step (buttons 0xFF)) ; Select JUMP mode.271 (step (buttons target-high))272 (step (buttons target-low)))273 program-counters274 (capture-program-counter275 post-jump276 10000)]277 (println program-counters)278 (assert (contains? (set program-counters) target-address))279 post-jump))282 (defn test-loop []283 (contains?284 (set285 (capture-program-counter286 (-> (mid-game)287 ;; (IE! 0)288 (set-memory-range 0xD135 [0xF3 0x18 0xFE])289 (PC! 0xD135)) 10000))290 0xD136))