rlm@145: (ns com.aurellem.gb.assembly rlm@145: (:use (com.aurellem.gb gb-driver vbm util items)) rlm@145: (:import [com.aurellem.gb.gb_driver SaveState])) rlm@145: rlm@145: (defn inject-assembly rlm@145: ([^SaveState state rlm@145: program-counter registers rlm@145: assembly-code] rlm@145: (let [scratch-memory (memory state)] rlm@145: ;; inject assembly code rlm@145: (dorun (map (fn [index val] rlm@145: (aset scratch-memory index val)) rlm@145: (range program-counter rlm@145: (+ program-counter (count assembly-code))) rlm@145: assembly-code)) rlm@145: (-> state rlm@145: (write-memory! scratch-memory) rlm@145: (write-registers! registers) rlm@145: (PC! program-counter))))) rlm@145: rlm@145: (defn inject-item-assembly rlm@145: ([^SaveState state assembly-code] rlm@145: (inject-assembly state (inc item-list-start) rlm@145: (registers state) rlm@145: assembly-code)) rlm@145: ([assembly-code] rlm@145: (inject-item-assembly @current-state assembly-code))) rlm@145: rlm@145: (defn run-assembly rlm@145: ([info-fn assembly n] rlm@145: (let [final-state rlm@145: (reduce (fn [state _] rlm@145: (tick (info-fn state))) rlm@145: (inject-item-assembly rlm@145: (mid-game) assembly) rlm@145: (range n))] rlm@145: final-state)) rlm@145: ([assembly n] rlm@145: (run-assembly d-tick assembly n))) rlm@145: rlm@145: (def buttons-port 0xFF00) rlm@145: rlm@145: (defn trace [state] rlm@145: (loop [program-counters [(first (registers @current-state)) ] rlm@145: opcodes [(aget (memory @current-state) (PC @current-state))]] rlm@145: (let [frame-boundary? rlm@145: (com.aurellem.gb.Gb/tick)] rlm@145: (if frame-boundary? rlm@145: [program-counters opcodes] rlm@145: (recur rlm@145: (conj program-counters rlm@145: (first (registers @current-state))) rlm@145: (conj opcodes rlm@145: (aget (memory @current-state) rlm@145: (PC @current-state)))))))) rlm@145: rlm@145: (defn print-trace [state n] rlm@145: (let [[program-counters opcodes] (trace state)] rlm@145: (dorun (map (fn [pc op] (println (format "%04X: 0x%02X" pc op))) rlm@145: (take n program-counters) rlm@145: (take n opcodes))))) rlm@145: rlm@145: (defn good-trace [] rlm@145: (-> (mid-game) (tick) (IE! 0) rlm@145: (set-inv-mem [0x00 0x00 0X00 0x00]) rlm@145: (PC! item-list-start)(print-interrupt) rlm@145: (d-tick) (tick) (d-tick) (tick) (d-tick))) rlm@145: rlm@145: (defn read-down-button [] rlm@145: (-> (tick (mid-game)) rlm@145: (IE! 0) ; disable interrupts rlm@145: (inject-item-assembly rlm@145: ;; write 00010000 to 0xFF00 to select joypad rlm@145: [0x18 ;D31D ; jump over rlm@145: 0x01 ;D31E ; the next 8 bits rlm@145: ;D31F rlm@145: (Integer/parseInt "00100000" 2) ; data section rlm@145: rlm@145: 0xFA ;D320 ; load (D31F) into A rlm@145: 0x1F ;D321 --> rlm@145: 0xD3 ;D322 --> D31F rlm@145: rlm@145: 0xEA ;D323 ; load (A), which is rlm@145: 0x00 ;D324 --> ; 00010000, into FF00 rlm@145: 0xFF ;D325 --> FF00 rlm@145: rlm@145: 0x18 ;D326 ; this is the place where rlm@145: 0x01 ;D327 ; we will store whether rlm@145: 0x00 ;D328 ; "down" is pressed. rlm@145: rlm@145: 0xFA ;D329 ; (FF00) -> A rlm@145: 0x00 ;D32A rlm@145: 0xFF ;D32B rlm@145: rlm@145: 0xCB ;D32C ; Test whether "down" rlm@145: 0x5F ;D32D ; is pressed. rlm@145: rlm@145: 0x28 ;D32E ; if down is pressed, rlm@145: 0x03 ;D32F ; skip the next section rlm@145: ; of code. rlm@145: ;; down-is-not-pressed rlm@145: 0xC3 ;D330 rlm@145: 0x1D ;D331 ; return to beginning rlm@145: 0xD3 ;D332 rlm@145: rlm@145: ;; down-is-pressed rlm@145: 0xEA ;D334 ; write A to D328 if rlm@145: 0x28 ;D335 ; "down" was pressed rlm@145: 0xD3 ;D336 rlm@145: rlm@145: 0xC3 ;D330 rlm@145: 0x1D ;D331 ; return to beginning rlm@145: 0xD3 ;D332 rlm@145: ]))) rlm@145: rlm@145: (defn test-read-down [] rlm@145: (= (view-memory (step (step (read-down-button) [:d])) 0xD328) rlm@145: (view-memory (step (step (read-down-button))) 0xD328))) rlm@145: rlm@145: (defn count-frames [] rlm@145: (-> (tick (mid-game)) rlm@145: (IE! 0) ; disable interrupts rlm@145: (inject-item-assembly rlm@145: [0x18 ;D31D ; jump over rlm@145: 0x02 ;D31E ; the next 2 bytes rlm@145: 0x00 ;D31F ; frame-count rlm@145: 0x00 ;D320 ; v-blank-prev rlm@145: rlm@145: 0xFA ;D321 rlm@145: 0x41 ;D322 ; load (FF41) into A rlm@145: 0xFF ;D323 ; this contains mode flags rlm@145: rlm@145: ;; if we're in v-blank, the bit-1 is 0 rlm@145: ;; and bit-2 is 1 Otherwise, it is not v-blank. rlm@145: 0xCB ;D324 ; test bit-1 of A rlm@145: 0x4F ;D325 rlm@145: rlm@145: 0xC2 ;D326 ; if bit-1 is not 0 rlm@145: 0x44 ;D327 ; GOTO not-v-blank rlm@145: 0xD3 ;D328 rlm@145: rlm@145: 0xCB ;D329 ; test bit-0 of A rlm@145: 0x47 ;D32A rlm@145: rlm@145: 0xCA ;D32B ; if bit-0 is not 1 rlm@145: 0x44 ;D32C ; GOTO not-v-blank rlm@145: 0xD3 ;D32D rlm@145: ;;; in v-blank mode rlm@145: ;; if v-blank-prev was 0, rlm@145: ;; increment frame-count rlm@145: rlm@145: 0xFA ;D32E ; load v-blank-prev to A rlm@145: 0x20 ;D32F rlm@145: 0xD3 ;D330 rlm@145: rlm@145: 0xCB ;D331 rlm@145: 0x47 ;D332 ; test bit-0 of A rlm@145: rlm@145: 0x20 ;D333 ; skip next section rlm@145: 0x07 ;D334 ; if v-blank-prev was not zero rlm@145: rlm@145: ;; v-blank was 0, increment frame-count rlm@145: 0xFA ;D335 ; load frame-count into A rlm@145: 0x1F ;D336 rlm@145: 0xD3 ;D337 rlm@145: rlm@145: 0x3C ;D338 ; inc A rlm@145: rlm@145: 0xEA ;D339 ; load A into frame-count rlm@145: 0x1F ;D33A rlm@145: 0xD3 ;D33B rlm@145: rlm@145: ;; set v-blank-prev to 1 rlm@145: 0x3E ;D33C ; load 1 into A rlm@145: 0x01 ;D33D rlm@145: rlm@145: 0xEA ;D33E ; load A into v-blank-prev rlm@145: 0x20 ;D33F rlm@145: 0xD3 ;D340 rlm@145: rlm@145: 0xC3 ;D341 ; return to beginning rlm@145: 0x1D ;D342 rlm@145: 0xD3 ;D343 rlm@145: rlm@145: ;;; not in v-blank mode rlm@145: ;; set v-blank-prev to 0 rlm@145: 0x3E ;D344 ; load 0 into A rlm@145: 0x00 ;D345 rlm@145: rlm@145: 0xEA ;D346 ; load A into v-blank-prev rlm@145: 0x20 ;D347 rlm@145: 0xD3 ;D348 rlm@145: rlm@145: 0xC3 ;D349 ; return to beginning rlm@145: 0x1D ;D34A rlm@145: 0xD3 ;D34B rlm@145: ]))) rlm@145: rlm@145: (defn step-count-frames [] rlm@145: (-> (read-down-button) rlm@145: (d-tick) rlm@145: (tick) ;; skip over data section rlm@145: (d-tick) rlm@145: (view-register "Register A" A) rlm@145: (tick) ;; load-data into A rlm@145: (view-register "Register A" A) rlm@145: (d-tick) rlm@145: (view-memory 0xFF00) rlm@145: (tick) ;; load A into 0xFF00 rlm@145: (view-memory 0xFF00) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: (tick) rlm@145: (print-inventory))) rlm@145: rlm@145: (defn test-count-frames [] rlm@145: (= 255 (aget (memory ((apply comp (repeat 255 step)) rlm@145: (count-frames))) rlm@145: 0xD31F))) rlm@145: rlm@145: ;; specs for main bootstrap program rlm@145: ;; starts in "mode-select" mode rlm@145: ;; Each button press takes place in a single frame. rlm@145: ;; mode-select-mode takes one of the main buttons rlm@145: ;; which selects one of up to eight modes rlm@145: ;; mode 1 activated by the "A" button rlm@145: ;; the next two button presses indicates the start rlm@145: ;; memory location which to which the bootstrap rlm@145: ;; program will write. rlm@145: ;; This is done by using each of the eight buttons to rlm@145: ;; spell out an 8 bit number. The order of buttons is rlm@145: ;; [:d :u :l :r :start :select :b :a] rlm@145: ;; [:a :start :l] --> 00101001 rlm@145: rlm@145: ;; the next button press determines how many bytes are to be rlm@145: ;; written, starting at the start position. rlm@145: rlm@145: ;; then, the actual bytes are entered and are written to the rlm@145: ;; start address in sequence. rlm@145: rlm@145: (defn input-number-assembly [] rlm@145: [0x18 ;D31D ; jump over rlm@145: 0x02 ;D31E ; the next 2 bytes rlm@145: 0x00 ;D31F ; frame-count rlm@145: 0x00 ;D320 ; v-blank-prev rlm@145: rlm@145: 0xFA ;D321 rlm@145: 0x41 ;D322 ; load (FF41) into A rlm@145: 0xFF ;D323 ; this contains mode flags rlm@145: rlm@145: ;; if we're in v-blank, the bit-1 is 0 rlm@145: ;; and bit-2 is 1 Otherwise, it is not v-blank. rlm@145: 0xCB ;D324 ; test bit-1 of A rlm@145: 0x4F ;D325 rlm@145: rlm@145: 0xC2 ;D326 ; if bit-1 is not 0 rlm@145: 0x44 ;D327 ; GOTO not-v-blank rlm@145: 0xD3 ;D328 rlm@145: rlm@145: 0xCB ;D329 ; test bit-0 of A rlm@145: 0x47 ;D32A rlm@145: rlm@145: 0xCA ;D32B ; if bit-0 is not 1 rlm@145: 0x44 ;D32C ; GOTO not-v-blank rlm@145: 0xD3 ;D32D rlm@145: rlm@145: ;;; in v-blank mode rlm@145: rlm@145: ;; if v-blank-prev was 0, rlm@145: ;; increment frame-count rlm@145: rlm@145: 0xFA ;D32E ; load v-blank-prev to A rlm@145: 0x20 ;D32F rlm@145: 0xD3 ;D330 rlm@145: rlm@145: 0xCB ;D331 rlm@145: 0x47 ;D332 ; test bit-0 of A rlm@145: rlm@145: 0x20 ;D333 ; skip next section rlm@145: 0x07 ;D334 ; if v-blank-prev was not zero rlm@145: rlm@145: ;; v-blank was 0, increment frame-count rlm@145: 0xFA ;D335 ; load frame-count into A rlm@145: 0x1F ;D336 rlm@145: 0xD3 ;D337 rlm@145: rlm@145: 0x3C ;D338 ; inc A rlm@145: rlm@145: 0xEA ;D339 ; load A into frame-count rlm@145: 0x1F ;D33A rlm@145: 0xD3 ;D33B rlm@145: rlm@145: ;; set v-blank-prev to 1 rlm@145: 0x3E ;D33C ; load 1 into A rlm@145: 0x01 ;D33D rlm@145: rlm@145: 0xEA ;D33E ; load A into v-blank-prev rlm@145: 0x20 ;D33F rlm@145: 0xD3 ;D340 rlm@145: rlm@145: 0xC3 ;D341 ; GOTO input handling code rlm@145: 0x4E ;D342 rlm@145: 0xD3 ;D343 rlm@145: rlm@145: ;;; not in v-blank mode rlm@145: ;; set v-blank-prev to 0 rlm@145: 0x3E ;D344 ; load 0 into A rlm@145: 0x00 ;D345 rlm@145: rlm@145: 0xEA ;D346 ; load A into v-blank-prev rlm@145: 0x20 ;D347 rlm@145: 0xD3 ;D348 rlm@145: rlm@145: 0xC3 ;D349 ; return to beginning rlm@145: 0x1D ;D34A rlm@145: 0xD3 ;D34B rlm@145: rlm@145: 0x00 ;D34C ; these are here rlm@145: 0x00 ;D34D ; for glue rlm@145: rlm@145: rlm@145: ;;; calculate input number based on button presses rlm@145: 0x18 ;D34E ; skip next 3 bytes rlm@145: 0x03 ;D34F rlm@145: ;D350 rlm@145: (Integer/parseInt "00100000" 2) ; select directional pad rlm@145: ;D351 rlm@145: (Integer/parseInt "00010000" 2) ; select buttons rlm@145: 0x00 ;D352 ; input-number rlm@145: rlm@145: ;; select directional pad, store low bits in B rlm@145: rlm@145: 0xFA ;D353 ; load (D350) into A rlm@145: 0x50 ;D354 --> rlm@145: 0xD3 ;D355 --> D31F rlm@145: rlm@145: 0xEA ;D356 ; load A, which is rlm@145: 0x00 ;D357 --> ; 00010000, into FF00 rlm@145: 0xFF ;D358 --> FF00 rlm@145: rlm@145: 0x06 ;D359 rlm@145: ;D35A rlm@145: (Integer/parseInt "11110000" 2) ; "11110000" -> B rlm@145: 0xFA ;D35B ; (FF00) -> A rlm@145: 0x00 ;D35C rlm@145: 0xFF ;D35D rlm@145: rlm@145: 0xCB ;D35E ; swap nybbles on A rlm@145: 0x37 ;D35F rlm@145: 0xA0 ;D360 ; (AND A B) -> A rlm@145: 0x47 ;D361 ; A -> B rlm@145: rlm@145: ;; select buttons store bottom bits in C rlm@145: rlm@145: 0xFA ; ; load (D351) into A rlm@145: 0x51 ; --> rlm@145: 0xD3 ; --> D31F rlm@145: rlm@145: 0xEA ; ; load (A), which is rlm@145: 0x00 ; --> ; 00001000, into FF00 rlm@145: 0xFF ; --> FF00 rlm@145: rlm@145: 0x0E ; rlm@145: (Integer/parseInt "00001111" 2) ; "00001111" -> C rlm@145: rlm@145: 0xFA ; ; (FF00) -> A rlm@145: 0x00 ; rlm@145: 0xFF ; rlm@145: rlm@145: 0xA1 ; ; (AND A C) -> A rlm@145: 0x4F ; ; A -> C rlm@145: rlm@145: ;; combine the B and C registers into the input number rlm@145: 0x79 ; ; C -> A rlm@145: 0xB0 ; ; (OR A B) -> A rlm@145: 0x2F ; ; negate A rlm@145: rlm@145: 0xEA ; ; store A into input-number rlm@145: 0x52 ; rlm@145: 0xD3 ; rlm@145: rlm@145: 0xC3 ; ; return to beginning rlm@145: 0x1D ; rlm@145: 0xD3 ; rlm@145: ]) rlm@145: rlm@145: rlm@145: rlm@145: (defn input-number [] rlm@145: (-> (tick (mid-game)) rlm@145: (IE! 0) ; disable interrupts rlm@145: (inject-item-assembly (input-number-assembly)))) rlm@145: rlm@145: (defn test-input-number rlm@145: "Input freestyle buttons and observe the effects at the repl." rlm@145: [] rlm@145: (set-state! (input-number)) rlm@145: (dotimes [_ 90000] (step (view-memory @current-state 0xD352)))) rlm@145: ocsenave@183: ocsenave@183: ocsenave@183: ocsenave@183: ocsenave@183: rlm@145: (defn write-memory-assembly* ocsenave@175: "A program for altering in-game memory by pressing buttons." rlm@145: [] rlm@145: [ ocsenave@242: ;; 0xF3 ; stop interrupts ocsenave@175: ;; --------- CLEANUP ocsenave@175: 0xAF ; zero A [D31E] ocsenave@175: 0x57 ; A->D; makes D=0. ocsenave@175: rlm@145: ;; --------- FRAME METRONOME ocsenave@175: 0xF1 ;; pop AF (vblank prev) [D320] rlm@145: ocsenave@175: 0x2F ;; invert A ocsenave@183: 0x4F ;; A -> C ocsenave@175: ocsenave@175: 0xF0 ;; copy STAT into A rlm@145: 0x41 rlm@145: ocsenave@183: 0x47 ;; A->B ocsenave@183: 0x1F ;; rotate A right ocsenave@183: 0x2F ;; complement A ocsenave@183: 0xA0 ;; A & B --> A ocsenave@183: ocsenave@175: 0xF5 ;; push AF (vbprev) rlm@145: ocsenave@183: 0xA1 ;; A & C --> A. Now A_0 contains "increment?" ocsenave@242: ocsenave@242: 0x4F ocsenave@242: 0xCB ;; test bit 0 of C. sadly, this result can't be reused below. ocsenave@242: 0x41 ocsenave@183: ocsenave@175: 0x28 ;; end frame (JUMP) if A_0 = 0. ocsenave@183: 0xF3 ;; TODO: set jump length rlm@145: rlm@145: ;; -------- GET BUTTON INPUT ocsenave@175: rlm@145: ;; prepare to select bits rlm@145: rlm@145: 0x3E ;; load 0x20 into A, to measure dpad rlm@145: 0x20 ocsenave@175: ocsenave@175: 0x06 ;; load 0x00 into B ocsenave@175: 0x00 ;; to initialize for "OR" loop rlm@145: rlm@145: 0xE0 ;; load A into [FF00] ;; start of OR loop [D33C] rlm@145: 0x00 rlm@145: rlm@145: 0xF0 ;; load A from [FF00] rlm@145: 0x00 rlm@145: rlm@145: 0xE6 ;; bitmask 00001111 rlm@145: 0x0F rlm@145: rlm@145: 0xB0 ;; A or B --> A ocsenave@175: ocsenave@242: 0xCB ;; check bit 0 of C ocsenave@242: 0x41 ocsenave@242: ocsenave@175: 0x28 ;; JUMP forward if Z=0 rlm@145: 0x08 rlm@145: rlm@145: 0x47 ;; A -> B rlm@145: 0xCB ;; swap B nybbles rlm@145: 0x30 ocsenave@175: rlm@145: 0x3E ;; load 0x10 into A, to measure btns rlm@145: 0x10 ocsenave@175: ocsenave@183: 0x18 ;; JUMP back to "load A into [FF00]" ocsenave@242: 0xF0 rlm@145: rlm@145: rlm@145: ;; ------ TAKE ACTION BASED ON USER INPUT rlm@145: rlm@145: ;; "input mode" rlm@145: ;; mode 0x00 : select mode rlm@145: ;; mode 0x08 : select bytes-to-write rlm@145: ;; mode 0x10 : select hi-bit rlm@145: ;; mode 0x18 : select lo-bit rlm@145: rlm@145: ;; "output mode" rlm@145: ;; mode 0x20 : write bytes rlm@145: ;; mode 0xFF : jump PC rlm@145: rlm@145: rlm@145: ;; registers rlm@145: ;; D : mode select rlm@145: ;; E : count of bytes to write rlm@145: ;; H : address-high rlm@145: ;; L : address-low rlm@145: rlm@145: ;; now A contains the pressed keys rlm@145: 0x2F ; complement A, by request. [D34F] rlm@145: rlm@145: 0x47 ; A->B ;; now B contains the pressed keys rlm@145: rlm@145: 0xCB ; test bit 5 of D (are we in o/p mode?) rlm@145: 0x6A rlm@145: 0x28 ; if test == 0, skip this o/p section rlm@145: 0x13 ; JUMP rlm@145: rlm@145: 0xCB ; else, test bit 0 of D (fragile; are we in pc mode?) rlm@145: 0x42 rlm@145: 0x28 ; if test == 0, skip the following command rlm@145: 0x01 rlm@145: rlm@145: ;; output mode I: moving the program counter rlm@145: 0xE9 ; ** move PC to (HL) rlm@145: rlm@145: ;; output mode II: writing bytes ocsenave@175: 0xAF ; zero A ocsenave@175: 0xBB ; compare count to zero. finished writing? ocsenave@175: 0x28 ; if we are finished, jump back to cleanup ocsenave@175: 0x00 ; TODO: set jump length backwards. rlm@145: rlm@145: ;; continue writing bytes ocsenave@175: 0x78 ;; B->A ocsenave@175: 0x22 ;; copy A to (HL) and increment HL. rlm@145: 0x18 ;; end frame. [goto D31F] ocsenave@175: 0xB6 ;; JUMP rlm@145: rlm@145: rlm@145: ;; ---- end of o/p section rlm@145: rlm@145: ;; i/p mode rlm@145: ;; adhere to the mode discipline: rlm@145: ;; D must be one of 0x00 0x08 0x10 0x18. rlm@145: rlm@145: 0x3E ;; load the constant 57 into A. [D369] rlm@145: 0x57 rlm@145: 0x82 ;; add the mode to A rlm@145: 0xEA ;; store A into "thing to execute" ocsenave@242: 0x74 ;; ABSOLUTE LOCATION ocsenave@242: 0xD3 ;; ABSOLUTE LOCATION rlm@145: rlm@145: 0x3E ;; load the constant 8 into A rlm@145: 0x08 rlm@145: 0x82 ;; add the mode to A rlm@145: rlm@145: 0x57 ;; store the incremented mode into D rlm@145: 0x78 ;; B->A; now A contains the pressed keys rlm@145: rlm@145: 0x00 ;; var: thing to execute [D374] rlm@145: rlm@145: 0x18 ;; end frame ocsenave@175: 0xA8 ;; JUMP rlm@145: ] rlm@145: ) rlm@145: rlm@145: (defn write-mem-dyl [] rlm@145: (-> (tick (mid-game)) rlm@145: (IE! 0) rlm@145: (inject-item-assembly (write-memory-assembly*)))) rlm@145: ocsenave@183: (defn ntick [s n] ocsenave@183: (if (zero? n) s ocsenave@183: (do ocsenave@183: (set-state! s) ocsenave@183: (dorun (dotimes [_ n] ocsenave@183: (com.aurellem.gb.Gb/tick))) ocsenave@183: (update-state)))) ocsenave@183: ocsenave@183: ocsenave@183: (defn find-frame-shift [state] ocsenave@183: ;;(restart!) ocsenave@183: (set-state! state) ocsenave@183: (loop [n 0] ocsenave@183: (if (>= (first (registers)) 0xD32D) ocsenave@183: (do (println n) ocsenave@183: (update-state)) ocsenave@183: (do ocsenave@183: (com.aurellem.gb.Gb/tick) ocsenave@183: (recur (inc n) ))))) ocsenave@183: ocsenave@183: (defn demo-assembly [n] ocsenave@183: (repeat n 0x00)) ocsenave@183: ocsenave@183: ocsenave@183: (defn find-frame-shift* [state] ocsenave@183: (set-state! state) ocsenave@183: (loop [] ocsenave@183: (com.aurellem.gb.Gb/tick) ocsenave@183: ;;(println (first (registers))) ocsenave@183: (if (>= (first (registers)) 0xD32D) ocsenave@183: (update-state) ocsenave@183: (recur)))) ocsenave@183: ocsenave@183: ocsenave@183: (defn dylan** ocsenave@183: ([k] ocsenave@183: (-> ocsenave@183: (tick (mid-game)) ocsenave@183: (inject-item-assembly(write-memory-assembly*)) ocsenave@183: ;;(find-frame-shift) ocsenave@183: (ntick k) ocsenave@183: (d-tick) ocsenave@183: (view-register "A" A) ocsenave@183: (view-register "B" B) ocsenave@183: (view-register "D" D) ocsenave@183: (view-register "E" E) ocsenave@183: (view-register "F" F) ocsenave@183: (#(do (println) %)) ocsenave@183: )) ocsenave@183: ([] (dylan** 0))) ocsenave@183: ocsenave@183: ocsenave@183: rlm@145: rlm@145: (defn dylan* [] rlm@145: (-> rlm@145: (write-mem-dyl) rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: rlm@145: ;;(view-memory 0xD374) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: ;;(view-memory 0xD374) rlm@145: (d-tick) rlm@145: rlm@145: (view-register "A" A) rlm@145: (view-register "B" B) rlm@145: (view-register "C" C)) rlm@145: rlm@145: ) rlm@145: rlm@145: rlm@145: (defn dylan [] rlm@145: (-> rlm@145: (write-mem-dyl) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) ;; first loop rlm@145: rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) ;; dpad bits rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: rlm@145: rlm@145: rlm@145: (view-register "A" A) rlm@145: (view-register "B" B) rlm@145: (view-register "C" C) rlm@145: rlm@145: )) rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: (defn d2 [] rlm@145: (-> rlm@145: (write-mem-dyl) rlm@145: (view-memory 0xD31F) rlm@145: step step step step step rlm@145: (view-memory 0xD31F))) rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: rlm@145: (defn write-memory-assembly [] rlm@145: [ rlm@145: ;; Main Timing Loop rlm@145: ;; Constantly check for v-blank and Trigger main state machine on rlm@145: ;; every transtion from v-blank to non-v-blank. rlm@145: rlm@145: 0x18 ; D31D ; Variable declaration rlm@145: 0x02 ; D31E rlm@145: 0x00 ; D31F ; frame-count rlm@145: 0x00 ; D320 ; v-blank-prev rlm@145: rlm@145: 0xF0 ; D321 ; load v-blank mode flags into A rlm@145: 0x41 rlm@145: 0x00 rlm@145: rlm@145: rlm@145: ;; Branch dependent on v-blank. v-blank happens when the last two rlm@145: ;; bits in A are "01" rlm@145: 0xCB ; D324 rlm@145: 0x4F ; D325 rlm@145: rlm@145: 0xC2 ; D326 ; if bit-1 is not 0, then rlm@145: 0x3E ; D327 ; GOTO non-v-blank. rlm@145: 0xD3 ; D328 rlm@145: rlm@145: 0xCB ; D329 rlm@145: 0x47 ; D32A rlm@145: rlm@145: 0xCA ; D32B ; if bit-0 is not 1, then rlm@145: 0x3E ; D32C ; GOTO non-v-blank. rlm@145: 0xD3 ; D32D rlm@145: rlm@145: ;; V-Blank rlm@145: ;; Activate state-machine if this is a transition event. rlm@145: rlm@145: 0xFA ; D32E ; load v-bank-prev into A rlm@145: 0x20 ; D32F rlm@145: 0xD3 ; D330 rlm@145: rlm@145: 0xFE ; D331 ; compare A to 0. >--------\ rlm@145: 0x00 ; D332 \ rlm@145: ; | rlm@145: ;; set v-blank-prev to 1. | rlm@145: 0x3E ; D333 ; load 1 into A. | rlm@145: 0x01 ; D334 | rlm@145: ; | rlm@145: 0xEA ; D335 ; load A into v-blank-prev | rlm@145: 0x20 ; D336 | rlm@145: 0xD3 ; D337 | rlm@145: ; / rlm@145: ;; if v-blank-prev was 0, activate state-machine <------/ rlm@145: 0xCA ; D338 ; if v-blank-prev rlm@145: 0x46 ; D339 ; was 0, rlm@145: 0xD3 ; D33A ; GOTO state-machine rlm@145: rlm@145: 0xC3 ; D33B rlm@145: 0x1D ; D33C rlm@145: 0xD3 ; D33D ; GOTO beginning rlm@145: ;; END V-blank rlm@145: rlm@145: ;; Non-V-Blank rlm@145: ;; Set v-blank-prev to 0 rlm@145: 0x3E ; D33E ; load 0 into A rlm@145: 0x00 ; D33F rlm@145: rlm@145: 0xEA ; D340 ; load A into v-blank-prev rlm@145: 0x20 ; D341 rlm@145: 0xD3 ; D342 rlm@145: rlm@145: 0xC3 ; D343 rlm@145: 0x1D ; D344 rlm@145: 0xD3 ; D345 ; GOTO beginning rlm@145: ;; END Not-V-Blank rlm@145: rlm@145: rlm@145: ;; Main State Machine -- Input Section rlm@145: ;; This is called once every frame. rlm@145: ;; It collects input and uses it to drive the rlm@145: ;; state transitions. rlm@145: rlm@145: ;; Increment frame-count rlm@145: 0xFA ; D346 ; load frame-count into A rlm@145: 0x1F ; D347 rlm@145: 0xD3 ; D348 rlm@145: rlm@145: 0x3C ; D349 ; inc A rlm@145: rlm@145: 0xEA ; D34A rlm@145: 0x1F ; D34B ; load A into frame-count rlm@145: 0xD3 ; D34C rlm@145: rlm@145: 0x00 ; D34D ; glue :) rlm@145: rlm@145: 0x18 ;D34E ; skip next 3 bytes rlm@145: 0x03 ;D34F rlm@145: ;D350 rlm@145: (Integer/parseInt "00100000" 2) ; select directional pad rlm@145: ;D351 rlm@145: (Integer/parseInt "00010000" 2) ; select buttons rlm@145: 0x00 ;D352 ; input-number rlm@145: rlm@145: ;; select directional pad; store low bits in B rlm@145: rlm@145: 0xFA ;D353 ; load (D350) into A rlm@145: 0x50 ;D354 --> rlm@145: 0xD3 ;D355 --> D350 rlm@145: rlm@145: 0xE0 ;D356 ; load (A), which is rlm@145: 0x00 ;D357 --> ; 00010000, into FF00 rlm@145: 0x00 ;D358 --> FF00 ;; NO-OP rlm@145: rlm@145: 0x06 ;D359 rlm@145: ;D35A rlm@145: (Integer/parseInt "11110000" 2) ; "11110000" -> B rlm@145: 0xF0 ;D35B ; (FF00) -> A rlm@145: 0x00 ;D35C rlm@145: 0x00 ;D35D ;; NO-OP rlm@145: rlm@145: 0xCB ;D35E ; swap nybbles on A rlm@145: 0x37 ;D35F rlm@145: 0xA0 ;D360 ; (AND A B) -> A rlm@145: 0x47 ;D361 ; A -> B rlm@145: rlm@145: ;; select buttons; store bottom bits in C rlm@145: rlm@145: 0xFA ;D362 ; load (D351) into A rlm@145: 0x51 ;D363 --> rlm@145: 0xD3 ;D364 --> D351 rlm@145: rlm@145: 0xE0 ;D365 ; load (A), which is rlm@145: 0x00 ;D366 --> ; 00001000, into FF00 rlm@145: 0x00 ;D367 --> FF00 ;; NO-OP rlm@145: rlm@145: 0x0E ;D368 rlm@145: ;D369 rlm@145: (Integer/parseInt "00001111" 2) ; "00001111" -> C rlm@145: rlm@145: 0xF0 ;D36A ; (FF00) -> A rlm@145: 0x00 ;D36B rlm@145: 0x00 ;D36C rlm@145: rlm@145: 0xA1 ;D36D ; (AND A C) -> A rlm@145: 0x4F ;D36E ; A -> C rlm@145: rlm@145: ;; combine the B and C registers into the input number rlm@145: 0x79 ;D36F ; C -> A rlm@145: 0xB0 ;D370 ; (OR A B) -> A rlm@145: 0x2F ;D371 ; negate A rlm@145: rlm@145: 0xEA ;D372 ; store A into input-number rlm@145: 0x52 ;D373 rlm@145: 0xD3 ;D374 rlm@145: rlm@145: 0x00 ;D375 rlm@145: 0x00 ;D376 rlm@145: 0x00 ;D377 rlm@145: 0x00 ;D378 rlm@145: 0x00 ;D379 rlm@145: 0x00 ;D37A rlm@145: 0x00 ;D37B ; these are here because rlm@145: 0x00 ;D37C ; I messed up :( rlm@145: 0x00 ;D37D rlm@145: 0x00 ;D37E rlm@145: 0x00 ;D37F rlm@145: rlm@145: ;; beginning of main state machine rlm@145: 0x18 ;D380 ; Declaration of variables rlm@145: 0x05 ;D381 ; 5 variables: rlm@145: 0x00 ;D382 ; current-mode rlm@145: 0x00 ;D383 ; bytes-to-write rlm@145: 0x00 ;D384 ; bytes-written rlm@145: 0x00 ;D385 ; start-point-high rlm@145: 0x00 ;D386 ; start-point-low rlm@145: rlm@145: rlm@145: ;; banch on current mode rlm@145: 0xFA ;D387 ; load current-mode (0xD382) rlm@145: 0x82 ;D388 ; into A rlm@145: 0xD3 ;D389 rlm@145: 0x00 ;D38A rlm@145: rlm@145: rlm@145: ;; GOTO Mode 0 (input-mode) if current-mode is 0 rlm@145: 0xFE ;D38B rlm@145: 0x00 ;D38C ; compare A with 0x00 rlm@145: rlm@145: 0xCA ;D38D ; goto Mode 0 if A == 0 rlm@145: 0xA8 ;D38E rlm@145: 0xD3 ;D38F rlm@145: rlm@145: ;; GOTO Mode 1 (set-length) if current-mode is 1 rlm@145: 0xFE ;D390 rlm@145: 0x01 ;D391 ; compare A with 0x01 rlm@145: rlm@145: 0xCA ;D392 rlm@145: 0xB1 ;D393 rlm@145: 0xD3 ;D394 ; goto Mode 1 if A == 1 rlm@145: rlm@145: ;; GOTO Mode 2 (set-start-point-high) if current mode is 2 rlm@145: 0xFE ;D395 rlm@145: 0x02 ;D396 ; compare A with 0x02 rlm@145: rlm@145: 0xCA ;D397 rlm@145: 0xBF ;D398 rlm@145: 0xD3 ;D399 ; goto Mode 2 if A == 2 rlm@145: rlm@145: ;; GOTO Mode 3 (set-start-point-low) if current mode is 3 rlm@145: 0xFE ;D39A rlm@145: 0x03 ;D39B rlm@145: rlm@145: 0xCA ;D39C rlm@145: 0xCD ;D39D rlm@145: 0xD3 ;D39E ; goto Mode 3 if A == 3 rlm@145: rlm@145: ;; GOTO Mode 4 (write-memory) if current mode is 4 rlm@145: 0xFE ;D39F rlm@145: 0x04 ;D3A0 rlm@145: rlm@145: 0xCA ;D3A1 rlm@145: 0xDB ;D3A2 rlm@145: 0xD3 ;D3A3 rlm@145: rlm@145: 0x00 ;D3A4 rlm@145: ;; End of Mode checking, goto beginning rlm@145: 0xC3 ;D3A5 rlm@145: 0x1D ;D3A6 rlm@145: 0xD3 ;D3A7 rlm@145: rlm@145: rlm@145: ;; Mode 0 -- input-mode mode rlm@145: ;; means that we are waiting for a mode, so set the mode to rlm@145: ;; whatever is currently in input-number. If nothing is rlm@145: ;; entered, then the program stays in input-mode mode rlm@145: rlm@145: ;; set current-mode to input-number rlm@145: 0xFA ;D3A8 ; load input-number (0xD352) rlm@145: 0x52 ;D3A9 ; into A rlm@145: 0xD3 ;D3AA rlm@145: rlm@145: 0xEA ;D3AB ; load A into current-mode rlm@145: 0x82 ;D3AC ; (0xD382) rlm@145: 0xD3 ;D3AD rlm@145: rlm@145: 0xC3 ;D3AE ; go back to beginning rlm@145: 0x1D ;D3AF rlm@145: 0xD3 ;D3B0 rlm@145: ;; End Mode 0 rlm@145: rlm@145: rlm@145: ;; Mode 1 -- set-length mode rlm@145: ;; This is the header for writing things to memory. rlm@145: ;; User specifies the number of bytes to write. rlm@145: ;; Mode is auto advanced to Mode 2 after this mode rlm@145: ;; completes. rlm@145: rlm@145: ;; Set bytes left to write to input-number; rlm@145: ;; set current-mode to 0x02. rlm@145: 0xFA ;D3B1 ; load input-number (0xD352) rlm@145: 0x52 ;D3B2 ; into A rlm@145: 0xD3 ;D3B3 rlm@145: rlm@145: 0xEA ;D3B4 ; load A into bytes-left-to-write rlm@145: 0x83 ;D3B5 ; (0xD383) rlm@145: 0xD3 ;D3B6 rlm@145: rlm@145: 0x3E ;D3B7 ; load 0x02 into A. rlm@145: 0x02 ;D3B8 rlm@145: rlm@145: 0xEA ;D3B9 ; load A to current-mode rlm@145: 0x82 ;D3BA ; advancing from Mode 1 to rlm@145: 0xD3 ;D3BB ; Mode 2 rlm@145: rlm@145: 0xC3 ;D3BC ; go back to beginning rlm@145: 0x1D ;D3BD rlm@145: 0xD3 ;D3BE rlm@145: ;; End Mode 1 rlm@145: rlm@145: rlm@145: ;; Mode 2 -- set start-point-high mode rlm@145: ;; Middle part of the header for writing things to memory. rlm@145: ;; User specifies the start location in RAM to which rlm@145: ;; data will be written. rlm@145: ;; Mode is auto advanced to Mode 3 after this mode completes. rlm@145: rlm@145: ;; Set start-point-high to input-number; rlm@145: ;; set current mode to 0x03. rlm@145: 0xFA ;D3BF ; load input-number (0xD352) rlm@145: 0x52 ;D3C0 ; into A rlm@145: 0xD3 ;D3C1 rlm@145: rlm@145: 0xEA ;D3C2 ; load A into start-point-high rlm@145: 0x85 ;D3C3 ; (0xD385) rlm@145: 0xD3 ;D3C4 rlm@145: rlm@145: 0x3E ;D3C5 ; load 0x03 into A. rlm@145: 0x03 ;D3C6 rlm@145: rlm@145: 0xEA ;D3C7 ; load A to current-mode, rlm@145: 0x82 ;D3C8 ; advancing from Mode 2 to rlm@145: 0xD3 ;D3C9 ; Mode 3. rlm@145: rlm@145: 0xC3 ;D3CA ; go back to beginning rlm@145: 0x1D ;D3CB rlm@145: 0xD3 ;D3CC rlm@145: ;;End Mode 2 rlm@145: rlm@145: rlm@145: ;; Mode 3 -- set-start-point-low mode rlm@145: ;; Final part of header for writing things to memory. rlm@145: ;; User specifies the low bytes of 16 bit start-point. rlm@145: rlm@145: ;; Set start-point-low to input-number; rlm@145: ;; set current mode to 0x04 rlm@145: 0xFA ;D3CD ; load input-number into A rlm@145: 0x52 ;D3CE rlm@145: 0xD3 ;D3CF rlm@145: rlm@145: 0xEA ;D3D0 ; load A into start-point-low rlm@145: 0x86 ;D3D1 rlm@145: 0xD3 ;D3D2 rlm@145: rlm@145: 0x3E ;D3D3 ; load 0x04 into A. rlm@145: 0x04 ;D3D4 rlm@145: rlm@145: 0xEA ;D3D5 ; load A to current-mode, rlm@145: 0x82 ;D3D6 ; advancing from Mode 3 to rlm@145: 0xD3 ;D3D7 ; Mode 4. rlm@145: rlm@145: 0xC3 ;D3D8 ; go back to beginning rlm@145: 0x1D ;D3D9 rlm@145: 0xD3 ;D3DA rlm@145: rlm@145: ;; Mode 4 -- write bytes mode rlm@145: rlm@145: ;; This is where RAM manipulation happens. User supplies rlm@145: ;; bytes every frame, which are written sequentially to rlm@145: ;; start-point until bytes-to-write have been written. Once rlm@145: ;; bytes-to-write have been written, the mode is reset to 0. rlm@145: rlm@145: ;; compare bytes-written with bytes-to-write. rlm@145: ;; if they are the same, then reset mode to 0 rlm@145: rlm@145: 0xFA ;D3DB ; load bytes-to-write into A rlm@145: 0x83 ;D3DC rlm@145: 0xD3 ;D3DD rlm@145: rlm@145: 0x47 ;D3DE ; load A into B rlm@145: rlm@145: 0xFA ;D3DF ; load bytes-written into A rlm@145: 0x84 ;D3E0 rlm@145: 0xD3 ;D3E1 rlm@145: rlm@145: 0xB8 ;D3E2 ; compare A with B rlm@145: rlm@145: 0xCA ;D3E3 ; if they are equal, go to cleanup rlm@145: 0x07 ;D3E4 rlm@145: 0xD4 ;D3E5 rlm@145: rlm@145: ;; Write Memory Section rlm@145: ;; Write the input-number, interpreted as an 8-bit number, rlm@145: ;; into the current target register, determined by rlm@145: ;; (+ start-point bytes-written). rlm@145: ;; Then, increment bytes-written by 1. rlm@145: rlm@145: 0xFA ;D3E6 ; load start-point-high into A rlm@145: 0x85 ;D3E7 rlm@145: 0xD3 ;D3E8 rlm@145: rlm@145: 0x67 ;D3E9 ; load A into H rlm@145: rlm@145: 0xFA ;D3EA ; load start-point-low into A rlm@145: 0x86 ;D3EB rlm@145: 0xD3 ;D3EC rlm@145: rlm@145: 0x6F ;D3ED ; load A into L rlm@145: rlm@145: 0xFA ;D3EE ; load bytes-written into A rlm@145: 0x84 ;D3EF rlm@145: 0xD3 ;D3F0 rlm@145: rlm@145: 0x00 ;D3F1 ; These are here because rlm@145: 0x00 ;D3F2 ; I screwed up again. rlm@145: 0x00 ;D3F3 rlm@145: rlm@145: 0x85 ;D3F4 ; add L to A; store A in L. rlm@145: 0x6F ;D3F5 rlm@145: rlm@145: 0x30 ;D3F6 ; If the addition overflowed, rlm@145: 0x01 ;D3F7 rlm@145: 0x24 ;D3F8 ; increment H. rlm@145: rlm@145: ;; Now, HL points to the correct place in memory rlm@145: rlm@145: 0xFA ;D3F9 ; load input-number into A rlm@145: 0x52 ;D3FA rlm@145: 0xD3 ;D3FB rlm@145: rlm@145: 0x77 ;D3FC ; load A into (HL) rlm@145: rlm@145: 0xFA ;D3FD ; load bytes-written into A rlm@145: 0x84 ;D3FE rlm@145: 0xD3 ;D3FF rlm@145: rlm@145: 0x3C ;D400 ; increment A rlm@145: rlm@145: 0xEA ;D401 ; load A into bytes-written rlm@145: 0x84 ;D402 rlm@145: 0xD3 ;D403 rlm@145: rlm@145: 0xC3 ;D404 ; go back to beginning. rlm@145: 0x1D ;D405 rlm@145: 0xD3 ;D406 rlm@145: ;; End Write Memory Section rlm@145: rlm@145: ;; Mode 4 Cleanup Section rlm@145: ;; reset bytes-written to 0 rlm@145: ;; set mode to 0 rlm@145: 0x3E ;D407 ; load 0 into A rlm@145: 0x00 ;D408 rlm@145: rlm@145: 0xEA ;D409 ; load A into bytes-written rlm@145: 0x84 ;D40A rlm@145: 0xD3 ;D40B rlm@145: rlm@145: 0xEA ;D40C ; load A into current-mode rlm@145: 0x82 ;D40D rlm@145: 0xD3 ;D40E rlm@145: rlm@145: 0xC3 ;D40F ; go back to beginning rlm@145: 0x1D ;D410 rlm@145: 0xD3 ;D411 rlm@145: rlm@145: ;; End Mode 4 rlm@145: rlm@145: ]) rlm@145: rlm@145: rlm@145: rlm@145: (def frame-count 0xD31F) rlm@145: (def input 0xD352) rlm@145: (def current-mode 0xD382) rlm@145: (def bytes-to-write 0xD383) rlm@145: (def bytes-written 0xD384) rlm@145: (def start-point-high 0xD385) rlm@145: (def start-point-low 0xD386) rlm@145: rlm@145: rlm@145: rlm@145: (defn write-memory [] rlm@145: (-> (tick (mid-game)) rlm@145: (IE! 0) ; disable interrupts rlm@145: (inject-item-assembly (write-memory-assembly)))) rlm@145: rlm@145: (defn test-write-memory [] rlm@145: (set-state! (write-memory)) rlm@145: (dorun rlm@145: (dotimes [_ 5000] rlm@145: (view-memory (step @current-state) current-mode)))) rlm@145: rlm@145: (def bytes-to-write 0xD383) rlm@145: (def start-point 0xD384) rlm@145: rlm@145: (defn print-blank-assembly rlm@145: [start end] rlm@145: (dorun rlm@145: (map rlm@145: #(println (format "0x00 ;%04X " %)) rlm@145: (range start end)))) rlm@145: rlm@145: (defn test-mode-2 [] rlm@145: (-> rlm@145: (write-memory) rlm@145: (view-memory frame-count) rlm@145: (step) rlm@145: (step [:a]) rlm@145: (step [:b]) rlm@145: (step [:start]) rlm@145: (step []) rlm@145: (view-memory frame-count))) rlm@145: rlm@145: rlm@145: rlm@145: (defn dylan-test-mode rlm@145: ([] (dylan-test-mode (write-mem-dyl))) rlm@145: ([target-state] rlm@145: (let [ rlm@145: v-blank-prev 54046 rlm@145: btn-register 65280 rlm@145: eggs 0xD374 rlm@145: ] rlm@145: rlm@145: (-> rlm@145: target-state rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick);; jumps back to beginning rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: rlm@145: rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) ;; just complemented A rlm@145: rlm@145: (tick) rlm@145: (DE! 0x1800) rlm@145: (AF! 0x7700) ;; change inputs @ A rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: rlm@145: ;;(view-memory eggs) rlm@145: (tick) rlm@145: (tick) rlm@145: ;;(view-memory eggs) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (tick) rlm@145: (d-tick) rlm@145: rlm@145: rlm@145: ;;(view-memory btn-register) rlm@145: (view-register "A" A) rlm@145: (view-register "B" B) rlm@145: rlm@145: ;;(view-register "C" C) rlm@145: (view-register "D" D) rlm@145: (view-register "E" E) rlm@145: (view-register "H" H) rlm@145: (view-register "L" L) rlm@145: )))) rlm@145: rlm@145: (defn test-mode-4 rlm@145: ([] (test-mode-4 (write-memory))) rlm@145: ([target-state] rlm@145: (-> rlm@145: target-state rlm@145: (#(do (println "memory from 0xC00F to 0xC01F:" rlm@145: (subvec (vec (memory %)) 0xC00F 0xC01F)) %)) rlm@145: (view-memory current-mode) rlm@145: (step []) rlm@145: (step []) rlm@145: (step []) rlm@145: (#(do (println "after three steps") %)) rlm@145: (view-memory current-mode) rlm@145: rlm@145: ;; Activate memory writing mode rlm@145: rlm@145: (#(do (println "step with [:a]") %)) rlm@145: (step [:a]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-to-write) rlm@145: (view-memory start-point-high) rlm@145: (view-memory start-point-low) rlm@145: rlm@145: ;; Specify four bytes to be written rlm@145: rlm@145: (#(do (println "step with [:select]")%)) rlm@145: (step [:select]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-to-write) rlm@145: (view-memory start-point-high) rlm@145: (view-memory start-point-low) rlm@145: rlm@145: ;; Specify target memory address as 0xC00F rlm@145: rlm@145: (#(do (println "step with [:u :d]")%)) rlm@145: (step [:u :d]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-to-write) rlm@145: (view-memory start-point-high) rlm@145: (view-memory start-point-low) rlm@145: rlm@145: (#(do (println "step with [:a :b :start :select]")%)) rlm@145: (step [:a :b :start :select]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-to-write) rlm@145: (view-memory start-point-high) rlm@145: (view-memory start-point-low) rlm@145: rlm@145: ;; Start reprogramming memory rlm@145: rlm@145: (#(do (println "step with [:a]")%)) rlm@145: (step [:a]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-written) rlm@145: rlm@145: (#(do (println "step with [:b]")%)) rlm@145: (step [:b]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-written) rlm@145: rlm@145: (#(do (println "step with [:a :b]")%)) rlm@145: (step [:a :b]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-written) rlm@145: rlm@145: (#(do (println "step with [:select]")%)) rlm@145: (step [:select]) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-written) rlm@145: rlm@145: ;; Reprogramming done, program ready for more commands. rlm@145: rlm@145: (#(do (println "step with []")%)) rlm@145: (step []) rlm@145: (view-memory current-mode) rlm@145: (view-memory bytes-written) rlm@145: rlm@145: (#(do (println "memory from 0xC00F to 0xC01F:" rlm@145: (subvec (vec (memory %)) 0xC00F 0xC01F)) %))))) rlm@145: ocsenave@184: ocsenave@184: ocsenave@184: ocsenave@184: ocsenave@184: ocsenave@184: ;;; ASSEMBLY-READING UTILITIES ocsenave@184: ocsenave@184: (def opcodes ocsenave@184: [ ocsenave@184: "NOP" ocsenave@184: "LD BC,nn" ocsenave@184: "LD (BC),A" ocsenave@184: "INC BC" ocsenave@184: "INC B" ocsenave@184: "DEC B" ocsenave@184: "LD B,n" ocsenave@184: "RLC A" ocsenave@184: "LD (nn),SP" ocsenave@184: "ADD HL,BC" ocsenave@184: "LD A,(BC)" ocsenave@184: "DEC BC" ocsenave@184: "INC C" ocsenave@184: "DEC C" ocsenave@184: "LD C,n" ocsenave@184: "RRC A" ocsenave@184: ocsenave@184: "STOP" ocsenave@184: "LD DE,nn" ocsenave@184: "LD (DE),A" ocsenave@184: "INC DE" ocsenave@184: "INC D" ocsenave@184: "DEC D" ocsenave@184: "LD D,n" ocsenave@184: "RL A" ocsenave@184: "JR n" ocsenave@184: "ADD HL,DE" ocsenave@184: "LD A,(DE)" ocsenave@184: "DEC DE" ocsenave@184: "INC E" ocsenave@184: "DEC E" ocsenave@184: "LD E,n" ocsenave@184: "RR A" ocsenave@184: ocsenave@184: "JR NZ,n" ocsenave@184: "LD HL,nn" ocsenave@184: "LDI (HL),A" ocsenave@184: "INC HL" ocsenave@184: "INC H" ocsenave@184: "DEC H" ocsenave@184: "LD H,n" ocsenave@184: "DAA" ocsenave@184: "JR Z,n" ocsenave@184: "ADD HL,HL" ocsenave@184: "LDI A,(HL)" ocsenave@184: "DEC HL" ocsenave@184: "INC L" ocsenave@184: "DEC L" ocsenave@184: "LD L,n" ocsenave@184: "CPL" ocsenave@184: ocsenave@184: "JR NC,n" ocsenave@184: "LD SP,nn" ocsenave@184: "LDD (HL),A" ocsenave@184: "INC SP" ocsenave@184: "INC (HL)" ocsenave@184: "DEC (HL)" ocsenave@184: "LD (HL),n" ocsenave@184: "SCF" ocsenave@184: "JR C,n" ocsenave@184: "ADD HL,SP" ocsenave@184: "LDD A,(HL)" ocsenave@184: "DEC SP" ocsenave@184: "INC A" ocsenave@184: "DEC A" ocsenave@184: "LD A,n" ocsenave@184: "CCF" ocsenave@184: ocsenave@184: "LD B,B" ocsenave@184: "LD B,C" ocsenave@184: "LD B,D" ocsenave@184: "LD B,E" ocsenave@184: "LD B,H" ocsenave@184: "LD B,L" ocsenave@184: "LD B,(HL)" ocsenave@184: "LD B,A" ocsenave@184: "LD C,B" ocsenave@184: "LD C,C" ocsenave@184: "LD C,D" ocsenave@184: "LD C,E" ocsenave@184: "LD C,H" ocsenave@184: "LD C,L" ocsenave@184: "LD C,(HL)" ocsenave@184: "LD C,A" ocsenave@184: ocsenave@184: "LD D,B" ocsenave@184: "LD D,C" ocsenave@184: "LD D,D" ocsenave@184: "LD D,E" ocsenave@184: "LD D,H" ocsenave@184: "LD D,L" ocsenave@184: "LD D,(HL)" ocsenave@184: "LD D,A" ocsenave@184: "LD E,B" ocsenave@184: "LD E,C" ocsenave@184: "LD E,D" ocsenave@184: "LD E,E" ocsenave@184: "LD E,H" ocsenave@184: "LD E,L" ocsenave@184: "LD E,(HL)" ocsenave@184: "LD E,A" ocsenave@184: ocsenave@184: "LD H,B" ocsenave@184: "LD H,C" ocsenave@184: "LD H,D" ocsenave@184: "LD H,E" ocsenave@184: "LD H,H" ocsenave@184: "LD H,L" ocsenave@184: "LD H,(HL)" ocsenave@184: "LD H,A" ocsenave@184: "LD L,B" ocsenave@184: "LD L,C" ocsenave@184: "LD L,D" ocsenave@184: "LD L,E" ocsenave@184: "LD L,H" ocsenave@184: "LD L,L" ocsenave@184: "LD L,(HL)" ocsenave@184: "LD L,A" ocsenave@184: ocsenave@184: "LD (HL),B" ocsenave@184: "LD (HL),C" ocsenave@184: "LD (HL),D" ocsenave@184: "LD (HL),E" ocsenave@184: "LD (HL),H" ocsenave@184: "LD (HL),L" ocsenave@184: "HALT" ocsenave@184: "LD (HL),A" ocsenave@184: "LD A,B" ocsenave@184: "LD A,C" ocsenave@184: "LD A,D" ocsenave@184: "LD A,E" ocsenave@184: "LD A,H" ocsenave@184: "LD A,L" ocsenave@184: "LD A,(HL)" ocsenave@184: "LD A,A" ocsenave@184: ocsenave@184: "ADD A,B" ocsenave@184: "ADD A,C" ocsenave@184: "ADD A,D" ocsenave@184: "ADD A,E" ocsenave@184: "ADD A,H" ocsenave@184: "ADD A,L" ocsenave@184: "ADD A,(HL)" ocsenave@184: "ADD A,A" ocsenave@184: "ADC A,B" ocsenave@184: "ADC A,C" ocsenave@184: "ADC A,D" ocsenave@184: "ADC A,E" ocsenave@184: "ADC A,H" ocsenave@184: "ADC A,L" ocsenave@184: "ADC A,(HL)" ocsenave@184: "ADC A,A" ocsenave@184: ocsenave@184: "SUB A,B" ocsenave@184: "SUB A,C" ocsenave@184: "SUB A,D" ocsenave@184: "SUB A,E" ocsenave@184: "SUB A,H" ocsenave@184: "SUB A,L" ocsenave@184: "SUB A,(HL)" ocsenave@184: "SUB A,A" ocsenave@184: "SBC A,B" ocsenave@184: "SBC A,C" ocsenave@184: "SBC A,D" ocsenave@184: "SBC A,E" ocsenave@184: "SBC A,H" ocsenave@184: "SBC A,L" ocsenave@184: "SBC A,(HL)" ocsenave@184: "SBC A,A" ocsenave@184: ocsenave@184: "AND B" ocsenave@184: "AND C" ocsenave@184: "AND D" ocsenave@184: "AND E" ocsenave@184: "AND H" ocsenave@184: "AND L" ocsenave@184: "AND (HL)" ocsenave@184: "AND A" ocsenave@184: "XOR B" ocsenave@184: "XOR C" ocsenave@184: "XOR D" ocsenave@184: "XOR E" ocsenave@184: "XOR H" ocsenave@184: "XOR L" ocsenave@184: "XOR (HL)" ocsenave@184: "XOR A" ocsenave@184: ocsenave@184: "OR B" ocsenave@184: "OR C" ocsenave@184: "OR D" ocsenave@184: "OR E" ocsenave@184: "OR H" ocsenave@184: "OR L" ocsenave@184: "OR (HL)" ocsenave@184: "OR A" ocsenave@184: "CP B" ocsenave@184: "CP C" ocsenave@184: "CP D" ocsenave@184: "CP E" ocsenave@184: "CP H" ocsenave@184: "CP L" ocsenave@184: "CP (HL)" ocsenave@184: "CP A" ocsenave@184: ocsenave@184: "RET NZ" ocsenave@184: "POP BC" ocsenave@184: "JP NZ,nn" ocsenave@184: "JP nn" ocsenave@184: "CALL NZ,nn" ocsenave@184: "PUSH BC" ocsenave@184: "ADD A,n" ocsenave@184: "RST 0" ocsenave@184: "RET Z" ocsenave@184: "RET" ocsenave@184: "JP Z,nn" ocsenave@184: "Ext ops" ocsenave@184: "CALL Z,nn" ocsenave@184: "CALL nn" ocsenave@184: "ADC A,n" ocsenave@184: "RST 8" ocsenave@184: ocsenave@184: "RET NC" ocsenave@184: "POP DE" ocsenave@184: "JP NC,nn" ocsenave@184: "XX" ocsenave@184: "CALL NC,nn" ocsenave@184: "PUSH DE" ocsenave@184: "SUB A,n" ocsenave@184: "RST 10" ocsenave@184: "RET C" ocsenave@184: "RETI" ocsenave@184: "JP C,nn" ocsenave@184: "XX" ocsenave@184: "CALL C,nn" ocsenave@184: "XX" ocsenave@184: "SBC A,n" ocsenave@184: "RST 18" ocsenave@184: ocsenave@184: "LDH (n),A" ocsenave@184: "POP HL" ocsenave@184: "LDH (C),A" ocsenave@184: "XX" ocsenave@184: "XX" ocsenave@184: "PUSH HL" ocsenave@184: "AND n" ocsenave@184: "RST 20" ocsenave@184: "ADD SP,d" ocsenave@184: "JP (HL)" ocsenave@184: "LD (nn),A" ocsenave@184: "XX" ocsenave@184: "XX" ocsenave@184: "XX" ocsenave@184: "XOR n" ocsenave@184: "RST 28" ocsenave@184: ocsenave@184: "LDH A,(n)" ocsenave@184: "POP AF" ocsenave@184: "XX" ocsenave@184: "DI" ocsenave@184: "XX" ocsenave@184: "PUSH AF" ocsenave@184: "OR n" ocsenave@184: "RST 30" ocsenave@184: "LDHL SP,d" ocsenave@184: "LD SP,HL" ocsenave@184: "LD A,(nn)" ocsenave@184: "EI" ocsenave@184: "XX" ocsenave@184: "XX" ocsenave@184: "CP n" ocsenave@184: "RST 38"]) ocsenave@184: ocsenave@184: ocsenave@184: (defn hex ocsenave@184: "Converts the number into a hexadecimal-formatted symbol." ocsenave@184: [n] ocsenave@184: (symbol (str "0x" (.toUpperCase (Integer/toHexString n))))) ocsenave@184: ocsenave@184: ocsenave@184: ocsenave@184: (defn arity ocsenave@184: "Returns the arity of the given opcode (hex numeral)." ocsenave@184: [op] ocsenave@184: (cond ocsenave@184: (#{0x06 0x0E 0x16 0x1E ocsenave@184: 0x20 0x26 0x28 0x2E ocsenave@184: 0x30 0x36 0x38 0x3E ocsenave@184: 0xC6 0xD6 0xCE 0xDE ocsenave@184: 0xE0 0xF0 0xE6 0xF6 ocsenave@184: 0xEE 0xFE} op) ocsenave@184: 1 ocsenave@184: (#{0x01 0x08 0x11 0x21 ocsenave@184: 0x31 0xC2 0xC3 0xC4 ocsenave@184: 0xCA 0xDA 0xCC 0xDC ocsenave@184: 0xCD 0xEA 0xFA} op) ocsenave@184: 2 ocsenave@184: :else ocsenave@184: 0))