diff clojure/com/aurellem/gb/rlm_assembly.clj @ 404:41647cb85901

got main-bootstrap-program down to 67 opcodes.
author Robert McIntyre <rlm@mit.edu>
date Fri, 13 Apr 2012 11:18:08 -0500
parents ea37e98e188e
children bca0abd39db5
line wrap: on
line diff
     1.1 --- a/clojure/com/aurellem/gb/rlm_assembly.clj	Fri Apr 13 09:59:32 2012 -0500
     1.2 +++ b/clojure/com/aurellem/gb/rlm_assembly.clj	Fri Apr 13 11:18:08 2012 -0500
     1.3 @@ -70,38 +70,51 @@
     1.4    (if (< n 0)
     1.5      (+ 256 n) n))
     1.6  
     1.7 -(defn frame-metronome
     1.8 -  ([] (frame-metronome true))
     1.9 -  ([spin-loop?]
    1.10 -     (let [init [0xC5] ;; save value of BC
    1.11 -           timing-loop
    1.12 -           [0x01 ; \
    1.13 -            0x43 ;  |
    1.14 -            0xFE ;  |  load 0xFF44 into BC without repeats
    1.15 -            0x0C ;  |
    1.16 -            0x04 ; /
    1.17 -            0x0A] ;; (BC) -> A, now A = LY (vertical line coord)
    1.18 -           continue-if-144
    1.19 -           [0xFE
    1.20 -            144     ;; compare LY (in A) with 144
    1.21 -            0x20    ;; jump back to beginning if LY != 144 (not-v-blank)
    1.22 -            (->signed-8-bit
    1.23 -             (+ -4 (- (count timing-loop))))]
    1.24 -           spin-loop
    1.25 -           [0x05 ;; dec B, which is 0xFF
    1.26 -            0x20 ;; spin until B==0
    1.27 -            0xFD]]
    1.28 -       (concat init timing-loop continue-if-144
    1.29 -               (if spin-loop?
    1.30 -                 spin-loop [])))))
    1.31 +(defn frame-metronome** []
    1.32 +  (let [init [0xC5] ;; save value of BC
    1.33 +        timing-loop
    1.34 +        [0x01 ; \
    1.35 +         0x43 ;  |
    1.36 +         0xFE ;  |  load 0xFF44 into BC without repeats
    1.37 +         0x0C ;  |
    1.38 +         0x04 ; /
    1.39 +         0x0A] ;; (BC) -> A, now A = LY (vertical line coord)
    1.40 +        continue-if-144
    1.41 +        [0xFE
    1.42 +         144     ;; compare LY (in A) with 144
    1.43 +         0x20    ;; jump back to beginning if LY != 144 (not-v-blank)
    1.44 +         (->signed-8-bit
    1.45 +          (+ -4 (- (count timing-loop))))]
    1.46 +        spin-loop
    1.47 +        [0x05 ;; dec B, which is 0xFF
    1.48 +         0x20 ;; spin until B==0
    1.49 +         0xFD]]
    1.50 +    (concat init timing-loop continue-if-144 spin-loop)))
    1.51 +
    1.52 +(defn frame-metronome* []
    1.53 +  [0x3E   ;; smallest version, but uses repeated nybbles
    1.54 +   0x01    
    1.55 +   0xE0
    1.56 +   0xFF])
    1.57 +
    1.58 +
    1.59 +(defn frame-metronome []
    1.60 +  [0x06 ;; load 0xFE into B
    1.61 +   0xFE
    1.62 +   0x04 ;; inc B, now B == FF
    1.63 +   0x3E
    1.64 +   0x01 ;; 1->A
    1.65 +   
    1.66 +   0x48 ;; B->C
    1.67 +   0x02]) ;; A->(BC) set exclusive v-blank interrupt
    1.68  
    1.69  (defn test-frame-metronome
    1.70    "Ensure that frame-metronome ticks exactly once every frame."
    1.71    ([] (test-frame-metronome 151))
    1.72    ([steps]
    1.73 -     (let [inc-E [0x1C 0x18
    1.74 -                  (->signed-8-bit
    1.75 -                   (+ -3 (- (count (frame-metronome)))))]
    1.76 +     (let [inc-E [0x1C 0x76 0x18 
    1.77 +                  (->signed-8-bit -4)]
    1.78 +                   
    1.79             program (concat (frame-metronome) inc-E)
    1.80             count-frames
    1.81             (-> (tick (mid-game))
    1.82 @@ -113,12 +126,15 @@
    1.83             (E (run-moves count-frames (repeat steps [])))]
    1.84         (println "E:" E-after-moves) 
    1.85         (assert (= steps E-after-moves))
    1.86 -
    1.87 +       
    1.88         (println "E =" E-after-moves "after" steps "steps")
    1.89         count-frames)))
    1.90  
    1.91  (defn read-user-input []
    1.92 -  [0x3E
    1.93 +  [0xAF 0x4F 0x47 ;; 0->A; 0->C; 0->B
    1.94 +   0xC5 ;; save value of BC
    1.95 +      
    1.96 +   0x3E
    1.97     0x20 ; prepare to measure d-pad
    1.98  
    1.99     0x01 ;\
   1.100 @@ -156,7 +172,6 @@
   1.101     0xB0 ;; (or A B) -> A
   1.102   
   1.103     0x2F ;; (NOT A) -> A
   1.104 -   
   1.105     ])
   1.106  
   1.107  (defn test-read-user-input []
   1.108 @@ -164,19 +179,19 @@
   1.109          (concat
   1.110           (frame-metronome) (read-user-input)
   1.111           [0x5F ;; A-> E
   1.112 +          0x76
   1.113            0x18
   1.114            (->signed-8-bit
   1.115 -           (+ (- (count (frame-metronome)))
   1.116 -              (- (count (read-user-input)))
   1.117 -              (- 3)))])
   1.118 +           (+ (- (count (read-user-input)))
   1.119 +              (- 4)))])
   1.120          read-input
   1.121          (-> (tick (mid-game))
   1.122              (IE! 0)
   1.123              (set-memory-range pokemon-list-start program)
   1.124              (PC! pokemon-list-start))]
   1.125      (dorun
   1.126 -      (for [i (range 0x100)]
   1.127 -        (assert (= (E (step read-input (buttons i))) i))))
   1.128 +     (for [i (range 0x100)]
   1.129 +       (assert (= (E (step read-input (buttons i))) i))))
   1.130       (println "Tested all inputs.")
   1.131      read-input))
   1.132  
   1.133 @@ -208,13 +223,8 @@
   1.134       ;; multi-action-modes
   1.135       ;; WRITE               0x47 ;; A->B
   1.136  
   1.137 -     (let [[start-high start-low] (disect-bytes-2 start-address)
   1.138 -           jump-distance (+ (count (frame-metronome))
   1.139 -                            (count (read-user-input)))
   1.140 -
   1.141 -           init
   1.142 -           [0xAF 0x4F 0x47] ;; 0->A; 0->C; 0->B
   1.143 -
   1.144 +     (let [header (concat (frame-metronome) (read-user-input))
   1.145 +           
   1.146             input
   1.147             [0xC1  ;; pop BC so it's not volatile
   1.148  
   1.149 @@ -244,37 +254,35 @@
   1.150              0x7B ;; E->A
   1.151              0x4F ;; A->C now C stores previous instruction
   1.152              0x18           ;; return
   1.153 -            :to-beginning-1]
   1.154 +            :to-halt]
   1.155             
   1.156             output
   1.157             [:output-start ;; just a label
   1.158              0x54 ;;
   1.159              0x5D ;; HL->DE  \
   1.160 -            ;;          | This mess is here to do
   1.161 +                 ;;          | This mess is here to do
   1.162              0x12 ;; A->(DE)  | 0x22 (LDI (HL), A) without
   1.163 -            ;;          | any repeating nybbles
   1.164 +                 ;;          | any repeating nybbles
   1.165              0x23 ;; inc HL  /
   1.166  
   1.167              0x05 ;; DEC bytes-to-write (B)
   1.168  
   1.169 +            0x76 ;; HALT, peasant!
   1.170              0x18
   1.171 -            :to-beginning-2]
   1.172 -           
   1.173 +            :to-beginning] 
   1.174 +
   1.175             symbols
   1.176             {:to-be-executed-address
   1.177              (reverse
   1.178               (disect-bytes-2
   1.179 -              (+ start-address jump-distance
   1.180 -                 (count init)
   1.181 +              (+ start-address
   1.182 +                 (count header)
   1.183                   (symbol-index :to-be-executed input))))
   1.184              :to-be-executed 0x00} ;; clear carry flag no-op
   1.185  
   1.186             program** (flatten
   1.187 -                      (replace
   1.188 -                       symbols
   1.189 -                       (concat init (frame-metronome)
   1.190 -                               (read-user-input)
   1.191 -                               input output)))
   1.192 +                      (replace symbols (concat header input output)))
   1.193 +           
   1.194             resolve-internal-jumps
   1.195             {:output-start []
   1.196              :to-output
   1.197 @@ -287,14 +295,14 @@
   1.198             (flatten (replace resolve-internal-jumps program**))
   1.199             
   1.200             resolve-external-jumps
   1.201 -           {:to-beginning-1
   1.202 +           {:to-halt
   1.203 +            (- (- (symbol-index :to-beginning program*)
   1.204 +                  (symbol-index :to-halt program*)) 3)
   1.205 +               
   1.206 +            :to-beginning
   1.207              (->signed-8-bit
   1.208 -             (+ (count init)
   1.209 -                -2 (- (dec (symbol-index :to-beginning-1 program*)))))
   1.210 -            :to-beginning-2
   1.211 -            (->signed-8-bit
   1.212 -             (+ (count init)
   1.213 -                -2 (- (dec (symbol-index :to-beginning-2 program*)))))}
   1.214 +             (+ 2 (count (frame-metronome))
   1.215 +                (- (symbol-index :to-beginning program*))))}
   1.216  
   1.217             program
   1.218             (replace resolve-external-jumps program*)]