diff --git a/get_opcodes.js b/get_opcodes.js new file mode 100644 index 0000000..2a5e213 --- /dev/null +++ b/get_opcodes.js @@ -0,0 +1,13 @@ +let total = 0; +for (let row = 1; row < rows.length; row++) { + let cols = rows[row].getElementsByTagName("td"); + for (let col = 1; col < cols.length; col++) { + let html = cols[col].innerHTML; + if (html.indexOf("
") != -1) { + html = html.substring(0, html.indexOf("
")); + } + console.log("{ 0x" + total.toString(16) + ", \"" + html + "\" },"); + total++; + } +} + diff --git a/src/cpu.c b/src/cpu.c index e20eec2..3fdc7cb 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -3,6 +3,7 @@ #include "cpu.h" #include "types.h" +#include "instructions.h" void cpu_bind_mem_model( struct cpu *cpu, @@ -15,6 +16,21 @@ void cpu_bind_mem_model( 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_af(struct cpu *cpu) { return cpu->a << 8 | cpu->f; @@ -35,6 +51,11 @@ static inline u16 read_hl(struct cpu *cpu) return cpu->h << 8 | cpu->l; } +static inline u16 read_double_reg(struct cpu *cpu, u8 *rh, u8 *rl) +{ + return *rh << 8 | *rl; +} + static inline void write_af(struct cpu *cpu, int value) { cpu->a = value >> 8; @@ -53,16 +74,20 @@ static inline void write_de(struct cpu *cpu, int value) cpu->e = value & 0xff; } -static inline void write_hl(struct cpu *cpu, int value) +// TODO figure out if I like this style better and convert write_af, etc to this +static inline void write_double_reg(struct cpu *cpu, u8 *rh, u8 *rl, int value) { - cpu->h = value >> 8; - cpu->l = value & 0xff; + *rh = value >> 8; + *rl = value & 0xff; } +#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\n", cpu->sp, cpu->pc); exit(0); } @@ -83,39 +108,105 @@ 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); +} + +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); +} + +static void rotate_left(struct cpu *regs, u8 *reg) +{ + // copy old leftmost bit to carry flag + regs->f = (*reg & 0x80) >> 3 | (regs->f & ~FLAG_CARRY); + // rotate + *reg <<= 1; + // restore leftmost (now rightmost) bit + *reg |= (regs->f & FLAG_CARRY) >> 4; +} + +static void rotate_right(struct cpu *regs, u8 *reg) +{ + // copy old rightmost bit to carry flag + regs->f = (*reg & 0x01) << 4 | (regs->f & ~FLAG_CARRY); + // rotate + *reg >>= 1; + // restore rightmost bit to left + *reg |= (regs->f & FLAG_CARRY) << 3; +} + +static void xor(struct cpu *regs, u8 value) +{ + regs->a ^= value; + if(regs->a == 0) + set_flag(regs, FLAG_ZERO); + clear_flag(regs, FLAG_SIGN); + clear_flag(regs, FLAG_HALF_CARRY); + clear_flag(regs, FLAG_CARRY); +} + void cpu_step(struct cpu *cpu) { u8 opc = cpu->mem_read(cpu->mem_model, cpu->pc); + cpu->pc++; switch (opc) { case 0: // NOP - cpu->pc++; + break; + case 0x01: // LD BC, 0xNNNN + write_bc(cpu, read16(cpu, cpu->pc)); + cpu->pc += 2; + break; + case 0x03: // INC BC + write_bc(cpu, read_bc(cpu) + 1); + break; + case 0x04: // INC B + inc_with_carry(cpu, &cpu->b); + break; + case 0x05: // DEC B + dec_with_carry(cpu, &cpu->b); break; case 0x06: // LD B, d8 - cpu->b = read8(cpu, cpu->pc + 1); - cpu->pc += 2; + cpu->b = read8(cpu, cpu->pc); + cpu->pc += 1; break; case 0x0e: // LD C, d8 - cpu->c = read8(cpu, cpu->pc + 1); - cpu->pc += 2; + cpu->c = read8(cpu, cpu->pc); + cpu->pc += 1; break; case 0x21: // LD HL, d16 - write_hl(cpu, read16(cpu, cpu->pc + 1)); - cpu->pc += 3; + write_hl(cpu, read16(cpu, cpu->pc)); + cpu->pc += 2; break; case 0x32: // LD (HL-), A write8(cpu, read_hl(cpu), cpu->a); write_hl(cpu, read_hl(cpu) - 1); - cpu->pc++; break; case 0xc3: // JP a16 - cpu->pc = read16(cpu, cpu->pc + 1); + cpu->pc = read16(cpu, cpu->pc); break; case 0xaf: // XOR A cpu->a = 0; - cpu->pc++; break; default: - printf("unknown opcode %02x\n", opc); + printf("unknown opcode 0x%02x %s\n", opc, instructions[opc].format); cpu_panic(cpu); } } diff --git a/src/cpu.h b/src/cpu.h index a565d73..c731629 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -30,9 +30,9 @@ void cpu_bind_mem_model( void cpu_step(struct cpu *cpu); -#define FLAG_Z(cpu) ((cpu)->f >> 7 & 1) -#define FLAG_N(cpu) ((cpu)->f >> 6 & 1) -#define FLAG_H(cpu) ((cpu)->f >> 5 & 1) -#define FLAG_C(cpu) ((cpu)->f >> 4 & 1) +#define FLAG_ZERO 0x80 +#define FLAG_SIGN 0x40 +#define FLAG_HALF_CARRY 0x20 +#define FLAG_CARRY 0x10 #endif diff --git a/src/instructions.c b/src/instructions.c new file mode 100644 index 0000000..a31188d --- /dev/null +++ b/src/instructions.c @@ -0,0 +1,260 @@ +#include "instructions.h" + +const struct instruction instructions[] = { + { 0x0, "NOP" }, + { 0x1, "LD BC,d16" }, + { 0x2, "LD (BC),A" }, + { 0x3, "INC BC" }, + { 0x4, "INC B" }, + { 0x5, "DEC B" }, + { 0x6, "LD B,d8" }, + { 0x7, "RLCA" }, + { 0x8, "LD (a16),SP" }, + { 0x9, "ADD HL,BC" }, + { 0xa, "LD A,(BC)" }, + { 0xb, "DEC BC" }, + { 0xc, "INC C" }, + { 0xd, "DEC C" }, + { 0xe, "LD C,d8" }, + { 0xf, "RRCA" }, + { 0x10, "STOP 0" }, + { 0x11, "LD DE,d16" }, + { 0x12, "LD (DE),A" }, + { 0x13, "INC DE" }, + { 0x14, "INC D" }, + { 0x15, "DEC D" }, + { 0x16, "LD D,d8" }, + { 0x17, "RLA" }, + { 0x18, "JR r8" }, + { 0x19, "ADD HL,DE" }, + { 0x1a, "LD A,(DE)" }, + { 0x1b, "DEC DE" }, + { 0x1c, "INC E" }, + { 0x1d, "DEC E" }, + { 0x1e, "LD E,d8" }, + { 0x1f, "RRA" }, + { 0x20, "JR NZ,r8" }, + { 0x21, "LD HL,d16" }, + { 0x22, "LD (HL+),A" }, + { 0x23, "INC HL" }, + { 0x24, "INC H" }, + { 0x25, "DEC H" }, + { 0x26, "LD H,d8" }, + { 0x27, "DAA" }, + { 0x28, "JR Z,r8" }, + { 0x29, "ADD HL,HL" }, + { 0x2a, "LD A,(HL+)" }, + { 0x2b, "DEC HL" }, + { 0x2c, "INC L" }, + { 0x2d, "DEC L" }, + { 0x2e, "LD L,d8" }, + { 0x2f, "CPL" }, + { 0x30, "JR NC,r8" }, + { 0x31, "LD SP,d16" }, + { 0x32, "LD (HL-),A" }, + { 0x33, "INC SP" }, + { 0x34, "INC (HL)" }, + { 0x35, "DEC (HL)" }, + { 0x36, "LD (HL),d8" }, + { 0x37, "SCF" }, + { 0x38, "JR C,r8" }, + { 0x39, "ADD HL,SP" }, + { 0x3a, "LD A,(HL-)" }, + { 0x3b, "DEC SP" }, + { 0x3c, "INC A" }, + { 0x3d, "DEC A" }, + { 0x3e, "LD A,d8" }, + { 0x3f, "CCF" }, + { 0x40, "LD B,B" }, + { 0x41, "LD B,C" }, + { 0x42, "LD B,D" }, + { 0x43, "LD B,E" }, + { 0x44, "LD B,H" }, + { 0x45, "LD B,L" }, + { 0x46, "LD B,(HL)" }, + { 0x47, "LD B,A" }, + { 0x48, "LD C,B" }, + { 0x49, "LD C,C" }, + { 0x4a, "LD C,D" }, + { 0x4b, "LD C,E" }, + { 0x4c, "LD C,H" }, + { 0x4d, "LD C,L" }, + { 0x4e, "LD C,(HL)" }, + { 0x4f, "LD C,A" }, + { 0x50, "LD D,B" }, + { 0x51, "LD D,C" }, + { 0x52, "LD D,D" }, + { 0x53, "LD D,E" }, + { 0x54, "LD D,H" }, + { 0x55, "LD D,L" }, + { 0x56, "LD D,(HL)" }, + { 0x57, "LD D,A" }, + { 0x58, "LD E,B" }, + { 0x59, "LD E,C" }, + { 0x5a, "LD E,D" }, + { 0x5b, "LD E,E" }, + { 0x5c, "LD E,H" }, + { 0x5d, "LD E,L" }, + { 0x5e, "LD E,(HL)" }, + { 0x5f, "LD E,A" }, + { 0x60, "LD H,B" }, + { 0x61, "LD H,C" }, + { 0x62, "LD H,D" }, + { 0x63, "LD H,E" }, + { 0x64, "LD H,H" }, + { 0x65, "LD H,L" }, + { 0x66, "LD H,(HL)" }, + { 0x67, "LD H,A" }, + { 0x68, "LD L,B" }, + { 0x69, "LD L,C" }, + { 0x6a, "LD L,D" }, + { 0x6b, "LD L,E" }, + { 0x6c, "LD L,H" }, + { 0x6d, "LD L,L" }, + { 0x6e, "LD L,(HL)" }, + { 0x6f, "LD L,A" }, + { 0x70, "LD (HL),B" }, + { 0x71, "LD (HL),C" }, + { 0x72, "LD (HL),D" }, + { 0x73, "LD (HL),E" }, + { 0x74, "LD (HL),H" }, + { 0x75, "LD (HL),L" }, + { 0x76, "HALT" }, + { 0x77, "LD (HL),A" }, + { 0x78, "LD A,B" }, + { 0x79, "LD A,C" }, + { 0x7a, "LD A,D" }, + { 0x7b, "LD A,E" }, + { 0x7c, "LD A,H" }, + { 0x7d, "LD A,L" }, + { 0x7e, "LD A,(HL)" }, + { 0x7f, "LD A,A" }, + { 0x80, "ADD A,B" }, + { 0x81, "ADD A,C" }, + { 0x82, "ADD A,D" }, + { 0x83, "ADD A,E" }, + { 0x84, "ADD A,H" }, + { 0x85, "ADD A,L" }, + { 0x86, "ADD A,(HL)" }, + { 0x87, "ADD A,A" }, + { 0x88, "ADC A,B" }, + { 0x89, "ADC A,C" }, + { 0x8a, "ADC A,D" }, + { 0x8b, "ADC A,E" }, + { 0x8c, "ADC A,H" }, + { 0x8d, "ADC A,L" }, + { 0x8e, "ADC A,(HL)" }, + { 0x8f, "ADC A,A" }, + { 0x90, "SUB B" }, + { 0x91, "SUB C" }, + { 0x92, "SUB D" }, + { 0x93, "SUB E" }, + { 0x94, "SUB H" }, + { 0x95, "SUB L" }, + { 0x96, "SUB (HL)" }, + { 0x97, "SUB A" }, + { 0x98, "SBC A,B" }, + { 0x99, "SBC A,C" }, + { 0x9a, "SBC A,D" }, + { 0x9b, "SBC A,E" }, + { 0x9c, "SBC A,H" }, + { 0x9d, "SBC A,L" }, + { 0x9e, "SBC A,(HL)" }, + { 0x9f, "SBC A,A" }, + { 0xa0, "AND B" }, + { 0xa1, "AND C" }, + { 0xa2, "AND D" }, + { 0xa3, "AND E" }, + { 0xa4, "AND H" }, + { 0xa5, "AND L" }, + { 0xa6, "AND (HL)" }, + { 0xa7, "AND A" }, + { 0xa8, "XOR B" }, + { 0xa9, "XOR C" }, + { 0xaa, "XOR D" }, + { 0xab, "XOR E" }, + { 0xac, "XOR H" }, + { 0xad, "XOR L" }, + { 0xae, "XOR (HL)" }, + { 0xaf, "XOR A" }, + { 0xb0, "OR B" }, + { 0xb1, "OR C" }, + { 0xb2, "OR D" }, + { 0xb3, "OR E" }, + { 0xb4, "OR H" }, + { 0xb5, "OR L" }, + { 0xb6, "OR (HL)" }, + { 0xb7, "OR A" }, + { 0xb8, "CP B" }, + { 0xb9, "CP C" }, + { 0xba, "CP D" }, + { 0xbb, "CP E" }, + { 0xbc, "CP H" }, + { 0xbd, "CP L" }, + { 0xbe, "CP (HL)" }, + { 0xbf, "CP A" }, + { 0xc0, "RET NZ" }, + { 0xc1, "POP BC" }, + { 0xc2, "JP NZ,a16" }, + { 0xc3, "JP a16" }, + { 0xc4, "CALL NZ,a16" }, + { 0xc5, "PUSH BC" }, + { 0xc6, "ADD A,d8" }, + { 0xc7, "RST 00H" }, + { 0xc8, "RET Z" }, + { 0xc9, "RET" }, + { 0xca, "JP Z,a16" }, + { 0xcb, "PREFIX CB" }, + { 0xcc, "CALL Z,a16" }, + { 0xcd, "CALL a16" }, + { 0xce, "ADC A,d8" }, + { 0xcf, "RST 08H" }, + { 0xd0, "RET NC" }, + { 0xd1, "POP DE" }, + { 0xd2, "JP NC,a16" }, + { 0xd3, " " }, + { 0xd4, "CALL NC,a16" }, + { 0xd5, "PUSH DE" }, + { 0xd6, "SUB d8" }, + { 0xd7, "RST 10H" }, + { 0xd8, "RET C" }, + { 0xd9, "RETI" }, + { 0xda, "JP C,a16" }, + { 0xdb, " " }, + { 0xdc, "CALL C,a16" }, + { 0xdd, " " }, + { 0xde, "SBC A,d8" }, + { 0xdf, "RST 18H" }, + { 0xe0, "LDH (a8),A" }, + { 0xe1, "POP HL" }, + { 0xe2, "LD (C),A" }, + { 0xe3, " " }, + { 0xe4, " " }, + { 0xe5, "PUSH HL" }, + { 0xe6, "AND d8" }, + { 0xe7, "RST 20H" }, + { 0xe8, "ADD SP,r8" }, + { 0xe9, "JP (HL)" }, + { 0xea, "LD (a16),A" }, + { 0xeb, " " }, + { 0xec, " " }, + { 0xed, " " }, + { 0xee, "XOR d8" }, + { 0xef, "RST 28H" }, + { 0xf0, "LDH A,(a8)" }, + { 0xf1, "POP AF" }, + { 0xf2, "LD A,(C)" }, + { 0xf3, "DI" }, + { 0xf4, " " }, + { 0xf5, "PUSH AF" }, + { 0xf6, "OR d8" }, + { 0xf7, "RST 30H" }, + { 0xf8, "LD HL,SP+r8" }, + { 0xf9, "LD SP,HL" }, + { 0xfa, "LD A,(a16)" }, + { 0xfb, "EI" }, + { 0xfc, " " }, + { 0xfd, " " }, + { 0xfe, "CP d8" }, + { 0xff, "RST 38H" }, +}; \ No newline at end of file diff --git a/src/instructions.h b/src/instructions.h new file mode 100644 index 0000000..3502b5f --- /dev/null +++ b/src/instructions.h @@ -0,0 +1,11 @@ +#ifndef _INSTRUCTIONS_H +#define _INSTRUCTIONS_H + +struct instruction { + int opcode; + const char *format; +}; + +extern const struct instruction instructions[]; + +#endif \ No newline at end of file