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 {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,17 +11,163 @@ struct APU : Thread, MMIO {
auto serialize(serializer&) -> void;
#include "square1/square1.hpp"
#include "square2/square2.hpp"
#include "wave/wave.hpp"
#include "noise/noise.hpp"
#include "sequencer/sequencer.hpp"
//square1.cpp
struct Square1 {
auto dacEnable() const -> bool;
Square1 square1;
Square2 square2;
Wave wave;
Noise noise;
Sequencer sequencer;
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;
} 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
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 {
#include "mmio.cpp"
#include "io.cpp"
#include "memory.cpp"
#include "timing.cpp"
#include "serialization.cpp"

View File

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

View File

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

View File

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

View File

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

View File

@ -3,12 +3,12 @@
namespace GameBoy {
PPU ppu;
#include "mmio.cpp"
#include "io.cpp"
#include "dmg.cpp"
#include "cgb.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 {
while(true) scheduler.synchronize(), ppu.main();
@ -21,20 +21,20 @@ auto PPU::main() -> void {
if(status.ly <= 143) {
mode(2);
scanline();
wait(92);
step(92);
mode(3);
for(auto n : range(160)) {
run();
wait(1);
step(1);
}
mode(0);
if(enabled()) cpu.hblank();
wait(204);
step(204);
} else {
mode(1);
wait(456);
step(456);
}
status.ly++;
@ -56,10 +56,10 @@ auto PPU::mode(uint mode) -> void {
auto PPU::stat() -> void {
bool irq = status.irq;
status.irq = status.interrupt_hblank && status.mode == 0;
status.irq |= status.interrupt_vblank && status.mode == 1;
status.irq |= status.interrupt_oam && status.mode == 2;
status.irq |= status.interrupt_lyc && coincidence();
status.irq = status.interruptHblank && status.mode == 0;
status.irq |= status.interruptVblank && status.mode == 1;
status.irq |= status.interruptOAM && status.mode == 2;
status.irq |= status.interruptLYC && coincidence();
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);
}
auto PPU::wait(uint clocks) -> void {
auto PPU::step(uint clocks) -> void {
while(clocks--) {
stat();
if(status.dma_active) {
uint hi = status.dma_clock++;
if(status.dmaActive) {
uint hi = status.dmaClock++;
uint lo = hi & (cpu.status.speedDouble ? 1 : 3);
hi >>= cpu.status.speedDouble ? 1 : 2;
if(lo == 0) {
@ -86,9 +86,9 @@ auto PPU::wait(uint clocks) -> void {
//warm-up
} else if(hi == 161) {
//cool-down; disable
status.dma_active = false;
status.dmaActive = false;
} 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);
if(system.cgb()) {
scanline = {&PPU::cgb_scanline, this};
run = {&PPU::cgb_run, this};
scanline = {&PPU::scanlineCGB, this};
run = {&PPU::runCGB, this};
} else {
scanline = {&PPU::dmg_scanline, this};
run = {&PPU::dmg_run, this};
scanline = {&PPU::scanlineDMG, this};
run = {&PPU::runDMG, this};
}
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 : obpd) n = 0x0000;
status.irq = false;
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;
memory::fill(&status, sizeof(Status));
for(auto& n : screen) n = 0;

View File

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

View File

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

View File

@ -2,7 +2,7 @@
namespace GameBoyAdvance {
#include "mmio.cpp"
#include "io.cpp"
#include "square.cpp"
#include "square1.cpp"
#include "square2.cpp"
@ -87,7 +87,7 @@ auto APU::power() -> void {
regs.bias.amplitude = 0;
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;
#include "registers.hpp"
@ -7,8 +7,8 @@ struct APU : Thread, MMIO {
auto main() -> void;
auto step(uint clocks) -> void;
auto read(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void;
auto readIO(uint32 addr) -> uint8;
auto writeIO(uint32 addr, uint8 byte) -> void;
auto power() -> void;
auto runsequencer() -> void;

View File

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

View File

@ -42,7 +42,7 @@ auto Cartridge::FLASH::write(uint16 addr, uint8 byte) -> void {
if(byte == 0x10 && addr == 0x5555) {
if(erasemode) {
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
if(erasemode && id != 0x3d1f) {
erasemode = false;
unsigned offset = bank << 16 | (addr & ~4095);
for(unsigned n = 0; n < 4096; n++) data[offset++] = 0xff;
uint offset = bank << 16 | (addr & ~4095);
for(uint n : range(4096)) data[offset++] = 0xff;
}
}

View File

@ -1,63 +1,63 @@
auto CPU::busIdle() -> void {
prefetch_step(1);
auto CPU::_idle() -> void {
prefetchStep(1);
}
auto CPU::busRead(uint mode, uint32 addr) -> uint32 {
uint wait = busWait(mode, addr);
auto CPU::_read(uint mode, uint32 addr) -> uint32 {
uint wait = this->wait(mode, addr);
uint word = pipeline.fetch.instruction;
if(addr >= 0x1000'0000) {
prefetch_step(wait);
prefetchStep(wait);
} else if(addr & 0x0800'0000) {
if(mode & Prefetch && regs.wait.control.prefetch) {
prefetch_sync(addr);
word = prefetch_read();
if(mode & Word) word |= prefetch_read() << 16;
prefetchSync(addr);
word = prefetchRead();
if(mode & Word) word |= prefetchRead() << 16;
} else {
if(!active.dma) prefetch_wait();
if(!active.dma) prefetchWait();
step(wait - 1);
word = cartridge.read(mode, addr);
step(1);
}
} else {
prefetch_step(wait - 1);
prefetchStep(wait - 1);
if(addr < 0x0200'0000) word = bios.read(mode, addr);
else if(addr < 0x0300'0000) word = ewram_read(mode, addr);
else if(addr < 0x0400'0000) word = iwram_read(mode, addr);
else if(addr >= 0x0700'0000) word = ppu.oam_read(mode, addr);
else if(addr >= 0x0600'0000) word = ppu.vram_read(mode, addr);
else if(addr >= 0x0500'0000) word = ppu.pram_read(mode, addr);
else if((addr & 0xffff'fc00) == 0x0400'0000) word = bus.mmio[addr & 0x3ff]->read(mode, addr);
else if((addr & 0xff00'ffff) == 0x0400'0800) word = ((MMIO*)this)->read(mode, 0x0400'0800 | (addr & 3));
prefetch_step(1);
else if(addr < 0x0300'0000) word = readEWRAM(mode, addr);
else if(addr < 0x0400'0000) word = readIWRAM(mode, addr);
else if(addr >= 0x0700'0000) word = ppu.readOAM(mode, addr);
else if(addr >= 0x0600'0000) word = ppu.readVRAM(mode, addr);
else if(addr >= 0x0500'0000) word = ppu.readPRAM(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 = ((IO*)this)->readIO(mode, 0x0400'0800 | (addr & 3));
prefetchStep(1);
}
return word;
}
auto CPU::busWrite(uint mode, uint32 addr, uint32 word) -> void {
uint wait = busWait(mode, addr);
auto CPU::_write(uint mode, uint32 addr, uint32 word) -> void {
uint wait = this->wait(mode, addr);
if(addr >= 0x1000'0000) {
prefetch_step(wait);
prefetchStep(wait);
} else if(addr & 0x0800'0000) {
if(!active.dma) prefetch_wait();
if(!active.dma) prefetchWait();
step(wait);
cartridge.write(mode, addr, word);
} else {
prefetch_step(wait);
prefetchStep(wait);
if(addr < 0x0200'0000);
else if(addr < 0x0300'0000) ewram_write(mode, addr, word);
else if(addr < 0x0400'0000) iwram_write(mode, addr, word);
else if(addr >= 0x0700'0000) ppu.oam_write(mode, addr, word);
else if(addr >= 0x0600'0000) ppu.vram_write(mode, addr, word);
else if(addr >= 0x0500'0000) ppu.pram_write(mode, addr, word);
else if((addr & 0xffff'fc00) == 0x0400'0000) bus.mmio[addr & 0x3ff]->write(mode, addr, word);
else if((addr & 0xff00'ffff) == 0x0400'0800) ((MMIO*)this)->write(mode, 0x0400'0800 | (addr & 3), word);
else if(addr < 0x0300'0000) writeEWRAM(mode, addr, word);
else if(addr < 0x0400'0000) writeIWRAM(mode, addr, word);
else if(addr >= 0x0700'0000) ppu.writeOAM(mode, addr, word);
else if(addr >= 0x0600'0000) ppu.writeVRAM(mode, addr, word);
else if(addr >= 0x0500'0000) ppu.writePRAM(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) ((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 < 0x0200'0000) return 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 "bus.cpp"
#include "mmio.cpp"
#include "io.cpp"
#include "memory.cpp"
#include "dma.cpp"
#include "timer.cpp"
@ -56,14 +56,14 @@ auto CPU::main() -> void {
if(regs.mode == Registers::Mode::Stop) {
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 {
regs.mode = Registers::Mode::Normal;
}
return;
}
dma_run();
dmaRun();
if(regs.mode == Registers::Mode::Halt) {
if(!(regs.irq.enable & regs.irq.flag)) {
@ -78,11 +78,11 @@ auto CPU::main() -> void {
}
auto CPU::step(uint clocks) -> void {
timer_step(clocks);
sync_step(clocks);
timerStep(clocks);
syncStep(clocks);
}
auto CPU::sync_step(uint clocks) -> void {
auto CPU::syncStep(uint clocks) -> void {
ppu.clock -= clocks;
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);
}
auto CPU::keypad_run() -> void {
auto CPU::keypadRun() -> void {
//lookup table to convert button indexes to Emulator::Interface indexes
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;
for(uint n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this; //DMA
for(uint n = 0x100; n <= 0x10f; n++) bus.mmio[n] = this; //Timers
for(uint n = 0x120; n <= 0x12b; n++) bus.mmio[n] = this; //Serial
for(uint n = 0x130; n <= 0x133; n++) bus.mmio[n] = this; //Keypad
for(uint n = 0x134; n <= 0x159; n++) bus.mmio[n] = this; //Serial
for(uint n = 0x200; n <= 0x209; n++) bus.mmio[n] = this; //System
for(uint n = 0x300; n <= 0x301; n++) bus.mmio[n] = this; //System
for(uint n = 0x0b0; n <= 0x0df; n++) bus.io[n] = this; //DMA
for(uint n = 0x100; n <= 0x10f; n++) bus.io[n] = this; //Timers
for(uint n = 0x120; n <= 0x12b; n++) bus.io[n] = this; //Serial
for(uint n = 0x130; n <= 0x133; n++) bus.io[n] = this; //Keypad
for(uint n = 0x134; n <= 0x159; n++) bus.io[n] = this; //Serial
for(uint n = 0x200; n <= 0x209; n++) bus.io[n] = this; //System
for(uint n = 0x300; n <= 0x301; n++) bus.io[n] = this; //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::write;
@ -34,37 +34,37 @@ struct CPU : Processor::ARM, Thread, MMIO {
auto step(uint clocks) -> void override;
auto sync_step(uint clocks) -> void;
auto keypad_run() -> void;
auto syncStep(uint clocks) -> void;
auto keypadRun() -> void;
auto power() -> void;
//bus.cpp
auto busIdle() -> void override;
auto busRead(uint mode, uint32 addr) -> uint32 override;
auto busWrite(uint mode, uint32 addr, uint32 word) -> void override;
auto busWait(uint mode, uint32 addr) -> uint;
auto _idle() -> void override;
auto _read(uint mode, uint32 addr) -> uint32 override;
auto _write(uint mode, uint32 addr, uint32 word) -> void override;
auto wait(uint mode, uint32 addr) -> uint;
//mmio.cpp
auto read(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void;
//io.cpp
auto readIO(uint32 addr) -> uint8;
auto writeIO(uint32 addr, uint8 byte) -> void;
auto iwram_read(uint mode, uint32 addr) -> uint32;
auto iwram_write(uint mode, uint32 addr, uint32 word) -> void;
auto readIWRAM(uint mode, uint32 addr) -> uint32;
auto writeIWRAM(uint mode, uint32 addr, uint32 word) -> void;
auto ewram_read(uint mode, uint32 addr) -> uint32;
auto ewram_write(uint mode, uint32 addr, uint32 word) -> void;
auto readEWRAM(uint mode, uint32 addr) -> uint32;
auto writeEWRAM(uint mode, uint32 addr, uint32 word) -> void;
//dma.cpp
auto dma_run() -> void;
auto dma_exec(Registers::DMA& dma) -> void;
auto dma_vblank() -> void;
auto dma_hblank() -> void;
auto dma_hdma() -> void;
auto dmaRun() -> void;
auto dmaExecute(Registers::DMA& dma) -> void;
auto dmaVblank() -> void;
auto dmaHblank() -> void;
auto dmaHDMA() -> void;
//timer.cpp
auto timer_step(uint clocks) -> void;
auto timer_increment(uint n) -> void;
auto timer_fifo_run(uint n) -> void;
auto timerStep(uint clocks) -> void;
auto timerIncrement(uint n) -> void;
auto timerRunFIFO(uint n) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -1,4 +1,4 @@
auto CPU::dma_run() -> void {
auto CPU::dmaRun() -> void {
active.dma = true;
while(true) {
@ -6,7 +6,7 @@ auto CPU::dma_run() -> void {
for(auto n : range(4)) {
auto& dma = regs.dma[n];
if(dma.pending) {
dma_exec(dma);
dmaExecute(dma);
if(dma.control.irq) regs.irq.flag |= Interrupt::DMA0 << n;
if(dma.control.drq && n == 3) regs.irq.flag |= Interrupt::Cartridge;
transferred = true;
@ -19,7 +19,7 @@ auto CPU::dma_run() -> void {
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 mode = dma.control.size ? Word : Half;
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;
if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1;
dma.data = busRead(mode, addr);
dma.data = _read(mode, addr);
}
if(dma.run.target < 0x0200'0000) {
@ -48,7 +48,7 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
uint32 addr = dma.run.target;
if(mode & Word) addr &= ~3;
if(mode & Half) addr &= ~1;
busWrite(mode, addr, dma.data);
_write(mode, addr, dma.data);
}
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) {
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) {
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];
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 timer = [&]() -> Registers::Timer& { return regs.timer[addr.bits(2,3)]; };
@ -196,7 +196,7 @@ auto CPU::read(uint32 addr) -> uint8 {
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 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(mode & Word) return iwram_read(Half, addr &~ 2) << 0 | iwram_read(Half, addr | 2) << 16;
if(mode & Half) return iwram_read(Byte, addr &~ 1) << 0 | iwram_read(Byte, addr | 1) << 8;
if(mode & Word) return readIWRAM(Half, addr &~ 2) << 0 | readIWRAM(Half, addr | 2) << 16;
if(mode & Half) return readIWRAM(Byte, addr &~ 1) << 0 | readIWRAM(Byte, addr | 1) << 8;
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(mode & Word) {
iwram_write(Half, addr &~2, word >> 0);
iwram_write(Half, addr | 2, word >> 16);
writeIWRAM(Half, addr &~2, word >> 0);
writeIWRAM(Half, addr | 2, word >> 16);
return;
}
if(mode & Half) {
iwram_write(Byte, addr &~1, word >> 0);
iwram_write(Byte, addr | 1, word >> 8);
writeIWRAM(Byte, addr &~1, word >> 0);
writeIWRAM(Byte, addr | 1, word >> 8);
return;
}
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.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 & Half) return ewram_read(Byte, addr &~ 1) << 0 | ewram_read(Byte, addr | 1) << 8;
if(mode & Word) return readEWRAM(Half, addr &~ 2) << 0 | readEWRAM(Half, addr | 2) << 16;
if(mode & Half) return readEWRAM(Byte, addr &~ 1) << 0 | readEWRAM(Byte, addr | 1) << 8;
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.ewram) return iwram_write(mode, addr, word);
if(!regs.memory.control.ewram) return writeIWRAM(mode, addr, word);
if(mode & Word) {
ewram_write(Half, addr &~2, word >> 0);
ewram_write(Half, addr | 2, word >> 16);
writeEWRAM(Half, addr &~2, word >> 0);
writeEWRAM(Half, addr | 2, word >> 16);
return;
}
if(mode & Half) {
ewram_write(Byte, addr &~1, word >> 0);
ewram_write(Byte, addr | 1, word >> 8);
writeEWRAM(Byte, addr &~1, word >> 0);
writeEWRAM(Byte, addr | 1, word >> 8);
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;
prefetch.addr = 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);
if(!regs.wait.control.prefetch || active.dma) return;
@ -14,22 +14,22 @@ auto CPU::prefetch_step(uint clocks) -> void {
if(--prefetch.wait) continue;
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
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;
prefetch_step(prefetch.wait);
prefetch.wait = busWait(Half | Nonsequential, prefetch.load);
prefetchStep(prefetch.wait);
prefetch.wait = wait(Half | Nonsequential, prefetch.load);
}
auto CPU::prefetch_read() -> uint16 {
if(prefetch.empty()) prefetch_step(prefetch.wait);
else prefetch_step(1);
auto CPU::prefetchRead() -> uint16 {
if(prefetch.empty()) prefetchStep(prefetch.wait);
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];
prefetch.addr += 2;

View File

@ -8,7 +8,7 @@ struct {
auto full() const { return load - addr == 16; }
} prefetch;
auto prefetch_sync(uint32 addr) -> void;
auto prefetch_step(uint clocks) -> void;
auto prefetch_wait() -> void;
auto prefetch_read() -> uint16;
auto prefetchSync(uint32 addr) -> void;
auto prefetchStep(uint clocks) -> void;
auto prefetchWait() -> void;
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 n : range(4)) {
auto& timer = regs.timer[n];
@ -11,11 +11,11 @@ auto CPU::timer_step(uint clocks) -> void {
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};
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];
if(++timer.period == 0) {
timer.period = timer.reload;
if(timer.control.irq) regs.irq.flag |= Interrupt::Timer0 << n;
if(apu.fifo[0].timer == n) timer_fifo_run(0);
if(apu.fifo[1].timer == n) timer_fifo_run(1);
if(apu.fifo[0].timer == n) timerRunFIFO(0);
if(apu.fifo[1].timer == n) timerRunFIFO(1);
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();
if(apu.fifo[n].size > 16) return;

View File

@ -2,15 +2,50 @@
namespace GameBoyAdvance {
#include "mmio.cpp"
Bus bus;
struct UnmappedMemory : Memory {
auto read(uint mode, uint32 addr) -> uint32 override { return 0; }
auto write(uint mode, uint32 addr, uint32 word) -> void override {}
auto IO::readIO(uint mode, uint32 addr) -> uint32 {
uint32 word = 0;
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 {
uint32 base = 0;
@ -31,7 +66,7 @@ auto Bus::mirror(uint32 addr, uint32 size) -> uint32 {
}
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 {
virtual auto read(uint mode, uint32 addr) -> uint32 = 0;
virtual auto write(uint mode, uint32 addr, uint32 word) -> void = 0;
};
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 IO {
virtual auto readIO(uint32 addr) -> uint8 = 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 Bus {
@ -15,7 +10,7 @@ struct Bus {
auto power() -> void;
Memory* mmio[0x400] = {nullptr};
IO* io[0x400] = {nullptr};
};
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) {
case 0:
render_background_linear(regs.bg[3]);
render_background_linear(regs.bg[2]);
render_background_linear(regs.bg[1]);
render_background_linear(regs.bg[0]);
renderBackgroundLinear(regs.bg[3]);
renderBackgroundLinear(regs.bg[2]);
renderBackgroundLinear(regs.bg[1]);
renderBackgroundLinear(regs.bg[0]);
break;
case 1:
render_background_affine(regs.bg[2]);
render_background_linear(regs.bg[1]);
render_background_linear(regs.bg[0]);
renderBackgroundAffine(regs.bg[2]);
renderBackgroundLinear(regs.bg[1]);
renderBackgroundLinear(regs.bg[0]);
break;
case 2:
render_background_affine(regs.bg[3]);
render_background_affine(regs.bg[2]);
renderBackgroundAffine(regs.bg[3]);
renderBackgroundAffine(regs.bg[2]);
break;
case 3: case 4: case 5:
render_background_bitmap(regs.bg[2]);
renderBackgroundBitmap(regs.bg[2]);
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;
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 & 2) if(ty & 32) offset += 32 * 32 * (1 + (bg.control.screensize & 1));
offset = basemap + offset * 2;
uint16 mapdata = vram_read(Half, offset);
uint16 mapdata = readVRAM(Half, offset);
tile.character = mapdata >> 0;
tile.hflip = mapdata >> 10;
@ -57,12 +57,12 @@ auto PPU::render_background_linear(Registers::Background& bg) -> void {
if(bg.control.colormode == 0) {
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;
} else {
offset = basechr + tile.character * 64 + (py ^ (tile.vflip ? 7 : 0)) * 8;
uint32 wordlo = vram_read(Word, offset + 0);
uint32 wordhi = vram_read(Word, offset + 4);
uint32 wordlo = readVRAM(Word, offset + 0);
uint32 wordhi = readVRAM(Word, offset + 4);
for(auto n : range(4)) data[0 + n] = (wordlo >> (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;
auto& output = layer[bg.id];
@ -113,7 +113,7 @@ auto PPU::render_background_affine(Registers::Background& bg) -> void {
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;
auto& output = layer[bg.id];
@ -138,7 +138,7 @@ auto PPU::render_background_bitmap(Registers::Background& bg) -> void {
if(px < width && py < height) {
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 == 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 wf = [&]() -> Registers::WindowFlags& {
static uint id[] = {In0, In1, Out, Obj};
@ -102,7 +102,7 @@ auto PPU::read(uint32 addr) -> uint8 {
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 bgofs = [&]() -> Registers::Background& { return regs.bg[addr.bits(2,3)]; };
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;
if(mode & Word) {
@ -14,7 +14,7 @@ auto PPU::vram_read(uint mode, uint32 addr) -> uint32 {
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;
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 {
if(mode & Word) return pram_read(Half, addr & ~2) << 0 | pram_read(Half, addr | 2) << 16;
if(mode & Byte) return pram_read(Half, addr) >> ((addr & 1) * 8);
auto PPU::readPRAM(uint mode, uint32 addr) -> uint32 {
if(mode & Word) return readPRAM(Half, addr & ~2) << 0 | readPRAM(Half, addr | 2) << 16;
if(mode & Byte) return readPRAM(Half, addr) >> ((addr & 1) * 8);
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) {
pram_write(Half, addr & ~2, word >> 0);
pram_write(Half, addr | 2, word >> 16);
writePRAM(Half, addr & ~2, word >> 0);
writePRAM(Half, addr | 2, word >> 16);
return;
}
if(mode & Byte) {
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;
}
auto PPU::oam_read(uint mode, uint32 addr) -> uint32 {
if(mode & Word) return oam_read(Half, addr & ~2) << 0 | oam_read(Half, addr | 2) << 16;
if(mode & Byte) return oam_read(Half, addr) >> ((addr & 1) * 8);
auto PPU::readOAM(uint mode, uint32 addr) -> uint32 {
if(mode & Word) return readOAM(Half, addr & ~2) << 0 | readOAM(Half, addr | 2) << 16;
if(mode & Byte) return readOAM(Half, addr) >> ((addr & 1) * 8);
auto& obj = object[addr >> 3 & 127];
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) {
oam_write(Half, addr & ~2, word >> 0);
oam_write(Half, addr | 2, word >> 16);
writeOAM(Half, addr & ~2, word >> 0);
writeOAM(Half, addr | 2, word >> 16);
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;
uint width = 1 + regs.mosaic.bghsize;
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;
uint width = 1 + regs.mosaic.objhsize;
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;
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)
//fx,fy = affine pixel coordinates
//pa,pb,pc,pd = affine pixel adjustments
//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;
if(obj.affine == 0 && obj.affinesize == 1) return; //hidden
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);
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(color) {
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(addr <= 0x3fff) return 0u;
}

View File

@ -17,7 +17,7 @@ PPU ppu;
#include "object.cpp"
#include "mosaic.cpp"
#include "screen.cpp"
#include "mmio.cpp"
#include "io.cpp"
#include "memory.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 < 1024; n += 2) pram_write(n, Half, 0x0000);
for(uint n = 0; n < 1024; n += 2) oam_write(n, Half, 0x0000);
for(uint n = 0; n < 1024; n += 2) writePRAM(n, Half, 0x0000);
for(uint n = 0; n < 1024; n += 2) writeOAM(n, Half, 0x0000);
regs.control.bgmode = 0;
regs.control.cgbmode = 0;
@ -112,11 +112,11 @@ auto PPU::power() -> void {
regs.blend.evb = 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 {
cpu.keypad_run();
cpu.keypadRun();
regs.status.vblank = regs.vcounter >= 160 && regs.vcounter <= 226;
regs.status.vcoincidence = regs.vcounter == regs.status.vcompare;
@ -133,7 +133,7 @@ auto PPU::scanline() -> void {
if(regs.vcounter == 160) {
if(regs.status.irqvblank) cpu.regs.irq.flag |= CPU::Interrupt::VBlank;
cpu.dma_vblank();
cpu.dmaVblank();
}
if(regs.status.irqvcoincidence) {
@ -142,7 +142,7 @@ auto PPU::scanline() -> void {
if(regs.vcounter < 160) {
if(regs.control.forceblank || cpu.regs.mode == CPU::Registers::Mode::Stop) {
render_forceblank();
renderForceBlank();
} else {
for(auto x : range(240)) {
windowmask[0][x] = false;
@ -155,22 +155,22 @@ auto PPU::scanline() -> void {
layer[BG3][x].write(false);
layer[SFX][x].write(true, 3, pram[0]);
}
render_window(0);
render_window(1);
render_objects();
render_backgrounds();
render_screen();
renderWindow(0);
renderWindow(1);
renderObjects();
renderBackgrounds();
renderScreen();
}
}
step(960);
regs.status.hblank = 1;
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);
regs.status.hblank = 0;
if(regs.vcounter < 160) cpu.dma_hdma();
if(regs.vcounter < 160) cpu.dmaHDMA();
step(32);
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 "state.hpp"
@ -14,33 +14,33 @@ struct PPU : Thread, MMIO {
auto frame() -> void;
auto refresh() -> void;
auto read(uint32 addr) -> uint8;
auto write(uint32 addr, uint8 byte) -> void;
auto readIO(uint32 addr) -> uint8;
auto writeIO(uint32 addr, uint8 byte) -> void;
auto vram_read(uint mode, uint32 addr) -> uint32;
auto vram_write(uint mode, uint32 addr, uint32 word) -> void;
auto readVRAM(uint mode, uint32 addr) -> uint32;
auto writeVRAM(uint mode, uint32 addr, uint32 word) -> void;
auto pram_read(uint mode, uint32 addr) -> uint32;
auto pram_write(uint mode, uint32 addr, uint32 word) -> void;
auto readPRAM(uint mode, uint32 addr) -> uint32;
auto writePRAM(uint mode, uint32 addr, uint32 word) -> void;
auto oam_read(uint mode, uint32 addr) -> uint32;
auto oam_write(uint mode, uint32 addr, uint32 word) -> void;
auto readOAM(uint mode, uint32 addr) -> uint32;
auto writeOAM(uint mode, uint32 addr, uint32 word) -> void;
auto render_backgrounds() -> void;
auto render_background_linear(Registers::Background&) -> void;
auto render_background_affine(Registers::Background&) -> void;
auto render_background_bitmap(Registers::Background&) -> void;
auto renderBackgrounds() -> void;
auto renderBackgroundLinear(Registers::Background&) -> void;
auto renderBackgroundAffine(Registers::Background&) -> void;
auto renderBackgroundBitmap(Registers::Background&) -> void;
auto render_objects() -> void;
auto render_object(Object&) -> void;
auto object_vram_read(uint addr) const -> uint8;
auto renderObjects() -> void;
auto renderObject(Object&) -> void;
auto readObjectVRAM(uint addr) const -> uint8;
auto render_mosaic_background(uint id) -> void;
auto render_mosaic_object() -> void;
auto renderMosaicBackground(uint id) -> void;
auto renderMosaicObject() -> void;
auto render_forceblank() -> void;
auto render_screen() -> void;
auto render_window(uint window) -> void;
auto renderForceBlank() -> void;
auto renderScreen() -> void;
auto renderWindow(uint window) -> void;
auto blend(uint above, uint eva, uint below, uint evb) -> uint;
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;
for(auto x : range(240)) line[x] = 0x7fff;
}
auto PPU::render_screen() -> void {
auto PPU::renderScreen() -> void {
uint32* line = output + regs.vcounter * 240;
if(regs.bg[0].control.mosaic) render_mosaic_background(BG0);
if(regs.bg[1].control.mosaic) render_mosaic_background(BG1);
if(regs.bg[2].control.mosaic) render_mosaic_background(BG2);
if(regs.bg[3].control.mosaic) render_mosaic_background(BG3);
render_mosaic_object();
if(regs.bg[0].control.mosaic) renderMosaicBackground(BG0);
if(regs.bg[1].control.mosaic) renderMosaicBackground(BG1);
if(regs.bg[2].control.mosaic) renderMosaicBackground(BG2);
if(regs.bg[3].control.mosaic) renderMosaicBackground(BG3);
renderMosaicObject();
for(auto x : range(240)) {
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 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,
};
struct BIOS : Memory {
struct BIOS {
BIOS();
~BIOS();
auto read(uint mode, uint32 addr) -> uint32 override;
auto write(uint mode, uint32 addr, uint32 word) -> void override;
auto read(uint mode, uint32 addr) -> uint32;
auto write(uint mode, uint32 addr, uint32 word) -> void;
uint8* data = nullptr;
uint size = 0;

View File

@ -26,21 +26,21 @@ auto ARM::power() -> void {
}
auto ARM::exec() -> void {
cpsr().t ? thumb_step() : arm_step();
cpsr().t ? stepTHUMB() : stepARM();
}
auto ARM::idle() -> void {
pipeline.nonsequential = true;
return busIdle();
return _idle();
}
auto ARM::read(unsigned mode, uint32 addr) -> uint32 {
return busRead(mode, addr);
auto ARM::read(uint mode, uint32 addr) -> uint32 {
return _read(mode, addr);
}
auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
auto ARM::load(uint mode, uint32 addr) -> uint32 {
pipeline.nonsequential = true;
uint32 word = busRead(Load | mode, addr);
uint32 word = _read(Load | mode, addr);
if(mode & Half) {
addr &= 1;
@ -62,18 +62,18 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
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;
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;
if(mode & Half) { word &= 0xffff; 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 {

View File

@ -7,7 +7,7 @@ namespace Processor {
//* ARMv4T (ARM7TDMI)
struct ARM {
enum : unsigned { //mode flags for bus_read, bus_write:
enum : uint { //mode flags for bus_read, bus_write:
Nonsequential = 1, //N cycle
Sequential = 2, //S cycle
Prefetch = 4, //instruction fetch (eligible for prefetch)
@ -24,19 +24,19 @@ struct ARM {
#include "instructions-thumb.hpp"
#include "disassembler.hpp"
virtual auto step(unsigned clocks) -> void = 0;
virtual auto busIdle() -> void = 0;
virtual auto busRead(unsigned mode, uint32 addr) -> uint32 = 0;
virtual auto busWrite(unsigned mode, uint32 addr, uint32 word) -> void = 0;
virtual auto step(uint clocks) -> void = 0;
virtual auto _idle() -> void = 0;
virtual auto _read(uint mode, uint32 addr) -> uint32 = 0;
virtual auto _write(uint mode, uint32 addr, uint32 word) -> void = 0;
//arm.cpp
auto power() -> void;
auto exec() -> void;
auto idle() -> void;
auto read(unsigned mode, uint32 addr) -> uint32;
auto load(unsigned mode, uint32 addr) -> uint32;
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
auto store(unsigned mode, uint32 addr, uint32 word) -> void;
auto read(uint mode, uint32 addr) -> uint32;
auto load(uint mode, uint32 addr) -> uint32;
auto write(uint mode, uint32 addr, uint32 word) -> void;
auto store(uint mode, uint32 addr, uint32 word) -> void;
auto vector(uint32 addr, Processor::Mode mode) -> void;
//algorithms.cpp
@ -52,9 +52,9 @@ struct ARM {
auto rrx(uint32 source) -> uint32;
//step.cpp
auto pipeline_step() -> void;
auto arm_step() -> void;
auto thumb_step() -> void;
auto stepPipeline() -> void;
auto stepARM() -> void;
auto stepTHUMB() -> void;
//serialization.cpp
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[] = {
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
@ -24,9 +24,9 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
"da", "ia", "db", "ib",
};
static auto is_move = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
static auto isMove = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
static auto isComp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
static auto isMath = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
string output{hex(pc, 8L), " "};
@ -272,13 +272,13 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(is_comp(opcode)) output.append(" ", registers[rn]);
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(isComp(opcode)) output.append(" ", registers[rn]);
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",", registers[rm]);
if(op == 0 && shift != 0) output.append(" lsl #", shift);
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
if(op == 2) output.append(" asr #", 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 : (uint)shift);
if(op == 3 && shift != 0) output.append(" ror #", shift);
if(op == 3 && shift == 0) output.append(" rrx");
@ -300,9 +300,9 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
uint4 rm = instruction;
output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
if(is_comp(opcode)) output.append(registers[rn], ",");
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
if(isComp(opcode)) output.append(registers[rn], ",");
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
output.append(registers[rm]);
if(mode == 0) output.append(" lsl ");
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)));
output.append(opcodes[opcode], conditions[condition]);
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(is_comp(opcode)) output.append(" ", registers[rn]);
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd]);
if(isComp(opcode)) output.append(" ", registers[rn]);
if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
output.append(",#0x", hex(rm, 8L));
return output;
@ -382,8 +382,8 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
if(pre == 0) output.append("]");
output.append(",", up ? "+" : "-", registers[rm]);
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
if(mode == 2) output.append(" asr #", 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 : (uint)shift);
if(mode == 3 && shift != 0) output.append(" ror #", shift);
if(mode == 3 && shift == 0) output.append(" rrx");
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(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.append("}", s ? "^" : "");
@ -438,7 +438,7 @@ auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
return output;
}
auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
auto ARM::disassembleInstructionTHUMB(uint32 pc) -> string {
static string conditions[] = {
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
@ -567,7 +567,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint3 rd = instruction >> 8;
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(" =0x", hex(read(Word | Nonsequential, rm), 8L));
@ -675,7 +675,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint8 list = instruction;
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(branch) output.append(load == 0 ? "lr," : "pc,");
@ -693,7 +693,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
uint8 list = instruction;
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], ",");
}
output.trimRight(",", 1L);
@ -759,7 +759,7 @@ auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
return output;
}
auto ARM::disassemble_registers() -> string {
auto ARM::disassembleRegisters() -> string {
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( "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 disassemble_thumb_instruction(uint32 pc) -> string;
auto disassemble_registers() -> string;
auto disassembleInstructionARM(uint32 pc) -> string;
auto disassembleInstructionTHUMB(uint32 pc) -> string;
auto disassembleRegisters() -> string;

View File

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

View File

@ -69,8 +69,8 @@ auto ARM::thumb_op_shift_immediate() {
switch(opcode) {
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 2: r(d) = bit(asr(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 : (uint)immediate)); break;
}
}
@ -142,7 +142,7 @@ auto ARM::thumb_op_load_literal() {
uint3 d = instruction() >> 8;
uint8 displacement = instruction();
unsigned rm = (r(15) & ~3) + displacement * 4;
uint rm = (r(15) & ~3) + displacement * 4;
r(d) = load(Word | Nonsequential, rm);
}
@ -273,8 +273,8 @@ auto ARM::thumb_op_stack_multiple() {
if(l == 1) sp = r(13);
if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4;
unsigned sequential = Nonsequential;
for(unsigned m = 0; m < 8; m++) {
uint sequential = Nonsequential;
for(uint m : range(8)) {
if(list & 1 << m) {
if(l == 1) r(m) = read(Word | sequential, sp); //POP
if(l == 0) write(Word | sequential, sp, r(m)); //PUSH
@ -310,7 +310,7 @@ auto ARM::thumb_op_move_multiple() {
uint8 list = instruction();
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(l == 1) r(m) = read(Word | Nonsequential, rn); //LDMIA
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 {
cpsr.m = 0x10 | (unsigned)mode;
cpsr.m = 0x10 | (uint)mode;
if(mode == Mode::FIQ) {
r[ 8] = &fiq.r8;

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ ICD2 icd2;
#if defined(SFC_SUPERGAMEBOY)
#include "interface.cpp"
#include "mmio.cpp"
#include "io.cpp"
#include "serialization.cpp"
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 inputPoll(uint port, uint device, uint id) -> int16 override;
//mmio.cpp
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
//io.cpp
auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void;
//serialization.cpp
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;
//LY counter
@ -38,7 +38,7 @@ auto ICD2::read(uint24 addr, uint8 data) -> uint8 {
return 0x00;
}
auto ICD2::write(uint24 addr, uint8 data) -> void {
auto ICD2::writeIO(uint24 addr, uint8 data) -> void {
addr &= 0xffff;
//VRAM port

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,7 +17,7 @@ struct PPU : Thread, PPUcounter {
auto serialize(serializer&) -> void;
//mmio.cpp
//io.cpp
alwaysinline auto getVramAddress() -> uint16;
alwaysinline auto vramAccessible() const -> bool;
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
if(execute("icarus", "--name").output.strip() == "icarus") {
libraryMenu.append(MenuSeparator());
libraryMenu.append(MenuItem().setText("Import ROM File ...").onActivate([&] {
libraryMenu.append(MenuItem().setText("Load ROM File ...").onActivate([&] {
audio->clear();
if(auto location = execute("icarus", "--import")) {
program->mediumQueue.append(location.output.strip());
program->loadMedium();
}
}));
libraryMenu.append(MenuItem().setText("Import ROM Files ...").onActivate([&] {