1 #include "rockmacros.h"
17 struct cpu cpu IBSS_ATTR
;
20 #define ZFLAG(n) ( (n) ? 0 : FZ )
23 #define PUSH(w) ( (SP -= 2), (writew(xSP, (w))) )
24 #define POP(w) ( ((w) = readw(xSP)), (SP += 2) )
26 #define FETCH (readb(PC++))
29 #define INC(r) { ((r)++); \
30 F = (F & (FL|FC)) | incflag_table[(r)]; }
32 #define DEC(r) { ((r)--); \
33 F = (F & (FL|FC)) | decflag_table[(r)]; }
35 #define INCW(r) ( (r)++ )
37 #define DECW(r) ( (r)-- )
40 W(acc) = (un16)A + (un16)(n); \
41 F = (ZFLAG(LB(acc))) \
42 | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
47 W(acc) = (un16)A + (un16)(n) + (un16)((F&FC)>>4); \
48 F = (ZFLAG(LB(acc))) \
49 | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
54 DW(acc) = (un32)HL + (un32)(n); \
56 | (FH & ((H ^ ((n)>>8) ^ HB(acc)) << 1)) \
57 | (acc.b[HI][LO] << 4); \
61 DW(acc) = (un32)SP + (un32)(n8)(n); \
62 F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \
63 | (acc.b[HI][LO] << 4); \
67 DW(acc) = (un32)SP + (un32)(n8)(n); \
68 F = (FH & (((SP>>8) ^ ((n)>>8) ^ HB(acc)) << 1)) \
69 | (acc.b[HI][LO] << 4); \
73 W(acc) = (un16)A - (un16)(n); \
76 | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
77 | ((un8)(-(n8)HB(acc)) << 4); }
79 #define SUB(n) { CP((n)); A = LB(acc); }
82 W(acc) = (un16)A - (un16)(n) - (un16)((F&FC)>>4); \
84 | (ZFLAG((n8)LB(acc))) \
85 | (FH & ((A ^ (n) ^ LB(acc)) << 1)) \
86 | ((un8)(-(n8)HB(acc)) << 4); \
89 #define AND(n) { A &= (n); \
92 #define XOR(n) { A ^= (n); \
95 #define OR(n) { A |= (n); \
98 #define RLCA(r) { (r) = ((r)>>7) | ((r)<<1); \
99 F = (((r)&0x01)<<4); }
101 #define RRCA(r) { (r) = ((r)<<7) | ((r)>>1); \
102 F = (((r)&0x80)>>3); }
105 LB(acc) = (((r)&0x80)>>3); \
106 (r) = ((r)<<1) | ((F&FC)>>4); \
110 LB(acc) = (((r)&0x01)<<4); \
111 (r) = ((r)>>1) | ((F&FC)<<3); \
114 #define RLC(r) { RLCA(r); F |= ZFLAG(r); }
115 #define RRC(r) { RRCA(r); F |= ZFLAG(r); }
116 #define RL(r) { RLA(r); F |= ZFLAG(r); }
117 #define RR(r) { RRA(r); F |= ZFLAG(r); }
120 LB(acc) = (((r)&0x80)>>3); \
122 F = ZFLAG((r)) | LB(acc); }
125 LB(acc) = (((r)&0x01)<<4); \
126 (r) = (un8)(((n8)(r))>>1); \
127 F = ZFLAG((r)) | LB(acc); }
130 LB(acc) = (((r)&0x01)<<4); \
132 F = ZFLAG((r)) | LB(acc); }
138 #define SCF { F = (F & (FZ)) | FC; }
140 #define CCF { F = (F & (FZ|FC)) ^ FC; }
143 A += (LB(acc) = daa_table[((((int)F)&0x70)<<4) | A]); \
144 F = (F & (FN)) | ZFLAG(A) | daa_carry_table[LB(acc)>>2]; }
147 (r) = swap_table[(r)]; \
150 #define BIT(n,r) { F = (F & FC) | ZFLAG(((r) & (1 << (n)))) | FH; }
151 #define RES(n,r) { (r) &= ~(1 << (n)); }
152 #define SET(n,r) { (r) |= (1 << (n)); }
154 #define CB_REG_CASES(r, n) \
155 case 0x00|(n): RLC(r); break; \
156 case 0x08|(n): RRC(r); break; \
157 case 0x10|(n): RL(r); break; \
158 case 0x18|(n): RR(r); break; \
159 case 0x20|(n): SLA(r); break; \
160 case 0x28|(n): SRA(r); break; \
161 case 0x30|(n): SWAP(r); break; \
162 case 0x38|(n): SRL(r); break; \
163 case 0x40|(n): BIT(0, r); break; \
164 case 0x48|(n): BIT(1, r); break; \
165 case 0x50|(n): BIT(2, r); break; \
166 case 0x58|(n): BIT(3, r); break; \
167 case 0x60|(n): BIT(4, r); break; \
168 case 0x68|(n): BIT(5, r); break; \
169 case 0x70|(n): BIT(6, r); break; \
170 case 0x78|(n): BIT(7, r); break; \
171 case 0x80|(n): RES(0, r); break; \
172 case 0x88|(n): RES(1, r); break; \
173 case 0x90|(n): RES(2, r); break; \
174 case 0x98|(n): RES(3, r); break; \
175 case 0xA0|(n): RES(4, r); break; \
176 case 0xA8|(n): RES(5, r); break; \
177 case 0xB0|(n): RES(6, r); break; \
178 case 0xB8|(n): RES(7, r); break; \
179 case 0xC0|(n): SET(0, r); break; \
180 case 0xC8|(n): SET(1, r); break; \
181 case 0xD0|(n): SET(2, r); break; \
182 case 0xD8|(n): SET(3, r); break; \
183 case 0xE0|(n): SET(4, r); break; \
184 case 0xE8|(n): SET(5, r); break; \
185 case 0xF0|(n): SET(6, r); break; \
186 case 0xF8|(n): SET(7, r); break;
189 #define ALU_CASES(base, imm, op, label) \
190 case (imm): b = FETCH; goto label; \
191 case (base): b = B; goto label; \
192 case (base)+1: b = C; goto label; \
193 case (base)+2: b = D; goto label; \
194 case (base)+3: b = E; goto label; \
195 case (base)+4: b = H; goto label; \
196 case (base)+5: b = L; goto label; \
197 case (base)+6: b = readb(HL); goto label; \
198 case (base)+7: b = A; \
208 #define JR ( PC += 1+(n8)readb(PC) )
209 #define JP ( PC = readw(PC) )
211 #define CALL ( PUSH(PC+2), JP )
213 #define NOJR ( clen--, PC++ )
214 #define NOJP ( clen--, PC+=2 )
215 #define NOCALL ( clen-=3, PC+=2 )
216 #define NORET ( clen-=3 )
218 #define RST(n) { PUSH(PC); PC = (n); }
220 #define RET ( POP(PC) )
222 #define EI ( IMA = 1 )
223 #define DI ( IMA = IME = 0 )
227 #define PRE_INT ( DI, PUSH(PC) )
228 #define THROW_INT(n) ( (IF &= ~(1<<(n))), (PC = 0x40+((n)<<3)) )
232 struct dynarec_block
*address_map
[1<<HASH_SIGNIFICANT_LOWER_BITS
];
233 extern void *dynapointer
;
269 if (hw
.cgb
) A
= 0x11;
271 for(i
=0;i
<(1<<HASH_SIGNIFICANT_LOWER_BITS
);i
++)
277 void div_advance(int cnt
)
282 R_DIV
+= (cpu
.div
>> 8);
287 void timer_advance(int cnt
)
291 if (!(R_TAC
& 0x04)) return;
293 unit
= ((-R_TAC
) & 3) << 1;
294 cpu
.tim
+= (cnt
<<unit
);
298 tima
= R_TIMA
+ (cpu
.tim
>> 9);
302 hw_interrupt(IF_TIMER
, IF_TIMER
);
303 hw_interrupt(0, IF_TIMER
);
306 tima
= tima
- 256 + R_TMA
;
311 void lcdc_advance(int cnt
)
314 if (cpu
.lcdc
<= 0) lcdc_trans();
317 void sound_advance(int cnt
)
322 void cpu_timers(int cnt
)
324 div_advance(cnt
<< cpu
.speed
);
325 timer_advance(cnt
<< cpu
.speed
);
331 int cpu_idle(int max
)
335 if (!(cpu
.halt
&& IME
)) return 0;
337 /* Make sure we don't miss lcdc status events! */
338 if ((R_IE
& (IF_VBLANK
| IF_STAT
)) && (max
> cpu
.lcdc
))
341 /* If timer interrupt cannot happen, this is very simple! */
342 if (!((R_IE
& IF_TIMER
) && (R_TAC
& 0x04)))
348 /* Figure out when the next timer interrupt will happen */
349 unit
= ((-R_TAC
) & 3) << 1;
350 cnt
= (511 - cpu
.tim
+ (1<<unit
)) >> unit
;
351 cnt
+= (255 - R_TIMA
) << (9 - unit
);
360 #ifndef ASM_CPU_EMULATE
362 extern int debug_trace
;
364 int cpu_emulate(int cycles
)
367 static byte op IBSS_ATTR
;
368 static byte cbop IBSS_ATTR
;
370 static union reg acc IBSS_ATTR
;
371 static byte b IBSS_ATTR
;
372 static word w IBSS_ATTR
;
380 if ((clen
= cpu_idle(i
)))
383 if (i
> 0) goto next
;
387 if (IME
&& (IF
& IE
))
390 switch ((byte
)(IF
& IE
))
392 case 0x01: case 0x03: case 0x05: case 0x07:
393 case 0x09: case 0x0B: case 0x0D: case 0x0F:
394 case 0x11: case 0x13: case 0x15: case 0x17:
395 case 0x19: case 0x1B: case 0x1D: case 0x1F:
397 case 0x02: case 0x06: case 0x0A: case 0x0E:
398 case 0x12: case 0x16: case 0x1A: case 0x1E:
400 case 0x04: case 0x0C: case 0x14: case 0x1C:
402 case 0x08: case 0x18:
410 /* if (debug_trace) debug_disassemble(PC, 1); */
415 clen
= cycles_table
[op
];
420 case 0x40: /* LD B,B */
421 case 0x49: /* LD C,C */
422 case 0x52: /* LD D,D */
423 case 0x5B: /* LD E,E */
424 case 0x64: /* LD H,H */
425 case 0x6D: /* LD L,L */
426 case 0x7F: /* LD A,A */
429 case 0x41: /* LD B,C */
431 case 0x42: /* LD B,D */
433 case 0x43: /* LD B,E */
435 case 0x44: /* LD B,H */
437 case 0x45: /* LD B,L */
439 case 0x46: /* LD B,(HL) */
440 B
= readb(xHL
); break;
441 case 0x47: /* LD B,A */
444 case 0x48: /* LD C,B */
446 case 0x4A: /* LD C,D */
448 case 0x4B: /* LD C,E */
450 case 0x4C: /* LD C,H */
452 case 0x4D: /* LD C,L */
454 case 0x4E: /* LD C,(HL) */
455 C
= readb(xHL
); break;
456 case 0x4F: /* LD C,A */
459 case 0x50: /* LD D,B */
461 case 0x51: /* LD D,C */
463 case 0x53: /* LD D,E */
465 case 0x54: /* LD D,H */
467 case 0x55: /* LD D,L */
469 case 0x56: /* LD D,(HL) */
470 D
= readb(xHL
); break;
471 case 0x57: /* LD D,A */
474 case 0x58: /* LD E,B */
476 case 0x59: /* LD E,C */
478 case 0x5A: /* LD E,D */
480 case 0x5C: /* LD E,H */
482 case 0x5D: /* LD E,L */
484 case 0x5E: /* LD E,(HL) */
485 E
= readb(xHL
); break;
486 case 0x5F: /* LD E,A */
489 case 0x60: /* LD H,B */
491 case 0x61: /* LD H,C */
493 case 0x62: /* LD H,D */
495 case 0x63: /* LD H,E */
497 case 0x65: /* LD H,L */
499 case 0x66: /* LD H,(HL) */
500 H
= readb(xHL
); break;
501 case 0x67: /* LD H,A */
504 case 0x68: /* LD L,B */
506 case 0x69: /* LD L,C */
508 case 0x6A: /* LD L,D */
510 case 0x6B: /* LD L,E */
512 case 0x6C: /* LD L,H */
514 case 0x6E: /* LD L,(HL) */
515 L
= readb(xHL
); break;
516 case 0x6F: /* LD L,A */
519 case 0x70: /* LD (HL),B */
521 case 0x71: /* LD (HL),C */
523 case 0x72: /* LD (HL),D */
525 case 0x73: /* LD (HL),E */
527 case 0x74: /* LD (HL),H */
529 case 0x75: /* LD (HL),L */
531 case 0x77: /* LD (HL),A */
537 case 0x78: /* LD A,B */
539 case 0x79: /* LD A,C */
541 case 0x7A: /* LD A,D */
543 case 0x7B: /* LD A,E */
545 case 0x7C: /* LD A,H */
547 case 0x7D: /* LD A,L */
549 case 0x7E: /* LD A,(HL) */
550 A
= readb(xHL
); break;
552 case 0x01: /* LD BC,imm */
562 case 0x11: /* LD DE,imm */
572 case 0x21: /* LD HL,imm */
573 HL
= readw(xPC
); PC
+= 2; break;
574 case 0x31: /* LD SP,imm */
575 SP
= readw(xPC
); PC
+= 2; break;
577 case 0x02: /* LD (BC),A */
578 writeb(xBC
, A
); break;
579 case 0x0A: /* LD A,(BC) */
580 A
= readb(xBC
); break;
581 case 0x12: /* LD (DE),A */
582 writeb(xDE
, A
); break;
583 case 0x1A: /* LD A,(DE) */
584 A
= readb(xDE
); break;
586 case 0x22: /* LDI (HL),A */
587 writeb(xHL
, A
); HL
++; break;
588 case 0x2A: /* LDI A,(HL) */
589 A
= readb(xHL
); HL
++; break;
590 case 0x32: /* LDD (HL),A */
591 writeb(xHL
, A
); HL
--; break;
592 case 0x3A: /* LDD A,(HL) */
593 A
= readb(xHL
); HL
--; break;
595 case 0x06: /* LD B,imm */
597 case 0x0E: /* LD C,imm */
599 case 0x16: /* LD D,imm */
601 case 0x1E: /* LD E,imm */
603 case 0x26: /* LD H,imm */
605 case 0x2E: /* LD L,imm */
607 case 0x36: /* LD (HL),imm */
608 b
= FETCH
; writeb(xHL
, b
); break;
609 case 0x3E: /* LD A,imm */
612 case 0x08: /* LD (imm),SP */
613 writew(readw(xPC
), SP
); PC
+= 2; break;
614 case 0xEA: /* LD (imm),A */
615 writeb(readw(xPC
), A
); PC
+= 2; break;
617 case 0xE0: /* LDH (imm),A */
618 writehi(FETCH
, A
); break;
619 case 0xE2: /* LDH (C),A */
620 writehi(C
, A
); break;
621 case 0xF0: /* LDH A,(imm) */
622 A
= readhi(FETCH
); break;
623 case 0xF2: /* LDH A,(C) (undocumented) */
624 A
= readhi(C
); break;
627 case 0xF8: /* LD HL,SP+imm */
628 b
= FETCH
; LDHLSP(b
); break;
629 case 0xF9: /* LD SP,HL */
631 case 0xFA: /* LD A,(imm) */
632 A
= readb(readw(xPC
)); PC
+= 2; break;
634 ALU_CASES(0x80, 0xC6, ADD
, __ADD
)
635 ALU_CASES(0x88, 0xCE, ADC
, __ADC
)
636 ALU_CASES(0x90, 0xD6, SUB
, __SUB
)
637 ALU_CASES(0x98, 0xDE, SBC
, __SBC
)
638 ALU_CASES(0xA0, 0xE6, AND
, __AND
)
639 ALU_CASES(0xA8, 0xEE, XOR
, __XOR
)
640 ALU_CASES(0xB0, 0xF6, OR
, __OR
)
641 ALU_CASES(0xB8, 0xFE, CP
, __CP
)
643 case 0x09: /* ADD HL,BC */
645 case 0x19: /* ADD HL,DE */
647 case 0x39: /* ADD HL,SP */
649 case 0x29: /* ADD HL,HL */
655 case 0x04: /* INC B */
657 case 0x0C: /* INC C */
659 case 0x14: /* INC D */
661 case 0x1C: /* INC E */
663 case 0x24: /* INC H */
665 case 0x2C: /* INC L */
667 case 0x34: /* INC (HL) */
672 case 0x3C: /* INC A */
675 case 0x03: /* INC BC */
684 case 0x13: /* INC DE */
693 case 0x23: /* INC HL */
695 case 0x33: /* INC SP */
698 case 0x05: /* DEC B */
700 case 0x0D: /* DEC C */
702 case 0x15: /* DEC D */
704 case 0x1D: /* DEC E */
706 case 0x25: /* DEC H */
708 case 0x2D: /* DEC L */
710 case 0x35: /* DEC (HL) */
715 case 0x3D: /* DEC A */
718 case 0x0B: /* DEC BC */
727 case 0x1B: /* DEC DE */
736 case 0x2B: /* DEC HL */
738 case 0x3B: /* DEC SP */
741 case 0x07: /* RLCA */
743 case 0x0F: /* RRCA */
758 case 0x20: /* JR NZ */
759 if (!(F
&FZ
)) goto __JR
; NOJR
; break;
760 case 0x28: /* JR Z */
761 if (F
&FZ
) goto __JR
; NOJR
; break;
762 case 0x30: /* JR NC */
763 if (!(F
&FC
)) goto __JR
; NOJR
; break;
764 case 0x38: /* JR C */
765 if (F
&FC
) goto __JR
; NOJR
; break;
770 case 0xC2: /* JP NZ */
771 if (!(F
&FZ
)) goto __JP
; NOJP
; break;
772 case 0xCA: /* JP Z */
773 if (F
&FZ
) goto __JP
; NOJP
; break;
774 case 0xD2: /* JP NC */
775 if (!(F
&FC
)) goto __JP
; NOJP
; break;
776 case 0xDA: /* JP C */
777 if (F
&FC
) goto __JP
; NOJP
; break;
778 case 0xE9: /* JP HL */
784 case 0xC0: /* RET NZ */
785 if (!(F
&FZ
)) goto __RET
; NORET
; break;
786 case 0xC8: /* RET Z */
787 if (F
&FZ
) goto __RET
; NORET
; break;
788 case 0xD0: /* RET NC */
789 if (!(F
&FC
)) goto __RET
; NORET
; break;
790 case 0xD8: /* RET C */
791 if (F
&FC
) goto __RET
; NORET
; break;
792 case 0xD9: /* RETI */
793 IME
= IMA
= 1; goto __RET
;
795 case 0xCD: /* CALL */
798 case 0xC4: /* CALL NZ */
799 if (!(F
&FZ
)) goto __CALL
; NOCALL
; break;
800 case 0xCC: /* CALL Z */
801 if (F
&FZ
) goto __CALL
; NOCALL
; break;
802 case 0xD4: /* CALL NC */
803 if (!(F
&FC
)) goto __CALL
; NOCALL
; break;
804 case 0xDC: /* CALL C */
805 if (F
&FC
) goto __CALL
; NOCALL
; break;
807 case 0xC7: /* RST 0 */
808 b
= 0x00; goto __RST
;
809 case 0xCF: /* RST 8 */
810 b
= 0x08; goto __RST
;
811 case 0xD7: /* RST 10 */
812 b
= 0x10; goto __RST
;
813 case 0xDF: /* RST 18 */
814 b
= 0x18; goto __RST
;
815 case 0xE7: /* RST 20 */
816 b
= 0x20; goto __RST
;
817 case 0xEF: /* RST 28 */
818 b
= 0x28; goto __RST
;
819 case 0xF7: /* RST 30 */
820 b
= 0x30; goto __RST
;
821 case 0xFF: /* RST 38 */
826 case 0xC1: /* POP BC */
835 case 0xC5: /* PUSH BC */
837 case 0xD1: /* POP DE */
846 case 0xD5: /* PUSH DE */
848 case 0xE1: /* POP HL */
850 case 0xE5: /* PUSH HL */
852 case 0xF1: /* POP AF */
861 case 0xF5: /* PUSH AF */
864 case 0xE8: /* ADD SP,imm */
865 b
= FETCH
; ADDSP(b
); break;
877 case 0x10: /* STOP */
881 cpu
.speed
= cpu
.speed
^ 1;
882 R_KEY1
= (R_KEY1
& 0x7E) | (cpu
.speed
<< 7);
885 /* NOTE - we do not implement dmg STOP whatsoever */
888 case 0x76: /* HALT */
892 case 0xCB: /* CB prefix */
894 clen
= cb_cycles_table
[cbop
];
910 if ((cbop
& 0xC0) != 0x40) /* exclude BIT */
918 "invalid opcode 0x%02X at address 0x%04X, rombank = %d\n",
919 op
, (PC
-1) & 0xffff, mbc
.rombank
);
925 { /* ROM, dynarec. */
926 struct dynarec_block
*p
=0,*b
=address_map
[PC
&HASH_BITMASK
];
928 byte
*ptr
=mbc
.rmap
[PC
>>12];
929 snprintf(meow
,499,"PC: 0x%x 0x%x a: 0x%x\n",
930 ptr
,PC
, b
? b
->address
.d
: 0);
931 rb
->splash(HZ
*2,meow
);
932 while(b
&&b
->address
.d
!=((unsigned int)(ptr
)+PC
))
941 snprintf(meow
,499,"/dyna_0x%x_run.rb",PC
);
942 fd
=open(meow
,O_WRONLY
|O_CREAT
|O_TRUNC
);
945 fdprintf(fd
,"Block 0x%x Blockcount: %d\n",PC
,blockcount
);
946 fdprintf(fd
,"before: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
947 cpu
.a
,cpu
.b
,cpu
.c
,cpu
.d
,cpu
.e
,cpu
.hl
,cpu
.f
,cpu
.sp
,cpu
.pc
,
949 if(blockcount
<MAXBLOCK
)
951 asm volatile ("movem.l (%0),%%d1-%%d7/%%a0-%%a1\n\t"
953 "movem.l %%d1-%%d7/%%a0-%%a1,(%0)\n\t"
955 : "a" (&cpu
.a
), "a" (b
->block
)
956 : "d0", "d1", "d2", "d3", "d4", "d5", "d6",
957 "d7", "a0","a1", "a2","a3","a4");
959 fdprintf(fd
,"after: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
960 cpu
.a
,cpu
.b
,cpu
.c
,cpu
.d
,cpu
.e
,cpu
.hl
,cpu
.f
,cpu
.sp
,
969 { /* Hash miss -> not found -> recompile block and add it */
970 struct dynarec_block
*newblock
;
971 newblock
=malloc(sizeof(struct dynarec_block
));
972 memset(newblock
,0,sizeof(struct dynarec_block
));
973 newblock
->address
.d
=(unsigned int)(ptr
)+PC
;
974 dynamic_recompile(newblock
);
978 address_map
[PC
&HASH_BITMASK
]=newblock
;
994 if (i
> 0) goto next
;
998 #endif /* ASM_CPU_EMULATE */
1001 #ifndef ASM_CPU_STEP
1003 inline int cpu_step(int max
)
1006 if ((cnt
= cpu_idle(max
))) return cnt
;
1007 return cpu_emulate(1);
1010 #endif /* ASM_CPU_STEP */