ref: 69af2676b0c62a79370158b9a6ee1263d614ac88
dir: /sys/src/games/gb/cpu.c/
#include <u.h> #include <libc.h> #include <thread.h> #include <draw.h> #include "dat.h" #include "fns.h" #define lohi(L, H) (((u16int)L) | (((u16int)H) << 8)) u8int R[8], Fl; u16int pc, sp, curpc; int halt, IME; static void invalid(void) { sysfatal("invalid instruction %.2x (pc = %.4x)", memread(curpc), curpc); } static u8int fetch8(void) { return memread(pc++); } static u16int fetch16(void) { u16int r; r = lohi(memread(pc), memread(pc+1)); pc += 2; return r; } static void push8(u8int n) { memwrite(--sp, n); } static void push16(u16int n) { memwrite(--sp, n >> 8); memwrite(--sp, n); } static u8int pop8(void) { return memread(sp++); } static u16int pop16(void) { u8int a, b; b = pop8(); a = pop8(); return lohi(b, a); } static int ld01(u8int op) { u8int val, a, b; int time; a = (op & 0x38) >> 3; b = op & 7; time = 4; if(a == rHL && b == rHL){ halt = 1; return 4; } if(b == rHL){ val = memread(lohi(R[rL], R[rH])); time = 8; }else{ val = R[b]; } if(a == rHL){ memwrite(lohi(R[rL], R[rH]), val); time = 8; }else{ R[a] = val; } return time; } static int ldi(u8int op) { u8int val, a; val = fetch8(); a = (op & 0x38) >> 3; if(a == rHL){ memwrite(lohi(R[rL], R[rH]), val); return 12; }else{ R[a] = val; return 8; } } static int ld16(u8int op) { u16int val; u8int a; val = fetch16(); a = (op & 0x30) >> 4; switch(a){ case 0: R[rB] = val >> 8; R[rC] = val; break; case 1: R[rD] = val >> 8; R[rE] = val; break; case 2: R[rH] = val >> 8; R[rL] = val; break; case 3: sp = val; break; } return 12; } static int add16(u8int op) { u16int val1, val2; u8int a; u32int val32; a = (op & 0x30) >> 4; switch(a){ case 0: val1 = lohi(R[rC], R[rB]); break; case 1: val1 = lohi(R[rE], R[rD]); break; case 2: val1 = lohi(R[rL], R[rH]); break; default: val1 = sp; } Fl &= FLAGZ; val2 = lohi(R[rL], R[rH]); val32 = (u32int)(val1) + (u32int)(val2); if(val32 > 0xFFFF) Fl |= FLAGC; if(((val1&0xFFF)+(val2&0xFFF)) > 0xFFF) Fl |= FLAGH; R[rL] = val32; R[rH] = val32 >> 8; return 8; } static int ldin(u8int op) { u16int addr; switch(op >> 4){ case 0: addr = lohi(R[rC], R[rB]); break; case 1: addr = lohi(R[rE], R[rD]); break; default: addr = lohi(R[rL], R[rH]); } if(op & 8){ R[rA] = memread(addr); }else{ memwrite(addr, R[rA]); } if((op >> 4) > 1){ if(op & 16) addr--; else addr++; R[rL] = addr; R[rH] = addr >> 8; } return 8; } static int inc16(u8int op) { u16int val; u8int a; a = (op & 0x38) >> 3; switch(a >> 1){ case 0: val = lohi(R[rC], R[rB]); break; case 1: val = lohi(R[rE], R[rD]); break; case 2: val = lohi(R[rL], R[rH]); break; default: val = sp; } if(a & 1) val--; else val++; switch(a >> 1){ case 0: R[rB] = val >> 8; R[rC] = val; break; case 1: R[rD] = val >> 8; R[rE] = val; break; case 2: R[rH] = val >> 8; R[rL] = val; break; default: sp = val; } return 8; } static int inc8(u8int op) { u8int val, a; int time; a = (op & 0x38) >> 3; if(a == rHL){ val = memread(lohi(R[rL], R[rH])); time = 12; }else{ val = R[a]; time = 4; } if(a == rHL){ memwrite(lohi(R[rL], R[rH]), val+1); }else{ R[a] = val + 1; } Fl &= FLAGC; if(val == 0xFF) Fl |= FLAGZ; if((val & 0xF) == 0xF) Fl |= FLAGH; return time; } static int dec8(u8int op) { u8int val, a; int time; a = (op & 0x38) >> 3; if(a == rHL){ val = memread(lohi(R[rL], R[rH])); time = 12; }else{ val = R[a]; time = 4; } if(a == rHL){ memwrite(lohi(R[rL], R[rH]), val - 1); }else{ R[a] = val - 1; } Fl = (Fl & FLAGC) | FLAGN; if(val == 1) Fl |= FLAGZ; if((val & 0xF) == 0) Fl |= FLAGH; return time; } static int alu(u8int op) { u8int val4, val8, a, b; short val16; int time; a = op & 7; b = (op & 0x38) >> 3; if((op >> 6) == 3){ val8 = fetch8(); time = 8; }else if(a == rHL){ val8 = memread(lohi(R[rL], R[rH])); time = 8; }else{ val8 = R[a]; time = 4; } switch(b){ case 0: case 1: val16 = (ushort)(R[rA]) + (ushort)(val8); val4 = (R[rA] & 0xF) + (val8 & 0xF); if(b == 1 && (Fl & FLAGC)){ val16++; val4++; } Fl = 0; val8 = val16; if(val16 >= 0x100) Fl |= FLAGC; if(val4 >= 0x10) Fl |= FLAGH; break; case 2: case 3: case 7: val16 = (ushort)R[rA]; val16 -= (ushort)val8; val4 = val8 & 0xF; if(b == 3 && (Fl & FLAGC)){ val16--; val4++; } val8 = val16; Fl = FLAGN; if(val16 < 0) Fl |= FLAGC; if(val4 > (R[rA] & 0xF)) Fl |= FLAGH; break; case 4: val8 &= R[rA]; Fl = FLAGH; break; case 5: val8 ^= R[rA]; Fl = 0; break; default: Fl = 0; val8 |= R[rA]; } if(val8 == 0) Fl |= FLAGZ; if(b != 7) R[rA] = val8; return time; } static int jr(u8int op) { u8int a; u16int addr; short step; a = (op & 0x38) >> 3; switch(a){ case 0: return 4; case 1: addr = fetch16(); memwrite(addr, sp); memwrite(addr + 1, sp >> 8); return 8; } step = (short)(schar)fetch8(); switch(a){ case 2: return 4; case 4: if(Fl & FLAGZ) return 8; break; case 5: if((Fl & FLAGZ) == 0) return 8; break; case 6: if(Fl & FLAGC) return 8; break; case 7: if((Fl & FLAGC) == 0) return 8; } pc += step; return 8; } static int jp(u8int op) { u16int addr; addr = fetch16(); if(op != 0xC3){ switch((op & 0x38) >> 3){ case 0: if(Fl & FLAGZ) return 12; break; case 1: if((Fl & FLAGZ) == 0) return 12; break; case 2: if(Fl & FLAGC) return 12; break; case 3: if((Fl & FLAGC) == 0) return 12; break; } } pc = addr; return 12; } static int call(u8int op) { u16int addr; addr = fetch16(); if(op != 0xCD){ switch((op & 0x38) >> 3){ case 0: if(Fl & FLAGZ) return 12; break; case 1: if((Fl & FLAGZ) == 0) return 12; break; case 2: if(Fl & FLAGC) return 12; break; case 3: if((Fl & FLAGC) == 0) return 12; break; } } push16(pc); pc = addr; return 12; } static int rst(u8int op) { u16int addr; addr = op & 0x38; push16(pc); pc = addr; return 32; } static int ret(u8int op) { if(op != 0xC9 && op!= 0xD9){ switch((op & 0x38) >> 3){ case 0: if(Fl & FLAGZ) return 8; break; case 1: if((Fl & FLAGZ) == 0) return 8; break; case 2: if(Fl & FLAGC) return 8; break; case 3: if((Fl & FLAGC) == 0) return 8; break; } } pc = pop16(); if(op == 0xD9) IME = 1; return 8; } static int push(u8int op) { u8int a; a = (op & 0x38) >> 4; switch(a){ case 0: push8(R[rB]); push8(R[rC]); break; case 1: push8(R[rD]); push8(R[rE]); break; case 2: push8(R[rH]); push8(R[rL]); break; default: push8(R[rA]); push8(Fl); break; } return 16; } static int pop(u8int op) { u8int a; a = (op & 0x38) >> 4; switch(a){ case 0: R[rC] = pop8(); R[rB] = pop8(); break; case 1: R[rE] = pop8(); R[rD] = pop8(); break; case 2: R[rL] = pop8(); R[rH] = pop8(); break; default: Fl = pop8() & 0xF0; R[rA] = pop8(); } return 12; } static int shift(u8int op, int cb) { u16int val; u8int a, b; int time; a = (op & 0x38) >> 3; b = op & 7; if(b == rHL){ val = memread(lohi(R[rL], R[rH])); time = 16; }else{ val = R[b]; time = 8; } switch(a){ case 0: Fl = 0; if(val & 0x80) Fl = FLAGC; val = (val << 1) | (val >> 7); break; case 1: Fl = 0; if(val & 1) Fl = FLAGC; val = (val >> 1) | (val << 7); break; case 2: val <<= 1; if(Fl & FLAGC) val |= 1; Fl = 0; if(val & 0x100) Fl = FLAGC; break; case 3: if(Fl & FLAGC) val |= 0x100; Fl = 0; if(val & 1) Fl = FLAGC; val >>= 1; break; case 4: Fl = 0; if(val & 0x80) Fl = FLAGC; val <<= 1; break; case 5: Fl = 0; if(val & 1) Fl = FLAGC; val = (val >> 1) | (val & 0x80); break; case 6: val = (val << 4) | (val >> 4); Fl = 0; break; default: Fl = 0; if(val & 1) Fl = FLAGC; val >>= 1; } if((val & 0xFF) == 0) Fl |= FLAGZ; if(b == rHL) memwrite(lohi(R[rL], R[rH]), val); else R[b] = val; if(!cb) Fl &= FLAGC; return time; } static int bit(u8int op) { u8int val, a, b; int time; a = (op & 0x38) >> 3; b = op & 7; if(b == rHL){ val = memread(lohi(R[rL], R[rH])), time = 16; }else{ val = R[b]; time = 8; } Fl = (Fl & FLAGC) | FLAGH; if((val & (1<<a)) == 0) Fl |= FLAGZ; return time; } static int setres(u8int op) { u8int val, a, b; int time; a = (op & 0x38) >> 3; b = op & 7; if(b == rHL){ val = memread(lohi(R[rL], R[rH])); time = 16; }else{ val = R[b]; time = 8; } if(op & 0x40) val |= (1 << a); else val &= ~(1 << a); if(b == rHL) memwrite(lohi(R[rL], R[rH]), val); else R[b] = val; return time; } static int cb(void) { u8int op; op = fetch8(); if((op & 0xC0) == 0) return shift(op, 1); if((op & 0xC0) == 0x40) return bit(op); return setres(op); } void interrupt(u8int t) { mem[IF] |= (1 << t); } int step(void) { u8int op; ushort val; extern u8int daa[]; int val32, i; if(halt){ if(mem[IF] & mem[IE]) halt = 0; else return 4; } if(IME && (mem[IF] & mem[IE])) for(i = 0; i < 5; i++) if(mem[IF] & mem[IE] & (1<<i)){ mem[IF] &= ~(1<<i); push16(pc); IME = 0; halt = 0; pc = 0x40 + 8 * i; break; } curpc = pc; op = fetch8(); if(0){ print("%.4x A %.2x B %.2x C %.2x D %.2x E %.2x HL %.2x%.2x SP %.4x F %.2x ", curpc, R[rA], R[rB], R[rC], R[rD], R[rE], R[rH], R[rL], sp, Fl); disasm(curpc); } if((op & 0xC7) == 0x00) return jr(op); if((op & 0xCF) == 0x01) return ld16(op); if((op & 0xCF) == 0x09) return add16(op); if((op & 0xC7) == 0x02) return ldin(op); if((op & 0xC7) == 0x03) return inc16(op); if((op & 0xC7) == 0x04) return inc8(op); if((op & 0xC7) == 0x05) return dec8(op); if((op & 0xC7) == 0x06) return ldi(op); if((op & 0xE7) == 0x07) return shift(op, 0); if((op & 0xC0) == 0x40) return ld01(op); if((op & 0xC0) == 0x80 || (op & 0xC7) == 0xC6) return alu(op); if((op & 0xE7) == 0xC0 || op == 0xC9 || op == 0xD9) return ret(op); if((op & 0xCF) == 0xC1) return pop(op); if((op & 0xE7) == 0xC2 || op == 0xC3) return jp(op); if((op & 0xE7) == 0xC4 || op == 0xCD) return call(op); if((op & 0xCF) == 0xC5) return push(op); if((op & 0xC7) == 0xC7) return rst(op); switch(op){ case 0x27: i = (((int)R[rA]) + (((int)Fl) * 16)) * 2; R[rA] = daa[i]; Fl = daa[i+1]; return 4; case 0x2F: R[rA] = ~R[rA]; Fl |= FLAGN | FLAGH; return 4; case 0x37: Fl = (Fl & FLAGZ) | FLAGC; return 4; case 0x3F: Fl &= FLAGZ | FLAGC; Fl ^= FLAGC; return 4; case 0xE0: memwrite(lohi(fetch8(), 0xFF), R[rA]); return 8; case 0xE2: memwrite(lohi(R[rC], 0xFF), R[rA]); return 8; case 0xE8: val = (short)(schar)fetch8(); val32 = (uint)sp + (uint)val; Fl = 0; if(((sp & 0xFF) + (val & 0xFF)) > 0xFF) Fl |= FLAGC; if(((sp & 0xF) + (val & 0xF)) > 0xF) Fl |= FLAGH; sp = val32; return 16; case 0xE9: pc = lohi(R[rL], R[rH]); return 4; case 0xEA: memwrite(fetch16(), R[rA]); return 16; case 0xF0: R[rA] = memread(lohi(fetch8(), 0xFF)); return 12; case 0xFA: R[rA] = memread(fetch16()); return 16; case 0xF2: R[rA] = memread(lohi(R[rC], 0xFF)); return 8; case 0xCB: return cb(); case 0xF3: IME= 0; return 4; case 0xF8: val = (short)(schar)fetch8(); val32 = (uint)sp + (uint)val; Fl = 0; if(((sp & 0xFF) + (val & 0xFF)) > 0xFF) Fl |= FLAGC; if(((sp & 0xF) + (val & 0xF)) > 0xF) Fl |= FLAGH; R[rL] = val32; R[rH] = val32 >> 8; return 12; case 0xF9: sp = lohi(R[rL], R[rH]); return 8; case 0xFB: IME = 1; return 4; default: invalid(); } return 0; }