Compare commits
5
Commits
6a44e48244
...
2c870e89c6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c870e89c6 | ||
|
|
e2db1598af | ||
|
|
2a234fabfd | ||
|
|
07345d0552 | ||
|
|
7689efeb44 |
@@ -14,6 +14,7 @@ AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
|
||||
+92
-14
@@ -44,13 +44,6 @@ CPU::CPU(uint32_t frequency)
|
||||
m_shared_registers.emplace("nf", &m_nf);
|
||||
m_shared_registers.emplace("hf", &m_hf);
|
||||
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()
|
||||
@@ -65,8 +58,23 @@ void CPU::update()
|
||||
if (m_wait_cycles <= 0) {
|
||||
// Read next opcode
|
||||
uint8_t opcode = peekMemory();
|
||||
VERIFY(m_opcode_lookup_table.find(opcode) != m_opcode_lookup_table.end(), "opcode {:#x} not implemented", opcode);
|
||||
m_opcode_lookup_table[opcode]();
|
||||
switch (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");
|
||||
@@ -77,11 +85,8 @@ void CPU::add()
|
||||
uint8_t opcode = consumeMemory();
|
||||
uint8_t immediate = consumeMemory();
|
||||
switch (opcode) {
|
||||
case 0xc6: // ADD A,d8
|
||||
// Program counter +2
|
||||
m_pc += 2;
|
||||
|
||||
// Clock cycles +8
|
||||
case 0xc6:
|
||||
// ADD A,d8
|
||||
m_wait_cycles += 8;
|
||||
|
||||
// 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()
|
||||
{
|
||||
uint8_t opcode = consumeMemory();
|
||||
@@ -123,6 +162,35 @@ void CPU::ld16()
|
||||
m_sp = immediate16();
|
||||
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:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
@@ -140,6 +208,16 @@ uint8_t CPU::consumeMemory()
|
||||
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)
|
||||
{
|
||||
m_b = value >> 8;
|
||||
|
||||
@@ -38,6 +38,8 @@ public:
|
||||
// Load Instructions
|
||||
|
||||
// 8-bit
|
||||
void ld8();
|
||||
void ldh8();
|
||||
|
||||
// 16-bit
|
||||
void ld16();
|
||||
@@ -45,6 +47,8 @@ public:
|
||||
// -------------------------------------
|
||||
// Jumps and Subroutines
|
||||
|
||||
void jp16();
|
||||
|
||||
// -------------------------------------
|
||||
// Stack Operations Instructions
|
||||
|
||||
@@ -55,8 +59,12 @@ private:
|
||||
uint8_t peekMemory(int32_t offset = 0) const;
|
||||
uint8_t consumeMemory();
|
||||
|
||||
uint32_t immediate8() { return consumeMemory(); }
|
||||
uint32_t immediate16() { return consumeMemory() | (consumeMemory() << 8); }
|
||||
|
||||
void writeFf(uint32_t value);
|
||||
uint32_t readFf();
|
||||
|
||||
void setBc(uint32_t value);
|
||||
void setDe(uint32_t value);
|
||||
void setHl(uint32_t value);
|
||||
@@ -83,6 +91,4 @@ private:
|
||||
uint32_t m_cf { 0 }; // Carry flag
|
||||
|
||||
int8_t m_wait_cycles { 0 };
|
||||
|
||||
std::unordered_map<uint32_t, std::function<void()>> m_opcode_lookup_table;
|
||||
};
|
||||
|
||||
+8
-5
@@ -34,12 +34,15 @@ int main(int argc, char* argv[])
|
||||
Emu::the().addMemorySpace("BOOTROM1", 0x0000, 0x00ff); // 256B
|
||||
Emu::the().addMemorySpace("BOOTROM2", 0x0200, 0x08ff); // 1792B
|
||||
Emu::the().addMemorySpace("VRAM", 0x8000, 0x9fff, 2); // 8KiB * 2 banks
|
||||
Emu::the().addMemorySpace("CARDRAM", 0xa000, 0xbfff); // 8KiB
|
||||
Emu::the().addMemorySpace("WRAM1", 0xc000, 0xcfff, 1); // 4 KiB, Work RAM
|
||||
Emu::the().addMemorySpace("CARDRAM", 0xa000, 0xbfff, 1); // 8KiB * ? banks, if any
|
||||
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("ECHORAM", 0xe000, 0xfdff, 1); // 7680B, Mirror of 0xc000~0xddff
|
||||
Emu::the().addMemorySpace("OAM", 0xfe00, 0xfe9f, 1); // 160B, Object Attribute Memory (VRAM Sprite Attribute Table)
|
||||
Emu::the().addMemorySpace("HRAM", 0xff80, 0xfffe, 1); // 127B, High RAM (CPU cache)
|
||||
Emu::the().addMemorySpace("ECHORAM", 0xe000, 0xfdff); // 7680B, Mirror of 0xc000~0xddff
|
||||
Emu::the().addMemorySpace("OAM", 0xfe00, 0xfe9f); // 160B, Object Attribute Memory (VRAM Sprite Attribute Table)
|
||||
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
|
||||
auto bootrom = ruc::File("gbc_bios.bin").data();
|
||||
|
||||
Reference in New Issue
Block a user