Compare commits

...
5 Commits
4 changed files with 109 additions and 21 deletions
+1
View File
@@ -14,6 +14,7 @@ AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortLambdasOnASingleLine: All AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: Yes AlwaysBreakTemplateDeclarations: Yes
+92 -14
View File
@@ -44,13 +44,6 @@ CPU::CPU(uint32_t frequency)
m_shared_registers.emplace("nf", &m_nf); m_shared_registers.emplace("nf", &m_nf);
m_shared_registers.emplace("hf", &m_hf); m_shared_registers.emplace("hf", &m_hf);
m_shared_registers.emplace("cf", &m_cf); m_shared_registers.emplace("cf", &m_cf);
// Add opcode functions to lookup table
m_opcode_lookup_table.emplace(0xc6, std::bind(&CPU::add, this));
m_opcode_lookup_table.emplace(0x01, std::bind(&CPU::ld16, this));
m_opcode_lookup_table.emplace(0x11, std::bind(&CPU::ld16, this));
m_opcode_lookup_table.emplace(0x21, std::bind(&CPU::ld16, this));
m_opcode_lookup_table.emplace(0x31, std::bind(&CPU::ld16, this));
} }
CPU::~CPU() CPU::~CPU()
@@ -65,8 +58,23 @@ void CPU::update()
if (m_wait_cycles <= 0) { if (m_wait_cycles <= 0) {
// Read next opcode // Read next opcode
uint8_t opcode = peekMemory(); uint8_t opcode = peekMemory();
VERIFY(m_opcode_lookup_table.find(opcode) != m_opcode_lookup_table.end(), "opcode {:#x} not implemented", opcode); switch (opcode) {
m_opcode_lookup_table[opcode](); case 0x01: ld16(); break;
case 0x08: ld16(); break;
case 0x11: ld16(); break;
case 0x21: ld16(); break;
case 0x31: ld16(); break;
case 0x3e: ld8(); break;
case 0xc3: jp16(); break;
case 0xc6: add(); break;
case 0xe0: ldh8(); break;
case 0xf0: ldh8(); break;
case 0xf8: ld16(); break;
case 0xf9: ld16(); break;
default:
print("opcode {:#x} not implemented", opcode);
VERIFY_NOT_REACHED();
}
} }
// print("This is an update from the CPU\n"); // print("This is an update from the CPU\n");
@@ -77,11 +85,8 @@ void CPU::add()
uint8_t opcode = consumeMemory(); uint8_t opcode = consumeMemory();
uint8_t immediate = consumeMemory(); uint8_t immediate = consumeMemory();
switch (opcode) { switch (opcode) {
case 0xc6: // ADD A,d8 case 0xc6:
// Program counter +2 // ADD A,d8
m_pc += 2;
// Clock cycles +8
m_wait_cycles += 8; m_wait_cycles += 8;
// Flags: Z0HC // Flags: Z0HC
@@ -101,6 +106,40 @@ void CPU::add()
} }
} }
void CPU::ld8()
{
uint8_t opcode = consumeMemory();
switch (opcode) {
case 0x3e:
m_wait_cycles += 8;
m_a = immediate8();
break;
default:
VERIFY_NOT_REACHED();
}
}
void CPU::ldh8()
{
uint8_t opcode = consumeMemory();
switch (opcode) {
case 0xe0:
// LD ($ff00 + n),A == LDH (n),A
// Put value in A into address (0xff00 + next byte in memory):
m_wait_cycles += 12;
writeFf(m_a);
break;
case 0xf0:
// LD A,($ff00 + n) == LDH A,(n)
// Put value at address (0xff00 + next byte in memory) into A:
m_wait_cycles += 12;
m_a = readFf();
break;
default:
VERIFY_NOT_REACHED();
}
}
void CPU::ld16() void CPU::ld16()
{ {
uint8_t opcode = consumeMemory(); uint8_t opcode = consumeMemory();
@@ -123,6 +162,35 @@ void CPU::ld16()
m_sp = immediate16(); m_sp = immediate16();
break; break;
} }
case 0x08: {
m_wait_cycles += 20;
// TODO
break;
}
case 0xf8: {
m_wait_cycles += 12;
// TODO
// TODO flags
break;
}
case 0xf9: {
m_wait_cycles += 8;
m_sp = hl();
break;
}
default:
VERIFY_NOT_REACHED();
}
}
void CPU::jp16()
{
uint8_t opcode = consumeMemory();
switch (opcode) {
case 0xc3:
m_wait_cycles += 16;
m_pc = immediate16();
break;
default: default:
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@@ -140,6 +208,16 @@ uint8_t CPU::consumeMemory()
return Emu::the().readMemory(m_pc++); return Emu::the().readMemory(m_pc++);
} }
void CPU::writeFf(uint32_t value)
{
Emu::the().writeMemory(immediate8() | (0xff << 8), value);
}
uint32_t CPU::readFf()
{
return Emu::the().readMemory(immediate8() | (0xff << 8));
}
void CPU::setBc(uint32_t value) void CPU::setBc(uint32_t value)
{ {
m_b = value >> 8; m_b = value >> 8;
+8 -2
View File
@@ -38,6 +38,8 @@ public:
// Load Instructions // Load Instructions
// 8-bit // 8-bit
void ld8();
void ldh8();
// 16-bit // 16-bit
void ld16(); void ld16();
@@ -45,6 +47,8 @@ public:
// ------------------------------------- // -------------------------------------
// Jumps and Subroutines // Jumps and Subroutines
void jp16();
// ------------------------------------- // -------------------------------------
// Stack Operations Instructions // Stack Operations Instructions
@@ -55,8 +59,12 @@ private:
uint8_t peekMemory(int32_t offset = 0) const; uint8_t peekMemory(int32_t offset = 0) const;
uint8_t consumeMemory(); uint8_t consumeMemory();
uint32_t immediate8() { return consumeMemory(); }
uint32_t immediate16() { return consumeMemory() | (consumeMemory() << 8); } uint32_t immediate16() { return consumeMemory() | (consumeMemory() << 8); }
void writeFf(uint32_t value);
uint32_t readFf();
void setBc(uint32_t value); void setBc(uint32_t value);
void setDe(uint32_t value); void setDe(uint32_t value);
void setHl(uint32_t value); void setHl(uint32_t value);
@@ -83,6 +91,4 @@ private:
uint32_t m_cf { 0 }; // Carry flag uint32_t m_cf { 0 }; // Carry flag
int8_t m_wait_cycles { 0 }; int8_t m_wait_cycles { 0 };
std::unordered_map<uint32_t, std::function<void()>> m_opcode_lookup_table;
}; };
+8 -5
View File
@@ -34,12 +34,15 @@ int main(int argc, char* argv[])
Emu::the().addMemorySpace("BOOTROM1", 0x0000, 0x00ff); // 256B Emu::the().addMemorySpace("BOOTROM1", 0x0000, 0x00ff); // 256B
Emu::the().addMemorySpace("BOOTROM2", 0x0200, 0x08ff); // 1792B Emu::the().addMemorySpace("BOOTROM2", 0x0200, 0x08ff); // 1792B
Emu::the().addMemorySpace("VRAM", 0x8000, 0x9fff, 2); // 8KiB * 2 banks Emu::the().addMemorySpace("VRAM", 0x8000, 0x9fff, 2); // 8KiB * 2 banks
Emu::the().addMemorySpace("CARDRAM", 0xa000, 0xbfff); // 8KiB Emu::the().addMemorySpace("CARDRAM", 0xa000, 0xbfff, 1); // 8KiB * ? banks, if any
Emu::the().addMemorySpace("WRAM1", 0xc000, 0xcfff, 1); // 4 KiB, Work RAM Emu::the().addMemorySpace("WRAM1", 0xc000, 0xcfff); // 4 KiB, Work RAM
Emu::the().addMemorySpace("WRAM2", 0xd000, 0xdfff, 7); // 4 KiB * 7 banks, Work RAM Emu::the().addMemorySpace("WRAM2", 0xd000, 0xdfff, 7); // 4 KiB * 7 banks, Work RAM
Emu::the().addMemorySpace("ECHORAM", 0xe000, 0xfdff, 1); // 7680B, Mirror of 0xc000~0xddff Emu::the().addMemorySpace("ECHORAM", 0xe000, 0xfdff); // 7680B, Mirror of 0xc000~0xddff
Emu::the().addMemorySpace("OAM", 0xfe00, 0xfe9f, 1); // 160B, Object Attribute Memory (VRAM Sprite Attribute Table) Emu::the().addMemorySpace("OAM", 0xfe00, 0xfe9f); // 160B, Object Attribute Memory (VRAM Sprite Attribute Table)
Emu::the().addMemorySpace("HRAM", 0xff80, 0xfffe, 1); // 127B, High RAM (CPU cache) Emu::the().addMemorySpace("Not Usable", 0xfea0, 0xfeff); // 96B, Nintendo probibits this area
Emu::the().addMemorySpace("IO", 0xff00, 0xff7f); // 128B, I/O Registers
Emu::the().addMemorySpace("HRAM", 0xff80, 0xfffe); // 127B, High RAM (CPU cache)
Emu::the().addMemorySpace("IE", 0xffff, 0xffff); // 1B, Interrupt Enable register
// Load bootrom // Load bootrom
auto bootrom = ruc::File("gbc_bios.bin").data(); auto bootrom = ruc::File("gbc_bios.bin").data();