#include #include #include "cpu.h" #include "types.h" #include "instructions.h" void cpu_bind_mem_model( struct cpu *cpu, void *mem_model, u8 (*mem_read)(void *, u16), void (*mem_write)(void *, u16, u8) ) { cpu->mem_model = mem_model; cpu->mem_read = mem_read; cpu->mem_write = mem_write; } static inline int flag_isset(struct cpu *cpu, int flag) { return (cpu->f & flag) != 0; } static inline void set_flag(struct cpu *cpu, int flag) { cpu->f |= flag; } static inline void clear_flag(struct cpu *cpu, int flag) { cpu->f &= ~flag; } static inline u16 read_double_reg(struct cpu *cpu, u8 *rh, u8 *rl) { return *rh << 8 | *rl; } #define read_af(cpu) read_double_reg((cpu), &(cpu)->a, &(cpu)->f) #define read_bc(cpu) read_double_reg((cpu), &(cpu)->b, &(cpu)->c) #define read_de(cpu) read_double_reg((cpu), &(cpu)->d, &(cpu)->e) #define read_hl(cpu) read_double_reg((cpu), &(cpu)->h, &(cpu)->l) static inline void write_double_reg(struct cpu *cpu, u8 *rh, u8 *rl, int value) { *rh = value >> 8; *rl = value & 0xff; } #define write_af(cpu, value) write_double_reg((cpu), &(cpu)->a, &(cpu)->f, value) #define write_bc(cpu, value) write_double_reg((cpu), &(cpu)->b, &(cpu)->c, value) #define write_de(cpu, value) write_double_reg((cpu), &(cpu)->d, &(cpu)->e, value) #define write_hl(cpu, value) write_double_reg((cpu), &(cpu)->h, &(cpu)->l, value) void cpu_panic(struct cpu *cpu) { printf("a=%02x f=%02x b=%02x c=%02x\n", cpu->a, cpu->f, cpu->b, cpu->c); printf("d=%02x e=%02x h=%02x l=%02x\n", cpu->d, cpu->e, cpu->h, cpu->l); printf("sp=%04x pc=%04x flags=%s%s%s%s\n", cpu->sp, cpu->pc, flag_isset(cpu, FLAG_ZERO) ? "Z" : "-", flag_isset(cpu, FLAG_SIGN) ? "S" : "-", flag_isset(cpu, FLAG_HALF_CARRY) ? "H" : "-", flag_isset(cpu, FLAG_CARRY) ? "C" : "-"); exit(0); } static inline u8 read8(struct cpu *cpu, u16 address) { return cpu->mem_read(cpu->mem_model, address); } static inline u16 read16(struct cpu *cpu, u16 address) { u8 low = read8(cpu, address); u8 high = read8(cpu, address + 1); return high << 8 | low; } static inline void write8(struct cpu *cpu, u16 address, u8 data) { cpu->mem_write(cpu->mem_model, address, data); } static inline void write16(struct cpu *cpu, u16 address, u16 data) { cpu->mem_write(cpu->mem_model, address, data); } static void inc_with_carry(struct cpu *regs, u8 *reg) { clear_flag(regs, FLAG_SIGN); if(*reg == 0xff || *reg == 0x0f) set_flag(regs, FLAG_HALF_CARRY); (*reg)++; if(*reg == 0) set_flag(regs, FLAG_ZERO); else clear_flag(regs, FLAG_ZERO); } static void dec_with_carry(struct cpu *regs, u8 *reg) { set_flag(regs, FLAG_SIGN); if(*reg == 0x00 || *reg == 0x10) set_flag(regs, FLAG_HALF_CARRY); (*reg)--; if(*reg == 0) set_flag(regs, FLAG_ZERO); else clear_flag(regs, FLAG_ZERO); } static u8 rotate_left(struct cpu *regs, u8 reg) { // copy old leftmost bit to carry flag regs->f = (reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY); // rotate int result = reg << 1; // restore leftmost (now rightmost) bit result |= (regs->f & FLAG_CARRY) >> 4; return result; } static u8 rotate_right(struct cpu *regs, u8 reg) { // copy old rightmost bit to carry flag regs->f = (reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY); // rotate int result = reg >> 1; // restore rightmost bit to left result |= (regs->f & FLAG_CARRY) << 3; return result; } static u8 shift_left(struct cpu *cpu, u8 value) { return 0; } static u8 shift_right(struct cpu *cpu, u8 value) { return 0; } static u8 swap(struct cpu *cpu, u8 value) { return ((value & 0xf0) >> 4) | ((value & 0x0f) << 4); } static void xor(struct cpu *regs, u8 value) { regs->a ^= value; if(regs->a == 0) set_flag(regs, FLAG_ZERO); else clear_flag(regs, FLAG_ZERO); clear_flag(regs, FLAG_SIGN); clear_flag(regs, FLAG_HALF_CARRY); clear_flag(regs, FLAG_CARRY); } static void or(struct cpu *regs, u8 value) { regs->a |= value; if(regs->a == 0) set_flag(regs, FLAG_ZERO); else clear_flag(regs, FLAG_ZERO); clear_flag(regs, FLAG_SIGN); clear_flag(regs, FLAG_HALF_CARRY); clear_flag(regs, FLAG_CARRY); } static void and(struct cpu *cpu, u8 value) { cpu->a &= value; if(cpu->a == 0) { set_flag(cpu, FLAG_ZERO); } else { clear_flag(cpu, FLAG_ZERO); } clear_flag(cpu, FLAG_SIGN); set_flag(cpu, FLAG_HALF_CARRY); clear_flag(cpu, FLAG_CARRY); } static void add(struct cpu *cpu, u8 value, int with_carry) { u8 sum_trunc; int sum_full = cpu->a + value; if (with_carry && flag_isset(cpu, FLAG_CARRY)) { sum_full++; } sum_trunc = (u8) sum_full; set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0); clear_flag(cpu, FLAG_SIGN); set_flag(cpu, sum_full > sum_trunc ? FLAG_CARRY : 0); // TODO H cpu->a = sum_trunc; } static void subtract(struct cpu *cpu, u8 value, int with_carry, int just_compare) { u8 sum_trunc; int sum_full = cpu->a - value; if (with_carry && flag_isset(cpu, FLAG_CARRY)) { sum_full--; } sum_trunc = (u8) sum_full; set_flag(cpu, sum_trunc == 0 ? FLAG_ZERO : 0); set_flag(cpu, FLAG_SIGN); set_flag(cpu, sum_full < sum_trunc ? FLAG_CARRY : 0); // TODO H if (!just_compare) { cpu->a = sum_trunc; } } static void push(struct cpu *cpu, u16 value) { // todo #if DEBUG or something //printf("sp=%04x\n", cpu->sp); //printf("memory[sp-2] = %02x\n", value & 0xff); //printf("memory[sp-1] = %02x\n", value >> 8); write8(cpu, cpu->sp - 2, value & 0xff); write8(cpu, cpu->sp - 1, value >> 8); cpu->sp -= 2; } static u16 pop(struct cpu *cpu) { cpu->sp += 2; //printf("sp=%04x\n", cpu->sp); //printf("read memory[sp-2] = %02x\n", read8(cpu, cpu->sp - 2)); //printf("read memory[sp-1] = %02x\n", read8(cpu, cpu->sp - 1)); return read8(cpu, cpu->sp - 1) << 8 | read8(cpu, cpu->sp - 2); } static void add16(struct cpu *cpu, u16 src) { clear_flag(cpu, FLAG_SIGN); int total = read_hl(cpu) + src; // promoted to int if (total > 0xffff) { set_flag(cpu, FLAG_CARRY); } else { clear_flag(cpu, FLAG_CARRY); } if (((cpu->h & 0xf) + ((src >> 8) & 0xf)) & 0x10) { // true if carry from bit 11 to bit 12 set_flag(cpu, FLAG_HALF_CARRY); } else { clear_flag(cpu, FLAG_HALF_CARRY); } write_hl(cpu, total & 0xffff); } static u8 read_reg(struct cpu *cpu, int index) { switch (index) { case 0: return cpu->b; case 1: return cpu->c; case 2: return cpu->d; case 3: return cpu->e; case 4: return cpu->h; case 5: return cpu->l; case 6: return read8(cpu, read_hl(cpu)); case 7: return cpu->a; default: cpu_panic(cpu); } } static u8 write_reg(struct cpu *cpu, int index, u8 val) { switch (index) { case 0: cpu->b = val; break; case 1: cpu->c = val; break; case 2: cpu->d = val; break; case 3: cpu->e = val; break; case 4: cpu->h = val; break; case 5: cpu->l = val; break; case 6: write8(cpu, read_hl(cpu), val); break; case 7: cpu->a = val; break; default: cpu_panic(cpu); } } static void extended_insn(struct cpu *cpu, u8 insn) { u8 temp; int op = insn >> 6; int bit = (insn >> 3) & 0x7; int reg = insn & 0x7; u8 (*funcs[8])(struct cpu *, u8) = { rotate_left, rotate_right, rotate_left, // TODO non-carry version rotate_right, shift_left, shift_right, swap, shift_right // TODO SRL }; switch (op) { case 0: write_reg(cpu, reg, funcs[bit](cpu, read_reg(cpu, reg))); break; case 1: // BIT temp = read_reg(cpu, reg); if ((temp & (1 << bit)) == 0) { set_flag(cpu, FLAG_ZERO); } else { clear_flag(cpu, FLAG_ZERO); } clear_flag(cpu, FLAG_SIGN); set_flag(cpu, FLAG_HALF_CARRY); break; case 2: // RES write_reg(cpu, reg, read_reg(cpu, reg) & ~(1 << bit)); break; case 3: // SET write_reg(cpu, reg, read_reg(cpu, reg) | (1 << bit)); break; } } void cpu_step(struct cpu *cpu) { u8 temp; u16 temp16; u8 opc = cpu->mem_read(cpu->mem_model, cpu->pc); printf("0x%04x %s\n", cpu->pc, instructions[opc].format); cpu->pc++; switch (opc) { case 0: // NOP break; case 0x01: // LD BC, 0xNNNN write_bc(cpu, read16(cpu, cpu->pc)); cpu->pc += 2; break; case 0x11: // LD DE,d16 write_de(cpu, read16(cpu, cpu->pc)); cpu->pc += 2; break; case 0x07: // RLCA cpu->a = rotate_left(cpu, cpu->a); break; case 0x08: // LD (a16),SP write16(cpu, read16(cpu, cpu->pc), cpu->sp); cpu->pc += 2; break; case 0x19: // ADD HL,DE add16(cpu, read_de(cpu)); break; case 0x17: // RLA cpu->a = rotate_left(cpu, cpu->a); break; case 0x1f: // RRA cpu->a = rotate_right(cpu, cpu->a); break; // incs and decs case 0x03: write_bc(cpu, read_bc(cpu) + 1); break; case 0x04: inc_with_carry(cpu, &cpu->b); break; case 0x05: dec_with_carry(cpu, &cpu->b); break; case 0x0b: write_bc(cpu, read_bc(cpu) - 1); break; case 0x0c: inc_with_carry(cpu, &cpu->c); break; case 0x0d: dec_with_carry(cpu, &cpu->c); break; case 0x13: write_de(cpu, read_de(cpu) + 1); break; case 0x14: inc_with_carry(cpu, &cpu->d); break; case 0x15: dec_with_carry(cpu, &cpu->d); break; case 0x1b: write_de(cpu, read_de(cpu) - 1); break; case 0x1c: inc_with_carry(cpu, &cpu->e); break; case 0x1d: dec_with_carry(cpu, &cpu->e); break; case 0x23: write_hl(cpu, read_hl(cpu) + 1); break; case 0x24: inc_with_carry(cpu, &cpu->h); break; case 0x25: dec_with_carry(cpu, &cpu->h); break; case 0x2b: write_hl(cpu, read_hl(cpu) - 1); break; case 0x2c: inc_with_carry(cpu, &cpu->l); break; case 0x2d: dec_with_carry(cpu, &cpu->l); break; case 0x33: cpu->sp++; break; case 0x34: temp = read8(cpu, read_hl(cpu)); inc_with_carry(cpu, &temp); break; case 0x35: temp = read8(cpu, read_hl(cpu)); dec_with_carry(cpu, &temp); break; case 0x3b: cpu->sp--; break; case 0x3c: inc_with_carry(cpu, &cpu->a); break; case 0x3d: dec_with_carry(cpu, &cpu->a); break; // 8-bit immediate loads case 0x06: cpu->b = read8(cpu, cpu->pc); cpu->pc++; break; case 0x0e: cpu->c = read8(cpu, cpu->pc); cpu->pc++; break; case 0x16: cpu->d = read8(cpu, cpu->pc); cpu->pc++; break; case 0x1e: cpu->e = read8(cpu, cpu->pc); cpu->pc++; break; case 0x26: cpu->h = read8(cpu, cpu->pc); cpu->pc++; break; case 0x2e: cpu->l = read8(cpu, cpu->pc); cpu->pc++; break; case 0x36: write8(cpu, read_hl(cpu), read8(cpu, cpu->pc)); cpu->pc++; break; case 0x3e: cpu->a = read8(cpu, cpu->pc); cpu->pc++; break; // 8-bit register -> register copies // dest = B case 0x40: break; // copy B to B case 0x41: cpu->b = cpu->c; break; case 0x42: cpu->b = cpu->d; break; case 0x43: cpu->b = cpu->e; break; case 0x44: cpu->b = cpu->h; break; case 0x45: cpu->b = cpu->l; break; case 0x46: cpu->b = read8(cpu, read_hl(cpu)); break; case 0x47: cpu->b = cpu->a; break; // dest = C case 0x48: cpu->c = cpu->b; break; case 0x49: break; // copy C to C case 0x4a: cpu->c = cpu->d; break; case 0x4b: cpu->c = cpu->e; break; case 0x4c: cpu->c = cpu->h; break; case 0x4d: cpu->c = cpu->l; break; case 0x4e: cpu->c = read8(cpu, read_hl(cpu)); break; case 0x4f: cpu->c = cpu->a; break; // dest = D case 0x50: cpu->d = cpu->b; break; case 0x51: cpu->d = cpu->c; break; case 0x52: break; // copy D to D case 0x53: cpu->d = cpu->e; break; case 0x54: cpu->d = cpu->h; break; case 0x55: cpu->d = cpu->l; break; case 0x56: cpu->d = read8(cpu, read_hl(cpu)); break; case 0x57: cpu->d = cpu->a; break; // dest = E case 0x58: cpu->e = cpu->b; break; case 0x59: cpu->e = cpu->c; break; case 0x5a: cpu->e = cpu->d; break; case 0x5b: break; // copy E to E case 0x5c: cpu->e = cpu->h; break; case 0x5d: cpu->e = cpu->l; break; case 0x5e: cpu->e = read8(cpu, read_hl(cpu)); break; case 0x5f: cpu->e = cpu->a; break; // dest = H case 0x60: cpu->h = cpu->b; break; case 0x61: cpu->h = cpu->c; break; case 0x62: cpu->h = cpu->d; break; case 0x63: cpu->h = cpu->e; break; case 0x64: break; // copy H to H case 0x65: cpu->h = cpu->l; break; case 0x66: cpu->h = read8(cpu, read_hl(cpu)); break; case 0x67: cpu->h = cpu->a; break; // dest = L case 0x68: cpu->l = cpu->b; break; case 0x69: cpu->l = cpu->c; break; case 0x6a: cpu->l = cpu->d; break; case 0x6b: cpu->l = cpu->e; break; case 0x6c: cpu->l = cpu->h; break; case 0x6d: break; // copy L to L case 0x6e: cpu->l = read8(cpu, read_hl(cpu)); break; case 0x6f: cpu->l = cpu->a; break; // dest = *HL case 0x70: write8(cpu, read_hl(cpu), cpu->b); break; case 0x71: write8(cpu, read_hl(cpu), cpu->c); break; case 0x72: write8(cpu, read_hl(cpu), cpu->d); break; case 0x73: write8(cpu, read_hl(cpu), cpu->e); break; case 0x74: write8(cpu, read_hl(cpu), cpu->h); break; case 0x75: write8(cpu, read_hl(cpu), cpu->l); break; // 0x76 is HALT case 0x77: write8(cpu, read_hl(cpu), cpu->a); break; // dest = A case 0x78: cpu->a = cpu->b; break; case 0x79: cpu->a = cpu->c; break; case 0x7a: cpu->a = cpu->d; break; case 0x7b: cpu->a = cpu->e; break; case 0x7c: cpu->a = cpu->h; break; case 0x7d: cpu->a = cpu->l; break; case 0x7e: cpu->a = read8(cpu, read_hl(cpu)); break; case 0x7f: break; // copy A to A // A = r16 case 0x0a: cpu->a = read8(cpu, read_bc(cpu)); break; // A = *BC case 0x1a: cpu->a = read8(cpu, read_de(cpu)); break; // A = *DE case 0x2a: cpu->a = read8(cpu, read_hl(cpu)); write_hl(cpu, read_hl(cpu) + 1); break; case 0x3a: cpu->a = read8(cpu, read_hl(cpu)); write_hl(cpu, read_hl(cpu) - 1); break; case 0x12: // LD (DE),A write8(cpu, read_de(cpu), cpu->a); break; case 0x18: // JR r8 temp = read8(cpu, cpu->pc); cpu->pc += *((signed char *) &temp) + 1; break; case 0x20: // JR NZ,r8 case 0x28: // JR Z,r8 temp = read8(cpu, cpu->pc); if ((opc == 0x20) ^ flag_isset(cpu, FLAG_ZERO)) { cpu->pc += *((signed char *) &temp) + 1; } else { cpu->pc++; } break; case 0x21: // LD HL, d16 write_hl(cpu, read16(cpu, cpu->pc)); cpu->pc += 2; break; case 0x29: // ADD HL,HL add16(cpu, read_hl(cpu)); break; case 0x2f: // CPL cpu->a = ~cpu->a; break; case 0x31: // LD SP,d16 cpu->sp = read16(cpu, cpu->pc); cpu->pc += 2; break; case 0x22: // LD (HL+), A write8(cpu, read_hl(cpu), cpu->a); write_hl(cpu, read_hl(cpu) + 1); break; case 0x32: // LD (HL-), A write8(cpu, read_hl(cpu), cpu->a); write_hl(cpu, read_hl(cpu) - 1); break; case 0xc0: // RET NZ if (!flag_isset(cpu, FLAG_ZERO)) { cpu->pc = pop(cpu); } break; case 0xc9: // RET cpu->pc = pop(cpu); break; case 0xcd: // CALL a16 temp16 = read16(cpu, cpu->pc); cpu->pc += 2; push(cpu, cpu->pc); cpu->pc = temp16; break; case 0xc3: // JP a16 cpu->pc = read16(cpu, cpu->pc); break; case 0xd2: // JP NC,a16 if (flag_isset(cpu, FLAG_CARRY)) { cpu->pc = read16(cpu, cpu->pc); } break; case 0x80: add(cpu, cpu->b, 0); break; case 0x81: add(cpu, cpu->c, 0); break; case 0x82: add(cpu, cpu->d, 0); break; case 0x83: add(cpu, cpu->e, 0); break; case 0x84: add(cpu, cpu->h, 0); break; case 0x85: add(cpu, cpu->l, 0); break; case 0x86: add(cpu, read8(cpu, read_hl(cpu)), 0); break; case 0x87: add(cpu, cpu->a, 0); break; case 0x88: add(cpu, cpu->b, 1); break; case 0x89: add(cpu, cpu->c, 1); break; case 0x8a: add(cpu, cpu->d, 1); break; case 0x8b: add(cpu, cpu->e, 1); break; case 0x8c: add(cpu, cpu->h, 1); break; case 0x8d: add(cpu, cpu->l, 1); break; case 0x8e: add(cpu, read8(cpu, read_hl(cpu)), 1); break; case 0x8f: add(cpu, cpu->a, 1); break; case 0x90: subtract(cpu, cpu->b, 0, 0); break; case 0x91: subtract(cpu, cpu->c, 0, 0); break; case 0x92: subtract(cpu, cpu->d, 0, 0); break; case 0x93: subtract(cpu, cpu->e, 0, 0); break; case 0x94: subtract(cpu, cpu->h, 0, 0); break; case 0x95: subtract(cpu, cpu->l, 0, 0); break; case 0x96: subtract(cpu, read8(cpu, read_hl(cpu)), 0, 0); break; case 0x97: subtract(cpu, cpu->a, 0, 0); break; case 0x98: subtract(cpu, cpu->b, 1, 0); break; case 0x99: subtract(cpu, cpu->c, 1, 0); break; case 0x9a: subtract(cpu, cpu->d, 1, 0); break; case 0x9b: subtract(cpu, cpu->e, 1, 0); break; case 0x9c: subtract(cpu, cpu->h, 1, 0); break; case 0x9d: subtract(cpu, cpu->l, 1, 0); break; case 0x9e: subtract(cpu, read8(cpu, read_hl(cpu)), 1, 0); break; case 0x9f: subtract(cpu, cpu->a, 1, 0); break; // AND case 0xa0: and(cpu, cpu->b); break; case 0xa1: and(cpu, cpu->c); break; case 0xa2: and(cpu, cpu->d); break; case 0xa3: and(cpu, cpu->e); break; case 0xa4: and(cpu, cpu->h); break; case 0xa5: and(cpu, cpu->l); break; case 0xa6: and(cpu, read8(cpu, read_hl(cpu))); break; case 0xa7: and(cpu, cpu->a); break; case 0xe6: and(cpu, read8(cpu, cpu->pc)); cpu->pc++; break; // XOR case 0xa8: xor(cpu, cpu->b); break; case 0xa9: xor(cpu, cpu->c); break; case 0xaa: xor(cpu, cpu->d); break; case 0xab: xor(cpu, cpu->e); break; case 0xac: xor(cpu, cpu->h); break; case 0xad: xor(cpu, cpu->l); break; case 0xae: xor(cpu, read8(cpu, read_hl(cpu))); break; case 0xaf: xor(cpu, cpu->a); break; case 0xee: xor(cpu, read8(cpu, cpu->pc)); cpu->pc++; break; // OR case 0xb0: or(cpu, cpu->b); break; case 0xb1: or(cpu, cpu->c); break; case 0xb2: or(cpu, cpu->d); break; case 0xb3: or(cpu, cpu->e); break; case 0xb4: or(cpu, cpu->h); break; case 0xb5: or(cpu, cpu->l); break; case 0xb6: or(cpu, read8(cpu, read_hl(cpu))); break; case 0xb7: or(cpu, cpu->a); break; // CP case 0xb8: subtract(cpu, cpu->b, 0, 1); break; case 0xb9: subtract(cpu, cpu->c, 0, 1); break; case 0xba: subtract(cpu, cpu->d, 0, 1); break; case 0xbb: subtract(cpu, cpu->e, 0, 1); break; case 0xbc: subtract(cpu, cpu->h, 0, 1); break; case 0xbd: subtract(cpu, cpu->l, 0, 1); break; case 0xbe: subtract(cpu, read8(cpu, read_hl(cpu)), 0, 1); break; case 0xbf: subtract(cpu, cpu->a, 0, 1); break; case 0xfe: subtract(cpu, read8(cpu, cpu->pc), 0, 1); cpu->pc++; break; // RST case 0xc7: push(cpu, cpu->pc); cpu->pc = 0x00; break; case 0xcf: push(cpu, cpu->pc); cpu->pc = 0x08; break; case 0xd7: push(cpu, cpu->pc); cpu->pc = 0x10; break; case 0xdf: push(cpu, cpu->pc); cpu->pc = 0x18; break; case 0xe7: push(cpu, cpu->pc); cpu->pc = 0x20; break; case 0xef: push(cpu, cpu->pc); cpu->pc = 0x28; break; case 0xf7: push(cpu, cpu->pc); cpu->pc = 0x30; break; case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break; case 0xc1: // POP BC write_bc(cpu, pop(cpu)); break; case 0xc5: // PUSH BC push(cpu, read_bc(cpu)); break; case 0xcb: extended_insn(cpu, read8(cpu, cpu->pc)); cpu->pc++; break; case 0xce: add(cpu, read8(cpu, cpu->pc), 1); cpu->pc++; break; case 0xe0: // LDH (a8),A write16(cpu, 0xff00 + read8(cpu, cpu->pc), cpu->a); cpu->pc++; break; case 0xe2: // LD (C),A write8(cpu, 0xff00 + cpu->c, cpu->a); break; case 0xea: // LD (a16),A write16(cpu, read16(cpu, cpu->pc), cpu->a); cpu->pc += 2; break; case 0xf0: // LDH A,(a8) cpu->a = read16(cpu, 0xff00 + read8(cpu, cpu->pc)); cpu->pc++; break; case 0xf2: // LD A,(C) cpu->a = read8(cpu, 0xff00 + cpu->c); break; case 0xf3: // DI break; case 0xfb: // EI break; default: printf("unknown opcode 0x%02x %s\n", opc, instructions[opc].format); cpu_panic(cpu); } }