diff --git a/src/mmu.c b/src/mmu.c index 2aa491f..244abbe 100644 --- a/src/mmu.c +++ b/src/mmu.c @@ -119,7 +119,7 @@ static inline uint8_t bank_byte_read(const uint8_t* bank, uint16_t addr) - http://www.smspower.org/Development/MemoryMap - http://www.smspower.org/Development/Mappers */ -uint8_t mmu_read_byte(MMU *mmu, uint16_t addr) +uint8_t mmu_read_byte(const MMU *mmu, uint16_t addr) { if (addr < 0x0400) // First kilobyte is unpaged, for interrupt handlers return bank_byte_read(mmu->rom_banks[0], addr); @@ -136,6 +136,26 @@ uint8_t mmu_read_byte(MMU *mmu, uint16_t addr) } /* + Read two bytes of memory from the given address. +*/ +uint16_t mmu_read_double(const MMU *mmu, uint16_t addr) +{ + return mmu_read_byte(mmu, addr) + (mmu_read_byte(mmu, addr + 1) << 8); +} + +/* + Read four bytes of memory from the given address. +*/ +uint32_t mmu_read_quad(const MMU *mmu, uint16_t addr) +{ + return ( + mmu_read_byte(mmu, addr) + + (mmu_read_byte(mmu, addr + 1) << 8) + + (mmu_read_byte(mmu, addr + 2) << 16) + + (mmu_read_byte(mmu, addr + 3) << 24)); +} + +/* Write a byte of memory to the given address. Return true if the byte was written, and false if it wasn't. Writes will @@ -161,15 +181,3 @@ bool mmu_write_byte(MMU *mmu, uint16_t addr, uint8_t value) return true; } } - -/* - Read four bytes of memory from the given address. -*/ -uint32_t mmu_read_quad(MMU *mmu, uint16_t addr) -{ - return ( - mmu_read_byte(mmu, addr) + - (mmu_read_byte(mmu, addr + 1) << 8) + - (mmu_read_byte(mmu, addr + 2) << 16) + - (mmu_read_byte(mmu, addr + 3) << 24)); -} diff --git a/src/mmu.h b/src/mmu.h index a91669a..8a5dd0c 100644 --- a/src/mmu.h +++ b/src/mmu.h @@ -26,6 +26,7 @@ void mmu_init(MMU*); void mmu_free(MMU*); void mmu_load_rom(MMU*, const uint8_t*, size_t); void mmu_power(MMU*); -uint8_t mmu_read_byte(MMU*, uint16_t); +uint8_t mmu_read_byte(const MMU*, uint16_t); +uint16_t mmu_read_double(const MMU*, uint16_t); +uint32_t mmu_read_quad(const MMU*, uint16_t); bool mmu_write_byte(MMU*, uint16_t, uint8_t); -uint32_t mmu_read_quad(MMU*, uint16_t); diff --git a/src/z80.c b/src/z80.c index f951ca8..492cfa5 100644 --- a/src/z80.c +++ b/src/z80.c @@ -9,6 +9,7 @@ #define REG_BC 1 #define REG_DE 2 #define REG_HL 3 +#define REG_SP 4 #define FLAG_CARRY 0 #define FLAG_SUBTRACT 1 @@ -89,6 +90,7 @@ static inline uint16_t get_pair(Z80 *z80, uint8_t pair) case REG_BC: return (z80->regfile.b << 8) + z80->regfile.c; case REG_DE: return (z80->regfile.d << 8) + z80->regfile.e; case REG_HL: return (z80->regfile.h << 8) + z80->regfile.l; + case REG_SP: return z80->regfile.sp; default: FATAL("invalid call: get_pair(z80, %u)", pair) } return 0; @@ -104,6 +106,7 @@ static inline void set_pair(Z80 *z80, uint8_t pair, uint16_t value) case REG_BC: z80->regfile.b = value >> 8; z80->regfile.c = value; break; case REG_DE: z80->regfile.d = value >> 8; z80->regfile.e = value; break; case REG_HL: z80->regfile.h = value >> 8; z80->regfile.l = value; break; + case REG_SP: z80->regfile.sp = value; break; default: FATAL("invalid call: set_pair(z80, %u, 0x%04X)", pair, value) } } diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 835f5ff..2c721e8 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -24,17 +24,179 @@ static uint8_t z80_inst_unimplemented(Z80 *z80, uint8_t opcode) return 2; } +// LD r, r' + /* - NOP (0x00): - No operation is performed. + LD r, n (0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, 0x3E): + Load the immediate value into the 8-bit register. */ -static uint8_t z80_inst_nop(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_r_n(Z80 *z80, uint8_t opcode) { - (void) opcode; + uint8_t *reg; + + switch(opcode) { + case 0x3E: reg = &z80->regfile.a; break; + case 0x06: reg = &z80->regfile.b; break; + case 0x0E: reg = &z80->regfile.c; break; + case 0x16: reg = &z80->regfile.d; break; + case 0x1E: reg = &z80->regfile.e; break; + case 0x26: reg = &z80->regfile.h; break; + case 0x2E: reg = &z80->regfile.l; break; + } + + *reg = mmu_read_byte(z80->mmu, ++z80->regfile.pc); z80->regfile.pc++; - return 4; + return 7; } +// LD r, (HL) + +// LD r, (IX+d) + +// LD r, (IY+d) + +// LD (HL), r + +// LD (IX+d), r + +// LD (IY+d), r + +// LD (HL), n + +// LD (IX+d), n + +// LD (IY+d), n + +// LD A, (BC) + +// LD A, (DE) + +// LD A, (nn) + +// LD (BC), A + +// LD (DE), A + +// LD (nn), A + +// LD A, I + +// LD A, R + +// LD I,A + +// LD R, A + +/* + LD dd, nn (0x01, 0x11, 0x21, 0x31): + Load the two-byte immediate into the 16-bit register. +*/ +static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) +{ + uint8_t pair; + + switch(opcode) { + case 0x01: pair = REG_BC; break; + case 0x11: pair = REG_DE; break; + case 0x21: pair = REG_HL; break; + case 0x31: pair = REG_SP; break; + } + + set_pair(z80, pair, mmu_read_double(z80->mmu, ++z80->regfile.pc)); + z80->regfile.pc += 2; + return 6; +} + +// LD IX, nn + +// LD IY, nn + +// LD HL, (nn) + +// LD dd, (nn) + +// LD IX, (nn) + +// LD IY, (nn) + +// LD (nn), HL + +// LD (nn), dd + +// LD (nn), IX + +// LD (nn), IY + +// LD SP, HL + +// LD SP, IX + +// LD SP, IY + +// PUSH qq + +// PUSH IX + +// PUSH IY + +// POP qq + +// POP IX + +// POP IY + +// EX DE, HL + +// EX AF, AF′ + +// EXX + +// EX (SP), HL + +// EX (SP), IX + +// EX (SP), IY + +// LDI + +// LDIR + +// LDD + +// LDDR + +// CPI + +// CPIR + +// CPD + +// CPDR + +// ADD A, r + +// ADD A, n + +// ADD A, (HL) + +// ADD A, (IX + d) + +// ADD A, (IY + d) + +// ADC A, s + +// SUB s + +// SBC A, s + +// AND s + +// OR s + +// XOR s + +// CP s + /* INC r (0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x3C): Increment the 8-bit register encoded in the opcode. @@ -62,36 +224,205 @@ static uint8_t z80_inst_inc_r(Z80 *z80, uint8_t opcode) return 4; } +// INC (HL) + +// INC (IX+d) + +// INC (IY+d) + +// DEC m + +// DAA + +// CPL + +// NEG + +// CCF + +// SCF + +/* + NOP (0x00): + No operation is performed. +*/ +static uint8_t z80_inst_nop(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + z80->regfile.pc++; + return 4; +} + +// HALT + +// DI + +// EI + +// IM 0 + +// IM 1 + +// IM 2 + +// ADD HL, ss + +// ADC HL, ss + +// SBC HL, ss + +// ADD IX, pp + +// ADD IY, rr + /* INC ss (0x03, 0x13, 0x23, 0x33): Increment the 16-bit register encoded in the opcode. */ static uint8_t z80_inst_inc_ss(Z80 *z80, uint8_t opcode) { - if (opcode == 0x33) { - z80->regfile.sp++; - } else { - uint8_t pair; - switch(opcode) { - case 0x03: pair = REG_BC; break; - case 0x13: pair = REG_DE; break; - case 0x23: pair = REG_HL; break; - } - set_pair(z80, pair, get_pair(z80, pair) + 1); + uint8_t pair; + + switch(opcode) { + case 0x03: pair = REG_BC; break; + case 0x13: pair = REG_DE; break; + case 0x23: pair = REG_HL; break; + case 0x33: pair = REG_SP; break; } + set_pair(z80, pair, get_pair(z80, pair) + 1); z80->regfile.pc++; return 6; } +// INC IX + +// INC IY + +// DEC ss + +// DEC IX + +// DEC IY + +// RLCA + +// RLA + +// RRCA + +// RRA + +// RLC r + +// RLC (HL) + +// RLC (IX+d) + +// RLC (IY+d) + +// RL m + +// RRC m + +// RR m + +// SLA m + +// SRA m + +// SRL m + +// RLD + +// RRD + +// BIT b, r + +// BIT b, (HL) + +// BIT b, (IX+d) + +// BIT b, (IY+d) + +// SET b, r + +// SET b, (HL) + +// SET b, (IX+d) + +// SET b, (IY+d) + +// RES b, m + +// JP nn + +// JP cc, nn + +// JR e + +// JR C, e + +// JR NC, e + +// JR Z, e + +// JR NZ, e + +// JP (HL) + +// JP (IX) + +// JP (IY) + +// DJNZ, e + +// CALL nn + +// CALL cc, nn + +// RET + +// RET cc + +// RETI + +// RETN + +// RST p + +// IN A, (n) + +// IN r (C) + +// INI + +// INIR + +// IND + +// INDR + +// OUT (n), A + +// OUT (C), r + +// OUTI + +// OTIR + +// OUTD + +// OTDR + static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x00] = z80_inst_nop, - [0x01] = z80_inst_unimplemented, // TODO + [0x01] = z80_inst_ld_dd_nn, [0x02] = z80_inst_unimplemented, // TODO [0x03] = z80_inst_inc_ss, [0x04] = z80_inst_inc_r, [0x05] = z80_inst_unimplemented, // TODO - [0x06] = z80_inst_unimplemented, // TODO + [0x06] = z80_inst_ld_r_n, [0x07] = z80_inst_unimplemented, // TODO [0x08] = z80_inst_unimplemented, // TODO [0x09] = z80_inst_unimplemented, // TODO @@ -99,15 +430,15 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x0B] = z80_inst_unimplemented, // TODO [0x0C] = z80_inst_inc_r, [0x0D] = z80_inst_unimplemented, // TODO - [0x0E] = z80_inst_unimplemented, // TODO + [0x0E] = z80_inst_ld_r_n, [0x0F] = z80_inst_unimplemented, // TODO [0x10] = z80_inst_unimplemented, // TODO - [0x11] = z80_inst_unimplemented, // TODO + [0x11] = z80_inst_ld_dd_nn, [0x12] = z80_inst_unimplemented, // TODO [0x13] = z80_inst_inc_ss, [0x14] = z80_inst_inc_r, [0x15] = z80_inst_unimplemented, // TODO - [0x16] = z80_inst_unimplemented, // TODO + [0x16] = z80_inst_ld_r_n, [0x17] = z80_inst_unimplemented, // TODO [0x18] = z80_inst_unimplemented, // TODO [0x19] = z80_inst_unimplemented, // TODO @@ -115,15 +446,15 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x1B] = z80_inst_unimplemented, // TODO [0x1C] = z80_inst_inc_r, [0x1D] = z80_inst_unimplemented, // TODO - [0x1E] = z80_inst_unimplemented, // TODO + [0x1E] = z80_inst_ld_r_n, [0x1F] = z80_inst_unimplemented, // TODO [0x20] = z80_inst_unimplemented, // TODO - [0x21] = z80_inst_unimplemented, // TODO + [0x21] = z80_inst_ld_dd_nn, [0x22] = z80_inst_unimplemented, // TODO [0x23] = z80_inst_inc_ss, [0x24] = z80_inst_inc_r, [0x25] = z80_inst_unimplemented, // TODO - [0x26] = z80_inst_unimplemented, // TODO + [0x26] = z80_inst_ld_r_n, [0x27] = z80_inst_unimplemented, // TODO [0x28] = z80_inst_unimplemented, // TODO [0x29] = z80_inst_unimplemented, // TODO @@ -131,10 +462,10 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x2B] = z80_inst_unimplemented, // TODO [0x2C] = z80_inst_inc_r, [0x2D] = z80_inst_unimplemented, // TODO - [0x2E] = z80_inst_unimplemented, // TODO + [0x2E] = z80_inst_ld_r_n, [0x2F] = z80_inst_unimplemented, // TODO [0x30] = z80_inst_unimplemented, // TODO - [0x31] = z80_inst_unimplemented, // TODO + [0x31] = z80_inst_ld_dd_nn, [0x32] = z80_inst_unimplemented, // TODO [0x33] = z80_inst_inc_ss, [0x34] = z80_inst_unimplemented, // TODO @@ -147,7 +478,7 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x3B] = z80_inst_unimplemented, // TODO [0x3C] = z80_inst_inc_r, [0x3D] = z80_inst_unimplemented, // TODO - [0x3E] = z80_inst_unimplemented, // TODO + [0x3E] = z80_inst_ld_r_n, [0x3F] = z80_inst_unimplemented, // TODO [0x40] = z80_inst_unimplemented, // TODO [0x41] = z80_inst_unimplemented, // TODO