Implement everything for Gameboy Doctor
This commit is contained in:
parent
66c19caaee
commit
c52aa91f26
8 changed files with 136 additions and 14 deletions
|
@ -5,10 +5,10 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
enum CartridgeType : u8 {
|
enum CartridgeType : u8 {
|
||||||
ROM_ONLY = 0x00,
|
CT_ROM_ONLY = 0x00,
|
||||||
MBC1 = 0x01,
|
CT_MBC1 = 0x01,
|
||||||
MBC1_RAM = 0x02,
|
CT_MBC1_RAM = 0x02,
|
||||||
MBC1_RAM_BATTERY = 0x03,
|
CT_MBC1_RAM_BATTERY = 0x03,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Cartridge {
|
class Cartridge {
|
||||||
|
@ -28,10 +28,14 @@ public:
|
||||||
u8 operator[](size_t addr);
|
u8 operator[](size_t addr);
|
||||||
|
|
||||||
inline
|
inline
|
||||||
const char* title()
|
const char* title() const
|
||||||
{ return _title; }
|
{ return _title; }
|
||||||
|
|
||||||
inline
|
inline
|
||||||
size_t size()
|
CartridgeType type() const
|
||||||
|
{ return (CartridgeType)_data[0x147]; }
|
||||||
|
|
||||||
|
inline
|
||||||
|
size_t size() const
|
||||||
{ return _size; }
|
{ return _size; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,14 @@ u16 Cpu_state::getAF()
|
||||||
(carry ? 0x10 : 0);
|
(carry ? 0x10 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 Cpu_state::getF()
|
||||||
|
{
|
||||||
|
return (zero ? 0x80 : 0) |
|
||||||
|
(subtract ? 0x40 : 0) |
|
||||||
|
(halfcarry ? 0x20 : 0) |
|
||||||
|
(carry ? 0x10 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
u8& Cpu_state::reg8(Cpu& cpu, u8 idx)
|
u8& Cpu_state::reg8(Cpu& cpu, u8 idx)
|
||||||
{
|
{
|
||||||
switch(idx)
|
switch(idx)
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct Cpu_state {
|
||||||
|
|
||||||
void setAF(u16 v);
|
void setAF(u16 v);
|
||||||
u16 getAF();
|
u16 getAF();
|
||||||
|
u8 getF();
|
||||||
|
|
||||||
u8& reg8(Cpu& cpu, u8 idx);
|
u8& reg8(Cpu& cpu, u8 idx);
|
||||||
u16& reg16(Cpu& cpu, u8 idx);
|
u16& reg16(Cpu& cpu, u8 idx);
|
||||||
|
|
91
main.cpp
91
main.cpp
|
@ -1,4 +1,93 @@
|
||||||
|
#include <cpu/cpu.h>
|
||||||
|
#include <cartridge/cartridge.h>
|
||||||
|
#include <memory/mbc/mbc1.h>
|
||||||
|
#include <memory/ram.h>
|
||||||
|
#include <memory/bus.h>
|
||||||
|
#include <memory/register.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
return 0;
|
if(argc < 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
std::ifstream file(argv[1]);
|
||||||
|
Cartridge cart(file);
|
||||||
|
|
||||||
|
if(cart.type() != CT_MBC1)
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
RAM wram1(0x1000);
|
||||||
|
RAM wram2(0x1000);
|
||||||
|
RAM hram(0x100);
|
||||||
|
RAM oam(0x100);
|
||||||
|
|
||||||
|
MBC1 mbc1(cart);
|
||||||
|
|
||||||
|
ConstRegister ly_reg(0x90);
|
||||||
|
|
||||||
|
Bus b;
|
||||||
|
b.map_device(0x0000, 0x7FFF, &mbc1);
|
||||||
|
b.map_device(0xA000, 0xBFFF, &mbc1, 0xA000);
|
||||||
|
b.map_device(0xC000, 0xCFFF, &wram1);
|
||||||
|
b.map_device(0xD000, 0xDFFF, &wram2);
|
||||||
|
b.map_device(0xE000, 0xFDFF, &wram1);
|
||||||
|
b.map_device(0xFE00, 0xFE9F, &oam);
|
||||||
|
b.map_device(0xFF44, 0xFF44, &ly_reg);
|
||||||
|
b.map_device(0xFF80, 0xFFFE, &hram);
|
||||||
|
|
||||||
|
Cpu cpu(&b);
|
||||||
|
|
||||||
|
BoundRegister ie_mapped(cpu.state.IE);
|
||||||
|
BoundRegister if_mapped(cpu.state.IF);
|
||||||
|
b.map_device(0xFFFF, 0xFFFF, &ie_mapped);
|
||||||
|
b.map_device(0xFF0F, 0xFF0F, &ie_mapped);
|
||||||
|
|
||||||
|
cpu.state.A = 0x1;
|
||||||
|
cpu.state.carry = true;
|
||||||
|
cpu.state.halfcarry = true;
|
||||||
|
cpu.state.subtract = false;
|
||||||
|
cpu.state.zero = true;
|
||||||
|
|
||||||
|
cpu.state.B = 0x00;
|
||||||
|
cpu.state.C = 0x13;
|
||||||
|
cpu.state.D = 0x00;
|
||||||
|
cpu.state.E = 0xD8;
|
||||||
|
cpu.state.H = 0x01;
|
||||||
|
cpu.state.L = 0x4D;
|
||||||
|
|
||||||
|
cpu.state.SP = 0xFFFE;
|
||||||
|
cpu.state.PC = 0x100;
|
||||||
|
|
||||||
|
const std::chrono::milliseconds delay(1);
|
||||||
|
|
||||||
|
while(!cpu.state.stopped)
|
||||||
|
{
|
||||||
|
std::cout
|
||||||
|
<< "A:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.A
|
||||||
|
<< " F:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.getF()
|
||||||
|
<< " B:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.B
|
||||||
|
<< " C:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.C
|
||||||
|
<< " D:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.D
|
||||||
|
<< " E:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.E
|
||||||
|
<< " H:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.H
|
||||||
|
<< " L:" << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << (unsigned)cpu.state.L
|
||||||
|
<< " SP:" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << (unsigned)cpu.state.SP
|
||||||
|
<< " PC:" << std::setfill('0') << std::setw(4) << std::hex << std::uppercase << (unsigned)cpu.state.PC
|
||||||
|
<< " PCMEM:"
|
||||||
|
<< std::setw(2) << std::hex << std::uppercase << (unsigned)b.read8(cpu.state.PC) << ","
|
||||||
|
<< std::setw(2) << std::hex << std::uppercase << (unsigned)b.read8(cpu.state.PC+1) << ","
|
||||||
|
<< std::setw(2) << std::hex << std::uppercase << (unsigned)b.read8(cpu.state.PC+2) << ","
|
||||||
|
<< std::setw(2) << std::hex << std::uppercase << (unsigned)b.read8(cpu.state.PC+3) << std::endl;
|
||||||
|
|
||||||
|
cpu.step();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(delay);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ std::optional<Bus::MapEntry> Bus::find_entry(u16 addr)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::map_device(u16 start, u16 end, Mem_device* dev)
|
void Bus::map_device(u16 start, u16 end, Mem_device* dev, u16 offset)
|
||||||
{
|
{
|
||||||
map.push_back(Bus::MapEntry{ Range(start,end), dev });
|
map.push_back(Bus::MapEntry{ Range(start,end), offset, dev });
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::write8(u16 addr, u8 data)
|
void Bus::write8(u16 addr, u8 data)
|
||||||
|
@ -24,7 +24,7 @@ void Bus::write8(u16 addr, u8 data)
|
||||||
|
|
||||||
if(!mapentry) return;
|
if(!mapentry) return;
|
||||||
|
|
||||||
mapentry->dev->write8(addr - mapentry->range.start, data);
|
mapentry->dev->write8(addr - mapentry->range.start + mapentry->offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Bus::read8(u16 addr)
|
u8 Bus::read8(u16 addr)
|
||||||
|
@ -33,19 +33,19 @@ u8 Bus::read8(u16 addr)
|
||||||
|
|
||||||
if(!mapentry) return 0xFFu;
|
if(!mapentry) return 0xFFu;
|
||||||
|
|
||||||
return mapentry->dev->read8(addr - mapentry->range.start);
|
return mapentry->dev->read8(addr - mapentry->range.start + mapentry->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bus::write16(u16 addr, u16 data)
|
void Bus::write16(u16 addr, u16 data)
|
||||||
{
|
{
|
||||||
auto mapentry = find_entry(addr);
|
auto mapentry = find_entry(addr);
|
||||||
if(!mapentry) return;
|
if(!mapentry) return;
|
||||||
mapentry->dev->write16(addr - mapentry->range.start, data);
|
mapentry->dev->write16(addr - mapentry->range.start + mapentry->offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 Bus::read16(u16 addr)
|
u16 Bus::read16(u16 addr)
|
||||||
{
|
{
|
||||||
auto mapentry = find_entry(addr);
|
auto mapentry = find_entry(addr);
|
||||||
if(!mapentry) return 0xFFFFu;
|
if(!mapentry) return 0xFFFFu;
|
||||||
return mapentry->dev->read16(addr - mapentry->range.start);
|
return mapentry->dev->read16(addr - mapentry->range.start + mapentry->offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ class Bus : public Mem_device {
|
||||||
private:
|
private:
|
||||||
struct MapEntry {
|
struct MapEntry {
|
||||||
Range range;
|
Range range;
|
||||||
|
u16 offset;
|
||||||
Mem_device *dev;
|
Mem_device *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ private:
|
||||||
public:
|
public:
|
||||||
Bus();
|
Bus();
|
||||||
|
|
||||||
void map_device(u16 start, u16 end, Mem_device* dev);
|
void map_device(u16 start, u16 end, Mem_device* dev, u16 offset = 0x0);
|
||||||
|
|
||||||
virtual void write8(u16 addr, u8 data);
|
virtual void write8(u16 addr, u8 data);
|
||||||
virtual u8 read8(u16 addr);
|
virtual u8 read8(u16 addr);
|
||||||
|
|
|
@ -11,3 +11,9 @@ u8 BoundRegister::read8(u16 addr)
|
||||||
if(addr) return 0xFF;
|
if(addr) return 0xFF;
|
||||||
return reg;
|
return reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConstRegister::write8(u16 addr, u8 data)
|
||||||
|
{}
|
||||||
|
|
||||||
|
u8 ConstRegister::read8(u16 addr)
|
||||||
|
{ return value; }
|
||||||
|
|
|
@ -15,3 +15,16 @@ public:
|
||||||
virtual void write8(u16 addr, u8 data);
|
virtual void write8(u16 addr, u8 data);
|
||||||
virtual u8 read8(u16 addr);
|
virtual u8 read8(u16 addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ConstRegister : public Mem_device {
|
||||||
|
private:
|
||||||
|
u8 value;
|
||||||
|
public:
|
||||||
|
inline
|
||||||
|
ConstRegister(u8 value)
|
||||||
|
: value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual void write8(u16 addr, u8 data);
|
||||||
|
virtual u8 read8(u16 addr);
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in a new issue