Compare commits
8
Commits
2c870e89c6
...
af07357812
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af07357812 | ||
|
|
7e54c733a8 | ||
|
|
5d2ee7cbc9 | ||
|
|
2dc4da71e4 | ||
|
|
6bbc705651 | ||
|
|
5035b26f8a | ||
|
|
afedc8a30b | ||
|
|
c83d322d0c |
+177
-56
@@ -57,33 +57,45 @@ void CPU::update()
|
|||||||
m_wait_cycles--;
|
m_wait_cycles--;
|
||||||
if (m_wait_cycles <= 0) {
|
if (m_wait_cycles <= 0) {
|
||||||
// Read next opcode
|
// Read next opcode
|
||||||
uint8_t opcode = peekMemory();
|
uint8_t opcode = read(m_pc);
|
||||||
|
print("running opcode: {:#x}\n", opcode);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
|
||||||
case 0x01: ld16(); break;
|
case 0x01: ld16(); break;
|
||||||
|
case 0x02: ld8(); break;
|
||||||
|
case 0x06: ld8(); break;
|
||||||
case 0x08: ld16(); break;
|
case 0x08: ld16(); break;
|
||||||
case 0x11: ld16(); break;
|
case 0x11: ld16(); break;
|
||||||
|
case 0x12: ld8(); break;
|
||||||
|
case 0x16: ld8(); break;
|
||||||
case 0x21: ld16(); break;
|
case 0x21: ld16(); break;
|
||||||
|
case 0x22: ld8(); break;
|
||||||
|
case 0x26: ld8(); break;
|
||||||
case 0x31: ld16(); break;
|
case 0x31: ld16(); break;
|
||||||
|
case 0x32: ld8(); break;
|
||||||
|
case 0x36: ld8(); break;
|
||||||
case 0x3e: ld8(); break;
|
case 0x3e: ld8(); break;
|
||||||
|
case 0xa8: xor8(); break;
|
||||||
|
case 0xaf: xor8(); break;
|
||||||
case 0xc3: jp16(); break;
|
case 0xc3: jp16(); break;
|
||||||
case 0xc6: add(); break;
|
case 0xc6: add(); break;
|
||||||
|
case 0xcd: call(); break;
|
||||||
case 0xe0: ldh8(); break;
|
case 0xe0: ldh8(); break;
|
||||||
case 0xf0: ldh8(); break;
|
case 0xf0: ldh8(); break;
|
||||||
case 0xf8: ld16(); break;
|
case 0xf8: ld16(); break;
|
||||||
case 0xf9: ld16(); break;
|
case 0xf9: ld16(); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
print("opcode {:#x} not implemented", opcode);
|
print("opcode {:#x} not implemented\n", opcode);
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print("This is an update from the CPU\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::add()
|
void CPU::add()
|
||||||
{
|
{
|
||||||
uint8_t opcode = consumeMemory();
|
uint8_t opcode = pcRead();
|
||||||
uint8_t immediate = consumeMemory();
|
uint8_t immediate = pcRead();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0xc6:
|
case 0xc6:
|
||||||
// ADD A,d8
|
// ADD A,d8
|
||||||
@@ -99,7 +111,28 @@ void CPU::add()
|
|||||||
m_a += immediate;
|
m_a += immediate;
|
||||||
|
|
||||||
// Drop overflown bits, the 'A' register is 8-bit
|
// Drop overflown bits, the 'A' register is 8-bit
|
||||||
m_a &= 0xff;
|
m_a &= 0x00ff;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU::xor8()
|
||||||
|
{
|
||||||
|
uint8_t opcode = pcRead();
|
||||||
|
switch (opcode) {
|
||||||
|
case 0xa8:
|
||||||
|
// XOR B, flags: Z 0 0 0
|
||||||
|
m_nf = m_hf = m_cf = 0;
|
||||||
|
m_a ^= m_b;
|
||||||
|
m_zf = m_a == 0;
|
||||||
|
break;
|
||||||
|
case 0xaf:
|
||||||
|
// XOR A, flags: 1 0 0 0
|
||||||
|
// A^A will always be 0
|
||||||
|
m_a = m_nf = m_hf = m_cf = 0;
|
||||||
|
m_zf = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
@@ -108,11 +141,70 @@ void CPU::add()
|
|||||||
|
|
||||||
void CPU::ld8()
|
void CPU::ld8()
|
||||||
{
|
{
|
||||||
uint8_t opcode = consumeMemory();
|
uint8_t opcode = pcRead();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0x3e:
|
case 0x02:
|
||||||
|
// LD (BC),A
|
||||||
m_wait_cycles += 8;
|
m_wait_cycles += 8;
|
||||||
m_a = immediate8();
|
write(bc(), m_a);
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
// LD B,n
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
m_b = pcRead();
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
// LD (DE),A
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
write(de(), m_a);
|
||||||
|
break;
|
||||||
|
case 0x16:
|
||||||
|
// LD D,n
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
m_d = pcRead();
|
||||||
|
break;
|
||||||
|
case 0x22: {
|
||||||
|
// LD (HL+),A == LD (HLI),A == LDI (HL),A
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
|
||||||
|
// Put A into memory address in HL
|
||||||
|
uint32_t address = hl();
|
||||||
|
write(address, m_a);
|
||||||
|
|
||||||
|
// Increment HL
|
||||||
|
address = (address + 1) & 0xffff;
|
||||||
|
m_l = address & 0x00ff;
|
||||||
|
m_h = address >> 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x26:
|
||||||
|
// LD H,n
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
m_h = pcRead();
|
||||||
|
break;
|
||||||
|
case 0x32: {
|
||||||
|
// LD (HL-),A == LD (HLD),A == LDD (HL),A
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
|
||||||
|
// Put A into memory address in HL
|
||||||
|
uint32_t address = hl();
|
||||||
|
write(address, m_a);
|
||||||
|
|
||||||
|
// Decrement HL
|
||||||
|
address = (address - 1) & 0xffff;
|
||||||
|
m_l = address & 0x00ff;
|
||||||
|
m_h = address >> 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x36:
|
||||||
|
// LD (HL),n
|
||||||
|
m_wait_cycles += 12;
|
||||||
|
write(hl(), pcRead());
|
||||||
|
break;
|
||||||
|
case 0x3e:
|
||||||
|
// LD A,n
|
||||||
|
m_wait_cycles += 8;
|
||||||
|
m_a = pcRead();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
@@ -121,19 +213,21 @@ void CPU::ld8()
|
|||||||
|
|
||||||
void CPU::ldh8()
|
void CPU::ldh8()
|
||||||
{
|
{
|
||||||
uint8_t opcode = consumeMemory();
|
uint8_t opcode = pcRead();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0xe0:
|
case 0xe0:
|
||||||
// LD ($ff00 + n),A == LDH (n),A
|
// LD ($ff00 + n),A == LDH (n),A
|
||||||
// Put value in A into address (0xff00 + next byte in memory):
|
|
||||||
m_wait_cycles += 12;
|
m_wait_cycles += 12;
|
||||||
writeFf(m_a);
|
|
||||||
|
// Put value in A into address (0xff00 + next byte in memory)
|
||||||
|
ffWrite(pcRead(), m_a);
|
||||||
break;
|
break;
|
||||||
case 0xf0:
|
case 0xf0:
|
||||||
// LD A,($ff00 + n) == LDH A,(n)
|
// LD A,($ff00 + n) == LDH A,(n)
|
||||||
// Put value at address (0xff00 + next byte in memory) into A:
|
|
||||||
m_wait_cycles += 12;
|
m_wait_cycles += 12;
|
||||||
m_a = readFf();
|
|
||||||
|
// Put value at address (0xff00 + next byte in memory) into A
|
||||||
|
m_a = ffRead(pcRead());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
@@ -142,38 +236,50 @@ void CPU::ldh8()
|
|||||||
|
|
||||||
void CPU::ld16()
|
void CPU::ld16()
|
||||||
{
|
{
|
||||||
uint8_t opcode = consumeMemory();
|
uint8_t opcode = pcRead();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0x01: {
|
case 0x01: {
|
||||||
m_wait_cycles += 12;
|
m_wait_cycles += 12;
|
||||||
setBc(immediate16());
|
write(bc(), pcRead16());
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x11:
|
|
||||||
m_wait_cycles += 12;
|
|
||||||
setDe(immediate16());
|
|
||||||
break;
|
|
||||||
case 0x21:
|
|
||||||
m_wait_cycles += 12;
|
|
||||||
setHl(immediate16());
|
|
||||||
break;
|
|
||||||
case 0x31: {
|
|
||||||
m_wait_cycles += 12;
|
|
||||||
m_sp = immediate16();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x08: {
|
case 0x08: {
|
||||||
|
// LD (nn),SP
|
||||||
m_wait_cycles += 20;
|
m_wait_cycles += 20;
|
||||||
|
|
||||||
|
// Put value of SP into address given by next 2 bytes in memory
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf8: {
|
case 0x11:
|
||||||
|
// LD DE,nn
|
||||||
m_wait_cycles += 12;
|
m_wait_cycles += 12;
|
||||||
|
write(de(), pcRead16());
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
// LD HL,nn
|
||||||
|
m_wait_cycles += 12;
|
||||||
|
write(hl(), pcRead16());
|
||||||
|
break;
|
||||||
|
case 0x31: {
|
||||||
|
// LD SP,nn
|
||||||
|
m_wait_cycles += 12;
|
||||||
|
m_sp = pcRead16();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xf8: {
|
||||||
|
// LD HL,SP + e8 == LDHL SP,e8
|
||||||
|
m_wait_cycles += 12;
|
||||||
|
|
||||||
|
// Put SP + next (signed) byte in memory into HL
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
// Unsets ZF and NF, may enable HF and CF
|
||||||
// TODO flags
|
// TODO flags
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0xf9: {
|
case 0xf9: {
|
||||||
|
// LD SP,HL
|
||||||
m_wait_cycles += 8;
|
m_wait_cycles += 8;
|
||||||
m_sp = hl();
|
m_sp = hl();
|
||||||
break;
|
break;
|
||||||
@@ -183,13 +289,39 @@ void CPU::ld16()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPU::call()
|
||||||
|
{
|
||||||
|
uint8_t opcode = pcRead();
|
||||||
|
switch (opcode) {
|
||||||
|
case 0xcd: {
|
||||||
|
// CALL nn
|
||||||
|
m_wait_cycles += 24;
|
||||||
|
|
||||||
|
uint32_t data = pcRead16();
|
||||||
|
|
||||||
|
// Push address of next 2 bytes in memory onto stack
|
||||||
|
m_sp = (m_sp - 1) & 0xffff;
|
||||||
|
write(m_sp, data >> 8);
|
||||||
|
m_sp = (m_sp - 1) & 0xffff;
|
||||||
|
write(m_sp, data & 0x00ff);
|
||||||
|
|
||||||
|
// Jump to this address
|
||||||
|
m_pc = data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CPU::jp16()
|
void CPU::jp16()
|
||||||
{
|
{
|
||||||
uint8_t opcode = consumeMemory();
|
uint8_t opcode = pcRead();
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0xc3:
|
case 0xc3:
|
||||||
|
// JP nn
|
||||||
m_wait_cycles += 16;
|
m_wait_cycles += 16;
|
||||||
m_pc = immediate16();
|
m_pc = pcRead16();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
@@ -198,40 +330,29 @@ void CPU::jp16()
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
uint8_t CPU::peekMemory(int32_t offset) const
|
uint32_t CPU::pcRead()
|
||||||
{
|
{
|
||||||
return Emu::the().readMemory(m_pc + offset);
|
uint32_t data = Emu::the().readMemory(m_pc);
|
||||||
|
m_pc = (m_pc + 1) & 0xffff;
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CPU::consumeMemory()
|
void CPU::write(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
return Emu::the().readMemory(m_pc++);
|
Emu::the().writeMemory(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::writeFf(uint32_t value)
|
uint32_t CPU::read(uint32_t address)
|
||||||
{
|
{
|
||||||
Emu::the().writeMemory(immediate8() | (0xff << 8), value);
|
return Emu::the().readMemory(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CPU::readFf()
|
void CPU::ffWrite(uint32_t address, uint32_t value)
|
||||||
{
|
{
|
||||||
return Emu::the().readMemory(immediate8() | (0xff << 8));
|
Emu::the().writeMemory(address | (0xff << 8), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::setBc(uint32_t value)
|
uint32_t CPU::ffRead(uint32_t address)
|
||||||
{
|
{
|
||||||
m_b = value >> 8;
|
return Emu::the().readMemory(address | (0xff << 8));
|
||||||
m_c = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPU::setDe(uint32_t value)
|
|
||||||
{
|
|
||||||
m_d = value >> 8;
|
|
||||||
m_e = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPU::setHl(uint32_t value)
|
|
||||||
{
|
|
||||||
m_h = value >> 8;
|
|
||||||
m_l = value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public:
|
|||||||
|
|
||||||
// 8-bit
|
// 8-bit
|
||||||
void add();
|
void add();
|
||||||
|
void xor8();
|
||||||
|
|
||||||
// 16-bit
|
// 16-bit
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ public:
|
|||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
// Jumps and Subroutines
|
// Jumps and Subroutines
|
||||||
|
|
||||||
|
void call();
|
||||||
void jp16();
|
void jp16();
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
@@ -56,18 +58,14 @@ public:
|
|||||||
// Miscellaneous Instructions
|
// Miscellaneous Instructions
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t peekMemory(int32_t offset = 0) const;
|
uint32_t pcRead();
|
||||||
uint8_t consumeMemory();
|
uint32_t pcRead16() { return pcRead() | (pcRead() << 8); }
|
||||||
|
|
||||||
uint32_t immediate8() { return consumeMemory(); }
|
void write(uint32_t address, uint32_t value);
|
||||||
uint32_t immediate16() { return consumeMemory() | (consumeMemory() << 8); }
|
uint32_t read(uint32_t address);
|
||||||
|
|
||||||
void writeFf(uint32_t value);
|
void ffWrite(uint32_t address, uint32_t value);
|
||||||
uint32_t readFf();
|
uint32_t ffRead(uint32_t address);
|
||||||
|
|
||||||
void setBc(uint32_t value);
|
|
||||||
void setDe(uint32_t value);
|
|
||||||
void setHl(uint32_t value);
|
|
||||||
|
|
||||||
uint32_t bc() const { return m_b << 8 | m_c; }
|
uint32_t bc() const { return m_b << 8 | m_c; }
|
||||||
uint32_t de() const { return m_b << 8 | m_c; }
|
uint32_t de() const { return m_b << 8 | m_c; }
|
||||||
|
|||||||
Reference in New Issue
Block a user