# HG changeset patch # User Robert McIntyre # Date 1334333888 18000 # Node ID 41647cb85901e2f1b2599951a2f2a8caaf1500b6 # Parent ea37e98e188e2d648f2569264b56b564bcd3759e got main-bootstrap-program down to 67 opcodes. diff -r ea37e98e188e -r 41647cb85901 clojure/com/aurellem/gb/rlm_assembly.clj --- a/clojure/com/aurellem/gb/rlm_assembly.clj Fri Apr 13 09:59:32 2012 -0500 +++ b/clojure/com/aurellem/gb/rlm_assembly.clj Fri Apr 13 11:18:08 2012 -0500 @@ -70,38 +70,51 @@ (if (< n 0) (+ 256 n) n)) -(defn frame-metronome - ([] (frame-metronome true)) - ([spin-loop?] - (let [init [0xC5] ;; save value of BC - timing-loop - [0x01 ; \ - 0x43 ; | - 0xFE ; | load 0xFF44 into BC without repeats - 0x0C ; | - 0x04 ; / - 0x0A] ;; (BC) -> A, now A = LY (vertical line coord) - continue-if-144 - [0xFE - 144 ;; compare LY (in A) with 144 - 0x20 ;; jump back to beginning if LY != 144 (not-v-blank) - (->signed-8-bit - (+ -4 (- (count timing-loop))))] - spin-loop - [0x05 ;; dec B, which is 0xFF - 0x20 ;; spin until B==0 - 0xFD]] - (concat init timing-loop continue-if-144 - (if spin-loop? - spin-loop []))))) +(defn frame-metronome** [] + (let [init [0xC5] ;; save value of BC + timing-loop + [0x01 ; \ + 0x43 ; | + 0xFE ; | load 0xFF44 into BC without repeats + 0x0C ; | + 0x04 ; / + 0x0A] ;; (BC) -> A, now A = LY (vertical line coord) + continue-if-144 + [0xFE + 144 ;; compare LY (in A) with 144 + 0x20 ;; jump back to beginning if LY != 144 (not-v-blank) + (->signed-8-bit + (+ -4 (- (count timing-loop))))] + spin-loop + [0x05 ;; dec B, which is 0xFF + 0x20 ;; spin until B==0 + 0xFD]] + (concat init timing-loop continue-if-144 spin-loop))) + +(defn frame-metronome* [] + [0x3E ;; smallest version, but uses repeated nybbles + 0x01 + 0xE0 + 0xFF]) + + +(defn frame-metronome [] + [0x06 ;; load 0xFE into B + 0xFE + 0x04 ;; inc B, now B == FF + 0x3E + 0x01 ;; 1->A + + 0x48 ;; B->C + 0x02]) ;; A->(BC) set exclusive v-blank interrupt (defn test-frame-metronome "Ensure that frame-metronome ticks exactly once every frame." ([] (test-frame-metronome 151)) ([steps] - (let [inc-E [0x1C 0x18 - (->signed-8-bit - (+ -3 (- (count (frame-metronome)))))] + (let [inc-E [0x1C 0x76 0x18 + (->signed-8-bit -4)] + program (concat (frame-metronome) inc-E) count-frames (-> (tick (mid-game)) @@ -113,12 +126,15 @@ (E (run-moves count-frames (repeat steps [])))] (println "E:" E-after-moves) (assert (= steps E-after-moves)) - + (println "E =" E-after-moves "after" steps "steps") count-frames))) (defn read-user-input [] - [0x3E + [0xAF 0x4F 0x47 ;; 0->A; 0->C; 0->B + 0xC5 ;; save value of BC + + 0x3E 0x20 ; prepare to measure d-pad 0x01 ;\ @@ -156,7 +172,6 @@ 0xB0 ;; (or A B) -> A 0x2F ;; (NOT A) -> A - ]) (defn test-read-user-input [] @@ -164,19 +179,19 @@ (concat (frame-metronome) (read-user-input) [0x5F ;; A-> E + 0x76 0x18 (->signed-8-bit - (+ (- (count (frame-metronome))) - (- (count (read-user-input))) - (- 3)))]) + (+ (- (count (read-user-input))) + (- 4)))]) read-input (-> (tick (mid-game)) (IE! 0) (set-memory-range pokemon-list-start program) (PC! pokemon-list-start))] (dorun - (for [i (range 0x100)] - (assert (= (E (step read-input (buttons i))) i)))) + (for [i (range 0x100)] + (assert (= (E (step read-input (buttons i))) i)))) (println "Tested all inputs.") read-input)) @@ -208,13 +223,8 @@ ;; multi-action-modes ;; WRITE 0x47 ;; A->B - (let [[start-high start-low] (disect-bytes-2 start-address) - jump-distance (+ (count (frame-metronome)) - (count (read-user-input))) - - init - [0xAF 0x4F 0x47] ;; 0->A; 0->C; 0->B - + (let [header (concat (frame-metronome) (read-user-input)) + input [0xC1 ;; pop BC so it's not volatile @@ -244,37 +254,35 @@ 0x7B ;; E->A 0x4F ;; A->C now C stores previous instruction 0x18 ;; return - :to-beginning-1] + :to-halt] output [:output-start ;; just a label 0x54 ;; 0x5D ;; HL->DE \ - ;; | This mess is here to do + ;; | This mess is here to do 0x12 ;; A->(DE) | 0x22 (LDI (HL), A) without - ;; | any repeating nybbles + ;; | any repeating nybbles 0x23 ;; inc HL / 0x05 ;; DEC bytes-to-write (B) + 0x76 ;; HALT, peasant! 0x18 - :to-beginning-2] - + :to-beginning] + symbols {:to-be-executed-address (reverse (disect-bytes-2 - (+ start-address jump-distance - (count init) + (+ start-address + (count header) (symbol-index :to-be-executed input)))) :to-be-executed 0x00} ;; clear carry flag no-op program** (flatten - (replace - symbols - (concat init (frame-metronome) - (read-user-input) - input output))) + (replace symbols (concat header input output))) + resolve-internal-jumps {:output-start [] :to-output @@ -287,14 +295,14 @@ (flatten (replace resolve-internal-jumps program**)) resolve-external-jumps - {:to-beginning-1 + {:to-halt + (- (- (symbol-index :to-beginning program*) + (symbol-index :to-halt program*)) 3) + + :to-beginning (->signed-8-bit - (+ (count init) - -2 (- (dec (symbol-index :to-beginning-1 program*))))) - :to-beginning-2 - (->signed-8-bit - (+ (count init) - -2 (- (dec (symbol-index :to-beginning-2 program*)))))} + (+ 2 (count (frame-metronome)) + (- (symbol-index :to-beginning program*))))} program (replace resolve-external-jumps program*)]