mirror of https://github.com/bsnes-emu/bsnes.git
Update to v097r16 release.
byuu says: Changelog: - sfc/ppu/sprite updated to use new .bit(s) functions; masked sizes better; added valid flags instead of using magic numbers - ws/ppu updates to use new .bit(s) functions - ws/ppu: added line compare interrupt support - added ws/eeprom; emulation of WS/WSC internal EEPROM and cartridge EEPROM (1kbit - 16kbit supported) - added basic read/write handlers for remaining WS/WSC PPU registers WS EEPROM emulation is basically a direct copy of trap15's code. Still some unknown areas in there, but hopefully it's enough to get further into games that depend on EEPROM support. Note that you'll have to manually add the eeprom line to the manifest for now, as icarus doesn't know how to detect EEPROM/sizes yet. I figured the changes to the SNES PPU sprites would slow it down a tad, but it actually sped it up. Most of the impact from the integer classes are gone now.
This commit is contained in:
parent
4b29f4bad7
commit
810cbdafb4
|
@ -0,0 +1,2 @@
|
||||||
|
higan/profile/WonderSwan.sys/internal.rom
|
||||||
|
higan/profile/WonderSwan Color.sys/internal.rom
|
|
@ -6,7 +6,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "097.15";
|
static const string Version = "097.16";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@ -17,8 +17,6 @@ namespace Emulator {
|
||||||
static const string Profile = "Balanced";
|
static const string Profile = "Balanced";
|
||||||
#elif defined(PROFILE_PERFORMANCE)
|
#elif defined(PROFILE_PERFORMANCE)
|
||||||
static const string Profile = "Performance";
|
static const string Profile = "Performance";
|
||||||
#else
|
|
||||||
static const string Profile = "Accuracy";
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
system name:WonderSwan Color
|
system name:WonderSwan Color
|
||||||
|
eeprom name=internal.rom size=2048
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
system name:WonderSwan
|
system name:WonderSwan
|
||||||
|
eeprom name=internal.rom size=128
|
||||||
|
|
|
@ -62,12 +62,12 @@ privileged:
|
||||||
friend class Video;
|
friend class Video;
|
||||||
|
|
||||||
struct Debugger {
|
struct Debugger {
|
||||||
hook<void (uint16, uint8)> vram_read;
|
hook<auto (uint16, uint8) -> void> vram_read;
|
||||||
hook<void (uint16, uint8)> oam_read;
|
hook<auto (uint16, uint8) -> void> oam_read;
|
||||||
hook<void (uint16, uint8)> cgram_read;
|
hook<auto (uint16, uint8) -> void> cgram_read;
|
||||||
hook<void (uint16, uint8)> vram_write;
|
hook<auto (uint16, uint8) -> void> vram_write;
|
||||||
hook<void (uint16, uint8)> oam_write;
|
hook<auto (uint16, uint8) -> void> oam_write;
|
||||||
hook<void (uint16, uint8)> cgram_write;
|
hook<auto (uint16, uint8) -> void> cgram_write;
|
||||||
} debugger;
|
} debugger;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -137,16 +137,16 @@ auto PPU::Background::serialize(serializer& s) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::serialize(serializer& s) -> void {
|
auto PPU::Sprite::serialize(serializer& s) -> void {
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(auto n : range(128)) {
|
||||||
s.integer(list[i].x);
|
s.integer(list[n].x);
|
||||||
s.integer(list[i].y);
|
s.integer(list[n].y);
|
||||||
s.integer(list[i].character);
|
s.integer(list[n].character);
|
||||||
s.integer(list[i].nameselect);
|
s.integer(list[n].nameselect);
|
||||||
s.integer(list[i].vflip);
|
s.integer(list[n].vflip);
|
||||||
s.integer(list[i].hflip);
|
s.integer(list[n].hflip);
|
||||||
s.integer(list[i].priority);
|
s.integer(list[n].priority);
|
||||||
s.integer(list[i].palette);
|
s.integer(list[n].palette);
|
||||||
s.integer(list[i].size);
|
s.integer(list[n].size);
|
||||||
}
|
}
|
||||||
|
|
||||||
s.integer(t.x);
|
s.integer(t.x);
|
||||||
|
@ -156,17 +156,21 @@ auto PPU::Sprite::serialize(serializer& s) -> void {
|
||||||
s.integer(t.tile_count);
|
s.integer(t.tile_count);
|
||||||
|
|
||||||
s.integer(t.active);
|
s.integer(t.active);
|
||||||
for(unsigned n = 0; n < 2; n++) {
|
for(auto p : range(2)) {
|
||||||
s.array(t.item[n]);
|
for(auto n : range(32)) {
|
||||||
for(unsigned i = 0; i < 34; i++) {
|
s.integer(t.item[p][n].valid);
|
||||||
s.integer(t.tile[n][i].x);
|
s.integer(t.item[p][n].index);
|
||||||
s.integer(t.tile[n][i].priority);
|
}
|
||||||
s.integer(t.tile[n][i].palette);
|
for(auto n : range(34)) {
|
||||||
s.integer(t.tile[n][i].hflip);
|
s.integer(t.tile[p][n].valid);
|
||||||
s.integer(t.tile[n][i].d0);
|
s.integer(t.tile[p][n].x);
|
||||||
s.integer(t.tile[n][i].d1);
|
s.integer(t.tile[p][n].priority);
|
||||||
s.integer(t.tile[n][i].d2);
|
s.integer(t.tile[p][n].palette);
|
||||||
s.integer(t.tile[n][i].d3);
|
s.integer(t.tile[p][n].hflip);
|
||||||
|
s.integer(t.tile[p][n].d0);
|
||||||
|
s.integer(t.tile[p][n].d1);
|
||||||
|
s.integer(t.tile[p][n].d2);
|
||||||
|
s.integer(t.tile[p][n].d3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
auto PPU::Sprite::update(uint addr, uint8 data) -> void {
|
auto PPU::Sprite::update(uint addr, uint8 data) -> void {
|
||||||
if(addr < 0x0200) {
|
if(addr < 0x0200) {
|
||||||
uint n = addr >> 2;
|
uint n = addr >> 2; //sprite#
|
||||||
addr &= 3;
|
addr &= 3;
|
||||||
if(addr == 0) {
|
if(addr == 0) {
|
||||||
list[n].x = (list[n].x & 0x100) | data;
|
list[n].x.bits(0,7) = data;
|
||||||
} else if(addr == 1) {
|
} else if(addr == 1) {
|
||||||
list[n].y = data;
|
list[n].y = data;
|
||||||
} else if(addr == 2) {
|
} else if(addr == 2) {
|
||||||
list[n].character = data;
|
list[n].character = data;
|
||||||
} else { //(addr == 3)
|
} else { //(addr == 3)
|
||||||
list[n].vflip = data & 0x80;
|
list[n].vflip = data.bit (7);
|
||||||
list[n].hflip = data & 0x40;
|
list[n].hflip = data.bit (6);
|
||||||
list[n].priority = (data >> 4) & 3;
|
list[n].priority = data.bits(5,4);
|
||||||
list[n].palette = (data >> 1) & 7;
|
list[n].palette = data.bits(3,1);
|
||||||
list[n].nameselect = data & 1;
|
list[n].nameselect = data.bit (0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint n = (addr & 0x1f) << 2;
|
uint n = (addr & 0x1f) << 2; //sprite#
|
||||||
list[n + 0].x = ((data & 0x01) << 8) | (list[n + 0].x & 0xff);
|
list[n + 0].x.bit(8) = data.bit(0);
|
||||||
list[n + 0].size = data & 0x02;
|
list[n + 0].size = data.bit(1);
|
||||||
list[n + 1].x = ((data & 0x04) << 6) | (list[n + 1].x & 0xff);
|
list[n + 1].x.bit(8) = data.bit(2);
|
||||||
list[n + 1].size = data & 0x08;
|
list[n + 1].size = data.bit(3);
|
||||||
list[n + 2].x = ((data & 0x10) << 4) | (list[n + 2].x & 0xff);
|
list[n + 2].x.bit(8) = data.bit(4);
|
||||||
list[n + 2].size = data & 0x20;
|
list[n + 2].size = data.bit(5);
|
||||||
list[n + 3].x = ((data & 0x40) << 2) | (list[n + 3].x & 0xff);
|
list[n + 3].x.bit(8) = data.bit(6);
|
||||||
list[n + 3].size = data & 0x80;
|
list[n + 3].size = data.bit(7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::synchronize() -> void {
|
auto PPU::Sprite::synchronize() -> void {
|
||||||
for(uint n = 0; n < 544; n++) update(n, ppu.oam[n]);
|
for(auto n : range(544)) update(n, ppu.oam[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::SpriteItem::width() const -> uint{
|
auto PPU::Sprite::Object::width() const -> uint{
|
||||||
if(size == 0) {
|
if(size == 0) {
|
||||||
static uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16};
|
static uint width[] = { 8, 8, 8, 16, 16, 32, 16, 16};
|
||||||
return width[ppu.sprite.regs.base_size];
|
return width[ppu.sprite.regs.base_size];
|
||||||
|
@ -42,7 +42,7 @@ auto PPU::Sprite::SpriteItem::width() const -> uint{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::SpriteItem::height() const -> uint {
|
auto PPU::Sprite::Object::height() const -> uint {
|
||||||
if(size == 0) {
|
if(size == 0) {
|
||||||
if(ppu.sprite.regs.interlace && ppu.sprite.regs.base_size >= 6) return 16;
|
if(ppu.sprite.regs.interlace && ppu.sprite.regs.base_size >= 6) return 16;
|
||||||
static uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32};
|
static uint height[] = { 8, 8, 8, 16, 16, 32, 32, 32};
|
||||||
|
|
|
@ -9,7 +9,7 @@ auto PPU::Sprite::address_reset() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::set_first_sprite() -> void {
|
auto PPU::Sprite::set_first_sprite() -> void {
|
||||||
regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);
|
regs.first_sprite = !self.regs.oam_priority ? 0 : self.regs.oam_addr >> 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::frame() -> void {
|
auto PPU::Sprite::frame() -> void {
|
||||||
|
@ -28,27 +28,27 @@ auto PPU::Sprite::scanline() -> void {
|
||||||
auto oam_item = t.item[t.active];
|
auto oam_item = t.item[t.active];
|
||||||
auto oam_tile = t.tile[t.active];
|
auto oam_tile = t.tile[t.active];
|
||||||
|
|
||||||
if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disable == false) address_reset();
|
if(t.y == (!self.regs.overscan ? 225 : 240) && !self.regs.display_disable) address_reset();
|
||||||
if(t.y >= (!self.regs.overscan ? 224 : 239)) return;
|
if(t.y >= (!self.regs.overscan ? 224 : 239)) return;
|
||||||
|
|
||||||
memset(oam_item, 0xff, 32); //default to invalid
|
for(auto n : range(32)) oam_item[n].valid = false; //default to invalid
|
||||||
for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid
|
for(auto n : range(34)) oam_tile[n].valid = false; //default to invalid
|
||||||
|
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(auto n : range(128)) {
|
||||||
unsigned sprite = (regs.first_sprite + i) & 127;
|
uint7 sprite = regs.first_sprite + n;
|
||||||
if(on_scanline(list[sprite]) == false) continue;
|
if(!on_scanline(list[sprite])) continue;
|
||||||
if(t.item_count++ >= 32) break;
|
if(t.item_count++ >= 32) break;
|
||||||
oam_item[t.item_count - 1] = sprite;
|
oam_item[t.item_count - 1] = {true, sprite};
|
||||||
}
|
}
|
||||||
|
|
||||||
if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) {
|
if(t.item_count > 0 && oam_item[t.item_count - 1].valid) {
|
||||||
ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2);
|
ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1].index >> 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::on_scanline(SpriteItem& sprite) -> bool {
|
auto PPU::Sprite::on_scanline(Object& sprite) -> bool {
|
||||||
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
|
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
|
||||||
signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1));
|
int height = sprite.height() >> regs.interlace;
|
||||||
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
|
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
|
||||||
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
||||||
return false;
|
return false;
|
||||||
|
@ -59,18 +59,18 @@ auto PPU::Sprite::run() -> void {
|
||||||
output.sub.priority = 0;
|
output.sub.priority = 0;
|
||||||
|
|
||||||
auto oam_tile = t.tile[!t.active];
|
auto oam_tile = t.tile[!t.active];
|
||||||
unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
|
uint priority_table[] = {regs.priority0, regs.priority1, regs.priority2, regs.priority3};
|
||||||
unsigned x = t.x++;
|
uint x = t.x++;
|
||||||
|
|
||||||
for(unsigned n = 0; n < 34; n++) {
|
for(auto n : range(34)) {
|
||||||
auto tile = oam_tile[n];
|
auto tile = oam_tile[n];
|
||||||
if(tile.x == 0xffff) break;
|
if(!tile.valid) break;
|
||||||
|
|
||||||
int px = x - sclip<9>(tile.x);
|
int px = x - sclip<9>(tile.x);
|
||||||
if(px & ~7) continue;
|
if(px & ~7) continue;
|
||||||
|
|
||||||
unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px);
|
uint mask = 0x80 >> (!tile.hflip ? px : 7 - px);
|
||||||
unsigned color;
|
uint color;
|
||||||
color = ((bool)(tile.d0 & mask)) << 0;
|
color = ((bool)(tile.d0 & mask)) << 0;
|
||||||
color |= ((bool)(tile.d1 & mask)) << 1;
|
color |= ((bool)(tile.d1 & mask)) << 1;
|
||||||
color |= ((bool)(tile.d2 & mask)) << 2;
|
color |= ((bool)(tile.d2 & mask)) << 2;
|
||||||
|
@ -94,13 +94,13 @@ auto PPU::Sprite::tilefetch() -> void {
|
||||||
auto oam_item = t.item[t.active];
|
auto oam_item = t.item[t.active];
|
||||||
auto oam_tile = t.tile[t.active];
|
auto oam_tile = t.tile[t.active];
|
||||||
|
|
||||||
for(signed i = 31; i >= 0; i--) {
|
for(int i = 31; i >= 0; i--) {
|
||||||
if(oam_item[i] == 0xff) continue;
|
if(!oam_item[i].valid) continue;
|
||||||
auto sprite = list[oam_item[i]];
|
auto sprite = list[oam_item[i].index];
|
||||||
|
|
||||||
unsigned tile_width = sprite.width() >> 3;
|
uint tile_width = sprite.width() >> 3;
|
||||||
signed x = sprite.x;
|
int x = sprite.x;
|
||||||
signed y = (t.y - sprite.y) & 0xff;
|
int y = (t.y - sprite.y) & 0xff;
|
||||||
if(regs.interlace) y <<= 1;
|
if(regs.interlace) y <<= 1;
|
||||||
|
|
||||||
if(sprite.vflip) {
|
if(sprite.vflip) {
|
||||||
|
@ -114,7 +114,7 @@ auto PPU::Sprite::tilefetch() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(regs.interlace) {
|
if(regs.interlace) {
|
||||||
y = (sprite.vflip == false ? y + self.field() : y - self.field());
|
y = !sprite.vflip ? y + self.field() : y - self.field();
|
||||||
}
|
}
|
||||||
|
|
||||||
x &= 511;
|
x &= 511;
|
||||||
|
@ -130,19 +130,20 @@ auto PPU::Sprite::tilefetch() -> void {
|
||||||
chry &= 15;
|
chry &= 15;
|
||||||
chry <<= 4;
|
chry <<= 4;
|
||||||
|
|
||||||
for(unsigned tx = 0; tx < tile_width; tx++) {
|
for(uint tx = 0; tx < tile_width; tx++) {
|
||||||
unsigned sx = (x + (tx << 3)) & 511;
|
uint sx = (x + (tx << 3)) & 511;
|
||||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||||
if(t.tile_count++ >= 34) break;
|
if(t.tile_count++ >= 34) break;
|
||||||
|
|
||||||
unsigned n = t.tile_count - 1;
|
uint n = t.tile_count - 1;
|
||||||
|
oam_tile[n].valid = true;
|
||||||
oam_tile[n].x = sx;
|
oam_tile[n].x = sx;
|
||||||
oam_tile[n].priority = sprite.priority;
|
oam_tile[n].priority = sprite.priority;
|
||||||
oam_tile[n].palette = 128 + (sprite.palette << 4);
|
oam_tile[n].palette = 128 + (sprite.palette << 4);
|
||||||
oam_tile[n].hflip = sprite.hflip;
|
oam_tile[n].hflip = sprite.hflip;
|
||||||
|
|
||||||
unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx);
|
uint mx = !sprite.hflip ? tx : (tile_width - 1) - tx;
|
||||||
unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
|
uint pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||||
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
|
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
|
||||||
|
|
||||||
oam_tile[n].d0 = ppu.vram[addr + 0];
|
oam_tile[n].d0 = ppu.vram[addr + 0];
|
||||||
|
@ -161,16 +162,16 @@ auto PPU::Sprite::tilefetch() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PPU::Sprite::reset() -> void {
|
auto PPU::Sprite::reset() -> void {
|
||||||
for(unsigned i = 0; i < 128; i++) {
|
for(auto n : range(128)) {
|
||||||
list[i].x = 0;
|
list[n].x = 0;
|
||||||
list[i].y = 0;
|
list[n].y = 0;
|
||||||
list[i].character = 0;
|
list[n].character = 0;
|
||||||
list[i].nameselect = 0;
|
list[n].nameselect = 0;
|
||||||
list[i].vflip = 0;
|
list[n].vflip = 0;
|
||||||
list[i].hflip = 0;
|
list[n].hflip = 0;
|
||||||
list[i].priority = 0;
|
list[n].priority = 0;
|
||||||
list[i].palette = 0;
|
list[n].palette = 0;
|
||||||
list[i].size = 0;
|
list[n].size = 0;
|
||||||
}
|
}
|
||||||
synchronize();
|
synchronize();
|
||||||
|
|
||||||
|
@ -181,17 +182,21 @@ auto PPU::Sprite::reset() -> void {
|
||||||
t.tile_count = 0;
|
t.tile_count = 0;
|
||||||
|
|
||||||
t.active = 0;
|
t.active = 0;
|
||||||
for(unsigned n = 0; n < 2; n++) {
|
for(auto p : range(2)) {
|
||||||
memset(t.item[n], 0, 32);
|
for(auto n : range(32)) {
|
||||||
for(unsigned i = 0; i < 34; i++) {
|
t.item[p][n].valid = false;
|
||||||
t.tile[n][i].x = 0;
|
t.item[p][n].index = 0;
|
||||||
t.tile[n][i].priority = 0;
|
}
|
||||||
t.tile[n][i].palette = 0;
|
for(auto n : range(34)) {
|
||||||
t.tile[n][i].hflip = 0;
|
t.tile[p][n].valid = false;
|
||||||
t.tile[n][i].d0 = 0;
|
t.tile[p][n].x = 0;
|
||||||
t.tile[n][i].d1 = 0;
|
t.tile[p][n].priority = 0;
|
||||||
t.tile[n][i].d2 = 0;
|
t.tile[p][n].palette = 0;
|
||||||
t.tile[n][i].d3 = 0;
|
t.tile[p][n].hflip = 0;
|
||||||
|
t.tile[p][n].d0 = 0;
|
||||||
|
t.tile[p][n].d1 = 0;
|
||||||
|
t.tile[p][n].d2 = 0;
|
||||||
|
t.tile[p][n].d3 = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,28 @@
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
struct SpriteItem {
|
struct Object {
|
||||||
uint16 x;
|
uint9 x;
|
||||||
uint16 y;
|
uint8 y;
|
||||||
uint8 character;
|
uint8 character;
|
||||||
bool nameselect;
|
bool nameselect;
|
||||||
bool vflip;
|
bool vflip;
|
||||||
bool hflip;
|
bool hflip;
|
||||||
uint8 priority;
|
uint2 priority;
|
||||||
uint8 palette;
|
uint3 palette;
|
||||||
bool size;
|
bool size;
|
||||||
alwaysinline auto width() const -> uint;
|
alwaysinline auto width() const -> uint;
|
||||||
alwaysinline auto height() const -> uint;
|
alwaysinline auto height() const -> uint;
|
||||||
} list[128];
|
} list[128];
|
||||||
|
|
||||||
struct TileItem {
|
struct Item {
|
||||||
uint16 x;
|
bool valid;
|
||||||
uint16 priority;
|
uint7 index;
|
||||||
uint16 palette;
|
};
|
||||||
|
|
||||||
|
struct Tile {
|
||||||
|
bool valid;
|
||||||
|
uint9 x;
|
||||||
|
uint2 priority;
|
||||||
|
uint8 palette;
|
||||||
bool hflip;
|
bool hflip;
|
||||||
uint8 d0, d1, d2, d3;
|
uint8 d0, d1, d2, d3;
|
||||||
};
|
};
|
||||||
|
@ -29,8 +35,8 @@ struct Sprite {
|
||||||
uint tile_count;
|
uint tile_count;
|
||||||
|
|
||||||
bool active;
|
bool active;
|
||||||
uint8 item[2][32];
|
Item item[2][32];
|
||||||
TileItem tile[2][34];
|
Tile tile[2][34];
|
||||||
} t;
|
} t;
|
||||||
|
|
||||||
struct Regs {
|
struct Regs {
|
||||||
|
@ -41,7 +47,7 @@ struct Sprite {
|
||||||
uint3 base_size;
|
uint3 base_size;
|
||||||
uint2 nameselect;
|
uint2 nameselect;
|
||||||
uint16 tiledata_addr;
|
uint16 tiledata_addr;
|
||||||
uint8 first_sprite;
|
uint7 first_sprite;
|
||||||
|
|
||||||
uint priority0;
|
uint priority0;
|
||||||
uint priority1;
|
uint priority1;
|
||||||
|
@ -54,7 +60,7 @@ struct Sprite {
|
||||||
|
|
||||||
struct Output {
|
struct Output {
|
||||||
struct Pixel {
|
struct Pixel {
|
||||||
uint priority; //0 = none (transparent)
|
uint2 priority; //0 = none (transparent)
|
||||||
uint8 palette;
|
uint8 palette;
|
||||||
} main, sub;
|
} main, sub;
|
||||||
} output;
|
} output;
|
||||||
|
@ -74,7 +80,7 @@ struct Sprite {
|
||||||
auto tilefetch() -> void;
|
auto tilefetch() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto on_scanline(SpriteItem&) -> bool;
|
auto on_scanline(Object&) -> bool;
|
||||||
|
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
ws_objects := ws-interface ws-system ws-scheduler
|
ws_objects := ws-interface ws-system ws-scheduler
|
||||||
ws_objects += ws-memory ws-cartridge
|
ws_objects += ws-memory ws-eeprom ws-cartridge
|
||||||
ws_objects += ws-cpu ws-ppu ws-apu
|
ws_objects += ws-cpu ws-ppu ws-apu
|
||||||
objects += $(ws_objects)
|
objects += $(ws_objects)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ obj/ws-interface.o: $(ws)/interface/interface.cpp $(call rwildcard,$(ws)/interfa
|
||||||
obj/ws-system.o: $(ws)/system/system.cpp $(call rwildcard,$(ws)/system/)
|
obj/ws-system.o: $(ws)/system/system.cpp $(call rwildcard,$(ws)/system/)
|
||||||
obj/ws-scheduler.o: $(ws)/scheduler/scheduler.cpp $(call rwildcard,$(ws)/scheduler/)
|
obj/ws-scheduler.o: $(ws)/scheduler/scheduler.cpp $(call rwildcard,$(ws)/scheduler/)
|
||||||
obj/ws-memory.o: $(ws)/memory/memory.cpp $(call rwildcard,$(ws)/memory/)
|
obj/ws-memory.o: $(ws)/memory/memory.cpp $(call rwildcard,$(ws)/memory/)
|
||||||
|
obj/ws-eeprom.o: $(ws)/eeprom/eeprom.cpp $(call rwildcard,$(ws)/eeprom/)
|
||||||
obj/ws-cartridge.o: $(ws)/cartridge/cartridge.cpp $(call rwildcard,$(ws)/cartridge/)
|
obj/ws-cartridge.o: $(ws)/cartridge/cartridge.cpp $(call rwildcard,$(ws)/cartridge/)
|
||||||
obj/ws-cpu.o: $(ws)/cpu/cpu.cpp $(call rwildcard,$(ws)/cpu/)
|
obj/ws-cpu.o: $(ws)/cpu/cpu.cpp $(call rwildcard,$(ws)/cpu/)
|
||||||
obj/ws-ppu.o: $(ws)/ppu/ppu.cpp $(call rwildcard,$(ws)/ppu/)
|
obj/ws-ppu.o: $(ws)/ppu/ppu.cpp $(call rwildcard,$(ws)/ppu/)
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace WonderSwan {
|
||||||
|
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
#include "memory.cpp"
|
#include "memory.cpp"
|
||||||
|
#include "io.cpp"
|
||||||
|
|
||||||
auto Cartridge::load() -> void {
|
auto Cartridge::load() -> void {
|
||||||
information.manifest = "";
|
information.manifest = "";
|
||||||
|
@ -26,7 +27,14 @@ auto Cartridge::load() -> void {
|
||||||
ram.size = node["size"].natural();
|
ram.size = node["size"].natural();
|
||||||
ram.mask = bit::round(ram.size) - 1;
|
ram.mask = bit::round(ram.size) - 1;
|
||||||
if(ram.size) ram.data = new uint8[ram.mask + 1]();
|
if(ram.size) ram.data = new uint8[ram.mask + 1]();
|
||||||
if(ram.name) interface->loadRequest(ID::RAM, ram.name, true);
|
if(ram.name) interface->loadRequest(ID::RAM, ram.name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto node = document["board/eeprom"]) {
|
||||||
|
eeprom.setName(node["name"].text());
|
||||||
|
eeprom.setSize(node["size"].natural() / sizeof(uint16));
|
||||||
|
eeprom.erase();
|
||||||
|
if(eeprom.name()) interface->loadRequest(ID::EEPROM, eeprom.name(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
information.title = document["information/title"].text();
|
information.title = document["information/title"].text();
|
||||||
|
@ -48,10 +56,9 @@ auto Cartridge::unload() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::power() -> void {
|
auto Cartridge::power() -> void {
|
||||||
iomap[0x00c0] = this;
|
eeprom.power();
|
||||||
iomap[0x00c1] = this;
|
|
||||||
iomap[0x00c2] = this;
|
for(uint n = 0x00c0; n <= 0x00c8; n++) iomap[n] = this;
|
||||||
iomap[0x00c3] = this;
|
|
||||||
|
|
||||||
r.bank_rom0 = 0xff;
|
r.bank_rom0 = 0xff;
|
||||||
r.bank_rom1 = 0xff;
|
r.bank_rom1 = 0xff;
|
||||||
|
|
|
@ -26,6 +26,8 @@ struct Cartridge : IO {
|
||||||
string name;
|
string name;
|
||||||
} rom, ram;
|
} rom, ram;
|
||||||
|
|
||||||
|
EEPROM eeprom;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string manifest;
|
string manifest;
|
||||||
string title;
|
string title;
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
auto Cartridge::portRead(uint16 addr) -> uint8 {
|
||||||
|
//BANK_ROM2
|
||||||
|
if(addr == 0x00c0) return r.bank_rom2;
|
||||||
|
|
||||||
|
//BANK_SRAM
|
||||||
|
if(addr == 0x00c1) return r.bank_sram;
|
||||||
|
|
||||||
|
//BANK_ROM0
|
||||||
|
if(addr == 0x00c2) return r.bank_rom0;
|
||||||
|
|
||||||
|
//BANK_ROM1
|
||||||
|
if(addr == 0x00c3) return r.bank_rom1;
|
||||||
|
|
||||||
|
//EEP_DATA
|
||||||
|
if(addr == 0x00c4) return eeprom.read(EEPROM::DataLo);
|
||||||
|
if(addr == 0x00c5) return eeprom.read(EEPROM::DataHi);
|
||||||
|
|
||||||
|
//EEP_ADDR
|
||||||
|
if(addr == 0x00c6) return eeprom.read(EEPROM::AddressLo);
|
||||||
|
if(addr == 0x00c7) return eeprom.read(EEPROM::AddressHi);
|
||||||
|
|
||||||
|
//EEP_STATUS
|
||||||
|
if(addr == 0x00c8) return eeprom.read(EEPROM::Status);
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
|
//BANK_ROM2
|
||||||
|
if(addr == 0x00c0) {
|
||||||
|
r.bank_rom2 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//BANK_SRAM
|
||||||
|
if(addr == 0x00c1) {
|
||||||
|
r.bank_sram = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//BANK_ROM0
|
||||||
|
if(addr == 0x00c2) {
|
||||||
|
r.bank_rom0 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//BANK_ROM1
|
||||||
|
if(addr == 0x00c3) {
|
||||||
|
r.bank_rom1 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//EEP_DATA
|
||||||
|
if(addr == 0x00c4) return eeprom.write(EEPROM::DataLo, data);
|
||||||
|
if(addr == 0x00c5) return eeprom.write(EEPROM::DataHi, data);
|
||||||
|
|
||||||
|
//EEP_ADDR
|
||||||
|
if(addr == 0x00c6) return eeprom.write(EEPROM::AddressLo, data);
|
||||||
|
if(addr == 0x00c7) return eeprom.write(EEPROM::AddressHi, data);
|
||||||
|
|
||||||
|
//EEP_CMD
|
||||||
|
if(addr == 0x00c8) return eeprom.write(EEPROM::Command, data);
|
||||||
|
}
|
|
@ -24,45 +24,3 @@ auto Cartridge::ramWrite(uint addr, uint8 data) -> void {
|
||||||
if(!ram.data) return;
|
if(!ram.data) return;
|
||||||
ram.data[addr & ram.mask] = data;
|
ram.data[addr & ram.mask] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::portRead(uint16 addr) -> uint8 {
|
|
||||||
if(addr == 0x00c0) {
|
|
||||||
return r.bank_rom2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c1) {
|
|
||||||
return r.bank_sram;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c2) {
|
|
||||||
return r.bank_rom0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c3) {
|
|
||||||
return r.bank_rom1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0x00;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::portWrite(uint16 addr, uint8 data) -> void {
|
|
||||||
if(addr == 0x00c0) {
|
|
||||||
r.bank_rom2 = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c1) {
|
|
||||||
r.bank_sram = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c2) {
|
|
||||||
r.bank_rom0 = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(addr == 0x00c3) {
|
|
||||||
r.bank_rom1 = data;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
#include <ws/ws.hpp>
|
||||||
|
|
||||||
|
namespace WonderSwan {
|
||||||
|
|
||||||
|
auto EEPROM::name() const -> string { return _name; }
|
||||||
|
auto EEPROM::data() -> uint16* { return _data; }
|
||||||
|
auto EEPROM::size() const -> uint { return _size; }
|
||||||
|
|
||||||
|
auto EEPROM::setName(string name) -> void {
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::setSize(uint size) -> void {
|
||||||
|
_size = bit::round(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::erase() -> void {
|
||||||
|
for(auto& word : _data) word = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::power() -> void {
|
||||||
|
r.latch = 0;
|
||||||
|
r.address = 0;
|
||||||
|
r.unknown = false;
|
||||||
|
r.writeRequested = false;
|
||||||
|
r.readRequested = false;
|
||||||
|
r.writeCompleted = false;
|
||||||
|
r.readCompleted = false;
|
||||||
|
r.writeProtect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::read(uint port) -> uint8 {
|
||||||
|
if(!_size) return 0x00;
|
||||||
|
|
||||||
|
if(port == DataLo) return r.latch.byte(0);
|
||||||
|
if(port == DataHi) return r.latch.byte(1);
|
||||||
|
|
||||||
|
if(port == AddressLo) return r.address.byte(0);
|
||||||
|
if(port == AddressHi) return r.address.byte(1);
|
||||||
|
|
||||||
|
if(port == Status) return (
|
||||||
|
1 << 7
|
||||||
|
| r.unknown << 6
|
||||||
|
| r.writeRequested << 5
|
||||||
|
| r.readRequested << 4
|
||||||
|
| r.writeCompleted << 1
|
||||||
|
| r.readCompleted << 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::write(uint port, uint8 data) -> void {
|
||||||
|
if(!_size) return;
|
||||||
|
|
||||||
|
if(port == DataLo) {
|
||||||
|
r.latch.byte(0) = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == DataHi) {
|
||||||
|
r.latch.byte(1) = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == AddressLo) {
|
||||||
|
r.address.byte(0) = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == AddressHi) {
|
||||||
|
r.address.byte(1) = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == Command) {
|
||||||
|
r.unknown = data.bit(6);
|
||||||
|
r.writeRequested = data.bit(5);
|
||||||
|
r.readRequested = data.bit(4);
|
||||||
|
execute();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto EEPROM::execute() -> void {
|
||||||
|
auto bits = bit::first(_size);
|
||||||
|
auto address = r.address.bits(0, bits - 1);
|
||||||
|
auto special = r.address.bits(bits - 2, bits - 1);
|
||||||
|
auto command = r.address.bits(bits, bits + 1);
|
||||||
|
auto start = r.address.bit(bits + 2);
|
||||||
|
if(!start) return;
|
||||||
|
|
||||||
|
//write disable
|
||||||
|
if(command == 0 && special == 0) {
|
||||||
|
r.writeProtect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//write all
|
||||||
|
if(command == 0 && special == 1 && !r.writeProtect) {
|
||||||
|
for(auto n : range(_size)) _data[n] = r.latch;
|
||||||
|
}
|
||||||
|
|
||||||
|
//erase all
|
||||||
|
if(command == 0 && special == 2 && !r.writeProtect) {
|
||||||
|
for(auto n : range(_size)) _data[n] = 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//write enable
|
||||||
|
if(command == 0 && special == 3) {
|
||||||
|
r.writeProtect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//write word
|
||||||
|
if(command == 1 && r.writeRequested && !r.writeProtect) {
|
||||||
|
_data[address] = r.latch;
|
||||||
|
r.writeRequested = false;
|
||||||
|
r.writeCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read word
|
||||||
|
if(command == 2 && r.readRequested) {
|
||||||
|
r.latch = _data[address];
|
||||||
|
r.readRequested = false;
|
||||||
|
r.readCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//erase word
|
||||||
|
if(command == 3 && r.writeRequested && !r.writeProtect) {
|
||||||
|
_data[address] = 0xffff;
|
||||||
|
r.writeRequested = false;
|
||||||
|
r.writeCompleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
//93LC46 ( 64x16-bit) [ 128 bytes]
|
||||||
|
//93LC56 ( 128x16-bit) [ 256 bytes]
|
||||||
|
//93LC66 ( 256x16-bit) [ 512 bytes]
|
||||||
|
//93LC76 ( 512x16-bit) [1024 bytes]
|
||||||
|
//93LC86 (1024x16-bit) [2048 bytes]
|
||||||
|
|
||||||
|
struct EEPROM {
|
||||||
|
enum : uint {
|
||||||
|
DataLo,
|
||||||
|
DataHi,
|
||||||
|
AddressLo,
|
||||||
|
AddressHi,
|
||||||
|
Status,
|
||||||
|
Command = Status,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto name() const -> string;
|
||||||
|
auto data() -> uint16*;
|
||||||
|
auto size() const -> uint;
|
||||||
|
|
||||||
|
auto setName(string name) -> void;
|
||||||
|
auto setSize(uint size) -> void;
|
||||||
|
|
||||||
|
auto erase() -> void;
|
||||||
|
auto power() -> void;
|
||||||
|
auto read(uint) -> uint8;
|
||||||
|
auto write(uint, uint8) -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto execute() -> void;
|
||||||
|
|
||||||
|
string _name;
|
||||||
|
uint16 _data[1024];
|
||||||
|
uint _size = 0; //in words
|
||||||
|
|
||||||
|
struct Registers {
|
||||||
|
uint16 latch;
|
||||||
|
uint16 address;
|
||||||
|
|
||||||
|
bool unknown;
|
||||||
|
bool writeRequested;
|
||||||
|
bool readRequested;
|
||||||
|
|
||||||
|
bool writeCompleted;
|
||||||
|
bool readCompleted;
|
||||||
|
|
||||||
|
bool writeProtect;
|
||||||
|
} r;
|
||||||
|
};
|
|
@ -85,10 +85,13 @@ auto Interface::sha256() -> string {
|
||||||
auto Interface::group(uint id) -> uint {
|
auto Interface::group(uint id) -> uint {
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case ID::SystemManifest:
|
case ID::SystemManifest:
|
||||||
|
case ID::SystemIPLROM:
|
||||||
|
case ID::SystemEEPROM:
|
||||||
return 0;
|
return 0;
|
||||||
case ID::Manifest:
|
case ID::Manifest:
|
||||||
case ID::ROM:
|
case ID::ROM:
|
||||||
case ID::RAM:
|
case ID::RAM:
|
||||||
|
case ID::EEPROM:
|
||||||
switch(system.revision()) {
|
switch(system.revision()) {
|
||||||
case System::Revision::WonderSwan:
|
case System::Revision::WonderSwan:
|
||||||
return ID::WonderSwan;
|
return ID::WonderSwan;
|
||||||
|
@ -106,7 +109,9 @@ auto Interface::load(uint id) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
auto Interface::save() -> void {
|
||||||
if(cartridge.ram.name) interface->saveRequest(ID::RAM, cartridge.ram.name);
|
if(auto name = system.eeprom.name()) interface->saveRequest(ID::SystemEEPROM, name);
|
||||||
|
if(auto name = cartridge.ram.name) interface->saveRequest(ID::RAM, name);
|
||||||
|
if(auto name = cartridge.eeprom.name()) interface->saveRequest(ID::EEPROM, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id, const stream& stream) -> void {
|
auto Interface::load(uint id, const stream& stream) -> void {
|
||||||
|
@ -114,6 +119,10 @@ auto Interface::load(uint id, const stream& stream) -> void {
|
||||||
system.information.manifest = stream.text();
|
system.information.manifest = stream.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(id == ID::SystemEEPROM) {
|
||||||
|
stream.read((uint8_t*)system.eeprom.data(), min(system.eeprom.size() * sizeof(uint16), stream.size()));
|
||||||
|
}
|
||||||
|
|
||||||
if(id == ID::Manifest) {
|
if(id == ID::Manifest) {
|
||||||
cartridge.information.manifest = stream.text();
|
cartridge.information.manifest = stream.text();
|
||||||
}
|
}
|
||||||
|
@ -125,12 +134,24 @@ auto Interface::load(uint id, const stream& stream) -> void {
|
||||||
if(id == ID::RAM) {
|
if(id == ID::RAM) {
|
||||||
stream.read((uint8_t*)cartridge.ram.data, min(cartridge.ram.size, stream.size()));
|
stream.read((uint8_t*)cartridge.ram.data, min(cartridge.ram.size, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(id == ID::EEPROM) {
|
||||||
|
stream.read((uint8_t*)cartridge.eeprom.data(), min(cartridge.eeprom.size() * sizeof(uint16), stream.size()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save(uint id, const stream& stream) -> void {
|
auto Interface::save(uint id, const stream& stream) -> void {
|
||||||
|
if(id == ID::SystemEEPROM) {
|
||||||
|
stream.write((uint8_t*)system.eeprom.data(), system.eeprom.size() * sizeof(uint16));
|
||||||
|
}
|
||||||
|
|
||||||
if(id == ID::RAM) {
|
if(id == ID::RAM) {
|
||||||
stream.write((uint8_t*)cartridge.ram.data, cartridge.ram.size);
|
stream.write((uint8_t*)cartridge.ram.data, cartridge.ram.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(id == ID::EEPROM) {
|
||||||
|
stream.write((uint8_t*)cartridge.eeprom.data(), cartridge.eeprom.size() * sizeof(uint16));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::unload() -> void {
|
auto Interface::unload() -> void {
|
||||||
|
|
|
@ -9,10 +9,13 @@ struct ID {
|
||||||
|
|
||||||
enum : uint {
|
enum : uint {
|
||||||
SystemManifest,
|
SystemManifest,
|
||||||
|
SystemIPLROM,
|
||||||
|
SystemEEPROM,
|
||||||
|
|
||||||
Manifest,
|
Manifest,
|
||||||
ROM,
|
ROM,
|
||||||
RAM,
|
RAM,
|
||||||
|
EEPROM,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : uint {
|
enum : uint {
|
||||||
|
|
|
@ -14,6 +14,12 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
||||||
//BACK_COLOR
|
//BACK_COLOR
|
||||||
if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0;
|
if(addr == 0x0001) return r.backColorPalette << 4 | r.backColorIndex << 0;
|
||||||
|
|
||||||
|
//LINE_CUR
|
||||||
|
if(addr == 0x0002) return status.vclk;
|
||||||
|
|
||||||
|
//LINE_CMP
|
||||||
|
if(addr == 0x0003) return r.lineCompare;
|
||||||
|
|
||||||
//SPR_BASE
|
//SPR_BASE
|
||||||
if(addr == 0x0004) return r.spriteBase;
|
if(addr == 0x0004) return r.spriteBase;
|
||||||
|
|
||||||
|
@ -26,6 +32,30 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
||||||
//MAP_BASE
|
//MAP_BASE
|
||||||
if(addr == 0x0007) return r.screenTwoMapBase << 4 | r.screenOneMapBase << 0;
|
if(addr == 0x0007) return r.screenTwoMapBase << 4 | r.screenOneMapBase << 0;
|
||||||
|
|
||||||
|
//SCR2_WIN_X0
|
||||||
|
if(addr == 0x0008) return r.screenTwoWindowX0;
|
||||||
|
|
||||||
|
//SCR2_WIN_Y0
|
||||||
|
if(addr == 0x0009) return r.screenTwoWindowY0;
|
||||||
|
|
||||||
|
//SCR2_WIN_X1
|
||||||
|
if(addr == 0x000a) return r.screenTwoWindowX1;
|
||||||
|
|
||||||
|
//SCR2_WIN_Y1
|
||||||
|
if(addr == 0x000b) return r.screenTwoWindowY1;
|
||||||
|
|
||||||
|
//SPR_WIN_X0
|
||||||
|
if(addr == 0x000c) return r.spriteWindowX0;
|
||||||
|
|
||||||
|
//SPR_WIN_Y0
|
||||||
|
if(addr == 0x000d) return r.spriteWindowY0;
|
||||||
|
|
||||||
|
//SPR_WIN_X1
|
||||||
|
if(addr == 0x000e) return r.spriteWindowX1;
|
||||||
|
|
||||||
|
//SPR_WIN_Y1
|
||||||
|
if(addr == 0x000f) return r.spriteWindowY1;
|
||||||
|
|
||||||
//SCR1_X
|
//SCR1_X
|
||||||
if(addr == 0x0010) return r.scrollOneX;
|
if(addr == 0x0010) return r.scrollOneX;
|
||||||
|
|
||||||
|
@ -53,17 +83,27 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_0
|
//LCD_VTOTAL
|
||||||
if(addr == 0x001c) return r.monoPool[0] << 0 | r.monoPool[1] << 4;
|
if(addr == 0x0016) return r.vtotal;
|
||||||
|
|
||||||
//PALMONO_POOL_1
|
//LCD_VBLANK
|
||||||
if(addr == 0x001d) return r.monoPool[2] << 0 | r.monoPool[3] << 4;
|
if(addr == 0x0017) return r.vblank;
|
||||||
|
|
||||||
//PALMONO_POOL_2
|
//PALMONO_POOL
|
||||||
if(addr == 0x001e) return r.monoPool[4] << 0 | r.monoPool[5] << 4;
|
if(addr >= 0x001c && addr <= 0x001f) {
|
||||||
|
return (
|
||||||
|
r.pool[addr.bits(1,0) * 2 + 1] << 4
|
||||||
|
| r.pool[addr.bits(1,0) * 2 + 0] << 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_3
|
//PALMONO
|
||||||
if(addr == 0x001f) return r.monoPool[6] << 0 | r.monoPool[7] << 4;
|
if(addr >= 0x0020 && addr <= 0x003f) {
|
||||||
|
return (
|
||||||
|
r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 1] << 4
|
||||||
|
| r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 0] << 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//DISP_MODE
|
//DISP_MODE
|
||||||
if(addr == 0x0060) {
|
if(addr == 0x0060) {
|
||||||
|
@ -81,12 +121,12 @@ auto PPU::portRead(uint16 addr) -> uint8 {
|
||||||
auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
//DISP_CTRL
|
//DISP_CTRL
|
||||||
if(addr == 0x0000) {
|
if(addr == 0x0000) {
|
||||||
r.screenTwoWindowEnable = data & 0x20;
|
r.screenTwoWindowEnable = data.bit(5);
|
||||||
r.screenTwoWindowMode = data & 0x10;
|
r.screenTwoWindowMode = data.bit(4);
|
||||||
r.spriteWindowEnable = data & 0x08;
|
r.spriteWindowEnable = data.bit(3);
|
||||||
r.spriteEnable = data & 0x04;
|
r.spriteEnable = data.bit(2);
|
||||||
r.screenTwoEnable = data & 0x02;
|
r.screenTwoEnable = data.bit(1);
|
||||||
r.screenOneEnable = data & 0x01;
|
r.screenOneEnable = data.bit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,48 +134,102 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
if(addr == 0x0001) {
|
if(addr == 0x0001) {
|
||||||
if(WS()) {
|
if(WS()) {
|
||||||
r.backColorPalette = 0;
|
r.backColorPalette = 0;
|
||||||
r.backColorIndex = (uint3)(data >> 0);
|
r.backColorIndex = data.bits(2,0);
|
||||||
} else {
|
} else {
|
||||||
r.backColorPalette = (uint4)(data >> 4);
|
r.backColorPalette = data.bits(7,4);
|
||||||
r.backColorIndex = (uint4)(data >> 0);
|
r.backColorIndex = data.bits(3,0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//LINE_CMP
|
||||||
|
if(addr == 0x0003) {
|
||||||
|
r.lineCompare = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//SPR_BASE
|
//SPR_BASE
|
||||||
if(addr == 0x0004) {
|
if(addr == 0x0004) {
|
||||||
if(WS()) {
|
if(WS()) {
|
||||||
r.spriteBase = (uint5)data;
|
r.spriteBase = data.bits(4,0);
|
||||||
} else {
|
} else {
|
||||||
r.spriteBase = (uint6)data;
|
r.spriteBase = data.bits(5,0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SPR_FIRST
|
//SPR_FIRST
|
||||||
if(addr == 0x0005) {
|
if(addr == 0x0005) {
|
||||||
r.spriteFirst = data;
|
r.spriteFirst = data.bits(6,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//SPR_COUNT
|
//SPR_COUNT
|
||||||
if(addr == 0x0006) {
|
if(addr == 0x0006) {
|
||||||
r.spriteCount = data;
|
r.spriteCount = data; //0 - 128
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//MAP_BASE
|
//MAP_BASE
|
||||||
if(addr == 0x0007) {
|
if(addr == 0x0007) {
|
||||||
if(WS()) {
|
if(WS()) {
|
||||||
r.screenTwoMapBase = (uint3)(data >> 4);
|
r.screenTwoMapBase = data.bits(6,4);
|
||||||
r.screenOneMapBase = (uint3)(data >> 0);
|
r.screenOneMapBase = data.bits(2,0);
|
||||||
} else {
|
} else {
|
||||||
r.screenTwoMapBase = (uint4)(data >> 4);
|
r.screenTwoMapBase = data.bits(7,4);
|
||||||
r.screenOneMapBase = (uint4)(data >> 0);
|
r.screenOneMapBase = data.bits(3,0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//SCR2_WIN_X0
|
||||||
|
if(addr == 0x0008) {
|
||||||
|
r.screenTwoWindowX0 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SCR2_WIN_Y0
|
||||||
|
if(addr == 0x0009) {
|
||||||
|
r.screenTwoWindowY0 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SCR2_WIN_X1
|
||||||
|
if(addr == 0x000a) {
|
||||||
|
r.screenTwoWindowX1 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SCR2_WIN_Y1
|
||||||
|
if(addr == 0x000b) {
|
||||||
|
r.screenTwoWindowY1 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPR_WIN_X0
|
||||||
|
if(addr == 0x000c) {
|
||||||
|
r.spriteWindowX0 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPR_WIN_Y0
|
||||||
|
if(addr == 0x000d) {
|
||||||
|
r.spriteWindowY0 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPR_WIN_X1
|
||||||
|
if(addr == 0x000e) {
|
||||||
|
r.spriteWindowX1 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPR_WIN_Y1
|
||||||
|
if(addr == 0x000f) {
|
||||||
|
r.spriteWindowY1 = data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//SCR1_X
|
//SCR1_X
|
||||||
if(addr == 0x0010) {
|
if(addr == 0x0010) {
|
||||||
r.scrollOneX = data;
|
r.scrollOneX = data;
|
||||||
|
@ -168,48 +262,46 @@ auto PPU::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
|
|
||||||
//LCD_ICON
|
//LCD_ICON
|
||||||
if(addr == 0x0015) {
|
if(addr == 0x0015) {
|
||||||
r.iconAux3 = data & 0x20;
|
r.iconAux3 = data.bit(5);
|
||||||
r.iconAux2 = data & 0x10;
|
r.iconAux2 = data.bit(4);
|
||||||
r.iconAux1 = data & 0x08;
|
r.iconAux1 = data.bit(3);
|
||||||
r.iconHorizontal = data & 0x04;
|
r.iconHorizontal = data.bit(2);
|
||||||
r.iconVertical = data & 0x02;
|
r.iconVertical = data.bit(1);
|
||||||
r.iconSleep = data & 0x01;
|
r.iconSleep = data.bit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_0
|
//LCD_VTOTAL
|
||||||
if(addr == 0x001c) {
|
if(addr == 0x0016) {
|
||||||
r.monoPool[0] = data >> 0;
|
r.vtotal = data;
|
||||||
r.monoPool[1] = data >> 4;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_1
|
//LCD_VBLANK
|
||||||
if(addr == 0x001d) {
|
if(addr == 0x0017) {
|
||||||
r.monoPool[2] = data >> 0;
|
r.vblank = data;
|
||||||
r.monoPool[3] = data >> 4;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_2
|
//PALMONO_POOL
|
||||||
if(addr == 0x001e) {
|
if(addr >= 0x001c && addr <= 0x001f) {
|
||||||
r.monoPool[4] = data >> 0;
|
r.pool[addr.bits(1,0) * 2 + 1] = data.bits(7,4);
|
||||||
r.monoPool[5] = data >> 4;
|
r.pool[addr.bits(1,0) * 2 + 0] = data.bits(3,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//PALMONO_POOL_3
|
//PALMONO
|
||||||
if(addr == 0x001f) {
|
if(addr >= 0x0020 && addr <= 0x003f) {
|
||||||
r.monoPool[6] = data >> 0;
|
r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 1] = data.bits(6,4);
|
||||||
r.monoPool[7] = data >> 4;
|
r.palette[addr.bits(3,1)].color[addr.bit(0) * 2 + 0] = data.bits(2,0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//DISP_MODE
|
//DISP_MODE
|
||||||
if(addr == 0x0060) {
|
if(addr == 0x0060) {
|
||||||
r.bpp = data & 0x80;
|
r.bpp = data.bit(7);
|
||||||
r.color = data & 0x40;
|
r.color = data.bit(6);
|
||||||
r.format = data & 0x20;
|
r.format = data.bit(5);
|
||||||
r.u0060 = data & 0b1011;
|
r.u0060 = data & 0b1011;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@ auto PPU::main() -> void {
|
||||||
auto PPU::scanline() -> void {
|
auto PPU::scanline() -> void {
|
||||||
status.hclk = 0;
|
status.hclk = 0;
|
||||||
status.vclk++;
|
status.vclk++;
|
||||||
|
if(status.vclk == r.lineCompare) {
|
||||||
|
cpu.raise(CPU::Interrupt::LineCompare);
|
||||||
|
}
|
||||||
if(status.vclk == 144) {
|
if(status.vclk == 144) {
|
||||||
cpu.raise(CPU::Interrupt::Vblank);
|
cpu.raise(CPU::Interrupt::Vblank);
|
||||||
}
|
}
|
||||||
|
@ -40,10 +43,8 @@ auto PPU::step(uint clocks) -> void {
|
||||||
auto PPU::power() -> void {
|
auto PPU::power() -> void {
|
||||||
create(PPU::Enter, 3'072'000);
|
create(PPU::Enter, 3'072'000);
|
||||||
|
|
||||||
for(uint n = 0x0000; n <= 0x0001; n++) iomap[n] = this;
|
for(uint n = 0x0000; n <= 0x0017; n++) iomap[n] = this;
|
||||||
for(uint n = 0x0004; n <= 0x0007; n++) iomap[n] = this;
|
for(uint n = 0x001c; n <= 0x003f; n++) iomap[n] = this;
|
||||||
for(uint n = 0x0010; n <= 0x0015; n++) iomap[n] = this;
|
|
||||||
for(uint n = 0x001c; n <= 0x001f; n++) iomap[n] = this;
|
|
||||||
iomap[0x0060] = this;
|
iomap[0x0060] = this;
|
||||||
|
|
||||||
for(auto& n : output) n = 0;
|
for(auto& n : output) n = 0;
|
||||||
|
@ -51,6 +52,8 @@ auto PPU::power() -> void {
|
||||||
status.vclk = 0;
|
status.vclk = 0;
|
||||||
status.hclk = 0;
|
status.hclk = 0;
|
||||||
|
|
||||||
|
r.lineCompare = 0xff;
|
||||||
|
|
||||||
video.power();
|
video.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct PPU : Thread, IO {
|
||||||
auto portRead(uint16 addr) -> uint8 override;
|
auto portRead(uint16 addr) -> uint8 override;
|
||||||
auto portWrite(uint16 addr, uint8 data) -> void override;
|
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
uint16_t output[224 * 144] = {0};
|
uint16 output[224 * 144];
|
||||||
|
|
||||||
struct Status {
|
struct Status {
|
||||||
uint vclk;
|
uint vclk;
|
||||||
|
@ -31,6 +31,9 @@ struct PPU : Thread, IO {
|
||||||
uint4 backColorIndex;
|
uint4 backColorIndex;
|
||||||
uint4 backColorPalette;
|
uint4 backColorPalette;
|
||||||
|
|
||||||
|
//$0003 LINE_CMP
|
||||||
|
uint8 lineCompare;
|
||||||
|
|
||||||
//$0004 SPR_BASE
|
//$0004 SPR_BASE
|
||||||
uint6 spriteBase;
|
uint6 spriteBase;
|
||||||
|
|
||||||
|
@ -44,6 +47,30 @@ struct PPU : Thread, IO {
|
||||||
uint4 screenTwoMapBase;
|
uint4 screenTwoMapBase;
|
||||||
uint4 screenOneMapBase;
|
uint4 screenOneMapBase;
|
||||||
|
|
||||||
|
//$0008 SCR2_WIN_X0
|
||||||
|
uint8 screenTwoWindowX0;
|
||||||
|
|
||||||
|
//$0009 SCR2_WIN_Y0
|
||||||
|
uint8 screenTwoWindowY0;
|
||||||
|
|
||||||
|
//$000a SCR2_WIN_X1
|
||||||
|
uint8 screenTwoWindowX1;
|
||||||
|
|
||||||
|
//$000b SCR2_WIN_Y1
|
||||||
|
uint8 screenTwoWindowY1;
|
||||||
|
|
||||||
|
//$000c SPR_WIN_X0
|
||||||
|
uint8 spriteWindowX0;
|
||||||
|
|
||||||
|
//$000d SPR_WIN_Y0
|
||||||
|
uint8 spriteWindowY0;
|
||||||
|
|
||||||
|
//$000e SPR_WIN_X1
|
||||||
|
uint8 spriteWindowX1;
|
||||||
|
|
||||||
|
//$000f SPR_WIN_Y1
|
||||||
|
uint8 spriteWindowY1;
|
||||||
|
|
||||||
//$0010 SCR1_X
|
//$0010 SCR1_X
|
||||||
uint8 scrollOneX;
|
uint8 scrollOneX;
|
||||||
|
|
||||||
|
@ -67,8 +94,19 @@ struct PPU : Thread, IO {
|
||||||
bool iconVertical;
|
bool iconVertical;
|
||||||
bool iconSleep;
|
bool iconSleep;
|
||||||
|
|
||||||
|
//$0016 LCD_VTOTAL
|
||||||
|
uint8 vtotal;
|
||||||
|
|
||||||
|
//$0017 LCD_VBLANK
|
||||||
|
uint8 vblank;
|
||||||
|
|
||||||
//$001c-001f PALMONO_POOL
|
//$001c-001f PALMONO_POOL
|
||||||
uint4 monoPool[8];
|
uint4 pool[8];
|
||||||
|
|
||||||
|
//$0020-003f PALMONO
|
||||||
|
struct Palette {
|
||||||
|
uint3 color[4];
|
||||||
|
} palette[16];
|
||||||
|
|
||||||
//$0060 DISP_MODE
|
//$0060 DISP_MODE
|
||||||
bool bpp;
|
bool bpp;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
auto System::portRead(uint16 addr) -> uint8 {
|
||||||
|
//IEEP_DATA
|
||||||
|
if(addr == 0x00ba) return eeprom.read(EEPROM::DataLo);
|
||||||
|
if(addr == 0x00bb) return eeprom.read(EEPROM::DataHi);
|
||||||
|
|
||||||
|
//IEEP_ADDR
|
||||||
|
if(addr == 0x00bc) return eeprom.read(EEPROM::AddressLo);
|
||||||
|
if(addr == 0x00bd) return eeprom.read(EEPROM::AddressHi);
|
||||||
|
|
||||||
|
//IEEP_CMD
|
||||||
|
if(addr == 0x00be) return eeprom.read(EEPROM::Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto System::portWrite(uint16 addr, uint8 data) -> void {
|
||||||
|
//IEEP_DATA
|
||||||
|
if(addr == 0x00ba) return eeprom.write(EEPROM::DataLo, data);
|
||||||
|
if(addr == 0x00bb) return eeprom.write(EEPROM::DataHi, data);
|
||||||
|
|
||||||
|
//IEEP_ADDR
|
||||||
|
if(addr == 0x00bc) return eeprom.write(EEPROM::AddressLo, data);
|
||||||
|
if(addr == 0x00bd) return eeprom.write(EEPROM::AddressHi, data);
|
||||||
|
|
||||||
|
//IEEP_CMD
|
||||||
|
if(addr == 0x00be) return eeprom.write(EEPROM::Command, data);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace WonderSwan {
|
namespace WonderSwan {
|
||||||
|
|
||||||
System system;
|
System system;
|
||||||
|
#include "io.cpp"
|
||||||
|
|
||||||
auto System::loaded() const -> bool { return _loaded; }
|
auto System::loaded() const -> bool { return _loaded; }
|
||||||
auto System::revision() const -> Revision { return _revision; }
|
auto System::revision() const -> Revision { return _revision; }
|
||||||
|
@ -21,23 +22,37 @@ auto System::load(Revision revision) -> void {
|
||||||
|
|
||||||
//note: IPLROM is currently undumped; otherwise we'd load it here ...
|
//note: IPLROM is currently undumped; otherwise we'd load it here ...
|
||||||
|
|
||||||
|
if(auto node = document["system/eeprom"]) {
|
||||||
|
eeprom.setName(node["name"].text());
|
||||||
|
eeprom.setSize(node["size"].natural() / sizeof(uint16));
|
||||||
|
eeprom.erase();
|
||||||
|
interface->loadRequest(ID::SystemEEPROM, eeprom.name(), false);
|
||||||
|
}
|
||||||
|
|
||||||
cartridge.load();
|
cartridge.load();
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::unload() -> void {
|
auto System::unload() -> void {
|
||||||
if(!loaded()) return;
|
if(!loaded()) return;
|
||||||
|
|
||||||
|
eeprom.setName("");
|
||||||
|
eeprom.setSize(0);
|
||||||
|
|
||||||
cartridge.unload();
|
cartridge.unload();
|
||||||
_loaded = false;
|
_loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
IO::power();
|
IO::power();
|
||||||
|
eeprom.power();
|
||||||
cpu.power();
|
cpu.power();
|
||||||
ppu.power();
|
ppu.power();
|
||||||
apu.power();
|
apu.power();
|
||||||
cartridge.power();
|
cartridge.power();
|
||||||
scheduler.power();
|
scheduler.power();
|
||||||
|
|
||||||
|
for(uint n = 0x00ba; n <= 0x00be; n++) iomap[n] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::run() -> void {
|
auto System::run() -> void {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
struct System {
|
struct System : IO {
|
||||||
enum class Revision : uint {
|
enum class Revision : uint {
|
||||||
WonderSwan, //SW-001 (ASWAN)
|
WonderSwan, //SW-001 (ASWAN)
|
||||||
WonderSwanColor, //WSC-001 (SPHINX)
|
WonderSwanColor, //WSC-001 (SPHINX)
|
||||||
|
@ -15,10 +15,15 @@ struct System {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
|
auto portRead(uint16 addr) -> uint8 override;
|
||||||
|
auto portWrite(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string manifest;
|
string manifest;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
|
EEPROM eeprom;
|
||||||
|
|
||||||
privileged:
|
privileged:
|
||||||
bool _loaded = false;
|
bool _loaded = false;
|
||||||
Revision _revision = Revision::WonderSwan;
|
Revision _revision = Revision::WonderSwan;
|
||||||
|
|
|
@ -42,9 +42,10 @@ namespace WonderSwan {
|
||||||
int64 clock = 0;
|
int64 clock = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include <ws/memory/memory.hpp>
|
||||||
|
#include <ws/eeprom/eeprom.hpp>
|
||||||
#include <ws/system/system.hpp>
|
#include <ws/system/system.hpp>
|
||||||
#include <ws/scheduler/scheduler.hpp>
|
#include <ws/scheduler/scheduler.hpp>
|
||||||
#include <ws/memory/memory.hpp>
|
|
||||||
#include <ws/cartridge/cartridge.hpp>
|
#include <ws/cartridge/cartridge.hpp>
|
||||||
#include <ws/cpu/cpu.hpp>
|
#include <ws/cpu/cpu.hpp>
|
||||||
#include <ws/ppu/ppu.hpp>
|
#include <ws/ppu/ppu.hpp>
|
||||||
|
|
Loading…
Reference in New Issue