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