Update to v099r12 release.

byuu says:

Changelog:
- fixed FC AxROM / VRC7 regression
- BitField split to BooleanBitField/NaturalBitField (in preparation
  for IntegerBitField)
- BitFieldReference removed
- GB CPU cleaned up
- GB Cartridge + Mappers cleaned up
- SFC CGRAM is now emulated as uint15[256] instead of uint[512]
- sfc/ppu/memory.cpp no longer needed; removed
- purged SFC Debugger hooks for now (some of the operator[] calls were
  bypassing them anyway)

Unfortunately, for reasons that defy all semblance of logic, the CGRAM
change caused a slight speed hit. As have the last few changes. We're
now down to around 129.5fps compared to 123.fps for v099 and 134.5fps
at our peak (v099r01-r02).

I really like the style I came up with for the Game Boy mappers to settle
the purpose(ROM,RAM) vs (rom,ram)Purpose naming convention. If I ever get
around to redoing the NES mappers, that's likely the approach I'll take.
This commit is contained in:
Tim Allen 2016-06-28 20:43:47 +10:00
parent 3e807946b8
commit 7a68059f78
74 changed files with 781 additions and 923 deletions

View File

@ -11,7 +11,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "099.11";
static const string Version = "099.12";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -23,7 +23,7 @@ struct KonamiVRC7 : Board {
return chrram.read(vrc7.addrCHR(addr));
}
auto chr_write(uint addr, uint8 data) -> void {
auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.addrCIRAM(addr), data);
return chrram.write(vrc7.addrCHR(addr), data);
}

View File

@ -24,7 +24,7 @@ struct NES_AxROM : Board {
return Board::readCHR(addr);
}
auto chr_write(uint addr, uint8 data) -> void {
auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM((mirrorSelect << 10) | (addr & 0x03ff), data);
return Board::writeCHR(addr, data);
}

View File

@ -106,25 +106,23 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
//PPUSCROLL
case 5:
if(!r.v.latch) {
if(r.v.latch++ == 0) {
r.v.fineX = data.bits(0,2);
r.t.tileX = data.bits(3,7);
} else {
r.t.fineY = data.bits(0,2);
r.t.tileY = data.bits(3,7);
}
r.v.latch ^= 1;
break;
//PPUADDR
case 6:
if(!r.v.latch) {
if(r.v.latch++ == 0) {
r.t.addressHi = data.bits(0,5);
} else {
r.t.addressLo = data.bits(0,7);
r.v.address = r.t.address;
}
r.v.latch ^= 1;
break;
//PPUDATA

View File

@ -44,7 +44,7 @@ auto PPU::scanline() -> void {
}
auto PPU::frame() -> void {
r.field ^= 1;
r.field++;
scheduler.exit(Scheduler::Event::Frame);
}

View File

@ -35,7 +35,7 @@ struct PPU : Thread {
//internal
uint8 mdr;
bool field;
uint1 field;
uint lx;
uint ly;
@ -43,17 +43,17 @@ struct PPU : Thread {
union {
uint value;
BitField<uint, 0, 4> tileX;
BitField<uint, 5, 9> tileY;
BitField<uint,10,11> nametable;
BitField<uint, 10> nametableX;
BitField<uint, 11> nametableY;
BitField<uint,12,14> fineY;
BitField<uint, 0,14> address;
BitField<uint, 0, 7> addressLo;
BitField<uint, 8,14> addressHi;
BitField<uint, 15> latch;
BitField<uint,16,18> fineX;
NaturalBitField<uint, 0, 4> tileX;
NaturalBitField<uint, 5, 9> tileY;
NaturalBitField<uint,10,11> nametable;
NaturalBitField<uint,10,10> nametableX;
NaturalBitField<uint,11,11> nametableY;
NaturalBitField<uint,12,14> fineY;
NaturalBitField<uint, 0,14> address;
NaturalBitField<uint, 0, 7> addressLo;
NaturalBitField<uint, 8,14> addressHi;
NaturalBitField<uint,15,15> latch;
NaturalBitField<uint,16,18> fineX;
} v, t;
bool nmiHold;

View File

@ -105,8 +105,8 @@ auto PPU::renderScanline() -> void {
renderPixel();
step(1);
if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
if(enable() && tile == 31 && ++r.v.fineY == 0 && ++r.v.tileY == 30) r.v.nametableY ^= 1, r.v.tileY = 0;
if(enable() && ++r.v.tileX == 0) r.v.nametableX++;
if(enable() && tile == 31 && ++r.v.fineY == 0 && ++r.v.tileY == 30) r.v.nametableY++, r.v.tileY = 0;
renderPixel();
renderSprite();
step(1);
@ -179,7 +179,7 @@ auto PPU::renderScanline() -> void {
if(r.v.tileX & 2) attribute >>= 2;
step(1);
if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
if(enable() && ++r.v.tileX == 0) r.v.nametableX++;
step(1);
uint tiledataLo = loadCHR(tileaddr + 0);

View File

@ -78,7 +78,7 @@ auto APU::power() -> void {
for(auto& n : wave.pattern) n = r();
}
auto APU::mmio_read(uint16 addr) -> uint8 {
auto APU::readIO(uint16 addr) -> uint8 {
if(addr >= 0xff10 && addr <= 0xff14) return square1.read(addr);
if(addr >= 0xff15 && addr <= 0xff19) return square2.read(addr);
if(addr >= 0xff1a && addr <= 0xff1e) return wave.read(addr);
@ -88,7 +88,7 @@ auto APU::mmio_read(uint16 addr) -> uint8 {
return 0xff;
}
auto APU::mmio_write(uint16 addr, uint8 data) -> void {
auto APU::writeIO(uint16 addr, uint8 data) -> void {
if(!sequencer.enable) {
bool valid = addr == 0xff26; //NR52
if(!system.cgb()) {

View File

@ -6,8 +6,8 @@ struct APU : Thread, MMIO {
auto hipass(int16& sample, int64& bias) -> void;
auto power() -> void;
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto serialize(serializer&) -> void;

View File

@ -40,6 +40,7 @@ auto Cartridge::load(System::Revision revision) -> bool {
} else return false;
auto document = BML::unserialize(information.manifest);
auto board = document["board"];
information.title = document["information/title"].text();
auto mapperid = document["board/mapper"].text();
@ -56,29 +57,24 @@ auto Cartridge::load(System::Revision revision) -> bool {
information.rtc = false;
information.rumble = false;
auto rom = document["board/rom"];
auto ram = document["board/ram"];
rom.size = max(32768u, board["rom/size"].natural());
rom.data = (uint8*)memory::allocate(rom.size, 0xff);
romsize = max(32768u, rom["size"].natural());
romdata = allocate<uint8>(romsize, 0xff);
ram.size = board["ram/size"].natural();
ram.data = (uint8*)memory::allocate(ram.size, 0xff);
ramsize = ram["size"].natural();
ramdata = allocate<uint8>(ramsize, 0xff);
if(auto name = rom["name"].text()) {
if(auto name = board["rom/name"].text()) {
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
fp->read(romdata, min(romsize, fp->size()));
fp->read(rom.data, min(rom.size, fp->size()));
}
}
if(auto name = ram["name"].text()) {
if(auto name = board["ram/name"].text()) {
if(auto fp = interface->open(pathID(), name, File::Read, File::Optional)) {
fp->read(ramdata, min(ramsize, fp->size()));
fp->read(ram.data, min(ram.size, fp->size()));
}
}
information.romsize = romsize;
information.ramsize = ramsize;
information.battery = (bool)ram["name"];
information.battery = (bool)board["ram/name"];
switch(information.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;
@ -92,7 +88,7 @@ auto Cartridge::load(System::Revision revision) -> bool {
case Mapper::HuC3: mapper = &huc3; break;
}
information.sha256 = Hash::SHA256(romdata, romsize).digest();
information.sha256 = Hash::SHA256(rom.data, rom.size).digest();
return true;
}
@ -101,42 +97,44 @@ auto Cartridge::save() -> void {
if(auto name = document["board/ram/name"].text()) {
if(auto fp = interface->open(pathID(), name, File::Write)) {
fp->write(ramdata, ramsize);
fp->write(ram.data, ram.size);
}
}
}
auto Cartridge::unload() -> void {
if(romdata) { delete[] romdata; romdata = nullptr; romsize = 0; }
if(ramdata) { delete[] ramdata; ramdata = nullptr; ramsize = 0; }
delete[] rom.data;
delete[] ram.data;
rom = {};
ram = {};
}
auto Cartridge::rom_read(uint addr) -> uint8 {
if(addr >= romsize) addr %= romsize;
return romdata[addr];
auto Cartridge::readROM(uint addr) -> uint8 {
if(addr >= rom.size) addr %= rom.size;
return rom.data[addr];
}
auto Cartridge::rom_write(uint addr, uint8 data) -> void {
if(addr >= romsize) addr %= romsize;
romdata[addr] = data;
auto Cartridge::writeROM(uint addr, uint8 data) -> void {
if(addr >= rom.size) addr %= rom.size;
rom.data[addr] = data;
}
auto Cartridge::ram_read(uint addr) -> uint8 {
if(ramsize == 0) return 0xff;
if(addr >= ramsize) addr %= ramsize;
return ramdata[addr];
auto Cartridge::readRAM(uint addr) -> uint8 {
if(ram.size == 0) return 0xff;
if(addr >= ram.size) addr %= ram.size;
return ram.data[addr];
}
auto Cartridge::ram_write(uint addr, uint8 data) -> void {
if(ramsize == 0) return;
if(addr >= ramsize) addr %= ramsize;
ramdata[addr] = data;
auto Cartridge::writeRAM(uint addr, uint8 data) -> void {
if(ram.size == 0) return;
if(addr >= ram.size) addr %= ram.size;
ram.data[addr] = data;
}
auto Cartridge::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::readIO(uint16 addr) -> uint8 {
if(addr == 0xff50) return 0xff;
if(bootrom_enable) {
if(bootromEnable) {
const uint8* data = nullptr;
switch(system.revision()) { default:
case System::Revision::GameBoy: data = system.bootROM.dmg; break;
@ -147,20 +145,20 @@ auto Cartridge::mmio_read(uint16 addr) -> uint8 {
if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256];
}
return mapper->mmio_read(addr);
return mapper->readIO(addr);
}
auto Cartridge::mmio_write(uint16 addr, uint8 data) -> void {
if(bootrom_enable && addr == 0xff50) {
bootrom_enable = false;
auto Cartridge::writeIO(uint16 addr, uint8 data) -> void {
if(bootromEnable && addr == 0xff50) {
bootromEnable = false;
return;
}
mapper->mmio_write(addr, data);
mapper->writeIO(addr, data);
}
auto Cartridge::power() -> void {
bootrom_enable = true;
bootromEnable = true;
mbc0.power();
mbc1.power();

View File

@ -8,13 +8,14 @@ struct Cartridge : MMIO {
auto save() -> void;
auto unload() -> void;
auto rom_read(uint addr) -> uint8;
auto rom_write(uint addr, uint8 data) -> void;
auto ram_read(uint addr) -> uint8;
auto ram_write(uint addr, uint8 data) -> void;
auto readROM(uint addr) -> uint8;
auto writeROM(uint addr, uint8 data) -> void;
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readRAM(uint addr) -> uint8;
auto writeRAM(uint addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
@ -54,19 +55,15 @@ struct Cartridge : MMIO {
boolean battery;
boolean rtc;
boolean rumble;
uint romsize = 0;
uint ramsize = 0;
} information;
uint8* romdata = nullptr;
uint romsize = 0;
uint8* ramdata = nullptr;
uint ramsize = 0;
struct Memory {
uint8* data = nullptr;
uint size = 0;
} rom, ram;
MMIO* mapper = nullptr;
bool bootrom_enable = true;
bool bootromEnable = true;
};
extern Cartridge cartridge;

View File

@ -1,50 +1,49 @@
auto Cartridge::HuC1::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::HuC1::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select << 14 | (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return cartridge.readRAM(ram.select << 13 | (uint13)addr);
}
return 0xff;
}
auto Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::HuC1::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_writable = (data & 0x0f) == 0x0a;
ram.writable = data.bits(0,3) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
if(rom_select == 0) rom_select = 1;
rom.select = data + (data == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
ram.select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
model = data & 0x01;
model = data.bit(0);
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_writable == false) return;
return cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
if(!ram.writable) return;
return cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
}
}
auto Cartridge::HuC1::power() -> void {
ram_writable = false;
rom_select = 0x01;
ram_select = 0x00;
rom.select = 0x01;
ram.writable = false;
ram.select = 0x00;
model = 0;
}

View File

@ -1,10 +1,14 @@
struct HuC1 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_writable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool model; //$6000-7fff
struct ROM {
uint8 select;
} rom;
struct RAM {
bool writable;
uint8 select;
} ram;
bool model;
} huc1;

View File

@ -1,33 +1,33 @@
auto Cartridge::HuC3::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::HuC3::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select << 14 | (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr);
return 0x01; //does not return open collection
}
return 0xff;
}
auto Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::HuC3::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
ram.enable = data.bits(0,3) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
rom.select = data;
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
ram.select = data;
return;
}
@ -37,13 +37,13 @@ auto Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) -> void {
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
return;
}
}
auto Cartridge::HuC3::power() -> void {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
rom.select = 0x01;
ram.enable = false;
ram.select = 0x00;
}

View File

@ -1,9 +1,13 @@
struct HuC3 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
struct ROM {
uint8 select;
} rom;
struct RAM {
bool enable;
uint8 select;
} ram;
} huc3;

View File

@ -1,18 +1,18 @@
auto Cartridge::MBC0::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC0::readIO(uint16 addr) -> uint8 {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read(addr & 0x1fff);
return cartridge.readRAM((uint13)addr);
}
return 0xff;
}
auto Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC0::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram_write(addr & 0x1fff, data);
cartridge.writeRAM((uint13)addr, data);
return;
}
}

View File

@ -1,5 +1,5 @@
struct MBC0 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
} mbc0;

View File

@ -1,22 +1,22 @@
auto Cartridge::MBC1::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC1::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
if(mode == 0) {
return cartridge.readROM(ram.select << 19 | rom.select << 14 | (uint14)addr);
} else {
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select << 14 | (uint14)addr);
}
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
if(ram.enable) {
if(mode == 0) {
return cartridge.readRAM((uint13)addr);
} else {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return cartridge.readRAM(ram.select << 13 | (uint13)addr);
}
}
return 0xff;
@ -25,33 +25,33 @@ auto Cartridge::MBC1::mmio_read(uint16 addr) -> uint8 {
return 0xff;
}
auto Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC1::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
ram.enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
rom.select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x03;
ram.select = data & 0x03;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
mode_select = data & 0x01;
mode = data & 0x01;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);
if(ram.enable) {
if(mode == 0) {
cartridge.writeRAM(addr & 0x1fff, data);
} else {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
}
}
return;
@ -59,8 +59,8 @@ auto Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) -> void {
}
auto Cartridge::MBC1::power() -> void {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
mode_select = 0;
rom.select = 0x01;
ram.enable = false;
ram.select = 0x00;
mode = 0;
}

View File

@ -1,10 +1,14 @@
struct MBC1 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool mode_select; //$6000-7fff
struct ROM {
uint8 select;
} rom;
struct RAM {
bool enable;
uint8 select;
} ram;
bool mode;
} mbc1;

View File

@ -1,40 +1,40 @@
auto Cartridge::MBC1M::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC1M::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
if(!modeSelect) return cartridge.rom_read(addr & 0x3fff);
return cartridge.rom_read((romHi << 4) * 0x4000 + (addr & 0x3fff));
if(mode == 0) return cartridge.readROM((uint14)addr);
return cartridge.readROM(rom.hi << 18 | (uint14)addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((romHi << 4 | romLo) * 0x4000 + (addr & 0x3fff));
return cartridge.readROM(rom.hi << 18 | rom.lo << 14 | (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read(addr & 0x1fff);
return cartridge.readRAM((uint13)addr);
}
return 0xff;
}
auto Cartridge::MBC1M::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC1M::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
romLo = data.bits(0,3);
rom.lo = data.bits(0,3);
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
romHi = data.bits(0,1);
rom.hi = data.bits(0,1);
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
modeSelect = data.bit(0);
mode = data.bit(0);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram_write(addr & 0x1fff, data);
cartridge.writeRAM((uint13)addr, data);
}
}
auto Cartridge::MBC1M::power() -> void {
romHi = 0;
romLo = 1;
modeSelect = 0;
rom.lo = 1;
rom.hi = 0;
mode = 0;
}

View File

@ -1,9 +1,11 @@
struct MBC1M : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
uint4 romLo;
uint2 romHi;
uint1 modeSelect;
struct ROM {
uint4 lo;
uint2 hi;
} rom;
uint1 mode;
} mbc1m;

View File

@ -1,38 +1,38 @@
auto Cartridge::MBC2::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC2::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select << 14 | (uint14)addr);
}
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
if(ram.enable) return cartridge.readRAM((uint9)addr);
return 0xff;
}
return 0xff;
}
auto Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC2::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
if(!addr.bit(8)) ram.enable = data.bits(0,3) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
if( addr.bit(8)) rom.select = data.bits(0,3) + (data.bits(0,3) == 0);
return;
}
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
if(ram.enable) cartridge.writeRAM((uint9)addr, data.bits(0,3));
return;
}
}
auto Cartridge::MBC2::power() -> void {
ram_enable = false;
rom_select = 0x01;
rom.select = 0x01;
ram.enable = false;
}

View File

@ -1,8 +1,12 @@
struct MBC2 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
struct ROM {
uint8 select;
} rom;
struct RAM {
bool enable;
} ram;
} mbc2;

View File

@ -1,14 +1,14 @@
auto Cartridge::MBC3::second() -> void {
if(rtc_halt == false) {
if(++rtc_second >= 60) {
rtc_second = 0;
if(++rtc_minute >= 60) {
rtc_minute = 0;
if(++rtc_hour >= 24) {
rtc_hour = 0;
if(++rtc_day >= 512) {
rtc_day = 0;
rtc_day_carry = true;
if(!rtc.halt) {
if(++rtc.second >= 60) {
rtc.second = 0;
if(++rtc.minute >= 60) {
rtc.minute = 0;
if(++rtc.hour >= 24) {
rtc.hour = 0;
if(++rtc.day >= 512) {
rtc.day = 0;
rtc.dayCarry = true;
}
}
}
@ -16,25 +16,25 @@ auto Cartridge::MBC3::second() -> void {
}
}
auto Cartridge::MBC3::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC3::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select<< 14 | (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
if(ram.enable) {
if(ram.select <= 0x03) {
return cartridge.readRAM(ram.select << 13 | (uint13)addr);
}
if(ram_select == 0x08) return rtc_latch_second;
if(ram_select == 0x09) return rtc_latch_minute;
if(ram_select == 0x0a) return rtc_latch_hour;
if(ram_select == 0x0b) return rtc_latch_day;
if(ram_select == 0x0c) return (rtc_latch_day_carry << 7) | (rtc_latch_day >> 8);
if(ram.select == 0x08) return rtc.latchSecond;
if(ram.select == 0x09) return rtc.latchMinute;
if(ram.select == 0x0a) return rtc.latchHour;
if(ram.select == 0x0b) return rtc.latchDay;
if(ram.select == 0x0c) return rtc.latchDayCarry << 7 | rtc.latchDay >> 8;
}
return 0xff;
}
@ -42,53 +42,53 @@ auto Cartridge::MBC3::mmio_read(uint16 addr) -> uint8 {
return 0xff;
}
auto Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC3::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
ram.enable = (data & 0x0f) == 0x0a;
return;
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
rom.select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
ram.select = data;
return;
}
if((addr & 0xe000) == 0x6000) { //$6000-7fff
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
rtc_latch_hour = rtc_hour;
rtc_latch_day = rtc_day;
rtc_latch_day_carry = rtc_day_carry;
if(rtc.latch == 0 && data == 1) {
rtc.latchSecond = rtc.second;
rtc.latchMinute = rtc.minute;
rtc.latchHour = rtc.hour;
rtc.latchDay = rtc.day;
rtc.latchDayCarry = rtc.dayCarry;
}
rtc_latch = data;
rtc.latch = data;
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
} else if(ram_select == 0x08) {
if(ram.enable) {
if(ram.select <= 0x03) {
cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
} else if(ram.select == 0x08) {
if(data >= 60) data = 0;
rtc_second = data;
} else if(ram_select == 0x09) {
rtc.second = data;
} else if(ram.select == 0x09) {
if(data >= 60) data = 0;
rtc_minute = data;
} else if(ram_select == 0x0a) {
rtc.minute = data;
} else if(ram.select == 0x0a) {
if(data >= 24) data = 0;
rtc_hour = data;
} else if(ram_select == 0x0b) {
rtc_day = (rtc_day & 0x0100) | data;
} else if(ram_select == 0x0c) {
rtc_day = ((data & 1) << 8) | (rtc_day & 0xff);
rtc_halt = data & 0x40;
rtc_day_carry = data & 0x80;
rtc.hour = data;
} else if(ram.select == 0x0b) {
rtc.day = (rtc.day & 0x0100) | data;
} else if(ram.select == 0x0c) {
rtc.day = ((data & 1) << 8) | (rtc.day & 0xff);
rtc.halt = data & 0x40;
rtc.dayCarry = data & 0x80;
}
}
return;
@ -96,21 +96,23 @@ auto Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) -> void {
}
auto Cartridge::MBC3::power() -> void {
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
rtc_latch = 0;
rom.select = 0x01;
rtc_halt = true;
rtc_second = 0;
rtc_minute = 0;
rtc_hour = 0;
rtc_day = 0;
rtc_day_carry = false;
ram.enable = false;
ram.select = 0x00;
rtc_latch_second = 0;
rtc_latch_minute = 0;
rtc_latch_hour = 0;
rtc_latch_day = 0;
rtc_latch_day_carry = false;
rtc.latch = 0;
rtc.halt = true;
rtc.second = 0;
rtc.minute = 0;
rtc.hour = 0;
rtc.day = 0;
rtc.dayCarry = false;
rtc.latchSecond = 0;
rtc.latchMinute = 0;
rtc.latchHour = 0;
rtc.latchDay = 0;
rtc.latchDayCarry = false;
}

View File

@ -1,24 +1,30 @@
struct MBC3 : MMIO {
auto second() -> void;
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool rtc_latch; //$6000-7fff
struct ROM {
uint8 select;
} rom;
struct RAM {
bool enable;
uint8 select;
} ram;
struct RTC {
bool latch;
bool rtc_halt;
uint rtc_second;
uint rtc_minute;
uint rtc_hour;
uint rtc_day;
bool rtc_day_carry;
bool halt;
uint second;
uint minute;
uint hour;
uint day;
bool dayCarry;
uint rtc_latch_second;
uint rtc_latch_minute;
uint rtc_latch_hour;
uint rtc_latch_day;
uint rtc_latch_day_carry;
uint latchSecond;
uint latchMinute;
uint latchHour;
uint latchDay;
uint latchDayCarry;
} rtc;
} mbc3;

View File

@ -1,49 +1,49 @@
auto Cartridge::MBC5::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MBC5::readIO(uint16 addr) -> uint8 {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
return cartridge.readROM(rom.select << 14 | (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr);
return 0xff;
}
return 0xff;
}
auto Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MBC5::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
ram.enable = data.bits(0,3) == 0x0a;
return;
}
if((addr & 0xf000) == 0x2000) { //$2000-2fff
rom_select = (rom_select & 0x0100) | data;
rom.select.byte(0) = data;
return;
}
if((addr & 0xf000) == 0x3000) { //$3000-3fff
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
rom.select.byte(1) = data.bit(0);
return;
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x0f;
ram.select = data.bits(0,3);
return;
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
return;
}
}
auto Cartridge::MBC5::power() -> void {
ram_enable = false;
rom_select = 0x001;
ram_select = 0x00;
rom.select = 0x001;
ram.enable = false;
ram.select = 0x00;
}

View File

@ -1,9 +1,13 @@
struct MBC5 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool ram_enable; //$0000-1fff
uint16 rom_select; //$2000-2fff + $3000-3fff
uint8 ram_select; //$4000-5fff
struct ROM {
uint9 select;
} rom;
struct RAM {
bool enable;
uint4 select;
} ram;
} mbc5;

View File

@ -1,44 +1,44 @@
auto Cartridge::MMM01::mmio_read(uint16 addr) -> uint8 {
auto Cartridge::MMM01::readIO(uint16 addr) -> uint8 {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
if(rom_mode == 0) return cartridge.rom_read(addr);
if(mode == 0) return cartridge.readROM(addr);
}
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
return cartridge.readROM(0x8000 + (rom.base << 14) + (uint14)addr);
}
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
return cartridge.readROM(0x8000 + (rom.base << 14) + (rom.select<< 14) + (uint14)addr);
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
if(ram.enable) return cartridge.readRAM(ram.select << 13 | (uint13)addr);
return 0xff;
}
return 0xff;
}
auto Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) -> void {
auto Cartridge::MMM01::writeIO(uint16 addr, uint8 data) -> void {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(rom_mode == 0) {
rom_mode = 1;
if(mode == 0) {
mode = 1;
} else {
ram_enable = (data & 0x0f) == 0x0a;
ram.enable= data.bits(0,3) == 0x0a;
}
}
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if(rom_mode == 0) {
rom_base = data & 0x3f;
if(mode == 0) {
rom.base = data.bits(0,5);
} else {
rom_select = data;
rom.select = data;
}
}
if((addr & 0xe000) == 0x4000) { //$4000-5fff
if(rom_mode == 1) {
ram_select = data;
if(mode == 1) {
ram.select = data;
}
}
@ -47,15 +47,14 @@ auto Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) -> void {
}
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
if(ram.enable) cartridge.writeRAM(ram.select << 13 | (uint13)addr, data);
}
}
auto Cartridge::MMM01::power() -> void {
rom_mode = 0;
rom_base = 0;
ram_enable = false;
rom_select = 0x01;
ram_select = 0x00;
rom.base = 0x00;
rom.select = 0x01;
ram.enable = false;
ram.select = 0x00;
mode = 0;
}

View File

@ -1,12 +1,15 @@
struct MMM01 : MMIO {
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
auto power() -> void;
bool rom_mode;
uint8 rom_base;
bool ram_enable;
uint8 rom_select;
uint8 ram_select;
struct ROM {
uint6 base;
uint8 select;
} rom;
struct RAM {
bool enable;
uint8 select;
} ram;
bool mode;
} mmm01;

View File

@ -1,54 +1,51 @@
auto Cartridge::serialize(serializer& s) -> void {
if(information.battery) s.array(ramdata, ramsize);
s.integer(bootrom_enable);
if(information.battery) s.array(ram.data, ram.size);
s.integer(bootromEnable);
s.integer(mbc1.ram_enable);
s.integer(mbc1.rom_select);
s.integer(mbc1.ram_select);
s.integer(mbc1.mode_select);
s.integer(mbc1.rom.select);
s.integer(mbc1.ram.enable);
s.integer(mbc1.ram.select);
s.integer(mbc1.mode);
s.integer(mbc1m.romLo);
s.integer(mbc1m.romHi);
s.integer(mbc1m.modeSelect);
s.integer(mbc1m.rom.lo);
s.integer(mbc1m.rom.hi);
s.integer(mbc1m.mode);
s.integer(mbc2.ram_enable);
s.integer(mbc2.rom_select);
s.integer(mbc2.rom.select);
s.integer(mbc2.ram.enable);
s.integer(mbc3.ram_enable);
s.integer(mbc3.rom_select);
s.integer(mbc3.ram_select);
s.integer(mbc3.rtc_latch);
s.integer(mbc3.rom.select);
s.integer(mbc3.ram.enable);
s.integer(mbc3.ram.select);
s.integer(mbc3.rtc.latch);
s.integer(mbc3.rtc.halt);
s.integer(mbc3.rtc.second);
s.integer(mbc3.rtc.minute);
s.integer(mbc3.rtc.hour);
s.integer(mbc3.rtc.day);
s.integer(mbc3.rtc.dayCarry);
s.integer(mbc3.rtc.latchSecond);
s.integer(mbc3.rtc.latchMinute);
s.integer(mbc3.rtc.latchHour);
s.integer(mbc3.rtc.latchDay);
s.integer(mbc3.rtc.latchDayCarry);
s.integer(mbc3.rtc_halt);
s.integer(mbc3.rtc_second);
s.integer(mbc3.rtc_minute);
s.integer(mbc3.rtc_hour);
s.integer(mbc3.rtc_day);
s.integer(mbc3.rtc_day_carry);
s.integer(mbc5.rom.select);
s.integer(mbc5.ram.enable);
s.integer(mbc5.ram.select);
s.integer(mbc3.rtc_latch_second);
s.integer(mbc3.rtc_latch_minute);
s.integer(mbc3.rtc_latch_hour);
s.integer(mbc3.rtc_latch_day);
s.integer(mbc3.rtc_latch_day_carry);
s.integer(mmm01.rom.base);
s.integer(mmm01.rom.select);
s.integer(mmm01.ram.enable);
s.integer(mmm01.ram.select);
s.integer(mmm01.mode);
s.integer(mbc5.ram_enable);
s.integer(mbc5.rom_select);
s.integer(mbc5.ram_select);
s.integer(mmm01.rom_mode);
s.integer(mmm01.rom_base);
s.integer(mmm01.ram_enable);
s.integer(mmm01.rom_select);
s.integer(mmm01.ram_select);
s.integer(huc1.ram_writable);
s.integer(huc1.rom_select);
s.integer(huc1.ram_select);
s.integer(huc1.rom.select);
s.integer(huc1.ram.writable);
s.integer(huc1.ram.select);
s.integer(huc1.model);
s.integer(huc3.ram_enable);
s.integer(huc3.rom_select);
s.integer(huc3.ram_select);
s.integer(huc3.rom.select);
s.integer(huc3.ram.enable);
s.integer(huc3.ram.select);
}

View File

@ -13,72 +13,72 @@ auto CPU::Enter() -> void {
}
auto CPU::main() -> void {
interrupt_test();
interruptTest();
instruction();
}
auto CPU::raise(CPU::Interrupt id) -> void {
if(id == Interrupt::Vblank) {
status.interrupt_request_vblank = 1;
if(status.interrupt_enable_vblank) r.halt = false;
status.interruptRequestVblank = 1;
if(status.interruptEnableVblank) r.halt = false;
}
if(id == Interrupt::Stat) {
status.interrupt_request_stat = 1;
if(status.interrupt_enable_stat) r.halt = false;
status.interruptRequestStat = 1;
if(status.interruptEnableStat) r.halt = false;
}
if(id == Interrupt::Timer) {
status.interrupt_request_timer = 1;
if(status.interrupt_enable_timer) r.halt = false;
status.interruptRequestTimer = 1;
if(status.interruptEnableTimer) r.halt = false;
}
if(id == Interrupt::Serial) {
status.interrupt_request_serial = 1;
if(status.interrupt_enable_serial) r.halt = false;
status.interruptRequestSerial = 1;
if(status.interruptEnableSerial) r.halt = false;
}
if(id == Interrupt::Joypad) {
status.interrupt_request_joypad = 1;
if(status.interrupt_enable_joypad) r.halt = r.stop = false;
status.interruptRequestJoypad = 1;
if(status.interruptEnableJoypad) r.halt = r.stop = false;
}
}
auto CPU::interrupt_test() -> void {
auto CPU::interruptTest() -> void {
if(!r.ime) return;
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
status.interrupt_request_vblank = 0;
if(status.interruptRequestVblank && status.interruptEnableVblank) {
status.interruptRequestVblank = 0;
return interrupt(0x0040);
}
if(status.interrupt_request_stat && status.interrupt_enable_stat) {
status.interrupt_request_stat = 0;
if(status.interruptRequestStat && status.interruptEnableStat) {
status.interruptRequestStat = 0;
return interrupt(0x0048);
}
if(status.interrupt_request_timer && status.interrupt_enable_timer) {
status.interrupt_request_timer = 0;
if(status.interruptRequestTimer && status.interruptEnableTimer) {
status.interruptRequestTimer = 0;
return interrupt(0x0050);
}
if(status.interrupt_request_serial && status.interrupt_enable_serial) {
status.interrupt_request_serial = 0;
if(status.interruptRequestSerial && status.interruptEnableSerial) {
status.interruptRequestSerial = 0;
return interrupt(0x0058);
}
if(status.interrupt_request_joypad && status.interrupt_enable_joypad) {
status.interrupt_request_joypad = 0;
if(status.interruptRequestJoypad && status.interruptEnableJoypad) {
status.interruptRequestJoypad = 0;
return interrupt(0x0060);
}
}
auto CPU::stop() -> bool {
if(status.speed_switch) {
status.speed_switch = 0;
status.speed_double ^= 1;
if(status.speed_double == 0) frequency = 4 * 1024 * 1024;
if(status.speed_double == 1) frequency = 8 * 1024 * 1024;
if(status.speedSwitch) {
status.speedSwitch = 0;
status.speedDouble ^= 1;
if(status.speedDouble == 0) frequency = 4 * 1024 * 1024;
if(status.speedDouble == 1) frequency = 8 * 1024 * 1024;
return true;
}
return false;
@ -130,57 +130,9 @@ auto CPU::power() -> void {
r[DE] = 0x0000;
r[HL] = 0x0000;
status.clock = 0;
status.p15 = 0;
status.p14 = 0;
status.joyp = 0;
status.mlt_req = 0;
status.serial_data = 0;
status.serial_bits = 0;
status.serial_transfer = 0;
status.serial_clock = 0;
status.div = 0;
status.tima = 0;
status.tma = 0;
status.timer_enable = 0;
status.timer_clock = 0;
status.interrupt_request_joypad = 0;
status.interrupt_request_serial = 0;
status.interrupt_request_timer = 0;
status.interrupt_request_stat = 0;
status.interrupt_request_vblank = 0;
status.speed_double = 0;
status.speed_switch = 0;
status.dma_source = 0;
status.dma_target = 0;
status.dma_mode = 0;
status.dma_length = 0;
status.dma_completed = true;
status.ff6c = 0;
status.ff72 = 0;
status.ff73 = 0;
status.ff74 = 0;
status.ff75 = 0;
status.wram_bank = 1;
status.interrupt_enable_joypad = 0;
status.interrupt_enable_serial = 0;
status.interrupt_enable_timer = 0;
status.interrupt_enable_stat = 0;
status.interrupt_enable_vblank = 0;
memory::fill(&status, sizeof(Status));
status.dmaCompleted = true;
status.wramBank = 1;
}
}

View File

@ -4,34 +4,34 @@ struct CPU : Processor::LR35902, Thread, MMIO {
static auto Enter() -> void;
auto main() -> void;
auto raise(Interrupt id) -> void;
auto interrupt_test() -> void;
auto interruptTest() -> void;
auto stop() -> bool;
auto power() -> void;
auto serialize(serializer&) -> void;
//mmio.cpp
auto wram_addr(uint16 addr) const -> uint;
auto mmio_joyp_poll() -> void;
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto wramAddress(uint16 addr) const -> uint;
auto joypPoll() -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
//memory.cpp
auto io() -> void override;
auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override;
auto cycle_edge() -> void;
auto dma_read(uint16 addr) -> uint8;
auto dma_write(uint16 addr, uint8 data) -> void;
auto debugger_read(uint16 addr) -> uint8;
auto cycleEdge() -> void;
auto readDMA(uint16 addr) -> uint8;
auto writeDMA(uint16 addr, uint8 data) -> void;
auto readDebugger(uint16 addr) -> uint8;
//timing.cpp
auto add_clocks(uint clocks) -> void;
auto timer_262144hz() -> void;
auto timer_65536hz() -> void;
auto timer_16384hz() -> void;
auto timer_8192hz() -> void;
auto timer_4096hz() -> void;
auto step(uint clocks) -> void;
auto timer262144hz() -> void;
auto timer65536hz() -> void;
auto timer16384hz() -> void;
auto timer8192hz() -> void;
auto timer4096hz() -> void;
auto hblank() -> void;
struct Status {
@ -41,15 +41,15 @@ struct CPU : Processor::LR35902, Thread, MMIO {
bool p15;
bool p14;
uint8 joyp;
uint8 mlt_req;
uint8 mltReq;
//$ff01 SB
uint8 serial_data;
uint serial_bits;
uint8 serialData;
uint serialBits;
//$ff02 SC
bool serial_transfer;
bool serial_clock;
bool serialTransfer;
bool serialClock;
//$ff04 DIV
uint16 div;
@ -61,36 +61,36 @@ struct CPU : Processor::LR35902, Thread, MMIO {
uint8 tma;
//$ff07 TAC
bool timer_enable;
uint timer_clock;
bool timerEnable;
uint timerClock;
//$ff0f IF
bool interrupt_request_joypad;
bool interrupt_request_serial;
bool interrupt_request_timer;
bool interrupt_request_stat;
bool interrupt_request_vblank;
bool interruptRequestJoypad;
bool interruptRequestSerial;
bool interruptRequestTimer;
bool interruptRequestStat;
bool interruptRequestVblank;
//$ff4d KEY1
bool speed_double;
bool speed_switch;
bool speedDouble;
bool speedSwitch;
//$ff51,$ff52 HDMA1,HDMA2
uint16 dma_source;
uint16 dmaSource;
//$ff53,$ff54 HDMA3,HDMA4
uint16 dma_target;
uint16 dmaTarget;
//$ff55 HDMA5
bool dma_mode;
uint16 dma_length;
bool dma_completed;
bool dmaMode;
uint16 dmaLength;
bool dmaCompleted;
//$ff6c ???
uint8 ff6c;
//$ff70 SVBK
uint3 wram_bank;
uint3 wramBank;
//$ff72-$ff75 ???
uint8 ff72;
@ -99,11 +99,11 @@ struct CPU : Processor::LR35902, Thread, MMIO {
uint8 ff75;
//$ffff IE
bool interrupt_enable_joypad;
bool interrupt_enable_serial;
bool interrupt_enable_timer;
bool interrupt_enable_stat;
bool interrupt_enable_vblank;
bool interruptEnableJoypad;
bool interruptEnableSerial;
bool interruptEnableTimer;
bool interruptEnableStat;
bool interruptEnableVblank;
} status;
uint8 wram[32768]; //GB=8192, GBC=32768

View File

@ -1,21 +1,21 @@
auto CPU::io() -> void {
cycle_edge();
add_clocks(4);
cycleEdge();
step(4);
}
auto CPU::read(uint16 addr) -> uint8 {
cycle_edge();
add_clocks(4);
cycleEdge();
step(4);
return bus.read(addr);
}
auto CPU::write(uint16 addr, uint8 data) -> void {
cycle_edge();
add_clocks(4);
cycleEdge();
step(4);
bus.write(addr, data);
}
auto CPU::cycle_edge() -> void {
auto CPU::cycleEdge() -> void {
if(r.ei) {
r.ei = false;
r.ime = 1;
@ -23,7 +23,7 @@ auto CPU::cycle_edge() -> void {
}
//VRAM DMA source can only be ROM or RAM
auto CPU::dma_read(uint16 addr) -> uint8 {
auto CPU::readDMA(uint16 addr) -> uint8 {
if(addr < 0x8000) return bus.read(addr); //0000-7fff
if(addr < 0xa000) return 0xff; //8000-9fff
if(addr < 0xe000) return bus.read(addr); //a000-dfff
@ -31,11 +31,11 @@ auto CPU::dma_read(uint16 addr) -> uint8 {
}
//VRAM DMA target is always VRAM
auto CPU::dma_write(uint16 addr, uint8 data) -> void {
auto CPU::writeDMA(uint16 addr, uint8 data) -> void {
addr = 0x8000 | (addr & 0x1fff); //8000-9fff
return bus.write(addr, data);
}
auto CPU::debugger_read(uint16 addr) -> uint8 {
auto CPU::readDebugger(uint16 addr) -> uint8 {
return bus.read(addr);
}

View File

@ -1,11 +1,11 @@
auto CPU::wram_addr(uint16 addr) const -> uint {
auto CPU::wramAddress(uint16 addr) const -> uint {
addr &= 0x1fff;
if(addr < 0x1000) return addr;
auto bank = status.wram_bank + (status.wram_bank == 0);
auto bank = status.wramBank + (status.wramBank == 0);
return (bank * 0x1000) + (addr & 0x0fff);
}
auto CPU::mmio_joyp_poll() -> void {
auto CPU::joypPoll() -> void {
uint button = 0, dpad = 0;
button |= interface->inputPoll(0, 0, (uint)Input::Start) << 3;
@ -26,18 +26,18 @@ auto CPU::mmio_joyp_poll() -> void {
}
status.joyp = 0x0f;
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mltReq;
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
if(status.joyp != 0x0f) raise(Interrupt::Joypad);
}
auto CPU::mmio_read(uint16 addr) -> uint8 {
if(addr >= 0xc000 && addr <= 0xfdff) return wram[wram_addr(addr)];
auto CPU::readIO(uint16 addr) -> uint8 {
if(addr >= 0xc000 && addr <= 0xfdff) return wram[wramAddress(addr)];
if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f];
if(addr == 0xff00) { //JOYP
mmio_joyp_poll();
joypPoll();
return 0xc0
| (status.p15 << 5)
| (status.p14 << 4)
@ -49,9 +49,9 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
}
if(addr == 0xff02) { //SC
return (status.serial_transfer << 7)
return (status.serialTransfer << 7)
| 0x7e
| (status.serial_clock << 0);
| (status.serialClock << 0);
}
if(addr == 0xff04) { //DIV
@ -68,26 +68,26 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
if(addr == 0xff07) { //TAC
return 0xf8
| (status.timer_enable << 2)
| (status.timer_clock << 0);
| (status.timerEnable << 2)
| (status.timerClock << 0);
}
if(addr == 0xff0f) { //IF
return 0xe0
| (status.interrupt_request_joypad << 4)
| (status.interrupt_request_serial << 3)
| (status.interrupt_request_timer << 2)
| (status.interrupt_request_stat << 1)
| (status.interrupt_request_vblank << 0);
| (status.interruptRequestJoypad << 4)
| (status.interruptRequestSerial << 3)
| (status.interruptRequestTimer << 2)
| (status.interruptRequestStat << 1)
| (status.interruptRequestVblank << 0);
}
if(addr == 0xff4d) { //KEY1
return (status.speed_double << 7);
return (status.speedDouble << 7);
}
if(addr == 0xff55) { //HDMA5
return (status.dma_completed << 7)
| (((status.dma_length / 16) - 1) & 0x7f);
return (status.dmaCompleted << 7)
| (((status.dmaLength / 16) - 1) & 0x7f);
}
if(addr == 0xff56) { //RP
@ -99,7 +99,7 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
}
if(addr == 0xff70) { //SVBK
return status.wram_bank;
return status.wramBank;
}
if(addr == 0xff72) { //???
@ -128,18 +128,18 @@ auto CPU::mmio_read(uint16 addr) -> uint8 {
if(addr == 0xffff) { //IE
return 0xe0
| (status.interrupt_enable_joypad << 4)
| (status.interrupt_enable_serial << 3)
| (status.interrupt_enable_timer << 2)
| (status.interrupt_enable_stat << 1)
| (status.interrupt_enable_vblank << 0);
| (status.interruptEnableJoypad << 4)
| (status.interruptEnableSerial << 3)
| (status.interruptEnableTimer << 2)
| (status.interruptEnableStat << 1)
| (status.interruptEnableVblank << 0);
}
return 0xff;
}
auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
if(addr >= 0xc000 && addr <= 0xfdff) { wram[wram_addr(addr)] = data; return; }
auto CPU::writeIO(uint16 addr, uint8 data) -> void {
if(addr >= 0xc000 && addr <= 0xfdff) { wram[wramAddress(addr)] = data; return; }
if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; }
if(addr == 0xff00) { //JOYP
@ -150,14 +150,14 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
}
if(addr == 0xff01) { //SB
status.serial_data = data;
status.serialData = data;
return;
}
if(addr == 0xff02) { //SC
status.serial_transfer = data & 0x80;
status.serial_clock = data & 0x01;
if(status.serial_transfer) status.serial_bits = 8;
status.serialTransfer = data & 0x80;
status.serialClock = data & 0x01;
if(status.serialTransfer) status.serialBits = 8;
return;
}
@ -177,58 +177,58 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
}
if(addr == 0xff07) { //TAC
status.timer_enable = data & 0x04;
status.timer_clock = data & 0x03;
status.timerEnable = data & 0x04;
status.timerClock = data & 0x03;
return;
}
if(addr == 0xff0f) { //IF
status.interrupt_request_joypad = data & 0x10;
status.interrupt_request_serial = data & 0x08;
status.interrupt_request_timer = data & 0x04;
status.interrupt_request_stat = data & 0x02;
status.interrupt_request_vblank = data & 0x01;
status.interruptRequestJoypad = data & 0x10;
status.interruptRequestSerial = data & 0x08;
status.interruptRequestTimer = data & 0x04;
status.interruptRequestStat = data & 0x02;
status.interruptRequestVblank = data & 0x01;
return;
}
if(addr == 0xff4d) { //KEY1
status.speed_switch = data & 0x01;
status.speedSwitch = data & 0x01;
return;
}
if(addr == 0xff51) { //HDMA1
status.dma_source = (status.dma_source & 0x00ff) | (data << 8);
status.dmaSource = (status.dmaSource & 0x00ff) | (data << 8);
return;
}
if(addr == 0xff52) { //HDMA2
status.dma_source = (status.dma_source & 0xff00) | (data & 0xf0);
status.dmaSource = (status.dmaSource & 0xff00) | (data & 0xf0);
return;
}
if(addr == 0xff53) { //HDMA3
status.dma_target = (status.dma_target & 0x00ff) | (data << 8);
status.dmaTarget = (status.dmaTarget & 0x00ff) | (data << 8);
return;
}
if(addr == 0xff54) { //HDMA4
status.dma_target = (status.dma_target & 0xff00) | (data & 0xf0);
status.dmaTarget = (status.dmaTarget & 0xff00) | (data & 0xf0);
return;
}
if(addr == 0xff55) { //HDMA5
status.dma_mode = data & 0x80;
status.dma_length = ((data & 0x7f) + 1) * 16;
status.dma_completed = !status.dma_mode;
status.dmaMode = data & 0x80;
status.dmaLength = ((data & 0x7f) + 1) * 16;
status.dmaCompleted = !status.dmaMode;
if(status.dma_mode == 0) {
if(status.dmaMode == 0) {
do {
for(auto n : range(16)) {
dma_write(status.dma_target++, dma_read(status.dma_source++));
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++));
}
add_clocks(8 << status.speed_double);
status.dma_length -= 16;
} while(status.dma_length);
step(8 << status.speedDouble);
status.dmaLength -= 16;
} while(status.dmaLength);
}
return;
}
@ -263,16 +263,16 @@ auto CPU::mmio_write(uint16 addr, uint8 data) -> void {
}
if(addr == 0xff70) { //SVBK
status.wram_bank = data & 0x07;
status.wramBank = data & 0x07;
return;
}
if(addr == 0xffff) { //IE
status.interrupt_enable_joypad = data & 0x10;
status.interrupt_enable_serial = data & 0x08;
status.interrupt_enable_timer = data & 0x04;
status.interrupt_enable_stat = data & 0x02;
status.interrupt_enable_vblank = data & 0x01;
status.interruptEnableJoypad = data & 0x10;
status.interruptEnableSerial = data & 0x08;
status.interruptEnableTimer = data & 0x04;
status.interruptEnableStat = data & 0x02;
status.interruptEnableVblank = data & 0x01;
return;
}
}

View File

@ -10,47 +10,47 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(status.p15);
s.integer(status.p14);
s.integer(status.joyp);
s.integer(status.mlt_req);
s.integer(status.mltReq);
s.integer(status.serial_data);
s.integer(status.serial_bits);
s.integer(status.serialData);
s.integer(status.serialBits);
s.integer(status.serial_transfer);
s.integer(status.serial_clock);
s.integer(status.serialTransfer);
s.integer(status.serialClock);
s.integer(status.div);
s.integer(status.tima);
s.integer(status.tma);
s.integer(status.timer_enable);
s.integer(status.timer_clock);
s.integer(status.timerEnable);
s.integer(status.timerClock);
s.integer(status.interrupt_request_joypad);
s.integer(status.interrupt_request_serial);
s.integer(status.interrupt_request_timer);
s.integer(status.interrupt_request_stat);
s.integer(status.interrupt_request_vblank);
s.integer(status.interruptRequestJoypad);
s.integer(status.interruptRequestSerial);
s.integer(status.interruptRequestTimer);
s.integer(status.interruptRequestStat);
s.integer(status.interruptRequestVblank);
s.integer(status.speed_double);
s.integer(status.speed_switch);
s.integer(status.speedDouble);
s.integer(status.speedSwitch);
s.integer(status.dma_source);
s.integer(status.dma_target);
s.integer(status.dma_mode);
s.integer(status.dma_length);
s.integer(status.dma_completed);
s.integer(status.dmaSource);
s.integer(status.dmaTarget);
s.integer(status.dmaMode);
s.integer(status.dmaLength);
s.integer(status.dmaCompleted);
s.integer(status.ff6c);
s.integer(status.wram_bank);
s.integer(status.wramBank);
s.integer(status.ff72);
s.integer(status.ff73);
s.integer(status.ff74);
s.integer(status.ff75);
s.integer(status.interrupt_enable_joypad);
s.integer(status.interrupt_enable_serial);
s.integer(status.interrupt_enable_timer);
s.integer(status.interrupt_enable_stat);
s.integer(status.interrupt_enable_vblank);
s.integer(status.interruptEnableJoypad);
s.integer(status.interruptEnableSerial);
s.integer(status.interruptEnableTimer);
s.integer(status.interruptEnableStat);
s.integer(status.interruptEnableVblank);
}

View File

@ -2,7 +2,7 @@
// 456 clocks/scanline
// 154 scanlines/frame
auto CPU::add_clocks(uint clocks) -> void {
auto CPU::step(uint clocks) -> void {
for(auto n : range(clocks)) {
if(++status.clock == 0) {
cartridge.mbc3.second();
@ -10,11 +10,11 @@ auto CPU::add_clocks(uint clocks) -> void {
//4MHz / N(hz) - 1 = mask
status.div++;
if((status.div & 15) == 0) timer_262144hz();
if((status.div & 63) == 0) timer_65536hz();
if((status.div & 255) == 0) timer_16384hz();
if((status.div & 511) == 0) timer_8192hz();
if((status.div & 1023) == 0) timer_4096hz();
if((status.div & 15) == 0) timer262144hz();
if((status.div & 63) == 0) timer65536hz();
if((status.div & 255) == 0) timer16384hz();
if((status.div & 511) == 0) timer8192hz();
if((status.div & 1023) == 0) timer4096hz();
ppu.clock -= ppu.frequency;
if(ppu.clock < 0) co_switch(ppu.thread);
@ -29,8 +29,8 @@ auto CPU::add_clocks(uint clocks) -> void {
}
}
auto CPU::timer_262144hz() -> void {
if(status.timer_enable && status.timer_clock == 1) {
auto CPU::timer262144hz() -> void {
if(status.timerEnable && status.timerClock == 1) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
@ -38,8 +38,8 @@ auto CPU::timer_262144hz() -> void {
}
}
auto CPU::timer_65536hz() -> void {
if(status.timer_enable && status.timer_clock == 2) {
auto CPU::timer65536hz() -> void {
if(status.timerEnable && status.timerClock == 2) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
@ -47,8 +47,8 @@ auto CPU::timer_65536hz() -> void {
}
}
auto CPU::timer_16384hz() -> void {
if(status.timer_enable && status.timer_clock == 3) {
auto CPU::timer16384hz() -> void {
if(status.timerEnable && status.timerClock == 3) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
@ -56,17 +56,17 @@ auto CPU::timer_16384hz() -> void {
}
}
auto CPU::timer_8192hz() -> void {
if(status.serial_transfer && status.serial_clock) {
if(--status.serial_bits == 0) {
status.serial_transfer = 0;
auto CPU::timer8192hz() -> void {
if(status.serialTransfer && status.serialClock) {
if(--status.serialBits == 0) {
status.serialTransfer = 0;
raise(Interrupt::Serial);
}
}
}
auto CPU::timer_4096hz() -> void {
if(status.timer_enable && status.timer_clock == 0) {
auto CPU::timer4096hz() -> void {
if(status.timerEnable && status.timerClock == 0) {
if(++status.tima == 0) {
status.tima = status.tma;
raise(Interrupt::Timer);
@ -75,11 +75,11 @@ auto CPU::timer_4096hz() -> void {
}
auto CPU::hblank() -> void {
if(status.dma_mode == 1 && status.dma_length && ppu.status.ly < 144) {
if(status.dmaMode == 1 && status.dmaLength && ppu.status.ly < 144) {
for(auto n : range(16)) {
dma_write(status.dma_target++, dma_read(status.dma_source++));
writeDMA(status.dmaTarget++, readDMA(status.dmaSource++));
}
add_clocks(8 << status.speed_double);
status.dma_length -= 16;
step(8 << status.speedDouble);
status.dmaLength -= 16;
}
}

View File

@ -36,7 +36,7 @@ auto Memory::free() -> void {
//
auto Bus::read(uint16 addr) -> uint8 {
uint8 data = mmio[addr]->mmio_read(addr);
uint8 data = mmio[addr]->readIO(addr);
if(cheat.enable()) {
if(auto result = cheat.find(addr, data)) return result();
@ -46,7 +46,7 @@ auto Bus::read(uint16 addr) -> uint8 {
}
auto Bus::write(uint16 addr, uint8 data) -> void {
mmio[addr]->mmio_write(addr, data);
mmio[addr]->writeIO(addr, data);
}
auto Bus::power() -> void {

View File

@ -11,13 +11,13 @@ struct Memory {
};
struct MMIO {
virtual auto mmio_read(uint16 addr) -> uint8 = 0;
virtual auto mmio_write(uint16 addr, uint8 data) -> void = 0;
virtual auto readIO(uint16 addr) -> uint8 = 0;
virtual auto writeIO(uint16 addr, uint8 data) -> void = 0;
};
struct Unmapped : MMIO {
auto mmio_read(uint16) -> uint8 { return 0xff; }
auto mmio_write(uint16, uint8) -> void {}
auto readIO(uint16) -> uint8 { return 0xff; }
auto writeIO(uint16, uint8) -> void {}
};
struct Bus {

View File

@ -2,7 +2,7 @@ auto PPU::vram_addr(uint16 addr) const -> uint {
return (status.vram_bank * 0x2000) + (addr & 0x1fff);
}
auto PPU::mmio_read(uint16 addr) -> uint8 {
auto PPU::readIO(uint16 addr) -> uint8 {
if(addr >= 0x8000 && addr <= 0x9fff) {
return vram[vram_addr(addr)];
}
@ -100,7 +100,7 @@ auto PPU::mmio_read(uint16 addr) -> uint8 {
return 0xff; //should never occur
}
auto PPU::mmio_write(uint16 addr, uint8 data) -> void {
auto PPU::writeIO(uint16 addr, uint8 data) -> void {
if(addr >= 0x8000 && addr <= 0x9fff) {
vram[vram_addr(addr)] = data;
return;

View File

@ -79,8 +79,8 @@ auto PPU::wait(uint clocks) -> void {
stat();
if(status.dma_active) {
uint hi = status.dma_clock++;
uint lo = hi & (cpu.status.speed_double ? 1 : 3);
hi >>= cpu.status.speed_double ? 1 : 2;
uint lo = hi & (cpu.status.speedDouble ? 1 : 3);
hi >>= cpu.status.speedDouble ? 1 : 2;
if(lo == 0) {
if(hi == 0) {
//warm-up

View File

@ -13,8 +13,8 @@ struct PPU : Thread, MMIO {
//mmio.cpp
auto vram_addr(uint16 addr) const -> uint;
auto mmio_read(uint16 addr) -> uint8;
auto mmio_write(uint16 addr, uint8 data) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;
//dmg.cpp
auto dmg_read_tile(bool select, uint x, uint y, uint& data) -> void;

View File

@ -21,14 +21,14 @@ struct GPR {
struct PSR {
union {
uint32_t data = 0;
BitField<uint32_t, 31> n; //negative
BitField<uint32_t, 30> z; //zero
BitField<uint32_t, 29> c; //carry
BitField<uint32_t, 28> v; //overflow
BitField<uint32_t, 7> i; //irq
BitField<uint32_t, 6> f; //fiq
BitField<uint32_t, 5> t; //thumb
BitField<uint32_t, 4, 0> m; //mode
BooleanBitField<uint32_t, 31> n; //negative
BooleanBitField<uint32_t, 30> z; //zero
BooleanBitField<uint32_t, 29> c; //carry
BooleanBitField<uint32_t, 28> v; //overflow
BooleanBitField<uint32_t, 7> i; //irq
BooleanBitField<uint32_t, 6> f; //fiq
BooleanBitField<uint32_t, 5> t; //thumb
NaturalBitField<uint32_t, 4, 0> m; //mode
};
PSR() = default;

View File

@ -36,19 +36,19 @@ struct Register {
struct SFR {
union {
uint16_t data = 0;
BitField<uint16_t, 15> irq; //interrupt flag
BitField<uint16_t, 12> b; //with flag
BitField<uint16_t, 11> ih; //immediate higher 8-bit flag
BitField<uint16_t, 10> il; //immediate lower 8-bit flag
BitField<uint16_t, 9> alt2; //alt2 instruction mode
BitField<uint16_t, 8> alt1; //alt1 instruction mode
BitField<uint16_t, 6> r; //ROM r14 read flag
BitField<uint16_t, 5> g; //go flag
BitField<uint16_t, 4> ov; //overflow flag
BitField<uint16_t, 3> s; //sign flag
BitField<uint16_t, 2> cy; //carry flag
BitField<uint16_t, 1> z; //zero flag
BitField<uint16_t, 9, 8> alt; //instruction mode (composite flag)
BooleanBitField<uint16_t, 15> irq; //interrupt flag
BooleanBitField<uint16_t, 12> b; //with flag
BooleanBitField<uint16_t, 11> ih; //immediate higher 8-bit flag
BooleanBitField<uint16_t, 10> il; //immediate lower 8-bit flag
BooleanBitField<uint16_t, 9> alt2; //alt2 instruction mode
BooleanBitField<uint16_t, 8> alt1; //alt1 instruction mode
BooleanBitField<uint16_t, 6> r; //ROM r14 read flag
BooleanBitField<uint16_t, 5> g; //go flag
BooleanBitField<uint16_t, 4> ov; //overflow flag
BooleanBitField<uint16_t, 3> s; //sign flag
BooleanBitField<uint16_t, 2> cy; //carry flag
BooleanBitField<uint16_t, 1> z; //zero flag
NaturalBitField<uint16_t, 9, 8> alt; //instruction mode (composite flag)
};
inline operator uint() const { return data & 0x9f7e; }

View File

@ -1,12 +1,12 @@
struct Flags {
union {
uint8_t data = 0;
BitField<uint8_t, 7> n;
BitField<uint8_t, 6> v;
BitField<uint8_t, 3> d;
BitField<uint8_t, 2> i;
BitField<uint8_t, 1> z;
BitField<uint8_t, 0> c;
BooleanBitField<uint8_t, 7> n;
BooleanBitField<uint8_t, 6> v;
BooleanBitField<uint8_t, 3> d;
BooleanBitField<uint8_t, 2> i;
BooleanBitField<uint8_t, 1> z;
BooleanBitField<uint8_t, 0> c;
};
inline operator uint() { return data; }
@ -26,8 +26,8 @@ struct Registers {
struct Register16 {
union {
uint16_t w;
BitField<uint16_t, 0, 7> l;
BitField<uint16_t, 8, 15> h;
NaturalBitField<uint16_t, 0, 7> l;
NaturalBitField<uint16_t, 8, 15> h;
};
} abs, iabs;

View File

@ -4,7 +4,7 @@ auto R65816::dreadb(uint24 addr) -> uint8 {
//do not read MMIO registers within debugger
return 0x00;
}
return disassemblerRead(addr);
return readDisassembler(addr);
}
auto R65816::dreadw(uint24 addr) -> uint16 {

View File

@ -12,11 +12,11 @@ namespace Processor {
#define L lastCycle();
#define call(op) (this->*op)()
#include "opcode_read.cpp"
#include "opcode_write.cpp"
#include "opcode_rmw.cpp"
#include "opcode_pc.cpp"
#include "opcode_misc.cpp"
#include "instructions-read.cpp"
#include "instructions-write.cpp"
#include "instructions-rmw.cpp"
#include "instructions-pc.cpp"
#include "instructions-misc.cpp"
#include "switch.cpp"
//immediate, 2-cycle opcodes with I/O cycle will become bus read

View File

@ -20,7 +20,7 @@ struct R65816 {
virtual auto interruptPending() const -> bool = 0;
virtual auto interrupt() -> void;
virtual auto disassemblerRead(uint24 addr) -> uint8 { return 0; }
virtual auto readDisassembler(uint24 addr) -> uint8 { return 0; }
//r65816.cpp
alwaysinline auto ioIRQ() -> void;

View File

@ -1,14 +1,14 @@
struct Flags {
union {
uint8_t b = 0;
BitField<uint8_t, 7> n;
BitField<uint8_t, 6> v;
BitField<uint8_t, 5> m;
BitField<uint8_t, 4> x;
BitField<uint8_t, 3> d;
BitField<uint8_t, 2> i;
BitField<uint8_t, 1> z;
BitField<uint8_t, 0> c;
BooleanBitField<uint8_t, 7> n;
BooleanBitField<uint8_t, 6> v;
BooleanBitField<uint8_t, 5> m;
BooleanBitField<uint8_t, 4> x;
BooleanBitField<uint8_t, 3> d;
BooleanBitField<uint8_t, 2> i;
BooleanBitField<uint8_t, 1> z;
BooleanBitField<uint8_t, 0> c;
};
inline operator uint() const { return b; }
@ -20,8 +20,8 @@ struct Flags {
struct Reg16 {
union {
uint16_t w = 0;
BitField<uint16_t, 0, 7> l;
BitField<uint16_t, 8, 15> h;
NaturalBitField<uint16_t, 0, 7> l;
NaturalBitField<uint16_t, 8, 15> h;
};
inline operator uint() const { return w; }
@ -41,10 +41,10 @@ struct Reg16 {
struct Reg24 {
union {
uint32_t d = 0;
BitField<uint32_t, 0, 7> l;
BitField<uint32_t, 8, 15> h;
BitField<uint32_t, 16, 23> b;
BitField<uint32_t, 0, 15> w;
NaturalBitField<uint32_t, 0, 7> l;
NaturalBitField<uint32_t, 8, 15> h;
NaturalBitField<uint32_t, 16, 23> b;
NaturalBitField<uint32_t, 0, 15> w;
};
inline operator uint() const { return d; }

View File

@ -1,6 +1,6 @@
auto SPC700::disassemble(uint16 addr, bool p) -> string {
auto read = [&](uint16 addr) -> uint8 {
return disassemblerRead(addr);
return readDisassembler(addr);
};
auto relative = [&](uint length, int8 offset) -> uint16 {

View File

@ -1,14 +1,14 @@
struct Flags {
union {
uint8_t data = 0;
BitField<uint8_t, 7> n;
BitField<uint8_t, 6> v;
BitField<uint8_t, 5> p;
BitField<uint8_t, 4> b;
BitField<uint8_t, 3> h;
BitField<uint8_t, 2> i;
BitField<uint8_t, 1> z;
BitField<uint8_t, 0> c;
BooleanBitField<uint8_t, 7> n;
BooleanBitField<uint8_t, 6> v;
BooleanBitField<uint8_t, 5> p;
BooleanBitField<uint8_t, 4> b;
BooleanBitField<uint8_t, 3> h;
BooleanBitField<uint8_t, 2> i;
BooleanBitField<uint8_t, 1> z;
BooleanBitField<uint8_t, 0> c;
};
inline operator uint() const { return data; }
@ -21,8 +21,8 @@ struct Flags {
struct Register {
union {
uint16_t w = 0;
BitField<uint16_t, 0, 7> l;
BitField<uint16_t, 8, 15> h;
NaturalBitField<uint16_t, 0, 7> l;
NaturalBitField<uint16_t, 8, 15> h;
};
inline operator uint() const { return w; }

View File

@ -6,7 +6,7 @@ struct SPC700 {
virtual auto io() -> void = 0;
virtual auto read(uint16 addr) -> uint8 = 0;
virtual auto write(uint16 addr, uint8 data) -> void = 0;
virtual auto disassemblerRead(uint16 addr) -> uint8 = 0;
virtual auto readDisassembler(uint16 addr) -> uint8 = 0;
auto instruction() -> void;

View File

@ -35,12 +35,12 @@ struct uPD96050 {
struct Flag {
union {
uint8_t data = 0;
BitField<uint8_t, 5> s1;
BitField<uint8_t, 4> s0;
BitField<uint8_t, 3> c;
BitField<uint8_t, 2> z;
BitField<uint8_t, 1> ov1;
BitField<uint8_t, 0> ov0;
BooleanBitField<uint8_t, 5> s1;
BooleanBitField<uint8_t, 4> s0;
BooleanBitField<uint8_t, 3> c;
BooleanBitField<uint8_t, 2> z;
BooleanBitField<uint8_t, 1> ov1;
BooleanBitField<uint8_t, 0> ov0;
};
inline operator uint() const { return data & 0x3f; }
@ -51,17 +51,17 @@ struct uPD96050 {
struct Status {
union {
uint16_t data = 0;
BitField<uint16_t, 15> rqm;
BitField<uint16_t, 14> usf1;
BitField<uint16_t, 13> usf0;
BitField<uint16_t, 12> drs;
BitField<uint16_t, 11> dma;
BitField<uint16_t, 10> drc;
BitField<uint16_t, 9> soc;
BitField<uint16_t, 8> sic;
BitField<uint16_t, 7> ei;
BitField<uint16_t, 1> p1;
BitField<uint16_t, 0> p0;
BooleanBitField<uint16_t, 15> rqm;
BooleanBitField<uint16_t, 14> usf1;
BooleanBitField<uint16_t, 13> usf0;
BooleanBitField<uint16_t, 12> drs;
BooleanBitField<uint16_t, 11> dma;
BooleanBitField<uint16_t, 10> drc;
BooleanBitField<uint16_t, 9> soc;
BooleanBitField<uint16_t, 8> sic;
BooleanBitField<uint16_t, 7> ei;
BooleanBitField<uint16_t, 1> p1;
BooleanBitField<uint16_t, 0> p0;
};
inline operator uint() const { return data & 0xff83; }

View File

@ -249,16 +249,16 @@ struct V30MZ {
struct Flags {
union {
uint16_t data = 0;
BitField<uint16_t, 15> m; //mode
BitField<uint16_t, 11> v; //overflow
BitField<uint16_t, 10> d; //direction
BitField<uint16_t, 9> i; //interrupt
BitField<uint16_t, 8> b; //break
BitField<uint16_t, 7> s; //sign
BitField<uint16_t, 6> z; //zero
BitField<uint16_t, 4> h; //half-carry
BitField<uint16_t, 2> p; //parity
BitField<uint16_t, 0> c; //carry
BooleanBitField<uint16_t, 15> m; //mode
BooleanBitField<uint16_t, 11> v; //overflow
BooleanBitField<uint16_t, 10> d; //direction
BooleanBitField<uint16_t, 9> i; //interrupt
BooleanBitField<uint16_t, 8> b; //break
BooleanBitField<uint16_t, 7> s; //sign
BooleanBitField<uint16_t, 6> z; //zero
BooleanBitField<uint16_t, 4> h; //half-carry
BooleanBitField<uint16_t, 2> p; //parity
BooleanBitField<uint16_t, 0> c; //carry
};
operator uint() const { return data & 0x8fd5 | 0x7002; }

View File

@ -104,7 +104,7 @@ auto ICD2::audioSample(const double* samples, uint channels) -> void {
}
auto ICD2::inputPoll(uint port, uint device, uint id) -> int16 {
GameBoy::cpu.status.mlt_req = joypID & mltReq;
GameBoy::cpu.status.mltReq = joypID & mltReq;
uint data = 0x00;
switch(joypID & mltReq) {

View File

@ -62,12 +62,10 @@ auto CPU::main() -> void {
status.nmiPending = false;
r.vector = r.e ? 0xfffa : 0xffea;
interrupt();
debugger.nmi();
} else if(status.irqPending) {
status.irqPending = false;
r.vector = r.e ? 0xfffe : 0xffee;
interrupt();
debugger.irq();
} else if(status.resetPending) {
status.resetPending = false;
addClocks(132);
@ -81,7 +79,6 @@ auto CPU::main() -> void {
}
}
debugger.execute(r.pc.d);
instruction();
}

View File

@ -50,7 +50,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
auto read(uint24 addr) -> uint8 override;
auto write(uint24 addr, uint8 data) -> void override;
alwaysinline auto speed(uint24 addr) const -> uint;
auto disassemblerRead(uint24 addr) -> uint8 override;
auto readDisassembler(uint24 addr) -> uint8 override;
//mmio.cpp
auto readAPU(uint24 addr, uint8 data) -> uint8;
@ -244,14 +244,6 @@ privileged:
uint addr;
uint8 data;
} pipe;
struct Debugger {
hook<auto (uint24) -> void> execute;
hook<auto (uint24, uint8) -> void> read;
hook<auto (uint24, uint8) -> void> write;
hook<auto () -> void> nmi;
hook<auto () -> void> irq;
} debugger;
};
extern CPU cpu;

View File

@ -20,7 +20,6 @@ auto CPU::read(uint24 addr) -> uint8 {
r.mdr = bus.read(addr, r.mdr);
addClocks(4);
aluEdge();
debugger.read(addr, r.mdr);
return r.mdr;
}
@ -30,7 +29,6 @@ auto CPU::write(uint24 addr, uint8 data) -> void {
dmaEdge();
addClocks(status.clockCount);
bus.write(addr, r.mdr = data);
debugger.write(addr, r.mdr);
}
auto CPU::speed(uint24 addr) const -> uint {
@ -43,6 +41,6 @@ auto CPU::speed(uint24 addr) const -> uint {
return 12;
}
auto CPU::disassemblerRead(uint24 addr) -> uint8 {
auto CPU::readDisassembler(uint24 addr) -> uint8 {
return bus.read(addr, r.mdr);
}

View File

@ -1,6 +1,6 @@
auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 {
synchronizeSMP();
return smp.portRead(addr.bits(0,1));
return smp.readPort(addr.bits(0,1));
}
auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {

View File

@ -1,49 +0,0 @@
auto PPU::getVramAddress() -> uint16 {
uint16 address = r.vramAddress;
switch(r.vramMapping) {
case 0: return (address);
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
case 3: return (address & 0xfc00) | ((address & 0x007f) << 3) | ((address >> 7) & 7);
}
unreachable;
}
auto PPU::vramRead(bool chip, uint addr) -> uint8 {
uint8 data = 0x00;
if(r.displayDisable || vcounter() >= vdisp()) {
data = vram[addr].byte(chip);
debugger.vramRead(addr << 1 | chip, data);
}
return data;
}
auto PPU::vramWrite(bool chip, uint addr, uint8 data) -> void {
if(r.displayDisable || vcounter() >= vdisp()) {
vram[addr].byte(chip) = data;
debugger.vramWrite(addr << 1 | chip, data);
}
}
auto PPU::oamRead(uint addr) -> uint8 {
uint8 data = oam[addr];
debugger.oamRead(addr, data);
return data;
}
auto PPU::oamWrite(uint addr, uint8 data) -> void {
oam[addr] = data;
obj.update(addr, data);
debugger.oamWrite(addr, data);
}
auto PPU::cgramRead(uint addr) -> uint8 {
uint8 data = cgram[addr];
debugger.cgramRead(addr, data);
return data;
}
auto PPU::cgramWrite(uint addr, uint8 data) -> void {
cgram[addr] = data;
debugger.cgramWrite(addr, data);
}

View File

@ -1,4 +1,24 @@
auto PPU::read(uint24 addr, uint8 data) -> uint8 {
auto PPU::getVramAddress() -> uint16 {
uint16 address = r.vramAddress;
switch(r.vramMapping) {
case 0: return (address);
case 1: return (address & 0xff00) | ((address & 0x001f) << 3) | ((address >> 5) & 7);
case 2: return (address & 0xfe00) | ((address & 0x003f) << 3) | ((address >> 6) & 7);
case 3: return (address & 0xfc00) | ((address & 0x007f) << 3) | ((address >> 7) & 7);
}
unreachable;
}
auto PPU::vramAccessible() const -> bool {
return r.displayDisable || vcounter() >= vdisp();
}
auto PPU::oamWrite(uint addr, uint8 data) -> void {
oam[addr] = data;
obj.update(addr, data);
}
auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
cpu.synchronizePPU();
switch((uint16)addr) {
@ -44,18 +64,16 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
if(!r.displayDisable && vcounter() < vdisp()) address = latch.oamAddress;
if(address & 0x0200) address &= 0x021f;
ppu1.mdr = oamRead(address);
ppu1.mdr = oam[address];
obj.setFirstSprite();
return ppu1.mdr;
}
//VMDATALREAD
case 0x2139: {
auto address = getVramAddress();
ppu1.mdr = latch.vram >> 0;
if(r.vramIncrementMode == 0) {
latch.vram.byte(0) = vramRead(0, address);
latch.vram.byte(1) = vramRead(1, address);
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
r.vramAddress += r.vramIncrementSize;
}
return ppu1.mdr;
@ -63,11 +81,9 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
//VMDATAHREAD
case 0x213a: {
uint16 address = getVramAddress();
ppu1.mdr = latch.vram >> 8;
if(r.vramIncrementMode == 1) {
latch.vram.byte(0) = vramRead(0, address);
latch.vram.byte(1) = vramRead(1, address);
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
r.vramAddress += r.vramIncrementSize;
}
return ppu1.mdr;
@ -75,18 +91,17 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
//CGDATAREAD
case 0x213b: {
bool l = r.cgramAddress & 1;
uint9 address = r.cgramAddress++;
auto address = r.cgramAddress;
if(!r.displayDisable
&& vcounter() > 0 && vcounter() < vdisp()
&& hcounter() >= 88 && hcounter() < 1096
) address = latch.cgramAddress;
if(l == 0) {
ppu2.mdr = cgramRead(address);
if(r.cgramAddressLatch++) {
ppu2.mdr = cgram[address].byte(0);
} else {
ppu2.mdr &= 0x80;
ppu2.mdr |= cgramRead(address);
ppu2.mdr |= cgram[address].byte(1);
}
return ppu2.mdr;
}
@ -147,7 +162,7 @@ auto PPU::read(uint24 addr, uint8 data) -> uint8 {
return data;
}
auto PPU::write(uint24 addr, uint8 data) -> void {
auto PPU::writeIO(uint24 addr, uint8 data) -> void {
cpu.synchronizePPU();
switch((uint16)addr) {
@ -342,36 +357,28 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
//VMADDL
case 0x2116: {
r.vramAddress &= 0xff00;
r.vramAddress |= (data << 0);
auto address = getVramAddress();
latch.vram.byte(0) = vramRead(0, address);
latch.vram.byte(1) = vramRead(1, address);
r.vramAddress.byte(0) = data;
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
return;
}
//VMADDH
case 0x2117: {
r.vramAddress &= 0x00ff;
r.vramAddress |= (data << 8);
auto address = getVramAddress();
latch.vram.byte(0) = vramRead(0, address);
latch.vram.byte(1) = vramRead(1, address);
r.vramAddress.byte(1) = data;
latch.vram = vramAccessible() ? vram[getVramAddress()] : (uint16)0;
return;
}
//VMDATAL
case 0x2118: {
auto address = getVramAddress();
vramWrite(0, address, data);
if(vramAccessible()) vram[getVramAddress()].byte(0) = data;
if(r.vramIncrementMode == 0) r.vramAddress += r.vramIncrementSize;
return;
}
//VMDATAH
case 0x2119: {
auto address = getVramAddress();
vramWrite(1, address, data);
if(vramAccessible()) vram[getVramAddress()].byte(1) = data;
if(r.vramIncrementMode == 1) r.vramAddress += r.vramIncrementSize;
return;
}
@ -428,24 +435,24 @@ auto PPU::write(uint24 addr, uint8 data) -> void {
//CGADD
case 0x2121: {
r.cgramAddress = data << 1;
r.cgramAddress = data;
r.cgramAddressLatch = 0;
return;
}
//CGDATA
case 0x2122: {
bool l = r.cgramAddress & 1;
uint9 address = r.cgramAddress++;
auto address = r.cgramAddress;
if(!r.displayDisable
&& vcounter() > 0 && vcounter() < vdisp()
&& hcounter() >= 88 && hcounter() < 1096
) address = latch.cgramAddress;
if(l == 0) {
if(r.cgramAddressLatch++ == 0) {
latch.cgram = data;
} else {
cgramWrite((address & ~1) + 0, latch.cgram);
cgramWrite((address & ~1) + 1, data & 0x7f);
cgram[address] = data.bits(0,6) << 8 | latch.cgram;
r.cgramAddress++;
}
return;
}

View File

@ -4,7 +4,6 @@ namespace SuperFamicom {
PPU ppu;
#include "memory.cpp"
#include "mmio.cpp"
#include "background/background.cpp"
#include "object/object.cpp"
@ -97,8 +96,8 @@ auto PPU::load(Markup::Node node) -> bool {
auto PPU::power() -> void {
for(auto& n : vram.data) n = random(0x0000);
for(auto& n : oam) n = random(0x00);
for(auto& n : cgram) n = random(0x00);
for(auto& n : oam.data) n = random(0x00);
for(auto& n : cgram.data) n = random(0x0000);
}
auto PPU::reset() -> void {
@ -106,8 +105,8 @@ auto PPU::reset() -> void {
PPUcounter::reset();
memory::fill(output, 512 * 480 * sizeof(uint32));
function<auto (uint24, uint8) -> uint8> reader{&PPU::read, this};
function<auto (uint24, uint8) -> void> writer{&PPU::write, this};
function<auto (uint24, uint8) -> uint8> reader{&PPU::readIO, this};
function<auto (uint24, uint8) -> void> writer{&PPU::writeIO, this};
bus.map(reader, writer, "00-3f,80-bf:2100-213f");
ppu1.mdr = random(0xff);
@ -178,7 +177,8 @@ auto PPU::reset() -> void {
r.m7y = random(0x0000);
//$2121 CGADD
r.cgramAddress = random(0x0000);
r.cgramAddress = random(0x00);
r.cgramAddressLatch = random(0);
//$2133 SETINI
r.extbg = random(false);

View File

@ -17,18 +17,12 @@ struct PPU : Thread, PPUcounter {
auto serialize(serializer&) -> void;
//memory.cpp
alwaysinline auto getVramAddress() -> uint16;
alwaysinline auto vramRead(bool chip, uint addr) -> uint8;
alwaysinline auto vramWrite(bool chip, uint addr, uint8 data) -> void;
alwaysinline auto oamRead(uint addr) -> uint8;
alwaysinline auto oamWrite(uint addr, uint8 data) -> void;
alwaysinline auto cgramRead(uint addr) -> uint8;
alwaysinline auto cgramWrite(uint addr, uint8 data) -> void;
//mmio.cpp
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
alwaysinline auto getVramAddress() -> uint16;
alwaysinline auto vramAccessible() const -> bool;
alwaysinline auto oamWrite(uint addr, uint8 data) -> void;
auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void;
auto latchCounters() -> void;
auto updateVideoMode() -> void;
@ -38,8 +32,16 @@ privileged:
uint16 data[64 * 1024];
uint mask = 0x7fff;
} vram;
uint8 oam[544];
uint8 cgram[512];
struct OAM {
auto& operator[](uint offset) { return data[offset]; }
uint8 data[544];
} oam;
struct CGRAM {
auto& operator[](uint8 offset) { return data[offset]; }
uint15 data[256];
} cgram;
uint32* output = nullptr;
@ -70,7 +72,7 @@ privileged:
bool vcounter;
uint10 oamAddress;
uint9 cgramAddress;
uint8 cgramAddress;
} latch;
struct Registers {
@ -127,7 +129,8 @@ privileged:
uint16 m7y;
//$2121 CGADD
uint9 cgramAddress;
uint8 cgramAddress;
uint1 cgramAddressLatch;
//$2133 SETINI
bool extbg;
@ -160,15 +163,6 @@ privileged:
friend class PPU::Window;
friend class PPU::Screen;
friend class Scheduler;
struct Debugger {
hook<auto (uint16, uint8) -> void> vramRead;
hook<auto (uint16, uint8) -> void> oamRead;
hook<auto (uint16, uint8) -> void> cgramRead;
hook<auto (uint16, uint8) -> void> vramWrite;
hook<auto (uint16, uint8) -> void> oamWrite;
hook<auto (uint16, uint8) -> void> cgramWrite;
} debugger;
};
extern PPU ppu;

View File

@ -58,10 +58,10 @@ auto PPU::Screen::below(bool hires) -> uint16 {
if(math.transparent = (priority == 0)) math.below.color = paletteColor(0);
if(!hires) return 0;
if(!math.below.colorEnable) return math.above.colorEnable ? math.below.color : (uint16)0;
if(!math.below.colorEnable) return math.above.colorEnable ? math.below.color : (uint15)0;
return blend(
math.above.colorEnable ? math.below.color : (uint16)0,
math.above.colorEnable ? math.below.color : (uint15)0,
math.blendMode ? math.above.color : fixedColor()
);
}
@ -106,7 +106,7 @@ auto PPU::Screen::above() -> uint16 {
if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false;
math.above.colorEnable = ppu.window.output.above.colorEnable;
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint16)0;
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint15)0;
if(r.blendMode && math.transparent) {
math.blendMode = false;
@ -117,12 +117,12 @@ auto PPU::Screen::above() -> uint16 {
}
return blend(
math.above.colorEnable ? math.above.color : (uint16)0,
math.above.colorEnable ? math.above.color : (uint15)0,
math.blendMode ? math.below.color : fixedColor()
);
}
auto PPU::Screen::blend(uint x, uint y) const -> uint16 {
auto PPU::Screen::blend(uint x, uint y) const -> uint15 {
if(!r.colorMode) {
if(!math.colorHalve) {
uint sum = x + y;
@ -142,13 +142,12 @@ auto PPU::Screen::blend(uint x, uint y) const -> uint16 {
}
}
auto PPU::Screen::paletteColor(uint palette) const -> uint16 {
palette <<= 1;
auto PPU::Screen::paletteColor(uint8 palette) const -> uint15 {
ppu.latch.cgramAddress = palette;
return ppu.cgram[palette + 0] << 0 | ppu.cgram[palette + 1] << 8;
return ppu.cgram[palette];
}
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint16 {
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint15 {
//palette = -------- BBGGGRRR
//tile = ---bgr-- --------
//output = 0BBb00GG Gg0RRRr0
@ -157,7 +156,7 @@ auto PPU::Screen::directColor(uint palette, uint tile) const -> uint16 {
+ ((palette << 2) & 0x001c) + ((tile >> 9) & 0x0002);
}
auto PPU::Screen::fixedColor() const -> uint16 {
auto PPU::Screen::fixedColor() const -> uint15 {
return r.colorBlue << 10 | r.colorGreen << 5 | r.colorRed << 0;
}

View File

@ -6,10 +6,10 @@ struct Screen {
auto below(bool hires) -> uint16;
auto above() -> uint16;
auto blend(uint x, uint y) const -> uint16;
alwaysinline auto paletteColor(uint palette) const -> uint16;
alwaysinline auto directColor(uint palette, uint tile) const -> uint16;
alwaysinline auto fixedColor() const -> uint16;
auto blend(uint x, uint y) const -> uint15;
alwaysinline auto paletteColor(uint8 palette) const -> uint15;
alwaysinline auto directColor(uint palette, uint tile) const -> uint15;
alwaysinline auto fixedColor() const -> uint15;
auto serialize(serializer&) -> void;
@ -33,7 +33,7 @@ struct Screen {
struct Math {
struct Screen {
uint16 color;
uint15 color;
bool colorEnable;
} above, below;
bool transparent;

View File

@ -16,8 +16,8 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(vram.mask);
s.array(vram.data, vram.mask + 1);
s.array(oam);
s.array(cgram);
s.array(oam.data);
s.array(cgram.data);
s.integer(ppu1.version);
s.integer(ppu1.mdr);
@ -71,6 +71,7 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(r.m7y);
s.integer(r.cgramAddress);
s.integer(r.cgramAddressLatch);
s.integer(r.extbg);
s.integer(r.pseudoHires);

View File

@ -1,23 +1,23 @@
alwaysinline auto SMP::ramRead(uint16 addr) -> uint8 {
alwaysinline auto SMP::readRAM(uint16 addr) -> uint8 {
if(addr >= 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
if(status.ramDisable) return 0x5a; //0xff on mini-SNES
return apuram[addr];
}
alwaysinline auto SMP::ramWrite(uint16 addr, uint8 data) -> void {
alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
//writes to $ffc0-$ffff always go to apuram, even if the iplrom is enabled
if(status.ramWritable && !status.ramDisable) apuram[addr] = data;
}
auto SMP::portRead(uint2 port) const -> uint8 {
auto SMP::readPort(uint2 port) const -> uint8 {
return apuram[0xf4 + port];
}
auto SMP::portWrite(uint2 port, uint8 data) -> void {
auto SMP::writePort(uint2 port, uint8 data) -> void {
apuram[0xf4 + port] = data;
}
auto SMP::busRead(uint16 addr) -> uint8 {
auto SMP::readBus(uint16 addr) -> uint8 {
uint result;
switch(addr) {
@ -68,10 +68,10 @@ auto SMP::busRead(uint16 addr) -> uint8 {
return result;
}
return ramRead(addr);
return readRAM(addr);
}
auto SMP::busWrite(uint16 addr, uint8 data) -> void {
auto SMP::writeBus(uint16 addr, uint8 data) -> void {
switch(addr) {
case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear
@ -141,7 +141,7 @@ auto SMP::busWrite(uint16 addr, uint8 data) -> void {
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
synchronizeCPU();
portWrite(addr, data);
writePort(addr, data);
break;
case 0xf8: //RAM0
@ -170,7 +170,7 @@ auto SMP::busWrite(uint16 addr, uint8 data) -> void {
break;
}
ramWrite(addr, data); //all writes, even to MMIO registers, appear on bus
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
}
auto SMP::io() -> void {
@ -180,21 +180,19 @@ auto SMP::io() -> void {
auto SMP::read(uint16 addr) -> uint8 {
addClocks(12);
uint8 data = busRead(addr);
uint8 data = readBus(addr);
addClocks(12);
cycleEdge();
debugger.read(addr, data);
return data;
}
auto SMP::write(uint16 addr, uint8 data) -> void {
addClocks(24);
busWrite(addr, data);
writeBus(addr, data);
cycleEdge();
debugger.write(addr, data);
}
auto SMP::disassemblerRead(uint16 addr) -> uint8 {
auto SMP::readDisassembler(uint16 addr) -> uint8 {
if((addr & 0xfff0) == 0x00f0) return 0x00;
if((addr & 0xffc0) == 0xffc0 && status.iplromEnable) return iplrom[addr & 0x3f];
return apuram[addr];

View File

@ -26,7 +26,6 @@ auto SMP::Enter() -> void {
}
auto SMP::main() -> void {
debugger.execute(regs.pc);
instruction();
}

View File

@ -5,8 +5,8 @@ struct SMP : Processor::SPC700, Thread {
alwaysinline auto synchronizeCPU() -> void;
alwaysinline auto synchronizeDSP() -> void;
auto portRead(uint2 port) const -> uint8;
auto portWrite(uint2 port, uint8 data) -> void;
auto readPort(uint2 port) const -> uint8;
auto writePort(uint2 port, uint8 data) -> void;
auto main() -> void;
auto load(Markup::Node) -> bool;
@ -46,24 +46,18 @@ privileged:
static auto Enter() -> void;
struct Debugger {
hook<auto (uint16) -> void> execute;
hook<auto (uint16, uint8) -> void> read;
hook<auto (uint16, uint8) -> void> write;
} debugger;
//memory.cpp
auto ramRead(uint16 addr) -> uint8;
auto ramWrite(uint16 addr, uint8 data) -> void;
auto readRAM(uint16 addr) -> uint8;
auto writeRAM(uint16 addr, uint8 data) -> void;
auto busRead(uint16 addr) -> uint8;
auto busWrite(uint16 addr, uint8 data) -> void;
auto readBus(uint16 addr) -> uint8;
auto writeBus(uint16 addr, uint8 data) -> void;
auto io() -> void override;
auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override;
auto disassemblerRead(uint16 addr) -> uint8 override;
auto readDisassembler(uint16 addr) -> uint8 override;
//timing.cpp
template<uint Frequency>

View File

@ -2,67 +2,21 @@
namespace nall {
template<typename type> struct BitFieldReference {
BitFieldReference(type& data, uint lo, uint hi)
: data(data), lo(lo), hi(hi), bits(hi + lo - 1), mask((~0ull >> (64 - bits)) << lo) {
}
inline explicit operator bool() const { return data & mask; }
inline operator type() const { return get(); }
inline auto& operator=(const BitFieldReference& value) { return set(value.data); }
template<typename T> inline auto& operator=(const T& value) { return set(value << lo); }
inline auto operator++(int) { type value = get(); set(data + (1 << lo)); return value; }
inline auto operator--(int) { type value = get(); set(data - (1 << lo)); return value; }
inline auto& operator++() { return set(data + (1 << lo)); }
inline auto& operator--() { return set(data - (1 << lo)); }
inline auto& operator &=(const type value) { return set(data & (value << lo)); }
inline auto& operator |=(const type value) { return set(data | (value << lo)); }
inline auto& operator ^=(const type value) { return set(data ^ (value << lo)); }
inline auto& operator<<=(const type value) { return set((data & mask) << value); }
inline auto& operator>>=(const type value) { return set((data & mask) >> value); }
inline auto& operator +=(const type value) { return set(data + (value << lo)); }
inline auto& operator -=(const type value) { return set(data - (value << lo)); }
inline auto& operator *=(const type value) { return set((get() * value) << lo); }
inline auto& operator /=(const type value) { return set((get() / value) << lo); }
inline auto& operator %=(const type value) { return set((get() % value) << lo); }
const uint lo;
const uint hi;
const uint bits;
const uint mask;
private:
type& data;
inline auto get() const -> type {
return (data & mask) >> lo;
}
inline auto set(type value) -> BitFieldReference& {
return data = (data & ~mask) | (value & mask), *this;
}
};
template<typename type, uint Lo, uint Hi = ~0U> struct BitField {
template<typename type, uint Lo, uint Hi> struct NaturalBitField {
enum : uint { lo = Lo <= Hi ? Lo : Hi };
enum : uint { hi = Hi >= Lo ? Hi : Lo };
enum : uint { bits = hi - lo + 1 };
enum : uint { mask = (~0ull >> (64 - bits)) << lo };
static_assert(hi < sizeof(type) * 8, "");
inline BitField() = default;
inline BitField(const BitField& value) { set(value.data); }
template<typename T> inline BitField(const T& value) { set(value << lo); }
inline NaturalBitField() = default;
inline NaturalBitField(const NaturalBitField& value) { set(value.data); }
template<typename T> inline NaturalBitField(const T& value) { set(value << lo); }
inline explicit operator bool() const { return data & mask; }
inline operator type() const { return get(); }
inline operator BitFieldReference<type>() { return {data, lo, hi}; }
inline auto& operator=(const BitField& value) { return set(value.data); }
inline auto& operator=(const NaturalBitField& value) { return set(value.data); }
template<typename T> inline auto& operator=(const T& value) { return set(value << lo); }
inline auto operator++(int) { type value = get(); set(data + (1 << lo)); return value; }
@ -89,30 +43,31 @@ private:
return (data & mask) >> lo;
}
inline auto set(type value) -> BitField& {
inline auto set(type value) -> NaturalBitField& {
return data = (data & ~mask) | (value & mask), *this;
}
};
template<typename type, uint Bit> struct BitField<type, Bit, ~0U> {
template<typename type, uint Bit> struct BooleanBitField {
enum : uint { bit = Bit };
enum : uint { mask = 1ull << bit };
static_assert(bit < sizeof(type) * 8, "");
inline BitField() = default;
inline BitField(const BitField& value) { set(value.get()); }
template<typename T> inline BitField(const bool value) { set(value); }
inline BooleanBitField() = default;
inline BooleanBitField(const BooleanBitField& value) { set(value.get()); }
template<typename T> inline BooleanBitField(const bool value) { set(value); }
inline operator bool() const { return get(); }
inline operator BitFieldReference<type>() { return {data, bit, bit}; }
inline auto& operator=(const BitField& value) { return set(value.get()); }
inline auto& operator=(const BooleanBitField& value) { return set(value.get()); }
inline auto& operator=(const bool value) { return set(value); }
inline auto& operator&=(const bool value) { return set(get() & value); }
inline auto& operator|=(const bool value) { return set(get() | value); }
inline auto& operator^=(const bool value) { return set(get() ^ value); }
inline auto raise() { return get() == 0 ? set(1), true : false; }
inline auto lower() { return get() == 1 ? set(0), true : false; }
inline auto& invert() { return set(get() ^ 1); }
private:
@ -122,7 +77,7 @@ private:
return data & mask;
}
inline auto set(bool value) -> BitField& {
inline auto set(bool value) -> BooleanBitField& {
return data = (data & ~mask) | (value << bit), *this;
}
};