Mercurial > vba-clojure
comparison 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 |
comparison
equal
deleted
inserted
replaced
403:ea37e98e188e | 404:41647cb85901 |
---|---|
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 ([] (frame-metronome true)) | 74 (let [init [0xC5] ;; save value of BC |
75 ([spin-loop?] | 75 timing-loop |
76 (let [init [0xC5] ;; save value of BC | 76 [0x01 ; \ |
77 timing-loop | 77 0x43 ; | |
78 [0x01 ; \ | 78 0xFE ; | load 0xFF44 into BC without repeats |
79 0x43 ; | | 79 0x0C ; | |
80 0xFE ; | load 0xFF44 into BC without repeats | 80 0x04 ; / |
81 0x0C ; | | 81 0x0A] ;; (BC) -> A, now A = LY (vertical line coord) |
82 0x04 ; / | 82 continue-if-144 |
83 0x0A] ;; (BC) -> A, now A = LY (vertical line coord) | 83 [0xFE |
84 continue-if-144 | 84 144 ;; compare LY (in A) with 144 |
85 [0xFE | 85 0x20 ;; jump back to beginning if LY != 144 (not-v-blank) |
86 144 ;; compare LY (in A) with 144 | 86 (->signed-8-bit |
87 0x20 ;; jump back to beginning if LY != 144 (not-v-blank) | 87 (+ -4 (- (count timing-loop))))] |
88 (->signed-8-bit | 88 spin-loop |
89 (+ -4 (- (count timing-loop))))] | 89 [0x05 ;; dec B, which is 0xFF |
90 spin-loop | 90 0x20 ;; spin until B==0 |
91 [0x05 ;; dec B, which is 0xFF | 91 0xFD]] |
92 0x20 ;; spin until B==0 | 92 (concat init timing-loop continue-if-144 spin-loop))) |
93 0xFD]] | 93 |
94 (concat init timing-loop continue-if-144 | 94 (defn frame-metronome* [] |
95 (if spin-loop? | 95 [0x3E ;; smallest version, but uses repeated nybbles |
96 spin-loop []))))) | 96 0x01 |
97 0xE0 | |
98 0xFF]) | |
99 | |
100 | |
101 (defn frame-metronome [] | |
102 [0x06 ;; load 0xFE into B | |
103 0xFE | |
104 0x04 ;; inc B, now B == FF | |
105 0x3E | |
106 0x01 ;; 1->A | |
107 | |
108 0x48 ;; B->C | |
109 0x02]) ;; A->(BC) set exclusive v-blank interrupt | |
97 | 110 |
98 (defn test-frame-metronome | 111 (defn test-frame-metronome |
99 "Ensure that frame-metronome ticks exactly once every frame." | 112 "Ensure that frame-metronome ticks exactly once every frame." |
100 ([] (test-frame-metronome 151)) | 113 ([] (test-frame-metronome 151)) |
101 ([steps] | 114 ([steps] |
102 (let [inc-E [0x1C 0x18 | 115 (let [inc-E [0x1C 0x76 0x18 |
103 (->signed-8-bit | 116 (->signed-8-bit -4)] |
104 (+ -3 (- (count (frame-metronome)))))] | 117 |
105 program (concat (frame-metronome) inc-E) | 118 program (concat (frame-metronome) inc-E) |
106 count-frames | 119 count-frames |
107 (-> (tick (mid-game)) | 120 (-> (tick (mid-game)) |
108 (IE! 0) | 121 (IE! 0) |
109 (DE! 0) | 122 (DE! 0) |
111 (PC! pokemon-list-start)) | 124 (PC! pokemon-list-start)) |
112 E-after-moves | 125 E-after-moves |
113 (E (run-moves count-frames (repeat steps [])))] | 126 (E (run-moves count-frames (repeat steps [])))] |
114 (println "E:" E-after-moves) | 127 (println "E:" E-after-moves) |
115 (assert (= steps E-after-moves)) | 128 (assert (= steps E-after-moves)) |
116 | 129 |
117 (println "E =" E-after-moves "after" steps "steps") | 130 (println "E =" E-after-moves "after" steps "steps") |
118 count-frames))) | 131 count-frames))) |
119 | 132 |
120 (defn read-user-input [] | 133 (defn read-user-input [] |
121 [0x3E | 134 [0xAF 0x4F 0x47 ;; 0->A; 0->C; 0->B |
135 0xC5 ;; save value of BC | |
136 | |
137 0x3E | |
122 0x20 ; prepare to measure d-pad | 138 0x20 ; prepare to measure d-pad |
123 | 139 |
124 0x01 ;\ | 140 0x01 ;\ |
125 0x01 ; | | 141 0x01 ; | |
126 0xFE ; | load 0xFF00 into BC without repeats | 142 0xFE ; | load 0xFF00 into BC without repeats |
154 0x37 ;; swap A nybbles | 170 0x37 ;; swap A nybbles |
155 | 171 |
156 0xB0 ;; (or A B) -> A | 172 0xB0 ;; (or A B) -> A |
157 | 173 |
158 0x2F ;; (NOT A) -> A | 174 0x2F ;; (NOT A) -> A |
159 | |
160 ]) | 175 ]) |
161 | 176 |
162 (defn test-read-user-input [] | 177 (defn test-read-user-input [] |
163 (let [program | 178 (let [program |
164 (concat | 179 (concat |
165 (frame-metronome) (read-user-input) | 180 (frame-metronome) (read-user-input) |
166 [0x5F ;; A-> E | 181 [0x5F ;; A-> E |
182 0x76 | |
167 0x18 | 183 0x18 |
168 (->signed-8-bit | 184 (->signed-8-bit |
169 (+ (- (count (frame-metronome))) | 185 (+ (- (count (read-user-input))) |
170 (- (count (read-user-input))) | 186 (- 4)))]) |
171 (- 3)))]) | |
172 read-input | 187 read-input |
173 (-> (tick (mid-game)) | 188 (-> (tick (mid-game)) |
174 (IE! 0) | 189 (IE! 0) |
175 (set-memory-range pokemon-list-start program) | 190 (set-memory-range pokemon-list-start program) |
176 (PC! pokemon-list-start))] | 191 (PC! pokemon-list-start))] |
177 (dorun | 192 (dorun |
178 (for [i (range 0x100)] | 193 (for [i (range 0x100)] |
179 (assert (= (E (step read-input (buttons i))) i)))) | 194 (assert (= (E (step read-input (buttons i))) i)))) |
180 (println "Tested all inputs.") | 195 (println "Tested all inputs.") |
181 read-input)) | 196 read-input)) |
182 | 197 |
183 (def symbol-index | 198 (def symbol-index |
184 (fn [symbol sequence] | 199 (fn [symbol sequence] |
206 ;; JUMP 0xE9 ;; jump to (HL) | 221 ;; JUMP 0xE9 ;; jump to (HL) |
207 | 222 |
208 ;; multi-action-modes | 223 ;; multi-action-modes |
209 ;; WRITE 0x47 ;; A->B | 224 ;; WRITE 0x47 ;; A->B |
210 | 225 |
211 (let [[start-high start-low] (disect-bytes-2 start-address) | 226 (let [header (concat (frame-metronome) (read-user-input)) |
212 jump-distance (+ (count (frame-metronome)) | 227 |
213 (count (read-user-input))) | |
214 | |
215 init | |
216 [0xAF 0x4F 0x47] ;; 0->A; 0->C; 0->B | |
217 | |
218 input | 228 input |
219 [0xC1 ;; pop BC so it's not volatile | 229 [0xC1 ;; pop BC so it's not volatile |
220 | 230 |
221 0x5F ;; A->E | 231 0x5F ;; A->E |
222 0xAF ;; test for output-mode (bytes-to-write > 0) | 232 0xAF ;; test for output-mode (bytes-to-write > 0) |
242 :to-be-executed-address | 252 :to-be-executed-address |
243 | 253 |
244 0x7B ;; E->A | 254 0x7B ;; E->A |
245 0x4F ;; A->C now C stores previous instruction | 255 0x4F ;; A->C now C stores previous instruction |
246 0x18 ;; return | 256 0x18 ;; return |
247 :to-beginning-1] | 257 :to-halt] |
248 | 258 |
249 output | 259 output |
250 [:output-start ;; just a label | 260 [:output-start ;; just a label |
251 0x54 ;; | 261 0x54 ;; |
252 0x5D ;; HL->DE \ | 262 0x5D ;; HL->DE \ |
253 ;; | This mess is here to do | 263 ;; | This mess is here to do |
254 0x12 ;; A->(DE) | 0x22 (LDI (HL), A) without | 264 0x12 ;; A->(DE) | 0x22 (LDI (HL), A) without |
255 ;; | any repeating nybbles | 265 ;; | any repeating nybbles |
256 0x23 ;; inc HL / | 266 0x23 ;; inc HL / |
257 | 267 |
258 0x05 ;; DEC bytes-to-write (B) | 268 0x05 ;; DEC bytes-to-write (B) |
259 | 269 |
270 0x76 ;; HALT, peasant! | |
260 0x18 | 271 0x18 |
261 :to-beginning-2] | 272 :to-beginning] |
262 | 273 |
263 symbols | 274 symbols |
264 {:to-be-executed-address | 275 {:to-be-executed-address |
265 (reverse | 276 (reverse |
266 (disect-bytes-2 | 277 (disect-bytes-2 |
267 (+ start-address jump-distance | 278 (+ start-address |
268 (count init) | 279 (count header) |
269 (symbol-index :to-be-executed input)))) | 280 (symbol-index :to-be-executed input)))) |
270 :to-be-executed 0x00} ;; clear carry flag no-op | 281 :to-be-executed 0x00} ;; clear carry flag no-op |
271 | 282 |
272 program** (flatten | 283 program** (flatten |
273 (replace | 284 (replace symbols (concat header input output))) |
274 symbols | 285 |
275 (concat init (frame-metronome) | |
276 (read-user-input) | |
277 input output))) | |
278 resolve-internal-jumps | 286 resolve-internal-jumps |
279 {:output-start [] | 287 {:output-start [] |
280 :to-output | 288 :to-output |
281 (->signed-8-bit | 289 (->signed-8-bit |
282 (dec | 290 (dec |
285 | 293 |
286 program* | 294 program* |
287 (flatten (replace resolve-internal-jumps program**)) | 295 (flatten (replace resolve-internal-jumps program**)) |
288 | 296 |
289 resolve-external-jumps | 297 resolve-external-jumps |
290 {:to-beginning-1 | 298 {:to-halt |
299 (- (- (symbol-index :to-beginning program*) | |
300 (symbol-index :to-halt program*)) 3) | |
301 | |
302 :to-beginning | |
291 (->signed-8-bit | 303 (->signed-8-bit |
292 (+ (count init) | 304 (+ 2 (count (frame-metronome)) |
293 -2 (- (dec (symbol-index :to-beginning-1 program*))))) | 305 (- (symbol-index :to-beginning program*))))} |
294 :to-beginning-2 | |
295 (->signed-8-bit | |
296 (+ (count init) | |
297 -2 (- (dec (symbol-index :to-beginning-2 program*)))))} | |
298 | 306 |
299 program | 307 program |
300 (replace resolve-external-jumps program*)] | 308 (replace resolve-external-jumps program*)] |
301 program))) | 309 program))) |
302 | 310 |