comparison clojure/com/aurellem/gb/rlm_assembly.clj @ 403:ea37e98e188e

removed one opcode
author Robert McIntyre <rlm@mit.edu>
date Fri, 13 Apr 2012 09:59:32 -0500
parents eee219d1a259
children 41647cb85901
comparison
equal deleted inserted replaced
402:eee219d1a259 403:ea37e98e188e
68 68
69 (defn ->signed-8-bit [n] 69 (defn ->signed-8-bit [n]
70 (if (< n 0) 70 (if (< n 0)
71 (+ 256 n) n)) 71 (+ 256 n) n))
72 72
73 (defn frame-metronome [] 73 (defn frame-metronome
74 (let [init [0xC5] ;; save value of BC 74 ([] (frame-metronome true))
75 timing-loop 75 ([spin-loop?]
76 [0x01 ; \ 76 (let [init [0xC5] ;; save value of BC
77 0x43 ; | 77 timing-loop
78 0xFE ; | load 0xFF44 into BC without repeats 78 [0x01 ; \
79 0x0C ; | 79 0x43 ; |
80 0x04 ; / 80 0xFE ; | load 0xFF44 into BC without repeats
81 0x0A] ;; (BC) -> A, now A = LY (vertical line coord) 81 0x0C ; |
82 continue-if-144 82 0x04 ; /
83 [0xFE 83 0x0A] ;; (BC) -> A, now A = LY (vertical line coord)
84 144 ;; compare LY (in A) with 144 84 continue-if-144
85 0x20 ;; jump back to beginning if LY != 144 (not-v-blank) 85 [0xFE
86 (->signed-8-bit 86 144 ;; compare LY (in A) with 144
87 (+ -4 (- (count timing-loop))))] 87 0x20 ;; jump back to beginning if LY != 144 (not-v-blank)
88 spin-loop 88 (->signed-8-bit
89 [0x05 ;; dec B, which is 0xFF 89 (+ -4 (- (count timing-loop))))]
90 0x20 ;; spin until B==0 90 spin-loop
91 0xFD]] 91 [0x05 ;; dec B, which is 0xFF
92 (concat init timing-loop continue-if-144 spin-loop))) 92 0x20 ;; spin until B==0
93 0xFD]]
94 (concat init timing-loop continue-if-144
95 (if spin-loop?
96 spin-loop [])))))
93 97
94 (defn test-frame-metronome 98 (defn test-frame-metronome
95 "Ensure that frame-metronome ticks exactly once every frame." 99 "Ensure that frame-metronome ticks exactly once every frame."
96 ([] (test-frame-metronome 151)) 100 ([] (test-frame-metronome 151))
97 ([steps] 101 ([steps]
180 (fn [symbol sequence] 184 (fn [symbol sequence]
181 (count (take-while 185 (count (take-while
182 (partial not= symbol) 186 (partial not= symbol)
183 sequence)))) 187 sequence))))
184 188
185 189 (defn main-bootstrap-program
186 (defn main-bootstrap-program [start-address] 190 ([] (main-bootstrap-program pokemon-list-start))
187 ;; Register Use: 191 ([start-address]
188 192 ;; Register Use:
189 ;; ED non-volitale scratch 193
190 194 ;; ED non-volitale scratch
191 ;; A user-input 195
192 ;; HL target-address 196 ;; A user-input
193 ;; B bytes-to-write 197 ;; HL target-address
194 ;; C non-volatile scratch 198 ;; B bytes-to-write
195 199 ;; C non-volatile scratch
196 ;; Modes (with codes) are: 200
197 201 ;; Modes (with codes) are:
198 ;; single-action-modes: 202
199 ;; SET-TARGET-HIGH 0x67 ;; A->H 203 ;; single-action-modes:
200 ;; SET-TARGET-LOW 0x6F ;; A->L 204 ;; SET-TARGET-HIGH 0x67 ;; A->H
201 ;; JUMP 0xE9 ;; jump to (HL) 205 ;; SET-TARGET-LOW 0x6F ;; A->L
202 206 ;; JUMP 0xE9 ;; jump to (HL)
203 ;; multi-action-modes 207
204 ;; WRITE 0x47 ;; A->B 208 ;; multi-action-modes
205 209 ;; WRITE 0x47 ;; A->B
206 (let [[start-high start-low] (disect-bytes-2 start-address) 210
207 jump-distance (+ (count (frame-metronome)) 211 (let [[start-high start-low] (disect-bytes-2 start-address)
208 (count (read-user-input))) 212 jump-distance (+ (count (frame-metronome))
209 213 (count (read-user-input)))
210 init 214
211 [0xAF 0x4F 0x57 0x47] ;; 0->A; 0->C; 0->D; 0->B 215 init
212 216 [0xAF 0x4F 0x47] ;; 0->A; 0->C; 0->B
213 input 217
214 [0xC1 ;; pop BC so it's not volatile 218 input
215 219 [0xC1 ;; pop BC so it's not volatile
216 0x5F ;; A->E 220
217 0xAF ;; test for output-mode (bytes-to-write > 0) 221 0x5F ;; A->E
218 0xB8 ;; (cp A B) 222 0xAF ;; test for output-mode (bytes-to-write > 0)
219 0x7B ;; E->A 223 0xB8 ;; (cp A B)
220 0x20 ;; skip to output section if 224 0x7B ;; E->A
221 :to-output ;; we're not in input mode 225 0x20 ;; skip to output section if
222 226 :to-output ;; we're not in input mode
223 :to-be-executed 227
224 228 :to-be-executed
225 ;; write mode to instruction-to-be-executed (pun) 229
226 0xEA 230 ;; write mode to instruction-to-be-executed (pun)
227 :to-be-executed-address 231 0xEA
228 232 :to-be-executed-address
229 ;; protection region -- do not queue this op for 233
230 ;; execution if the last one was non-zero 234 ;; protection region -- do not queue this op for
231 0x79 ;; C->A 235 ;; execution if the last one was non-zero
232 0xA7 ;; test A==0 236 0x79 ;; C->A
233 0x28 237 0xA7 ;; test A==0
234 0x04 238 0x28
235 0xAF ;; put a no op (0x00) in to-be-executed 239 0x04
236 0xEA ;; 240 0xAF ;; put a no op (0x00) in to-be-executed
237 :to-be-executed-address 241 0xEA ;;
238 242 :to-be-executed-address
239 0x7B ;; E->A 243
240 0x4F ;; A->C now C stores previous instruction 244 0x7B ;; E->A
241 0x18 ;; return 245 0x4F ;; A->C now C stores previous instruction
242 :to-beginning-1] 246 0x18 ;; return
243 247 :to-beginning-1]
244 output 248
245 [:output-start ;; just a label 249 output
246 0x54 ;; 250 [:output-start ;; just a label
247 0x5D ;; HL->DE \ 251 0x54 ;;
248 ;; | This mess is here to do 252 0x5D ;; HL->DE \
249 0x12 ;; A->(DE) | 0x22 (LDI (HL), A) without 253 ;; | This mess is here to do
250 ;; | any repeating nybbles 254 0x12 ;; A->(DE) | 0x22 (LDI (HL), A) without
251 0x23 ;; inc HL / 255 ;; | any repeating nybbles
252 256 0x23 ;; inc HL /
253 0x05 ;; DEC bytes-to-write (B) 257
254 258 0x05 ;; DEC bytes-to-write (B)
255 0x18 259
256 :to-beginning-2] 260 0x18
257 261 :to-beginning-2]
258 symbols 262
259 {:to-be-executed-address 263 symbols
260 (reverse 264 {:to-be-executed-address
261 (disect-bytes-2 265 (reverse
262 (+ start-address jump-distance 266 (disect-bytes-2
263 (count init) 267 (+ start-address jump-distance
264 (symbol-index :to-be-executed input)))) 268 (count init)
265 :to-be-executed 0x00} ;; clear carry flag no-op 269 (symbol-index :to-be-executed input))))
266 270 :to-be-executed 0x00} ;; clear carry flag no-op
267 program** (flatten 271
268 (replace 272 program** (flatten
269 symbols 273 (replace
270 (concat init (frame-metronome) 274 symbols
271 (read-user-input) 275 (concat init (frame-metronome)
272 input output))) 276 (read-user-input)
273 resolve-internal-jumps 277 input output)))
274 {:output-start [] 278 resolve-internal-jumps
275 :to-output 279 {:output-start []
276 (->signed-8-bit 280 :to-output
277 (dec 281 (->signed-8-bit
278 (- (symbol-index :output-start program**) 282 (dec
279 (symbol-index :to-output program**))))} 283 (- (symbol-index :output-start program**)
280 284 (symbol-index :to-output program**))))}
281 program* 285
282 (flatten (replace resolve-internal-jumps program**)) 286 program*
283 287 (flatten (replace resolve-internal-jumps program**))
284 resolve-external-jumps 288
285 {:to-beginning-1 289 resolve-external-jumps
286 (->signed-8-bit 290 {:to-beginning-1
287 (+ (count init) 291 (->signed-8-bit
288 -2 (- (dec (symbol-index :to-beginning-1 program*))))) 292 (+ (count init)
289 :to-beginning-2 293 -2 (- (dec (symbol-index :to-beginning-1 program*)))))
290 (->signed-8-bit 294 :to-beginning-2
291 (+ (count init) 295 (->signed-8-bit
292 -2 (- (dec (symbol-index :to-beginning-2 program*)))))} 296 (+ (count init)
293 297 -2 (- (dec (symbol-index :to-beginning-2 program*)))))}
294 program 298
295 (replace resolve-external-jumps program*)] 299 program
296 program)) 300 (replace resolve-external-jumps program*)]
301 program)))
297 302
298 303
299 ;;;;;; TESTS ;;;;;; 304 ;;;;;; TESTS ;;;;;;
300 305
301 (def set-H-mode 0x67) 306 (def set-H-mode 0x67)
322 (step (buttons n)) 327 (step (buttons n))
323 (step []))] 328 (step []))]
324 ;;(println "desired H =" n "actual =" (H after)) 329 ;;(println "desired H =" n "actual =" (H after))
325 (assert (= n (H after))) 330 (assert (= n (H after)))
326 after))] 331 after))]
327 (println "tested all H values") 332 (let [result (reduce test-H (bootstrap-base) (range 0x100))]
328 (reduce test-H (bootstrap-base) (range 0x100)))) 333 (println "tested all H values")
334 result)))
329 335
330 (defn test-write-bytes [] 336 (defn test-write-bytes []
331 (let [target-address 0xC00F 337 (let [target-address 0xC00F
332 [target-high target-low] (disect-bytes-2 target-address) 338 [target-high target-low] (disect-bytes-2 target-address)
333 assembly [0xF3 0x18 0xFE 0x12] 339 assembly [0xF3 0x18 0xFE 0x12]