Update to v099r13 release.

byuu says:

Changelog:
- GB core code cleanup completed
- GBA core code cleanup completed
- some more cleanup on missed processor/arm functions/variables
- fixed FC loading icarus bug
- "Load ROM File" icarus functionality restored
- minor code unification efforts all around (not perfect yet)
  - MMIO->IO
  - mmio.cpp->io.cpp
  - read,write->readIO,writeIO

It's been a very long work in progress ... starting all the way back with
v094r09, but the major part of the higan code cleanup is now completed! Of
course, it's very important to note that this is only for the basic style:

- under_score functions and variables are now camelCase
- return-type function-name() are now auto function-name() -> return-type
- Natural<T>/Integer<T> replace (u)intT_n types where possible
- signed/unsigned are now int/uint
- most of the x==true,x==false tests changed to x,!x

A lot of spot improvements to consistency, simplicity and quality have
gone in along the way, of course. But we'll probably never fully finishing
beautifying every last line of code in the entire codebase. Still,
this is a really great start. Going forward, WIP diffs should start
being smaller and of higher quality once again.

I know the joke is, "until my coding style changes again", but ... this
was way too stressful, way too time consuming, and way too risky. I'm
too old and tired now for extreme upheavel like this again. The only
major change I'm slowly mulling over would be renaming the using
Natural<T>/Integer<T> = (u)intT; shorthand to something that isn't as
easily confused with the (u)int_t types ... but we'll see. I'll definitely
continue to change small things all the time, but for the larger picture,
I need to just accept the style I have and live with it.
This commit is contained in:
Tim Allen 2016-06-29 21:10:28 +10:00
parent 7a68059f78
commit 67457fade4
82 changed files with 834 additions and 878 deletions

View File

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

View File

@ -17,7 +17,7 @@ auto Cartridge::main() -> void {
auto Cartridge::load() -> bool { auto Cartridge::load() -> bool {
if(auto pathID = interface->load(ID::Famicom, "Famicom", "fc")) { if(auto pathID = interface->load(ID::Famicom, "Famicom", "fc")) {
information.pathID = pathID(); information.pathID = pathID();
} } else return false;
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) { if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads(); information.manifest = fp->reads();

View File

@ -9,7 +9,7 @@ auto PPU::writeCIRAM(uint11 addr, uint8 data) -> void {
auto PPU::readCGRAM(uint5 addr) -> uint8 { auto PPU::readCGRAM(uint5 addr) -> uint8 {
if((addr & 0x13) == 0x10) addr &= ~0x10; if((addr & 0x13) == 0x10) addr &= ~0x10;
uint8 data = cgram[addr]; uint8 data = cgram[addr];
if(r.grayscale) data &= 0x30; if(io.grayscale) data &= 0x30;
return data; return data;
} }
@ -25,36 +25,36 @@ auto PPU::readIO(uint16 addr) -> uint8 {
//PPUSTATUS //PPUSTATUS
case 2: case 2:
result |= r.mdr.bits(0,4); result |= io.mdr.bits(0,4);
result |= r.spriteOverflow << 5; result |= io.spriteOverflow << 5;
result |= r.spriteZeroHit << 6; result |= io.spriteZeroHit << 6;
result |= r.nmiFlag << 7; result |= io.nmiFlag << 7;
r.v.latch = 0; io.v.latch = 0;
r.nmiHold = 0; io.nmiHold = 0;
cpu.nmiLine(r.nmiFlag = 0); cpu.nmiLine(io.nmiFlag = 0);
break; break;
//OAMDATA //OAMDATA
case 4: case 4:
result = oam[r.oamAddress]; result = oam[io.oamAddress];
break; break;
//PPUDATA //PPUDATA
case 7: case 7:
if(enable() && (r.ly <= 240 || r.ly == 261)) return 0x00; if(enable() && (io.ly <= 240 || io.ly == 261)) return 0x00;
addr = (uint14)r.v.address; addr = (uint14)io.v.address;
if(addr <= 0x1fff) { if(addr <= 0x1fff) {
result = r.busData; result = io.busData;
r.busData = cartridge.readCHR(addr); io.busData = cartridge.readCHR(addr);
} else if(addr <= 0x3eff) { } else if(addr <= 0x3eff) {
result = r.busData; result = io.busData;
r.busData = cartridge.readCHR(addr); io.busData = cartridge.readCHR(addr);
} else if(addr <= 0x3fff) { } else if(addr <= 0x3fff) {
result = readCGRAM(addr); result = readCGRAM(addr);
r.busData = cartridge.readCHR(addr); io.busData = cartridge.readCHR(addr);
} }
r.v.address += r.vramIncrement; io.v.address += io.vramIncrement;
break; break;
} }
@ -63,30 +63,30 @@ auto PPU::readIO(uint16 addr) -> uint8 {
} }
auto PPU::writeIO(uint16 addr, uint8 data) -> void { auto PPU::writeIO(uint16 addr, uint8 data) -> void {
r.mdr = data; io.mdr = data;
switch(addr.bits(0,2)) { switch(addr.bits(0,2)) {
//PPUCTRL //PPUCTRL
case 0: case 0:
r.t.nametable = data.bits(0,1); io.t.nametable = data.bits(0,1);
r.vramIncrement = data.bit (2) ? 32 : 1; io.vramIncrement = data.bit (2) ? 32 : 1;
r.spriteAddress = data.bit (3) ? 0x1000 : 0x0000; io.spriteAddress = data.bit (3) ? 0x1000 : 0x0000;
r.bgAddress = data.bit (4) ? 0x1000 : 0x0000; io.bgAddress = data.bit (4) ? 0x1000 : 0x0000;
r.spriteHeight = data.bit (5) ? 16 : 8; io.spriteHeight = data.bit (5) ? 16 : 8;
r.masterSelect = data.bit (6); io.masterSelect = data.bit (6);
r.nmiEnable = data.bit (7); io.nmiEnable = data.bit (7);
cpu.nmiLine(r.nmiEnable && r.nmiHold && r.nmiFlag); cpu.nmiLine(io.nmiEnable && io.nmiHold && io.nmiFlag);
break; break;
//PPUMASK //PPUMASK
case 1: case 1:
r.grayscale = data.bit (0); io.grayscale = data.bit (0);
r.bgEdgeEnable = data.bit (1); io.bgEdgeEnable = data.bit (1);
r.spriteEdgeEnable = data.bit (2); io.spriteEdgeEnable = data.bit (2);
r.bgEnable = data.bit (3); io.bgEnable = data.bit (3);
r.spriteEnable = data.bit (4); io.spriteEnable = data.bit (4);
r.emphasis = data.bits(5,7); io.emphasis = data.bits(5,7);
break; break;
//PPUSTATUS //PPUSTATUS
@ -95,41 +95,41 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
//OAMADDR //OAMADDR
case 3: case 3:
r.oamAddress = data; io.oamAddress = data;
break; break;
//OAMDATA //OAMDATA
case 4: case 4:
if(r.oamAddress.bits(0,1) == 2) data.bits(2,4) = 0; //clear non-existent bits (always read back as 0) if(io.oamAddress.bits(0,1) == 2) data.bits(2,4) = 0; //clear non-existent bits (always read back as 0)
oam[r.oamAddress++] = data; oam[io.oamAddress++] = data;
break; break;
//PPUSCROLL //PPUSCROLL
case 5: case 5:
if(r.v.latch++ == 0) { if(io.v.latch++ == 0) {
r.v.fineX = data.bits(0,2); io.v.fineX = data.bits(0,2);
r.t.tileX = data.bits(3,7); io.t.tileX = data.bits(3,7);
} else { } else {
r.t.fineY = data.bits(0,2); io.t.fineY = data.bits(0,2);
r.t.tileY = data.bits(3,7); io.t.tileY = data.bits(3,7);
} }
break; break;
//PPUADDR //PPUADDR
case 6: case 6:
if(r.v.latch++ == 0) { if(io.v.latch++ == 0) {
r.t.addressHi = data.bits(0,5); io.t.addressHi = data.bits(0,5);
} else { } else {
r.t.addressLo = data.bits(0,7); io.t.addressLo = data.bits(0,7);
r.v.address = r.t.address; io.v.address = io.t.address;
} }
break; break;
//PPUDATA //PPUDATA
case 7: case 7:
if(enable() && (r.ly <= 240 || r.ly == 261)) return; if(enable() && (io.ly <= 240 || io.ly == 261)) return;
addr = (uint14)r.v.address; addr = (uint14)io.v.address;
if(addr <= 0x1fff) { if(addr <= 0x1fff) {
cartridge.writeCHR(addr, data); cartridge.writeCHR(addr, data);
} else if(addr <= 0x3eff) { } else if(addr <= 0x3eff) {
@ -137,7 +137,7 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
} else if(addr <= 0x3fff) { } else if(addr <= 0x3fff) {
writeCGRAM(addr, data); writeCGRAM(addr, data);
} }
r.v.address += r.vramIncrement; io.v.address += io.vramIncrement;
break; break;
} }

View File

@ -17,34 +17,34 @@ auto PPU::main() -> void {
auto PPU::step(uint clocks) -> void { auto PPU::step(uint clocks) -> void {
while(clocks--) { while(clocks--) {
if(r.ly == 240 && r.lx == 340) r.nmiHold = 1; if(io.ly == 240 && io.lx == 340) io.nmiHold = 1;
if(r.ly == 241 && r.lx == 0) r.nmiFlag = r.nmiHold; if(io.ly == 241 && io.lx == 0) io.nmiFlag = io.nmiHold;
if(r.ly == 241 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag); if(io.ly == 241 && io.lx == 2) cpu.nmiLine(io.nmiEnable && io.nmiFlag);
if(r.ly == 260 && r.lx == 340) r.spriteZeroHit = 0, r.spriteOverflow = 0; if(io.ly == 260 && io.lx == 340) io.spriteZeroHit = 0, io.spriteOverflow = 0;
if(r.ly == 260 && r.lx == 340) r.nmiHold = 0; if(io.ly == 260 && io.lx == 340) io.nmiHold = 0;
if(r.ly == 261 && r.lx == 0) r.nmiFlag = r.nmiHold; if(io.ly == 261 && io.lx == 0) io.nmiFlag = io.nmiHold;
if(r.ly == 261 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag); if(io.ly == 261 && io.lx == 2) cpu.nmiLine(io.nmiEnable && io.nmiFlag);
clock += 4; clock += 4;
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
r.lx++; io.lx++;
} }
} }
auto PPU::scanline() -> void { auto PPU::scanline() -> void {
r.lx = 0; io.lx = 0;
if(++r.ly == 262) { if(++io.ly == 262) {
r.ly = 0; io.ly = 0;
frame(); frame();
} }
cartridge.scanline(r.ly); cartridge.scanline(io.ly);
} }
auto PPU::frame() -> void { auto PPU::frame() -> void {
r.field++; io.field++;
scheduler.exit(Scheduler::Event::Frame); scheduler.exit(Scheduler::Event::Frame);
} }
@ -58,9 +58,9 @@ auto PPU::power() -> void {
auto PPU::reset() -> void { auto PPU::reset() -> void {
create(PPU::Enter, 21'477'272); create(PPU::Enter, 21'477'272);
memory::fill(&r, sizeof(Registers)); memory::fill(&io, sizeof(IO));
memory::fill(&l, sizeof(Latches)); memory::fill(&latch, sizeof(Latches));
r.vramIncrement = 1; io.vramIncrement = 1;
for(auto& n : ciram ) n = 0; for(auto& n : ciram ) n = 0;
for(auto& n : cgram ) n = 0; for(auto& n : cgram ) n = 0;

View File

@ -31,7 +31,7 @@ struct PPU : Thread {
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
struct Registers { struct IO {
//internal //internal
uint8 mdr; uint8 mdr;
@ -81,7 +81,7 @@ struct PPU : Thread {
//$2003 //$2003
uint8 oamAddress; uint8 oamAddress;
} r; } io;
struct OAM { struct OAM {
//serialization.cpp //serialization.cpp
@ -108,7 +108,7 @@ struct PPU : Thread {
OAM oam[8]; //primary OAM oam[8]; //primary
OAM soam[8]; //secondary OAM soam[8]; //secondary
} l; } latch;
uint8 ciram[2048]; uint8 ciram[2048];
uint8 cgram[32]; uint8 cgram[32];

View File

@ -1,5 +1,5 @@
auto PPU::enable() const -> bool { auto PPU::enable() const -> bool {
return r.bgEnable || r.spriteEnable; return io.bgEnable || io.spriteEnable;
} }
auto PPU::loadCHR(uint16 addr) -> uint8 { auto PPU::loadCHR(uint16 addr) -> uint8 {
@ -7,44 +7,44 @@ auto PPU::loadCHR(uint16 addr) -> uint8 {
} }
auto PPU::renderPixel() -> void { auto PPU::renderPixel() -> void {
uint32* output = buffer + r.ly * 256; uint32* output = buffer + io.ly * 256;
uint x = r.lx - 1; uint x = io.lx - 1;
uint mask = 0x8000 >> (r.v.fineX + (x & 7)); uint mask = 0x8000 >> (io.v.fineX + (x & 7));
uint palette = 0; uint palette = 0;
uint objectPalette = 0; uint objectPalette = 0;
bool objectPriority = 0; bool objectPriority = 0;
palette |= l.tiledataLo & mask ? 1 : 0; palette |= latch.tiledataLo & mask ? 1 : 0;
palette |= l.tiledataHi & mask ? 2 : 0; palette |= latch.tiledataHi & mask ? 2 : 0;
if(palette) { if(palette) {
uint attr = l.attribute; uint attr = latch.attribute;
if(mask >= 256) attr >>= 2; if(mask >= 256) attr >>= 2;
palette |= (attr & 3) << 2; palette |= (attr & 3) << 2;
} }
if(!r.bgEnable) palette = 0; if(!io.bgEnable) palette = 0;
if(!r.bgEdgeEnable && x < 8) palette = 0; if(!io.bgEdgeEnable && x < 8) palette = 0;
if(r.spriteEnable) if(io.spriteEnable)
for(int sprite = 7; sprite >= 0; sprite--) { for(int sprite = 7; sprite >= 0; sprite--) {
if(!r.spriteEdgeEnable && x < 8) continue; if(!io.spriteEdgeEnable && x < 8) continue;
if(l.oam[sprite].id == 64) continue; if(latch.oam[sprite].id == 64) continue;
uint spriteX = x - l.oam[sprite].x; uint spriteX = x - latch.oam[sprite].x;
if(spriteX >= 8) continue; if(spriteX >= 8) continue;
if(l.oam[sprite].attr & 0x40) spriteX ^= 7; if(latch.oam[sprite].attr & 0x40) spriteX ^= 7;
uint mask = 0x80 >> spriteX; uint mask = 0x80 >> spriteX;
uint spritePalette = 0; uint spritePalette = 0;
spritePalette |= l.oam[sprite].tiledataLo & mask ? 1 : 0; spritePalette |= latch.oam[sprite].tiledataLo & mask ? 1 : 0;
spritePalette |= l.oam[sprite].tiledataHi & mask ? 2 : 0; spritePalette |= latch.oam[sprite].tiledataHi & mask ? 2 : 0;
if(spritePalette == 0) continue; if(spritePalette == 0) continue;
if(l.oam[sprite].id == 0 && palette && x != 255) r.spriteZeroHit = 1; if(latch.oam[sprite].id == 0 && palette && x != 255) io.spriteZeroHit = 1;
spritePalette |= (l.oam[sprite].attr & 3) << 2; spritePalette |= (latch.oam[sprite].attr & 3) << 2;
objectPriority = l.oam[sprite].attr & 0x20; objectPriority = latch.oam[sprite].attr & 0x20;
objectPalette = 16 + spritePalette; objectPalette = 16 + spritePalette;
} }
@ -53,23 +53,23 @@ auto PPU::renderPixel() -> void {
} }
if(!enable()) palette = 0; if(!enable()) palette = 0;
output[x] = r.emphasis << 6 | readCGRAM(palette); output[x] = io.emphasis << 6 | readCGRAM(palette);
} }
auto PPU::renderSprite() -> void { auto PPU::renderSprite() -> void {
if(!enable()) return; if(!enable()) return;
uint n = l.oamIterator++; uint n = latch.oamIterator++;
int ly = r.ly == 261 ? -1 : r.ly; int ly = io.ly == 261 ? -1 : io.ly;
uint y = ly - oam[n * 4 + 0]; uint y = ly - oam[n * 4 + 0];
if(y >= r.spriteHeight) return; if(y >= io.spriteHeight) return;
if(l.oamCounter == 8) { if(latch.oamCounter == 8) {
r.spriteOverflow = 1; io.spriteOverflow = 1;
return; return;
} }
auto& o = l.soam[l.oamCounter++]; auto& o = latch.soam[latch.oamCounter++];
o.id = n; o.id = n;
o.y = oam[n * 4 + 0]; o.y = oam[n * 4 + 0];
o.tile = oam[n * 4 + 1]; o.tile = oam[n * 4 + 1];
@ -79,34 +79,34 @@ auto PPU::renderSprite() -> void {
auto PPU::renderScanline() -> void { auto PPU::renderScanline() -> void {
//Vblank //Vblank
if(r.ly >= 240 && r.ly <= 260) return step(341), scanline(); if(io.ly >= 240 && io.ly <= 260) return step(341), scanline();
l.oamIterator = 0; latch.oamIterator = 0;
l.oamCounter = 0; latch.oamCounter = 0;
for(auto n : range(8)) l.soam[n] = {}; for(auto n : range(8)) latch.soam[n] = {};
// 0 // 0
step(1); step(1);
// 1-256 // 1-256
for(uint tile : range(32)) { for(uint tile : range(32)) {
uint nametable = loadCHR(0x2000 | (uint12)r.v.address); uint nametable = loadCHR(0x2000 | (uint12)io.v.address);
uint tileaddr = r.bgAddress | nametable << 4 | r.v.fineY; uint tileaddr = io.bgAddress | nametable << 4 | io.v.fineY;
renderPixel(); renderPixel();
step(1); step(1);
renderPixel(); renderPixel();
step(1); step(1);
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2); uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2);
if(r.v.tileY & 2) attribute >>= 4; if(io.v.tileY & 2) attribute >>= 4;
if(r.v.tileX & 2) attribute >>= 2; if(io.v.tileX & 2) attribute >>= 2;
renderPixel(); renderPixel();
step(1); step(1);
if(enable() && ++r.v.tileX == 0) r.v.nametableX++; if(enable() && ++io.v.tileX == 0) io.v.nametableX++;
if(enable() && tile == 31 && ++r.v.fineY == 0 && ++r.v.tileY == 30) r.v.nametableY++, r.v.tileY = 0; if(enable() && tile == 31 && ++io.v.fineY == 0 && ++io.v.tileY == 30) io.v.nametableY++, io.v.tileY = 0;
renderPixel(); renderPixel();
renderSprite(); renderSprite();
step(1); step(1);
@ -126,60 +126,60 @@ auto PPU::renderScanline() -> void {
renderSprite(); renderSprite();
step(1); step(1);
l.nametable = l.nametable << 8 | nametable; latch.nametable = latch.nametable << 8 | nametable;
l.attribute = l.attribute << 2 | (attribute & 3); latch.attribute = latch.attribute << 2 | (attribute & 3);
l.tiledataLo = l.tiledataLo << 8 | tiledataLo; latch.tiledataLo = latch.tiledataLo << 8 | tiledataLo;
l.tiledataHi = l.tiledataHi << 8 | tiledataHi; latch.tiledataHi = latch.tiledataHi << 8 | tiledataHi;
} }
for(auto n : range(8)) l.oam[n] = l.soam[n]; for(auto n : range(8)) latch.oam[n] = latch.soam[n];
//257-320 //257-320
for(uint sprite : range(8)) { for(uint sprite : range(8)) {
uint nametable = loadCHR(0x2000 | (uint12)r.v.address); uint nametable = loadCHR(0x2000 | (uint12)io.v.address);
step(1); step(1);
if(enable() && sprite == 0) { if(enable() && sprite == 0) {
//258 //258
r.v.nametableX = r.t.nametableX; io.v.nametableX = io.t.nametableX;
r.v.tileX = r.t.tileX; io.v.tileX = io.t.tileX;
} }
step(1); step(1);
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2); uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2);
uint tileaddr = r.spriteHeight == 8 uint tileaddr = io.spriteHeight == 8
? r.spriteAddress + l.oam[sprite].tile * 16 ? io.spriteAddress + latch.oam[sprite].tile * 16
: (l.oam[sprite].tile & ~1) * 16 + (l.oam[sprite].tile & 1) * 0x1000; : (latch.oam[sprite].tile & ~1) * 16 + (latch.oam[sprite].tile & 1) * 0x1000;
step(2); step(2);
uint spriteY = (r.ly - l.oam[sprite].y) & (r.spriteHeight - 1); uint spriteY = (io.ly - latch.oam[sprite].y) & (io.spriteHeight - 1);
if(l.oam[sprite].attr & 0x80) spriteY ^= r.spriteHeight - 1; if(latch.oam[sprite].attr & 0x80) spriteY ^= io.spriteHeight - 1;
tileaddr += spriteY + (spriteY & 8); tileaddr += spriteY + (spriteY & 8);
l.oam[sprite].tiledataLo = loadCHR(tileaddr + 0); latch.oam[sprite].tiledataLo = loadCHR(tileaddr + 0);
step(2); step(2);
l.oam[sprite].tiledataHi = loadCHR(tileaddr + 8); latch.oam[sprite].tiledataHi = loadCHR(tileaddr + 8);
step(2); step(2);
if(enable() && sprite == 6 && r.ly == 261) { if(enable() && sprite == 6 && io.ly == 261) {
//305 //305
r.v.address = r.t.address; io.v.address = io.t.address;
} }
} }
//321-336 //321-336
for(uint tile : range(2)) { for(uint tile : range(2)) {
uint nametable = loadCHR(0x2000 | (uint12)r.v.address); uint nametable = loadCHR(0x2000 | (uint12)io.v.address);
uint tileaddr = r.bgAddress | nametable << 4 | r.v.fineY; uint tileaddr = io.bgAddress | nametable << 4 | io.v.fineY;
step(2); step(2);
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2); uint attribute = loadCHR(0x23c0 | io.v.nametable << 10 | (io.v.tileY >> 2) << 3 | io.v.tileX >> 2);
if(r.v.tileY & 2) attribute >>= 4; if(io.v.tileY & 2) attribute >>= 4;
if(r.v.tileX & 2) attribute >>= 2; if(io.v.tileX & 2) attribute >>= 2;
step(1); step(1);
if(enable() && ++r.v.tileX == 0) r.v.nametableX++; if(enable() && ++io.v.tileX == 0) io.v.nametableX++;
step(1); step(1);
uint tiledataLo = loadCHR(tileaddr + 0); uint tiledataLo = loadCHR(tileaddr + 0);
@ -188,20 +188,20 @@ auto PPU::renderScanline() -> void {
uint tiledataHi = loadCHR(tileaddr + 8); uint tiledataHi = loadCHR(tileaddr + 8);
step(2); step(2);
l.nametable = l.nametable << 8 | nametable; latch.nametable = latch.nametable << 8 | nametable;
l.attribute = l.attribute << 2 | (attribute & 3); latch.attribute = latch.attribute << 2 | (attribute & 3);
l.tiledataLo = l.tiledataLo << 8 | tiledataLo; latch.tiledataLo = latch.tiledataLo << 8 | tiledataLo;
l.tiledataHi = l.tiledataHi << 8 | tiledataHi; latch.tiledataHi = latch.tiledataHi << 8 | tiledataHi;
} }
//337-338 //337-338
loadCHR(0x2000 | (uint12)r.v.address); loadCHR(0x2000 | (uint12)io.v.address);
step(1); step(1);
bool skip = enable() && r.field == 1 && r.ly == 261; bool skip = enable() && io.field == 1 && io.ly == 261;
step(1); step(1);
//339 //339
loadCHR(0x2000 | (uint12)r.v.address); loadCHR(0x2000 | (uint12)io.v.address);
step(1); step(1);
//340 //340

View File

@ -1,49 +1,49 @@
auto PPU::serialize(serializer& s) -> void { auto PPU::serialize(serializer& s) -> void {
Thread::serialize(s); Thread::serialize(s);
s.integer(r.mdr); s.integer(io.mdr);
s.integer(r.field); s.integer(io.field);
s.integer(r.lx); s.integer(io.lx);
s.integer(r.ly); s.integer(io.ly);
s.integer(r.busData); s.integer(io.busData);
s.integer(r.v.value); s.integer(io.v.value);
s.integer(r.t.value); s.integer(io.t.value);
s.integer(r.nmiHold); s.integer(io.nmiHold);
s.integer(r.nmiFlag); s.integer(io.nmiFlag);
s.integer(r.vramIncrement); s.integer(io.vramIncrement);
s.integer(r.spriteAddress); s.integer(io.spriteAddress);
s.integer(r.bgAddress); s.integer(io.bgAddress);
s.integer(r.spriteHeight); s.integer(io.spriteHeight);
s.integer(r.masterSelect); s.integer(io.masterSelect);
s.integer(r.nmiEnable); s.integer(io.nmiEnable);
s.integer(r.grayscale); s.integer(io.grayscale);
s.integer(r.bgEdgeEnable); s.integer(io.bgEdgeEnable);
s.integer(r.spriteEdgeEnable); s.integer(io.spriteEdgeEnable);
s.integer(r.bgEnable); s.integer(io.bgEnable);
s.integer(r.spriteEnable); s.integer(io.spriteEnable);
s.integer(r.emphasis); s.integer(io.emphasis);
s.integer(r.spriteOverflow); s.integer(io.spriteOverflow);
s.integer(r.spriteZeroHit); s.integer(io.spriteZeroHit);
s.integer(r.oamAddress); s.integer(io.oamAddress);
s.integer(l.nametable); s.integer(latch.nametable);
s.integer(l.attribute); s.integer(latch.attribute);
s.integer(l.tiledataLo); s.integer(latch.tiledataLo);
s.integer(l.tiledataHi); s.integer(latch.tiledataHi);
s.integer(l.oamIterator); s.integer(latch.oamIterator);
s.integer(l.oamCounter); s.integer(latch.oamCounter);
for(auto& o : l.oam) o.serialize(s); for(auto& o : latch.oam) o.serialize(s);
for(auto& o : l.soam) o.serialize(s); for(auto& o : latch.soam) o.serialize(s);
s.array(ciram); s.array(ciram);
s.array(cgram); s.array(cgram);

View File

@ -2,11 +2,11 @@
namespace GameBoy { namespace GameBoy {
#include "sequencer/sequencer.cpp" #include "sequencer.cpp"
#include "square1/square1.cpp" #include "square1.cpp"
#include "square2/square2.cpp" #include "square2.cpp"
#include "wave/wave.cpp" #include "wave.cpp"
#include "noise/noise.cpp" #include "noise.cpp"
#include "serialization.cpp" #include "serialization.cpp"
APU apu; APU apu;

View File

@ -11,17 +11,163 @@ struct APU : Thread, MMIO {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
#include "square1/square1.hpp" //square1.cpp
#include "square2/square2.hpp" struct Square1 {
#include "wave/wave.hpp" auto dacEnable() const -> bool;
#include "noise/noise.hpp"
#include "sequencer/sequencer.hpp"
Square1 square1; auto run() -> void;
Square2 square2; auto sweep(bool update) -> void;
Wave wave; auto clockLength() -> void;
Noise noise; auto clockSweep() -> void;
Sequencer sequencer; auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint3 sweepFrequency;
bool sweepDirection;
uint3 sweepShift;
bool sweepNegate;
uint2 duty;
uint length;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint11 frequency;
bool counter;
int16 output;
bool dutyOutput;
uint3 phase;
uint period;
uint3 envelopePeriod;
uint3 sweepPeriod;
int frequencyShadow;
bool sweepEnable;
uint4 volume;
} square1;
//square2.cpp
struct Square2 {
auto dacEnable() const -> bool;
auto run() -> void;
auto clockLength() -> void;
auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint2 duty;
uint length;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint11 frequency;
bool counter;
int16 output;
bool dutyOutput;
uint3 phase;
uint period;
uint3 envelopePeriod;
uint4 volume;
} square2;
struct Wave {
auto getPattern(uint5 offset) const -> uint4;
auto run() -> void;
auto clockLength() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
bool dacEnable;
uint2 volume;
uint11 frequency;
bool counter;
uint8 pattern[16];
int16 output;
uint length;
uint period;
uint5 patternOffset;
uint4 patternSample;
uint patternHold;
} wave;
struct Noise {
auto dacEnable() const -> bool;
auto getPeriod() const -> uint;
auto run() -> void;
auto clockLength() -> void;
auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint4 frequency;
bool narrow;
uint3 divisor;
bool counter;
int16 output;
uint length;
uint3 envelopePeriod;
uint4 volume;
uint period;
uint15 lfsr;
} noise;
struct Sequencer {
auto run() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power() -> void;
auto serialize(serializer&) -> void;
bool leftEnable;
uint3 leftVolume;
bool rightEnable;
uint3 rightVolume;
struct Channel {
bool leftEnable;
bool rightEnable;
} square1, square2, wave, noise;
bool enable;
int16 center;
int16 left;
int16 right;
int64 centerBias;
int64 leftBias;
int64 rightBias;
} sequencer;
uint3 phase; //high 3-bits of clock counter uint3 phase; //high 3-bits of clock counter
uint12 cycle; //low 12-bits of clock counter uint12 cycle; //low 12-bits of clock counter

View File

@ -1,30 +0,0 @@
struct Noise {
auto dacEnable() const -> bool;
auto getPeriod() const -> uint;
auto run() -> void;
auto clockLength() -> void;
auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint4 frequency;
bool narrow;
uint3 divisor;
bool counter;
int16 output;
uint length;
uint3 envelopePeriod;
uint4 volume;
uint period;
uint15 lfsr;
};

View File

@ -1,28 +0,0 @@
struct Sequencer {
auto run() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power() -> void;
auto serialize(serializer&) -> void;
bool leftEnable;
uint3 leftVolume;
bool rightEnable;
uint3 rightVolume;
struct Channel {
bool leftEnable;
bool rightEnable;
} square1, square2, wave, noise;
bool enable;
int16 center;
int16 left;
int16 right;
int64 centerBias;
int64 leftBias;
int64 rightBias;
};

View File

@ -1,38 +0,0 @@
struct Square1 {
auto dacEnable() const -> bool;
auto run() -> void;
auto sweep(bool update) -> void;
auto clockLength() -> void;
auto clockSweep() -> void;
auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint3 sweepFrequency;
bool sweepDirection;
uint3 sweepShift;
bool sweepNegate;
uint2 duty;
uint length;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint11 frequency;
bool counter;
int16 output;
bool dutyOutput;
uint3 phase;
uint period;
uint3 envelopePeriod;
uint3 sweepPeriod;
int frequencyShadow;
bool sweepEnable;
uint4 volume;
};

View File

@ -1,29 +0,0 @@
struct Square2 {
auto dacEnable() const -> bool;
auto run() -> void;
auto clockLength() -> void;
auto clockEnvelope() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
uint2 duty;
uint length;
uint4 envelopeVolume;
bool envelopeDirection;
uint3 envelopeFrequency;
uint11 frequency;
bool counter;
int16 output;
bool dutyOutput;
uint3 phase;
uint period;
uint3 envelopePeriod;
uint4 volume;
};

View File

@ -1,26 +0,0 @@
struct Wave {
auto getPattern(uint5 offset) const -> uint4;
auto run() -> void;
auto clockLength() -> void;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto power(bool initializeLength = true) -> void;
auto serialize(serializer&) -> void;
bool enable;
bool dacEnable;
uint2 volume;
uint11 frequency;
bool counter;
uint8 pattern[16];
int16 output;
uint length;
uint period;
uint5 patternOffset;
uint4 patternSample;
uint patternHold;
};

View File

@ -2,7 +2,7 @@
namespace GameBoy { namespace GameBoy {
#include "mmio.cpp" #include "io.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "timing.cpp" #include "timing.cpp"
#include "serialization.cpp" #include "serialization.cpp"

View File

@ -10,7 +10,7 @@ struct CPU : Processor::LR35902, Thread, MMIO {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
//mmio.cpp //io.cpp
auto wramAddress(uint16 addr) const -> uint; auto wramAddress(uint16 addr) const -> uint;
auto joypPoll() -> void; auto joypPoll() -> void;
auto readIO(uint16 addr) -> uint8; auto readIO(uint16 addr) -> uint8;

View File

@ -12,7 +12,7 @@
//0x08: VRAM bank# //0x08: VRAM bank#
//0x07: palette# //0x07: palette#
auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) -> void { auto PPU::readTileCGB(bool select, uint x, uint y, uint& attr, uint& data) -> void {
uint tmaddr = 0x1800 + (select << 10); uint tmaddr = 0x1800 + (select << 10);
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
@ -20,7 +20,7 @@ auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) ->
attr = vram[0x2000 + tmaddr]; attr = vram[0x2000 + tmaddr];
uint tdaddr = attr & 0x08 ? 0x2000 : 0x0000; uint tdaddr = attr & 0x08 ? 0x2000 : 0x0000;
if(status.bg_tiledata_select == 0) { if(status.bgTiledataSelect == 0) {
tdaddr += 0x1000 + ((int8)tile << 4); tdaddr += 0x1000 + ((int8)tile << 4);
} else { } else {
tdaddr += 0x0000 + (tile << 4); tdaddr += 0x0000 + (tile << 4);
@ -35,11 +35,11 @@ auto PPU::cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) ->
if(attr & 0x20) data = hflip(data); if(attr & 0x20) data = hflip(data);
} }
auto PPU::cgb_scanline() -> void { auto PPU::scanlineCGB() -> void {
px = 0; px = 0;
if(!enabled()) return; if(!enabled()) return;
const uint Height = (status.ob_size == 0 ? 8 : 16); const uint Height = (status.obSize == 0 ? 8 : 16);
sprites = 0; sprites = 0;
//find first ten sprites on this scanline //find first ten sprites on this scanline
@ -47,7 +47,7 @@ auto PPU::cgb_scanline() -> void {
Sprite& s = sprite[sprites]; Sprite& s = sprite[sprites];
s.y = oam[n + 0] - 16; s.y = oam[n + 0] - 16;
s.x = oam[n + 1] - 8; s.x = oam[n + 1] - 8;
s.tile = oam[n + 2] & ~status.ob_size; s.tile = oam[n + 2] & ~status.obSize;
s.attr = oam[n + 3]; s.attr = oam[n + 3];
s.y = status.ly - s.y; s.y = status.ly - s.y;
@ -63,22 +63,22 @@ auto PPU::cgb_scanline() -> void {
} }
} }
auto PPU::cgb_run() -> void { auto PPU::runCGB() -> void {
ob.color = 0; ob.color = 0;
ob.palette = 0; ob.palette = 0;
ob.priority = 0; ob.priority = 0;
uint color = 0x7fff; uint color = 0x7fff;
if(enabled()) { if(enabled()) {
cgb_run_bg(); runBackgroundCGB();
if(status.window_display_enable) cgb_run_window(); if(status.windowDisplayEnable) runWindowCGB();
if(status.ob_enable) cgb_run_ob(); if(status.obEnable) runObjectsCGB();
if(ob.palette == 0) { if(ob.palette == 0) {
color = bg.color; color = bg.color;
} else if(bg.palette == 0) { } else if(bg.palette == 0) {
color = ob.color; color = ob.color;
} else if(status.bg_enable == 0) { } else if(status.bgEnable == 0) {
color = ob.color; color = ob.color;
} else if(bg.priority) { } else if(bg.priority) {
color = bg.color; color = bg.color;
@ -93,11 +93,11 @@ auto PPU::cgb_run() -> void {
*output = color; *output = color;
} }
auto PPU::cgb_run_bg() -> void { auto PPU::runBackgroundCGB() -> void {
uint scrolly = (status.ly + status.scy) & 255; uint scrolly = (status.ly + status.scy) & 255;
uint scrollx = (px + status.scx) & 255; uint scrollx = (px + status.scx) & 255;
uint tx = scrollx & 7; uint tx = scrollx & 7;
if(tx == 0 || px == 0) cgb_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.attr, background.data); if(tx == 0 || px == 0) readTileCGB(status.bgTilemapSelect, scrollx, scrolly, background.attr, background.data);
uint index = 0; uint index = 0;
index |= (background.data & (0x0080 >> tx)) ? 1 : 0; index |= (background.data & (0x0080 >> tx)) ? 1 : 0;
@ -113,13 +113,13 @@ auto PPU::cgb_run_bg() -> void {
bg.priority = background.attr & 0x80; bg.priority = background.attr & 0x80;
} }
auto PPU::cgb_run_window() -> void { auto PPU::runWindowCGB() -> void {
uint scrolly = status.ly - status.wy; uint scrolly = status.ly - status.wy;
uint scrollx = px + 7 - status.wx; uint scrollx = px + 7 - status.wx;
if(scrolly >= 144u) return; //also matches underflow (scrolly < 0) if(scrolly >= 144u) return; //also matches underflow (scrolly < 0)
if(scrollx >= 160u) return; //also matches underflow (scrollx < 0) if(scrollx >= 160u) return; //also matches underflow (scrollx < 0)
uint tx = scrollx & 7; uint tx = scrollx & 7;
if(tx == 0 || px == 0) cgb_read_tile(status.window_tilemap_select, scrollx, scrolly, window.attr, window.data); if(tx == 0 || px == 0) readTileCGB(status.windowTilemapSelect, scrollx, scrolly, window.attr, window.data);
uint index = 0; uint index = 0;
index |= (window.data & (0x0080 >> tx)) ? 1 : 0; index |= (window.data & (0x0080 >> tx)) ? 1 : 0;
@ -135,7 +135,7 @@ auto PPU::cgb_run_window() -> void {
bg.priority = window.attr & 0x80; bg.priority = window.attr & 0x80;
} }
auto PPU::cgb_run_ob() -> void { auto PPU::runObjectsCGB() -> void {
//render backwards, so that first sprite has priority //render backwards, so that first sprite has priority
for(int n = sprites - 1; n >= 0; n--) { for(int n = sprites - 1; n >= 0; n--) {
Sprite& s = sprite[n]; Sprite& s = sprite[n];

View File

@ -4,10 +4,10 @@
//0x20: horizontal flip //0x20: horizontal flip
//0x10: palette# //0x10: palette#
auto PPU::dmg_read_tile(bool select, uint x, uint y, uint& data) -> void { auto PPU::readTileDMG(bool select, uint x, uint y, uint& data) -> void {
uint tmaddr = 0x1800 + (select << 10), tdaddr; uint tmaddr = 0x1800 + (select << 10), tdaddr;
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff; tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
if(status.bg_tiledata_select == 0) { if(status.bgTiledataSelect == 0) {
tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4); tdaddr = 0x1000 + ((int8)vram[tmaddr] << 4);
} else { } else {
tdaddr = 0x0000 + (vram[tmaddr] << 4); tdaddr = 0x0000 + (vram[tmaddr] << 4);
@ -17,11 +17,11 @@ auto PPU::dmg_read_tile(bool select, uint x, uint y, uint& data) -> void {
data |= vram[tdaddr + 1] << 8; data |= vram[tdaddr + 1] << 8;
} }
auto PPU::dmg_scanline() -> void { auto PPU::scanlineDMG() -> void {
px = 0; px = 0;
if(!enabled()) return; if(!enabled()) return;
const uint Height = (status.ob_size == 0 ? 8 : 16); const uint Height = (status.obSize == 0 ? 8 : 16);
sprites = 0; sprites = 0;
//find first ten sprites on this scanline //find first ten sprites on this scanline
@ -29,7 +29,7 @@ auto PPU::dmg_scanline() -> void {
Sprite& s = sprite[sprites]; Sprite& s = sprite[sprites];
s.y = oam[n + 0] - 16; s.y = oam[n + 0] - 16;
s.x = oam[n + 1] - 8; s.x = oam[n + 1] - 8;
s.tile = oam[n + 2] & ~status.ob_size; s.tile = oam[n + 2] & ~status.obSize;
s.attr = oam[n + 3]; s.attr = oam[n + 3];
s.y = status.ly - s.y; s.y = status.ly - s.y;
@ -52,7 +52,7 @@ auto PPU::dmg_scanline() -> void {
} }
} }
auto PPU::dmg_run() -> void { auto PPU::runDMG() -> void {
bg.color = 0; bg.color = 0;
bg.palette = 0; bg.palette = 0;
@ -61,9 +61,9 @@ auto PPU::dmg_run() -> void {
uint color = 0; uint color = 0;
if(enabled()) { if(enabled()) {
if(status.bg_enable) dmg_run_bg(); if(status.bgEnable) runBackgroundDMG();
if(status.window_display_enable) dmg_run_window(); if(status.windowDisplayEnable) runWindowDMG();
if(status.ob_enable) dmg_run_ob(); if(status.obEnable) runObjectsDMG();
if(ob.palette == 0) { if(ob.palette == 0) {
color = bg.color; color = bg.color;
@ -81,11 +81,11 @@ auto PPU::dmg_run() -> void {
interface->lcdOutput(color); //Super Game Boy notification interface->lcdOutput(color); //Super Game Boy notification
} }
auto PPU::dmg_run_bg() -> void { auto PPU::runBackgroundDMG() -> void {
uint scrolly = (status.ly + status.scy) & 255; uint scrolly = (status.ly + status.scy) & 255;
uint scrollx = (px + status.scx) & 255; uint scrollx = (px + status.scx) & 255;
uint tx = scrollx & 7; uint tx = scrollx & 7;
if(tx == 0 || px == 0) dmg_read_tile(status.bg_tilemap_select, scrollx, scrolly, background.data); if(tx == 0 || px == 0) readTileDMG(status.bgTilemapSelect, scrollx, scrolly, background.data);
uint index = 0; uint index = 0;
index |= (background.data & (0x0080 >> tx)) ? 1 : 0; index |= (background.data & (0x0080 >> tx)) ? 1 : 0;
@ -95,13 +95,13 @@ auto PPU::dmg_run_bg() -> void {
bg.palette = index; bg.palette = index;
} }
auto PPU::dmg_run_window() -> void { auto PPU::runWindowDMG() -> void {
uint scrolly = status.ly - status.wy; uint scrolly = status.ly - status.wy;
uint scrollx = px + 7 - status.wx; uint scrollx = px + 7 - status.wx;
if(scrolly >= 144u) return; //also matches underflow (scrolly < 0) if(scrolly >= 144u) return; //also matches underflow (scrolly < 0)
if(scrollx >= 160u) return; //also matches underflow (scrollx < 0) if(scrollx >= 160u) return; //also matches underflow (scrollx < 0)
uint tx = scrollx & 7; uint tx = scrollx & 7;
if(tx == 0 || px == 0) dmg_read_tile(status.window_tilemap_select, scrollx, scrolly, window.data); if(tx == 0 || px == 0) readTileDMG(status.windowTilemapSelect, scrollx, scrolly, window.data);
uint index = 0; uint index = 0;
index |= (window.data & (0x0080 >> tx)) ? 1 : 0; index |= (window.data & (0x0080 >> tx)) ? 1 : 0;
@ -111,7 +111,7 @@ auto PPU::dmg_run_window() -> void {
bg.palette = index; bg.palette = index;
} }
auto PPU::dmg_run_ob() -> void { auto PPU::runObjectsDMG() -> void {
//render backwards, so that first sprite has priority //render backwards, so that first sprite has priority
for(int n = sprites - 1; n >= 0; n--) { for(int n = sprites - 1; n >= 0; n--) {
Sprite& s = sprite[n]; Sprite& s = sprite[n];

View File

@ -1,33 +1,33 @@
auto PPU::vram_addr(uint16 addr) const -> uint { auto PPU::vramAddress(uint16 addr) const -> uint {
return (status.vram_bank * 0x2000) + (addr & 0x1fff); return status.vramBank << 13 | (uint13)addr;
} }
auto PPU::readIO(uint16 addr) -> uint8 { auto PPU::readIO(uint16 addr) -> uint8 {
if(addr >= 0x8000 && addr <= 0x9fff) { if(addr >= 0x8000 && addr <= 0x9fff) {
return vram[vram_addr(addr)]; return vram[vramAddress(addr)];
} }
if(addr >= 0xfe00 && addr <= 0xfe9f) { if(addr >= 0xfe00 && addr <= 0xfe9f) {
if(status.dma_active && status.dma_clock >= 8) return 0xff; if(status.dmaActive && status.dmaClock >= 8) return 0xff;
return oam[addr & 0xff]; return oam[addr & 0xff];
} }
if(addr == 0xff40) { //LCDC if(addr == 0xff40) { //LCDC
return (status.display_enable << 7) return (status.displayEnable << 7)
| (status.window_tilemap_select << 6) | (status.windowTilemapSelect << 6)
| (status.window_display_enable << 5) | (status.windowDisplayEnable << 5)
| (status.bg_tiledata_select << 4) | (status.bgTiledataSelect << 4)
| (status.bg_tilemap_select << 3) | (status.bgTilemapSelect << 3)
| (status.ob_size << 2) | (status.obSize << 2)
| (status.ob_enable << 1) | (status.obEnable << 1)
| (status.bg_enable << 0); | (status.bgEnable << 0);
} }
if(addr == 0xff41) { //STAT if(addr == 0xff41) { //STAT
return (status.interrupt_lyc << 6) return (status.interruptLYC << 6)
| (status.interrupt_oam << 5) | (status.interruptOAM << 5)
| (status.interrupt_vblank << 4) | (status.interruptVblank << 4)
| (status.interrupt_hblank << 3) | (status.interruptHblank << 3)
| ((status.ly == status.lyc) << 2) | ((status.ly == status.lyc) << 2)
| (status.mode << 0); | (status.mode << 0);
} }
@ -78,11 +78,11 @@ auto PPU::readIO(uint16 addr) -> uint8 {
} }
if(addr == 0xff4f) { //VBK if(addr == 0xff4f) { //VBK
return status.vram_bank; return status.vramBank;
} }
if(addr == 0xff68) { //BGPI if(addr == 0xff68) { //BGPI
return status.bgpi_increment << 7 | status.bgpi; return status.bgpiIncrement << 7 | status.bgpi;
} }
if(addr == 0xff69) { //BGPD if(addr == 0xff69) { //BGPD
@ -90,7 +90,7 @@ auto PPU::readIO(uint16 addr) -> uint8 {
} }
if(addr == 0xff6a) { //OBPI if(addr == 0xff6a) { //OBPI
return status.obpi_increment << 7 | status.obpi; return status.obpiIncrement << 7 | status.obpi;
} }
if(addr == 0xff6b) { //OBPD if(addr == 0xff6b) { //OBPD
@ -102,18 +102,18 @@ auto PPU::readIO(uint16 addr) -> uint8 {
auto PPU::writeIO(uint16 addr, uint8 data) -> void { auto PPU::writeIO(uint16 addr, uint8 data) -> void {
if(addr >= 0x8000 && addr <= 0x9fff) { if(addr >= 0x8000 && addr <= 0x9fff) {
vram[vram_addr(addr)] = data; vram[vramAddress(addr)] = data;
return; return;
} }
if(addr >= 0xfe00 && addr <= 0xfe9f) { if(addr >= 0xfe00 && addr <= 0xfe9f) {
if(status.dma_active && status.dma_clock >= 8) return; if(status.dmaActive && status.dmaClock >= 8) return;
oam[addr & 0xff] = data; oam[addr & 0xff] = data;
return; return;
} }
if(addr == 0xff40) { //LCDC if(addr == 0xff40) { //LCDC
if(status.display_enable == false && (data & 0x80)) { if(!status.displayEnable && (data & 0x80)) {
status.ly = 0; status.ly = 0;
status.lx = 0; status.lx = 0;
@ -123,22 +123,22 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
this->clock = clock; this->clock = clock;
} }
status.display_enable = data & 0x80; status.displayEnable = data & 0x80;
status.window_tilemap_select = data & 0x40; status.windowTilemapSelect = data & 0x40;
status.window_display_enable = data & 0x20; status.windowDisplayEnable = data & 0x20;
status.bg_tiledata_select = data & 0x10; status.bgTiledataSelect = data & 0x10;
status.bg_tilemap_select = data & 0x08; status.bgTilemapSelect = data & 0x08;
status.ob_size = data & 0x04; status.obSize = data & 0x04;
status.ob_enable = data & 0x02; status.obEnable = data & 0x02;
status.bg_enable = data & 0x01; status.bgEnable = data & 0x01;
return; return;
} }
if(addr == 0xff41) { //STAT if(addr == 0xff41) { //STAT
status.interrupt_lyc = data & 0x40; status.interruptLYC = data & 0x40;
status.interrupt_oam = data & 0x20; status.interruptOAM = data & 0x20;
status.interrupt_vblank = data & 0x10; status.interruptVblank = data & 0x10;
status.interrupt_hblank = data & 0x08; status.interruptHblank = data & 0x08;
//hardware bug: writes to STAT on DMG,SGB during vblank triggers STAT IRQ //hardware bug: writes to STAT on DMG,SGB during vblank triggers STAT IRQ
//note: this behavior isn't entirely correct; more research is needed ... //note: this behavior isn't entirely correct; more research is needed ...
@ -170,9 +170,9 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
} }
if(addr == 0xff46) { //DMA if(addr == 0xff46) { //DMA
status.dma_active = true; status.dmaActive = true;
status.dma_clock = 0; status.dmaClock = 0;
status.dma_bank = data; status.dmaBank = data;
return; return;
} }
@ -211,29 +211,29 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
} }
if(addr == 0xff4f) { //VBK if(addr == 0xff4f) { //VBK
status.vram_bank = data & 1; status.vramBank = data & 1;
return; return;
} }
if(addr == 0xff68) { //BGPI if(addr == 0xff68) { //BGPI
status.bgpi_increment = data & 0x80; status.bgpiIncrement = data & 0x80;
status.bgpi = data & 0x3f; status.bgpi = data & 0x3f;
return; return;
} }
if(addr == 0xff69) { //BGPD if(addr == 0xff69) { //BGPD
bgpd[status.bgpi] = data; bgpd[status.bgpi] = data;
if(status.bgpi_increment) status.bgpi++; if(status.bgpiIncrement) status.bgpi++;
return; return;
} }
if(addr == 0xff6a) { //OBPI if(addr == 0xff6a) { //OBPI
status.obpi_increment = data & 0x80; status.obpiIncrement = data & 0x80;
status.obpi = data & 0x3f; status.obpi = data & 0x3f;
} }
if(addr == 0xff6b) { //OBPD if(addr == 0xff6b) { //OBPD
obpd[status.obpi] = data; obpd[status.obpi] = data;
if(status.obpi_increment) status.obpi++; if(status.obpiIncrement) status.obpi++;
} }
} }

View File

@ -3,12 +3,12 @@
namespace GameBoy { namespace GameBoy {
PPU ppu; PPU ppu;
#include "mmio.cpp" #include "io.cpp"
#include "dmg.cpp" #include "dmg.cpp"
#include "cgb.cpp" #include "cgb.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto PPU::enabled() const -> bool { return status.display_enable; } auto PPU::enabled() const -> bool { return status.displayEnable; }
auto PPU::Enter() -> void { auto PPU::Enter() -> void {
while(true) scheduler.synchronize(), ppu.main(); while(true) scheduler.synchronize(), ppu.main();
@ -21,20 +21,20 @@ auto PPU::main() -> void {
if(status.ly <= 143) { if(status.ly <= 143) {
mode(2); mode(2);
scanline(); scanline();
wait(92); step(92);
mode(3); mode(3);
for(auto n : range(160)) { for(auto n : range(160)) {
run(); run();
wait(1); step(1);
} }
mode(0); mode(0);
if(enabled()) cpu.hblank(); if(enabled()) cpu.hblank();
wait(204); step(204);
} else { } else {
mode(1); mode(1);
wait(456); step(456);
} }
status.ly++; status.ly++;
@ -56,10 +56,10 @@ auto PPU::mode(uint mode) -> void {
auto PPU::stat() -> void { auto PPU::stat() -> void {
bool irq = status.irq; bool irq = status.irq;
status.irq = status.interrupt_hblank && status.mode == 0; status.irq = status.interruptHblank && status.mode == 0;
status.irq |= status.interrupt_vblank && status.mode == 1; status.irq |= status.interruptVblank && status.mode == 1;
status.irq |= status.interrupt_oam && status.mode == 2; status.irq |= status.interruptOAM && status.mode == 2;
status.irq |= status.interrupt_lyc && coincidence(); status.irq |= status.interruptLYC && coincidence();
if(!irq && status.irq) cpu.raise(CPU::Interrupt::Stat); if(!irq && status.irq) cpu.raise(CPU::Interrupt::Stat);
} }
@ -74,11 +74,11 @@ auto PPU::refresh() -> void {
if(!system.sgb()) Emulator::video.refresh(screen, 160 * sizeof(uint32), 160, 144); if(!system.sgb()) Emulator::video.refresh(screen, 160 * sizeof(uint32), 160, 144);
} }
auto PPU::wait(uint clocks) -> void { auto PPU::step(uint clocks) -> void {
while(clocks--) { while(clocks--) {
stat(); stat();
if(status.dma_active) { if(status.dmaActive) {
uint hi = status.dma_clock++; uint hi = status.dmaClock++;
uint lo = hi & (cpu.status.speedDouble ? 1 : 3); uint lo = hi & (cpu.status.speedDouble ? 1 : 3);
hi >>= cpu.status.speedDouble ? 1 : 2; hi >>= cpu.status.speedDouble ? 1 : 2;
if(lo == 0) { if(lo == 0) {
@ -86,9 +86,9 @@ auto PPU::wait(uint clocks) -> void {
//warm-up //warm-up
} else if(hi == 161) { } else if(hi == 161) {
//cool-down; disable //cool-down; disable
status.dma_active = false; status.dmaActive = false;
} else { } else {
oam[hi - 1] = bus.read(status.dma_bank << 8 | hi - 1); oam[hi - 1] = bus.read(status.dmaBank << 8 | hi - 1);
} }
} }
} }
@ -110,11 +110,11 @@ auto PPU::power() -> void {
create(Enter, 4 * 1024 * 1024); create(Enter, 4 * 1024 * 1024);
if(system.cgb()) { if(system.cgb()) {
scanline = {&PPU::cgb_scanline, this}; scanline = {&PPU::scanlineCGB, this};
run = {&PPU::cgb_run, this}; run = {&PPU::runCGB, this};
} else { } else {
scanline = {&PPU::dmg_scanline, this}; scanline = {&PPU::scanlineDMG, this};
run = {&PPU::dmg_run, this}; run = {&PPU::runDMG, this};
} }
for(uint n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM for(uint n = 0x8000; n <= 0x9fff; n++) bus.mmio[n] = this; //VRAM
@ -149,43 +149,7 @@ auto PPU::power() -> void {
for(auto& n : bgpd) n = 0x0000; for(auto& n : bgpd) n = 0x0000;
for(auto& n : obpd) n = 0x0000; for(auto& n : obpd) n = 0x0000;
status.irq = false; memory::fill(&status, sizeof(Status));
status.lx = 0;
status.display_enable = 0;
status.window_tilemap_select = 0;
status.window_display_enable = 0;
status.bg_tiledata_select = 0;
status.bg_tilemap_select = 0;
status.ob_size = 0;
status.ob_enable = 0;
status.bg_enable = 0;
status.interrupt_lyc = 0;
status.interrupt_oam = 0;
status.interrupt_vblank = 0;
status.interrupt_hblank = 0;
status.mode = 0;
status.scy = 0;
status.scx = 0;
status.ly = 0;
status.lyc = 0;
status.dma_active = false;
status.dma_clock = 0;
status.dma_bank = 0;
status.wy = 0;
status.wx = 0;
status.vram_bank = 0;
status.bgpi_increment = 0;
status.bgpi = 0;
status.obpi_increment = 0;
status.obpi = 0;
for(auto& n : screen) n = 0; for(auto& n : screen) n = 0;

View File

@ -7,30 +7,30 @@ struct PPU : Thread, MMIO {
auto stat() -> void; auto stat() -> void;
auto coincidence() -> bool; auto coincidence() -> bool;
auto refresh() -> void; auto refresh() -> void;
auto wait(uint clocks) -> void; auto step(uint clocks) -> void;
auto hflip(uint data) const -> uint; auto hflip(uint data) const -> uint;
//mmio.cpp //io.cpp
auto vram_addr(uint16 addr) const -> uint; auto vramAddress(uint16 addr) const -> uint;
auto readIO(uint16 addr) -> uint8; auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void; auto writeIO(uint16 addr, uint8 data) -> void;
//dmg.cpp //dmg.cpp
auto dmg_read_tile(bool select, uint x, uint y, uint& data) -> void; auto readTileDMG(bool select, uint x, uint y, uint& data) -> void;
auto dmg_scanline() -> void; auto scanlineDMG() -> void;
auto dmg_run() -> void; auto runDMG() -> void;
auto dmg_run_bg() -> void; auto runBackgroundDMG() -> void;
auto dmg_run_window() -> void; auto runWindowDMG() -> void;
auto dmg_run_ob() -> void; auto runObjectsDMG() -> void;
//cgb.cpp //cgb.cpp
auto cgb_read_tile(bool select, uint x, uint y, uint& attr, uint& data) -> void; auto readTileCGB(bool select, uint x, uint y, uint& attr, uint& data) -> void;
auto cgb_scanline() -> void; auto scanlineCGB() -> void;
auto cgb_run() -> void; auto runCGB() -> void;
auto cgb_run_bg() -> void; auto runBackgroundCGB() -> void;
auto cgb_run_window() -> void; auto runWindowCGB() -> void;
auto cgb_run_ob() -> void; auto runObjectsCGB() -> void;
auto power() -> void; auto power() -> void;
@ -51,20 +51,20 @@ struct PPU : Thread, MMIO {
uint lx; uint lx;
//$ff40 LCDC //$ff40 LCDC
bool display_enable; bool displayEnable;
bool window_tilemap_select; bool windowTilemapSelect;
bool window_display_enable; bool windowDisplayEnable;
bool bg_tiledata_select; bool bgTiledataSelect;
bool bg_tilemap_select; bool bgTilemapSelect;
bool ob_size; bool obSize;
bool ob_enable; bool obEnable;
bool bg_enable; bool bgEnable;
//$ff41 STAT //$ff41 STAT
bool interrupt_lyc; bool interruptLYC;
bool interrupt_oam; bool interruptOAM;
bool interrupt_vblank; bool interruptVblank;
bool interrupt_hblank; bool interruptHblank;
uint2 mode; uint2 mode;
//$ff42 SCY //$ff42 SCY
@ -80,9 +80,9 @@ struct PPU : Thread, MMIO {
uint8 lyc; uint8 lyc;
//$ff46 DMA //$ff46 DMA
bool dma_active; bool dmaActive;
uint dma_clock; uint dmaClock;
uint8 dma_bank; uint8 dmaBank;
//$ff4a WY //$ff4a WY
uint8 wy; uint8 wy;
@ -91,14 +91,14 @@ struct PPU : Thread, MMIO {
uint8 wx; uint8 wx;
//$ff4f VBK //$ff4f VBK
bool vram_bank; bool vramBank;
//$ff68 BGPI //$ff68 BGPI
bool bgpi_increment; bool bgpiIncrement;
uint6 bgpi; uint6 bgpi;
//$ff6a OBPI //$ff6a OBPI
bool obpi_increment; bool obpiIncrement;
uint8 obpi; uint8 obpi;
} status; } status;

View File

@ -12,19 +12,19 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(status.irq); s.integer(status.irq);
s.integer(status.lx); s.integer(status.lx);
s.integer(status.display_enable); s.integer(status.displayEnable);
s.integer(status.window_tilemap_select); s.integer(status.windowTilemapSelect);
s.integer(status.window_display_enable); s.integer(status.windowDisplayEnable);
s.integer(status.bg_tiledata_select); s.integer(status.bgTiledataSelect);
s.integer(status.bg_tilemap_select); s.integer(status.bgTilemapSelect);
s.integer(status.ob_size); s.integer(status.obSize);
s.integer(status.ob_enable); s.integer(status.obEnable);
s.integer(status.bg_enable); s.integer(status.bgEnable);
s.integer(status.interrupt_lyc); s.integer(status.interruptLYC);
s.integer(status.interrupt_oam); s.integer(status.interruptOAM);
s.integer(status.interrupt_vblank); s.integer(status.interruptVblank);
s.integer(status.interrupt_hblank); s.integer(status.interruptHblank);
s.integer(status.mode); s.integer(status.mode);
s.integer(status.scy); s.integer(status.scy);
@ -33,19 +33,19 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(status.ly); s.integer(status.ly);
s.integer(status.lyc); s.integer(status.lyc);
s.integer(status.dma_active); s.integer(status.dmaActive);
s.integer(status.dma_clock); s.integer(status.dmaClock);
s.integer(status.dma_bank); s.integer(status.dmaBank);
s.integer(status.wy); s.integer(status.wy);
s.integer(status.wx); s.integer(status.wx);
s.integer(status.vram_bank); s.integer(status.vramBank);
s.integer(status.bgpi_increment); s.integer(status.bgpiIncrement);
s.integer(status.bgpi); s.integer(status.bgpi);
s.integer(status.obpi_increment); s.integer(status.obpiIncrement);
s.integer(status.obpi); s.integer(status.obpi);
s.array(screen); s.array(screen);

View File

@ -2,7 +2,7 @@
namespace GameBoyAdvance { namespace GameBoyAdvance {
#include "mmio.cpp" #include "io.cpp"
#include "square.cpp" #include "square.cpp"
#include "square1.cpp" #include "square1.cpp"
#include "square2.cpp" #include "square2.cpp"
@ -87,7 +87,7 @@ auto APU::power() -> void {
regs.bias.amplitude = 0; regs.bias.amplitude = 0;
regs.bias.level = 0x200; regs.bias.level = 0x200;
for(uint n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this; for(uint n = 0x060; n <= 0x0a7; n++) bus.io[n] = this;
} }
} }

View File

@ -1,4 +1,4 @@
struct APU : Thread, MMIO { struct APU : Thread, IO {
shared_pointer<Emulator::Stream> stream; shared_pointer<Emulator::Stream> stream;
#include "registers.hpp" #include "registers.hpp"
@ -7,8 +7,8 @@ struct APU : Thread, MMIO {
auto main() -> void; auto main() -> void;
auto step(uint clocks) -> void; auto step(uint clocks) -> void;
auto read(uint32 addr) -> uint8; auto readIO(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void; auto writeIO(uint32 addr, uint8 byte) -> void;
auto power() -> void; auto power() -> void;
auto runsequencer() -> void; auto runsequencer() -> void;

View File

@ -1,4 +1,4 @@
auto APU::read(uint32 addr) -> uint8 { auto APU::readIO(uint32 addr) -> uint8 {
switch(addr) { switch(addr) {
//NR10 //NR10
@ -111,7 +111,7 @@ auto APU::read(uint32 addr) -> uint8 {
return 0; return 0;
} }
auto APU::write(uint32 addr, uint8 data) -> void { auto APU::writeIO(uint32 addr, uint8 data) -> void {
switch(addr) { switch(addr) {
//NR10 //NR10

View File

@ -42,7 +42,7 @@ auto Cartridge::FLASH::write(uint16 addr, uint8 byte) -> void {
if(byte == 0x10 && addr == 0x5555) { if(byte == 0x10 && addr == 0x5555) {
if(erasemode) { if(erasemode) {
erasemode = false; erasemode = false;
for(unsigned n = 0; n < size; n++) data[n] = 0xff; for(uint n : range(size)) data[n] = 0xff;
} }
} }
@ -50,8 +50,8 @@ auto Cartridge::FLASH::write(uint16 addr, uint8 byte) -> void {
//command only valid for non-Atmel chips //command only valid for non-Atmel chips
if(erasemode && id != 0x3d1f) { if(erasemode && id != 0x3d1f) {
erasemode = false; erasemode = false;
unsigned offset = bank << 16 | (addr & ~4095); uint offset = bank << 16 | (addr & ~4095);
for(unsigned n = 0; n < 4096; n++) data[offset++] = 0xff; for(uint n : range(4096)) data[offset++] = 0xff;
} }
} }

View File

@ -1,63 +1,63 @@
auto CPU::busIdle() -> void { auto CPU::_idle() -> void {
prefetch_step(1); prefetchStep(1);
} }
auto CPU::busRead(uint mode, uint32 addr) -> uint32 { auto CPU::_read(uint mode, uint32 addr) -> uint32 {
uint wait = busWait(mode, addr); uint wait = this->wait(mode, addr);
uint word = pipeline.fetch.instruction; uint word = pipeline.fetch.instruction;
if(addr >= 0x1000'0000) { if(addr >= 0x1000'0000) {
prefetch_step(wait); prefetchStep(wait);
} else if(addr & 0x0800'0000) { } else if(addr & 0x0800'0000) {
if(mode & Prefetch && regs.wait.control.prefetch) { if(mode & Prefetch && regs.wait.control.prefetch) {
prefetch_sync(addr); prefetchSync(addr);
word = prefetch_read(); word = prefetchRead();
if(mode & Word) word |= prefetch_read() << 16; if(mode & Word) word |= prefetchRead() << 16;
} else { } else {
if(!active.dma) prefetch_wait(); if(!active.dma) prefetchWait();
step(wait - 1); step(wait - 1);
word = cartridge.read(mode, addr); word = cartridge.read(mode, addr);
step(1); step(1);
} }
} else { } else {
prefetch_step(wait - 1); prefetchStep(wait - 1);
if(addr < 0x0200'0000) word = bios.read(mode, addr); if(addr < 0x0200'0000) word = bios.read(mode, addr);
else if(addr < 0x0300'0000) word = ewram_read(mode, addr); else if(addr < 0x0300'0000) word = readEWRAM(mode, addr);
else if(addr < 0x0400'0000) word = iwram_read(mode, addr); else if(addr < 0x0400'0000) word = readIWRAM(mode, addr);
else if(addr >= 0x0700'0000) word = ppu.oam_read(mode, addr); else if(addr >= 0x0700'0000) word = ppu.readOAM(mode, addr);
else if(addr >= 0x0600'0000) word = ppu.vram_read(mode, addr); else if(addr >= 0x0600'0000) word = ppu.readVRAM(mode, addr);
else if(addr >= 0x0500'0000) word = ppu.pram_read(mode, addr); else if(addr >= 0x0500'0000) word = ppu.readPRAM(mode, addr);
else if((addr & 0xffff'fc00) == 0x0400'0000) word = bus.mmio[addr & 0x3ff]->read(mode, addr); else if((addr & 0xffff'fc00) == 0x0400'0000) word = bus.io[addr & 0x3ff]->readIO(mode, addr);
else if((addr & 0xff00'ffff) == 0x0400'0800) word = ((MMIO*)this)->read(mode, 0x0400'0800 | (addr & 3)); else if((addr & 0xff00'ffff) == 0x0400'0800) word = ((IO*)this)->readIO(mode, 0x0400'0800 | (addr & 3));
prefetch_step(1); prefetchStep(1);
} }
return word; return word;
} }
auto CPU::busWrite(uint mode, uint32 addr, uint32 word) -> void { auto CPU::_write(uint mode, uint32 addr, uint32 word) -> void {
uint wait = busWait(mode, addr); uint wait = this->wait(mode, addr);
if(addr >= 0x1000'0000) { if(addr >= 0x1000'0000) {
prefetch_step(wait); prefetchStep(wait);
} else if(addr & 0x0800'0000) { } else if(addr & 0x0800'0000) {
if(!active.dma) prefetch_wait(); if(!active.dma) prefetchWait();
step(wait); step(wait);
cartridge.write(mode, addr, word); cartridge.write(mode, addr, word);
} else { } else {
prefetch_step(wait); prefetchStep(wait);
if(addr < 0x0200'0000); if(addr < 0x0200'0000);
else if(addr < 0x0300'0000) ewram_write(mode, addr, word); else if(addr < 0x0300'0000) writeEWRAM(mode, addr, word);
else if(addr < 0x0400'0000) iwram_write(mode, addr, word); else if(addr < 0x0400'0000) writeIWRAM(mode, addr, word);
else if(addr >= 0x0700'0000) ppu.oam_write(mode, addr, word); else if(addr >= 0x0700'0000) ppu.writeOAM(mode, addr, word);
else if(addr >= 0x0600'0000) ppu.vram_write(mode, addr, word); else if(addr >= 0x0600'0000) ppu.writeVRAM(mode, addr, word);
else if(addr >= 0x0500'0000) ppu.pram_write(mode, addr, word); else if(addr >= 0x0500'0000) ppu.writePRAM(mode, addr, word);
else if((addr & 0xffff'fc00) == 0x0400'0000) bus.mmio[addr & 0x3ff]->write(mode, addr, word); else if((addr & 0xffff'fc00) == 0x0400'0000) bus.io[addr & 0x3ff]->writeIO(mode, addr, word);
else if((addr & 0xff00'ffff) == 0x0400'0800) ((MMIO*)this)->write(mode, 0x0400'0800 | (addr & 3), word); else if((addr & 0xff00'ffff) == 0x0400'0800) ((IO*)this)->writeIO(mode, 0x0400'0800 | (addr & 3), word);
} }
} }
auto CPU::busWait(uint mode, uint32 addr) -> uint { auto CPU::wait(uint mode, uint32 addr) -> uint {
if(addr >= 0x1000'0000) return 1; //unmapped if(addr >= 0x1000'0000) return 1; //unmapped
if(addr < 0x0200'0000) return 1; if(addr < 0x0200'0000) return 1;
if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1); if(addr < 0x0300'0000) return (16 - regs.memory.control.ewramwait) * (mode & Word ? 2 : 1);

View File

@ -4,7 +4,7 @@ namespace GameBoyAdvance {
#include "prefetch.cpp" #include "prefetch.cpp"
#include "bus.cpp" #include "bus.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "dma.cpp" #include "dma.cpp"
#include "timer.cpp" #include "timer.cpp"
@ -56,14 +56,14 @@ auto CPU::main() -> void {
if(regs.mode == Registers::Mode::Stop) { if(regs.mode == Registers::Mode::Stop) {
if(!(regs.irq.enable & regs.irq.flag & Interrupt::Keypad)) { if(!(regs.irq.enable & regs.irq.flag & Interrupt::Keypad)) {
sync_step(16); //STOP does not advance timers syncStep(16); //STOP does not advance timers
} else { } else {
regs.mode = Registers::Mode::Normal; regs.mode = Registers::Mode::Normal;
} }
return; return;
} }
dma_run(); dmaRun();
if(regs.mode == Registers::Mode::Halt) { if(regs.mode == Registers::Mode::Halt) {
if(!(regs.irq.enable & regs.irq.flag)) { if(!(regs.irq.enable & regs.irq.flag)) {
@ -78,11 +78,11 @@ auto CPU::main() -> void {
} }
auto CPU::step(uint clocks) -> void { auto CPU::step(uint clocks) -> void {
timer_step(clocks); timerStep(clocks);
sync_step(clocks); syncStep(clocks);
} }
auto CPU::sync_step(uint clocks) -> void { auto CPU::syncStep(uint clocks) -> void {
ppu.clock -= clocks; ppu.clock -= clocks;
if(ppu.clock < 0) co_switch(ppu.thread); if(ppu.clock < 0) co_switch(ppu.thread);
@ -90,7 +90,7 @@ auto CPU::sync_step(uint clocks) -> void {
if(apu.clock < 0) co_switch(apu.thread); if(apu.clock < 0) co_switch(apu.thread);
} }
auto CPU::keypad_run() -> void { auto CPU::keypadRun() -> void {
//lookup table to convert button indexes to Emulator::Interface indexes //lookup table to convert button indexes to Emulator::Interface indexes
static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1, 7, 6}; static const uint lookup[] = {5, 4, 8, 9, 3, 2, 0, 1, 7, 6};
@ -166,13 +166,13 @@ auto CPU::power() -> void {
active.dma = false; active.dma = false;
for(uint n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this; //DMA for(uint n = 0x0b0; n <= 0x0df; n++) bus.io[n] = this; //DMA
for(uint n = 0x100; n <= 0x10f; n++) bus.mmio[n] = this; //Timers for(uint n = 0x100; n <= 0x10f; n++) bus.io[n] = this; //Timers
for(uint n = 0x120; n <= 0x12b; n++) bus.mmio[n] = this; //Serial for(uint n = 0x120; n <= 0x12b; n++) bus.io[n] = this; //Serial
for(uint n = 0x130; n <= 0x133; n++) bus.mmio[n] = this; //Keypad for(uint n = 0x130; n <= 0x133; n++) bus.io[n] = this; //Keypad
for(uint n = 0x134; n <= 0x159; n++) bus.mmio[n] = this; //Serial for(uint n = 0x134; n <= 0x159; n++) bus.io[n] = this; //Serial
for(uint n = 0x200; n <= 0x209; n++) bus.mmio[n] = this; //System for(uint n = 0x200; n <= 0x209; n++) bus.io[n] = this; //System
for(uint n = 0x300; n <= 0x301; n++) bus.mmio[n] = this; //System for(uint n = 0x300; n <= 0x301; n++) bus.io[n] = this; //System
//0x080-0x083 mirrored via gba/memory/memory.cpp //System //0x080-0x083 mirrored via gba/memory/memory.cpp //System
} }

View File

@ -1,4 +1,4 @@
struct CPU : Processor::ARM, Thread, MMIO { struct CPU : Processor::ARM, Thread, IO {
using ARM::read; using ARM::read;
using ARM::write; using ARM::write;
@ -34,37 +34,37 @@ struct CPU : Processor::ARM, Thread, MMIO {
auto step(uint clocks) -> void override; auto step(uint clocks) -> void override;
auto sync_step(uint clocks) -> void; auto syncStep(uint clocks) -> void;
auto keypad_run() -> void; auto keypadRun() -> void;
auto power() -> void; auto power() -> void;
//bus.cpp //bus.cpp
auto busIdle() -> void override; auto _idle() -> void override;
auto busRead(uint mode, uint32 addr) -> uint32 override; auto _read(uint mode, uint32 addr) -> uint32 override;
auto busWrite(uint mode, uint32 addr, uint32 word) -> void override; auto _write(uint mode, uint32 addr, uint32 word) -> void override;
auto busWait(uint mode, uint32 addr) -> uint; auto wait(uint mode, uint32 addr) -> uint;
//mmio.cpp //io.cpp
auto read(uint32 addr) -> uint8; auto readIO(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void; auto writeIO(uint32 addr, uint8 byte) -> void;
auto iwram_read(uint mode, uint32 addr) -> uint32; auto readIWRAM(uint mode, uint32 addr) -> uint32;
auto iwram_write(uint mode, uint32 addr, uint32 word) -> void; auto writeIWRAM(uint mode, uint32 addr, uint32 word) -> void;
auto ewram_read(uint mode, uint32 addr) -> uint32; auto readEWRAM(uint mode, uint32 addr) -> uint32;
auto ewram_write(uint mode, uint32 addr, uint32 word) -> void; auto writeEWRAM(uint mode, uint32 addr, uint32 word) -> void;
//dma.cpp //dma.cpp
auto dma_run() -> void; auto dmaRun() -> void;
auto dma_exec(Registers::DMA& dma) -> void; auto dmaExecute(Registers::DMA& dma) -> void;
auto dma_vblank() -> void; auto dmaVblank() -> void;
auto dma_hblank() -> void; auto dmaHblank() -> void;
auto dma_hdma() -> void; auto dmaHDMA() -> void;
//timer.cpp //timer.cpp
auto timer_step(uint clocks) -> void; auto timerStep(uint clocks) -> void;
auto timer_increment(uint n) -> void; auto timerIncrement(uint n) -> void;
auto timer_fifo_run(uint n) -> void; auto timerRunFIFO(uint n) -> void;
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -1,4 +1,4 @@
auto CPU::dma_run() -> void { auto CPU::dmaRun() -> void {
active.dma = true; active.dma = true;
while(true) { while(true) {
@ -6,7 +6,7 @@ auto CPU::dma_run() -> void {
for(auto n : range(4)) { for(auto n : range(4)) {
auto& dma = regs.dma[n]; auto& dma = regs.dma[n];
if(dma.pending) { if(dma.pending) {
dma_exec(dma); dmaExecute(dma);
if(dma.control.irq) regs.irq.flag |= Interrupt::DMA0 << n; if(dma.control.irq) regs.irq.flag |= Interrupt::DMA0 << n;
if(dma.control.drq && n == 3) regs.irq.flag |= Interrupt::Cartridge; if(dma.control.drq && n == 3) regs.irq.flag |= Interrupt::Cartridge;
transferred = true; transferred = true;
@ -19,7 +19,7 @@ auto CPU::dma_run() -> void {
active.dma = false; active.dma = false;
} }
auto CPU::dma_exec(Registers::DMA& dma) -> void { auto CPU::dmaExecute(Registers::DMA& dma) -> void {
uint seek = dma.control.size ? 4 : 2; uint seek = dma.control.size ? 4 : 2;
uint mode = dma.control.size ? Word : Half; uint mode = dma.control.size ? Word : Half;
mode |= dma.run.length == dma.length ? Nonsequential : Sequential; mode |= dma.run.length == dma.length ? Nonsequential : Sequential;
@ -39,7 +39,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
uint32 addr = dma.run.source; uint32 addr = dma.run.source;
if(mode & Word) addr &= ~3; if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1; if(mode & Half) addr &= ~1;
dma.data = busRead(mode, addr); dma.data = _read(mode, addr);
} }
if(dma.run.target < 0x0200'0000) { if(dma.run.target < 0x0200'0000) {
@ -48,7 +48,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
uint32 addr = dma.run.target; uint32 addr = dma.run.target;
if(mode & Word) addr &= ~3; if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1; if(mode & Half) addr &= ~1;
busWrite(mode, addr, dma.data); _write(mode, addr, dma.data);
} }
switch(dma.control.sourcemode) { switch(dma.control.sourcemode) {
@ -70,19 +70,19 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
} }
} }
auto CPU::dma_vblank() -> void { auto CPU::dmaVblank() -> void {
for(auto& dma : regs.dma) { for(auto& dma : regs.dma) {
if(dma.control.enable && dma.control.timingmode == 1) dma.pending = true; if(dma.control.enable && dma.control.timingmode == 1) dma.pending = true;
} }
} }
auto CPU::dma_hblank() -> void { auto CPU::dmaHblank() -> void {
for(auto& dma : regs.dma) { for(auto& dma : regs.dma) {
if(dma.control.enable && dma.control.timingmode == 2) dma.pending = true; if(dma.control.enable && dma.control.timingmode == 2) dma.pending = true;
} }
} }
auto CPU::dma_hdma() -> void { auto CPU::dmaHDMA() -> void {
auto& dma = regs.dma[3]; auto& dma = regs.dma[3];
if(dma.control.enable && dma.control.timingmode == 3) dma.pending = true; if(dma.control.enable && dma.control.timingmode == 3) dma.pending = true;
} }

View File

@ -1,4 +1,4 @@
auto CPU::read(uint32 addr) -> uint8 { auto CPU::readIO(uint32 addr) -> uint8 {
auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; }; auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; };
auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; }; auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; };
@ -196,7 +196,7 @@ auto CPU::read(uint32 addr) -> uint8 {
return 0; return 0;
} }
auto CPU::write(uint32 addr, uint8 data) -> void { auto CPU::writeIO(uint32 addr, uint8 data) -> void {
auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; }; auto dma = [&]() -> Registers::DMA& { return regs.dma[addr / 12 & 3]; };
auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; }; auto timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; };

View File

@ -1,53 +1,53 @@
auto CPU::iwram_read(uint mode, uint32 addr) -> uint32 { auto CPU::readIWRAM(uint mode, uint32 addr) -> uint32 {
if(regs.memory.control.disable) return cpu.pipeline.fetch.instruction; if(regs.memory.control.disable) return cpu.pipeline.fetch.instruction;
if(mode & Word) return iwram_read(Half, addr &~ 2) << 0 | iwram_read(Half, addr | 2) << 16; if(mode & Word) return readIWRAM(Half, addr &~ 2) << 0 | readIWRAM(Half, addr | 2) << 16;
if(mode & Half) return iwram_read(Byte, addr &~ 1) << 0 | iwram_read(Byte, addr | 1) << 8; if(mode & Half) return readIWRAM(Byte, addr &~ 1) << 0 | readIWRAM(Byte, addr | 1) << 8;
return iwram[addr & 0x7fff]; return iwram[addr & 0x7fff];
} }
auto CPU::iwram_write(uint mode, uint32 addr, uint32 word) -> void { auto CPU::writeIWRAM(uint mode, uint32 addr, uint32 word) -> void {
if(regs.memory.control.disable) return; if(regs.memory.control.disable) return;
if(mode & Word) { if(mode & Word) {
iwram_write(Half, addr &~2, word >> 0); writeIWRAM(Half, addr &~2, word >> 0);
iwram_write(Half, addr | 2, word >> 16); writeIWRAM(Half, addr | 2, word >> 16);
return; return;
} }
if(mode & Half) { if(mode & Half) {
iwram_write(Byte, addr &~1, word >> 0); writeIWRAM(Byte, addr &~1, word >> 0);
iwram_write(Byte, addr | 1, word >> 8); writeIWRAM(Byte, addr | 1, word >> 8);
return; return;
} }
iwram[addr & 0x7fff] = word; iwram[addr & 0x7fff] = word;
} }
auto CPU::ewram_read(uint mode, uint32 addr) -> uint32 { auto CPU::readEWRAM(uint mode, uint32 addr) -> uint32 {
if(regs.memory.control.disable) return cpu.pipeline.fetch.instruction; if(regs.memory.control.disable) return cpu.pipeline.fetch.instruction;
if(!regs.memory.control.ewram) return iwram_read(mode, addr); if(!regs.memory.control.ewram) return readIWRAM(mode, addr);
if(mode & Word) return ewram_read(Half, addr &~ 2) << 0 | ewram_read(Half, addr | 2) << 16; if(mode & Word) return readEWRAM(Half, addr &~ 2) << 0 | readEWRAM(Half, addr | 2) << 16;
if(mode & Half) return ewram_read(Byte, addr &~ 1) << 0 | ewram_read(Byte, addr | 1) << 8; if(mode & Half) return readEWRAM(Byte, addr &~ 1) << 0 | readEWRAM(Byte, addr | 1) << 8;
return ewram[addr & 0x3ffff]; return ewram[addr & 0x3ffff];
} }
auto CPU::ewram_write(uint mode, uint32 addr, uint32 word) -> void { auto CPU::writeEWRAM(uint mode, uint32 addr, uint32 word) -> void {
if(regs.memory.control.disable) return; if(regs.memory.control.disable) return;
if(!regs.memory.control.ewram) return iwram_write(mode, addr, word); if(!regs.memory.control.ewram) return writeIWRAM(mode, addr, word);
if(mode & Word) { if(mode & Word) {
ewram_write(Half, addr &~2, word >> 0); writeEWRAM(Half, addr &~2, word >> 0);
ewram_write(Half, addr | 2, word >> 16); writeEWRAM(Half, addr | 2, word >> 16);
return; return;
} }
if(mode & Half) { if(mode & Half) {
ewram_write(Byte, addr &~1, word >> 0); writeEWRAM(Byte, addr &~1, word >> 0);
ewram_write(Byte, addr | 1, word >> 8); writeEWRAM(Byte, addr | 1, word >> 8);
return; return;
} }

View File

@ -1,12 +1,12 @@
auto CPU::prefetch_sync(uint32 addr) -> void { auto CPU::prefetchSync(uint32 addr) -> void {
if(addr == prefetch.addr) return; if(addr == prefetch.addr) return;
prefetch.addr = addr; prefetch.addr = addr;
prefetch.load = addr; prefetch.load = addr;
prefetch.wait = busWait(Half | Nonsequential, prefetch.load); prefetch.wait = wait(Half | Nonsequential, prefetch.load);
} }
auto CPU::prefetch_step(uint clocks) -> void { auto CPU::prefetchStep(uint clocks) -> void {
step(clocks); step(clocks);
if(!regs.wait.control.prefetch || active.dma) return; if(!regs.wait.control.prefetch || active.dma) return;
@ -14,22 +14,22 @@ auto CPU::prefetch_step(uint clocks) -> void {
if(--prefetch.wait) continue; if(--prefetch.wait) continue;
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load); prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
prefetch.load += 2; prefetch.load += 2;
prefetch.wait = busWait(Half | Sequential, prefetch.load); prefetch.wait = wait(Half | Sequential, prefetch.load);
} }
} }
auto CPU::prefetch_wait() -> void { auto CPU::prefetchWait() -> void {
if(!regs.wait.control.prefetch || active.dma || prefetch.full()) return; if(!regs.wait.control.prefetch || active.dma || prefetch.full()) return;
prefetch_step(prefetch.wait); prefetchStep(prefetch.wait);
prefetch.wait = busWait(Half | Nonsequential, prefetch.load); prefetch.wait = wait(Half | Nonsequential, prefetch.load);
} }
auto CPU::prefetch_read() -> uint16 { auto CPU::prefetchRead() -> uint16 {
if(prefetch.empty()) prefetch_step(prefetch.wait); if(prefetch.empty()) prefetchStep(prefetch.wait);
else prefetch_step(1); else prefetchStep(1);
if(prefetch.full()) prefetch.wait = busWait(Half | Sequential, prefetch.load); if(prefetch.full()) prefetch.wait = wait(Half | Sequential, prefetch.load);
uint16 half = prefetch.slot[prefetch.addr >> 1 & 7]; uint16 half = prefetch.slot[prefetch.addr >> 1 & 7];
prefetch.addr += 2; prefetch.addr += 2;

View File

@ -8,7 +8,7 @@ struct {
auto full() const { return load - addr == 16; } auto full() const { return load - addr == 16; }
} prefetch; } prefetch;
auto prefetch_sync(uint32 addr) -> void; auto prefetchSync(uint32 addr) -> void;
auto prefetch_step(uint clocks) -> void; auto prefetchStep(uint clocks) -> void;
auto prefetch_wait() -> void; auto prefetchWait() -> void;
auto prefetch_read() -> uint16; auto prefetchRead() -> uint16;

View File

@ -1,4 +1,4 @@
auto CPU::timer_step(uint clocks) -> void { auto CPU::timerStep(uint clocks) -> void {
for(auto c : range(clocks)) { for(auto c : range(clocks)) {
for(auto n : range(4)) { for(auto n : range(4)) {
auto& timer = regs.timer[n]; auto& timer = regs.timer[n];
@ -11,11 +11,11 @@ auto CPU::timer_step(uint clocks) -> void {
continue; continue;
} }
if(timer.control.enable == false || timer.control.cascade == true) continue; if(!timer.control.enable || timer.control.cascade) continue;
static uint mask[] = {0, 63, 255, 1023}; static uint mask[] = {0, 63, 255, 1023};
if((regs.clock & mask[timer.control.frequency]) == 0) { if((regs.clock & mask[timer.control.frequency]) == 0) {
timer_increment(n); timerIncrement(n);
} }
} }
@ -23,23 +23,23 @@ auto CPU::timer_step(uint clocks) -> void {
} }
} }
auto CPU::timer_increment(uint n) -> void { auto CPU::timerIncrement(uint n) -> void {
auto& timer = regs.timer[n]; auto& timer = regs.timer[n];
if(++timer.period == 0) { if(++timer.period == 0) {
timer.period = timer.reload; timer.period = timer.reload;
if(timer.control.irq) regs.irq.flag |= Interrupt::Timer0 << n; if(timer.control.irq) regs.irq.flag |= Interrupt::Timer0 << n;
if(apu.fifo[0].timer == n) timer_fifo_run(0); if(apu.fifo[0].timer == n) timerRunFIFO(0);
if(apu.fifo[1].timer == n) timer_fifo_run(1); if(apu.fifo[1].timer == n) timerRunFIFO(1);
if(n < 3 && regs.timer[n + 1].control.enable && regs.timer[n + 1].control.cascade) { if(n < 3 && regs.timer[n + 1].control.enable && regs.timer[n + 1].control.cascade) {
timer_increment(n + 1); timerIncrement(n + 1);
} }
} }
} }
auto CPU::timer_fifo_run(uint n) -> void { auto CPU::timerRunFIFO(uint n) -> void {
apu.fifo[n].read(); apu.fifo[n].read();
if(apu.fifo[n].size > 16) return; if(apu.fifo[n].size > 16) return;

View File

@ -2,15 +2,50 @@
namespace GameBoyAdvance { namespace GameBoyAdvance {
#include "mmio.cpp"
Bus bus; Bus bus;
struct UnmappedMemory : Memory { auto IO::readIO(uint mode, uint32 addr) -> uint32 {
auto read(uint mode, uint32 addr) -> uint32 override { return 0; } uint32 word = 0;
auto write(uint mode, uint32 addr, uint32 word) -> void override {}
if(mode & Word) {
addr &= ~3;
word |= readIO(addr + 0) << 0;
word |= readIO(addr + 1) << 8;
word |= readIO(addr + 2) << 16;
word |= readIO(addr + 3) << 24;
} else if(mode & Half) {
addr &= ~1;
word |= readIO(addr + 0) << 0;
word |= readIO(addr + 1) << 8;
} else if(mode & Byte) {
word |= readIO(addr + 0) << 0;
}
return word;
}
auto IO::writeIO(uint mode, uint32 addr, uint32 word) -> void {
if(mode & Word) {
addr &= ~3;
writeIO(addr + 0, word >> 0);
writeIO(addr + 1, word >> 8);
writeIO(addr + 2, word >> 16);
writeIO(addr + 3, word >> 24);
} else if(mode & Half) {
addr &= ~1;
writeIO(addr + 0, word >> 0);
writeIO(addr + 1, word >> 8);
} else if(mode & Byte) {
writeIO(addr + 0, word >> 0);
}
}
struct UnmappedIO : IO {
auto readIO(uint32 addr) -> uint8 override { return 0; }
auto writeIO(uint32 addr, uint8 byte) -> void override {}
}; };
static UnmappedMemory unmappedMemory; static UnmappedIO unmappedIO;
auto Bus::mirror(uint32 addr, uint32 size) -> uint32 { auto Bus::mirror(uint32 addr, uint32 size) -> uint32 {
uint32 base = 0; uint32 base = 0;
@ -31,7 +66,7 @@ auto Bus::mirror(uint32 addr, uint32 size) -> uint32 {
} }
auto Bus::power() -> void { auto Bus::power() -> void {
for(auto n : range(0x400)) mmio[n] = &unmappedMemory; for(auto n : range(0x400)) io[n] = &unmappedIO;
} }
} }

View File

@ -1,13 +1,8 @@
struct Memory { struct IO {
virtual auto read(uint mode, uint32 addr) -> uint32 = 0; virtual auto readIO(uint32 addr) -> uint8 = 0;
virtual auto write(uint mode, uint32 addr, uint32 word) -> void = 0; virtual auto writeIO(uint32 addr, uint8 data) -> void = 0;
}; auto readIO(uint mode, uint32 addr) -> uint32;
auto writeIO(uint mode, uint32 addr, uint32 word) -> void;
struct MMIO : Memory {
virtual auto read(uint32 addr) -> uint8 = 0;
virtual auto write(uint32 addr, uint8 data) -> void = 0;
auto read(uint mode, uint32 addr) -> uint32 final;
auto write(uint mode, uint32 addr, uint32 word) -> void final;
}; };
struct Bus { struct Bus {
@ -15,7 +10,7 @@ struct Bus {
auto power() -> void; auto power() -> void;
Memory* mmio[0x400] = {nullptr}; IO* io[0x400] = {nullptr};
}; };
extern Bus bus; extern Bus bus;

View File

@ -1,35 +0,0 @@
auto MMIO::read(uint mode, uint32 addr) -> uint32 {
uint32 word = 0;
if(mode & Word) {
addr &= ~3;
word |= read(addr + 0) << 0;
word |= read(addr + 1) << 8;
word |= read(addr + 2) << 16;
word |= read(addr + 3) << 24;
} else if(mode & Half) {
addr &= ~1;
word |= read(addr + 0) << 0;
word |= read(addr + 1) << 8;
} else if(mode & Byte) {
word |= read(addr + 0) << 0;
}
return word;
}
auto MMIO::write(uint mode, uint32 addr, uint32 word) -> void {
if(mode & Word) {
addr &= ~3;
write(addr + 0, word >> 0);
write(addr + 1, word >> 8);
write(addr + 2, word >> 16);
write(addr + 3, word >> 24);
} else if(mode & Half) {
addr &= ~1;
write(addr + 0, word >> 0);
write(addr + 1, word >> 8);
} else if(mode & Byte) {
write(addr + 0, word >> 0);
}
}

View File

@ -1,27 +1,27 @@
auto PPU::render_backgrounds() -> void { auto PPU::renderBackgrounds() -> void {
switch(regs.control.bgmode) { switch(regs.control.bgmode) {
case 0: case 0:
render_background_linear(regs.bg[3]); renderBackgroundLinear(regs.bg[3]);
render_background_linear(regs.bg[2]); renderBackgroundLinear(regs.bg[2]);
render_background_linear(regs.bg[1]); renderBackgroundLinear(regs.bg[1]);
render_background_linear(regs.bg[0]); renderBackgroundLinear(regs.bg[0]);
break; break;
case 1: case 1:
render_background_affine(regs.bg[2]); renderBackgroundAffine(regs.bg[2]);
render_background_linear(regs.bg[1]); renderBackgroundLinear(regs.bg[1]);
render_background_linear(regs.bg[0]); renderBackgroundLinear(regs.bg[0]);
break; break;
case 2: case 2:
render_background_affine(regs.bg[3]); renderBackgroundAffine(regs.bg[3]);
render_background_affine(regs.bg[2]); renderBackgroundAffine(regs.bg[2]);
break; break;
case 3: case 4: case 5: case 3: case 4: case 5:
render_background_bitmap(regs.bg[2]); renderBackgroundBitmap(regs.bg[2]);
break; break;
} }
} }
auto PPU::render_background_linear(Registers::Background& bg) -> void { auto PPU::renderBackgroundLinear(Registers::Background& bg) -> void {
if(regs.control.enable[bg.id] == false) return; if(regs.control.enable[bg.id] == false) return;
auto& output = layer[bg.id]; auto& output = layer[bg.id];
@ -48,7 +48,7 @@ auto PPU::render_background_linear(Registers::Background& bg) -> void {
if(bg.control.screensize & 1) if(tx & 32) offset += 32 * 32; if(bg.control.screensize & 1) if(tx & 32) offset += 32 * 32;
if(bg.control.screensize & 2) if(ty & 32) offset += 32 * 32 * (1 + (bg.control.screensize & 1)); if(bg.control.screensize & 2) if(ty & 32) offset += 32 * 32 * (1 + (bg.control.screensize & 1));
offset = basemap + offset * 2; offset = basemap + offset * 2;
uint16 mapdata = vram_read(Half, offset); uint16 mapdata = readVRAM(Half, offset);
tile.character = mapdata >> 0; tile.character = mapdata >> 0;
tile.hflip = mapdata >> 10; tile.hflip = mapdata >> 10;
@ -57,12 +57,12 @@ auto PPU::render_background_linear(Registers::Background& bg) -> void {
if(bg.control.colormode == 0) { if(bg.control.colormode == 0) {
offset = basechr + tile.character * 32 + (py ^ (tile.vflip ? 7 : 0)) * 4; offset = basechr + tile.character * 32 + (py ^ (tile.vflip ? 7 : 0)) * 4;
uint32 word = vram_read(Word, offset); uint32 word = readVRAM(Word, offset);
for(auto n : range(8)) data[n] = (word >> (n * 4)) & 15; for(auto n : range(8)) data[n] = (word >> (n * 4)) & 15;
} else { } else {
offset = basechr + tile.character * 64 + (py ^ (tile.vflip ? 7 : 0)) * 8; offset = basechr + tile.character * 64 + (py ^ (tile.vflip ? 7 : 0)) * 8;
uint32 wordlo = vram_read(Word, offset + 0); uint32 wordlo = readVRAM(Word, offset + 0);
uint32 wordhi = vram_read(Word, offset + 4); uint32 wordhi = readVRAM(Word, offset + 4);
for(auto n : range(4)) data[0 + n] = (wordlo >> (n * 8)) & 255; for(auto n : range(4)) data[0 + n] = (wordlo >> (n * 8)) & 255;
for(auto n : range(4)) data[4 + n] = (wordhi >> (n * 8)) & 255; for(auto n : range(4)) data[4 + n] = (wordhi >> (n * 8)) & 255;
} }
@ -78,7 +78,7 @@ auto PPU::render_background_linear(Registers::Background& bg) -> void {
} }
} }
auto PPU::render_background_affine(Registers::Background& bg) -> void { auto PPU::renderBackgroundAffine(Registers::Background& bg) -> void {
if(regs.control.enable[bg.id] == false) return; if(regs.control.enable[bg.id] == false) return;
auto& output = layer[bg.id]; auto& output = layer[bg.id];
@ -113,7 +113,7 @@ auto PPU::render_background_affine(Registers::Background& bg) -> void {
bg.ly += bg.pd; bg.ly += bg.pd;
} }
auto PPU::render_background_bitmap(Registers::Background& bg) -> void { auto PPU::renderBackgroundBitmap(Registers::Background& bg) -> void {
if(regs.control.enable[bg.id] == false) return; if(regs.control.enable[bg.id] == false) return;
auto& output = layer[bg.id]; auto& output = layer[bg.id];
@ -138,7 +138,7 @@ auto PPU::render_background_bitmap(Registers::Background& bg) -> void {
if(px < width && py < height) { if(px < width && py < height) {
uint offset = py * width + px; uint offset = py * width + px;
uint color = vram_read(mode, basemap + (offset << depth)); uint color = readVRAM(mode, basemap + (offset << depth));
if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
if(depth == 0) color = pram[color]; if(depth == 0) color = pram[color];

View File

@ -1,4 +1,4 @@
auto PPU::read(uint32 addr) -> uint8 { auto PPU::readIO(uint32 addr) -> uint8 {
auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; }; auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; };
auto wf = [&]() -> Registers::WindowFlags& { auto wf = [&]() -> Registers::WindowFlags& {
static uint id[] = {In0, In1, Out, Obj}; static uint id[] = {In0, In1, Out, Obj};
@ -102,7 +102,7 @@ auto PPU::read(uint32 addr) -> uint8 {
return 0; return 0;
} }
auto PPU::write(uint32 addr, uint8 data) -> void { auto PPU::writeIO(uint32 addr, uint8 data) -> void {
auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; }; auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; };
auto bgofs = [&]() -> Registers::Background& { return regs.bg[addr.bits(2,3)]; }; auto bgofs = [&]() -> Registers::Background& { return regs.bg[addr.bits(2,3)]; };
auto bg = [&]() -> Registers::Background& { return regs.bg[addr.bits(4,5)]; }; auto bg = [&]() -> Registers::Background& { return regs.bg[addr.bits(4,5)]; };

View File

@ -1,4 +1,4 @@
auto PPU::vram_read(uint mode, uint32 addr) -> uint32 { auto PPU::readVRAM(uint mode, uint32 addr) -> uint32 {
addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff;
if(mode & Word) { if(mode & Word) {
@ -14,7 +14,7 @@ auto PPU::vram_read(uint mode, uint32 addr) -> uint32 {
return 0; //should never occur return 0; //should never occur
} }
auto PPU::vram_write(uint mode, uint32 addr, uint32 word) -> void { auto PPU::writeVRAM(uint mode, uint32 addr, uint32 word) -> void {
addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff; addr &= (addr & 0x10000) ? 0x17fff : 0x0ffff;
if(mode & Word) { if(mode & Word) {
@ -38,30 +38,30 @@ auto PPU::vram_write(uint mode, uint32 addr, uint32 word) -> void {
} }
} }
auto PPU::pram_read(uint mode, uint32 addr) -> uint32 { auto PPU::readPRAM(uint mode, uint32 addr) -> uint32 {
if(mode & Word) return pram_read(Half, addr & ~2) << 0 | pram_read(Half, addr | 2) << 16; if(mode & Word) return readPRAM(Half, addr & ~2) << 0 | readPRAM(Half, addr | 2) << 16;
if(mode & Byte) return pram_read(Half, addr) >> ((addr & 1) * 8); if(mode & Byte) return readPRAM(Half, addr) >> ((addr & 1) * 8);
return pram[addr >> 1 & 511]; return pram[addr >> 1 & 511];
} }
auto PPU::pram_write(uint mode, uint32 addr, uint32 word) -> void { auto PPU::writePRAM(uint mode, uint32 addr, uint32 word) -> void {
if(mode & Word) { if(mode & Word) {
pram_write(Half, addr & ~2, word >> 0); writePRAM(Half, addr & ~2, word >> 0);
pram_write(Half, addr | 2, word >> 16); writePRAM(Half, addr | 2, word >> 16);
return; return;
} }
if(mode & Byte) { if(mode & Byte) {
word = (uint8)word; word = (uint8)word;
return pram_write(Half, addr, word << 8 | word << 0); return writePRAM(Half, addr, word << 8 | word << 0);
} }
pram[addr >> 1 & 511] = (uint16)word; pram[addr >> 1 & 511] = (uint16)word;
} }
auto PPU::oam_read(uint mode, uint32 addr) -> uint32 { auto PPU::readOAM(uint mode, uint32 addr) -> uint32 {
if(mode & Word) return oam_read(Half, addr & ~2) << 0 | oam_read(Half, addr | 2) << 16; if(mode & Word) return readOAM(Half, addr & ~2) << 0 | readOAM(Half, addr | 2) << 16;
if(mode & Byte) return oam_read(Half, addr) >> ((addr & 1) * 8); if(mode & Byte) return readOAM(Half, addr) >> ((addr & 1) * 8);
auto& obj = object[addr >> 3 & 127]; auto& obj = object[addr >> 3 & 127];
auto& par = objectparam[addr >> 5 & 31]; auto& par = objectparam[addr >> 5 & 31];
@ -103,10 +103,10 @@ auto PPU::oam_read(uint mode, uint32 addr) -> uint32 {
} }
} }
auto PPU::oam_write(uint mode, uint32 addr, uint32 word) -> void { auto PPU::writeOAM(uint mode, uint32 addr, uint32 word) -> void {
if(mode & Word) { if(mode & Word) {
oam_write(Half, addr & ~2, word >> 0); writeOAM(Half, addr & ~2, word >> 0);
oam_write(Half, addr | 2, word >> 16); writeOAM(Half, addr | 2, word >> 16);
return; return;
} }

View File

@ -1,4 +1,4 @@
auto PPU::render_mosaic_background(uint id) -> void { auto PPU::renderMosaicBackground(uint id) -> void {
if(regs.mosaic.bghsize == 0) return; if(regs.mosaic.bghsize == 0) return;
uint width = 1 + regs.mosaic.bghsize; uint width = 1 + regs.mosaic.bghsize;
auto& buffer = layer[id]; auto& buffer = layer[id];
@ -12,7 +12,7 @@ auto PPU::render_mosaic_background(uint id) -> void {
} }
} }
auto PPU::render_mosaic_object() -> void { auto PPU::renderMosaicObject() -> void {
if(regs.mosaic.objhsize == 0) return; if(regs.mosaic.objhsize == 0) return;
uint width = 1 + regs.mosaic.objhsize; uint width = 1 + regs.mosaic.objhsize;
auto& buffer = layer[OBJ]; auto& buffer = layer[OBJ];

View File

@ -1,13 +1,13 @@
auto PPU::render_objects() -> void { auto PPU::renderObjects() -> void {
if(regs.control.enable[OBJ] == false) return; if(regs.control.enable[OBJ] == false) return;
for(auto n : range(128)) render_object(object[n]); for(auto n : range(128)) renderObject(object[n]);
} }
//px,py = pixel coordinates within sprite [0,0 - width,height) //px,py = pixel coordinates within sprite [0,0 - width,height)
//fx,fy = affine pixel coordinates //fx,fy = affine pixel coordinates
//pa,pb,pc,pd = affine pixel adjustments //pa,pb,pc,pd = affine pixel adjustments
//x,y = adjusted coordinates within sprite (linear = vflip/hflip, affine = rotation/zoom) //x,y = adjusted coordinates within sprite (linear = vflip/hflip, affine = rotation/zoom)
auto PPU::render_object(Object& obj) -> void { auto PPU::renderObject(Object& obj) -> void {
uint8 py = regs.vcounter - obj.y; uint8 py = regs.vcounter - obj.y;
if(obj.affine == 0 && obj.affinesize == 1) return; //hidden if(obj.affine == 0 && obj.affinesize == 1) return; //hidden
if(py >= obj.height << obj.affinesize) return; //offscreen if(py >= obj.height << obj.affinesize) return; //offscreen
@ -55,7 +55,7 @@ auto PPU::render_object(Object& obj) -> void {
uint offset = (y / 8) * rowsize + (x / 8); uint offset = (y / 8) * rowsize + (x / 8);
offset = offset * 64 + (y & 7) * 8 + (x & 7); offset = offset * 64 + (y & 7) * 8 + (x & 7);
uint8 color = object_vram_read(baseaddr + (offset >> !obj.colors)); uint8 color = readObjectVRAM(baseaddr + (offset >> !obj.colors));
if(obj.colors == 0) color = (x & 1) ? color >> 4 : color & 15; if(obj.colors == 0) color = (x & 1) ? color >> 4 : color & 15;
if(color) { if(color) {
if(obj.mode & 2) { if(obj.mode & 2) {
@ -72,7 +72,7 @@ auto PPU::render_object(Object& obj) -> void {
} }
} }
auto PPU::object_vram_read(uint addr) const -> uint8 { auto PPU::readObjectVRAM(uint addr) const -> uint8 {
if(regs.control.bgmode == 3 || regs.control.bgmode == 4 || regs.control.bgmode == 5) { if(regs.control.bgmode == 3 || regs.control.bgmode == 4 || regs.control.bgmode == 5) {
if(addr <= 0x3fff) return 0u; if(addr <= 0x3fff) return 0u;
} }

View File

@ -17,7 +17,7 @@ PPU ppu;
#include "object.cpp" #include "object.cpp"
#include "mosaic.cpp" #include "mosaic.cpp"
#include "screen.cpp" #include "screen.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "serialization.cpp" #include "serialization.cpp"
@ -52,8 +52,8 @@ auto PPU::power() -> void {
for(uint n = 0; n < 240 * 160; n++) output[n] = 0; for(uint n = 0; n < 240 * 160; n++) output[n] = 0;
for(uint n = 0; n < 1024; n += 2) pram_write(n, Half, 0x0000); for(uint n = 0; n < 1024; n += 2) writePRAM(n, Half, 0x0000);
for(uint n = 0; n < 1024; n += 2) oam_write(n, Half, 0x0000); for(uint n = 0; n < 1024; n += 2) writeOAM(n, Half, 0x0000);
regs.control.bgmode = 0; regs.control.bgmode = 0;
regs.control.cgbmode = 0; regs.control.cgbmode = 0;
@ -112,11 +112,11 @@ auto PPU::power() -> void {
regs.blend.evb = 0; regs.blend.evb = 0;
regs.blend.evy = 0; regs.blend.evy = 0;
for(uint n = 0x000; n <= 0x055; n++) bus.mmio[n] = this; for(uint n = 0x000; n <= 0x055; n++) bus.io[n] = this;
} }
auto PPU::scanline() -> void { auto PPU::scanline() -> void {
cpu.keypad_run(); cpu.keypadRun();
regs.status.vblank = regs.vcounter >= 160 && regs.vcounter <= 226; regs.status.vblank = regs.vcounter >= 160 && regs.vcounter <= 226;
regs.status.vcoincidence = regs.vcounter == regs.status.vcompare; regs.status.vcoincidence = regs.vcounter == regs.status.vcompare;
@ -133,7 +133,7 @@ auto PPU::scanline() -> void {
if(regs.vcounter == 160) { if(regs.vcounter == 160) {
if(regs.status.irqvblank) cpu.regs.irq.flag |= CPU::Interrupt::VBlank; if(regs.status.irqvblank) cpu.regs.irq.flag |= CPU::Interrupt::VBlank;
cpu.dma_vblank(); cpu.dmaVblank();
} }
if(regs.status.irqvcoincidence) { if(regs.status.irqvcoincidence) {
@ -142,7 +142,7 @@ auto PPU::scanline() -> void {
if(regs.vcounter < 160) { if(regs.vcounter < 160) {
if(regs.control.forceblank || cpu.regs.mode == CPU::Registers::Mode::Stop) { if(regs.control.forceblank || cpu.regs.mode == CPU::Registers::Mode::Stop) {
render_forceblank(); renderForceBlank();
} else { } else {
for(auto x : range(240)) { for(auto x : range(240)) {
windowmask[0][x] = false; windowmask[0][x] = false;
@ -155,22 +155,22 @@ auto PPU::scanline() -> void {
layer[BG3][x].write(false); layer[BG3][x].write(false);
layer[SFX][x].write(true, 3, pram[0]); layer[SFX][x].write(true, 3, pram[0]);
} }
render_window(0); renderWindow(0);
render_window(1); renderWindow(1);
render_objects(); renderObjects();
render_backgrounds(); renderBackgrounds();
render_screen(); renderScreen();
} }
} }
step(960); step(960);
regs.status.hblank = 1; regs.status.hblank = 1;
if(regs.status.irqhblank) cpu.regs.irq.flag |= CPU::Interrupt::HBlank; if(regs.status.irqhblank) cpu.regs.irq.flag |= CPU::Interrupt::HBlank;
if(regs.vcounter < 160) cpu.dma_hblank(); if(regs.vcounter < 160) cpu.dmaHblank();
step(240); step(240);
regs.status.hblank = 0; regs.status.hblank = 0;
if(regs.vcounter < 160) cpu.dma_hdma(); if(regs.vcounter < 160) cpu.dmaHDMA();
step(32); step(32);
if(++regs.vcounter == 228) regs.vcounter = 0; if(++regs.vcounter == 228) regs.vcounter = 0;

View File

@ -1,4 +1,4 @@
struct PPU : Thread, MMIO { struct PPU : Thread, IO {
#include "registers.hpp" #include "registers.hpp"
#include "state.hpp" #include "state.hpp"
@ -14,33 +14,33 @@ struct PPU : Thread, MMIO {
auto frame() -> void; auto frame() -> void;
auto refresh() -> void; auto refresh() -> void;
auto read(uint32 addr) -> uint8; auto readIO(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void; auto writeIO(uint32 addr, uint8 byte) -> void;
auto vram_read(uint mode, uint32 addr) -> uint32; auto readVRAM(uint mode, uint32 addr) -> uint32;
auto vram_write(uint mode, uint32 addr, uint32 word) -> void; auto writeVRAM(uint mode, uint32 addr, uint32 word) -> void;
auto pram_read(uint mode, uint32 addr) -> uint32; auto readPRAM(uint mode, uint32 addr) -> uint32;
auto pram_write(uint mode, uint32 addr, uint32 word) -> void; auto writePRAM(uint mode, uint32 addr, uint32 word) -> void;
auto oam_read(uint mode, uint32 addr) -> uint32; auto readOAM(uint mode, uint32 addr) -> uint32;
auto oam_write(uint mode, uint32 addr, uint32 word) -> void; auto writeOAM(uint mode, uint32 addr, uint32 word) -> void;
auto render_backgrounds() -> void; auto renderBackgrounds() -> void;
auto render_background_linear(Registers::Background&) -> void; auto renderBackgroundLinear(Registers::Background&) -> void;
auto render_background_affine(Registers::Background&) -> void; auto renderBackgroundAffine(Registers::Background&) -> void;
auto render_background_bitmap(Registers::Background&) -> void; auto renderBackgroundBitmap(Registers::Background&) -> void;
auto render_objects() -> void; auto renderObjects() -> void;
auto render_object(Object&) -> void; auto renderObject(Object&) -> void;
auto object_vram_read(uint addr) const -> uint8; auto readObjectVRAM(uint addr) const -> uint8;
auto render_mosaic_background(uint id) -> void; auto renderMosaicBackground(uint id) -> void;
auto render_mosaic_object() -> void; auto renderMosaicObject() -> void;
auto render_forceblank() -> void; auto renderForceBlank() -> void;
auto render_screen() -> void; auto renderScreen() -> void;
auto render_window(uint window) -> void; auto renderWindow(uint window) -> void;
auto blend(uint above, uint eva, uint below, uint evb) -> uint; auto blend(uint above, uint eva, uint below, uint evb) -> uint;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -1,16 +1,16 @@
auto PPU::render_forceblank() -> void { auto PPU::renderForceBlank() -> void {
uint32* line = output + regs.vcounter * 240; uint32* line = output + regs.vcounter * 240;
for(auto x : range(240)) line[x] = 0x7fff; for(auto x : range(240)) line[x] = 0x7fff;
} }
auto PPU::render_screen() -> void { auto PPU::renderScreen() -> void {
uint32* line = output + regs.vcounter * 240; uint32* line = output + regs.vcounter * 240;
if(regs.bg[0].control.mosaic) render_mosaic_background(BG0); if(regs.bg[0].control.mosaic) renderMosaicBackground(BG0);
if(regs.bg[1].control.mosaic) render_mosaic_background(BG1); if(regs.bg[1].control.mosaic) renderMosaicBackground(BG1);
if(regs.bg[2].control.mosaic) render_mosaic_background(BG2); if(regs.bg[2].control.mosaic) renderMosaicBackground(BG2);
if(regs.bg[3].control.mosaic) render_mosaic_background(BG3); if(regs.bg[3].control.mosaic) renderMosaicBackground(BG3);
render_mosaic_object(); renderMosaicObject();
for(auto x : range(240)) { for(auto x : range(240)) {
Registers::WindowFlags flags; Registers::WindowFlags flags;
@ -66,7 +66,7 @@ auto PPU::render_screen() -> void {
} }
} }
auto PPU::render_window(uint w) -> void { auto PPU::renderWindow(uint w) -> void {
uint y = regs.vcounter; uint y = regs.vcounter;
uint y1 = regs.window[w].y1, y2 = regs.window[w].y2; uint y1 = regs.window[w].y1, y2 = regs.window[w].y2;

View File

@ -2,12 +2,12 @@ enum class Input : uint {
A, B, Select, Start, Right, Left, Up, Down, R, L, A, B, Select, Start, Right, Left, Up, Down, R, L,
}; };
struct BIOS : Memory { struct BIOS {
BIOS(); BIOS();
~BIOS(); ~BIOS();
auto read(uint mode, uint32 addr) -> uint32 override; auto read(uint mode, uint32 addr) -> uint32;
auto write(uint mode, uint32 addr, uint32 word) -> void override; auto write(uint mode, uint32 addr, uint32 word) -> void;
uint8* data = nullptr; uint8* data = nullptr;
uint size = 0; uint size = 0;

View File

@ -26,21 +26,21 @@ auto ARM::power() -> void {
} }
auto ARM::exec() -> void { auto ARM::exec() -> void {
cpsr().t ? thumb_step() : arm_step(); cpsr().t ? stepTHUMB() : stepARM();
} }
auto ARM::idle() -> void { auto ARM::idle() -> void {
pipeline.nonsequential = true; pipeline.nonsequential = true;
return busIdle(); return _idle();
} }
auto ARM::read(unsigned mode, uint32 addr) -> uint32 { auto ARM::read(uint mode, uint32 addr) -> uint32 {
return busRead(mode, addr); return _read(mode, addr);
} }
auto ARM::load(unsigned mode, uint32 addr) -> uint32 { auto ARM::load(uint mode, uint32 addr) -> uint32 {
pipeline.nonsequential = true; pipeline.nonsequential = true;
uint32 word = busRead(Load | mode, addr); uint32 word = _read(Load | mode, addr);
if(mode & Half) { if(mode & Half) {
addr &= 1; addr &= 1;
@ -62,18 +62,18 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
return word; return word;
} }
auto ARM::write(unsigned mode, uint32 addr, uint32 word) -> void { auto ARM::write(uint mode, uint32 addr, uint32 word) -> void {
pipeline.nonsequential = true; pipeline.nonsequential = true;
return busWrite(mode, addr, word); return _write(mode, addr, word);
} }
auto ARM::store(unsigned mode, uint32 addr, uint32 word) -> void { auto ARM::store(uint mode, uint32 addr, uint32 word) -> void {
pipeline.nonsequential = true; pipeline.nonsequential = true;
if(mode & Half) { word &= 0xffff; word |= word << 16; } if(mode & Half) { word &= 0xffff; word |= word << 16; }
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; } if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
return busWrite(Store | mode, addr, word); return _write(Store | mode, addr, word);
} }
auto ARM::vector(uint32 addr, Processor::Mode mode) -> void { auto ARM::vector(uint32 addr, Processor::Mode mode) -> void {

View File

@ -7,7 +7,7 @@ namespace Processor {
//* ARMv4T (ARM7TDMI) //* ARMv4T (ARM7TDMI)
struct ARM { struct ARM {
enum : unsigned { //mode flags for bus_read, bus_write: enum : uint { //mode flags for bus_read, bus_write:
Nonsequential = 1, //N cycle Nonsequential = 1, //N cycle
Sequential = 2, //S cycle Sequential = 2, //S cycle
Prefetch = 4, //instruction fetch (eligible for prefetch) Prefetch = 4, //instruction fetch (eligible for prefetch)
@ -24,19 +24,19 @@ struct ARM {
#include "instructions-thumb.hpp" #include "instructions-thumb.hpp"
#include "disassembler.hpp" #include "disassembler.hpp"
virtual auto step(unsigned clocks) -> void = 0; virtual auto step(uint clocks) -> void = 0;
virtual auto busIdle() -> void = 0; virtual auto _idle() -> void = 0;
virtual auto busRead(unsigned mode, uint32 addr) -> uint32 = 0; virtual auto _read(uint mode, uint32 addr) -> uint32 = 0;
virtual auto busWrite(unsigned mode, uint32 addr, uint32 word) -> void = 0; virtual auto _write(uint mode, uint32 addr, uint32 word) -> void = 0;
//arm.cpp //arm.cpp
auto power() -> void; auto power() -> void;
auto exec() -> void; auto exec() -> void;
auto idle() -> void; auto idle() -> void;
auto read(unsigned mode, uint32 addr) -> uint32; auto read(uint mode, uint32 addr) -> uint32;
auto load(unsigned mode, uint32 addr) -> uint32; auto load(uint mode, uint32 addr) -> uint32;
auto write(unsigned mode, uint32 addr, uint32 word) -> void; auto write(uint mode, uint32 addr, uint32 word) -> void;
auto store(unsigned mode, uint32 addr, uint32 word) -> void; auto store(uint mode, uint32 addr, uint32 word) -> void;
auto vector(uint32 addr, Processor::Mode mode) -> void; auto vector(uint32 addr, Processor::Mode mode) -> void;
//algorithms.cpp //algorithms.cpp
@ -52,9 +52,9 @@ struct ARM {
auto rrx(uint32 source) -> uint32; auto rrx(uint32 source) -> uint32;
//step.cpp //step.cpp
auto pipeline_step() -> void; auto stepPipeline() -> void;
auto arm_step() -> void; auto stepARM() -> void;
auto thumb_step() -> void; auto stepTHUMB() -> void;
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -1,4 +1,4 @@
auto ARM::disassemble_arm_instruction(uint32 pc) -> string { auto ARM::disassembleInstructionARM(uint32 pc) -> string {
static string conditions[] = { static string conditions[] = {
"eq", "ne", "cs", "cc", "eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc", "mi", "pl", "vs", "vc",
@ -24,9 +24,9 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
"da", "ia", "db", "ib", "da", "ia", "db", "ib",
}; };
static auto is_move = [](uint4 opcode) { return opcode == 13 || opcode == 15; }; static auto isMove = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; }; static auto isComp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; }; static auto isMath = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
string output{hex(pc, 8L), " "}; string output{hex(pc, 8L), " "};
@ -272,13 +272,13 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
uint4 rm = instruction; uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]); output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]); if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(is_comp(opcode)) output.append(" ", registers[rn]); if(isComp(opcode)) output.append(" ", registers[rn]);
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]); if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",", registers[rm]); output.append(",", registers[rm]);
if(op == 0 && shift != 0) output.append(" lsl #", shift); if(op == 0 && shift != 0) output.append(" lsl #", shift);
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift); if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (uint)shift);
if(op == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift); if(op == 2) output.append(" asr #", shift == 0 ? 32u : (uint)shift);
if(op == 3 && shift != 0) output.append(" ror #", shift); if(op == 3 && shift != 0) output.append(" ror #", shift);
if(op == 3 && shift == 0) output.append(" rrx"); if(op == 3 && shift == 0) output.append(" rrx");
@ -300,9 +300,9 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
uint4 rm = instruction; uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]); output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ","); if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
if(is_comp(opcode)) output.append(registers[rn], ","); if(isComp(opcode)) output.append(registers[rn], ",");
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ","); if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
output.append(registers[rm]); output.append(registers[rm]);
if(mode == 0) output.append(" lsl "); if(mode == 0) output.append(" lsl ");
if(mode == 1) output.append(" lsr "); if(mode == 1) output.append(" lsr ");
@ -328,9 +328,9 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
uint32 rm = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1))); uint32 rm = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)));
output.append(opcodes[opcode], conditions[condition]); output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]); if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(is_comp(opcode)) output.append(" ", registers[rn]); if(isComp(opcode)) output.append(" ", registers[rn]);
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]); if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",#0x", hex(rm, 8L)); output.append(",#0x", hex(rm, 8L));
return output; return output;
@ -382,8 +382,8 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
if(pre == 0) output.append("]"); if(pre == 0) output.append("]");
output.append(",", up ? "+" : "-", registers[rm]); output.append(",", up ? "+" : "-", registers[rm]);
if(mode == 0 && shift != 0) output.append(" lsl #", shift); if(mode == 0 && shift != 0) output.append(" lsl #", shift);
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift); if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (uint)shift);
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift); if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (uint)shift);
if(mode == 3 && shift != 0) output.append(" ror #", shift); if(mode == 3 && shift != 0) output.append(" ror #", shift);
if(mode == 3 && shift == 0) output.append(" rrx"); if(mode == 3 && shift == 0) output.append(" rrx");
if(pre == 1) output.append("]"); if(pre == 1) output.append("]");
@ -405,7 +405,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " "); output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " ");
output.append(registers[rn], writeback ? "!" : "", ",{"); output.append(registers[rn], writeback ? "!" : "", ",{");
for(unsigned n = 0; n < 16; n++) if(list & (1 << n)) output.append(registers[n], ","); for(uint n : range(16)) if(list & (1 << n)) output.append(registers[n], ",");
output.trimRight(",", 1L); output.trimRight(",", 1L);
output.append("}", s ? "^" : ""); output.append("}", s ? "^" : "");
@ -438,7 +438,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
return output; return output;
} }
auto ARM::disassemble_thumb_instruction(uint32 pc) -> string { auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
static string conditions[] = { static string conditions[] = {
"eq", "ne", "cs", "cc", "eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc", "mi", "pl", "vs", "vc",
@ -567,7 +567,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint3 rd = instruction >> 8; uint3 rd = instruction >> 8;
uint8 displacement = instruction; uint8 displacement = instruction;
unsigned rm = ((pc + 4) & ~3) + displacement * 4; uint rm = ((pc + 4) & ~3) + displacement * 4;
output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 3L), "]"); output.append("ldr ", registers[rd], ",[pc,#0x", hex(rm, 3L), "]");
output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L)); output.append(" =0x", hex(read(Word | Nonsequential, rm), 8L));
@ -675,7 +675,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint8 list = instruction; uint8 list = instruction;
output.append(load == 0 ? "push" : "pop", " {"); output.append(load == 0 ? "push" : "pop", " {");
for(unsigned l = 0; l < 8; l++) { for(uint l : range(8)) {
if(list & (1 << l)) output.append(registers[l], ","); if(list & (1 << l)) output.append(registers[l], ",");
} }
if(branch) output.append(load == 0 ? "lr," : "pc,"); if(branch) output.append(load == 0 ? "lr," : "pc,");
@ -693,7 +693,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint8 list = instruction; uint8 list = instruction;
output.append(load ? "ldmia " : "stmia ", registers[rn], "!,{"); output.append(load ? "ldmia " : "stmia ", registers[rn], "!,{");
for(unsigned l = 0; l < 8; l++) { for(uint l : range(8)) {
if(list & (1 << l)) output.append(registers[l], ","); if(list & (1 << l)) output.append(registers[l], ",");
} }
output.trimRight(",", 1L); output.trimRight(",", 1L);
@ -759,7 +759,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
return output; return output;
} }
auto ARM::disassemble_registers() -> string { auto ARM::disassembleRegisters() -> string {
string output; string output;
output.append( "r0:", hex(r( 0), 8L), " r1:", hex(r( 1), 8L), " r2:", hex(r( 2), 8L), " r3:", hex(r( 3), 8L), " "); output.append( "r0:", hex(r( 0), 8L), " r1:", hex(r( 1), 8L), " r2:", hex(r( 2), 8L), " r3:", hex(r( 3), 8L), " ");
output.append( "r4:", hex(r( 4), 8L), " r5:", hex(r( 5), 8L), " r6:", hex(r( 6), 8L), " r7:", hex(r( 7), 8L), " "); output.append( "r4:", hex(r( 4), 8L), " r5:", hex(r( 5), 8L), " r6:", hex(r( 6), 8L), " r7:", hex(r( 7), 8L), " ");

View File

@ -1,3 +1,3 @@
auto disassemble_arm_instruction(uint32 pc) -> string; auto disassembleInstructionARM(uint32 pc) -> string;
auto disassemble_thumb_instruction(uint32 pc) -> string; auto disassembleInstructionTHUMB(uint32 pc) -> string;
auto disassemble_registers() -> string; auto disassembleRegisters() -> string;

View File

@ -531,8 +531,8 @@ auto ARM::arm_op_move_multiple() {
if(s && l == 0) usr = true; if(s && l == 0) usr = true;
if(usr) processor.setMode(Processor::Mode::USR); if(usr) processor.setMode(Processor::Mode::USR);
unsigned sequential = Nonsequential; uint sequential = Nonsequential;
for(unsigned m = 0; m < 16; m++) { for(uint m : range(16)) {
if(list & 1 << m) { if(list & 1 << m) {
if(l == 1) r(m) = read(Word | sequential, rn); if(l == 1) r(m) = read(Word | sequential, rn);
if(l == 0) write(Word | sequential, rn, r(m)); if(l == 0) write(Word | sequential, rn, r(m));

View File

@ -69,8 +69,8 @@ auto ARM::thumb_op_shift_immediate() {
switch(opcode) { switch(opcode) {
case 0: r(d) = bit(lsl(r(m), immediate)); break; case 0: r(d) = bit(lsl(r(m), immediate)); break;
case 1: r(d) = bit(lsr(r(m), immediate == 0 ? 32u : (unsigned)immediate)); break; case 1: r(d) = bit(lsr(r(m), immediate == 0 ? 32u : (uint)immediate)); break;
case 2: r(d) = bit(asr(r(m), immediate == 0 ? 32u : (unsigned)immediate)); break; case 2: r(d) = bit(asr(r(m), immediate == 0 ? 32u : (uint)immediate)); break;
} }
} }
@ -142,7 +142,7 @@ auto ARM::thumb_op_load_literal() {
uint3 d = instruction() >> 8; uint3 d = instruction() >> 8;
uint8 displacement = instruction(); uint8 displacement = instruction();
unsigned rm = (r(15) & ~3) + displacement * 4; uint rm = (r(15) & ~3) + displacement * 4;
r(d) = load(Word | Nonsequential, rm); r(d) = load(Word | Nonsequential, rm);
} }
@ -273,8 +273,8 @@ auto ARM::thumb_op_stack_multiple() {
if(l == 1) sp = r(13); if(l == 1) sp = r(13);
if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4; if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4;
unsigned sequential = Nonsequential; uint sequential = Nonsequential;
for(unsigned m = 0; m < 8; m++) { for(uint m : range(8)) {
if(list & 1 << m) { if(list & 1 << m) {
if(l == 1) r(m) = read(Word | sequential, sp); //POP if(l == 1) r(m) = read(Word | sequential, sp); //POP
if(l == 0) write(Word | sequential, sp, r(m)); //PUSH if(l == 0) write(Word | sequential, sp, r(m)); //PUSH
@ -310,7 +310,7 @@ auto ARM::thumb_op_move_multiple() {
uint8 list = instruction(); uint8 list = instruction();
uint32 rn = r(n); //rn may be in register list; so we must cache it uint32 rn = r(n); //rn may be in register list; so we must cache it
for(unsigned m = 0; m < 8; m++) { for(uint m : range(8)) {
if(list & 1 << m) { if(list & 1 << m) {
if(l == 1) r(m) = read(Word | Nonsequential, rn); //LDMIA if(l == 1) r(m) = read(Word | Nonsequential, rn); //LDMIA
if(l == 0) write(Word | Nonsequential, rn, r(m)); //STMIA if(l == 0) write(Word | Nonsequential, rn, r(m)); //STMIA

View File

@ -32,7 +32,7 @@ auto ARM::Processor::power() -> void {
} }
auto ARM::Processor::setMode(Mode mode) -> void { auto ARM::Processor::setMode(Mode mode) -> void {
cpsr.m = 0x10 | (unsigned)mode; cpsr.m = 0x10 | (uint)mode;
if(mode == Mode::FIQ) { if(mode == Mode::FIQ) {
r[ 8] = &fiq.r8; r[ 8] = &fiq.r8;

View File

@ -54,7 +54,7 @@ struct Pipeline {
}; };
struct Processor { struct Processor {
enum class Mode : unsigned { enum class Mode : uint {
USR = 0x10, //user USR = 0x10, //user
FIQ = 0x11, //fast interrupt request FIQ = 0x11, //fast interrupt request
IRQ = 0x12, //interrupt request IRQ = 0x12, //interrupt request

View File

@ -1,8 +1,8 @@
auto ARM::pipeline_step() -> void { auto ARM::stepPipeline() -> void {
pipeline.execute = pipeline.decode; pipeline.execute = pipeline.decode;
pipeline.decode = pipeline.fetch; pipeline.decode = pipeline.fetch;
unsigned sequential = Sequential; uint sequential = Sequential;
if(pipeline.nonsequential) { if(pipeline.nonsequential) {
pipeline.nonsequential = false; pipeline.nonsequential = false;
sequential = Nonsequential; sequential = Nonsequential;
@ -19,7 +19,7 @@ auto ARM::pipeline_step() -> void {
} }
} }
auto ARM::arm_step() -> void { auto ARM::stepARM() -> void {
if(pipeline.reload) { if(pipeline.reload) {
pipeline.reload = false; pipeline.reload = false;
r(15).data &= ~3; r(15).data &= ~3;
@ -27,10 +27,10 @@ auto ARM::arm_step() -> void {
pipeline.fetch.address = r(15) & ~3; pipeline.fetch.address = r(15) & ~3;
pipeline.fetch.instruction = read(Prefetch | Word | Nonsequential, pipeline.fetch.address); pipeline.fetch.instruction = read(Prefetch | Word | Nonsequential, pipeline.fetch.address);
pipeline_step(); stepPipeline();
} }
pipeline_step(); stepPipeline();
if(processor.irqline && cpsr().i == 0) { if(processor.irqline && cpsr().i == 0) {
vector(0x00000018, Processor::Mode::IRQ); vector(0x00000018, Processor::Mode::IRQ);
@ -39,8 +39,8 @@ auto ARM::arm_step() -> void {
instructions++; instructions++;
if(trace) { if(trace) {
print(disassemble_registers(), "\n"); print(disassembleRegisters(), "\n");
print(disassemble_arm_instruction(pipeline.execute.address), "\n"); print(disassembleInstructionARM(pipeline.execute.address), "\n");
usleep(100000); usleep(100000);
} }
@ -76,7 +76,7 @@ auto ARM::arm_step() -> void {
crash = true; crash = true;
} }
auto ARM::thumb_step() -> void { auto ARM::stepTHUMB() -> void {
if(pipeline.reload) { if(pipeline.reload) {
pipeline.reload = false; pipeline.reload = false;
r(15).data &= ~1; r(15).data &= ~1;
@ -84,10 +84,10 @@ auto ARM::thumb_step() -> void {
pipeline.fetch.address = r(15) & ~1; pipeline.fetch.address = r(15) & ~1;
pipeline.fetch.instruction = read(Prefetch | Half | Nonsequential, pipeline.fetch.address); pipeline.fetch.instruction = read(Prefetch | Half | Nonsequential, pipeline.fetch.address);
pipeline_step(); stepPipeline();
} }
pipeline_step(); stepPipeline();
if(processor.irqline && cpsr().i == 0) { if(processor.irqline && cpsr().i == 0) {
vector(0x00000018, Processor::Mode::IRQ); vector(0x00000018, Processor::Mode::IRQ);
@ -97,8 +97,8 @@ auto ARM::thumb_step() -> void {
instructions++; instructions++;
if(trace) { if(trace) {
print(disassemble_registers(), "\n"); print(disassembleRegisters(), "\n");
print(disassemble_thumb_instruction(pipeline.execute.address), "\n"); print(disassembleInstructionTHUMB(pipeline.execute.address), "\n");
} }
#define decode(pattern, execute) if( \ #define decode(pattern, execute) if( \

View File

@ -84,7 +84,7 @@ auto Cartridge::loadICD2(Markup::Node node) -> void {
icd2.revision = max(1, node["revision"].natural()); icd2.revision = max(1, node["revision"].natural());
//Game Boy core loads data through ICD2 interface //Game Boy core loads data through ICD2 interface
for(auto leaf : node.find("map")) loadMap(leaf, {&ICD2::read, &icd2}, {&ICD2::write, &icd2}); for(auto leaf : node.find("map")) loadMap(leaf, {&ICD2::readIO, &icd2}, {&ICD2::writeIO, &icd2});
} }
auto Cartridge::loadMCC(Markup::Node node) -> void { auto Cartridge::loadMCC(Markup::Node node) -> void {

View File

@ -39,13 +39,13 @@ auto ArmDSP::boot() -> void {
auto ArmDSP::main() -> void { auto ArmDSP::main() -> void {
if(crash) { if(crash) {
print(disassemble_arm_instruction(pipeline.execute.address), "\n"); print(disassembleRegisters(), "\n");
print(disassemble_registers(), "\n"); print(disassembleInstructionARM(pipeline.execute.address), "\n");
print("Executed: ", instructions, "\n"); print("Executed: ", instructions, "\n");
while(true) step(frequency); while(true) step(frequency);
} }
arm_step(); stepARM();
} }
auto ArmDSP::step(uint clocks) -> void { auto ArmDSP::step(uint clocks) -> void {

View File

@ -11,9 +11,9 @@ struct ArmDSP : Processor::ARM, Cothread {
auto main() -> void; auto main() -> void;
auto step(uint clocks) -> void override; auto step(uint clocks) -> void override;
auto busIdle() -> void override; auto _idle() -> void override;
auto busRead(uint mode, uint32 addr) -> uint32 override; auto _read(uint mode, uint32 addr) -> uint32 override;
auto busWrite(uint mode, uint32 addr, uint32 word) -> void override; auto _write(uint mode, uint32 addr, uint32 word) -> void override;
auto read(uint24 addr, uint8 data) -> uint8; auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void; auto write(uint24 addr, uint8 data) -> void;

View File

@ -1,11 +1,11 @@
//note: timings are completely unverified //note: timings are completely unverified
//due to the ST018 chip design (on-die ROM), testing is nearly impossible //due to the ST018 chip design (on-die ROM), testing is nearly impossible
auto ArmDSP::busIdle() -> void { auto ArmDSP::_idle() -> void {
step(1); step(1);
} }
auto ArmDSP::busRead(uint mode, uint32 addr) -> uint32 { auto ArmDSP::_read(uint mode, uint32 addr) -> uint32 {
step(1); step(1);
static auto memory = [&](const uint8* memory, uint mode, uint32 addr) -> uint32 { static auto memory = [&](const uint8* memory, uint mode, uint32 addr) -> uint32 {
@ -46,7 +46,7 @@ auto ArmDSP::busRead(uint mode, uint32 addr) -> uint32 {
return 0; return 0;
} }
auto ArmDSP::busWrite(uint mode, uint32 addr, uint32 word) -> void { auto ArmDSP::_write(uint mode, uint32 addr, uint32 word) -> void {
step(1); step(1);
static auto memory = [](uint8* memory, uint mode, uint32 addr, uint32 word) { static auto memory = [](uint8* memory, uint mode, uint32 addr, uint32 word) {

View File

@ -7,7 +7,7 @@ ICD2 icd2;
#if defined(SFC_SUPERGAMEBOY) #if defined(SFC_SUPERGAMEBOY)
#include "interface.cpp" #include "interface.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "serialization.cpp" #include "serialization.cpp"
auto ICD2::Enter() -> void { auto ICD2::Enter() -> void {

View File

@ -24,9 +24,9 @@ struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Cothread {
auto audioSample(const double* samples, uint channels) -> void override; auto audioSample(const double* samples, uint channels) -> void override;
auto inputPoll(uint port, uint device, uint id) -> int16 override; auto inputPoll(uint port, uint device, uint id) -> int16 override;
//mmio.cpp //io.cpp
auto read(uint24 addr, uint8 data) -> uint8; auto readIO(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void; auto writeIO(uint24 addr, uint8 data) -> void;
//serialization.cpp //serialization.cpp
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;

View File

@ -1,4 +1,4 @@
auto ICD2::read(uint24 addr, uint8 data) -> uint8 { auto ICD2::readIO(uint24 addr, uint8 data) -> uint8 {
addr &= 0x40ffff; addr &= 0x40ffff;
//LY counter //LY counter
@ -38,7 +38,7 @@ auto ICD2::read(uint24 addr, uint8 data) -> uint8 {
return 0x00; return 0x00;
} }
auto ICD2::write(uint24 addr, uint8 data) -> void { auto ICD2::writeIO(uint24 addr, uint8 data) -> void {
addr &= 0xffff; addr &= 0xffff;
//VRAM port //VRAM port

View File

@ -5,7 +5,7 @@ namespace SuperFamicom {
#include "bus.cpp" #include "bus.cpp"
#include "dma.cpp" #include "dma.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "serialization.cpp" #include "serialization.cpp"
SA1 sa1; SA1 sa1;

View File

@ -63,7 +63,7 @@ struct SA1 : Processor::R65816, Cothread {
auto bitmapRead(uint addr, uint8 data) -> uint8; auto bitmapRead(uint addr, uint8 data) -> uint8;
auto bitmapWrite(uint addr, uint8 data) -> void; auto bitmapWrite(uint addr, uint8 data) -> void;
//mmio.cpp //io.cpp
auto readIO(uint24 addr, uint8 data) -> uint8; auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void; auto writeIO(uint24 addr, uint8 data) -> void;

View File

@ -5,7 +5,7 @@ namespace SuperFamicom {
#include "bus.cpp" #include "bus.cpp"
#include "core.cpp" #include "core.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "timing.cpp" #include "timing.cpp"
#include "serialization.cpp" #include "serialization.cpp"
SuperFX superfx; SuperFX superfx;

View File

@ -44,7 +44,7 @@ struct SuperFX : Processor::GSU, Cothread {
auto readCache(uint16 addr) -> uint8; auto readCache(uint16 addr) -> uint8;
auto writeCache(uint16 addr, uint8 data) -> void; auto writeCache(uint16 addr, uint8 data) -> void;
//mmio.cpp //io.cpp
auto readIO(uint24 addr, uint8 data) -> uint8; auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void; auto writeIO(uint24 addr, uint8 data) -> void;

View File

@ -5,7 +5,7 @@ namespace SuperFamicom {
CPU cpu; CPU cpu;
#include "dma.cpp" #include "dma.cpp"
#include "memory.cpp" #include "memory.cpp"
#include "mmio.cpp" #include "io.cpp"
#include "timing.cpp" #include "timing.cpp"
#include "irq.cpp" #include "irq.cpp"
#include "joypad.cpp" #include "joypad.cpp"

View File

@ -52,7 +52,7 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
alwaysinline auto speed(uint24 addr) const -> uint; alwaysinline auto speed(uint24 addr) const -> uint;
auto readDisassembler(uint24 addr) -> uint8 override; auto readDisassembler(uint24 addr) -> uint8 override;
//mmio.cpp //io.cpp
auto readAPU(uint24 addr, uint8 data) -> uint8; auto readAPU(uint24 addr, uint8 data) -> uint8;
auto readCPU(uint24 addr, uint8 data) -> uint8; auto readCPU(uint24 addr, uint8 data) -> uint8;
auto readDMA(uint24 addr, uint8 data) -> uint8; auto readDMA(uint24 addr, uint8 data) -> uint8;

View File

@ -4,7 +4,7 @@ namespace SuperFamicom {
PPU ppu; PPU ppu;
#include "mmio.cpp" #include "io.cpp"
#include "background/background.cpp" #include "background/background.cpp"
#include "object/object.cpp" #include "object/object.cpp"
#include "window/window.cpp" #include "window/window.cpp"

View File

@ -17,7 +17,7 @@ struct PPU : Thread, PPUcounter {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
//mmio.cpp //io.cpp
alwaysinline auto getVramAddress() -> uint16; alwaysinline auto getVramAddress() -> uint16;
alwaysinline auto vramAccessible() const -> bool; alwaysinline auto vramAccessible() const -> bool;
alwaysinline auto oamWrite(uint addr, uint8 data) -> void; alwaysinline auto oamWrite(uint addr, uint8 data) -> void;

View File

@ -17,9 +17,11 @@ Presentation::Presentation() {
//add icarus menu options -- but only if icarus binary is present //add icarus menu options -- but only if icarus binary is present
if(execute("icarus", "--name").output.strip() == "icarus") { if(execute("icarus", "--name").output.strip() == "icarus") {
libraryMenu.append(MenuSeparator()); libraryMenu.append(MenuSeparator());
libraryMenu.append(MenuItem().setText("Import ROM File ...").onActivate([&] { libraryMenu.append(MenuItem().setText("Load ROM File ...").onActivate([&] {
audio->clear(); audio->clear();
if(auto location = execute("icarus", "--import")) { if(auto location = execute("icarus", "--import")) {
program->mediumQueue.append(location.output.strip());
program->loadMedium();
} }
})); }));
libraryMenu.append(MenuItem().setText("Import ROM Files ...").onActivate([&] { libraryMenu.append(MenuItem().setText("Import ROM Files ...").onActivate([&] {