diff options
Diffstat (limited to 'apps/plugins/rockboy/cpu.c')
-rw-r--r-- | apps/plugins/rockboy/cpu.c | 880 |
1 files changed, 880 insertions, 0 deletions
diff --git a/apps/plugins/rockboy/cpu.c b/apps/plugins/rockboy/cpu.c new file mode 100644 index 0000000000..44a870a6eb --- /dev/null +++ b/apps/plugins/rockboy/cpu.c | |||
@@ -0,0 +1,880 @@ | |||
1 | |||
2 | |||
3 | |||
4 | #include "rockmacros.h" | ||
5 | #include "defs.h" | ||
6 | #include "regs.h" | ||
7 | #include "hw.h" | ||
8 | #include "cpu.h" | ||
9 | #include "lcdc.h" | ||
10 | #include "mem.h" | ||
11 | #include "fastmem.h" | ||
12 | #include "cpuregs.h" | ||
13 | #include "cpucore.h" | ||
14 | |||
15 | #ifdef USE_ASM | ||
16 | #include "asm.h" | ||
17 | #endif | ||
18 | |||
19 | |||
20 | struct cpu cpu; | ||
21 | |||
22 | |||
23 | |||
24 | |||
25 | #define ZFLAG(n) ( (n) ? 0 : FZ ) | ||
26 | |||
27 | |||
28 | #define PUSH(w) ( (SP -= 2), (writew(xSP, (w))) ) | ||
29 | #define POP(w) ( ((w) = readw(xSP)), (SP += 2) ) | ||
30 | |||
31 | |||
32 | #define FETCH_OLD ( mbc.rmap[PC>>12] \ | ||
33 | ? mbc.rmap[PC>>12][PC++] \ | ||
34 | : mem_read(PC++) ) | ||
35 | |||
36 | #define FETCH (readb(PC++)) | ||
37 | |||
38 | |||
39 | #define INC(r) { ((r)++); \ | ||
40 | F = (F & (FL|FC)) | incflag_table[(r)]; } | ||
41 | |||
42 | #define DEC(r) { ((r)--); \ | ||
43 | F = (F & (FL|FC)) | decflag_table[(r)]; } | ||
44 | |||
45 | #define INCW(r) ( (r)++ ) | ||
46 | |||
47 | #define DECW(r) ( (r)-- ) | ||
48 | |||
49 | #define ADD(n) { \ | ||
50 | W(acc) = (un16)A + (un16)(n); \ | ||
51 | F = (ZFLAG(LB(acc))) \ | ||
52 | | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ | ||
53 | | (HB(acc) << 4); \ | ||
54 | A = LB(acc); } | ||
55 | |||
56 | #define ADC(n) { \ | ||
57 | W(acc) = (un16)A + (un16)(n) + (un16)((F&FC)>>4); \ | ||
58 | F = (ZFLAG(LB(acc))) \ | ||
59 | | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ | ||
60 | | (HB(acc) << 4); \ | ||
61 | A = LB(acc); } | ||
62 | |||
63 | #define ADDW(n) { \ | ||
64 | DW(acc) = (un32)HL + (un32)(n); \ | ||
65 | F = (F & (FZ)) \ | ||
66 | | (FH & ((H ^ ((n)>>8) ^ HB(acc)) << 1)) \ | ||
67 | | (acc.b[HI][LO] << 4); \ | ||
68 | HL = W(acc); } | ||
69 | |||
70 | #define ADDSP(n) { \ | ||
71 | DW(acc) = (un32)SP + (un32)(n8)(n); \ | ||
72 | F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \ | ||
73 | | (acc.b[HI][LO] << 4); \ | ||
74 | SP = W(acc); } | ||
75 | |||
76 | #define LDHLSP(n) { \ | ||
77 | DW(acc) = (un32)SP + (un32)(n8)(n); \ | ||
78 | F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \ | ||
79 | | (acc.b[HI][LO] << 4); \ | ||
80 | HL = W(acc); } | ||
81 | |||
82 | #define CP(n) { \ | ||
83 | W(acc) = (un16)A - (un16)(n); \ | ||
84 | F = FN \ | ||
85 | | (ZFLAG(LB(acc))) \ | ||
86 | | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ | ||
87 | | ((un8)(-(n8)HB(acc)) << 4); } | ||
88 | |||
89 | #define SUB(n) { CP((n)); A = LB(acc); } | ||
90 | |||
91 | #define SBC(n) { \ | ||
92 | W(acc) = (un16)A - (un16)(n) - (un16)((F&FC)>>4); \ | ||
93 | F = FN \ | ||
94 | | (ZFLAG((n8)LB(acc))) \ | ||
95 | | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \ | ||
96 | | ((un8)(-(n8)HB(acc)) << 4); \ | ||
97 | A = LB(acc); } | ||
98 | |||
99 | #define AND(n) { A &= (n); \ | ||
100 | F = ZFLAG(A) | FH; } | ||
101 | |||
102 | #define XOR(n) { A ^= (n); \ | ||
103 | F = ZFLAG(A); } | ||
104 | |||
105 | #define OR(n) { A |= (n); \ | ||
106 | F = ZFLAG(A); } | ||
107 | |||
108 | #define RLCA(r) { (r) = ((r)>>7) | ((r)<<1); \ | ||
109 | F = (((r)&0x01)<<4); } | ||
110 | |||
111 | #define RRCA(r) { (r) = ((r)<<7) | ((r)>>1); \ | ||
112 | F = (((r)&0x80)>>3); } | ||
113 | |||
114 | #define RLA(r) { \ | ||
115 | LB(acc) = (((r)&0x80)>>3); \ | ||
116 | (r) = ((r)<<1) | ((F&FC)>>4); \ | ||
117 | F = LB(acc); } | ||
118 | |||
119 | #define RRA(r) { \ | ||
120 | LB(acc) = (((r)&0x01)<<4); \ | ||
121 | (r) = ((r)>>1) | ((F&FC)<<3); \ | ||
122 | F = LB(acc); } | ||
123 | |||
124 | #define RLC(r) { RLCA(r); F |= ZFLAG(r); } | ||
125 | #define RRC(r) { RRCA(r); F |= ZFLAG(r); } | ||
126 | #define RL(r) { RLA(r); F |= ZFLAG(r); } | ||
127 | #define RR(r) { RRA(r); F |= ZFLAG(r); } | ||
128 | |||
129 | #define SLA(r) { \ | ||
130 | LB(acc) = (((r)&0x80)>>3); \ | ||
131 | (r) <<= 1; \ | ||
132 | F = ZFLAG((r)) | LB(acc); } | ||
133 | |||
134 | #define SRA(r) { \ | ||
135 | LB(acc) = (((r)&0x01)<<4); \ | ||
136 | (r) = (un8)(((n8)(r))>>1); \ | ||
137 | F = ZFLAG((r)) | LB(acc); } | ||
138 | |||
139 | #define SRL(r) { \ | ||
140 | LB(acc) = (((r)&0x01)<<4); \ | ||
141 | (r) >>= 1; \ | ||
142 | F = ZFLAG((r)) | LB(acc); } | ||
143 | |||
144 | #define CPL(r) { \ | ||
145 | (r) = ~(r); \ | ||
146 | F |= (FH|FN); } | ||
147 | |||
148 | #define SCF { F = (F & (FZ)) | FC; } | ||
149 | |||
150 | #define CCF { F = (F & (FZ|FC)) ^ FC; } | ||
151 | |||
152 | #define DAA { \ | ||
153 | A += (LB(acc) = daa_table[((((int)F)&0x70)<<4) | A]); \ | ||
154 | F = (F & (FN)) | ZFLAG(A) | daa_carry_table[LB(acc)>>2]; } | ||
155 | |||
156 | #define SWAP(r) { \ | ||
157 | (r) = swap_table[(r)]; \ | ||
158 | F = ZFLAG((r)); } | ||
159 | |||
160 | #define BIT(n,r) { F = (F & FC) | ZFLAG(((r) & (1 << (n)))) | FH; } | ||
161 | #define RES(n,r) { (r) &= ~(1 << (n)); } | ||
162 | #define SET(n,r) { (r) |= (1 << (n)); } | ||
163 | |||
164 | #define CB_REG_CASES(r, n) \ | ||
165 | case 0x00|(n): RLC(r); break; \ | ||
166 | case 0x08|(n): RRC(r); break; \ | ||
167 | case 0x10|(n): RL(r); break; \ | ||
168 | case 0x18|(n): RR(r); break; \ | ||
169 | case 0x20|(n): SLA(r); break; \ | ||
170 | case 0x28|(n): SRA(r); break; \ | ||
171 | case 0x30|(n): SWAP(r); break; \ | ||
172 | case 0x38|(n): SRL(r); break; \ | ||
173 | case 0x40|(n): BIT(0, r); break; \ | ||
174 | case 0x48|(n): BIT(1, r); break; \ | ||
175 | case 0x50|(n): BIT(2, r); break; \ | ||
176 | case 0x58|(n): BIT(3, r); break; \ | ||
177 | case 0x60|(n): BIT(4, r); break; \ | ||
178 | case 0x68|(n): BIT(5, r); break; \ | ||
179 | case 0x70|(n): BIT(6, r); break; \ | ||
180 | case 0x78|(n): BIT(7, r); break; \ | ||
181 | case 0x80|(n): RES(0, r); break; \ | ||
182 | case 0x88|(n): RES(1, r); break; \ | ||
183 | case 0x90|(n): RES(2, r); break; \ | ||
184 | case 0x98|(n): RES(3, r); break; \ | ||
185 | case 0xA0|(n): RES(4, r); break; \ | ||
186 | case 0xA8|(n): RES(5, r); break; \ | ||
187 | case 0xB0|(n): RES(6, r); break; \ | ||
188 | case 0xB8|(n): RES(7, r); break; \ | ||
189 | case 0xC0|(n): SET(0, r); break; \ | ||
190 | case 0xC8|(n): SET(1, r); break; \ | ||
191 | case 0xD0|(n): SET(2, r); break; \ | ||
192 | case 0xD8|(n): SET(3, r); break; \ | ||
193 | case 0xE0|(n): SET(4, r); break; \ | ||
194 | case 0xE8|(n): SET(5, r); break; \ | ||
195 | case 0xF0|(n): SET(6, r); break; \ | ||
196 | case 0xF8|(n): SET(7, r); break; | ||
197 | |||
198 | |||
199 | #define ALU_CASES(base, imm, op, label) \ | ||
200 | case (imm): b = FETCH; goto label; \ | ||
201 | case (base): b = B; goto label; \ | ||
202 | case (base)+1: b = C; goto label; \ | ||
203 | case (base)+2: b = D; goto label; \ | ||
204 | case (base)+3: b = E; goto label; \ | ||
205 | case (base)+4: b = H; goto label; \ | ||
206 | case (base)+5: b = L; goto label; \ | ||
207 | case (base)+6: b = readb(HL); goto label; \ | ||
208 | case (base)+7: b = A; \ | ||
209 | label: op(b); break; | ||
210 | |||
211 | |||
212 | |||
213 | |||
214 | |||
215 | |||
216 | |||
217 | |||
218 | #define JR ( PC += 1+(n8)readb(PC) ) | ||
219 | #define JP ( PC = readw(PC) ) | ||
220 | |||
221 | #define CALL ( PUSH(PC+2), JP ) | ||
222 | |||
223 | #define NOJR ( clen--, PC++ ) | ||
224 | #define NOJP ( clen--, PC+=2 ) | ||
225 | #define NOCALL ( clen-=3, PC+=2 ) | ||
226 | #define NORET ( clen-=3 ) | ||
227 | |||
228 | #define RST(n) { PUSH(PC); PC = (n); } | ||
229 | |||
230 | #define RET ( POP(PC) ) | ||
231 | |||
232 | #define EI ( IMA = 1 ) | ||
233 | #define DI ( cpu.halt = IMA = IME = 0 ) | ||
234 | |||
235 | |||
236 | |||
237 | #define PRE_INT ( DI, PUSH(PC) ) | ||
238 | #define THROW_INT(n) ( (IF &= ~(1<<(n))), (PC = 0x40+((n)<<3)) ) | ||
239 | |||
240 | |||
241 | |||
242 | |||
243 | void cpu_reset(void) | ||
244 | { | ||
245 | cpu.speed = 0; | ||
246 | cpu.halt = 0; | ||
247 | cpu.div = 0; | ||
248 | cpu.tim = 0; | ||
249 | cpu.lcdc = 40; | ||
250 | |||
251 | IME = 0; | ||
252 | IMA = 0; | ||
253 | |||
254 | PC = 0x0100; | ||
255 | SP = 0xFFFE; | ||
256 | AF = 0x01B0; | ||
257 | BC = 0x0013; | ||
258 | DE = 0x00D8; | ||
259 | HL = 0x014D; | ||
260 | |||
261 | if (hw.cgb) A = 0x11; | ||
262 | if (hw.gba) B = 0x01; | ||
263 | } | ||
264 | |||
265 | |||
266 | void div_advance(int cnt) | ||
267 | { | ||
268 | cpu.div += (cnt<<1); | ||
269 | if (cpu.div >= 256) | ||
270 | { | ||
271 | R_DIV += (cpu.div >> 8); | ||
272 | cpu.div &= 0xff; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | void timer_advance(int cnt) | ||
277 | { | ||
278 | int unit, tima; | ||
279 | |||
280 | if (!(R_TAC & 0x04)) return; | ||
281 | |||
282 | unit = ((-R_TAC) & 3) << 1; | ||
283 | cpu.tim += (cnt<<unit); | ||
284 | |||
285 | if (cpu.tim >= 512) | ||
286 | { | ||
287 | tima = R_TIMA + (cpu.tim >> 9); | ||
288 | cpu.tim &= 0x1ff; | ||
289 | if (tima >= 256) | ||
290 | { | ||
291 | hw_interrupt(IF_TIMER, IF_TIMER); | ||
292 | hw_interrupt(0, IF_TIMER); | ||
293 | } | ||
294 | while (tima >= 256) | ||
295 | tima = tima - 256 + R_TMA; | ||
296 | R_TIMA = tima; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | void lcdc_advance(int cnt) | ||
301 | { | ||
302 | cpu.lcdc -= cnt; | ||
303 | if (cpu.lcdc <= 0) lcdc_trans(); | ||
304 | } | ||
305 | |||
306 | void sound_advance(int cnt) | ||
307 | { | ||
308 | cpu.snd += cnt; | ||
309 | } | ||
310 | |||
311 | void cpu_timers(int cnt) | ||
312 | { | ||
313 | div_advance(cnt << cpu.speed); | ||
314 | timer_advance(cnt << cpu.speed); | ||
315 | lcdc_advance(cnt); | ||
316 | sound_advance(cnt); | ||
317 | } | ||
318 | |||
319 | int cpu_idle(int max) | ||
320 | { | ||
321 | int cnt, unit; | ||
322 | |||
323 | if (!(cpu.halt && IME)) return 0; | ||
324 | if (R_IF & R_IE) | ||
325 | { | ||
326 | cpu.halt = 0; | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /* Make sure we don't miss lcdc status events! */ | ||
331 | if ((R_IE & (IF_VBLANK | IF_STAT)) && (max > cpu.lcdc)) | ||
332 | max = cpu.lcdc; | ||
333 | |||
334 | /* If timer interrupt cannot happen, this is very simple! */ | ||
335 | if (!((R_IE & IF_TIMER) && (R_TAC & 0x04))) | ||
336 | { | ||
337 | cpu_timers(max); | ||
338 | return max; | ||
339 | } | ||
340 | |||
341 | /* Figure out when the next timer interrupt will happen */ | ||
342 | unit = ((-R_TAC) & 3) << 1; | ||
343 | cnt = (511 - cpu.tim + (1<<unit)) >> unit; | ||
344 | cnt += (255 - R_TIMA) << (9 - unit); | ||
345 | |||
346 | if (max < cnt) | ||
347 | cnt = max; | ||
348 | |||
349 | cpu_timers(cnt); | ||
350 | return cnt; | ||
351 | } | ||
352 | |||
353 | #ifndef ASM_CPU_EMULATE | ||
354 | |||
355 | extern int debug_trace; | ||
356 | |||
357 | int cpu_emulate(int cycles) | ||
358 | { | ||
359 | int i; | ||
360 | byte op, cbop; | ||
361 | int clen; | ||
362 | static union reg acc; | ||
363 | static byte b; | ||
364 | static word w; | ||
365 | |||
366 | i = cycles; | ||
367 | next: | ||
368 | if ((clen = cpu_idle(i))) | ||
369 | { | ||
370 | i -= clen; | ||
371 | if (i > 0) goto next; | ||
372 | return cycles-i; | ||
373 | } | ||
374 | |||
375 | if (IME && (IF & IE)) | ||
376 | { | ||
377 | PRE_INT; | ||
378 | switch ((byte)(IF & IE)) | ||
379 | { | ||
380 | case 0x01: case 0x03: case 0x05: case 0x07: | ||
381 | case 0x09: case 0x0B: case 0x0D: case 0x0F: | ||
382 | case 0x11: case 0x13: case 0x15: case 0x17: | ||
383 | case 0x19: case 0x1B: case 0x1D: case 0x1F: | ||
384 | THROW_INT(0); break; | ||
385 | case 0x02: case 0x06: case 0x0A: case 0x0E: | ||
386 | case 0x12: case 0x16: case 0x1A: case 0x1E: | ||
387 | THROW_INT(1); break; | ||
388 | case 0x04: case 0x0C: case 0x14: case 0x1C: | ||
389 | THROW_INT(2); break; | ||
390 | case 0x08: case 0x18: | ||
391 | THROW_INT(3); break; | ||
392 | case 0x10: | ||
393 | THROW_INT(4); break; | ||
394 | } | ||
395 | } | ||
396 | IME = IMA; | ||
397 | |||
398 | // if (debug_trace) debug_disassemble(PC, 1); | ||
399 | |||
400 | op = FETCH; | ||
401 | clen = cycles_table[op]; | ||
402 | |||
403 | switch(op) | ||
404 | { | ||
405 | case 0x00: /* NOP */ | ||
406 | case 0x40: /* LD B,B */ | ||
407 | case 0x49: /* LD C,C */ | ||
408 | case 0x52: /* LD D,D */ | ||
409 | case 0x5B: /* LD E,E */ | ||
410 | case 0x64: /* LD H,H */ | ||
411 | case 0x6D: /* LD L,L */ | ||
412 | case 0x7F: /* LD A,A */ | ||
413 | break; | ||
414 | |||
415 | case 0x41: /* LD B,C */ | ||
416 | B = C; break; | ||
417 | case 0x42: /* LD B,D */ | ||
418 | B = D; break; | ||
419 | case 0x43: /* LD B,E */ | ||
420 | B = E; break; | ||
421 | case 0x44: /* LD B,H */ | ||
422 | B = H; break; | ||
423 | case 0x45: /* LD B,L */ | ||
424 | B = L; break; | ||
425 | case 0x46: /* LD B,(HL) */ | ||
426 | B = readb(xHL); break; | ||
427 | case 0x47: /* LD B,A */ | ||
428 | B = A; break; | ||
429 | |||
430 | case 0x48: /* LD C,B */ | ||
431 | C = B; break; | ||
432 | case 0x4A: /* LD C,D */ | ||
433 | C = D; break; | ||
434 | case 0x4B: /* LD C,E */ | ||
435 | C = E; break; | ||
436 | case 0x4C: /* LD C,H */ | ||
437 | C = H; break; | ||
438 | case 0x4D: /* LD C,L */ | ||
439 | C = L; break; | ||
440 | case 0x4E: /* LD C,(HL) */ | ||
441 | C = readb(xHL); break; | ||
442 | case 0x4F: /* LD C,A */ | ||
443 | C = A; break; | ||
444 | |||
445 | case 0x50: /* LD D,B */ | ||
446 | D = B; break; | ||
447 | case 0x51: /* LD D,C */ | ||
448 | D = C; break; | ||
449 | case 0x53: /* LD D,E */ | ||
450 | D = E; break; | ||
451 | case 0x54: /* LD D,H */ | ||
452 | D = H; break; | ||
453 | case 0x55: /* LD D,L */ | ||
454 | D = L; break; | ||
455 | case 0x56: /* LD D,(HL) */ | ||
456 | D = readb(xHL); break; | ||
457 | case 0x57: /* LD D,A */ | ||
458 | D = A; break; | ||
459 | |||
460 | case 0x58: /* LD E,B */ | ||
461 | E = B; break; | ||
462 | case 0x59: /* LD E,C */ | ||
463 | E = C; break; | ||
464 | case 0x5A: /* LD E,D */ | ||
465 | E = D; break; | ||
466 | case 0x5C: /* LD E,H */ | ||
467 | E = H; break; | ||
468 | case 0x5D: /* LD E,L */ | ||
469 | E = L; break; | ||
470 | case 0x5E: /* LD E,(HL) */ | ||
471 | E = readb(xHL); break; | ||
472 | case 0x5F: /* LD E,A */ | ||
473 | E = A; break; | ||
474 | |||
475 | case 0x60: /* LD H,B */ | ||
476 | H = B; break; | ||
477 | case 0x61: /* LD H,C */ | ||
478 | H = C; break; | ||
479 | case 0x62: /* LD H,D */ | ||
480 | H = D; break; | ||
481 | case 0x63: /* LD H,E */ | ||
482 | H = E; break; | ||
483 | case 0x65: /* LD H,L */ | ||
484 | H = L; break; | ||
485 | case 0x66: /* LD H,(HL) */ | ||
486 | H = readb(xHL); break; | ||
487 | case 0x67: /* LD H,A */ | ||
488 | H = A; break; | ||
489 | |||
490 | case 0x68: /* LD L,B */ | ||
491 | L = B; break; | ||
492 | case 0x69: /* LD L,C */ | ||
493 | L = C; break; | ||
494 | case 0x6A: /* LD L,D */ | ||
495 | L = D; break; | ||
496 | case 0x6B: /* LD L,E */ | ||
497 | L = E; break; | ||
498 | case 0x6C: /* LD L,H */ | ||
499 | L = H; break; | ||
500 | case 0x6E: /* LD L,(HL) */ | ||
501 | L = readb(xHL); break; | ||
502 | case 0x6F: /* LD L,A */ | ||
503 | L = A; break; | ||
504 | |||
505 | case 0x70: /* LD (HL),B */ | ||
506 | b = B; goto __LD_HL; | ||
507 | case 0x71: /* LD (HL),C */ | ||
508 | b = C; goto __LD_HL; | ||
509 | case 0x72: /* LD (HL),D */ | ||
510 | b = D; goto __LD_HL; | ||
511 | case 0x73: /* LD (HL),E */ | ||
512 | b = E; goto __LD_HL; | ||
513 | case 0x74: /* LD (HL),H */ | ||
514 | b = H; goto __LD_HL; | ||
515 | case 0x75: /* LD (HL),L */ | ||
516 | b = L; goto __LD_HL; | ||
517 | case 0x77: /* LD (HL),A */ | ||
518 | b = A; | ||
519 | __LD_HL: | ||
520 | writeb(xHL,b); | ||
521 | break; | ||
522 | |||
523 | case 0x78: /* LD A,B */ | ||
524 | A = B; break; | ||
525 | case 0x79: /* LD A,C */ | ||
526 | A = C; break; | ||
527 | case 0x7A: /* LD A,D */ | ||
528 | A = D; break; | ||
529 | case 0x7B: /* LD A,E */ | ||
530 | A = E; break; | ||
531 | case 0x7C: /* LD A,H */ | ||
532 | A = H; break; | ||
533 | case 0x7D: /* LD A,L */ | ||
534 | A = L; break; | ||
535 | case 0x7E: /* LD A,(HL) */ | ||
536 | A = readb(xHL); break; | ||
537 | |||
538 | case 0x01: /* LD BC,imm */ | ||
539 | BC = readw(xPC); PC += 2; break; | ||
540 | case 0x11: /* LD DE,imm */ | ||
541 | DE = readw(xPC); PC += 2; break; | ||
542 | case 0x21: /* LD HL,imm */ | ||
543 | HL = readw(xPC); PC += 2; break; | ||
544 | case 0x31: /* LD SP,imm */ | ||
545 | SP = readw(xPC); PC += 2; break; | ||
546 | |||
547 | case 0x02: /* LD (BC),A */ | ||
548 | writeb(xBC, A); break; | ||
549 | case 0x0A: /* LD A,(BC) */ | ||
550 | A = readb(xBC); break; | ||
551 | case 0x12: /* LD (DE),A */ | ||
552 | writeb(xDE, A); break; | ||
553 | case 0x1A: /* LD A,(DE) */ | ||
554 | A = readb(xDE); break; | ||
555 | |||
556 | case 0x22: /* LDI (HL),A */ | ||
557 | writeb(xHL, A); HL++; break; | ||
558 | case 0x2A: /* LDI A,(HL) */ | ||
559 | A = readb(xHL); HL++; break; | ||
560 | case 0x32: /* LDD (HL),A */ | ||
561 | writeb(xHL, A); HL--; break; | ||
562 | case 0x3A: /* LDD A,(HL) */ | ||
563 | A = readb(xHL); HL--; break; | ||
564 | |||
565 | case 0x06: /* LD B,imm */ | ||
566 | B = FETCH; break; | ||
567 | case 0x0E: /* LD C,imm */ | ||
568 | C = FETCH; break; | ||
569 | case 0x16: /* LD D,imm */ | ||
570 | D = FETCH; break; | ||
571 | case 0x1E: /* LD E,imm */ | ||
572 | E = FETCH; break; | ||
573 | case 0x26: /* LD H,imm */ | ||
574 | H = FETCH; break; | ||
575 | case 0x2E: /* LD L,imm */ | ||
576 | L = FETCH; break; | ||
577 | case 0x36: /* LD (HL),imm */ | ||
578 | b = FETCH; writeb(xHL, b); break; | ||
579 | case 0x3E: /* LD A,imm */ | ||
580 | A = FETCH; break; | ||
581 | |||
582 | case 0x08: /* LD (imm),SP */ | ||
583 | writew(readw(xPC), SP); PC += 2; break; | ||
584 | case 0xEA: /* LD (imm),A */ | ||
585 | writeb(readw(xPC), A); PC += 2; break; | ||
586 | |||
587 | case 0xE0: /* LDH (imm),A */ | ||
588 | writehi(FETCH, A); break; | ||
589 | case 0xE2: /* LDH (C),A */ | ||
590 | writehi(C, A); break; | ||
591 | case 0xF0: /* LDH A,(imm) */ | ||
592 | A = readhi(FETCH); break; | ||
593 | case 0xF2: /* LDH A,(C) (undocumented) */ | ||
594 | A = readhi(C); break; | ||
595 | |||
596 | |||
597 | case 0xF8: /* LD HL,SP+imm */ | ||
598 | b = FETCH; LDHLSP(b); break; | ||
599 | case 0xF9: /* LD SP,HL */ | ||
600 | SP = HL; break; | ||
601 | case 0xFA: /* LD A,(imm) */ | ||
602 | A = readb(readw(xPC)); PC += 2; break; | ||
603 | |||
604 | ALU_CASES(0x80, 0xC6, ADD, __ADD) | ||
605 | ALU_CASES(0x88, 0xCE, ADC, __ADC) | ||
606 | ALU_CASES(0x90, 0xD6, SUB, __SUB) | ||
607 | ALU_CASES(0x98, 0xDE, SBC, __SBC) | ||
608 | ALU_CASES(0xA0, 0xE6, AND, __AND) | ||
609 | ALU_CASES(0xA8, 0xEE, XOR, __XOR) | ||
610 | ALU_CASES(0xB0, 0xF6, OR, __OR) | ||
611 | ALU_CASES(0xB8, 0xFE, CP, __CP) | ||
612 | |||
613 | case 0x09: /* ADD HL,BC */ | ||
614 | w = BC; goto __ADDW; | ||
615 | case 0x19: /* ADD HL,DE */ | ||
616 | w = DE; goto __ADDW; | ||
617 | case 0x39: /* ADD HL,SP */ | ||
618 | w = SP; goto __ADDW; | ||
619 | case 0x29: /* ADD HL,HL */ | ||
620 | w = HL; | ||
621 | __ADDW: | ||
622 | ADDW(w); | ||
623 | break; | ||
624 | |||
625 | case 0x04: /* INC B */ | ||
626 | INC(B); break; | ||
627 | case 0x0C: /* INC C */ | ||
628 | INC(C); break; | ||
629 | case 0x14: /* INC D */ | ||
630 | INC(D); break; | ||
631 | case 0x1C: /* INC E */ | ||
632 | INC(E); break; | ||
633 | case 0x24: /* INC H */ | ||
634 | INC(H); break; | ||
635 | case 0x2C: /* INC L */ | ||
636 | INC(L); break; | ||
637 | case 0x34: /* INC (HL) */ | ||
638 | b = readb(xHL); | ||
639 | INC(b); | ||
640 | writeb(xHL, b); | ||
641 | break; | ||
642 | case 0x3C: /* INC A */ | ||
643 | INC(A); break; | ||
644 | |||
645 | case 0x03: /* INC BC */ | ||
646 | INCW(BC); break; | ||
647 | case 0x13: /* INC DE */ | ||
648 | INCW(DE); break; | ||
649 | case 0x23: /* INC HL */ | ||
650 | INCW(HL); break; | ||
651 | case 0x33: /* INC SP */ | ||
652 | INCW(SP); break; | ||
653 | |||
654 | case 0x05: /* DEC B */ | ||
655 | DEC(B); break; | ||
656 | case 0x0D: /* DEC C */ | ||
657 | DEC(C); break; | ||
658 | case 0x15: /* DEC D */ | ||
659 | DEC(D); break; | ||
660 | case 0x1D: /* DEC E */ | ||
661 | DEC(E); break; | ||
662 | case 0x25: /* DEC H */ | ||
663 | DEC(H); break; | ||
664 | case 0x2D: /* DEC L */ | ||
665 | DEC(L); break; | ||
666 | case 0x35: /* DEC (HL) */ | ||
667 | b = readb(xHL); | ||
668 | DEC(b); | ||
669 | writeb(xHL, b); | ||
670 | break; | ||
671 | case 0x3D: /* DEC A */ | ||
672 | DEC(A); break; | ||
673 | |||
674 | case 0x0B: /* DEC BC */ | ||
675 | DECW(BC); break; | ||
676 | case 0x1B: /* DEC DE */ | ||
677 | DECW(DE); break; | ||
678 | case 0x2B: /* DEC HL */ | ||
679 | DECW(HL); break; | ||
680 | case 0x3B: /* DEC SP */ | ||
681 | DECW(SP); break; | ||
682 | |||
683 | case 0x07: /* RLCA */ | ||
684 | RLCA(A); break; | ||
685 | case 0x0F: /* RRCA */ | ||
686 | RRCA(A); break; | ||
687 | case 0x17: /* RLA */ | ||
688 | RLA(A); break; | ||
689 | case 0x1F: /* RRA */ | ||
690 | RRA(A); break; | ||
691 | |||
692 | case 0x27: /* DAA */ | ||
693 | DAA; break; | ||
694 | case 0x2F: /* CPL */ | ||
695 | CPL(A); break; | ||
696 | |||
697 | case 0x18: /* JR */ | ||
698 | __JR: | ||
699 | JR; break; | ||
700 | case 0x20: /* JR NZ */ | ||
701 | if (!(F&FZ)) goto __JR; NOJR; break; | ||
702 | case 0x28: /* JR Z */ | ||
703 | if (F&FZ) goto __JR; NOJR; break; | ||
704 | case 0x30: /* JR NC */ | ||
705 | if (!(F&FC)) goto __JR; NOJR; break; | ||
706 | case 0x38: /* JR C */ | ||
707 | if (F&FC) goto __JR; NOJR; break; | ||
708 | |||
709 | case 0xC3: /* JP */ | ||
710 | __JP: | ||
711 | JP; break; | ||
712 | case 0xC2: /* JP NZ */ | ||
713 | if (!(F&FZ)) goto __JP; NOJP; break; | ||
714 | case 0xCA: /* JP Z */ | ||
715 | if (F&FZ) goto __JP; NOJP; break; | ||
716 | case 0xD2: /* JP NC */ | ||
717 | if (!(F&FC)) goto __JP; NOJP; break; | ||
718 | case 0xDA: /* JP C */ | ||
719 | if (F&FC) goto __JP; NOJP; break; | ||
720 | case 0xE9: /* JP HL */ | ||
721 | PC = HL; break; | ||
722 | |||
723 | case 0xC9: /* RET */ | ||
724 | __RET: | ||
725 | RET; break; | ||
726 | case 0xC0: /* RET NZ */ | ||
727 | if (!(F&FZ)) goto __RET; NORET; break; | ||
728 | case 0xC8: /* RET Z */ | ||
729 | if (F&FZ) goto __RET; NORET; break; | ||
730 | case 0xD0: /* RET NC */ | ||
731 | if (!(F&FC)) goto __RET; NORET; break; | ||
732 | case 0xD8: /* RET C */ | ||
733 | if (F&FC) goto __RET; NORET; break; | ||
734 | case 0xD9: /* RETI */ | ||
735 | IME = IMA = 1; goto __RET; | ||
736 | |||
737 | case 0xCD: /* CALL */ | ||
738 | __CALL: | ||
739 | CALL; break; | ||
740 | case 0xC4: /* CALL NZ */ | ||
741 | if (!(F&FZ)) goto __CALL; NOCALL; break; | ||
742 | case 0xCC: /* CALL Z */ | ||
743 | if (F&FZ) goto __CALL; NOCALL; break; | ||
744 | case 0xD4: /* CALL NC */ | ||
745 | if (!(F&FC)) goto __CALL; NOCALL; break; | ||
746 | case 0xDC: /* CALL C */ | ||
747 | if (F&FC) goto __CALL; NOCALL; break; | ||
748 | |||
749 | case 0xC7: /* RST 0 */ | ||
750 | b = 0x00; goto __RST; | ||
751 | case 0xCF: /* RST 8 */ | ||
752 | b = 0x08; goto __RST; | ||
753 | case 0xD7: /* RST 10 */ | ||
754 | b = 0x10; goto __RST; | ||
755 | case 0xDF: /* RST 18 */ | ||
756 | b = 0x18; goto __RST; | ||
757 | case 0xE7: /* RST 20 */ | ||
758 | b = 0x20; goto __RST; | ||
759 | case 0xEF: /* RST 28 */ | ||
760 | b = 0x28; goto __RST; | ||
761 | case 0xF7: /* RST 30 */ | ||
762 | b = 0x30; goto __RST; | ||
763 | case 0xFF: /* RST 38 */ | ||
764 | b = 0x38; | ||
765 | __RST: | ||
766 | RST(b); break; | ||
767 | |||
768 | case 0xC1: /* POP BC */ | ||
769 | POP(BC); break; | ||
770 | case 0xC5: /* PUSH BC */ | ||
771 | PUSH(BC); break; | ||
772 | case 0xD1: /* POP DE */ | ||
773 | POP(DE); break; | ||
774 | case 0xD5: /* PUSH DE */ | ||
775 | PUSH(DE); break; | ||
776 | case 0xE1: /* POP HL */ | ||
777 | POP(HL); break; | ||
778 | case 0xE5: /* PUSH HL */ | ||
779 | PUSH(HL); break; | ||
780 | case 0xF1: /* POP AF */ | ||
781 | POP(AF); break; | ||
782 | case 0xF5: /* PUSH AF */ | ||
783 | PUSH(AF); break; | ||
784 | |||
785 | case 0xE8: /* ADD SP,imm */ | ||
786 | b = FETCH; ADDSP(b); break; | ||
787 | |||
788 | case 0xF3: /* DI */ | ||
789 | DI; break; | ||
790 | case 0xFB: /* EI */ | ||
791 | EI; break; | ||
792 | |||
793 | case 0x37: /* SCF */ | ||
794 | SCF; break; | ||
795 | case 0x3F: /* CCF */ | ||
796 | CCF; break; | ||
797 | |||
798 | case 0x10: /* STOP */ | ||
799 | PC++; | ||
800 | if (R_KEY1 & 1) | ||
801 | { | ||
802 | cpu.speed = cpu.speed ^ 1; | ||
803 | R_KEY1 = (R_KEY1 & 0x7E) | (cpu.speed << 7); | ||
804 | break; | ||
805 | } | ||
806 | /* NOTE - we do not implement dmg STOP whatsoever */ | ||
807 | break; | ||
808 | |||
809 | case 0x76: /* HALT */ | ||
810 | cpu.halt = 1; | ||
811 | break; | ||
812 | |||
813 | case 0xCB: /* CB prefix */ | ||
814 | cbop = FETCH; | ||
815 | clen = cb_cycles_table[cbop]; | ||
816 | switch (cbop) | ||
817 | { | ||
818 | CB_REG_CASES(B, 0); | ||
819 | CB_REG_CASES(C, 1); | ||
820 | CB_REG_CASES(D, 2); | ||
821 | CB_REG_CASES(E, 3); | ||
822 | CB_REG_CASES(H, 4); | ||
823 | CB_REG_CASES(L, 5); | ||
824 | CB_REG_CASES(A, 7); | ||
825 | default: | ||
826 | b = readb(xHL); | ||
827 | switch(cbop) | ||
828 | { | ||
829 | CB_REG_CASES(b, 6); | ||
830 | } | ||
831 | if ((cbop & 0xC0) != 0x40) /* exclude BIT */ | ||
832 | writeb(xHL, b); | ||
833 | break; | ||
834 | } | ||
835 | break; | ||
836 | |||
837 | default: | ||
838 | die( | ||
839 | "invalid opcode 0x%02X at address 0x%04X, rombank = %d\n", | ||
840 | op, (PC-1) & 0xffff, mbc.rombank); | ||
841 | break; | ||
842 | } | ||
843 | |||
844 | clen <<= 1; | ||
845 | div_advance(clen); | ||
846 | timer_advance(clen); | ||
847 | clen >>= cpu.speed; | ||
848 | lcdc_advance(clen); | ||
849 | sound_advance(clen); | ||
850 | |||
851 | i -= clen; | ||
852 | if (i > 0) goto next; | ||
853 | return cycles-i; | ||
854 | } | ||
855 | |||
856 | #endif /* ASM_CPU_EMULATE */ | ||
857 | |||
858 | |||
859 | #ifndef ASM_CPU_STEP | ||
860 | |||
861 | int cpu_step(int max) | ||
862 | { | ||
863 | int cnt; | ||
864 | if ((cnt = cpu_idle(max))) return cnt; | ||
865 | return cpu_emulate(1); | ||
866 | } | ||
867 | |||
868 | #endif /* ASM_CPU_STEP */ | ||
869 | |||
870 | |||
871 | |||
872 | |||
873 | |||
874 | |||
875 | |||
876 | |||
877 | |||
878 | |||
879 | |||
880 | |||