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:
Tim Allen 2016-02-18 21:32:22 +11:00
parent 4b29f4bad7
commit 810cbdafb4
25 changed files with 656 additions and 221 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
higan/profile/WonderSwan.sys/internal.rom
higan/profile/WonderSwan Color.sys/internal.rom

View File

@ -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
} }

View File

@ -1 +1,2 @@
system name:WonderSwan Color system name:WonderSwan Color
eeprom name=internal.rom size=2048

View File

@ -1 +1,2 @@
system name:WonderSwan system name:WonderSwan
eeprom name=internal.rom size=128

View File

@ -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;
}; };

View File

@ -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);
} }
} }

View File

@ -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};

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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/)

View File

@ -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;

View File

@ -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;

63
higan/ws/cartridge/io.cpp Normal file
View File

@ -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);
}

View File

@ -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;
}
}

135
higan/ws/eeprom/eeprom.cpp Normal file
View File

@ -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;
}
}
}

View File

@ -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;
};

View File

@ -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 {

View File

@ -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 {

View File

@ -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;
} }

View File

@ -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();
} }

View File

@ -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;

25
higan/ws/system/io.cpp Normal file
View File

@ -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);
}

View File

@ -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 {

View File

@ -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;

View File

@ -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>