Update to v074r03 release.

byuu says:

You guys are going to hate the hell out of this one. It's twenty hours
of non-stop work, no exaggeration at all. Started at 4AM, just wrapped
up now at 8PM.
I rewrote the entire memory subsystem.

Old system:
65536 pages that map 256 bytes each
Mapping a new page overwrites old page
Granularity capped at 256 bytes minimum, requiring ST-001x to map
    60:0000-00ff instead of 60:0000,0001
Classes inherit from MMIO and Memory, forcing only one mappable function
    per class, and fixed names
MMIO sub-mapper inside memory: 00-3f:2000-5fff for one-byte granularity
Can dynamically change the map at run-time, MMC register settings
    perform dynamic remapping

New system:
XML mapping is still based around banklo-bankhi:addrlo-addrhi, as that
    shapes almost everything on the SNES very well
Internally, 2048 pages that map 8192 bytes each
Pages are vectors, scans O(n) from last to first (O(log n) would not
    help, n is never > 3)
Can multi-cast writes, but not reads [for the obvious reason of: which
    read do you return?]
Can map reads and writes separately
Granularity of one for entire 24-bit address range, no need for MMIO
    - whatever is in XML is exactly what you get
Read/Write tables bind function callbacks, so I can have any number of
    functions with any names from any classes with no inheritance (no
    more uPD7725DR, uPD7725SR helpers, etc)
Less memory usage overall due to less tables [ I tried 16 million tables
    and it used 2GB of RAM >_o ]
Cannot dynamically change the map at run-time, MMC read/write functions
    perform address translation [worse average case speed, better worst
    case speed]

Now the hate me part, functors can't beat virtual functions for speed.
There are speed penalties involved:
-4.5% on average games
-11% on SuperFX games (SFX has its own bus)
-15% on SA-1 games (SA-1 has two buses)
Of course the two that need the speed the most get the biggest hits.

I'm afraid there's really not a lot of wiggle room to boost speed back
up.
I suppose one bright spot is that we can much more easily try out
entirely new mapping systems now, since the dynamic portions have been
eliminated.
This commit is contained in:
Tim Allen 2011-01-15 15:30:29 +11:00
parent 5810e69be3
commit 2d73086569
49 changed files with 555 additions and 598 deletions

View File

@ -22,7 +22,7 @@ public:
};
GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
if(romsize < 0x4000) return;
info.mapper = "unknown";
@ -97,6 +97,7 @@ GameBoyCartridge::GameBoyCartridge(const uint8_t *romdata, unsigned romsize) {
xml << " <ram size='" << hex(info.ramsize) << "' battery='" << info.battery << "'/>\n";
xml << "</cartridge>\n";
xml.transform("'", "\"");
}
}

View File

@ -112,13 +112,13 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(type == TypeBsx) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
if(type == TypeSufamiTurbo) {
xml << "<cartridge/>";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
@ -128,7 +128,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " <ram size='" << hex(gameboy_ram_size(data, size)) << "'/>\n";
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
return;
}
@ -279,19 +279,23 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
xml << " </superfx>\n";
} else if(mapper == SA1ROM) {
xml << " <sa1>\n";
xml << " <mcu>\n";
xml << " <rom>\n";
xml << " <map mode='linear' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='linear' address='c0-ff:0000-ffff'/>\n";
xml << " <map mode='direct' address='00-3f:8000-ffff'/>\n";
xml << " <map mode='direct' address='80-bf:8000-ffff'/>\n";
xml << " <map mode='direct' address='c0-ff:0000-ffff'/>\n";
xml << " </rom>\n";
xml << " <ram>\n";
xml << " <map mode='direct' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='direct' address='80-bf:6000-7fff'/>\n";
xml << " </ram>\n";
xml << " </mcu>\n";
xml << " <iram size='800'>\n";
xml << " <map mode='linear' address='00-3f:3000-37ff'/>\n";
xml << " <map mode='linear' address='80-bf:3000-37ff'/>\n";
xml << " </iram>\n";
xml << " <bwram size='" << hex(ram_size) << "'>\n";
xml << " <map mode='linear' address='00-3f:6000-7fff'/>\n";
xml << " <map mode='linear' address='40-4f:0000-ffff'/>\n";
xml << " <map mode='linear' address='80-bf:6000-7fff'/>\n";
xml << " </bwram>\n";
xml << " <mmio>\n";
xml << " <map address='00-3f:2200-23ff'/>\n";
@ -402,48 +406,72 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(has_dsp1) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n";
if(dsp1_mapper == DSP1LoROM1MB) {
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1LoROM2MB) {
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='60-6f:0000-7fff'/>\n";
xml << " <map address='e0-ef:0000-7fff'/>\n";
xml << " <dr>\n";
xml << " <map address='60-6f:0000-3fff'/>\n";
xml << " <map address='e0-ef:0000-3fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60-6f:4000-7fff'/>\n";
xml << " <map address='e0-ef:4000-7fff'/>\n";
xml << " </sr>\n";
} else if(dsp1_mapper == DSP1HiROM) {
xml << " <dr mask='001000' test='000000'/>\n";
xml << " <sr mask='001000' test='001000'/>\n";
xml << " <map address='00-1f:6000-7fff'/>\n";
xml << " <map address='80-9f:6000-7fff'/>\n";
xml << " <dr>\n";
xml << " <map address='00-1f:6000-6fff'/>\n";
xml << " <map address='80-9f:6000-6fff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='00-1f:7000-7fff'/>\n";
xml << " <map address='80-9f:7000-7fff'/>\n";
xml << " </sr>\n";
}
xml << " </necdsp>\n";
}
if(has_dsp2) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
if(has_dsp3) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='20-3f:8000-ffff'/>\n";
xml << " <map address='a0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='20-3f:8000-bfff'/>\n";
xml << " <map address='a0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='20-3f:c000-ffff'/>\n";
xml << " <map address='a0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
if(has_dsp4) {
xml << " <necdsp revision='upd7725' frequency='8000000' program='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n";
xml << " <dr mask='004000' test='000000'/>\n";
xml << " <sr mask='004000' test='004000'/>\n";
xml << " <map address='30-3f:8000-ffff'/>\n";
xml << " <map address='b0-bf:8000-ffff'/>\n";
xml << " <dr>\n";
xml << " <map address='30-3f:8000-bfff'/>\n";
xml << " <map address='b0-bf:8000-bfff'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='30-3f:c000-ffff'/>\n";
xml << " <map address='b0-bf:c000-ffff'/>\n";
xml << " </sr>\n";
xml << " </necdsp>\n";
}
@ -456,21 +484,35 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
if(has_st010) {
xml << " <necdsp revision='upd96050' frequency='10000000' program='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n";
xml << " <dr mask='080001' test='000000'/>\n";
xml << " <sr mask='080001' test='000001'/>\n";
xml << " <dp mask='080000' test='080000'/>\n";
xml << " <map address='60-6f:0000-0fff'/>\n";
xml << " <map address='e0-ef:0000-0fff'/>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
if(has_st011) {
xml << " <necdsp revision='upd96050' frequency='15000000' program='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n";
xml << " <dr mask='080001' test='000000'/>\n";
xml << " <sr mask='080001' test='000001'/>\n";
xml << " <dp mask='080000' test='080000'/>\n";
xml << " <map address='60-6f:0000-0fff'/>\n";
xml << " <map address='e0-ef:0000-0fff'/>\n";
xml << " <dr>\n";
xml << " <map address='60:0000'/>\n";
xml << " <map address='e0:0000'/>\n";
xml << " </dr>\n";
xml << " <sr>\n";
xml << " <map address='60:0001'/>\n";
xml << " <map address='e0:0001'/>\n";
xml << " </sr>\n";
xml << " <dp>\n";
xml << " <map address='68-6f:0000-0fff'/>\n";
xml << " <map address='e8-ef:0000-0fff'/>\n";
xml << " </dp>\n";
xml << " </necdsp>\n";
}
@ -482,7 +524,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) {
}
xml << "</cartridge>\n";
xmlMemoryMap = xml;
xmlMemoryMap = xml.transform("'", "\"");
}
void SNESCartridge::read_header(const uint8_t *data, unsigned size) {

View File

@ -1,4 +1,4 @@
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
class CPU : public Processor, public CPUcore, public PPUcounter {
public:
enum : bool { Threaded = true };
array<Processor*> coprocessors;

View File

@ -1,4 +1,4 @@
class PPU : public Processor, public PPUcounter, public MMIO {
class PPU : public Processor, public PPUcounter {
public:
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);

View File

@ -1,4 +1,4 @@
class PPU : public Processor, public PPUcounter, public MMIO {
class PPU : public Processor, public PPUcounter {
public:
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);

View File

@ -38,7 +38,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_serial = false;
parse_xml(xml_list);
//print(xml_list[0], "\n\n");
print(xml_list[0], "\n\n");
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);

View File

@ -40,8 +40,8 @@ public:
readonly<bool> has_serial;
struct Mapping {
Memory *memory;
MMIO *mmio;
function<uint8 (unsigned)> read;
function<void (unsigned, uint8)> write;
Bus::MapMode mode;
unsigned banklo;
unsigned bankhi;
@ -51,10 +51,10 @@ public:
unsigned size;
Mapping();
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
Mapping(Memory&);
Mapping(MMIO&);
};
array<Mapping> mapping;
linear_vector<Mapping> mapping;
void load(Mode, const lstring&);
void unload();

View File

@ -70,6 +70,7 @@ void Cartridge::xml_parse_rom(xml_element &root) {
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = memory::cartrom.size() - m.offset;
mapping.append(m);
}
}
@ -89,6 +90,7 @@ void Cartridge::xml_parse_ram(xml_element &root) {
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size - m.offset;
mapping.append(m);
}
}
@ -107,7 +109,7 @@ void Cartridge::xml_parse_icd2(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m((Memory&)icd2);
Mapping m({ &ICD2::read, &icd2 }, { &ICD2::write, &icd2 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -147,13 +149,14 @@ void Cartridge::xml_parse_superfx(xml_element &root) {
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(superfx);
Mapping m({ &SuperFX::mmio_read, &superfx }, { &SuperFX::mmio_write, &superfx });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -168,10 +171,12 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
has_sa1 = true;
foreach(node, root.element) {
if(node.name == "rom") {
foreach(leaf, node.element) {
if(node.name == "mcu") {
foreach(subnode, node.element) {
if(subnode.name == "rom") {
foreach(leaf, subnode.element) {
if(leaf.name == "map") {
Mapping m(memory::vsprom);
Mapping m({ &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@ -181,6 +186,18 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
mapping.append(m);
}
}
} else if(subnode.name == "ram") {
foreach(leaf, subnode.element) {
if(leaf.name == "map") {
Mapping m({ &SA1::mmc_cpu_read, &sa1 }, { &SA1::mmc_cpu_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
} else if(node.name == "iram") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
@ -191,6 +208,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = 2048;
mapping.append(m);
}
}
@ -208,13 +226,14 @@ void Cartridge::xml_parse_sa1(xml_element &root) {
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.size == 0) m.size = ram_size;
mapping.append(m);
}
}
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(sa1);
Mapping m({ &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -276,34 +295,37 @@ void Cartridge::xml_parse_necdsp(xml_element &root) {
foreach(node, root.element) {
if(node.name == "dr") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.drmask = hex(attr.content);
if(attr.name == "test") necdsp.drtest = hex(attr.content);
}
}
if(node.name == "sr") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.srmask = hex(attr.content);
if(attr.name == "test") necdsp.srtest = hex(attr.content);
}
}
if(node.name == "dp") {
foreach(attr, node.attribute) {
if(attr.name == "mask") necdsp.dpmask = hex(attr.content);
if(attr.name == "test") necdsp.dptest = hex(attr.content);
}
}
if(node.name == "map") {
Mapping m(necdsp);
foreach(attr, node.attribute) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dr_read, &necdsp }, { &NECDSP::dr_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "sr") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::sr_read, &necdsp }, { &NECDSP::sr_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
} else if(node.name == "dp") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m({ &NECDSP::dp_read, &necdsp }, { &NECDSP::dp_write, &necdsp });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
mapping.append(m);
}
}
}
}
if(program == "") {
system.interface->message({ "Warning: NEC DSP program ", program, " is missing." });
@ -336,7 +358,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(bsxcart);
Mapping m({ &BSXCart::mmio_read, &bsxcart }, { &BSXCart::mmio_write, &bsxcart });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -364,27 +386,29 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) {
if(slot.name == "rom") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Mapping m(slotid == 0 ? memory::stArom : memory::stBrom);
Memory &memory = slotid == 0 ? memory::stArom : memory::stBrom;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
if(memory.size() > 0) mapping.append(m);
}
}
} else if(slot.name == "ram") {
foreach(leaf, slot.element) {
if(leaf.name == "map") {
Mapping m(slotid == 0 ? memory::stAram : memory::stBram);
Memory &memory = slotid == 0 ? memory::stAram : memory::stBram;
Mapping m(memory);
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
if(attr.name == "offset") m.offset = hex(attr.content);
if(attr.name == "size") m.size = hex(attr.content);
}
if(m.memory->size() > 0) mapping.append(m);
if(memory.size() > 0) mapping.append(m);
}
}
}
@ -398,7 +422,7 @@ void Cartridge::xml_parse_srtc(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(srtc);
Mapping m({ &SRTC::read, &srtc }, { &SRTC::write, &srtc });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -414,7 +438,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m((Memory&)sdd1);
Mapping m({ &SDD1::mcu_read, &sdd1 }, { &SDD1::mcu_write, &sdd1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -424,7 +448,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m((MMIO&)sdd1);
Mapping m({ &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -443,7 +467,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
if(node.name == "dcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110dcu);
Mapping m({ &SPC7110::dcu_read, &spc7110 }, { &SPC7110::dcu_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -453,7 +477,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
} else if(node.name == "mcu") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110mcu);
Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &SPC7110::mcu_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content);
@ -464,7 +488,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
} else if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110);
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -478,7 +502,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110ram);
Mapping m({ &SPC7110::ram_read, &spc7110 }, { &SPC7110::ram_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
if(attr.name == "mode") xml_parse_mode(m, attr.content);
@ -493,7 +517,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(spc7110);
Mapping m({ &SPC7110::mmio_read, &spc7110 }, { &SPC7110::mmio_write, &spc7110 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -509,7 +533,7 @@ void Cartridge::xml_parse_cx4(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(cx4);
Mapping m({ &Cx4::read, &cx4 }, { &Cx4::write, &cx4 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -523,7 +547,7 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
foreach(node, root.element) {
if(node.name == "map") {
Mapping m(obc1);
Mapping m({ &OBC1::read, &obc1 }, { &OBC1::write, &obc1 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -533,22 +557,11 @@ void Cartridge::xml_parse_obc1(xml_element &root) {
}
void Cartridge::xml_parse_setarisc(xml_element &root) {
unsigned program = 0;
foreach(attr, root.attribute) {
if(attr.name == "program") {
if(attr.content == "ST-0018") {
program = 1;
has_st0018 = true;
}
}
}
MMIO *map[2] = { 0, &st0018 };
foreach(node, root.element) {
if(node.name == "map" && map[program]) {
Mapping m(*map[program]);
if(node.name == "map") {
Mapping m({ &ST0018::mmio_read, &st0018 }, { &ST0018::mmio_write, &st0018 });
foreach(attr, node.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -564,7 +577,7 @@ void Cartridge::xml_parse_msu1(xml_element &root) {
if(node.name == "mmio") {
foreach(leaf, node.element) {
if(leaf.name == "map") {
Mapping m(msu1);
Mapping m({ &MSU1::mmio_read, &msu1 }, { &MSU1::mmio_write, &msu1 });
foreach(attr, leaf.attribute) {
if(attr.name == "address") xml_parse_address(m, attr.content);
}
@ -611,22 +624,20 @@ void Cartridge::xml_parse_mode(Mapping &m, const string& data) {
}
Cartridge::Mapping::Mapping() {
memory = 0;
mmio = 0;
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory_) {
memory = &memory_;
mmio = 0;
Cartridge::Mapping::Mapping(Memory &memory) {
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(MMIO &mmio_) {
memory = 0;
mmio = &mmio_;
Cartridge::Mapping::Mapping(const function<uint8 (unsigned)> &read_, const function<void (unsigned, uint8)> &write_) {
read = read_;
write = write_;
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}

View File

@ -1,4 +1,4 @@
class BSXBase : public MMIO {
class BSXBase {
public:
void init();
void enable();
@ -22,7 +22,7 @@ private:
} regs;
};
class BSXCart : public MMIO {
class BSXCart {
public:
void init();
void enable();
@ -43,7 +43,7 @@ private:
void update_memory_map();
};
class BSXFlash : public Memory {
class BSXFlash {
public:
void init();
void enable();

View File

@ -6,7 +6,6 @@ void BSXBase::init() {
}
void BSXBase::enable() {
for(uint16 i = 0x2188; i <= 0x219f; i++) memory::mmio.map(i, *this);
}
void BSXBase::power() {
@ -14,6 +13,9 @@ void BSXBase::power() {
}
void BSXBase::reset() {
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXBase::mmio_read, &bsxbase }, { &BSXBase::mmio_write, &bsxbase });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXBase::mmio_read, &bsxbase }, { &BSXBase::mmio_write, &bsxbase });
memset(&regs, 0x00, sizeof regs);
}

View File

@ -25,39 +25,39 @@ void BSXCart::update_memory_map() {
if((regs.r[0x02] & 0x80) == 0x00) {
//LoROM mapping
bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
// bus.map(Bus::MapMode::Linear, 0x00, 0x7d, 0x8000, 0xffff, cart);
// bus.map(Bus::MapMode::Linear, 0x80, 0xff, 0x8000, 0xffff, cart);
} else {
//HiROM mapping
bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
// bus.map(Bus::MapMode::Shadow, 0x00, 0x3f, 0x8000, 0xffff, cart);
// bus.map(Bus::MapMode::Linear, 0x40, 0x7d, 0x0000, 0xffff, cart);
// bus.map(Bus::MapMode::Shadow, 0x80, 0xbf, 0x8000, 0xffff, cart);
// bus.map(Bus::MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, cart);
}
if(regs.r[0x03] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
// bus.map(Bus::MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bsxpram);
//bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x05] & 0x80) == 0x00) {
bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
// bus.map(Bus::MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::bsxpram);
}
if((regs.r[0x06] & 0x80) == 0x00) {
bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
// bus.map(Bus::MapMode::Linear, 0x50, 0x5f, 0x0000, 0xffff, memory::bsxpram);
}
if(regs.r[0x07] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
// bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::cartrom);
}
if(regs.r[0x08] & 0x80) {
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
// bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::cartrom);
}
bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
// bus.map(Bus::MapMode::Shadow, 0x20, 0x3f, 0x6000, 0x7fff, memory::bsxpram);
// bus.map(Bus::MapMode::Linear, 0x70, 0x77, 0x0000, 0xffff, memory::bsxpram);
}
uint8 BSXCart::mmio_read(unsigned addr) {
@ -93,4 +93,3 @@ BSXCart::~BSXCart() {
}
#endif

View File

@ -1,4 +1,4 @@
class Cx4 : public Memory {
class Cx4 {
public:
void init();
void enable();

View File

@ -32,12 +32,6 @@ void ICD2::init() {
}
void ICD2::enable() {
mmio[0] = memory::mmio.handle(0x2181);
mmio[1] = memory::mmio.handle(0x2182);
mmio[2] = memory::mmio.handle(0x420b);
memory::mmio.map(0x2181, *this);
memory::mmio.map(0x2182, *this);
memory::mmio.map(0x420b, *this);
}
void ICD2::power() {
@ -47,6 +41,11 @@ void ICD2::power() {
void ICD2::reset() {
create(ICD2::Enter, cpu.frequency / 5);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2181, 0x2182, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x420b, 0x420b, { &ICD2::mmio_read, &icd2 }, { &ICD2::mmio_write, &icd2 });
r2181 = 0x00;
r2182 = 0x00;

View File

@ -1,4 +1,4 @@
class ICD2 : public GameBoy::Interface, public Coprocessor, public MMIO, public Memory {
class ICD2 : public GameBoy::Interface, public Coprocessor {
public:
unsigned revision;
@ -10,6 +10,9 @@ public:
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:

View File

@ -1,9 +1,9 @@
#ifdef ICD2_CPP
uint8 ICD2::mmio_read(unsigned addr) {
if((uint16)addr == 0x2181) return mmio[0]->mmio_read(addr);
if((uint16)addr == 0x2182) return mmio[1]->mmio_read(addr);
if((uint16)addr == 0x420b) return mmio[2]->mmio_read(addr);
if((uint16)addr == 0x2181) return cpu.mmio_read(addr);
if((uint16)addr == 0x2182) return cpu.mmio_read(addr);
if((uint16)addr == 0x420b) return cpu.mmio_read(addr);
return 0x00;
}
@ -30,9 +30,9 @@ void ICD2::mmio_write(unsigned addr, uint8 data) {
}
}
if((uint16)addr == 0x2181) return mmio[0]->mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return mmio[1]->mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return mmio[2]->mmio_write(addr, data);
if((uint16)addr == 0x2181) return cpu.mmio_write(addr, r2181 = data);
if((uint16)addr == 0x2182) return cpu.mmio_write(addr, r2182 = data);
if((uint16)addr == 0x420b) return cpu.mmio_write(addr, data);
}
uint8 ICD2::read(unsigned addr) {

View File

@ -1,6 +1,5 @@
uint8 r2181;
uint8 r2182;
MMIO *mmio[3];
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
@ -13,7 +12,5 @@ uint8 r6007;
uint8 r7000[16];
unsigned r7800;
uint8 mlt_req;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 vram[320];

View File

@ -1,4 +1,4 @@
class MSU1 : public Coprocessor, public MMIO {
class MSU1 : public Coprocessor {
public:
static void Enter();
void enter();

View File

@ -1,28 +1,16 @@
#ifdef NECDSP_CPP
uint8 NECDSP::read(unsigned addr) {
uint8 NECDSP::sr_read(unsigned) {
cpu.synchronize_coprocessor();
if((addr & srmask) == srtest) return sr_read();
if((addr & drmask) == drtest) return dr_read();
if((addr & dpmask) == dptest) return dp_read(addr);
return 0x00;
}
void NECDSP::write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
if((addr & srmask) == srtest) return sr_write(data);
if((addr & drmask) == drtest) return dr_write(data);
if((addr & dpmask) == dptest) return dp_write(addr, data);
}
uint8 NECDSP::sr_read() {
return regs.sr >> 8;
}
void NECDSP::sr_write(uint8 data) {
void NECDSP::sr_write(unsigned, uint8 data) {
cpu.synchronize_coprocessor();
}
uint8 NECDSP::dr_read() {
uint8 NECDSP::dr_read(unsigned) {
cpu.synchronize_coprocessor();
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
@ -40,7 +28,8 @@ uint8 NECDSP::dr_read() {
}
}
void NECDSP::dr_write(uint8 data) {
void NECDSP::dr_write(unsigned, uint8 data) {
cpu.synchronize_coprocessor();
if(regs.sr.drc == 0) {
//16-bit
if(regs.sr.drs == 0) {
@ -59,6 +48,7 @@ void NECDSP::dr_write(uint8 data) {
}
uint8 NECDSP::dp_read(unsigned addr) {
cpu.synchronize_coprocessor();
bool hi = addr & 1;
addr = (addr >> 1) & 2047;
@ -70,6 +60,7 @@ uint8 NECDSP::dp_read(unsigned addr) {
}
void NECDSP::dp_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
bool hi = addr & 1;
addr = (addr >> 1) & 2047;

View File

@ -253,7 +253,6 @@ void NECDSP::power() {
regs.pc.bits(11);
regs.rp.bits(10);
regs.dp.bits( 8);
dpmask = 0x000000, dptest = 0xffffff; //uPD7725 not mapped to SNES bus
}
if(revision == Revision::uPD96050) {

View File

@ -1,10 +1,7 @@
class NECDSP : public Coprocessor, public Memory {
class NECDSP : public Coprocessor {
public:
enum class Revision : unsigned { uPD7725, uPD96050 } revision;
unsigned frequency;
unsigned drmask, drtest;
unsigned srmask, srtest;
unsigned dpmask, dptest;
#include "registers.hpp"
@ -26,14 +23,11 @@ public:
string disassemble(uint14 ip);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 sr_read(unsigned);
void sr_write(unsigned, uint8 data);
uint8 sr_read();
void sr_write(uint8 data);
uint8 dr_read();
void dr_write(uint8 data);
uint8 dr_read(unsigned);
void dr_write(unsigned, uint8 data);
uint8 dp_read(unsigned addr);
void dp_write(unsigned addr, uint8 data);

View File

@ -1,4 +1,4 @@
class OBC1 : public Memory {
class OBC1 {
public:
void init();
void enable();

View File

@ -6,7 +6,6 @@ SA1Bus sa1bus;
namespace memory {
StaticRAM iram(2048);
//accessed by:
VSPROM vsprom; //S-CPU + SA-1
CPUIRAM cpuiram; //S-CPU
SA1IRAM sa1iram; //SA-1
SA1BWRAM sa1bwram; //SA-1
@ -15,73 +14,43 @@ namespace memory {
}
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.
//this is used both to avoid VBR-reads from accessing MMIO registers, and
//this is used both to keep VBR-reads from accessing MMIO registers, and
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
//these ports.
//(* eg, memory::cartram is used directly, as memory::sa1bwram syncs to the S-CPU)
void VBRBus::init() {
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapMode::Direct, 0x00, 0x3f, 0x8000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
map(MapMode::Direct, 0x80, 0xbf, 0x8000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
map(MapMode::Direct, 0xc0, 0xff, 0x0000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::iram);
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cartram);
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::cartram);
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::iram);
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::iram);
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cartram);
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, { &MappedRAM::read, &memory::cartram }, { &MappedRAM::write, &memory::cartram }, 0, memory::cartram.size());
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, { &MappedRAM::read, &memory::cartram }, { &MappedRAM::write, &memory::cartram }, 0, memory::cartram.size());
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, { &MappedRAM::read, &memory::cartram }, { &MappedRAM::write, &memory::cartram }, 0, memory::cartram.size());
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, { &StaticRAM::read, &memory::iram }, { &StaticRAM::write, &memory::iram }, 0, 2048);
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, { &StaticRAM::read, &memory::iram }, { &StaticRAM::write, &memory::iram }, 0, 2048);
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, { &StaticRAM::read, &memory::iram }, { &StaticRAM::write, &memory::iram }, 0, 2048);
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, { &StaticRAM::read, &memory::iram }, { &StaticRAM::write, &memory::iram }, 0, 2048);
}
void SA1Bus::init() {
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapMode::Direct, 0x00, 0x3f, 0x2200, 0x23ff, { &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
map(MapMode::Direct, 0x80, 0xbf, 0x2200, 0x23ff, { &SA1::mmio_read, &sa1 }, { &SA1::mmio_write, &sa1 });
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, memory::sa1iram);
map(MapMode::Direct, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, memory::sa1iram);
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram);
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::vsprom);
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, memory::sa1bwram);
map(MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, memory::bitmapram);
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, memory::sa1iram);
map(MapMode::Direct, 0x80, 0xbf, 0x2200, 0x23ff, memory::mmio);
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, memory::sa1iram);
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram);
map(MapMode::Linear, 0x80, 0xbf, 0x8000, 0xffff, memory::vsprom);
map(MapMode::Linear, 0xc0, 0xff, 0x0000, 0xffff, memory::vsprom);
}
map(MapMode::Direct, 0x00, 0x3f, 0x8000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
map(MapMode::Direct, 0x80, 0xbf, 0x8000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
map(MapMode::Direct, 0xc0, 0xff, 0x0000, 0xffff, { &SA1::mmc_read, &sa1 }, { &SA1::mmc_write, &sa1 });
//======
//VSPROM
//======
map(MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, { &SA1::mmc_sa1_read, &sa1 }, { &SA1::mmc_sa1_write, &sa1 });
map(MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, { &SA1::mmc_sa1_read, &sa1 }, { &SA1::mmc_sa1_write, &sa1 });
//this class maps $00:[ff00-ffff] for the purpose of supporting:
//$2209.d6 IVSW (S-CPU IRQ vector selection) (0 = cart, 1 = SA-1)
//$2209.d4 NVSW (S-CPU NMI vector selection) (0 = cart, 1 = SA-1)
//when set, vector addresses are over-ridden with SA-1 register settings:
//SIV = S-CPU IRQ vector address override
//SNV = S-CPU NMI vector address override
//
//$00:[ffea-ffeb|ffee-ffef] are special cased on read;
//all other addresses return original mapped data.
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x07ff, { &SA1IRAM::read, &memory::sa1iram }, { &SA1IRAM::write, &memory::sa1iram }, 0, 2048);
map(MapMode::Linear, 0x00, 0x3f, 0x3000, 0x37ff, { &SA1IRAM::read, &memory::sa1iram }, { &SA1IRAM::write, &memory::sa1iram }, 0, 2048);
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x07ff, { &SA1IRAM::read, &memory::sa1iram }, { &SA1IRAM::write, &memory::sa1iram }, 0, 2048);
map(MapMode::Linear, 0x80, 0xbf, 0x3000, 0x37ff, { &SA1IRAM::read, &memory::sa1iram }, { &SA1IRAM::write, &memory::sa1iram }, 0, 2048);
unsigned VSPROM::size() const {
return memory::cartrom.size();
}
uint8 VSPROM::read(unsigned addr) {
//use $7fex instead of $ffex due to linear mapping of 32k granularity ROM data
if((addr & 0xffffe0) == 0x007fe0) {
if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
if(addr == 0x7feb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
if(addr == 0x7fee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
if(addr == 0x7fef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
}
return memory::cartrom.read(addr);
}
void VSPROM::write(unsigned addr, uint8 data) {
map(MapMode::Linear, 0x40, 0x4f, 0x0000, 0xffff, { &SA1BWRAM::read, &memory::sa1bwram }, { &SA1BWRAM::write, &memory::sa1bwram }, 0, memory::sa1bwram.size());
map(MapMode::Linear, 0x60, 0x6f, 0x0000, 0xffff, { &BitmapRAM::read, &memory::bitmapram }, { &BitmapRAM::write, &memory::bitmapram }, 0, memory::bitmapram.size());
}
//=======

View File

@ -6,12 +6,6 @@ struct SA1Bus : Bus {
void init();
};
struct VSPROM : Memory {
unsigned size() const;
alwaysinline uint8 read(unsigned);
alwaysinline void write(unsigned, uint8);
};
struct CPUIRAM : Memory {
unsigned size() const;
alwaysinline uint8 read(unsigned);
@ -46,7 +40,6 @@ struct BitmapRAM : Memory {
namespace memory {
extern StaticRAM iram;
extern VSPROM vsprom;
extern CPUIRAM cpuiram;
extern SA1IRAM sa1iram;
extern SA1BWRAM sa1bwram;

View File

@ -21,4 +21,100 @@ void SA1::op_write(unsigned addr, uint8 data) {
sa1bus.write(addr, data);
}
uint8 SA1::mmc_read(unsigned addr) {
if((addr & 0xffffe0) == 0x00ffe0) {
if(addr == 0xffea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
if(addr == 0xffeb && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 8;
if(addr == 0xffee && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 0;
if(addr == 0xffef && sa1.mmio.cpu_ivsw) return sa1.mmio.siv >> 8;
}
static auto read = [](unsigned addr) {
return memory::cartrom.read(bus.mirror(addr, memory::cartrom.size()));
};
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.cbmode == 0) return read(0x000000 | addr);
return read((mmio.cb << 20) | addr);
}
if((addr & 0xe08000) == 0x208000) { //$20-3f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.dbmode == 0) return read(0x100000 | addr);
return read((mmio.db << 20) | addr);
}
if((addr & 0xe08000) == 0x808000) { //$80-9f:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.ebmode == 0) return read(0x200000 | addr);
return read((mmio.eb << 20) | addr);
}
if((addr & 0xe08000) == 0xa08000) { //$a0-bf:8000-ffff
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x007fff);
if(mmio.fbmode == 0) return read(0x300000 | addr);
return read((mmio.fb << 20) | addr);
}
if((addr & 0xf00000) == 0xc00000) { //$c0-cf:0000-ffff
return read((mmio.cb << 20) | (addr & 0x0fffff));
}
if((addr & 0xf00000) == 0xd00000) { //$d0-df:0000-ffff
return read((mmio.db << 20) | (addr & 0x0fffff));
}
if((addr & 0xf00000) == 0xe00000) { //$e0-ef:0000-ffff
return read((mmio.eb << 20) | (addr & 0x0fffff));
}
if((addr & 0xf00000) == 0xf00000) { //$f0-ff:0000-ffff
return read((mmio.fb << 20) | (addr & 0x0fffff));
}
return 0x00;
}
void SA1::mmc_write(unsigned addr, uint8 data) {
}
uint8 SA1::mmc_cpu_read(unsigned addr) {
cpu.synchronize_coprocessor();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), memory::cc1bwram.size());
return memory::cc1bwram.read(addr);
}
void SA1::mmc_cpu_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), memory::cc1bwram.size());
memory::cc1bwram.write(addr, data);
}
uint8 SA1::mmc_sa1_read(unsigned addr) {
synchronize_cpu();
if(mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), memory::sa1bwram.size());
return memory::sa1bwram.read(addr);
} else {
//$60-6f:0000-ffff x 128 projection
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), memory::bitmapram.size());
return memory::bitmapram.read(addr);
}
}
void SA1::mmc_sa1_write(unsigned addr, uint8 data) {
synchronize_cpu();
if(mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
addr = bus.mirror((mmio.cbm & 0x1f) * 0x2000 + (addr & 0x1fff), memory::sa1bwram.size());
memory::sa1bwram.write(addr, data);
} else {
//$60-6f:0000-ffff x 128 projection
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), memory::bitmapram.size());
memory::bitmapram.write(addr, data);
}
}
#endif

View File

@ -2,4 +2,11 @@ alwaysinline void op_io();
alwaysinline uint8 op_read(unsigned addr);
alwaysinline void op_write(unsigned addr, uint8 data);
uint8_t vbr_read(unsigned addr);
uint8 mmc_read(unsigned addr);
void mmc_write(unsigned addr, uint8 data);
uint8 mmc_cpu_read(unsigned addr);
void mmc_cpu_write(unsigned addr, uint8 data);
uint8 mmc_sa1_read(unsigned addr);
void mmc_sa1_write(unsigned addr, uint8 data);

View File

@ -1,13 +1,5 @@
#ifdef SA1_CPP
//BS-X flash carts, when present, are mapped to 0x400000+
Memory& SA1::mmio_access(unsigned &addr) {
if(!memory::bsxflash.data()) return memory::vsprom;
if(addr < 0x400000) return memory::vsprom;
addr &= 0x3fffff;
return bsxflash;
}
//(CCNT) SA-1 control
void SA1::mmio_w2200(uint8 data) {
if(mmio.sa1_resb && !(data & 0x80)) {
@ -151,104 +143,35 @@ void SA1::mmio_w2215(uint8 data) { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8
void SA1::mmio_w2220(uint8 data) {
mmio.cbmode = (data & 0x80);
mmio.cb = (data & 0x07);
unsigned addr = mmio.cb << 20;
Memory &access = mmio_access(addr);
if(mmio.cbmode == 0) {
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, memory::vsprom, 0x000000);
} else {
bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x1f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0xc0, 0xcf, 0x0000, 0xffff, access, addr);
}
//(DXB) Super MMC bank D
void SA1::mmio_w2221(uint8 data) {
mmio.dbmode = (data & 0x80);
mmio.db = (data & 0x07);
unsigned addr = mmio.db << 20;
Memory &access = mmio_access(addr);
if(mmio.dbmode == 0) {
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, memory::vsprom, 0x100000);
} else {
bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0x20, 0x3f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0xd0, 0xdf, 0x0000, 0xffff, access, addr);
}
//(EXB) Super MMC bank E
void SA1::mmio_w2222(uint8 data) {
mmio.ebmode = (data & 0x80);
mmio.eb = (data & 0x07);
unsigned addr = mmio.eb << 20;
Memory &access = mmio_access(addr);
if(mmio.ebmode == 0) {
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, memory::vsprom, 0x200000);
} else {
bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0x80, 0x9f, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0xe0, 0xef, 0x0000, 0xffff, access, addr);
}
//(FXB) Super MMC bank F
void SA1::mmio_w2223(uint8 data) {
mmio.fbmode = (data & 0x80);
mmio.fb = (data & 0x07);
unsigned addr = mmio.fb << 20;
Memory &access = mmio_access(addr);
if(mmio.fbmode == 0) {
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, memory::vsprom, 0x300000);
} else {
bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0xa0, 0xbf, 0x8000, 0xffff, access, addr);
}
bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
sa1bus.map(Bus::MapMode::Linear, 0xf0, 0xff, 0x0000, 0xffff, access, addr);
}
//(BMAPS) S-CPU BW-RAM address mapping
void SA1::mmio_w2224(uint8 data) {
mmio.sbm = (data & 0x1f);
bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::cc1bwram, mmio.sbm * 0x2000, 0x2000);
}
//(BMAP) SA-1 BW-RAM address mapping
void SA1::mmio_w2225(uint8 data) {
mmio.sw46 = (data & 0x80);
mmio.cbm = (data & 0x7f);
if(mmio.sw46 == 0) {
//$[40-43]:[0000-ffff] x 32 projection
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::sa1bwram, (mmio.cbm & 0x1f) * 0x2000, 0x2000);
} else {
//$[60-6f]:[0000-ffff] x 128 projection
sa1bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
sa1bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x6000, 0x7fff, memory::bitmapram, mmio.cbm * 0x2000, 0x2000);
}
}
//(SWBE) S-CPU BW-RAM write enable

View File

@ -1,6 +1,5 @@
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
Memory& mmio_access(unsigned &addr);
struct MMIO {
//$2200 CCNT
@ -64,19 +63,19 @@ struct MMIO {
//$2220 CXB
bool cbmode;
uint8 cb;
unsigned cb;
//$2221 DXB
bool dbmode;
uint8 db;
unsigned db;
//$2222 EXB
bool ebmode;
uint8 eb;
unsigned eb;
//$2223 FXB
bool fbmode;
uint8 fb;
unsigned fb;
//$2224 BMAPS
uint8 sbm;

View File

@ -124,13 +124,13 @@ void SA1::enable() {
void SA1::power() {
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
vbrbus.init();
sa1bus.init();
reset();
}
void SA1::reset() {
create(SA1::Enter, system.cpu_frequency());
vbrbus.init();
sa1bus.init();
memory::cc1bwram.dma = false;
for(unsigned addr = 0; addr < memory::iram.size(); addr++) {
@ -220,15 +220,15 @@ void SA1::reset() {
mmio.vcnt = 0x0000;
//$2220-2223 CXB, DXB, EXB, FXB
mmio.cbmode = 0;
mmio.dbmode = 0;
mmio.ebmode = 0;
mmio.fbmode = 0;
mmio.cbmode = 1;
mmio.dbmode = 1;
mmio.ebmode = 1;
mmio.fbmode = 1;
mmio.cb = 0x00;
mmio.db = 0x01;
mmio.eb = 0x02;
mmio.fb = 0x03;
mmio.eb = 0x00;
mmio.fb = 0x01;
//$2224 BMAPS
mmio.sbm = 0x00;

View File

@ -1,6 +1,6 @@
#include "bus/bus.hpp"
class SA1 : public Coprocessor, public CPUcore, public MMIO {
class SA1 : public Coprocessor, public CPUcore {
public:
#include "dma/dma.hpp"
#include "memory/memory.hpp"

View File

@ -11,12 +11,6 @@ SDD1 sdd1;
void SDD1::init() {}
void SDD1::enable() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::read()
for(unsigned i = 0x4300; i <= 0x437f; i++) {
cpu_mmio[i & 0x7f] = memory::mmio.handle(i);
memory::mmio.map(i, *this);
}
}
void SDD1::power() {
@ -24,6 +18,11 @@ void SDD1::power() {
}
void SDD1::reset() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
sdd1_enable = 0x00;
xfer_enable = 0x00;
@ -44,7 +43,7 @@ uint8 SDD1::mmio_read(unsigned addr) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
return cpu_mmio[addr & 0x7f]->mmio_read(addr);
return cpu.mmio_read(addr);
}
switch(addr) {
@ -70,7 +69,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
case 5: dma[channel].size = (dma[channel].size & 0xff00) + (data << 0); break;
case 6: dma[channel].size = (dma[channel].size & 0x00ff) + (data << 8); break;
}
return cpu_mmio[addr & 0x7f]->mmio_write(addr, data);
return cpu.mmio_write(addr, data);
}
switch(addr) {
@ -84,7 +83,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
}
}
//SDD1::read() is mapped to $[c0-ff]:[0000-ffff]
//SDD1::mcu_read() is mapped to $c0-ff:0000-ffff
//the design is meant to be as close to the hardware design as possible, thus this code
//avoids adding S-DD1 hooks inside S-CPU::DMA emulation.
//
@ -102,7 +101,7 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
//
//the actual S-DD1 transfer can occur on any channel, but it is most likely limited to
//one transfer per $420b write (for spooling purposes). however, this is not known for certain.
uint8 SDD1::read(unsigned addr) {
uint8 SDD1::mcu_read(unsigned addr) {
if(sdd1_enable & xfer_enable) {
//at least one channel has S-DD1 decompression enabled ...
for(unsigned i = 0; i < 8; i++) {
@ -142,7 +141,7 @@ uint8 SDD1::read(unsigned addr) {
return memory::cartrom.read(mmc[(addr >> 20) & 3] + (addr & 0x0fffff));
}
void SDD1::write(unsigned addr, uint8 data) {
void SDD1::mcu_write(unsigned addr, uint8 data) {
}
SDD1::SDD1() {

View File

@ -1,6 +1,6 @@
#include "sdd1emu.hpp"
class SDD1 : public MMIO, public Memory {
class SDD1 {
public:
void init();
void enable();
@ -10,16 +10,14 @@ public:
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 mcu_read(unsigned addr);
void mcu_write(unsigned addr, uint8 data);
void serialize(serializer&);
SDD1();
~SDD1();
private:
MMIO *cpu_mmio[0x80]; //bus spying hooks to glean information for struct dma[]
uint8 sdd1_enable; //channel bit-mask
uint8 xfer_enable; //channel bit-mask
unsigned mmc[4]; //memory map controller ROM indices

View File

@ -31,7 +31,7 @@ understood.
************************************************************************/
typedef uint8 bool8;
#define SDD1_read(__addr) (sdd1.read(__addr))
#define SDD1_read(__addr) (sdd1.mcu_read(__addr))
////////////////////////////////////////////////////

View File

@ -61,16 +61,16 @@ void Serial::write(uint8 data) {
uint8 Serial::mmio_read(unsigned addr) {
cpu.synchronize_coprocessor();
switch(addr & 1) { default:
case 0: return r4016->mmio_read(addr);
case 1: return r4017->mmio_read(addr);
case 0: return cpu.mmio_read(addr);
case 1: return cpu.mmio_read(addr);
}
}
void Serial::mmio_write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessor();
switch(addr & 1) { default:
case 0: r4016->mmio_write(addr, data); break;
case 1: r4017->mmio_write(addr, data); break;
case 0: cpu.mmio_write(addr, data); break;
case 1: cpu.mmio_write(addr, data); break;
}
}
@ -78,11 +78,6 @@ void Serial::init() {
}
void Serial::enable() {
r4016 = memory::mmio.handle(0x4016);
r4017 = memory::mmio.handle(0x4017);
memory::mmio.map(0x4016, *this);
memory::mmio.map(0x4017, *this);
if(opened()) close();
string name = notdir(cartridge.basename());
string path = dir(cartridge.basename());
@ -99,6 +94,9 @@ void Serial::power() {
void Serial::reset() {
create(Serial::Enter, baudrate() * 8);
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial });
}
}

View File

@ -1,4 +1,4 @@
class Serial : public Coprocessor, public MMIO, public library, public property<Serial> {
class Serial : public Coprocessor, public library, public property<Serial> {
public:
static void Enter();
void enter();
@ -19,7 +19,6 @@ public:
void mmio_write(unsigned addr, uint8 data);
private:
MMIO *r4016, *r4017;
function<unsigned ()> baudrate;
function<bool ()> flowcontrol;
function<void (void (*)(unsigned), uint8_t (*)(), void (*)(uint8_t))> main;

View File

@ -4,9 +4,6 @@
namespace SNES {
SPC7110 spc7110;
SPC7110MCU spc7110mcu;
SPC7110DCU spc7110dcu;
SPC7110RAM spc7110ram;
#include "serialization.cpp"
#include "decomp.cpp"
@ -634,49 +631,41 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
SPC7110::SPC7110() {
}
//==========
//SPC7110MCU
//==========
//============
//SPC7110::MCU
//============
unsigned SPC7110MCU::size() const {
return 0x300000;
}
uint8 SPC7110MCU::read(unsigned addr) {
if(addr <= 0xdfffff) return memory::cartrom.read(spc7110.dx_offset + (addr & 0x0fffff));
if(addr <= 0xefffff) return memory::cartrom.read(spc7110.ex_offset + (addr & 0x0fffff));
if(addr <= 0xffffff) return memory::cartrom.read(spc7110.fx_offset + (addr & 0x0fffff));
uint8 SPC7110::mcu_read(unsigned addr) {
if(addr <= 0xdfffff) return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
if(addr <= 0xefffff) return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
if(addr <= 0xffffff) return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
return cpu.regs.mdr;
}
void SPC7110MCU::write(unsigned addr, uint8 data) {
void SPC7110::mcu_write(unsigned addr, uint8 data) {
}
//==========
//SPC7110DCU
//==========
//============
//SPC7110::DCU
//============
uint8 SPC7110DCU::read(unsigned) {
return spc7110.mmio_read(0x4800);
uint8 SPC7110::dcu_read(unsigned) {
return mmio_read(0x4800);
}
void SPC7110DCU::write(unsigned, uint8) {
void SPC7110::dcu_write(unsigned, uint8) {
}
//==========
//SPC7110RAM
//==========
//============
//SPC7110::RAM
//============
unsigned SPC7110RAM::size() const {
return 0x2000;
}
uint8 SPC7110RAM::read(unsigned addr) {
uint8 SPC7110::ram_read(unsigned addr) {
return memory::cartram.read(addr & 0x1fff);
}
void SPC7110RAM::write(unsigned addr, uint8 data) {
if(spc7110.r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
void SPC7110::ram_write(unsigned addr, uint8 data) {
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
}
}

View File

@ -17,7 +17,7 @@
#include "decomp.hpp"
class SPC7110 : public MMIO {
class SPC7110 {
public:
unsigned data_rom_offset;
@ -40,6 +40,15 @@ public:
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 mcu_read(unsigned addr);
void mcu_write(unsigned addr, uint8 data);
uint8 dcu_read(unsigned);
void dcu_write(unsigned, uint8);
uint8 ram_read(unsigned addr);
void ram_write(unsigned addr, uint8 data);
//spc7110decomp
void decomp_init();
uint8 decomp_read();
@ -130,32 +139,6 @@ private:
unsigned rtc_index;
static const unsigned months[12];
friend class SPC7110MCU;
friend class SPC7110DCU;
friend class SPC7110RAM;
};
class SPC7110MCU : public Memory {
public:
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
class SPC7110DCU : public Memory {
public:
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
class SPC7110RAM : public Memory {
public:
unsigned size() const;
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
};
extern SPC7110 spc7110;
extern SPC7110MCU spc7110mcu;
extern SPC7110DCU spc7110dcu;
extern SPC7110RAM spc7110ram;

View File

@ -155,7 +155,7 @@ unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
return (sum + 1) % 7; //1900-01-01 was a Monday
}
uint8 SRTC::mmio_read(unsigned addr) {
uint8 SRTC::read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x2800) {
@ -176,7 +176,7 @@ uint8 SRTC::mmio_read(unsigned addr) {
return cpu.regs.mdr;
}
void SRTC::mmio_write(unsigned addr, uint8 data) {
void SRTC::write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x2801) {

View File

@ -1,12 +1,12 @@
class SRTC : public MMIO {
class SRTC {
public:
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
SRTC();

View File

@ -1,4 +1,4 @@
class ST0018 : public MMIO {
class ST0018 {
public:
void init();
void enable();

View File

@ -10,12 +10,10 @@ namespace memory {
}
void SuperFXBus::init() {
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
map(MapMode::Linear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
map(MapMode::Linear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x7fff, { &SuperFXGSUROM::read, &memory::gsurom }, { &SuperFXGSUROM::write, &memory::gsurom }, 0, memory::gsurom.size());
map(MapMode::Linear, 0x00, 0x3f, 0x8000, 0xffff, { &SuperFXGSUROM::read, &memory::gsurom }, { &SuperFXGSUROM::write, &memory::gsurom }, 0, memory::gsurom.size());
map(MapMode::Linear, 0x40, 0x5f, 0x0000, 0xffff, { &SuperFXGSUROM::read, &memory::gsurom }, { &SuperFXGSUROM::write, &memory::gsurom }, 0, memory::gsurom.size());
map(MapMode::Linear, 0x60, 0x7f, 0x0000, 0xffff, { &SuperFXGSURAM::read, &memory::gsuram }, { &SuperFXGSURAM::write, &memory::gsuram }, 0, memory::gsuram.size());
}
//ROM / RAM access from the SuperFX CPU

View File

@ -1,6 +1,6 @@
#include "bus/bus.hpp"
class SuperFX : public Coprocessor, public MMIO {
class SuperFX : public Coprocessor {
public:
#include "core/core.hpp"
#include "memory/memory.hpp"

View File

@ -1,4 +1,4 @@
class CPU : public Processor, public CPUcore, public PPUcounter, public MMIO {
class CPU : public Processor, public CPUcore, public PPUcounter {
public:
enum : bool { Threaded = true };
array<Processor*> coprocessors;

View File

@ -1,8 +1,11 @@
void mmio_power();
void mmio_reset();
public:
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
private:
void mmio_power();
void mmio_reset();
uint8 mmio_r2180();
uint8 mmio_r4016();
uint8 mmio_r4017();

View File

@ -51,18 +51,29 @@ MappedRAM::MappedRAM() : data_(0), size_(-1U), write_protect_(false) {}
//Bus
uint8 Bus::read(uint24 addr) {
uint8 Bus::read(unsigned addr) {
#if defined(CHEAT_SYSTEM)
if(cheat.active() && cheat.exists(addr)) {
uint8 r;
if(cheat.read(addr, r)) return r;
}
#endif
Page &p = page[addr >> 8];
return p.access->read(p.offset + addr);
linear_vector<MappedRead> &map = rdpage[addr >> 13];
for(signed n = map.size() - 1; n >= 0; n--) {
if(addr - map[n].lo < map[n].hi) {
return map[n].read(addr + map[n].offset);
}
}
void Bus::write(uint24 addr, uint8 data) {
Page &p = page[addr >> 8];
p.access->write(p.offset + addr, data);
return cpu.regs.mdr;
}
void Bus::write(unsigned addr, uint8 data) {
linear_vector<MappedWrite> &map = wrpage[addr >> 13];
for(signed n = map.size() - 1; n >= 0; n--) {
if(addr - map[n].lo < map[n].hi) {
return map[n].write(addr + map[n].offset, data);
}
}
}

View File

@ -8,44 +8,13 @@ Bus bus;
#include "serialization.cpp"
namespace memory {
MMIOAccess mmio;
StaticRAM wram(128 * 1024);
StaticRAM apuram(64 * 1024);
StaticRAM vram(64 * 1024);
StaticRAM oam(544);
StaticRAM cgram(512);
UnmappedMemory memory_unmapped;
UnmappedMMIO mmio_unmapped;
};
unsigned UnmappedMemory::size() const { return 16 * 1024 * 1024; }
uint8 UnmappedMemory::read(unsigned) { return cpu.regs.mdr; }
void UnmappedMemory::write(unsigned, uint8) {}
uint8 UnmappedMMIO::mmio_read(unsigned) { return cpu.regs.mdr; }
void UnmappedMMIO::mmio_write(unsigned, uint8) {}
MMIO* MMIOAccess::handle(unsigned addr) {
return mmio[addr & 0x7fff];
}
void MMIOAccess::map(unsigned addr, MMIO &access) {
mmio[addr & 0x7fff] = &access;
}
uint8 MMIOAccess::read(unsigned addr) {
return mmio[addr & 0x7fff]->mmio_read(addr);
}
void MMIOAccess::write(unsigned addr, uint8 data) {
mmio[addr & 0x7fff]->mmio_write(addr, data);
}
MMIOAccess::MMIOAccess() {
for(unsigned i = 0; i < 0x8000; i++) mmio[i] = &memory::mmio_unmapped;
}
unsigned Bus::mirror(unsigned addr, unsigned size) {
unsigned base = 0;
if(size) {
@ -64,60 +33,46 @@ unsigned Bus::mirror(unsigned addr, unsigned size) {
return base;
}
void Bus::map(unsigned addr, Memory &access, unsigned offset) {
Page &p = page[addr >> 8];
p.access = &access;
p.offset = offset - addr;
}
void Bus::map(
MapMode mode,
uint8 bank_lo, uint8 bank_hi,
uint16 addr_lo, uint16 addr_hi,
Memory &access, unsigned offset, unsigned size
unsigned bank_lo, unsigned bank_hi,
unsigned addr_lo, unsigned addr_hi,
const function<uint8 (unsigned)> &rd,
const function<void (unsigned, uint8)> &wr,
unsigned base, unsigned length
) {
assert(bank_lo <= bank_hi);
assert(addr_lo <= addr_hi);
if(access.size() == -1U) return;
assert(bank_lo <= bank_hi && bank_lo <= 0xff);
assert(addr_lo <= addr_hi && addr_lo <= 0xffff);
uint8 page_lo = addr_lo >> 8;
uint8 page_hi = addr_hi >> 8;
unsigned index = 0;
unsigned page_lo = addr_lo >> 13;
unsigned page_hi = addr_hi >> 13;
if(length == 0) length = (bank_hi - bank_lo + 1) * (addr_hi - addr_lo + 1);
switch(mode) {
case MapMode::Direct: {
unsigned offset = 0;
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
for(unsigned page = page_lo; page <= page_hi; page++) {
map((bank << 16) + (page << 8), access, (bank << 16) + (page << 8));
}
}
} break;
unsigned map_addr = (bank << 16) | (page << 13);
unsigned map_page = map_addr >> 13;
unsigned map_lo = map_addr | (page == page_lo ? addr_lo & 0x1fff : 0x0000);
unsigned map_hi = map_addr | (page == page_hi ? addr_hi & 0x1fff : 0x1fff);
case MapMode::Linear: {
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
for(unsigned page = page_lo; page <= page_hi; page++) {
map((bank << 16) + (page << 8), access, mirror(offset + index, access.size()));
index += 256;
if(size) index %= size;
}
}
} break;
case MapMode::Shadow: {
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
index += page_lo * 256;
if(size) index %= size;
for(unsigned page = page_lo; page <= page_hi; page++) {
map((bank << 16) + (page << 8), access, mirror(offset + index, access.size()));
index += 256;
if(size) index %= size;
unsigned out_adjust, out_length, out_offset;
if(mode == MapMode::Direct) {
out_offset = 0;
out_length = map_hi - map_lo + 1;
} else if(mode == MapMode::Linear) {
out_offset = base + mirror(offset, length) - map_lo;
out_length = min(map_hi - map_lo + 1, length - offset);
offset += map_hi - map_lo + 1;
offset %= length;
} else if(mode == MapMode::Shadow) {
out_offset = base + mirror(map_addr, length) - map_lo;
out_length = map_hi - map_lo + 1;
}
index += (255 - page_hi) * 256;
if(size) index %= size;
if(rd) rdpage[map_page].append({ rd, map_lo, out_length, out_offset });
if(wr) wrpage[map_page].append({ wr, map_lo, out_length, out_offset });
}
} break;
}
}
@ -134,33 +89,55 @@ void Bus::unload_cart() {
}
void Bus::map_reset() {
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapMode::Direct, 0x00, 0x3f, 0x2000, 0x5fff, memory::mmio);
map(MapMode::Direct, 0x80, 0xbf, 0x2000, 0x5fff, memory::mmio);
for(unsigned i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped);
for(unsigned n = 0; n < 2048; n++) {
rdpage[n].reset();
wrpage[n].reset();
}
}
void Bus::map_xml() {
foreach(m, cartridge.mapping) {
if(m.memory) {
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, *m.memory, m.offset, m.size);
} else if(m.mmio) {
for(unsigned i = m.addrlo; i <= m.addrhi; i++) memory::mmio.map(i, *m.mmio);
}
map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, m.read, m.write, m.offset, m.size);
}
}
void Bus::map_system() {
map(MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
map(MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, memory::wram, 0x000000, 0x002000);
map(MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, memory::wram);
map(
MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
map(
MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram },
0x000000, 0x002000
);
map(
MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff,
{ &StaticRAM::read, &memory::wram }, { &StaticRAM::write, &memory::wram }
);
}
void Bus::power() {
foreach(n, memory::wram) n = config.cpu.wram_init_value;
reset();
}
void Bus::reset() {
map(MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
map(MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, &ppu }, { &PPU::mmio_write, &ppu });
map(MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
map(MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &CPU::mmio_read, &cpu }, { &CPU::mmio_write, &cpu });
}
}

View File

@ -4,22 +4,6 @@ struct Memory {
virtual void write(unsigned addr, uint8 data) = 0;
};
struct MMIO {
virtual uint8 mmio_read(unsigned addr) = 0;
virtual void mmio_write(unsigned addr, uint8 data) = 0;
};
struct UnmappedMemory : Memory {
unsigned size() const;
uint8 read(unsigned);
void write(unsigned, uint8);
};
struct UnmappedMMIO : MMIO {
uint8 mmio_read(unsigned);
void mmio_write(unsigned, uint8);
};
struct StaticRAM : Memory {
inline uint8* data();
inline unsigned size() const;
@ -57,28 +41,11 @@ private:
bool write_protect_;
};
struct MMIOAccess : Memory {
MMIO* handle(unsigned addr);
void map(unsigned addr, MMIO &access);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
MMIOAccess();
private:
MMIO *mmio[0x8000];
};
struct Bus {
unsigned mirror(unsigned addr, unsigned size);
void map(unsigned addr, Memory &access, unsigned offset);
enum class MapMode : unsigned { Direct, Linear, Shadow };
void map(MapMode mode,
uint8 bank_lo, uint8 bank_hi,
uint16 addr_lo, uint16 addr_hi,
Memory &access, unsigned offset = 0, unsigned size = 0);
alwaysinline uint8 read(uint24 addr);
alwaysinline void write(uint24 addr, uint8 data);
alwaysinline uint8 read(unsigned addr);
alwaysinline void write(unsigned addr, uint8 data);
bool load_cart();
void unload_cart();
@ -86,10 +53,30 @@ struct Bus {
void power();
void reset();
struct Page {
Memory *access;
struct MappedRead {
function<uint8 (unsigned)> read;
unsigned lo, hi;
unsigned offset;
} page[65536];
};
struct MappedWrite {
function<void (unsigned, uint8)> write;
unsigned lo, hi;
unsigned offset;
};
linear_vector<MappedRead> rdpage[2048];
linear_vector<MappedWrite> wrpage[2048];
enum class MapMode : unsigned { Direct, Linear, Shadow };
void map(
MapMode mode,
unsigned bank_lo, unsigned bank_hi,
unsigned addr_lo, unsigned addr_hi,
const function<uint8 (unsigned)> &read,
const function<void (unsigned, uint8)> &write,
unsigned base = 0, unsigned length = 0
);
void serialize(serializer&);
@ -100,15 +87,11 @@ private:
};
namespace memory {
extern MMIOAccess mmio; //S-CPU, S-PPU
extern StaticRAM wram; //S-CPU
extern StaticRAM apuram; //S-SMP, S-DSP
extern StaticRAM vram; //S-PPU
extern StaticRAM oam; //S-PPU
extern StaticRAM cgram; //S-PPU
extern UnmappedMemory memory_unmapped;
extern UnmappedMMIO mmio_unmapped;
};
extern Bus bus;

View File

@ -1,4 +1,4 @@
class PPU : public Processor, public PPUcounter, public MMIO {
class PPU : public Processor, public PPUcounter {
public:
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "074.02";
static const char Version[] = "074.03";
static const unsigned SerializerVersion = 17;
}
}

View File

@ -106,12 +106,6 @@ void System::power() {
apu_frequency = region() == Region::NTSC ? config.smp.ntsc_frequency : config.smp.pal_frequency;
bus.power();
for(unsigned i = 0x2100; i <= 0x213f; i++) memory::mmio.map(i, ppu);
for(unsigned i = 0x2140; i <= 0x217f; i++) memory::mmio.map(i, cpu);
for(unsigned i = 0x2180; i <= 0x2183; i++) memory::mmio.map(i, cpu);
for(unsigned i = 0x4016; i <= 0x4017; i++) memory::mmio.map(i, cpu);
for(unsigned i = 0x4200; i <= 0x421f; i++) memory::mmio.map(i, cpu);
for(unsigned i = 0x4300; i <= 0x437f; i++) memory::mmio.map(i, cpu);
audio.coprocessor_enable(false);
if(expansion() == ExpansionPortDevice::BSX) bsxbase.enable();