Update to v099r03 release.

byuu says:

Changelog:
- finished cleaning up the SFC core to my new coding conventions
- removed sfc/controller/usart (superseded by 21fx)
- hid Synchronize Video option from the menu (still in the configuration
  file)

Pretty much the only minor detail left is some variable names in the
SA-1 core that really won't look good at all if I move to camelCase,
so I'll have to rethink how I handle those. It's probably a good area
to attempt using BitFields, to see how it impacts performance. But I'll
do that in a test branch first.

But for the most part, this should be the end of the gigantic diffs (this
one was 174KiB), at least for the SFC/WS cores. Still have the FC/GB/GBA
cores to clean up more fully. Assuming we don't spot any new regressions,
we should be ~95% out of the woods on code cleanups breaking things.
This commit is contained in:
Tim Allen 2016-06-17 23:03:54 +10:00
parent f1a80075fa
commit 44a8c5a2b4
64 changed files with 1539 additions and 1993 deletions

View File

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

View File

@ -93,17 +93,17 @@ auto Cartridge::load() -> void {
parseMarkup(information.markup.cartridge);
//Game Boy
if(cartridge.hasICD2()) {
if(cartridge.hasICD2) {
_sha256 = ""; //Game Boy cartridge not loaded yet: set later via loadGameBoy()
}
//BS Memory
else if(cartridge.hasMCC() && cartridge.hasBSMemorySlot()) {
else if(cartridge.hasMCC && cartridge.hasBSMemorySlot) {
_sha256 = Hash::SHA256(bsmemory.memory.data(), bsmemory.memory.size()).digest();
}
//Sufami Turbo
else if(cartridge.hasSufamiTurboSlots()) {
else if(cartridge.hasSufamiTurboSlots) {
Hash::SHA256 sha;
sha.data(sufamiturboA.rom.data(), sufamiturboA.rom.size());
sha.data(sufamiturboB.rom.data(), sufamiturboB.rom.size());
@ -134,8 +134,8 @@ auto Cartridge::load() -> void {
_sha256 = sha.digest();
}
rom.write_protect(true);
ram.write_protect(false);
rom.writeProtect(true);
ram.writeProtect(false);
}
auto Cartridge::loadGameBoy() -> void {

View File

@ -1,29 +1,9 @@
struct Cartridge : property<Cartridge> {
enum class Region : unsigned { NTSC, PAL };
struct Cartridge {
enum class Region : uint { NTSC, PAL };
auto sha256() const -> string { return _sha256; }
auto region() const -> Region { return _region; }
readonly<bool> hasICD2;
readonly<bool> hasMCC;
readonly<bool> hasNSSDIP;
readonly<bool> hasEvent;
readonly<bool> hasSA1;
readonly<bool> hasSuperFX;
readonly<bool> hasARMDSP;
readonly<bool> hasHitachiDSP;
readonly<bool> hasNECDSP;
readonly<bool> hasEpsonRTC;
readonly<bool> hasSharpRTC;
readonly<bool> hasSPC7110;
readonly<bool> hasSDD1;
readonly<bool> hasOBC1;
readonly<bool> hasMSU1;
readonly<bool> hasGameBoySlot;
readonly<bool> hasBSMemorySlot;
readonly<bool> hasSufamiTurboSlots;
auto manifest() -> string;
auto title() -> string;
@ -59,6 +39,26 @@ struct Cartridge : property<Cartridge> {
} title;
} information;
bool hasICD2;
bool hasMCC;
bool hasNSSDIP;
bool hasEvent;
bool hasSA1;
bool hasSuperFX;
bool hasARMDSP;
bool hasHitachiDSP;
bool hasNECDSP;
bool hasEpsonRTC;
bool hasSharpRTC;
bool hasSPC7110;
bool hasSDD1;
bool hasOBC1;
bool hasMSU1;
bool hasGameBoySlot;
bool hasBSMemorySlot;
bool hasSufamiTurboSlots;
private:
auto loadGameBoy() -> void;
auto loadBSMemory() -> void;

View File

@ -191,11 +191,11 @@ auto Cartridge::parseMarkupSA1(Markup::Node root) -> void {
}
for(auto node : root["rom"].find("map")) {
parseMarkupMap(node, {&SA1::mmcrom_read, &sa1}, {&SA1::mmcrom_write, &sa1});
parseMarkupMap(node, {&SA1::mmcromRead, &sa1}, {&SA1::mmcromWrite, &sa1});
}
for(auto node : root["bwram"].find("map")) {
parseMarkupMap(node, {&SA1::mmcbwram_read, &sa1}, {&SA1::mmcbwram_write, &sa1});
parseMarkupMap(node, {&SA1::mmcbwramRead, &sa1}, {&SA1::mmcbwramWrite, &sa1});
}
for(auto node : root["iram"].find("map")) {
@ -336,14 +336,14 @@ auto Cartridge::parseMarkupSPC7110(Markup::Node root) -> void {
for(auto node : root.find("map")) {
if(node.text() == "mcu") {
parseMarkupMap(node, {&SPC7110::mcurom_read, &spc7110}, {&SPC7110::mcurom_write, &spc7110});
parseMarkupMap(node, {&SPC7110::mcuromRead, &spc7110}, {&SPC7110::mcuromWrite, &spc7110});
} else {
parseMarkupMap(node, {&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
}
}
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, {&SPC7110::mcuram_read, &spc7110}, {&SPC7110::mcuram_write, &spc7110});
parseMarkupMap(node, {&SPC7110::mcuramRead, &spc7110}, {&SPC7110::mcuramWrite, &spc7110});
}
}

View File

@ -7,7 +7,6 @@ namespace SuperFamicom {
#include "mouse/mouse.cpp"
#include "superscope/superscope.cpp"
#include "justifier/justifier.cpp"
#include "usart/usart.cpp"
Controller::Controller(bool port) : port(port) {
if(!thread) create(Controller::Enter, 1);

View File

@ -32,4 +32,3 @@ struct Controller : Cothread {
#include "mouse/mouse.hpp"
#include "superscope/superscope.hpp"
#include "justifier/justifier.hpp"
#include "usart/usart.hpp"

View File

@ -10,13 +10,13 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
uint counter;
unsigned speed; //0 = slow, 1 = normal, 2 = fast
signed x; //x-coordinate
signed y; //y-coordinate
bool dx; //x-direction
bool dy; //y-direction
bool l; //left button
bool r; //right button
uint speed; //0 = slow, 1 = normal, 2 = fast
int x; //x-coordinate
int y; //y-coordinate
bool dx; //x-direction
bool dy; //y-direction
bool l; //left button
bool r; //right button
};

View File

@ -6,7 +6,7 @@ Multitap::Multitap(bool port) : Controller(port) {
auto Multitap::data() -> uint2 {
if(latched) return 2; //multitap detection
unsigned index, port1, port2;
uint index, port1, port2;
if(iobit()) {
index = counter1;

View File

@ -6,6 +6,6 @@ struct Multitap : Controller {
private:
bool latched;
unsigned counter1;
unsigned counter2;
uint counter1;
uint counter2;
};

View File

@ -1,122 +0,0 @@
//Synchronous serial communications cable emulation
//Hardware:
//Teensy++ 2.0 USB
//AT90USB1286
//Connection Diagram:
//SNES GND <> Teensy GND
//SNES IOBit <> Teensy B0
//SNES Latch <> Teensy D2
//SNES Data1 <> Teensy D3
//SNES Clock <> 1Kohm Resistor <> Teensy D5
//Teensy D5 <> Teensy D7
USART::USART(bool port) : Controller(port) {
string filename{interface->path(ID::SuperFamicom), "usart.so"};
if(openAbsolute(filename)) {
usart_init = sym("usart_init");
usart_main = sym("usart_main");
if(usart_init && usart_main) create(Controller::Enter, 10'000'000);
}
}
USART::~USART() {
if(open()) close();
}
auto USART::main() -> void {
if(usart_init && usart_main) {
usart_init(
{&USART::quit, this},
{&USART::usleep, this},
{&USART::readable, this},
{&USART::read, this},
{&USART::writable, this},
{&USART::write, this}
);
usart_main({});
}
while(true) step(10'000'000);
}
auto USART::quit() -> bool {
step(1);
return false;
}
auto USART::usleep(uint microseconds) -> void {
step(10 * microseconds);
}
auto USART::readable() -> bool {
step(1);
return txbuffer.size();
}
//SNES -> USART
auto USART::read() -> uint8 {
step(1);
while(txbuffer.size() == 0) step(1);
uint8 data = txbuffer[0];
txbuffer.remove(0);
return data;
}
auto USART::writable() -> bool {
step(1);
return true;
}
//USART -> SNES
auto USART::write(uint8 data) -> void {
step(1);
rxbuffer.append(data ^ 0xff);
}
//clock
auto USART::data() -> uint2 {
//Joypad
if(iobit()) {
if(counter >= 16) return 1;
uint2 result = 0;
if(counter < 12) result = interface->inputPoll(port, Device::Gamepad, counter);
if(latched == 0) counter++;
return result;
}
//SNES -> USART
if(txlength == 0) {
if(latched == 0) txlength++;
} else if(txlength <= 8) {
txdata = (latched << 7) | (txdata >> 1);
txlength++;
} else {
if(latched == 1) txbuffer.append(txdata);
txlength = 0;
}
//USART -> SNES
if(rxlength == 0 && rxbuffer.size()) {
data1 = 1;
rxdata = rxbuffer[0];
rxbuffer.remove(0);
rxlength++;
} else if(rxlength <= 8) {
data1 = rxdata & 1;
rxdata >>= 1;
rxlength++;
} else {
data1 = 0;
rxlength = 0;
}
return (data2 << 1) | (data1 << 0);
}
//latch
auto USART::latch(bool data) -> void {
if(latched == data) return;
latched = data;
counter = 0;
}

View File

@ -1,40 +0,0 @@
struct USART : Controller, public library {
USART(bool port);
~USART();
auto main() -> void;
auto quit() -> bool;
auto usleep(uint microseconds) -> void;
auto readable() -> bool;
auto read() -> uint8;
auto writable() -> bool;
auto write(uint8 data) -> void;
auto data() -> uint2;
auto latch(bool data) -> void;
private:
bool latched = 0;
bool data1 = 0;
bool data2 = 0;
uint counter = 0;
uint8 rxlength = 0;
uint8 rxdata = 0;
vector<uint8> rxbuffer;
uint8 txlength = 0;
uint8 txdata = 0;
vector<uint8> txbuffer;
function<void (
function<bool ()>, //quit
function<void (uint)>, //usleep
function<bool ()>, //readable
function<uint8 ()>, //read
function<bool ()>, //writable
function<void (uint8)> //write
)> usart_init;
function<void (lstring)> usart_main;
};

View File

@ -1,6 +1,6 @@
auto ArmDSP::firmware() const -> nall::vector<uint8> {
nall::vector<uint8> buffer;
if(!cartridge.hasARMDSP()) return buffer;
if(!cartridge.hasARMDSP) return buffer;
buffer.reserve(128 * 1024 + 32 * 1024);
for(auto n : range(128 * 1024)) buffer.append(programROM[n]);
for(auto n : range( 32 * 1024)) buffer.append(dataROM[n]);

View File

@ -12,14 +12,14 @@ auto HitachiDSP::Enter() -> void {
auto HitachiDSP::main() -> void {
if(mmio.dma) {
for(auto n : range(mmio.dma_length)) {
write(mmio.dma_target + n, read(mmio.dma_source + n));
for(auto n : range(mmio.dmaLength)) {
write(mmio.dmaTarget + n, read(mmio.dmaSource + n));
step(2);
}
mmio.dma = false;
}
exec(mmio.program_offset);
exec(mmio.programOffset);
step(1);
synchronizeCPU();
@ -39,14 +39,14 @@ auto HitachiDSP::unload() -> void {
auto HitachiDSP::power() -> void {
mmio.dma = false;
mmio.dma_source = 0x000000;
mmio.dma_length = 0x0000;
mmio.dma_target = 0x000000;
mmio.dmaSource = 0x000000;
mmio.dmaLength = 0x0000;
mmio.dmaTarget = 0x000000;
mmio.r1f48 = 0x00;
mmio.program_offset = 0x000000;
mmio.programOffset = 0x000000;
mmio.r1f4c = 0x00;
mmio.page_number = 0x0000;
mmio.program_counter = 0x00;
mmio.pageNumber = 0x0000;
mmio.programCounter = 0x00;
mmio.r1f50 = 0x33;
mmio.r1f51 = 0x00;
mmio.r1f52 = 0x01;

View File

@ -2,8 +2,6 @@ struct HitachiDSP : Processor::HG51B, Cothread {
MappedRAM rom;
MappedRAM ram;
#include "mmio.hpp"
static auto Enter() -> void;
auto main() -> void;
@ -38,6 +36,23 @@ struct HitachiDSP : Processor::HG51B, Cothread {
uint Frequency;
uint Roms;
struct MMIO {
bool dma; //true during DMA transfers
uint24 dmaSource; //$1f40-$1f42
uint24 dmaLength; //$1f43-$1f44
uint24 dmaTarget; //$1f45-$1f47
uint8 r1f48; //$1f48
uint24 programOffset; //$1f49-$1f4b
uint8 r1f4c; //$1f4c
uint16 pageNumber; //$1f4d-$1f4e
uint8 programCounter; //$1f4f
uint8 r1f50; //$1f50
uint8 r1f51; //$1f51
uint8 r1f52; //$1f52
uint8 vector[32]; //$1f60-$1f7f
} mmio;
};
extern HitachiDSP hitachidsp;

View File

@ -75,22 +75,22 @@ auto HitachiDSP::dspRead(uint24 addr, uint8) -> uint8 {
//MMIO
switch(addr) {
case 0x7f40: return mmio.dma_source >> 0;
case 0x7f41: return mmio.dma_source >> 8;
case 0x7f42: return mmio.dma_source >> 16;
case 0x7f43: return mmio.dma_length >> 0;
case 0x7f44: return mmio.dma_length >> 8;
case 0x7f45: return mmio.dma_target >> 0;
case 0x7f46: return mmio.dma_target >> 8;
case 0x7f47: return mmio.dma_target >> 16;
case 0x7f40: return mmio.dmaSource >> 0;
case 0x7f41: return mmio.dmaSource >> 8;
case 0x7f42: return mmio.dmaSource >> 16;
case 0x7f43: return mmio.dmaLength >> 0;
case 0x7f44: return mmio.dmaLength >> 8;
case 0x7f45: return mmio.dmaTarget >> 0;
case 0x7f46: return mmio.dmaTarget >> 8;
case 0x7f47: return mmio.dmaTarget >> 16;
case 0x7f48: return mmio.r1f48;
case 0x7f49: return mmio.program_offset >> 0;
case 0x7f4a: return mmio.program_offset >> 8;
case 0x7f4b: return mmio.program_offset >> 16;
case 0x7f49: return mmio.programOffset >> 0;
case 0x7f4a: return mmio.programOffset >> 8;
case 0x7f4b: return mmio.programOffset >> 16;
case 0x7f4c: return mmio.r1f4c;
case 0x7f4d: return mmio.page_number >> 0;
case 0x7f4e: return mmio.page_number >> 8;
case 0x7f4f: return mmio.program_counter;
case 0x7f4d: return mmio.pageNumber >> 0;
case 0x7f4e: return mmio.pageNumber >> 8;
case 0x7f4f: return mmio.programCounter;
case 0x7f50: return mmio.r1f50;
case 0x7f51: return mmio.r1f51;
case 0x7f52: return mmio.r1f52;
@ -120,26 +120,26 @@ auto HitachiDSP::dspWrite(uint24 addr, uint8 data) -> void {
//MMIO
switch(addr) {
case 0x7f40: mmio.dma_source = (mmio.dma_source & 0xffff00) | (data << 0); return;
case 0x7f41: mmio.dma_source = (mmio.dma_source & 0xff00ff) | (data << 8); return;
case 0x7f42: mmio.dma_source = (mmio.dma_source & 0x00ffff) | (data << 16); return;
case 0x7f43: mmio.dma_length = (mmio.dma_length & 0xff00) | (data << 0); return;
case 0x7f44: mmio.dma_length = (mmio.dma_length & 0x00ff) | (data << 8); return;
case 0x7f45: mmio.dma_target = (mmio.dma_target & 0xffff00) | (data << 0); return;
case 0x7f46: mmio.dma_target = (mmio.dma_target & 0xff00ff) | (data << 8); return;
case 0x7f47: mmio.dma_target = (mmio.dma_target & 0x00ffff) | (data << 16);
case 0x7f40: mmio.dmaSource = (mmio.dmaSource & 0xffff00) | (data << 0); return;
case 0x7f41: mmio.dmaSource = (mmio.dmaSource & 0xff00ff) | (data << 8); return;
case 0x7f42: mmio.dmaSource = (mmio.dmaSource & 0x00ffff) | (data << 16); return;
case 0x7f43: mmio.dmaLength = (mmio.dmaLength & 0xff00) | (data << 0); return;
case 0x7f44: mmio.dmaLength = (mmio.dmaLength & 0x00ff) | (data << 8); return;
case 0x7f45: mmio.dmaTarget = (mmio.dmaTarget & 0xffff00) | (data << 0); return;
case 0x7f46: mmio.dmaTarget = (mmio.dmaTarget & 0xff00ff) | (data << 8); return;
case 0x7f47: mmio.dmaTarget = (mmio.dmaTarget & 0x00ffff) | (data << 16);
if(regs.halt) mmio.dma = true;
return;
case 0x7f48: mmio.r1f48 = data & 0x01; return;
case 0x7f49: mmio.program_offset = (mmio.program_offset & 0xffff00) | (data << 0); return;
case 0x7f4a: mmio.program_offset = (mmio.program_offset & 0xff00ff) | (data << 8); return;
case 0x7f4b: mmio.program_offset = (mmio.program_offset & 0x00ffff) | (data << 16); return;
case 0x7f49: mmio.programOffset = (mmio.programOffset & 0xffff00) | (data << 0); return;
case 0x7f4a: mmio.programOffset = (mmio.programOffset & 0xff00ff) | (data << 8); return;
case 0x7f4b: mmio.programOffset = (mmio.programOffset & 0x00ffff) | (data << 16); return;
case 0x7f4c: mmio.r1f4c = data & 0x03; return;
case 0x7f4d: mmio.page_number = (mmio.page_number & 0x7f00) | ((data & 0xff) << 0); return;
case 0x7f4e: mmio.page_number = (mmio.page_number & 0x00ff) | ((data & 0x7f) << 8); return;
case 0x7f4f: mmio.program_counter = data;
case 0x7f4d: mmio.pageNumber = (mmio.pageNumber & 0x7f00) | ((data & 0xff) << 0); return;
case 0x7f4e: mmio.pageNumber = (mmio.pageNumber & 0x00ff) | ((data & 0x7f) << 8); return;
case 0x7f4f: mmio.programCounter = data;
if(regs.halt) {
regs.pc = mmio.page_number * 256 + mmio.program_counter;
regs.pc = mmio.pageNumber * 256 + mmio.programCounter;
regs.halt = false;
}
return;

View File

@ -1,16 +0,0 @@
struct MMIO {
bool dma; //true during DMA transfers
uint24 dma_source; //$1f40-$1f42
uint24 dma_length; //$1f43-$1f44
uint24 dma_target; //$1f45-$1f47
uint8 r1f48; //$1f48
uint24 program_offset; //$1f49-$1f4b
uint8 r1f4c; //$1f4c
uint16 page_number; //$1f4d-$1f4e
uint8 program_counter; //$1f4f
uint8 r1f50; //$1f50
uint8 r1f51; //$1f51
uint8 r1f52; //$1f52
uint8 vector[32]; //$1f60-$1f7f
} mmio;

View File

@ -1,6 +1,6 @@
auto HitachiDSP::firmware() const -> vector<uint8> {
vector<uint8> buffer;
if(!cartridge.hasHitachiDSP()) return buffer;
if(!cartridge.hasHitachiDSP) return buffer;
buffer.reserve(1024 * 3);
for(auto n : range(1024)) {
buffer.append(dataROM[n] >> 0);
@ -15,14 +15,14 @@ auto HitachiDSP::serialize(serializer& s) -> void {
Thread::serialize(s);
s.integer(mmio.dma);
s.integer(mmio.dma_source);
s.integer(mmio.dma_length);
s.integer(mmio.dma_target);
s.integer(mmio.dmaSource);
s.integer(mmio.dmaLength);
s.integer(mmio.dmaTarget);
s.integer(mmio.r1f48);
s.integer(mmio.program_offset);
s.integer(mmio.programOffset);
s.integer(mmio.r1f4c);
s.integer(mmio.page_number);
s.integer(mmio.program_counter);
s.integer(mmio.pageNumber);
s.integer(mmio.programCounter);
s.integer(mmio.r1f50);
s.integer(mmio.r1f51);
s.integer(mmio.r1f52);

View File

@ -62,19 +62,19 @@ auto ICD2::reset(bool soft) -> void {
r6006 = 0xff;
r6007 = 0xff;
for(auto& r : r7000) r = 0x00;
mlt_req = 0;
mltReq = 0;
for(auto& n : output) n = 0xff;
read_bank = 0;
read_addr = 0;
write_bank = 0;
write_addr = 0;
readBank = 0;
readAddress = 0;
writeBank = 0;
writeAddress = 0;
packetsize = 0;
joyp_id = 3;
joyp15lock = 0;
joyp14lock = 0;
pulselock = true;
packetSize = 0;
joypID = 3;
joyp15Lock = 0;
joyp14Lock = 0;
pulseLock = true;
GameBoy::system.init();
GameBoy::system.power();

View File

@ -43,17 +43,17 @@ private:
uint8 data[16];
};
Packet packet[64];
uint packetsize;
uint packetSize;
uint joyp_id;
bool joyp15lock;
bool joyp14lock;
bool pulselock;
bool strobelock;
bool packetlock;
Packet joyp_packet;
uint8 packetoffset;
uint8 bitdata, bitoffset;
uint joypID;
bool joyp15Lock;
bool joyp14Lock;
bool pulseLock;
bool strobeLock;
bool packetLock;
Packet joypPacket;
uint8 packetOffset;
uint8 bitData, bitOffset;
uint8 r6003; //control port
uint8 r6004; //joypad 1
@ -61,13 +61,13 @@ private:
uint8 r6006; //joypad 3
uint8 r6007; //joypad 4
uint8 r7000[16]; //JOYP packet data
uint8 mlt_req; //number of active joypads
uint8 mltReq; //number of active joypads
uint8 output[4 * 512];
uint read_bank;
uint read_addr;
uint write_bank;
uint write_addr;
uint readBank;
uint readAddress;
uint writeBank;
uint writeAddress;
};
#else

View File

@ -1,56 +1,56 @@
auto ICD2::lcdScanline() -> void {
if(GameBoy::ppu.status.ly > 143) return; //Vblank
if((GameBoy::ppu.status.ly & 7) == 0) {
write_bank = (write_bank + 1) & 3;
write_addr = 0;
writeBank = (writeBank + 1) & 3;
writeAddress = 0;
}
}
auto ICD2::lcdOutput(uint2 color) -> void {
uint y = write_addr / 160;
uint x = write_addr % 160;
uint addr = write_bank * 512 + y * 2 + x / 8 * 16;
uint y = writeAddress / 160;
uint x = writeAddress % 160;
uint addr = writeBank * 512 + y * 2 + x / 8 * 16;
output[addr + 0] = (output[addr + 0] << 1) | (bool)(color & 1);
output[addr + 1] = (output[addr + 1] << 1) | (bool)(color & 2);
write_addr = (write_addr + 1) % 1280;
writeAddress = (writeAddress + 1) % 1280;
}
auto ICD2::joypWrite(bool p15, bool p14) -> void {
//joypad handling
if(p15 == 1 && p14 == 1) {
if(joyp15lock == 0 && joyp14lock == 0) {
joyp15lock = 1;
joyp14lock = 1;
joyp_id = (joyp_id + 1) & 3;
if(joyp15Lock == 0 && joyp14Lock == 0) {
joyp15Lock = 1;
joyp14Lock = 1;
joypID = (joypID + 1) & 3;
}
}
if(p15 == 0 && p14 == 1) joyp15lock = 0;
if(p15 == 1 && p14 == 0) joyp14lock = 0;
if(p15 == 0 && p14 == 1) joyp15Lock = 0;
if(p15 == 1 && p14 == 0) joyp14Lock = 0;
//packet handling
if(p15 == 0 && p14 == 0) { //pulse
pulselock = false;
packetoffset = 0;
bitoffset = 0;
strobelock = true;
packetlock = false;
pulseLock = false;
packetOffset = 0;
bitOffset = 0;
strobeLock = true;
packetLock = false;
return;
}
if(pulselock) return;
if(pulseLock) return;
if(p15 == 1 && p14 == 1) {
strobelock = false;
strobeLock = false;
return;
}
if(strobelock) {
if(strobeLock) {
if(p15 == 1 || p14 == 1) { //malformed packet
packetlock = false;
pulselock = true;
bitoffset = 0;
packetoffset = 0;
packetLock = false;
pulseLock = true;
bitOffset = 0;
packetOffset = 0;
} else {
return;
}
@ -59,30 +59,30 @@ auto ICD2::joypWrite(bool p15, bool p14) -> void {
//p15:1, p14:0 = 0
//p15:0, p14:1 = 1
bool bit = (p15 == 0);
strobelock = true;
strobeLock = true;
if(packetlock) {
if(packetLock) {
if(p15 == 1 && p14 == 0) {
if((joyp_packet[0] >> 3) == 0x11) {
mlt_req = joyp_packet[1] & 3;
if(mlt_req == 2) mlt_req = 3;
joyp_id = 0;
if((joypPacket[0] >> 3) == 0x11) {
mltReq = joypPacket[1] & 3;
if(mltReq == 2) mltReq = 3;
joypID = 0;
}
if(packetsize < 64) packet[packetsize++] = joyp_packet;
packetlock = false;
pulselock = true;
if(packetSize < 64) packet[packetSize++] = joypPacket;
packetLock = false;
pulseLock = true;
}
return;
}
bitdata = (bit << 7) | (bitdata >> 1);
if(++bitoffset < 8) return;
bitData = (bit << 7) | (bitData >> 1);
if(++bitOffset < 8) return;
bitoffset = 0;
joyp_packet[packetoffset] = bitdata;
if(++packetoffset < 16) return;
packetlock = true;
bitOffset = 0;
joypPacket[packetOffset] = bitData;
if(++packetOffset < 16) return;
packetLock = true;
}
auto ICD2::loadRequest(uint id, string name, string type, bool required) -> void {
@ -124,10 +124,10 @@ auto ICD2::audioSample(const double* samples, uint channels) -> void {
}
auto ICD2::inputPoll(uint port, uint device, uint id) -> int16 {
GameBoy::cpu.status.mlt_req = joyp_id & mlt_req;
GameBoy::cpu.status.mlt_req = joypID & mltReq;
uint data = 0x00;
switch(joyp_id & mlt_req) {
switch(joypID & mltReq) {
case 0: data = ~r6004; break;
case 1: data = ~r6005; break;
case 2: data = ~r6006; break;

View File

@ -4,16 +4,16 @@ auto ICD2::read(uint24 addr, uint8 data) -> uint8 {
//LY counter
if(addr == 0x6000) {
uint y = min((uint8)143, GameBoy::ppu.status.ly);
return (y & ~7) | write_bank;
return (y & ~7) | writeBank;
}
//command ready port
if(addr == 0x6002) {
data = packetsize > 0;
data = packetSize > 0;
if(data) {
for(auto n : range(16)) r7000[n] = packet[0][n];
packetsize--;
for(auto n : range(packetsize)) packet[n] = packet[n + 1];
packetSize--;
for(auto n : range(packetSize)) packet[n] = packet[n + 1];
}
return data;
}
@ -30,8 +30,8 @@ auto ICD2::read(uint24 addr, uint8 data) -> uint8 {
//VRAM port
if(addr == 0x7800) {
data = output[read_bank * 512 + read_addr];
read_addr = (read_addr + 1) & 511;
data = output[readBank * 512 + readAddress];
readAddress = (readAddress + 1) & 511;
return data;
}
@ -43,8 +43,8 @@ auto ICD2::write(uint24 addr, uint8 data) -> void {
//VRAM port
if(addr == 0x6001) {
read_bank = data & 3;
read_addr = 0;
readBank = data & 3;
readAddress = 0;
return;
}

View File

@ -3,18 +3,18 @@ auto ICD2::serialize(serializer& s) -> void {
GameBoy::system.serializeAll(s);
for(auto n : range(64)) s.array(packet[n].data);
s.integer(packetsize);
s.integer(packetSize);
s.integer(joyp_id);
s.integer(joyp15lock);
s.integer(joyp14lock);
s.integer(pulselock);
s.integer(strobelock);
s.integer(packetlock);
s.array(joyp_packet.data);
s.integer(packetoffset);
s.integer(bitdata);
s.integer(bitoffset);
s.integer(joypID);
s.integer(joyp15Lock);
s.integer(joyp14Lock);
s.integer(pulseLock);
s.integer(strobeLock);
s.integer(packetLock);
s.array(joypPacket.data);
s.integer(packetOffset);
s.integer(bitData);
s.integer(bitOffset);
s.integer(r6003);
s.integer(r6004);
@ -22,11 +22,11 @@ auto ICD2::serialize(serializer& s) -> void {
s.integer(r6006);
s.integer(r6007);
s.array(r7000);
s.integer(mlt_req);
s.integer(mltReq);
s.array(output);
s.integer(read_bank);
s.integer(read_addr);
s.integer(write_bank);
s.integer(write_addr);
s.integer(readBank);
s.integer(readAddress);
s.integer(writeBank);
s.integer(writeAddress);
}

View File

@ -1,6 +1,6 @@
auto NECDSP::firmware() const -> vector<uint8> {
vector<uint8> buffer;
if(!cartridge.hasNECDSP()) return buffer;
if(!cartridge.hasNECDSP) return buffer;
uint plength = 2048, dlength = 1024;
if(revision == Revision::uPD96050) plength = 16384, dlength = 2048;
buffer.reserve(plength * 3 + dlength * 2);

View File

@ -20,7 +20,7 @@ auto SA1::CPUBWRAM::size() const -> uint {
auto SA1::CPUBWRAM::read(uint24 addr, uint8) -> uint8 {
cpu.synchronizeCoprocessors();
if(dma) return sa1.dma_cc1_read(addr);
if(dma) return sa1.dmaCC1Read(addr);
return sa1.bwram.read(addr);
}

View File

@ -2,7 +2,7 @@
//direct data transfer
//====================
auto SA1::dma_normal() -> void {
auto SA1::dmaNormal() -> void {
while(mmio.dtc--) {
uint8 data = r.mdr;
uint32 dsa = mmio.dsa++;
@ -15,13 +15,13 @@ auto SA1::dma_normal() -> void {
switch(mmio.sd) {
case DMA::SourceROM:
if((dsa & 0x408000) == 0x008000 || (dsa & 0xc00000) == 0xc00000) {
data = bus_read(dsa, data);
data = busRead(dsa, data);
}
break;
case DMA::SourceBWRAM:
if((dsa & 0x40e000) == 0x006000 || (dsa & 0xf00000) == 0x400000) {
data = bus_read(dsa, data);
data = busRead(dsa, data);
}
break;
@ -33,7 +33,7 @@ auto SA1::dma_normal() -> void {
switch(mmio.dd) {
case DMA::DestBWRAM:
if((dda & 0x40e000) == 0x006000 || (dda & 0xf00000) == 0x400000) {
bus_write(dda, data);
busWrite(dda, data);
}
break;
@ -56,7 +56,7 @@ auto SA1::dma_normal() -> void {
//type-1 character conversion
//===========================
auto SA1::dma_cc1() -> void {
auto SA1::dmaCC1() -> void {
cpubwram.dma = true;
mmio.chdma_irqfl = true;
if(mmio.chdma_irqen) {
@ -65,7 +65,7 @@ auto SA1::dma_cc1() -> void {
}
}
auto SA1::dma_cc1_read(uint addr) -> uint8 {
auto SA1::dmaCC1Read(uint addr) -> uint8 {
//16 bytes/char (2bpp); 32 bytes/char (4bpp); 64 bytes/char (8bpp)
uint charmask = (1 << (6 - mmio.dmacb)) - 1;
@ -114,7 +114,7 @@ auto SA1::dma_cc1_read(uint addr) -> uint8 {
//type-2 character conversion
//===========================
auto SA1::dma_cc2() -> void {
auto SA1::dmaCC2() -> void {
//select register file index (0-7 or 8-15)
const uint8* brf = &mmio.brf[(dma.line & 1) << 3];
uint bpp = 2 << (2 - mmio.dmacb);

View File

@ -1,19 +1,19 @@
auto SA1::bus_read(uint24 addr, uint8 data) -> uint8 {
auto SA1::busRead(uint24 addr, uint8 data) -> uint8 {
if((addr & 0x40fe00) == 0x002200) { //$00-3f,80-bf:2200-23ff
return readIO(addr, data);
}
if((addr & 0x408000) == 0x008000) { //$00-3f,80-bf:8000-ffff
addr = ((addr & 0x800000) >> 2) | ((addr & 0x3f0000) >> 1) | (addr & 0x7fff);
return mmcrom_read(addr, data);
return mmcromRead(addr, data);
}
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
return mmcrom_read(addr, data);
return mmcromRead(addr, data);
}
if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return mmc_sa1_read(addr, data);
return mmcSA1Read(addr, data);
}
if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
@ -33,20 +33,20 @@ auto SA1::bus_read(uint24 addr, uint8 data) -> uint8 {
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
synchronizeCPU();
return bitmap_read(addr & 0x0fffff, data);
return bitmapRead(addr & 0x0fffff, data);
}
//unmapped region
return data;
}
auto SA1::bus_write(uint24 addr, uint8 data) -> void {
auto SA1::busWrite(uint24 addr, uint8 data) -> void {
if((addr & 0x40fe00) == 0x002200) { //$00-3f,80-bf:2200-23ff
return writeIO(addr, data);
}
if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
return mmc_sa1_write(addr, data);
return mmcSA1Write(addr, data);
}
if((addr & 0x40f800) == 0x000000) { //$00-3f,80-bf:0000-07ff
@ -66,7 +66,7 @@ auto SA1::bus_write(uint24 addr, uint8 data) -> void {
if((addr & 0xf00000) == 0x600000) { //$60-6f:0000-ffff
synchronizeCPU();
return bitmap_write(addr & 0x0fffff, data);
return bitmapWrite(addr & 0x0fffff, data);
}
}
@ -74,14 +74,14 @@ auto SA1::bus_write(uint24 addr, uint8 data) -> void {
//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.
auto SA1::vbr_read(uint24 addr, uint8 data) -> uint8 {
auto SA1::vbrRead(uint24 addr, uint8 data) -> uint8 {
if((addr & 0x408000) == 0x008000) { //$00-3f,80-bf:8000-ffff
addr = ((addr & 0x800000) >> 2) | ((addr & 0x3f0000) >> 1) | (addr & 0x7fff);
return mmcrom_read(addr, data);
return mmcromRead(addr, data);
}
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
return mmcrom_read(addr, data);
return mmcromRead(addr, data);
}
if((addr & 0x40e000) == 0x006000) { //$00-3f,80-bf:6000-7fff
@ -115,19 +115,19 @@ auto SA1::io() -> void {
auto SA1::read(uint24 addr) -> uint8 {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
return bus_read(addr, r.mdr);
return busRead(addr, r.mdr);
}
auto SA1::write(uint24 addr, uint8 data) -> void {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
bus_write(addr, r.mdr = data);
busWrite(addr, r.mdr = data);
}
//note: addresses are translated prior to invoking this function:
//$00-3f,80-bf:8000-ffff mask=0x408000 => $00-3f:0000-ffff
//$c0-ff:0000-ffff mask=0
auto SA1::mmcrom_read(uint24 addr, uint8) -> uint8 {
auto SA1::mmcromRead(uint24 addr, uint8) -> uint8 {
//reset vector overrides
if((addr & 0xffffe0) == 0x007fe0) { //$00:ffe0-ffef
if(addr == 0x7fea && sa1.mmio.cpu_nvsw) return sa1.mmio.snv >> 0;
@ -166,10 +166,10 @@ auto SA1::mmcrom_read(uint24 addr, uint8) -> uint8 {
return 0x00;
}
auto SA1::mmcrom_write(uint24 addr, uint8 data) -> void {
auto SA1::mmcromWrite(uint24 addr, uint8 data) -> void {
}
auto SA1::mmcbwram_read(uint24 addr, uint8 data) -> uint8 {
auto SA1::mmcbwramRead(uint24 addr, uint8 data) -> uint8 {
if(addr < 0x2000) { //$00-3f,80-bf:6000-7fff
cpu.synchronizeCoprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
@ -183,7 +183,7 @@ auto SA1::mmcbwram_read(uint24 addr, uint8 data) -> uint8 {
return data;
}
auto SA1::mmcbwram_write(uint24 addr, uint8 data) -> void {
auto SA1::mmcbwramWrite(uint24 addr, uint8 data) -> void {
if(addr < 0x2000) { //$00-3f,80-bf:6000-7fff
cpu.synchronizeCoprocessors();
addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size());
@ -195,7 +195,7 @@ auto SA1::mmcbwram_write(uint24 addr, uint8 data) -> void {
}
}
auto SA1::mmc_sa1_read(uint addr, uint8 data) -> uint8 {
auto SA1::mmcSA1Read(uint addr, uint8 data) -> uint8 {
synchronizeCPU();
if(mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
@ -204,11 +204,11 @@ auto SA1::mmc_sa1_read(uint addr, uint8 data) -> uint8 {
} else {
//$60-6f:0000-ffff x 128 projection
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
return bitmap_read(addr, data);
return bitmapRead(addr, data);
}
}
auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
auto SA1::mmcSA1Write(uint addr, uint8 data) -> void {
synchronizeCPU();
if(mmio.sw46 == 0) {
//$40-43:0000-ffff x 32 projection
@ -217,11 +217,11 @@ auto SA1::mmc_sa1_write(uint addr, uint8 data) -> void {
} else {
//$60-6f:0000-ffff x 128 projection
addr = bus.mirror(mmio.cbm * 0x2000 + (addr & 0x1fff), 0x100000);
bitmap_write(addr, data);
bitmapWrite(addr, data);
}
}
auto SA1::bitmap_read(uint addr, uint8 data) -> uint8 {
auto SA1::bitmapRead(uint addr, uint8 data) -> uint8 {
if(mmio.bbf == 0) {
//4bpp
uint shift = addr & 1;
@ -243,7 +243,7 @@ auto SA1::bitmap_read(uint addr, uint8 data) -> uint8 {
}
}
auto SA1::bitmap_write(uint addr, uint8 data) -> void {
auto SA1::bitmapWrite(uint addr, uint8 data) -> void {
if(mmio.bbf == 0) {
//4bpp
uint shift = addr & 1;

View File

@ -1,371 +1,3 @@
//(CCNT) SA-1 control
auto SA1::mmio_w2200(uint8 data) -> void {
if(mmio.sa1_resb && !(data & 0x80)) {
//reset SA-1 CPU
r.pc.w = mmio.crv;
r.pc.b = 0x00;
}
mmio.sa1_irq = (data & 0x80);
mmio.sa1_rdyb = (data & 0x40);
mmio.sa1_resb = (data & 0x20);
mmio.sa1_nmi = (data & 0x10);
mmio.smeg = (data & 0x0f);
if(mmio.sa1_irq) {
mmio.sa1_irqfl = true;
if(mmio.sa1_irqen) mmio.sa1_irqcl = 0;
}
if(mmio.sa1_nmi) {
mmio.sa1_nmifl = true;
if(mmio.sa1_nmien) mmio.sa1_nmicl = 0;
}
}
//(SIE) S-CPU interrupt enable
auto SA1::mmio_w2201(uint8 data) -> void {
if(!mmio.cpu_irqen && (data & 0x80)) {
if(mmio.cpu_irqfl) {
mmio.cpu_irqcl = 0;
cpu.r.irq = 1;
}
}
if(!mmio.chdma_irqen && (data & 0x20)) {
if(mmio.chdma_irqfl) {
mmio.chdma_irqcl = 0;
cpu.r.irq = 1;
}
}
mmio.cpu_irqen = (data & 0x80);
mmio.chdma_irqen = (data & 0x20);
}
//(SIC) S-CPU interrupt clear
auto SA1::mmio_w2202(uint8 data) -> void {
mmio.cpu_irqcl = (data & 0x80);
mmio.chdma_irqcl = (data & 0x20);
if(mmio.cpu_irqcl ) mmio.cpu_irqfl = false;
if(mmio.chdma_irqcl) mmio.chdma_irqfl = false;
if(!mmio.cpu_irqfl && !mmio.chdma_irqfl) cpu.r.irq = 0;
}
//(CRV) SA-1 reset vector
auto SA1::mmio_w2203(uint8 data) -> void { mmio.crv = (mmio.crv & 0xff00) | data; }
auto SA1::mmio_w2204(uint8 data) -> void { mmio.crv = (data << 8) | (mmio.crv & 0xff); }
//(CNV) SA-1 NMI vector
auto SA1::mmio_w2205(uint8 data) -> void { mmio.cnv = (mmio.cnv & 0xff00) | data; }
auto SA1::mmio_w2206(uint8 data) -> void { mmio.cnv = (data << 8) | (mmio.cnv & 0xff); }
//(CIV) SA-1 IRQ vector
auto SA1::mmio_w2207(uint8 data) -> void { mmio.civ = (mmio.civ & 0xff00) | data; }
auto SA1::mmio_w2208(uint8 data) -> void { mmio.civ = (data << 8) | (mmio.civ & 0xff); }
//(SCNT) S-CPU control
auto SA1::mmio_w2209(uint8 data) -> void {
mmio.cpu_irq = (data & 0x80);
mmio.cpu_ivsw = (data & 0x40);
mmio.cpu_nvsw = (data & 0x10);
mmio.cmeg = (data & 0x0f);
if(mmio.cpu_irq) {
mmio.cpu_irqfl = true;
if(mmio.cpu_irqen) {
mmio.cpu_irqcl = 0;
cpu.r.irq = 1;
}
}
}
//(CIE) SA-1 interrupt enable
auto SA1::mmio_w220a(uint8 data) -> void {
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0;
if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0;
if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0;
mmio.sa1_irqen = (data & 0x80);
mmio.timer_irqen = (data & 0x40);
mmio.dma_irqen = (data & 0x20);
mmio.sa1_nmien = (data & 0x10);
}
//(CIC) SA-1 interrupt clear
auto SA1::mmio_w220b(uint8 data) -> void {
mmio.sa1_irqcl = (data & 0x80);
mmio.timer_irqcl = (data & 0x40);
mmio.dma_irqcl = (data & 0x20);
mmio.sa1_nmicl = (data & 0x10);
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
if(mmio.timer_irqcl) mmio.timer_irqfl = false;
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
}
//(SNV) S-CPU NMI vector
auto SA1::mmio_w220c(uint8 data) -> void { mmio.snv = (mmio.snv & 0xff00) | data; }
auto SA1::mmio_w220d(uint8 data) -> void { mmio.snv = (data << 8) | (mmio.snv & 0xff); }
//(SIV) S-CPU IRQ vector
auto SA1::mmio_w220e(uint8 data) -> void { mmio.siv = (mmio.siv & 0xff00) | data; }
auto SA1::mmio_w220f(uint8 data) -> void { mmio.siv = (data << 8) | (mmio.siv & 0xff); }
//(TMC) H/V timer control
auto SA1::mmio_w2210(uint8 data) -> void {
mmio.hvselb = (data & 0x80);
mmio.ven = (data & 0x02);
mmio.hen = (data & 0x01);
}
//(CTR) SA-1 timer restart
auto SA1::mmio_w2211(uint8 data) -> void {
status.vcounter = 0;
status.hcounter = 0;
}
//(HCNT) H-count
auto SA1::mmio_w2212(uint8 data) -> void { mmio.hcnt = (mmio.hcnt & 0xff00) | (data << 0); }
auto SA1::mmio_w2213(uint8 data) -> void { mmio.hcnt = (mmio.hcnt & 0x00ff) | (data << 8); }
//(VCNT) V-count
auto SA1::mmio_w2214(uint8 data) -> void { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); }
auto SA1::mmio_w2215(uint8 data) -> void { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); }
//(CXB) Super MMC bank C
auto SA1::mmio_w2220(uint8 data) -> void {
mmio.cbmode = (data & 0x80);
mmio.cb = (data & 0x07);
}
//(DXB) Super MMC bank D
auto SA1::mmio_w2221(uint8 data) -> void {
mmio.dbmode = (data & 0x80);
mmio.db = (data & 0x07);
}
//(EXB) Super MMC bank E
auto SA1::mmio_w2222(uint8 data) -> void {
mmio.ebmode = (data & 0x80);
mmio.eb = (data & 0x07);
}
//(FXB) Super MMC bank F
auto SA1::mmio_w2223(uint8 data) -> void {
mmio.fbmode = (data & 0x80);
mmio.fb = (data & 0x07);
}
//(BMAPS) S-CPU BW-RAM address mapping
auto SA1::mmio_w2224(uint8 data) -> void {
mmio.sbm = (data & 0x1f);
}
//(BMAP) SA-1 BW-RAM address mapping
auto SA1::mmio_w2225(uint8 data) -> void {
mmio.sw46 = (data & 0x80);
mmio.cbm = (data & 0x7f);
}
//(SWBE) S-CPU BW-RAM write enable
auto SA1::mmio_w2226(uint8 data) -> void {
mmio.swen = (data & 0x80);
}
//(CWBE) SA-1 BW-RAM write enable
auto SA1::mmio_w2227(uint8 data) -> void {
mmio.cwen = (data & 0x80);
}
//(BWPA) BW-RAM write-protected area
auto SA1::mmio_w2228(uint8 data) -> void {
mmio.bwp = (data & 0x0f);
}
//(SIWP) S-CPU I-RAM write protection
auto SA1::mmio_w2229(uint8 data) -> void {
mmio.siwp = data;
}
//(CIWP) SA-1 I-RAM write protection
auto SA1::mmio_w222a(uint8 data) -> void {
mmio.ciwp = data;
}
//(DCNT) DMA control
auto SA1::mmio_w2230(uint8 data) -> void {
mmio.dmaen = (data & 0x80);
mmio.dprio = (data & 0x40);
mmio.cden = (data & 0x20);
mmio.cdsel = (data & 0x10);
mmio.dd = (data & 0x04);
mmio.sd = (data & 0x03);
if(mmio.dmaen == 0) dma.line = 0;
}
//(CDMA) character conversion DMA parameters
auto SA1::mmio_w2231(uint8 data) -> void {
mmio.chdend = (data & 0x80);
mmio.dmasize = (data >> 2) & 7;
mmio.dmacb = (data & 0x03);
if(mmio.chdend) cpubwram.dma = false;
if(mmio.dmasize > 5) mmio.dmasize = 5;
if(mmio.dmacb > 2) mmio.dmacb = 2;
}
//(SDA) DMA source device start address
auto SA1::mmio_w2232(uint8 data) -> void { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); }
auto SA1::mmio_w2233(uint8 data) -> void { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); }
auto SA1::mmio_w2234(uint8 data) -> void { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); }
//(DDA) DMA destination start address
auto SA1::mmio_w2235(uint8 data) -> void {
mmio.dda = (mmio.dda & 0xffff00) | (data << 0);
}
auto SA1::mmio_w2236(uint8 data) -> void {
mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
if(mmio.dmaen == true) {
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
dma_normal();
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
dma_cc1();
}
}
}
auto SA1::mmio_w2237(uint8 data) -> void {
mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
if(mmio.dmaen == true) {
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
dma_normal();
}
}
}
//(DTC) DMA terminal counter
auto SA1::mmio_w2238(uint8 data) -> void { mmio.dtc = (mmio.dtc & 0xff00) | (data << 0); }
auto SA1::mmio_w2239(uint8 data) -> void { mmio.dtc = (mmio.dtc & 0x00ff) | (data << 8); }
//(BBF) BW-RAM bitmap format
auto SA1::mmio_w223f(uint8 data) -> void {
mmio.bbf = (data & 0x80);
}
//(BRF) bitmap register files
auto SA1::mmio_w2240(uint8 data) -> void { mmio.brf[ 0] = data; }
auto SA1::mmio_w2241(uint8 data) -> void { mmio.brf[ 1] = data; }
auto SA1::mmio_w2242(uint8 data) -> void { mmio.brf[ 2] = data; }
auto SA1::mmio_w2243(uint8 data) -> void { mmio.brf[ 3] = data; }
auto SA1::mmio_w2244(uint8 data) -> void { mmio.brf[ 4] = data; }
auto SA1::mmio_w2245(uint8 data) -> void { mmio.brf[ 5] = data; }
auto SA1::mmio_w2246(uint8 data) -> void { mmio.brf[ 6] = data; }
auto SA1::mmio_w2247(uint8 data) -> void { mmio.brf[ 7] = data;
if(mmio.dmaen == true) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dma_cc2();
}
}
}
auto SA1::mmio_w2248(uint8 data) -> void { mmio.brf[ 8] = data; }
auto SA1::mmio_w2249(uint8 data) -> void { mmio.brf[ 9] = data; }
auto SA1::mmio_w224a(uint8 data) -> void { mmio.brf[10] = data; }
auto SA1::mmio_w224b(uint8 data) -> void { mmio.brf[11] = data; }
auto SA1::mmio_w224c(uint8 data) -> void { mmio.brf[12] = data; }
auto SA1::mmio_w224d(uint8 data) -> void { mmio.brf[13] = data; }
auto SA1::mmio_w224e(uint8 data) -> void { mmio.brf[14] = data; }
auto SA1::mmio_w224f(uint8 data) -> void { mmio.brf[15] = data;
if(mmio.dmaen == true) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dma_cc2();
}
}
}
//(MCNT) arithmetic control
auto SA1::mmio_w2250(uint8 data) -> void {
mmio.acm = (data & 0x02);
mmio.md = (data & 0x01);
if(mmio.acm) mmio.mr = 0;
}
//(MAL) multiplicand / dividend low
auto SA1::mmio_w2251(uint8 data) -> void {
mmio.ma = (mmio.ma & 0xff00) | data;
}
//(MAH) multiplicand / dividend high
auto SA1::mmio_w2252(uint8 data) -> void {
mmio.ma = (data << 8) | (mmio.ma & 0x00ff);
}
//(MBL) multiplier / divisor low
auto SA1::mmio_w2253(uint8 data) -> void {
mmio.mb = (mmio.mb & 0xff00) | data;
}
//(MBH) multiplier / divisor high
//multiplication / cumulative sum only resets MB
//division resets both MA and MB
auto SA1::mmio_w2254(uint8 data) -> void {
mmio.mb = (data << 8) | (mmio.mb & 0x00ff);
if(mmio.acm == 0) {
if(mmio.md == 0) {
//signed multiplication
mmio.mr = (int16)mmio.ma * (int16)mmio.mb;
mmio.mb = 0;
} else {
//unsigned division
if(mmio.mb == 0) {
mmio.mr = 0;
} else {
int16 quotient = (int16)mmio.ma / (uint16)mmio.mb;
uint16 remainder = (int16)mmio.ma % (uint16)mmio.mb;
mmio.mr = (remainder << 16) | quotient;
}
mmio.ma = 0;
mmio.mb = 0;
}
} else {
//sigma (accumulative multiplication)
mmio.mr += (int16)mmio.ma * (int16)mmio.mb;
mmio.overflow = (mmio.mr >= (1ULL << 40));
mmio.mr &= (1ULL << 40) - 1;
mmio.mb = 0;
}
}
//(VBD) variable-length bit processing
auto SA1::mmio_w2258(uint8 data) -> void {
mmio.hl = (data & 0x80);
mmio.vb = (data & 0x0f);
if(mmio.vb == 0) mmio.vb = 16;
if(mmio.hl == 0) {
//fixed mode
mmio.vbit += mmio.vb;
mmio.va += (mmio.vbit >> 3);
mmio.vbit &= 7;
}
}
//(VDA) variable-length bit game pak ROM start address
auto SA1::mmio_w2259(uint8 data) -> void { mmio.va = (mmio.va & 0xffff00) | (data << 0); }
auto SA1::mmio_w225a(uint8 data) -> void { mmio.va = (mmio.va & 0xff00ff) | (data << 8); }
auto SA1::mmio_w225b(uint8 data) -> void { mmio.va = (mmio.va & 0x00ffff) | (data << 16); mmio.vbit = 0; }
auto SA1::readIO(uint24 addr, uint8) -> uint8 {
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
@ -422,9 +54,9 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 {
//(VDPL) variable-length data read port low
case 0x230c: {
uint24 data;
data.byte(0) = vbr_read(mmio.va + 0);
data.byte(1) = vbr_read(mmio.va + 1);
data.byte(2) = vbr_read(mmio.va + 2);
data.byte(0) = vbrRead(mmio.va + 0);
data.byte(1) = vbrRead(mmio.va + 1);
data.byte(2) = vbrRead(mmio.va + 2);
data >>= mmio.vbit;
return data >> 0;
@ -433,9 +65,9 @@ auto SA1::readIO(uint24 addr, uint8) -> uint8 {
//(VDPH) variable-length data read port high
case 0x230d: {
uint24 data;
data.byte(0) = vbr_read(mmio.va + 0);
data.byte(1) = vbr_read(mmio.va + 1);
data.byte(2) = vbr_read(mmio.va + 2);
data.byte(0) = vbrRead(mmio.va + 0);
data.byte(1) = vbrRead(mmio.va + 1);
data.byte(2) = vbrRead(mmio.va + 2);
data >>= mmio.vbit;
if(mmio.hl == 1) {
@ -462,80 +94,396 @@ auto SA1::writeIO(uint24 addr, uint8 data) -> void {
(co_active() == cpu.thread ? cpu.synchronizeCoprocessors() : synchronizeCPU());
switch(0x2200 | addr.bits(0,7)) {
case 0x2200: return mmio_w2200(data);
case 0x2201: return mmio_w2201(data);
case 0x2202: return mmio_w2202(data);
case 0x2203: return mmio_w2203(data);
case 0x2204: return mmio_w2204(data);
case 0x2205: return mmio_w2205(data);
case 0x2206: return mmio_w2206(data);
case 0x2207: return mmio_w2207(data);
case 0x2208: return mmio_w2208(data);
case 0x2209: return mmio_w2209(data);
case 0x220a: return mmio_w220a(data);
case 0x220b: return mmio_w220b(data);
case 0x220c: return mmio_w220c(data);
case 0x220d: return mmio_w220d(data);
case 0x220e: return mmio_w220e(data);
case 0x220f: return mmio_w220f(data);
case 0x2210: return mmio_w2210(data);
case 0x2211: return mmio_w2211(data);
case 0x2212: return mmio_w2212(data);
case 0x2213: return mmio_w2213(data);
case 0x2214: return mmio_w2214(data);
case 0x2215: return mmio_w2215(data);
//(CCNT) SA-1 control
case 0x2200: {
if(mmio.sa1_resb && !(data & 0x80)) {
//reset SA-1 CPU
r.pc.w = mmio.crv;
r.pc.b = 0x00;
}
case 0x2220: return mmio_w2220(data);
case 0x2221: return mmio_w2221(data);
case 0x2222: return mmio_w2222(data);
case 0x2223: return mmio_w2223(data);
case 0x2224: return mmio_w2224(data);
case 0x2225: return mmio_w2225(data);
case 0x2226: return mmio_w2226(data);
case 0x2227: return mmio_w2227(data);
case 0x2228: return mmio_w2228(data);
case 0x2229: return mmio_w2229(data);
case 0x222a: return mmio_w222a(data);
mmio.sa1_irq = (data & 0x80);
mmio.sa1_rdyb = (data & 0x40);
mmio.sa1_resb = (data & 0x20);
mmio.sa1_nmi = (data & 0x10);
mmio.smeg = (data & 0x0f);
case 0x2230: return mmio_w2230(data);
case 0x2231: return mmio_w2231(data);
case 0x2232: return mmio_w2232(data);
case 0x2233: return mmio_w2233(data);
case 0x2234: return mmio_w2234(data);
case 0x2235: return mmio_w2235(data);
case 0x2236: return mmio_w2236(data);
case 0x2237: return mmio_w2237(data);
case 0x2238: return mmio_w2238(data);
case 0x2239: return mmio_w2239(data);
if(mmio.sa1_irq) {
mmio.sa1_irqfl = true;
if(mmio.sa1_irqen) mmio.sa1_irqcl = 0;
}
case 0x223f: return mmio_w223f(data);
case 0x2240: return mmio_w2240(data);
case 0x2241: return mmio_w2241(data);
case 0x2242: return mmio_w2242(data);
case 0x2243: return mmio_w2243(data);
case 0x2244: return mmio_w2244(data);
case 0x2245: return mmio_w2245(data);
case 0x2246: return mmio_w2246(data);
case 0x2247: return mmio_w2247(data);
case 0x2248: return mmio_w2248(data);
case 0x2249: return mmio_w2249(data);
case 0x224a: return mmio_w224a(data);
case 0x224b: return mmio_w224b(data);
case 0x224c: return mmio_w224c(data);
case 0x224d: return mmio_w224d(data);
case 0x224e: return mmio_w224e(data);
case 0x224f: return mmio_w224f(data);
if(mmio.sa1_nmi) {
mmio.sa1_nmifl = true;
if(mmio.sa1_nmien) mmio.sa1_nmicl = 0;
}
case 0x2250: return mmio_w2250(data);
case 0x2251: return mmio_w2251(data);
case 0x2252: return mmio_w2252(data);
case 0x2253: return mmio_w2253(data);
case 0x2254: return mmio_w2254(data);
return;
}
//(SIE) S-CPU interrupt enable
case 0x2201: {
if(!mmio.cpu_irqen && (data & 0x80)) {
if(mmio.cpu_irqfl) {
mmio.cpu_irqcl = 0;
cpu.r.irq = 1;
}
}
if(!mmio.chdma_irqen && (data & 0x20)) {
if(mmio.chdma_irqfl) {
mmio.chdma_irqcl = 0;
cpu.r.irq = 1;
}
}
mmio.cpu_irqen = (data & 0x80);
mmio.chdma_irqen = (data & 0x20);
return;
}
//(SIC) S-CPU interrupt clear
case 0x2202: {
mmio.cpu_irqcl = (data & 0x80);
mmio.chdma_irqcl = (data & 0x20);
if(mmio.cpu_irqcl ) mmio.cpu_irqfl = false;
if(mmio.chdma_irqcl) mmio.chdma_irqfl = false;
if(!mmio.cpu_irqfl && !mmio.chdma_irqfl) cpu.r.irq = 0;
return;
}
//(CRV) SA-1 reset vector
case 0x2203: { mmio.crv = (mmio.crv & 0xff00) | data; return; }
case 0x2204: { mmio.crv = (data << 8) | (mmio.crv & 0xff); return; }
//(CNV) SA-1 NMI vector
case 0x2205: { mmio.cnv = (mmio.cnv & 0xff00) | data; return; }
case 0x2206: { mmio.cnv = (data << 8) | (mmio.cnv & 0xff); return; }
//(CIV) SA-1 IRQ vector
case 0x2207: { mmio.civ = (mmio.civ & 0xff00) | data; return; }
case 0x2208: { mmio.civ = (data << 8) | (mmio.civ & 0xff); return; }
//(SCNT) S-CPU control
case 0x2209: {
mmio.cpu_irq = (data & 0x80);
mmio.cpu_ivsw = (data & 0x40);
mmio.cpu_nvsw = (data & 0x10);
mmio.cmeg = (data & 0x0f);
if(mmio.cpu_irq) {
mmio.cpu_irqfl = true;
if(mmio.cpu_irqen) {
mmio.cpu_irqcl = 0;
cpu.r.irq = 1;
}
}
return;
}
//(CIE) SA-1 interrupt enable
case 0x220a: {
if(!mmio.sa1_irqen && (data & 0x80) && mmio.sa1_irqfl ) mmio.sa1_irqcl = 0;
if(!mmio.timer_irqen && (data & 0x40) && mmio.timer_irqfl) mmio.timer_irqcl = 0;
if(!mmio.dma_irqen && (data & 0x20) && mmio.dma_irqfl ) mmio.dma_irqcl = 0;
if(!mmio.sa1_nmien && (data & 0x10) && mmio.sa1_nmifl ) mmio.sa1_nmicl = 0;
mmio.sa1_irqen = (data & 0x80);
mmio.timer_irqen = (data & 0x40);
mmio.dma_irqen = (data & 0x20);
mmio.sa1_nmien = (data & 0x10);
return;
}
//(CIC) SA-1 interrupt clear
case 0x220b: {
mmio.sa1_irqcl = (data & 0x80);
mmio.timer_irqcl = (data & 0x40);
mmio.dma_irqcl = (data & 0x20);
mmio.sa1_nmicl = (data & 0x10);
if(mmio.sa1_irqcl) mmio.sa1_irqfl = false;
if(mmio.timer_irqcl) mmio.timer_irqfl = false;
if(mmio.dma_irqcl) mmio.dma_irqfl = false;
if(mmio.sa1_nmicl) mmio.sa1_nmifl = false;
return;
}
//(SNV) S-CPU NMI vector
case 0x220c: { mmio.snv = (mmio.snv & 0xff00) | data; return; }
case 0x220d: { mmio.snv = (data << 8) | (mmio.snv & 0xff); return; }
//(SIV) S-CPU IRQ vector
case 0x220e: { mmio.siv = (mmio.siv & 0xff00) | data; return; }
case 0x220f: { mmio.siv = (data << 8) | (mmio.siv & 0xff); return; }
//(TMC) H/V timer control
case 0x2210: {
mmio.hvselb = (data & 0x80);
mmio.ven = (data & 0x02);
mmio.hen = (data & 0x01);
return;
}
//(CTR) SA-1 timer restart
case 0x2211: {
status.vcounter = 0;
status.hcounter = 0;
return;
}
//(HCNT) H-count
case 0x2212: { mmio.hcnt = (mmio.hcnt & 0xff00) | (data << 0); return; }
case 0x2213: { mmio.hcnt = (mmio.hcnt & 0x00ff) | (data << 8); return; }
//(VCNT) V-count
case 0x2214: { mmio.vcnt = (mmio.vcnt & 0xff00) | (data << 0); return; }
case 0x2215: { mmio.vcnt = (mmio.vcnt & 0x00ff) | (data << 8); return; }
//(CXB) Super MMC bank C
case 0x2220: {
mmio.cbmode = (data & 0x80);
mmio.cb = (data & 0x07);
return;
}
//(DXB) Super MMC bank D
case 0x2221: {
mmio.dbmode = (data & 0x80);
mmio.db = (data & 0x07);
return;
}
//(EXB) Super MMC bank E
case 0x2222: {
mmio.ebmode = (data & 0x80);
mmio.eb = (data & 0x07);
return;
}
//(FXB) Super MMC bank F
case 0x2223: {
mmio.fbmode = (data & 0x80);
mmio.fb = (data & 0x07);
return;
}
//(BMAPS) S-CPU BW-RAM address mapping
case 0x2224: {
mmio.sbm = (data & 0x1f);
return;
}
//(BMAP) SA-1 BW-RAM address mapping
case 0x2225: {
mmio.sw46 = (data & 0x80);
mmio.cbm = (data & 0x7f);
return;
}
//(SWBE) S-CPU BW-RAM write enable
case 0x2226: {
mmio.swen = (data & 0x80);
return;
}
//(CWBE) SA-1 BW-RAM write enable
case 0x2227: {
mmio.cwen = (data & 0x80);
return;
}
//(BWPA) BW-RAM write-protected area
case 0x2228: {
mmio.bwp = (data & 0x0f);
return;
}
//(SIWP) S-CPU I-RAM write protection
case 0x2229: {
mmio.siwp = data;
return;
}
//(CIWP) SA-1 I-RAM write protection
case 0x222a: {
mmio.ciwp = data;
return;
}
//(DCNT) DMA control
case 0x2230: {
mmio.dmaen = (data & 0x80);
mmio.dprio = (data & 0x40);
mmio.cden = (data & 0x20);
mmio.cdsel = (data & 0x10);
mmio.dd = (data & 0x04);
mmio.sd = (data & 0x03);
if(mmio.dmaen == 0) dma.line = 0;
return;
}
//(CDMA) character conversion DMA parameters
case 0x2231: {
mmio.chdend = (data & 0x80);
mmio.dmasize = (data >> 2) & 7;
mmio.dmacb = (data & 0x03);
if(mmio.chdend) cpubwram.dma = false;
if(mmio.dmasize > 5) mmio.dmasize = 5;
if(mmio.dmacb > 2) mmio.dmacb = 2;
return;
}
//(SDA) DMA source device start address
case 0x2232: { mmio.dsa = (mmio.dsa & 0xffff00) | (data << 0); return; }
case 0x2233: { mmio.dsa = (mmio.dsa & 0xff00ff) | (data << 8); return; }
case 0x2234: { mmio.dsa = (mmio.dsa & 0x00ffff) | (data << 16); return; }
//(DDA) DMA destination start address
case 0x2235: { mmio.dda = (mmio.dda & 0xffff00) | (data << 0); return; }
case 0x2236: { mmio.dda = (mmio.dda & 0xff00ff) | (data << 8);
if(mmio.dmaen) {
if(mmio.cden == 0 && mmio.dd == DMA::DestIRAM) {
dmaNormal();
} else if(mmio.cden == 1 && mmio.cdsel == 1) {
dmaCC1();
}
}
return;
}
case 0x2237: { mmio.dda = (mmio.dda & 0x00ffff) | (data << 16);
if(mmio.dmaen) {
if(mmio.cden == 0 && mmio.dd == DMA::DestBWRAM) {
dmaNormal();
}
}
return;
}
//(DTC) DMA terminal counter
case 0x2238: { mmio.dtc = (mmio.dtc & 0xff00) | (data << 0); return; }
case 0x2239: { mmio.dtc = (mmio.dtc & 0x00ff) | (data << 8); return; }
//(BBF) BW-RAM bitmap format
case 0x223f: { mmio.bbf = (data & 0x80); return; }
//(BRF) bitmap register files
case 0x2240: { mmio.brf[ 0] = data; return; }
case 0x2241: { mmio.brf[ 1] = data; return; }
case 0x2242: { mmio.brf[ 2] = data; return; }
case 0x2243: { mmio.brf[ 3] = data; return; }
case 0x2244: { mmio.brf[ 4] = data; return; }
case 0x2245: { mmio.brf[ 5] = data; return; }
case 0x2246: { mmio.brf[ 6] = data; return; }
case 0x2247: { mmio.brf[ 7] = data;
if(mmio.dmaen) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dmaCC2();
}
}
return;
}
case 0x2248: { mmio.brf[ 8] = data; return; }
case 0x2249: { mmio.brf[ 9] = data; return; }
case 0x224a: { mmio.brf[10] = data; return; }
case 0x224b: { mmio.brf[11] = data; return; }
case 0x224c: { mmio.brf[12] = data; return; }
case 0x224d: { mmio.brf[13] = data; return; }
case 0x224e: { mmio.brf[14] = data; return; }
case 0x224f: { mmio.brf[15] = data;
if(mmio.dmaen) {
if(mmio.cden == 1 && mmio.cdsel == 0) {
dmaCC2();
}
}
return;
}
//(MCNT) arithmetic control
case 0x2250: {
mmio.acm = (data & 0x02);
mmio.md = (data & 0x01);
if(mmio.acm) mmio.mr = 0;
return;
}
//(MAL) multiplicand / dividend low
case 0x2251: {
mmio.ma = (mmio.ma & 0xff00) | data;
return;
}
//(MAH) multiplicand / dividend high
case 0x2252: {
mmio.ma = (data << 8) | (mmio.ma & 0x00ff);
return;
}
//(MBL) multiplier / divisor low
case 0x2253: {
mmio.mb = (mmio.mb & 0xff00) | data;
return;
}
//(MBH) multiplier / divisor high
//multiplication / cumulative sum only resets MB
//division resets both MA and MB
case 0x2254: {
mmio.mb = (data << 8) | (mmio.mb & 0x00ff);
if(mmio.acm == 0) {
if(mmio.md == 0) {
//signed multiplication
mmio.mr = (int16)mmio.ma * (int16)mmio.mb;
mmio.mb = 0;
} else {
//unsigned division
if(mmio.mb == 0) {
mmio.mr = 0;
} else {
int16 quotient = (int16)mmio.ma / (uint16)mmio.mb;
uint16 remainder = (int16)mmio.ma % (uint16)mmio.mb;
mmio.mr = (remainder << 16) | quotient;
}
mmio.ma = 0;
mmio.mb = 0;
}
} else {
//sigma (accumulative multiplication)
mmio.mr += (int16)mmio.ma * (int16)mmio.mb;
mmio.overflow = (mmio.mr >= (1ULL << 40));
mmio.mr &= (1ULL << 40) - 1;
mmio.mb = 0;
}
return;
}
//(VBD) variable-length bit processing
case 0x2258: {
mmio.hl = (data & 0x80);
mmio.vb = (data & 0x0f);
if(mmio.vb == 0) mmio.vb = 16;
if(mmio.hl == 0) {
//fixed mode
mmio.vbit += mmio.vb;
mmio.va += (mmio.vbit >> 3);
mmio.vbit &= 7;
}
return;
}
//(VDA) variable-length bit game pak ROM start address
case 0x2259: { mmio.va = (mmio.va & 0xffff00) | (data << 0); return; }
case 0x225a: { mmio.va = (mmio.va & 0xff00ff) | (data << 8); return; }
case 0x225b: { mmio.va = (mmio.va & 0x00ffff) | (data << 16); mmio.vbit = 0; return; }
case 0x2258: return mmio_w2258(data);
case 0x2259: return mmio_w2259(data);
case 0x225a: return mmio_w225a(data);
case 0x225b: return mmio_w225b(data);
}
}

View File

@ -37,107 +37,36 @@ struct SA1 : Processor::R65816, Cothread {
uint line;
};
auto dma_normal() -> void;
auto dma_cc1() -> void;
auto dma_cc1_read(uint addr) -> uint8;
auto dma_cc2() -> void;
auto dmaNormal() -> void;
auto dmaCC1() -> void;
auto dmaCC1Read(uint addr) -> uint8;
auto dmaCC2() -> void;
//memory.cpp
auto bus_read(uint24 addr, uint8 data) -> uint8;
auto bus_write(uint24 addr, uint8 data) -> void;
auto vbr_read(uint24 addr, uint8 data = 0) -> uint8;
auto busRead(uint24 addr, uint8 data) -> uint8;
auto busWrite(uint24 addr, uint8 data) -> void;
auto vbrRead(uint24 addr, uint8 data = 0) -> uint8;
alwaysinline auto io() -> void override;
alwaysinline auto read(uint24 addr) -> uint8 override;
alwaysinline auto write(uint24 addr, uint8 data) -> void override;
auto mmcrom_read(uint24 addr, uint8 data) -> uint8;
auto mmcrom_write(uint24 addr, uint8 data) -> void;
auto mmcromRead(uint24 addr, uint8 data) -> uint8;
auto mmcromWrite(uint24 addr, uint8 data) -> void;
auto mmcbwram_read(uint24 addr, uint8 data) -> uint8;
auto mmcbwram_write(uint24 addr, uint8 data) -> void;
auto mmcbwramRead(uint24 addr, uint8 data) -> uint8;
auto mmcbwramWrite(uint24 addr, uint8 data) -> void;
auto mmc_sa1_read(uint addr, uint8 data) -> uint8;
auto mmc_sa1_write(uint addr, uint8 data) -> void;
auto mmcSA1Read(uint addr, uint8 data) -> uint8;
auto mmcSA1Write(uint addr, uint8 data) -> void;
auto bitmap_read(uint addr, uint8 data) -> uint8;
auto bitmap_write(uint addr, uint8 data) -> void;
auto bitmapRead(uint addr, uint8 data) -> uint8;
auto bitmapWrite(uint addr, uint8 data) -> void;
//mmio.cpp
auto readIO(uint24 addr, uint8 data) -> uint8;
auto writeIO(uint24 addr, uint8 data) -> void;
//todo: merge these functions into writeIO()
auto mmio_w2200(uint8) -> void; //CCNT
auto mmio_w2201(uint8) -> void; //SIE
auto mmio_w2202(uint8) -> void; //SIC
auto mmio_w2203(uint8) -> void; //CRVL
auto mmio_w2204(uint8) -> void; //CRVH
auto mmio_w2205(uint8) -> void; //CNVL
auto mmio_w2206(uint8) -> void; //CNVH
auto mmio_w2207(uint8) -> void; //CIVL
auto mmio_w2208(uint8) -> void; //CIVH
auto mmio_w2209(uint8) -> void; //SCNT
auto mmio_w220a(uint8) -> void; //CIE
auto mmio_w220b(uint8) -> void; //CIC
auto mmio_w220c(uint8) -> void; //SNVL
auto mmio_w220d(uint8) -> void; //SNVH
auto mmio_w220e(uint8) -> void; //SIVL
auto mmio_w220f(uint8) -> void; //SIVH
auto mmio_w2210(uint8) -> void; //TMC
auto mmio_w2211(uint8) -> void; //CTR
auto mmio_w2212(uint8) -> void; //HCNTL
auto mmio_w2213(uint8) -> void; //HCNTH
auto mmio_w2214(uint8) -> void; //VCNTL
auto mmio_w2215(uint8) -> void; //VCNTH
auto mmio_w2220(uint8) -> void; //CXB
auto mmio_w2221(uint8) -> void; //DXB
auto mmio_w2222(uint8) -> void; //EXB
auto mmio_w2223(uint8) -> void; //FXB
auto mmio_w2224(uint8) -> void; //BMAPS
auto mmio_w2225(uint8) -> void; //BMAP
auto mmio_w2226(uint8) -> void; //SBWE
auto mmio_w2227(uint8) -> void; //CBWE
auto mmio_w2228(uint8) -> void; //BWPA
auto mmio_w2229(uint8) -> void; //SIWP
auto mmio_w222a(uint8) -> void; //CIWP
auto mmio_w2230(uint8) -> void; //DCNT
auto mmio_w2231(uint8) -> void; //CDMA
auto mmio_w2232(uint8) -> void; //SDAL
auto mmio_w2233(uint8) -> void; //SDAH
auto mmio_w2234(uint8) -> void; //SDAB
auto mmio_w2235(uint8) -> void; //DDAL
auto mmio_w2236(uint8) -> void; //DDAH
auto mmio_w2237(uint8) -> void; //DDAB
auto mmio_w2238(uint8) -> void; //DTCL
auto mmio_w2239(uint8) -> void; //DTCH
auto mmio_w223f(uint8) -> void; //BBF
auto mmio_w2240(uint8) -> void; //BRF0
auto mmio_w2241(uint8) -> void; //BRF1
auto mmio_w2242(uint8) -> void; //BRF2
auto mmio_w2243(uint8) -> void; //BRF3
auto mmio_w2244(uint8) -> void; //BRF4
auto mmio_w2245(uint8) -> void; //BRF5
auto mmio_w2246(uint8) -> void; //BRF6
auto mmio_w2247(uint8) -> void; //BRF7
auto mmio_w2248(uint8) -> void; //BRF8
auto mmio_w2249(uint8) -> void; //BRF9
auto mmio_w224a(uint8) -> void; //BRFA
auto mmio_w224b(uint8) -> void; //BRFB
auto mmio_w224c(uint8) -> void; //BRFC
auto mmio_w224d(uint8) -> void; //BRFD
auto mmio_w224e(uint8) -> void; //BRFE
auto mmio_w224f(uint8) -> void; //BRFF
auto mmio_w2250(uint8) -> void; //MCNT
auto mmio_w2251(uint8) -> void; //MAL
auto mmio_w2252(uint8) -> void; //MAH
auto mmio_w2253(uint8) -> void; //MBL
auto mmio_w2254(uint8) -> void; //MBH
auto mmio_w2258(uint8) -> void; //VBD
auto mmio_w2259(uint8) -> void; //VDAL
auto mmio_w225a(uint8) -> void; //VDAH
auto mmio_w225b(uint8) -> void; //VDAB
//serialization.cpp
auto serialize(serializer&) -> void;

View File

@ -10,32 +10,32 @@
auto SDD1::Decompressor::IM::init(uint offset_) -> void {
offset = offset_;
bit_count = 4;
bitCount = 4;
}
auto SDD1::Decompressor::IM::get_codeword(uint8 code_length) -> uint8 {
uint8 codeword;
uint8 comp_count;
auto SDD1::Decompressor::IM::getCodeWord(uint8 codeLength) -> uint8 {
uint8 codeWord;
uint8 compCount;
codeword = sdd1.mmcRead(offset) << bit_count;
bit_count++;
codeWord = sdd1.mmcRead(offset) << bitCount;
bitCount++;
if(codeword & 0x80) {
codeword |= sdd1.mmcRead(offset + 1) >> (9 - bit_count);
bit_count += code_length;
if(codeWord & 0x80) {
codeWord |= sdd1.mmcRead(offset + 1) >> (9 - bitCount);
bitCount += codeLength;
}
if(bit_count & 0x08) {
if(bitCount & 0x08) {
offset++;
bit_count &= 0x07;
bitCount &= 0x07;
}
return codeword;
return codeWord;
}
//golomb-code decoder
const uint8 SDD1::Decompressor::GCD::run_count[] = {
const uint8 SDD1::Decompressor::GCD::runCount[] = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x01, 0x02, 0x00,
0x07, 0x03, 0x05, 0x01, 0x06, 0x02, 0x04, 0x00,
0x0f, 0x07, 0x0b, 0x03, 0x0d, 0x05, 0x09, 0x01,
@ -70,43 +70,43 @@ const uint8 SDD1::Decompressor::GCD::run_count[] = {
0x70, 0x30, 0x50, 0x10, 0x60, 0x20, 0x40, 0x00,
};
auto SDD1::Decompressor::GCD::get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void {
uint8 codeword = self.im.get_codeword(code_number);
auto SDD1::Decompressor::GCD::getRunCount(uint8 codeNumber, uint8& mpsCount, bool& lpsIndex) -> void {
uint8 codeWord = self.im.getCodeWord(codeNumber);
if(codeword & 0x80) {
lps_index = 1;
mps_count = run_count[codeword >> (code_number ^ 0x07)];
if(codeWord & 0x80) {
lpsIndex = 1;
mpsCount = runCount[codeWord >> (codeNumber ^ 0x07)];
} else {
mps_count = 1 << code_number;
mpsCount = 1 << codeNumber;
}
}
//bits generator
auto SDD1::Decompressor::BG::init() -> void {
mps_count = 0;
lps_index = 0;
mpsCount = 0;
lpsIndex = 0;
}
auto SDD1::Decompressor::BG::get_bit(bool& end_of_run) -> uint8 {
if(!(mps_count || lps_index)) self.gcd.get_run_count(code_number, mps_count, lps_index);
auto SDD1::Decompressor::BG::getBit(bool& endOfRun) -> uint8 {
if(!(mpsCount || lpsIndex)) self.gcd.getRunCount(codeNumber, mpsCount, lpsIndex);
uint8 bit;
if(mps_count) {
if(mpsCount) {
bit = 0;
mps_count--;
mpsCount--;
} else {
bit = 1;
lps_index = 0;
lpsIndex = 0;
}
end_of_run = !(mps_count || lps_index);
endOfRun = !(mpsCount || lpsIndex);
return bit;
}
//probability estimation module
const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolution_table[33] = {
const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolutionTable[33] = {
{0, 25, 25},
{0, 2, 1},
{0, 3, 1},
@ -144,112 +144,112 @@ const SDD1::Decompressor::PEM::State SDD1::Decompressor::PEM::evolution_table[33
auto SDD1::Decompressor::PEM::init() -> void {
for(auto n : range(32)) {
context_info[n].status = 0;
context_info[n].mps = 0;
contextInfo[n].status = 0;
contextInfo[n].mps = 0;
}
}
auto SDD1::Decompressor::PEM::get_bit(uint8 context) -> uint8 {
ContextInfo& info = context_info[context];
uint8 current_status = info.status;
uint8 current_mps = info.mps;
const State& s = SDD1::Decompressor::PEM::evolution_table[current_status];
auto SDD1::Decompressor::PEM::getBit(uint8 context) -> uint8 {
ContextInfo& info = contextInfo[context];
uint8 currentStatus = info.status;
uint8 currentMps = info.mps;
const State& s = SDD1::Decompressor::PEM::evolutionTable[currentStatus];
uint8 bit;
bool end_of_run;
switch(s.code_number) {
case 0: bit = self.bg0.get_bit(end_of_run); break;
case 1: bit = self.bg1.get_bit(end_of_run); break;
case 2: bit = self.bg2.get_bit(end_of_run); break;
case 3: bit = self.bg3.get_bit(end_of_run); break;
case 4: bit = self.bg4.get_bit(end_of_run); break;
case 5: bit = self.bg5.get_bit(end_of_run); break;
case 6: bit = self.bg6.get_bit(end_of_run); break;
case 7: bit = self.bg7.get_bit(end_of_run); break;
bool endOfRun;
switch(s.codeNumber) {
case 0: bit = self.bg0.getBit(endOfRun); break;
case 1: bit = self.bg1.getBit(endOfRun); break;
case 2: bit = self.bg2.getBit(endOfRun); break;
case 3: bit = self.bg3.getBit(endOfRun); break;
case 4: bit = self.bg4.getBit(endOfRun); break;
case 5: bit = self.bg5.getBit(endOfRun); break;
case 6: bit = self.bg6.getBit(endOfRun); break;
case 7: bit = self.bg7.getBit(endOfRun); break;
}
if(end_of_run) {
if(endOfRun) {
if(bit) {
if(!(current_status & 0xfe)) info.mps ^= 0x01;
info.status = s.next_if_lps;
if(!(currentStatus & 0xfe)) info.mps ^= 0x01;
info.status = s.nextIfLps;
} else {
info.status = s.next_if_mps;
info.status = s.nextIfMps;
}
}
return bit ^ current_mps;
return bit ^ currentMps;
}
//context model
auto SDD1::Decompressor::CM::init(uint offset) -> void {
bitplanes_info = sdd1.mmcRead(offset) & 0xc0;
context_bits_info = sdd1.mmcRead(offset) & 0x30;
bit_number = 0;
for(auto n : range(8)) previous_bitplane_bits[n] = 0;
switch(bitplanes_info) {
case 0x00: current_bitplane = 1; break;
case 0x40: current_bitplane = 7; break;
case 0x80: current_bitplane = 3; break;
bitplanesInfo = sdd1.mmcRead(offset) & 0xc0;
contextBitsInfo = sdd1.mmcRead(offset) & 0x30;
bitNumber = 0;
for(auto n : range(8)) previousBitplaneBits[n] = 0;
switch(bitplanesInfo) {
case 0x00: currentBitplane = 1; break;
case 0x40: currentBitplane = 7; break;
case 0x80: currentBitplane = 3; break;
}
}
auto SDD1::Decompressor::CM::get_bit() -> uint8 {
switch(bitplanes_info) {
auto SDD1::Decompressor::CM::getBit() -> uint8 {
switch(bitplanesInfo) {
case 0x00:
current_bitplane ^= 0x01;
currentBitplane ^= 0x01;
break;
case 0x40:
current_bitplane ^= 0x01;
if(!(bit_number & 0x7f)) current_bitplane = ((current_bitplane + 2) & 0x07);
currentBitplane ^= 0x01;
if(!(bitNumber & 0x7f)) currentBitplane = ((currentBitplane + 2) & 0x07);
break;
case 0x80:
current_bitplane ^= 0x01;
if(!(bit_number & 0x7f)) current_bitplane ^= 0x02;
currentBitplane ^= 0x01;
if(!(bitNumber & 0x7f)) currentBitplane ^= 0x02;
break;
case 0xc0:
current_bitplane = bit_number & 0x07;
currentBitplane = bitNumber & 0x07;
break;
}
uint16& context_bits = previous_bitplane_bits[current_bitplane];
uint8 current_context = (current_bitplane & 0x01) << 4;
switch(context_bits_info) {
case 0x00: current_context |= ((context_bits & 0x01c0) >> 5) | (context_bits & 0x0001); break;
case 0x10: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0001); break;
case 0x20: current_context |= ((context_bits & 0x00c0) >> 5) | (context_bits & 0x0001); break;
case 0x30: current_context |= ((context_bits & 0x0180) >> 5) | (context_bits & 0x0003); break;
uint16& contextBits = previousBitplaneBits[currentBitplane];
uint8 currentContext = (currentBitplane & 0x01) << 4;
switch(contextBitsInfo) {
case 0x00: currentContext |= ((contextBits & 0x01c0) >> 5) | (contextBits & 0x0001); break;
case 0x10: currentContext |= ((contextBits & 0x0180) >> 5) | (contextBits & 0x0001); break;
case 0x20: currentContext |= ((contextBits & 0x00c0) >> 5) | (contextBits & 0x0001); break;
case 0x30: currentContext |= ((contextBits & 0x0180) >> 5) | (contextBits & 0x0003); break;
}
uint8 bit = self.pem.get_bit(current_context);
context_bits <<= 1;
context_bits |= bit;
bit_number++;
uint8 bit = self.pem.getBit(currentContext);
contextBits <<= 1;
contextBits |= bit;
bitNumber++;
return bit;
}
//output logic
auto SDD1::Decompressor::OL::init(uint offset) -> void {
bitplanes_info = sdd1.mmcRead(offset) & 0xc0;
bitplanesInfo = sdd1.mmcRead(offset) & 0xc0;
r0 = 0x01;
}
auto SDD1::Decompressor::OL::decompress() -> uint8 {
switch(bitplanes_info) {
switch(bitplanesInfo) {
case 0x00: case 0x40: case 0x80:
if(r0 == 0) {
r0 = ~r0;
return r2;
}
for(r0 = 0x80, r1 = 0, r2 = 0; r0; r0 >>= 1) {
if(self.cm.get_bit()) r1 |= r0;
if(self.cm.get_bit()) r2 |= r0;
if(self.cm.getBit()) r1 |= r0;
if(self.cm.getBit()) r2 |= r0;
}
return r1;
case 0xc0:
for(r0 = 0x01, r1 = 0; r0; r0 <<= 1) {
if(self.cm.get_bit()) r1 |= r0;
if(self.cm.getBit()) r1 |= r0;
}
return r1;
}

View File

@ -2,66 +2,66 @@ struct Decompressor {
struct IM { //input manager
IM(SDD1::Decompressor& self) : self(self) {}
auto init(uint offset) -> void;
auto get_codeword(uint8 code_length) -> uint8;
auto getCodeWord(uint8 codeLength) -> uint8;
private:
Decompressor& self;
uint offset;
uint bit_count;
uint bitCount;
};
struct GCD { //golomb-code decoder
GCD(SDD1::Decompressor& self) : self(self) {}
auto get_run_count(uint8 code_number, uint8& mps_count, bool& lps_index) -> void;
auto getRunCount(uint8 codeNumber, uint8& mpsCount, bool& lpsIndex) -> void;
private:
Decompressor& self;
static const uint8 run_count[256];
static const uint8 runCount[256];
};
struct BG { //bits generator
BG(SDD1::Decompressor& self, uint8 code_number) : self(self), code_number(code_number) {}
BG(SDD1::Decompressor& self, uint8 codeNumber) : self(self), codeNumber(codeNumber) {}
auto init() -> void;
auto get_bit(bool& end_of_run) -> uint8;
auto getBit(bool& endOfRun) -> uint8;
private:
Decompressor& self;
const uint8 code_number;
uint8 mps_count;
bool lps_index;
const uint8 codeNumber;
uint8 mpsCount;
bool lpsIndex;
};
struct PEM { //probability estimation module
PEM(SDD1::Decompressor& self) : self(self) {}
auto init() -> void;
auto get_bit(uint8 context) -> uint8;
auto getBit(uint8 context) -> uint8;
private:
Decompressor& self;
struct State {
uint8 code_number;
uint8 next_if_mps;
uint8 next_if_lps;
uint8 codeNumber;
uint8 nextIfMps;
uint8 nextIfLps;
};
static const State evolution_table[33];
static const State evolutionTable[33];
struct ContextInfo {
uint8 status;
uint8 mps;
} context_info[32];
} contextInfo[32];
};
struct CM { //context model
CM(SDD1::Decompressor& self) : self(self) {}
auto init(uint offset) -> void;
uint8 get_bit();
auto getBit() -> uint8;
private:
Decompressor& self;
uint8 bitplanes_info;
uint8 context_bits_info;
uint8 bit_number;
uint8 current_bitplane;
uint16 previous_bitplane_bits[8];
uint8 bitplanesInfo;
uint8 contextBitsInfo;
uint8 bitNumber;
uint8 currentBitplane;
uint16 previousBitplaneBits[8];
};
struct OL { //output logic
@ -71,7 +71,7 @@ struct Decompressor {
private:
Decompressor& self;
uint8 bitplanes_info;
uint8 bitplanesInfo;
uint8 r0, r1, r2;
};

View File

@ -70,7 +70,7 @@ auto SDD1::write(uint24 addr, uint8 data) -> void {
}
auto SDD1::dmaRead(uint24 addr, uint8 data) -> uint8 {
return cpu.dmaPortRead(addr, data);
return cpu.readDMA(addr, data);
}
auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void {
@ -82,7 +82,7 @@ auto SDD1::dmaWrite(uint24 addr, uint8 data) -> void {
case 5: dma[channel].size.byte(0) = data; break;
case 6: dma[channel].size.byte(1) = data; break;
}
return cpu.dmaPortWrite(addr, data);
return cpu.writeDMA(addr, data);
}
auto SDD1::mmcRead(uint24 addr) -> uint8 {

View File

@ -1,5 +1,5 @@
auto SPC7110::alu_multiply() -> void {
add_clocks(30);
auto SPC7110::aluMultiply() -> void {
addClocks(30);
if(r482e & 1) {
//signed 16-bit x 16-bit multiplication
@ -26,8 +26,8 @@ auto SPC7110::alu_multiply() -> void {
r482f &= 0x7f;
}
auto SPC7110::alu_divide() -> void {
add_clocks(40);
auto SPC7110::aluDivide() -> void {
addClocks(40);
if(r482e & 1) {
//signed 32-bit x 16-bit division

View File

@ -1,4 +1,4 @@
auto SPC7110::datarom_read(uint addr) -> uint8 {
auto SPC7110::dataromRead(uint addr) -> uint8 {
uint size = 1 << (r4834 & 3); //size in MB
uint mask = 0x100000 * size - 1;
uint offset = addr & mask;
@ -6,53 +6,53 @@ auto SPC7110::datarom_read(uint addr) -> uint8 {
return drom.read(Bus::mirror(offset, drom.size()));
}
auto SPC7110::data_offset() -> uint { return r4811 | r4812 << 8 | r4813 << 16; }
auto SPC7110::data_adjust() -> uint { return r4814 | r4815 << 8; }
auto SPC7110::data_stride() -> uint { return r4816 | r4817 << 8; }
auto SPC7110::set_data_offset(uint addr) -> void { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
auto SPC7110::set_data_adjust(uint addr) -> void { r4814 = addr; r4815 = addr >> 8; }
auto SPC7110::dataOffset() -> uint { return r4811 | r4812 << 8 | r4813 << 16; }
auto SPC7110::dataAdjust() -> uint { return r4814 | r4815 << 8; }
auto SPC7110::dataStride() -> uint { return r4816 | r4817 << 8; }
auto SPC7110::setDataOffset(uint addr) -> void { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
auto SPC7110::setDataAdjust(uint addr) -> void { r4814 = addr; r4815 = addr >> 8; }
auto SPC7110::data_port_read() -> void {
uint offset = data_offset();
uint adjust = r4818 & 2 ? data_adjust() : 0;
auto SPC7110::dataPortRead() -> void {
uint offset = dataOffset();
uint adjust = r4818 & 2 ? dataAdjust() : 0;
if(r4818 & 8) adjust = (int16)adjust;
r4810 = datarom_read(offset + adjust);
r4810 = dataromRead(offset + adjust);
}
auto SPC7110::data_port_increment_4810() -> void {
uint offset = data_offset();
uint stride = r4818 & 1 ? data_stride() : 1;
uint adjust = data_adjust();
auto SPC7110::dataPortIncrement4810() -> void {
uint offset = dataOffset();
uint stride = r4818 & 1 ? dataStride() : 1;
uint adjust = dataAdjust();
if(r4818 & 4) stride = (int16)stride;
if(r4818 & 8) adjust = (int16)adjust;
if((r4818 & 16) == 0) set_data_offset(offset + stride);
if((r4818 & 16) != 0) set_data_adjust(adjust + stride);
data_port_read();
if((r4818 & 16) == 0) setDataOffset(offset + stride);
if((r4818 & 16) != 0) setDataAdjust(adjust + stride);
dataPortRead();
}
auto SPC7110::data_port_increment_4814() -> void {
auto SPC7110::dataPortIncrement4814() -> void {
if(r4818 >> 5 != 1) return;
uint offset = data_offset();
uint adjust = data_adjust();
uint offset = dataOffset();
uint adjust = dataAdjust();
if(r4818 & 8) adjust = (int16)adjust;
set_data_offset(offset + adjust);
data_port_read();
setDataOffset(offset + adjust);
dataPortRead();
}
auto SPC7110::data_port_increment_4815() -> void {
auto SPC7110::dataPortIncrement4815() -> void {
if(r4818 >> 5 != 2) return;
uint offset = data_offset();
uint adjust = data_adjust();
uint offset = dataOffset();
uint adjust = dataAdjust();
if(r4818 & 8) adjust = (int16)adjust;
set_data_offset(offset + adjust);
data_port_read();
setDataOffset(offset + adjust);
dataPortRead();
}
auto SPC7110::data_port_increment_481a() -> void {
auto SPC7110::dataPortIncrement481a() -> void {
if(r4818 >> 5 != 3) return;
uint offset = data_offset();
uint adjust = data_adjust();
uint offset = dataOffset();
uint adjust = dataAdjust();
if(r4818 & 8) adjust = (int16)adjust;
set_data_offset(offset + adjust);
data_port_read();
setDataOffset(offset + adjust);
dataPortRead();
}

View File

@ -1,48 +1,48 @@
#include "decompressor.cpp"
auto SPC7110::dcu_load_address() -> void {
auto SPC7110::dcuLoadAddress() -> void {
uint table = r4801 | r4802 << 8 | r4803 << 16;
uint index = r4804 << 2;
uint addr = table + index;
dcu_mode = datarom_read(addr + 0);
dcu_addr = datarom_read(addr + 1) << 16;
dcu_addr |= datarom_read(addr + 2) << 8;
dcu_addr |= datarom_read(addr + 3) << 0;
uint address = table + index;
dcuMode = dataromRead(address + 0);
dcuAddress = dataromRead(address + 1) << 16;
dcuAddress |= dataromRead(address + 2) << 8;
dcuAddress |= dataromRead(address + 3) << 0;
}
auto SPC7110::dcu_begin_transfer() -> void {
if(dcu_mode == 3) return; //invalid mode
auto SPC7110::dcuBeginTransfer() -> void {
if(dcuMode == 3) return; //invalid mode
add_clocks(20);
decompressor->initialize(dcu_mode, dcu_addr);
addClocks(20);
decompressor->initialize(dcuMode, dcuAddress);
decompressor->decode();
uint seek = r480b & 2 ? r4805 | r4806 << 8 : 0;
while(seek--) decompressor->decode();
r480c |= 0x80;
dcu_offset = 0;
dcuOffset = 0;
}
auto SPC7110::dcu_read() -> uint8 {
auto SPC7110::dcuRead() -> uint8 {
if((r480c & 0x80) == 0) return 0x00;
if(dcu_offset == 0) {
if(dcuOffset == 0) {
for(auto row : range(8)) {
switch(decompressor->bpp) {
case 1:
dcu_tile[row] = decompressor->result;
dcuTile[row] = decompressor->result;
break;
case 2:
dcu_tile[row * 2 + 0] = decompressor->result >> 0;
dcu_tile[row * 2 + 1] = decompressor->result >> 8;
dcuTile[row * 2 + 0] = decompressor->result >> 0;
dcuTile[row * 2 + 1] = decompressor->result >> 8;
break;
case 4:
dcu_tile[row * 2 + 0] = decompressor->result >> 0;
dcu_tile[row * 2 + 1] = decompressor->result >> 8;
dcu_tile[row * 2 + 16] = decompressor->result >> 16;
dcu_tile[row * 2 + 17] = decompressor->result >> 24;
dcuTile[row * 2 + 0] = decompressor->result >> 0;
dcuTile[row * 2 + 1] = decompressor->result >> 8;
dcuTile[row * 2 + 16] = decompressor->result >> 16;
dcuTile[row * 2 + 17] = decompressor->result >> 24;
break;
}
@ -51,7 +51,7 @@ auto SPC7110::dcu_read() -> uint8 {
}
}
uint8 data = dcu_tile[dcu_offset++];
dcu_offset &= 8 * decompressor->bpp - 1;
uint8 data = dcuTile[dcuOffset++];
dcuOffset &= 8 * decompressor->bpp - 1;
return data;
}

View File

@ -8,7 +8,7 @@ struct Decompressor {
Decompressor(SPC7110& spc7110) : spc7110(spc7110) {}
auto read() -> uint8 {
return spc7110.datarom_read(offset++);
return spc7110.dataromRead(offset++);
}
//inverse morton code transform: unpack big-endian packed pixels

View File

@ -13,11 +13,11 @@ auto SPC7110::serialize(serializer& s) -> void {
s.integer(r480b);
s.integer(r480c);
s.integer(dcu_pending);
s.integer(dcu_mode);
s.integer(dcu_addr);
s.integer(dcu_offset);
s.array(dcu_tile);
s.integer(dcuPending);
s.integer(dcuMode);
s.integer(dcuAddress);
s.integer(dcuOffset);
s.array(dcuTile);
decompressor->serialize(s);
s.integer(r4810);
@ -48,8 +48,8 @@ auto SPC7110::serialize(serializer& s) -> void {
s.integer(r482e);
s.integer(r482f);
s.integer(mul_pending);
s.integer(div_pending);
s.integer(mulPending);
s.integer(divPending);
s.integer(r4830);
s.integer(r4831);

View File

@ -21,13 +21,13 @@ auto SPC7110::Enter() -> void {
}
auto SPC7110::main() -> void {
if(dcu_pending) { dcu_pending = 0; dcu_begin_transfer(); }
if(mul_pending) { mul_pending = 0; alu_multiply(); }
if(div_pending) { div_pending = 0; alu_divide(); }
add_clocks(1);
if(dcuPending) { dcuPending = 0; dcuBeginTransfer(); }
if(mulPending) { mulPending = 0; aluMultiply(); }
if(divPending) { divPending = 0; aluDivide(); }
addClocks(1);
}
auto SPC7110::add_clocks(uint clocks) -> void {
auto SPC7110::addClocks(uint clocks) -> void {
step(clocks);
synchronizeCPU();
}
@ -62,9 +62,9 @@ auto SPC7110::reset() -> void {
r480b = 0x00;
r480c = 0x00;
dcu_pending = 0;
dcu_mode = 0;
dcu_addr = 0;
dcuPending = 0;
dcuMode = 0;
dcuAddress = 0;
r4810 = 0x00;
r4811 = 0x00;
@ -94,8 +94,8 @@ auto SPC7110::reset() -> void {
r482e = 0x00;
r482f = 0x00;
mul_pending = 0;
div_pending = 0;
mulPending = 0;
divPending = 0;
r4830 = 0x00;
r4831 = 0x00;
@ -119,7 +119,7 @@ auto SPC7110::read(uint24 addr, uint8 data) -> uint8 {
counter--;
r4809 = counter >> 0;
r480a = counter >> 8;
return dcu_read();
return dcuRead();
}
case 0x4801: return r4801;
case 0x4802: return r4802;
@ -139,7 +139,7 @@ auto SPC7110::read(uint24 addr, uint8 data) -> uint8 {
//==============
case 0x4810: {
data = r4810;
data_port_increment_4810();
dataPortIncrement4810();
return data;
}
case 0x4811: return r4811;
@ -151,7 +151,7 @@ auto SPC7110::read(uint24 addr, uint8 data) -> uint8 {
case 0x4817: return r4817;
case 0x4818: return r4818;
case 0x481a: {
data_port_increment_481a();
dataPortIncrement481a();
return 0x00;
}
@ -201,9 +201,9 @@ auto SPC7110::write(uint24 addr, uint8 data) -> void {
case 0x4801: r4801 = data; break;
case 0x4802: r4802 = data; break;
case 0x4803: r4803 = data; break;
case 0x4804: r4804 = data; dcu_load_address(); break;
case 0x4804: r4804 = data; dcuLoadAddress(); break;
case 0x4805: r4805 = data; break;
case 0x4806: r4806 = data; r480c &= 0x7f; dcu_pending = 1; break;
case 0x4806: r4806 = data; r480c &= 0x7f; dcuPending = 1; break;
case 0x4807: r4807 = data; break;
case 0x4808: break;
case 0x4809: r4809 = data; break;
@ -215,12 +215,12 @@ auto SPC7110::write(uint24 addr, uint8 data) -> void {
//==============
case 0x4811: r4811 = data; break;
case 0x4812: r4812 = data; break;
case 0x4813: r4813 = data; data_port_read(); break;
case 0x4814: r4814 = data; data_port_increment_4814(); break;
case 0x4815: r4815 = data; if(r4818 & 2) data_port_read(); data_port_increment_4815(); break;
case 0x4813: r4813 = data; dataPortRead(); break;
case 0x4814: r4814 = data; dataPortIncrement4814(); break;
case 0x4815: r4815 = data; if(r4818 & 2) dataPortRead(); dataPortIncrement4815(); break;
case 0x4816: r4816 = data; break;
case 0x4817: r4817 = data; break;
case 0x4818: r4818 = data & 0x7f; data_port_read(); break;
case 0x4818: r4818 = data & 0x7f; dataPortRead(); break;
//=====================
//arithmetic logic unit
@ -230,9 +230,9 @@ auto SPC7110::write(uint24 addr, uint8 data) -> void {
case 0x4822: r4822 = data; break;
case 0x4823: r4823 = data; break;
case 0x4824: r4824 = data; break;
case 0x4825: r4825 = data; r482f |= 0x81; mul_pending = 1; break;
case 0x4825: r4825 = data; r482f |= 0x81; mulPending = 1; break;
case 0x4826: r4826 = data; break;
case 0x4827: r4827 = data; r482f |= 0x80; div_pending = 1; break;
case 0x4827: r4827 = data; r482f |= 0x80; divPending = 1; break;
case 0x482e: r482e = data & 0x01; break;
//===================
@ -252,7 +252,7 @@ auto SPC7110::write(uint24 addr, uint8 data) -> void {
//map address=00-3f,80-bf:8000-ffff mask=0x800000 => 00-3f:8000-ffff
//map address=c0-ff:0000-ffff mask=0xc00000 => c0-ff:0000-ffff
auto SPC7110::mcurom_read(uint24 addr, uint8 data) -> uint8 {
auto SPC7110::mcuromRead(uint24 addr, uint8 data) -> uint8 {
uint mask = (1 << (r4834 & 3)) - 1; //8mbit, 16mbit, 32mbit, 64mbit DROM
if(addr < 0x100000) { //$00-0f,80-8f:8000-ffff; $c0-cf:0000-ffff
@ -261,7 +261,7 @@ auto SPC7110::mcurom_read(uint24 addr, uint8 data) -> uint8 {
return prom.read(bus.mirror(0x000000 + addr, prom.size()));
}
addr |= 0x100000 * (r4830 & 7);
return datarom_read(addr);
return dataromRead(addr);
}
if(addr < 0x200000) { //$10-1f,90-9f:8000-ffff; $d0-df:0000-ffff
@ -270,25 +270,25 @@ auto SPC7110::mcurom_read(uint24 addr, uint8 data) -> uint8 {
return prom.read(bus.mirror(0x100000 + addr, prom.size()));
}
addr |= 0x100000 * (r4831 & 7);
return datarom_read(addr);
return dataromRead(addr);
}
if(addr < 0x300000) { //$20-2f,a0-af:8000-ffff; $e0-ef:0000-ffff
addr &= 0x0fffff;
addr |= 0x100000 * (r4832 & 7);
return datarom_read(addr);
return dataromRead(addr);
}
if(addr < 0x400000) { //$30-3f,b0-bf:8000-ffff; $f0-ff:0000-ffff
addr &= 0x0fffff;
addr |= 0x100000 * (r4833 & 7);
return datarom_read(addr);
return dataromRead(addr);
}
return data;
}
auto SPC7110::mcurom_write(uint24 addr, uint8 data) -> void {
auto SPC7110::mcuromWrite(uint24 addr, uint8 data) -> void {
}
//===============
@ -296,7 +296,7 @@ auto SPC7110::mcurom_write(uint24 addr, uint8 data) -> void {
//===============
//map address=00-3f,80-bf:6000-7fff mask=0x80e000 => 00-07:0000-ffff
auto SPC7110::mcuram_read(uint24 addr, uint8) -> uint8 {
auto SPC7110::mcuramRead(uint24 addr, uint8) -> uint8 {
if(r4830 & 0x80) {
addr = bus.mirror(addr, ram.size());
return ram.read(addr);
@ -304,7 +304,7 @@ auto SPC7110::mcuram_read(uint24 addr, uint8) -> uint8 {
return 0x00;
}
auto SPC7110::mcuram_write(uint24 addr, uint8 data) -> void {
auto SPC7110::mcuramWrite(uint24 addr, uint8 data) -> void {
if(r4830 & 0x80) {
addr = bus.mirror(addr, ram.size());
ram.write(addr, data);

View File

@ -12,48 +12,48 @@ struct SPC7110 : Cothread {
auto power() -> void;
auto reset() -> void;
auto add_clocks(uint clocks) -> void;
auto addClocks(uint clocks) -> void;
auto read(uint24 addr, uint8 data) -> uint8;
auto write(uint24 addr, uint8 data) -> void;
auto mcurom_read(uint24 addr, uint8 data) -> uint8;
auto mcurom_write(uint24 addr, uint8 data) -> void;
auto mcuromRead(uint24 addr, uint8 data) -> uint8;
auto mcuromWrite(uint24 addr, uint8 data) -> void;
auto mcuram_read(uint24 addr, uint8 data) -> uint8;
auto mcuram_write(uint24 addr, uint8 data) -> void;
auto mcuramRead(uint24 addr, uint8 data) -> uint8;
auto mcuramWrite(uint24 addr, uint8 data) -> void;
auto serialize(serializer&) -> void;
//dcu.cpp
auto dcu_load_address() -> void;
auto dcu_begin_transfer() -> void;
auto dcu_read() -> uint8;
auto dcuLoadAddress() -> void;
auto dcuBeginTransfer() -> void;
auto dcuRead() -> uint8;
auto deinterleave_1bpp(uint length) -> void;
auto deinterleave_2bpp(uint length) -> void;
auto deinterleave_4bpp(uint length) -> void;
auto deinterleave1bpp(uint length) -> void;
auto deinterleave2bpp(uint length) -> void;
auto deinterleave4bpp(uint length) -> void;
//data.cpp
auto datarom_read(uint addr) -> uint8;
auto dataromRead(uint addr) -> uint8;
auto data_offset() -> uint;
auto data_adjust() -> uint;
auto data_stride() -> uint;
auto dataOffset() -> uint;
auto dataAdjust() -> uint;
auto dataStride() -> uint;
auto set_data_offset(uint addr) -> void;
auto set_data_adjust(uint addr) -> void;
auto setDataOffset(uint addr) -> void;
auto setDataAdjust(uint addr) -> void;
auto data_port_read() -> void;
auto dataPortRead() -> void;
auto data_port_increment_4810() -> void;
auto data_port_increment_4814() -> void;
auto data_port_increment_4815() -> void;
auto data_port_increment_481a() -> void;
auto dataPortIncrement4810() -> void;
auto dataPortIncrement4814() -> void;
auto dataPortIncrement4815() -> void;
auto dataPortIncrement481a() -> void;
//alu.cpp
auto alu_multiply() -> void;
auto alu_divide() -> void;
auto aluMultiply() -> void;
auto aluDivide() -> void;
MappedRAM prom; //program ROM
MappedRAM drom; //data ROM
@ -73,11 +73,11 @@ private:
uint8 r480b; //decompression settings
uint8 r480c; //decompression status
bool dcu_pending;
uint2 dcu_mode;
uint23 dcu_addr;
uint dcu_offset;
uint8 dcu_tile[32];
bool dcuPending;
uint2 dcuMode;
uint23 dcuAddress;
uint dcuOffset;
uint8 dcuTile[32];
Decompressor* decompressor;
//data port unit
@ -110,8 +110,8 @@ private:
uint8 r482e; //math settings
uint8 r482f; //math status
bool mul_pending;
bool div_pending;
bool mulPending;
bool divPending;
//memory control unit
uint8 r4830; //bank 0 mapping + SRAM write enable

View File

@ -11,9 +11,9 @@ CPU cpu;
#include "joypad.cpp"
#include "serialization.cpp"
auto CPU::interruptPending() const -> bool { return status.interrupt_pending; }
auto CPU::interruptPending() const -> bool { return status.interruptPending; }
auto CPU::pio() const -> uint8 { return status.pio; }
auto CPU::joylatch() const -> bool { return status.joypad_strobe_latch; }
auto CPU::joylatch() const -> bool { return status.joypadStrobeLatch; }
CPU::CPU() {
PPUcounter::scanline = {&CPU::scanline, this};
@ -56,32 +56,32 @@ auto CPU::Enter() -> void {
}
auto CPU::main() -> void {
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
status.nmi_pending = false;
if(status.interruptPending) {
status.interruptPending = false;
if(status.nmiPending) {
status.nmiPending = false;
r.vector = r.e ? 0xfffa : 0xffea;
interrupt();
debugger.op_nmi();
} else if(status.irq_pending) {
status.irq_pending = false;
debugger.nmi();
} else if(status.irqPending) {
status.irqPending = false;
r.vector = r.e ? 0xfffe : 0xffee;
interrupt();
debugger.op_irq();
} else if(status.reset_pending) {
status.reset_pending = false;
debugger.irq();
} else if(status.resetPending) {
status.resetPending = false;
addClocks(132);
r.vector = 0xfffc;
interrupt();
} else if(status.power_pending) {
status.power_pending = false;
} else if(status.powerPending) {
status.powerPending = false;
addClocks(186);
r.pc.l = bus.read(0xfffc, r.mdr);
r.pc.h = bus.read(0xfffd, r.mdr);
}
}
debugger.op_exec(r.pc.d);
debugger.execute(r.pc.d);
instruction();
}
@ -99,25 +99,25 @@ auto CPU::power() -> void {
channel.direction = 1;
channel.indirect = true;
channel.unused = true;
channel.reverse_transfer = true;
channel.fixed_transfer = true;
channel.transfer_mode = 7;
channel.reverseTransfer = true;
channel.fixedTransfer = true;
channel.transferMode = 7;
channel.dest_addr = 0xff;
channel.targetAddress = 0xff;
channel.source_addr = 0xffff;
channel.source_bank = 0xff;
channel.sourceAddress = 0xffff;
channel.sourceBank = 0xff;
channel.transfer_size = 0xffff;
channel.indirect_bank = 0xff;
channel.transferSize = 0xffff;
channel.indirectBank = 0xff;
channel.hdma_addr = 0xffff;
channel.line_counter = 0xff;
channel.hdmaAddress = 0xffff;
channel.lineCounter = 0xff;
channel.unknown = 0xff;
}
status.power_pending = true;
status.interrupt_pending = true;
status.powerPending = true;
status.interruptPending = true;
}
auto CPU::reset() -> void {
@ -128,16 +128,16 @@ auto CPU::reset() -> void {
function<auto (uint24, uint8) -> uint8> reader;
function<auto (uint24, uint8) -> void> writer;
reader = {&CPU::apuPortRead, this};
writer = {&CPU::apuPortWrite, this};
reader = {&CPU::readAPU, this};
writer = {&CPU::writeAPU, this};
bus.map(reader, writer, "00-3f,80-bf:2140-217f");
reader = {&CPU::cpuPortRead, this};
writer = {&CPU::cpuPortWrite, this};
reader = {&CPU::readCPU, this};
writer = {&CPU::writeCPU, this};
bus.map(reader, writer, "00-3f,80-bf:2180-2183,4016-4017,4200-421f");
reader = {&CPU::dmaPortRead, this};
writer = {&CPU::dmaPortWrite, this};
reader = {&CPU::readDMA, this};
writer = {&CPU::writeDMA, this};
bus.map(reader, writer, "00-3f,80-bf:4300-437f");
reader = [](uint24 addr, uint8) -> uint8 { return cpu.wram[addr]; };
@ -162,18 +162,18 @@ auto CPU::reset() -> void {
for(auto& port : status.port) port = 0x00;
//$2181-$2183
status.wram_addr = 0x000000;
status.wramAddress = 0x000000;
//$4016-$4017
status.joypad_strobe_latch = 0;
status.joypadStrobeLatch = 0;
status.joypad1_bits = ~0;
status.joypad2_bits = ~0;
//$4200
status.nmi_enabled = false;
status.hirq_enabled = false;
status.virq_enabled = false;
status.auto_joypad_poll = false;
status.nmiEnabled = false;
status.hirqEnabled = false;
status.virqEnabled = false;
status.autoJoypadPoll = false;
//$4201
status.pio = 0xff;
@ -187,11 +187,11 @@ auto CPU::reset() -> void {
status.wrdivb = 0xff;
//$4207-$420a
status.hirq_pos = 0x01ff;
status.virq_pos = 0x01ff;
status.hirqPos = 0x01ff;
status.virqPos = 0x01ff;
//$420d
status.rom_speed = 8;
status.romSpeed = 8;
//$4214-$4217
status.rddiv = 0x0000;
@ -210,11 +210,11 @@ auto CPU::reset() -> void {
//DMA
for(auto& channel : this->channel) {
channel.dma_enabled = false;
channel.hdma_enabled = false;
channel.dmaEnabled = false;
channel.hdmaEnabled = false;
channel.hdma_completed = false;
channel.hdma_do_transfer = false;
channel.hdmaCompleted = false;
channel.hdmaDoTransfer = false;
}
pipe.valid = false;
@ -222,45 +222,45 @@ auto CPU::reset() -> void {
pipe.data = 0;
//Timing
status.clock_count = 0;
status.line_clocks = lineclocks();
status.clockCount = 0;
status.lineClocks = lineclocks();
status.irq_lock = false;
status.dram_refresh_position = (cpu_version == 1 ? 530 : 538);
status.dram_refreshed = false;
status.irqLock = false;
status.dramRefreshPosition = (version == 1 ? 530 : 538);
status.dramRefreshed = false;
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdma_init_triggered = false;
status.hdmaInitPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdmaInitTriggered = false;
status.hdma_position = 1104;
status.hdma_triggered = false;
status.hdmaPosition = 1104;
status.hdmaTriggered = false;
status.nmi_valid = false;
status.nmi_line = false;
status.nmi_transition = false;
status.nmi_pending = false;
status.nmi_hold = false;
status.nmiValid = false;
status.nmiLine = false;
status.nmiTransition = false;
status.nmiPending = false;
status.nmiHold = false;
status.irq_valid = false;
status.irq_line = false;
status.irq_transition = false;
status.irq_pending = false;
status.irq_hold = false;
status.irqValid = false;
status.irqLine = false;
status.irqTransition = false;
status.irqPending = false;
status.irqHold = false;
status.reset_pending = !status.power_pending;
status.interrupt_pending = true;
status.resetPending = !status.powerPending;
status.interruptPending = true;
status.dma_active = false;
status.dma_counter = 0;
status.dma_clocks = 0;
status.dma_pending = false;
status.hdma_pending = false;
status.hdma_mode = 0;
status.dmaActive = false;
status.dmaCounter = 0;
status.dmaClocks = 0;
status.dmaPending = false;
status.hdmaPending = false;
status.hdmaMode = 0;
status.auto_joypad_active = false;
status.auto_joypad_latch = false;
status.auto_joypad_counter = 0;
status.auto_joypad_clock = 0;
status.autoJoypadActive = false;
status.autoJoypadLatch = false;
status.autoJoypadCounter = 0;
status.autoJoypadClock = 0;
}
}

View File

@ -27,16 +27,16 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
auto dmaWrite(bool valid, uint addr = 0, uint8 data = 0) -> void;
auto dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void;
auto dmaAddressB(uint n, uint channel) -> uint8;
auto dmaAddress(uint n) -> uint24;
auto hdmaAddress(uint n) -> uint24;
auto hdmaIndirectAddress(uint n) -> uint24;
inline auto dmaAddressB(uint n, uint channel) -> uint8;
inline auto dmaAddress(uint n) -> uint24;
inline auto hdmaAddress(uint n) -> uint24;
inline auto hdmaIndirectAddress(uint n) -> uint24;
auto dmaEnabledChannels() -> uint;
auto hdmaActive(uint n) -> bool;
auto hdmaActiveAfter(uint s) -> bool;
auto hdmaEnabledChannels() -> uint;
auto hdmaActiveChannels() -> uint;
inline auto dmaEnabledChannels() -> uint;
inline auto hdmaActive(uint n) -> bool;
inline auto hdmaActiveAfter(uint s) -> bool;
inline auto hdmaEnabledChannels() -> uint;
inline auto hdmaActiveChannels() -> uint;
auto dmaRun() -> void;
auto hdmaUpdate(uint n) -> void;
@ -52,12 +52,12 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
auto disassemblerRead(uint24 addr) -> uint8 override;
//mmio.cpp
auto apuPortRead(uint24 addr, uint8 data) -> uint8;
auto cpuPortRead(uint24 addr, uint8 data) -> uint8;
auto dmaPortRead(uint24 addr, uint8 data) -> uint8;
auto apuPortWrite(uint24 addr, uint8 data) -> void;
auto cpuPortWrite(uint24 addr, uint8 data) -> void;
auto dmaPortWrite(uint24 addr, uint8 data) -> void;
auto readAPU(uint24 addr, uint8 data) -> uint8;
auto readCPU(uint24 addr, uint8 data) -> uint8;
auto readDMA(uint24 addr, uint8 data) -> uint8;
auto writeAPU(uint24 addr, uint8 data) -> void;
auto writeCPU(uint24 addr, uint8 data) -> void;
auto writeDMA(uint24 addr, uint8 data) -> void;
//timing.cpp
auto dmaCounter() const -> uint;
@ -89,71 +89,72 @@ struct CPU : Processor::R65816, Thread, PPUcounter {
vector<Thread*> peripherals;
privileged:
uint cpu_version = 2; //allowed: 1, 2
uint version = 2; //allowed: 1, 2
struct Status {
bool interrupt_pending;
bool interruptPending;
uint clock_count;
uint line_clocks;
uint clockCount;
uint lineClocks;
//timing
bool irq_lock;
bool irqLock;
uint dram_refresh_position;
bool dram_refreshed;
uint dramRefreshPosition;
bool dramRefreshed;
uint hdma_init_position;
bool hdma_init_triggered;
uint hdmaInitPosition;
bool hdmaInitTriggered;
uint hdma_position;
bool hdma_triggered;
uint hdmaPosition;
bool hdmaTriggered;
bool nmi_valid;
bool nmi_line;
bool nmi_transition;
bool nmi_pending;
bool nmi_hold;
bool nmiValid;
bool nmiLine;
bool nmiTransition;
bool nmiPending;
bool nmiHold;
bool irq_valid;
bool irq_line;
bool irq_transition;
bool irq_pending;
bool irq_hold;
bool irqValid;
bool irqLine;
bool irqTransition;
bool irqPending;
bool irqHold;
bool power_pending;
bool reset_pending;
bool powerPending;
bool resetPending;
//DMA
bool dma_active;
uint dma_counter;
uint dma_clocks;
bool dma_pending;
bool hdma_pending;
bool hdma_mode; //0 = init, 1 = run
bool dmaActive;
uint dmaCounter;
uint dmaClocks;
bool dmaPending;
bool hdmaPending;
bool hdmaMode; //0 = init, 1 = run
//auto joypad polling
bool auto_joypad_active;
bool auto_joypad_latch;
uint auto_joypad_counter;
uint auto_joypad_clock;
bool autoJoypadActive;
bool autoJoypadLatch;
uint autoJoypadCounter;
uint autoJoypadClock;
//MMIO
//$2140-217f
uint8 port[4];
//$2181-$2183
uint17 wram_addr;
uint17 wramAddress;
//$4016-$4017
bool joypad_strobe_latch;
bool joypadStrobeLatch;
uint32 joypad1_bits;
uint32 joypad2_bits;
//$4200
bool nmi_enabled;
bool hirq_enabled, virq_enabled;
bool auto_joypad_poll;
bool nmiEnabled;
bool hirqEnabled;
bool virqEnabled;
bool autoJoypadPoll;
//$4201
uint8 pio;
@ -167,11 +168,11 @@ privileged:
uint8 wrdivb;
//$4207-$420a
uint9 hirq_pos;
uint9 virq_pos;
uint9 hirqPos;
uint9 virqPos;
//$420d
uint rom_speed;
uint romSpeed;
//$4214-$4217
uint16 rddiv;
@ -192,49 +193,49 @@ privileged:
struct Channel {
//$420b
bool dma_enabled;
bool dmaEnabled;
//$420c
bool hdma_enabled;
bool hdmaEnabled;
//$43x0
bool direction;
bool indirect;
bool unused;
bool reverse_transfer;
bool fixed_transfer;
uint3 transfer_mode;
bool reverseTransfer;
bool fixedTransfer;
uint3 transferMode;
//$43x1
uint8 dest_addr;
uint8 targetAddress;
//$43x2-$43x3
uint16 source_addr;
uint16 sourceAddress;
//$43x4
uint8 source_bank;
uint8 sourceBank;
//$43x5-$43x6
union {
uint16_t transfer_size;
uint16_t indirect_addr;
uint16 transferSize = 0;
uint16_t indirectAddress;
};
//$43x7
uint8 indirect_bank;
uint8 indirectBank;
//$43x8-$43x9
uint16 hdma_addr;
uint16 hdmaAddress;
//$43xa
uint8 line_counter;
uint8 lineCounter;
//$43xb/$43xf
uint8 unknown;
//internal state
bool hdma_completed;
bool hdma_do_transfer;
bool hdmaCompleted;
bool hdmaDoTransfer;
} channel[8];
struct Pipe {
@ -244,11 +245,11 @@ privileged:
} pipe;
struct Debugger {
hook<auto (uint24) -> void> op_exec;
hook<auto (uint24, uint8) -> void> op_read;
hook<auto (uint24, uint8) -> void> op_write;
hook<auto () -> void> op_nmi;
hook<auto () -> void> op_irq;
hook<auto (uint24) -> void> execute;
hook<auto (uint24, uint8) -> void> read;
hook<auto (uint24, uint8) -> void> write;
hook<auto () -> void> nmi;
hook<auto () -> void> irq;
} debugger;
};

View File

@ -1,5 +1,5 @@
auto CPU::dmaAddClocks(uint clocks) -> void {
status.dma_clocks += clocks;
status.dmaClocks += clocks;
addClocks(clocks);
}
@ -58,38 +58,39 @@ auto CPU::dmaTransfer(bool direction, uint8 bbus, uint24 abus) -> void {
//===================
auto CPU::dmaAddressB(uint n, uint index) -> uint8 {
switch(channel[n].transfer_mode) { default:
case 0: return (channel[n].dest_addr); //0
case 1: return (channel[n].dest_addr + (index & 1)); //0,1
case 2: return (channel[n].dest_addr); //0,0
case 3: return (channel[n].dest_addr + ((index >> 1) & 1)); //0,0,1,1
case 4: return (channel[n].dest_addr + (index & 3)); //0,1,2,3
case 5: return (channel[n].dest_addr + (index & 1)); //0,1,0,1
case 6: return (channel[n].dest_addr); //0,0 [2]
case 7: return (channel[n].dest_addr + ((index >> 1) & 1)); //0,0,1,1 [3]
switch(channel[n].transferMode) {
case 0: return (channel[n].targetAddress); //0
case 1: return (channel[n].targetAddress + (index & 1)); //0,1
case 2: return (channel[n].targetAddress); //0,0
case 3: return (channel[n].targetAddress + ((index >> 1) & 1)); //0,0,1,1
case 4: return (channel[n].targetAddress + (index & 3)); //0,1,2,3
case 5: return (channel[n].targetAddress + (index & 1)); //0,1,0,1
case 6: return (channel[n].targetAddress); //0,0 [2]
case 7: return (channel[n].targetAddress + ((index >> 1) & 1)); //0,0,1,1 [3]
}
unreachable;
}
inline auto CPU::dmaAddress(uint n) -> uint24 {
uint24 addr = channel[n].source_bank << 16 | channel[n].source_addr;
auto CPU::dmaAddress(uint n) -> uint24 {
uint24 addr = channel[n].sourceBank << 16 | channel[n].sourceAddress;
if(!channel[n].fixed_transfer) {
if(!channel[n].reverse_transfer) {
channel[n].source_addr++;
if(!channel[n].fixedTransfer) {
if(!channel[n].reverseTransfer) {
channel[n].sourceAddress++;
} else {
channel[n].source_addr--;
channel[n].sourceAddress--;
}
}
return addr;
}
inline auto CPU::hdmaAddress(uint n) -> uint24 {
return channel[n].source_bank << 16 | channel[n].hdma_addr++;
auto CPU::hdmaAddress(uint n) -> uint24 {
return channel[n].sourceBank << 16 | channel[n].hdmaAddress++;
}
inline auto CPU::hdmaIndirectAddress(uint n) -> uint24 {
return channel[n].indirect_bank << 16 | channel[n].indirect_addr++;
auto CPU::hdmaIndirectAddress(uint n) -> uint24 {
return channel[n].indirectBank << 16 | channel[n].indirectAddress++;
}
//==============
@ -98,28 +99,28 @@ inline auto CPU::hdmaIndirectAddress(uint n) -> uint24 {
auto CPU::dmaEnabledChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += channel[n].dma_enabled;
for(auto n : range(8)) count += channel[n].dmaEnabled;
return count;
}
inline auto CPU::hdmaActive(uint n) -> bool {
return channel[n].hdma_enabled && !channel[n].hdma_completed;
auto CPU::hdmaActive(uint n) -> bool {
return channel[n].hdmaEnabled && !channel[n].hdmaCompleted;
}
inline auto CPU::hdmaActiveAfter(uint s) -> bool {
auto CPU::hdmaActiveAfter(uint s) -> bool {
for(uint n = s + 1; n < 8; n++) {
if(hdmaActive(n)) return true;
}
return false;
}
inline auto CPU::hdmaEnabledChannels() -> uint {
auto CPU::hdmaEnabledChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += channel[n].hdma_enabled;
for(auto n : range(8)) count += channel[n].hdmaEnabled;
return count;
}
inline auto CPU::hdmaActiveChannels() -> uint {
auto CPU::hdmaActiveChannels() -> uint {
uint count = 0;
for(auto n : range(8)) count += hdmaActive(n);
return count;
@ -135,49 +136,49 @@ auto CPU::dmaRun() -> void {
dmaEdge();
for(auto n : range(8)) {
if(!channel[n].dma_enabled) continue;
if(!channel[n].dmaEnabled) continue;
uint index = 0;
do {
dmaTransfer(channel[n].direction, dmaAddressB(n, index++), dmaAddress(n));
dmaEdge();
} while(channel[n].dma_enabled && --channel[n].transfer_size);
} while(channel[n].dmaEnabled && --channel[n].transferSize);
dmaAddClocks(8);
dmaWrite(false);
dmaEdge();
channel[n].dma_enabled = false;
channel[n].dmaEnabled = false;
}
status.irq_lock = true;
status.irqLock = true;
}
auto CPU::hdmaUpdate(uint n) -> void {
dmaAddClocks(4);
r.mdr = dmaRead(channel[n].source_bank << 16 | channel[n].hdma_addr);
r.mdr = dmaRead(channel[n].sourceBank << 16 | channel[n].hdmaAddress);
dmaAddClocks(4);
dmaWrite(false);
if((channel[n].line_counter & 0x7f) == 0) {
channel[n].line_counter = r.mdr;
channel[n].hdma_addr++;
if((channel[n].lineCounter & 0x7f) == 0) {
channel[n].lineCounter = r.mdr;
channel[n].hdmaAddress++;
channel[n].hdma_completed = channel[n].line_counter == 0;
channel[n].hdma_do_transfer = !channel[n].hdma_completed;
channel[n].hdmaCompleted = channel[n].lineCounter == 0;
channel[n].hdmaDoTransfer = !channel[n].hdmaCompleted;
if(channel[n].indirect) {
dmaAddClocks(4);
r.mdr = dmaRead(hdmaAddress(n));
channel[n].indirect_addr = r.mdr << 8;
channel[n].indirectAddress = r.mdr << 8;
dmaAddClocks(4);
dmaWrite(false);
if(!channel[n].hdma_completed || hdmaActiveAfter(n)) {
if(!channel[n].hdmaCompleted || hdmaActiveAfter(n)) {
dmaAddClocks(4);
r.mdr = dmaRead(hdmaAddress(n));
channel[n].indirect_addr >>= 8;
channel[n].indirect_addr |= r.mdr << 8;
channel[n].indirectAddress >>= 8;
channel[n].indirectAddress |= r.mdr << 8;
dmaAddClocks(4);
dmaWrite(false);
}
@ -191,11 +192,11 @@ auto CPU::hdmaRun() -> void {
for(auto n : range(8)) {
if(!hdmaActive(n)) continue;
channel[n].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
channel[n].dmaEnabled = false; //HDMA run during DMA will stop DMA mid-transfer
if(channel[n].hdma_do_transfer) {
if(channel[n].hdmaDoTransfer) {
static const uint transferLength[8] = {1, 2, 2, 4, 4, 4, 2, 4};
uint length = transferLength[channel[n].transfer_mode];
uint length = transferLength[channel[n].transferMode];
for(auto index : range(length)) {
uint addr = !channel[n].indirect ? hdmaAddress(n) : hdmaIndirectAddress(n);
dmaTransfer(channel[n].direction, dmaAddressB(n, index), addr);
@ -206,18 +207,18 @@ auto CPU::hdmaRun() -> void {
for(auto n : range(8)) {
if(!hdmaActive(n)) continue;
channel[n].line_counter--;
channel[n].hdma_do_transfer = channel[n].line_counter & 0x80;
channel[n].lineCounter--;
channel[n].hdmaDoTransfer = channel[n].lineCounter & 0x80;
hdmaUpdate(n);
}
status.irq_lock = true;
status.irqLock = true;
}
auto CPU::hdmaInitReset() -> void {
for(auto n : range(8)) {
channel[n].hdma_completed = false;
channel[n].hdma_do_transfer = false;
channel[n].hdmaCompleted = false;
channel[n].hdmaDoTransfer = false;
}
}
@ -226,13 +227,13 @@ auto CPU::hdmaInit() -> void {
dmaWrite(false);
for(auto n : range(8)) {
if(!channel[n].hdma_enabled) continue;
channel[n].dma_enabled = false; //HDMA init during DMA will stop DMA mid-transfer
if(!channel[n].hdmaEnabled) continue;
channel[n].dmaEnabled = false; //HDMA init during DMA will stop DMA mid-transfer
channel[n].hdma_addr = channel[n].source_addr;
channel[n].line_counter = 0;
channel[n].hdmaAddress = channel[n].sourceAddress;
channel[n].lineCounter = 0;
hdmaUpdate(n);
}
status.irq_lock = true;
status.irqLock = true;
}

View File

@ -5,98 +5,98 @@
//it is used to emulate hardware communication delay between opcode and interrupt units.
auto CPU::pollInterrupts() -> void {
//NMI hold
if(status.nmi_hold) {
status.nmi_hold = false;
if(status.nmi_enabled) status.nmi_transition = true;
if(status.nmiHold) {
status.nmiHold = false;
if(status.nmiEnabled) status.nmiTransition = true;
}
//NMI test
bool nmi_valid = vcounter(2) >= ppu.vdisp();
if(!status.nmi_valid && nmi_valid) {
bool nmiValid = vcounter(2) >= ppu.vdisp();
if(!status.nmiValid && nmiValid) {
//0->1 edge sensitive transition
status.nmi_line = true;
status.nmi_hold = true; //hold /NMI for four cycles
} else if(status.nmi_valid && !nmi_valid) {
status.nmiLine = true;
status.nmiHold = true; //hold /NMI for four cycles
} else if(status.nmiValid && !nmiValid) {
//1->0 edge sensitive transition
status.nmi_line = false;
status.nmiLine = false;
}
status.nmi_valid = nmi_valid;
status.nmiValid = nmiValid;
//IRQ hold
status.irq_hold = false;
if(status.irq_line) {
if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true;
status.irqHold = false;
if(status.irqLine) {
if(status.virqEnabled || status.hirqEnabled) status.irqTransition = true;
}
//IRQ test
bool irq_valid = status.virq_enabled || status.hirq_enabled;
if(irq_valid) {
if((status.virq_enabled && vcounter(10) != (status.virq_pos))
|| (status.hirq_enabled && hcounter(10) != (status.hirq_pos + 1) * 4)
|| (status.virq_pos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irq_valid = false;
bool irqValid = status.virqEnabled || status.hirqEnabled;
if(irqValid) {
if((status.virqEnabled && vcounter(10) != (status.virqPos))
|| (status.hirqEnabled && hcounter(10) != (status.hirqPos + 1) * 4)
|| (status.virqPos && vcounter(6) == 0) //IRQs cannot trigger on last dot of field
) irqValid = false;
}
if(!status.irq_valid && irq_valid) {
if(!status.irqValid && irqValid) {
//0->1 edge sensitive transition
status.irq_line = true;
status.irq_hold = true; //hold /IRQ for four cycles
status.irqLine = true;
status.irqHold = true; //hold /IRQ for four cycles
}
status.irq_valid = irq_valid;
status.irqValid = irqValid;
}
auto CPU::nmitimenUpdate(uint8 data) -> void {
bool nmi_enabled = status.nmi_enabled;
bool virq_enabled = status.virq_enabled;
bool hirq_enabled = status.hirq_enabled;
status.nmi_enabled = data & 0x80;
status.virq_enabled = data & 0x20;
status.hirq_enabled = data & 0x10;
bool nmiEnabled = status.nmiEnabled;
bool virqEnabled = status.virqEnabled;
bool hirqEnabled = status.hirqEnabled;
status.nmiEnabled = data & 0x80;
status.virqEnabled = data & 0x20;
status.hirqEnabled = data & 0x10;
//0->1 edge sensitive transition
if(!nmi_enabled && status.nmi_enabled && status.nmi_line) {
status.nmi_transition = true;
if(!nmiEnabled && status.nmiEnabled && status.nmiLine) {
status.nmiTransition = true;
}
//?->1 level sensitive transition
if(status.virq_enabled && !status.hirq_enabled && status.irq_line) {
status.irq_transition = true;
if(status.virqEnabled && !status.hirqEnabled && status.irqLine) {
status.irqTransition = true;
}
if(!status.virq_enabled && !status.hirq_enabled) {
status.irq_line = false;
status.irq_transition = false;
if(!status.virqEnabled && !status.hirqEnabled) {
status.irqLine = false;
status.irqTransition = false;
}
status.irq_lock = true;
status.irqLock = true;
}
auto CPU::rdnmi() -> bool {
bool result = status.nmi_line;
if(!status.nmi_hold) {
status.nmi_line = false;
bool result = status.nmiLine;
if(!status.nmiHold) {
status.nmiLine = false;
}
return result;
}
auto CPU::timeup() -> bool {
bool result = status.irq_line;
if(!status.irq_hold) {
status.irq_line = false;
status.irq_transition = false;
bool result = status.irqLine;
if(!status.irqHold) {
status.irqLine = false;
status.irqTransition = false;
}
return result;
}
auto CPU::nmiTest() -> bool {
if(!status.nmi_transition) return false;
status.nmi_transition = false;
if(!status.nmiTransition) return false;
status.nmiTransition = false;
r.wai = false;
return true;
}
auto CPU::irqTest() -> bool {
if(!status.irq_transition && !r.irq) return false;
status.irq_transition = false;
if(!status.irqTransition && !r.irq) return false;
status.irqTransition = false;
r.wai = false;
return !r.p.i;
}

View File

@ -2,11 +2,11 @@
auto CPU::stepAutoJoypadPoll() -> void {
if(vcounter() >= ppu.vdisp()) {
//cache enable state at first iteration
if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll;
status.auto_joypad_active = status.auto_joypad_counter <= 15;
if(status.autoJoypadCounter == 0) status.autoJoypadLatch = status.autoJoypadPoll;
status.autoJoypadActive = status.autoJoypadCounter <= 15;
if(status.auto_joypad_active && status.auto_joypad_latch) {
if(status.auto_joypad_counter == 0) {
if(status.autoJoypadActive && status.autoJoypadLatch) {
if(status.autoJoypadCounter == 0) {
SuperFamicom::peripherals.controllerPort1->latch(1);
SuperFamicom::peripherals.controllerPort2->latch(1);
SuperFamicom::peripherals.controllerPort1->latch(0);
@ -22,6 +22,6 @@ auto CPU::stepAutoJoypadPoll() -> void {
status.joy4 = status.joy4 << 1 | port1.bit(1);
}
status.auto_joypad_counter++;
status.autoJoypadCounter++;
}
}

View File

@ -7,35 +7,35 @@ auto CPU::portWrite(uint2 port, uint8 data) -> void {
}
auto CPU::io() -> void {
status.clock_count = 6;
status.clockCount = 6;
dmaEdge();
addClocks(6);
aluEdge();
}
auto CPU::read(uint24 addr) -> uint8 {
status.clock_count = speed(addr);
status.clockCount = speed(addr);
dmaEdge();
addClocks(status.clock_count - 4);
addClocks(status.clockCount - 4);
r.mdr = bus.read(addr, r.mdr);
addClocks(4);
aluEdge();
debugger.op_read(addr, r.mdr);
debugger.read(addr, r.mdr);
return r.mdr;
}
auto CPU::write(uint24 addr, uint8 data) -> void {
aluEdge();
status.clock_count = speed(addr);
status.clockCount = speed(addr);
dmaEdge();
addClocks(status.clock_count);
addClocks(status.clockCount);
bus.write(addr, r.mdr = data);
debugger.op_write(addr, r.mdr);
debugger.write(addr, r.mdr);
}
auto CPU::speed(uint24 addr) const -> uint {
if(addr & 0x408000) {
if(addr & 0x800000) return status.rom_speed;
if(addr & 0x800000) return status.romSpeed;
return 8;
}
if((addr + 0x6000) & 0x4000) return 8;

View File

@ -1,27 +1,27 @@
auto CPU::apuPortRead(uint24 addr, uint8 data) -> uint8 {
auto CPU::readAPU(uint24 addr, uint8 data) -> uint8 {
synchronizeSMP();
return smp.portRead(addr.bits(0,1));
}
auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 {
addr &= 0xffff;
auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
switch((uint16)addr) {
//WMDATA
if(addr == 0x2180) {
return bus.read(0x7e0000 | status.wram_addr++, r.mdr);
case 0x2180: {
return bus.read(0x7e0000 | status.wramAddress++, r.mdr);
}
//JOYSER0
//7-2 = MDR
//1-0 = Joypad serial data
if(addr == 0x4016) {
case 0x4016: {
uint8 v = r.mdr & 0xfc;
v |= SuperFamicom::peripherals.controllerPort1->data();
return v;
}
//JOYSER1
if(addr == 0x4017) {
case 0x4017: {
//7-5 = MDR
//4-2 = Always 1 (pins are connected to GND)
//1-0 = Joypad serial data
@ -31,18 +31,18 @@ auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 {
}
//RDNMI
if(addr == 0x4210) {
case 0x4210: {
//7 = NMI acknowledge
//6-4 = MDR
//3-0 = CPU (5a22) version
uint8 v = (r.mdr & 0x70);
v |= (uint8)(rdnmi()) << 7;
v |= (cpu_version & 0x0f);
v |= (version & 0x0f);
return v;
}
//TIMEUP
if(addr == 0x4211) {
case 0x4211: {
//7 = IRQ acknowledge
//6-0 = MDR
uint8 v = (r.mdr & 0x7f);
@ -51,161 +51,157 @@ auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 {
}
//HVBJOY
if(addr == 0x4212) {
case 0x4212: {
//7 = VBLANK acknowledge
//6 = HBLANK acknowledge
//5-1 = MDR
//0 = JOYPAD acknowledge
uint8 v = (r.mdr & 0x3e);
if(status.auto_joypad_active) v |= 0x01;
if(status.autoJoypadActive) v |= 0x01;
if(hcounter() <= 2 || hcounter() >= 1096) v |= 0x40; //hblank
if(vcounter() >= ppu.vdisp()) v |= 0x80; //vblank
return v;
}
//RDIO
if(addr == 0x4213) {
case 0x4213: {
return status.pio;
}
//RDDIVL
if(addr == 0x4214) {
case 0x4214: {
return status.rddiv.byte(0);
}
//RDDIVH
if(addr == 0x4215) {
case 0x4215: {
return status.rddiv.byte(1);
}
//RDMPYL
if(addr == 0x4216) {
case 0x4216: {
return status.rdmpy.byte(0);
}
//RDMPYH
if(addr == 0x4217) {
case 0x4217: {
return status.rdmpy.byte(1);
}
if(addr == 0x4218) return status.joy1.byte(0); //JOY1L
if(addr == 0x4219) return status.joy1.byte(1); //JOY1H
if(addr == 0x421a) return status.joy2.byte(0); //JOY2L
if(addr == 0x421b) return status.joy2.byte(1); //JOY2H
if(addr == 0x421c) return status.joy3.byte(0); //JOY3L
if(addr == 0x421d) return status.joy3.byte(1); //JOY3H
if(addr == 0x421e) return status.joy4.byte(0); //JOY4L
if(addr == 0x421f) return status.joy4.byte(1); //JOY4H
case 0x4218: return status.joy1.byte(0); //JOY1L
case 0x4219: return status.joy1.byte(1); //JOY1H
case 0x421a: return status.joy2.byte(0); //JOY2L
case 0x421b: return status.joy2.byte(1); //JOY2H
case 0x421c: return status.joy3.byte(0); //JOY3L
case 0x421d: return status.joy3.byte(1); //JOY3H
case 0x421e: return status.joy4.byte(0); //JOY4L
case 0x421f: return status.joy4.byte(1); //JOY4H
}
return data;
}
auto CPU::dmaPortRead(uint24 addr, uint8 data) -> uint8 {
auto CPU::readDMA(uint24 addr, uint8 data) -> uint8 {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
switch(addr & 0xff0f) {
//DMAPx
if(addr == 0x4300) return (
channel.direction << 7
| channel.indirect << 6
| channel.unused << 5
| channel.reverse_transfer << 4
| channel.fixed_transfer << 3
| channel.transfer_mode << 0
case 0x4300: return (
channel.transferMode << 0
| channel.fixedTransfer << 3
| channel.reverseTransfer << 4
| channel.unused << 5
| channel.indirect << 6
| channel.direction << 7
);
//BBADx
if(addr == 0x4301) return channel.dest_addr;
case 0x4301: return channel.targetAddress;
//A1TxL
if(addr == 0x4302) return channel.source_addr >> 0;
case 0x4302: return channel.sourceAddress >> 0;
//A1TxH
if(addr == 0x4303) return channel.source_addr >> 8;
case 0x4303: return channel.sourceAddress >> 8;
//A1Bx
if(addr == 0x4304) return channel.source_bank;
case 0x4304: return channel.sourceBank;
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) return channel.transfer_size >> 0;
//DASxL -- union { uint16 transferSize; uint16 indirectAddress; };
case 0x4305: return channel.transferSize.byte(0);
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) return channel.transfer_size >> 8;
//DASxH -- union { uint16 transferSize; uint16 indirectAddress; };
case 0x4306: return channel.transferSize.byte(1);
//DASBx
if(addr == 0x4307) return channel.indirect_bank;
case 0x4307: return channel.indirectBank;
//A2AxL
if(addr == 0x4308) return channel.hdma_addr >> 0;
case 0x4308: return channel.hdmaAddress.byte(0);
//A2AxH
if(addr == 0x4309) return channel.hdma_addr >> 8;
case 0x4309: return channel.hdmaAddress.byte(1);
//NTRLx
if(addr == 0x430a) return channel.line_counter;
case 0x430a: return channel.lineCounter;
//???
if(addr == 0x430b || addr == 0x430f) return channel.unknown;
case 0x430b:
case 0x430f: return channel.unknown;
}
return data;
}
auto CPU::apuPortWrite(uint24 addr, uint8 data) -> void {
auto CPU::writeAPU(uint24 addr, uint8 data) -> void {
synchronizeSMP();
return portWrite(addr.bits(0,1), data);
}
auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void {
addr &= 0xffff;
auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
switch((uint16)addr) {
//WMDATA
if(addr == 0x2180) {
bus.write(0x7e0000 | status.wram_addr++, data);
case 0x2180: {
return bus.write(0x7e0000 | status.wramAddress++, data);
}
//WMADDL
if(addr == 0x2181) {
status.wram_addr.bits(0,7) = data;
}
//WMADDM
if(addr == 0x2182) {
status.wram_addr.bits(8,15) = data;
}
//WMADDH
if(addr == 0x2183) {
status.wram_addr.bit(16) = data.bit(0);
}
case 0x2181: status.wramAddress.bits( 0, 7) = data; return; //WMADDL
case 0x2182: status.wramAddress.bits( 8,15) = data; return; //WMADDM
case 0x2183: status.wramAddress.bit (16 ) = data.bit(0); return; //WMADDH
//JOYSER0
if(addr == 0x4016) {
case 0x4016: {
//bit 0 is shared between JOYSER0 and JOYSER1, therefore
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
SuperFamicom::peripherals.controllerPort1->latch(data.bit(0));
SuperFamicom::peripherals.controllerPort2->latch(data.bit(0));
return;
}
//NMITIMEN
if(addr == 0x4200) {
status.auto_joypad_poll = data.bit(0);
case 0x4200: {
status.autoJoypadPoll = data.bit(0);
nmitimenUpdate(data);
return;
}
//WRIO
if(addr == 0x4201) {
case 0x4201: {
if(status.pio.bit(7) && !data.bit(7)) ppu.latchCounters();
status.pio = data;
return;
}
//WRMPYA
if(addr == 0x4202) {
status.wrmpya = data;
}
case 0x4202: status.wrmpya = data; return;
//WRMPYB
if(addr == 0x4203) {
case 0x4203: {
status.rdmpy = 0;
if(alu.mpyctr || alu.divctr) return;
@ -214,20 +210,14 @@ auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void {
alu.mpyctr = 8; //perform multiplication over the next eight cycles
alu.shift = status.wrmpyb;
return;
}
//WRDIVL
if(addr == 0x4204) {
status.wrdiva.byte(0) = data;
}
//WRDIVH
if(addr == 0x4205) {
status.wrdiva.byte(1) = data;
}
case 0x4204: { status.wrdiva.byte(0) = data; return; } //WRDIVL
case 0x4205: { status.wrdiva.byte(1) = data; return; } //WRDIVH
//WRDIVB
if(addr == 0x4206) {
case 0x4206: {
status.rdmpy = status.wrdiva;
if(alu.mpyctr || alu.divctr) return;
@ -235,111 +225,86 @@ auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void {
alu.divctr = 16; //perform division over the next sixteen cycles
alu.shift = status.wrdivb << 16;
return;
}
//HTIMEL
if(addr == 0x4207) {
status.hirq_pos.bits(0,7) = data;
}
case 0x4207: status.hirqPos.bits(0,7) = data; return; //HTIMEL
case 0x4208: status.hirqPos.bit (8 ) = data.bit(0); return; //HTIMEH
//HTIMEH
if(addr == 0x4208) {
status.hirq_pos.bit(8) = data.bit(0);
}
//VTIMEL
if(addr == 0x4209) {
status.virq_pos.bits(0,7) = data;
}
//VTIMEH
if(addr == 0x420a) {
status.virq_pos.bit(8) = data;
}
case 0x4209: status.virqPos.bits(0,7) = data; return; //VTIMEL
case 0x420a: status.virqPos.bit (8 ) = data.bit(0); return; //VTIMEH
//DMAEN
if(addr == 0x420b) {
for(auto n : range(8)) channel[n].dma_enabled = data.bit(n);
if(data) status.dma_pending = true;
case 0x420b: {
for(auto n : range(8)) channel[n].dmaEnabled = data.bit(n);
if(data) status.dmaPending = true;
return;
}
//HDMAEN
if(addr == 0x420c) {
for(auto n : range(8)) channel[n].hdma_enabled = data.bit(n);
case 0x420c: {
for(auto n : range(8)) channel[n].hdmaEnabled = data.bit(n);
return;
}
//MEMSEL
if(addr == 0x420d) {
status.rom_speed = data.bit(0) ? 6 : 8;
case 0x420d: {
status.romSpeed = data.bit(0) ? 6 : 8;
return;
}
}
}
auto CPU::dmaPortWrite(uint24 addr, uint8 data) -> void {
auto CPU::writeDMA(uint24 addr, uint8 data) -> void {
auto& channel = this->channel[addr.bits(4,6)];
addr &= 0xff0f;
switch(addr & 0xff0f) {
//DMAPx
if(addr == 0x4300) {
channel.direction = data & 0x80;
channel.indirect = data & 0x40;
channel.unused = data & 0x20;
channel.reverse_transfer = data & 0x10;
channel.fixed_transfer = data & 0x08;
channel.transfer_mode = data & 0x07;
case 0x4300: {
channel.transferMode = data.bits(0,2);
channel.fixedTransfer = data.bit (3);
channel.reverseTransfer = data.bit (4);
channel.unused = data.bit (5);
channel.indirect = data.bit (6);
channel.direction = data.bit (7);
return;
}
//DDBADx
if(addr == 0x4301) {
channel.dest_addr = data;
}
case 0x4301: channel.targetAddress = data; return;
//A1TxL
if(addr == 0x4302) {
channel.source_addr = (channel.source_addr & 0xff00) | (data << 0);
}
case 0x4302: channel.sourceAddress.byte(0) = data; return;
//A1TxH
if(addr == 0x4303) {
channel.source_addr = (channel.source_addr & 0x00ff) | (data << 8);
}
case 0x4303: channel.sourceAddress.byte(1) = data; return;
//A1Bx
if(addr == 0x4304) {
channel.source_bank = data;
}
case 0x4304: channel.sourceBank = data; return;
//DASxL -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4305) {
channel.transfer_size = (channel.transfer_size & 0xff00) | (data << 0);
}
//DASxL -- union { uint16 transferSize; uint16 indirectAddress; };
case 0x4305: channel.transferSize.byte(0) = data; return;
//DASxH -- union { uint16 transfer_size; uint16 indirect_addr; };
if(addr == 0x4306) {
channel.transfer_size = (channel.transfer_size & 0x00ff) | (data << 8);
}
//DASxH -- union { uint16 transferSize; uint16 indirectAddress; };
case 0x4306: channel.transferSize.byte(1) = data; return;
//DASBx
if(addr == 0x4307) {
channel.indirect_bank = data;
}
case 0x4307: channel.indirectBank = data; return;
//A2AxL
if(addr == 0x4308) {
channel.hdma_addr = (channel.hdma_addr & 0xff00) | (data << 0);
}
case 0x4308: channel.hdmaAddress.byte(0) = data; return;
//A2AxH
if(addr == 0x4309) {
channel.hdma_addr = (channel.hdma_addr & 0x00ff) | (data << 8);
}
case 0x4309: channel.hdmaAddress.byte(1) = data; return;
//NTRLx
if(addr == 0x430a) {
channel.line_counter = data;
}
case 0x430a: channel.lineCounter = data; return;
//???
if(addr == 0x430b || addr == 0x430f) {
channel.unknown = data;
case 0x430b:
case 0x430f: channel.unknown = data; return;
}
}

View File

@ -5,63 +5,63 @@ auto CPU::serialize(serializer& s) -> void {
s.array(wram);
s.integer(cpu_version);
s.integer(version);
s.integer(status.interrupt_pending);
s.integer(status.interruptPending);
s.integer(status.clock_count);
s.integer(status.line_clocks);
s.integer(status.clockCount);
s.integer(status.lineClocks);
s.integer(status.irq_lock);
s.integer(status.irqLock);
s.integer(status.dram_refresh_position);
s.integer(status.dram_refreshed);
s.integer(status.dramRefreshPosition);
s.integer(status.dramRefreshed);
s.integer(status.hdma_init_position);
s.integer(status.hdma_init_triggered);
s.integer(status.hdmaInitPosition);
s.integer(status.hdmaInitTriggered);
s.integer(status.hdma_position);
s.integer(status.hdma_triggered);
s.integer(status.hdmaPosition);
s.integer(status.hdmaTriggered);
s.integer(status.nmi_valid);
s.integer(status.nmi_line);
s.integer(status.nmi_transition);
s.integer(status.nmi_pending);
s.integer(status.nmi_hold);
s.integer(status.nmiValid);
s.integer(status.nmiLine);
s.integer(status.nmiTransition);
s.integer(status.nmiPending);
s.integer(status.nmiHold);
s.integer(status.irq_valid);
s.integer(status.irq_line);
s.integer(status.irq_transition);
s.integer(status.irq_pending);
s.integer(status.irq_hold);
s.integer(status.irqValid);
s.integer(status.irqLine);
s.integer(status.irqTransition);
s.integer(status.irqPending);
s.integer(status.irqHold);
s.integer(status.power_pending);
s.integer(status.reset_pending);
s.integer(status.powerPending);
s.integer(status.resetPending);
s.integer(status.dma_active);
s.integer(status.dma_counter);
s.integer(status.dma_clocks);
s.integer(status.dma_pending);
s.integer(status.hdma_pending);
s.integer(status.hdma_mode);
s.integer(status.dmaActive);
s.integer(status.dmaCounter);
s.integer(status.dmaClocks);
s.integer(status.dmaPending);
s.integer(status.hdmaPending);
s.integer(status.hdmaMode);
s.integer(status.auto_joypad_active);
s.integer(status.auto_joypad_latch);
s.integer(status.auto_joypad_counter);
s.integer(status.auto_joypad_clock);
s.integer(status.autoJoypadActive);
s.integer(status.autoJoypadLatch);
s.integer(status.autoJoypadCounter);
s.integer(status.autoJoypadClock);
s.array(status.port);
s.integer(status.wram_addr);
s.integer(status.wramAddress);
s.integer(status.joypad_strobe_latch);
s.integer(status.joypadStrobeLatch);
s.integer(status.joypad1_bits);
s.integer(status.joypad2_bits);
s.integer(status.nmi_enabled);
s.integer(status.hirq_enabled);
s.integer(status.virq_enabled);
s.integer(status.auto_joypad_poll);
s.integer(status.nmiEnabled);
s.integer(status.hirqEnabled);
s.integer(status.virqEnabled);
s.integer(status.autoJoypadPoll);
s.integer(status.pio);
@ -71,10 +71,10 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(status.wrdiva);
s.integer(status.wrdivb);
s.integer(status.hirq_pos);
s.integer(status.virq_pos);
s.integer(status.hirqPos);
s.integer(status.virqPos);
s.integer(status.rom_speed);
s.integer(status.romSpeed);
s.integer(status.rddiv);
s.integer(status.rdmpy);
@ -88,25 +88,25 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(alu.divctr);
s.integer(alu.shift);
for(uint i = 0; i < 8; i++) {
s.integer(channel[i].dma_enabled);
s.integer(channel[i].hdma_enabled);
s.integer(channel[i].direction);
s.integer(channel[i].indirect);
s.integer(channel[i].unused);
s.integer(channel[i].reverse_transfer);
s.integer(channel[i].fixed_transfer);
s.integer(channel[i].transfer_mode);
s.integer(channel[i].dest_addr);
s.integer(channel[i].source_addr);
s.integer(channel[i].source_bank);
s.integer(channel[i].transfer_size);
s.integer(channel[i].indirect_bank);
s.integer(channel[i].hdma_addr);
s.integer(channel[i].line_counter);
s.integer(channel[i].unknown);
s.integer(channel[i].hdma_completed);
s.integer(channel[i].hdma_do_transfer);
for(uint n : range(8)) {
s.integer(channel[n].dmaEnabled);
s.integer(channel[n].hdmaEnabled);
s.integer(channel[n].direction);
s.integer(channel[n].indirect);
s.integer(channel[n].unused);
s.integer(channel[n].reverseTransfer);
s.integer(channel[n].fixedTransfer);
s.integer(channel[n].transferMode);
s.integer(channel[n].targetAddress);
s.integer(channel[n].sourceAddress);
s.integer(channel[n].sourceBank);
s.integer(channel[n].transferSize);
s.integer(channel[n].indirectBank);
s.integer(channel[n].hdmaAddress);
s.integer(channel[n].lineCounter);
s.integer(channel[n].unknown);
s.integer(channel[n].hdmaCompleted);
s.integer(channel[n].hdmaDoTransfer);
}
s.integer(pipe.valid);

View File

@ -1,9 +1,9 @@
auto CPU::dmaCounter() const -> uint {
return (status.dma_counter + hcounter()) & 7;
return (status.dmaCounter + hcounter()) & 7;
}
auto CPU::addClocks(uint clocks) -> void {
status.irq_lock = false;
status.irqLock = false;
uint ticks = clocks >> 1;
while(ticks--) {
tick();
@ -12,14 +12,14 @@ auto CPU::addClocks(uint clocks) -> void {
step(clocks);
status.auto_joypad_clock += clocks;
if(status.auto_joypad_clock >= 256) {
status.auto_joypad_clock -= 256;
status.autoJoypadClock += clocks;
if(status.autoJoypadClock >= 256) {
status.autoJoypadClock -= 256;
stepAutoJoypadPoll();
}
if(!status.dram_refreshed && hcounter() >= status.dram_refresh_position) {
status.dram_refreshed = true;
if(!status.dramRefreshed && hcounter() >= status.dramRefreshPosition) {
status.dramRefreshed = true;
addClocks(40);
}
@ -32,8 +32,8 @@ auto CPU::addClocks(uint clocks) -> void {
//called by ppu.tick() when Hcounter=0
auto CPU::scanline() -> void {
status.dma_counter = (status.dma_counter + status.line_clocks) & 7;
status.line_clocks = lineclocks();
status.dmaCounter = (status.dmaCounter + status.lineClocks) & 7;
status.lineClocks = lineclocks();
//forcefully sync S-CPU to other processors, in case chips are not communicating
synchronizeSMP();
@ -42,20 +42,20 @@ auto CPU::scanline() -> void {
if(vcounter() == 0) {
//HDMA init triggers once every frame
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdma_init_triggered = false;
status.hdmaInitPosition = (version == 1 ? 12 + 8 - dmaCounter() : 12 + dmaCounter());
status.hdmaInitTriggered = false;
status.auto_joypad_counter = 0;
status.autoJoypadCounter = 0;
}
//DRAM refresh occurs once every scanline
if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dmaCounter();
status.dram_refreshed = false;
if(version == 2) status.dramRefreshPosition = 530 + 8 - dmaCounter();
status.dramRefreshed = false;
//HDMA triggers once every visible scanline
if(vcounter() < ppu.vdisp()) {
status.hdma_position = 1104;
status.hdma_triggered = false;
status.hdmaPosition = 1104;
status.hdmaTriggered = false;
}
}
@ -87,53 +87,53 @@ auto CPU::dmaEdge() -> void {
//.. Run one bus CPU cycle
//.. CPU sync
if(status.dma_active == true) {
if(status.hdma_pending) {
status.hdma_pending = false;
if(status.dmaActive) {
if(status.hdmaPending) {
status.hdmaPending = false;
if(hdmaEnabledChannels()) {
if(!dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter());
}
status.hdma_mode == 0 ? hdmaInit() : hdmaRun();
status.hdmaMode == 0 ? hdmaInit() : hdmaRun();
if(!dmaEnabledChannels()) {
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
status.dmaActive = false;
}
}
}
if(status.dma_pending) {
status.dma_pending = false;
if(status.dmaPending) {
status.dmaPending = false;
if(dmaEnabledChannels()) {
dmaAddClocks(8 - dmaCounter());
dmaRun();
addClocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
addClocks(status.clockCount - (status.dmaClocks % status.clockCount));
status.dmaActive = false;
}
}
}
if(status.hdma_init_triggered == false && hcounter() >= status.hdma_init_position) {
status.hdma_init_triggered = true;
if(!status.hdmaInitTriggered && hcounter() >= status.hdmaInitPosition) {
status.hdmaInitTriggered = true;
hdmaInitReset();
if(hdmaEnabledChannels()) {
status.hdma_pending = true;
status.hdma_mode = 0;
status.hdmaPending = true;
status.hdmaMode = 0;
}
}
if(status.hdma_triggered == false && hcounter() >= status.hdma_position) {
status.hdma_triggered = true;
if(!status.hdmaTriggered && hcounter() >= status.hdmaPosition) {
status.hdmaTriggered = true;
if(hdmaActiveChannels()) {
status.hdma_pending = true;
status.hdma_mode = 1;
status.hdmaPending = true;
status.hdmaMode = 1;
}
}
if(status.dma_active == false) {
if(status.dma_pending || status.hdma_pending) {
status.dma_clocks = 0;
status.dma_active = true;
if(!status.dmaActive) {
if(status.dmaPending || status.hdmaPending) {
status.dmaClocks = 0;
status.dmaActive = true;
}
}
}
@ -144,9 +144,9 @@ auto CPU::dmaEdge() -> void {
//status.irq_lock is used to simulate hardware delay before interrupts can
//trigger during certain events (immediately after DMA, writes to $4200, etc)
auto CPU::lastCycle() -> void {
if(!status.irq_lock) {
status.nmi_pending |= nmiTest();
status.irq_pending |= irqTest();
status.interrupt_pending = (status.nmi_pending || status.irq_pending);
if(!status.irqLock) {
status.nmiPending |= nmiTest();
status.irqPending |= irqTest();
status.interruptPending = (status.nmiPending || status.irqPending);
}
}

View File

@ -22,17 +22,17 @@ auto Satellaview::read(uint24 addr, uint8 data) -> uint8 {
case 0x2190: return regs.r2190;
case 0x2192: {
uint counter = regs.r2192_counter++;
if(regs.r2192_counter >= 18) regs.r2192_counter = 0;
uint counter = regs.rtcCounter++;
if(regs.rtcCounter >= 18) regs.rtcCounter = 0;
if(counter == 0) {
time_t rawtime;
time(&rawtime);
tm* t = localtime(&rawtime);
regs.r2192_hour = t->tm_hour;
regs.r2192_minute = t->tm_min;
regs.r2192_second = t->tm_sec;
regs.rtcHour = t->tm_hour;
regs.rtcMinute = t->tm_min;
regs.rtcSecond = t->tm_sec;
}
switch(counter) {
@ -46,9 +46,9 @@ auto Satellaview::read(uint24 addr, uint8 data) -> uint8 {
case 7: return 0x00;
case 8: return 0x00;
case 9: return 0x00;
case 10: return regs.r2192_second;
case 11: return regs.r2192_minute;
case 12: return regs.r2192_hour;
case 10: return regs.rtcSecond;
case 11: return regs.rtcMinute;
case 12: return regs.rtcHour;
case 13: return 0x00; //???
case 14: return 0x00; //???
case 15: return 0x00; //???
@ -101,7 +101,7 @@ auto Satellaview::write(uint24 addr, uint8 data) -> void {
case 0x2191: {
regs.r2191 = data;
regs.r2192_counter = 0;
regs.rtcCounter = 0;
} break;
case 0x2192: {

View File

@ -14,7 +14,9 @@ private:
uint8 r2198, r2199, r219a, r219b;
uint8 r219c, r219d, r219e, r219f;
uint8 r2192_counter;
uint8 r2192_hour, r2192_minute, r2192_second;
uint8 rtcCounter;
uint8 rtcHour;
uint8 rtcMinute;
uint8 rtcSecond;
} regs;
};

View File

@ -101,19 +101,15 @@ Interface::Interface() {
devices.append(device);
}
{ Device device{7, ID::ControllerPort1, "Serial USART"};
{ Device device{7, ID::ExpansionPort, "Satellaview"};
devices.append(device);
}
{ Device device{8, ID::ExpansionPort, "Satellaview"};
{ Device device{8, ID::ExpansionPort, "Super Disc"};
devices.append(device);
}
{ Device device{9, ID::ExpansionPort, "Super Disc"};
devices.append(device);
}
{ Device device{10, ID::ExpansionPort, "21fx"};
{ Device device{9, ID::ExpansionPort, "21fx"};
devices.append(device);
}
@ -463,14 +459,14 @@ auto Interface::run() -> void {
}
auto Interface::rtc() -> bool {
if(cartridge.hasEpsonRTC()) return true;
if(cartridge.hasSharpRTC()) return true;
if(cartridge.hasEpsonRTC) return true;
if(cartridge.hasSharpRTC) return true;
return false;
}
auto Interface::rtcsync() -> void {
if(cartridge.hasEpsonRTC()) epsonrtc.sync();
if(cartridge.hasSharpRTC()) sharprtc.sync();
if(cartridge.hasEpsonRTC) epsonrtc.sync();
if(cartridge.hasSharpRTC) sharprtc.sync();
}
auto Interface::serialize() -> serializer {
@ -486,7 +482,7 @@ auto Interface::cheatSet(const lstring& list) -> void {
cheat.reset();
#if defined(SFC_SUPERGAMEBOY)
if(cartridge.hasICD2()) {
if(cartridge.hasICD2) {
GameBoy::cheat.reset();
for(auto& codeset : list) {
lstring codes = codeset.split("+");

View File

@ -4,53 +4,51 @@ auto Memory::size() const -> uint { return 0; }
//StaticRAM
StaticRAM::StaticRAM(uint n) : size_(n) { data_ = new uint8[size_]; }
StaticRAM::~StaticRAM() { delete[] data_; }
StaticRAM::StaticRAM(uint size) : _size(size) { _data = new uint8[_size]; }
StaticRAM::~StaticRAM() { delete[] _data; }
auto StaticRAM::data() -> uint8* { return data_; }
auto StaticRAM::size() const -> uint { return size_; }
auto StaticRAM::data() -> uint8* { return _data; }
auto StaticRAM::size() const -> uint { return _size; }
auto StaticRAM::read(uint24 addr, uint8) -> uint8 { return data_[addr]; }
auto StaticRAM::write(uint24 addr, uint8 data) -> void { data_[addr] = data; }
auto StaticRAM::operator[](uint24 addr) -> uint8& { return data_[addr]; }
auto StaticRAM::operator[](uint24 addr) const -> const uint8& { return data_[addr]; }
auto StaticRAM::read(uint24 addr, uint8) -> uint8 { return _data[addr]; }
auto StaticRAM::write(uint24 addr, uint8 data) -> void { _data[addr] = data; }
auto StaticRAM::operator[](uint24 addr) -> uint8& { return _data[addr]; }
auto StaticRAM::operator[](uint24 addr) const -> const uint8& { return _data[addr]; }
//MappedRAM
auto MappedRAM::reset() -> void {
if(data_) {
delete[] data_;
data_ = nullptr;
}
size_ = 0;
write_protect_ = false;
delete[] _data;
_data = nullptr;
_size = 0;
_writeProtect = false;
}
auto MappedRAM::map(uint8* source, uint length) -> void {
reset();
data_ = source;
size_ = data_ ? length : 0;
_data = source;
_size = _data ? length : 0;
}
auto MappedRAM::copy(const stream& memory) -> void {
if(data_) delete[] data_;
if(_data) delete[] _data;
//round size up to multiple of 256-bytes
size_ = (memory.size() & ~255) + ((bool)(memory.size() & 255) << 8);
data_ = new uint8[size_]();
memory.read((uint8_t*)data_, memory.size());
_size = (memory.size() & ~255) + ((bool)(memory.size() & 255) << 8);
_data = new uint8[_size]();
memory.read((uint8_t*)_data, memory.size());
}
auto MappedRAM::read(const stream& memory) -> void {
memory.read((uint8_t*)data_, min(memory.size(), size_));
memory.read((uint8_t*)_data, min(memory.size(), _size));
}
auto MappedRAM::write_protect(bool status) -> void { write_protect_ = status; }
auto MappedRAM::data() -> uint8* { return data_; }
auto MappedRAM::size() const -> uint { return size_; }
auto MappedRAM::writeProtect(bool writeProtect) -> void { _writeProtect = writeProtect; }
auto MappedRAM::data() -> uint8* { return _data; }
auto MappedRAM::size() const -> uint { return _size; }
auto MappedRAM::read(uint24 addr, uint8) -> uint8 { return data_[addr]; }
auto MappedRAM::write(uint24 addr, uint8 data) -> void { if(!write_protect_) data_[addr] = data; }
auto MappedRAM::operator[](uint24 addr) const -> const uint8& { return data_[addr]; }
auto MappedRAM::read(uint24 addr, uint8) -> uint8 { return _data[addr]; }
auto MappedRAM::write(uint24 addr, uint8 data) -> void { if(!_writeProtect) _data[addr] = data; }
auto MappedRAM::operator[](uint24 addr) const -> const uint8& { return _data[addr]; }
//Bus

View File

@ -17,8 +17,8 @@ struct StaticRAM : Memory {
inline auto operator[](uint24 addr) const -> const uint8&;
private:
uint8* data_ = nullptr;
uint size_ = 0;
uint8* _data = nullptr;
uint _size = 0;
};
struct MappedRAM : Memory {
@ -27,7 +27,7 @@ struct MappedRAM : Memory {
inline auto copy(const stream& memory) -> void;
inline auto read(const stream& memory) -> void;
inline auto write_protect(bool status) -> void;
inline auto writeProtect(bool writeProtect) -> void;
inline auto data() -> uint8*;
inline auto size() const -> uint;
@ -36,9 +36,9 @@ struct MappedRAM : Memory {
inline auto operator[](uint24 addr) const -> const uint8&;
private:
uint8* data_ = nullptr;
uint size_ = 0;
bool write_protect_ = false;
uint8* _data = nullptr;
uint _size = 0;
bool _writeProtect = false;
};
struct Bus {

View File

@ -1,127 +0,0 @@
//note: this source file is currently unused
//saved temporarily only for reference
auto Video::refresh() -> void {
auto output = this->output() + 16 * 512; //add offset for overscan
auto& palette = settings.colorEmulation ? paletteEmulation : paletteStandard;
if(settings.scanlineEmulation) {
for(uint y = 0; y < 240; y++) {
auto sourceLo = ppu.output + y * 1024;
auto sourceHi = ppu.output + y * 1024 + 512;
auto targetLo = output + y * 1024;
auto targetHi = output + y * 1024 + 512;
if(!ppu.interlace()) {
for(uint x = 0; x < 512; x++) {
auto color = palette[*sourceLo++];
*targetLo++ = color;
*targetHi++ = (255 << 24) | ((color & 0xfefefe) >> 1);
}
} else if(!ppu.field()) {
for(uint x = 0; x < 512; x++) {
auto color = palette[*sourceHi++];
*targetLo++ = palette[*sourceLo++];
*targetHi++ = (255 << 24) | ((color & 0xfefefe) >> 1);
}
} else {
for(uint x = 0; x < 512; x++) {
auto color = palette[*sourceLo++];
*targetLo++ = (255 << 24) | ((color & 0xfefefe) >> 1);
*targetHi++ = palette[*sourceHi++];
}
}
}
} else {
for(uint y = 0; y < 240; y++) {
auto sourceLo = ppu.output + y * 1024;
auto sourceHi = ppu.output + y * 1024 + 512;
auto targetLo = output + y * 1024;
auto targetHi = output + y * 1024 + 512;
if(!ppu.interlace()) {
for(uint x = 0; x < 512; x++) {
auto color = palette[*sourceLo++];
*targetLo++ = color;
*targetHi++ = color;
}
} else {
for(uint x = 0; x < 512; x++) {
*targetLo++ = palette[*sourceLo++];
*targetHi++ = palette[*sourceHi++];
}
}
}
}
if(settings.blurEmulation) {
for(uint y = 0; y < 480; y++) {
auto target = output + y * 512;
for(uint x = 0; x < 512; x++) {
auto a = target[x];
auto b = target[x + (x != 511)];
target[x] = (a + b - ((a ^ b) & 0x01010101)) >> 1;
}
}
}
drawCursors();
interface->videoRefresh(output - (ppu.overscan() ? 0 : 7 * 1024), 512 * sizeof(uint32), 512, 480);
}
auto Video::drawCursor(uint32 color, int x, int y) -> void {
static const uint8 cursor[15 * 15] = {
0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
0,0,0,0,1,1,2,2,2,1,1,0,0,0,0,
0,0,0,1,2,2,1,2,1,2,2,1,0,0,0,
0,0,1,2,1,1,0,1,0,1,1,2,1,0,0,
0,1,2,1,0,0,0,1,0,0,0,1,2,1,0,
0,1,2,1,0,0,1,2,1,0,0,1,2,1,0,
1,2,1,0,0,1,1,2,1,1,0,0,1,2,1,
1,2,2,1,1,2,2,2,2,2,1,1,2,2,1,
1,2,1,0,0,1,1,2,1,1,0,0,1,2,1,
0,1,2,1,0,0,1,2,1,0,0,1,2,1,0,
0,1,2,1,0,0,0,1,0,0,0,1,2,1,0,
0,0,1,2,1,1,0,1,0,1,1,2,1,0,0,
0,0,0,1,2,2,1,2,1,2,2,1,0,0,0,
0,0,0,0,1,1,2,2,2,1,1,0,0,0,0,
0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,
};
auto output = this->output() + 16 * 512;
for(int cy = 0; cy < 15; cy++) {
int vy = y + cy - 7;
if(vy <= 0 || vy >= 240) continue; //do not draw offscreen
for(int cx = 0; cx < 15; cx++) {
int vx = x + cx - 7;
if(vx < 0 || vx >= 256) continue; //do not draw offscreen
uint8 pixel = cursor[cy * 15 + cx];
if(pixel == 0) continue;
uint32 pixelcolor = pixel == 1 ? (uint32)(255 << 24) : color;
*(output + vy * 1024 + vx * 2 + 0) = pixelcolor;
*(output + vy * 1024 + vx * 2 + 1) = pixelcolor;
*(output + vy * 1024 + 512 + vx * 2 + 0) = pixelcolor;
*(output + vy * 1024 + 512 + vx * 2 + 1) = pixelcolor;
}
}
}
auto Video::drawCursors() -> void {
switch(settings.controllerPort2) {
case Device::SuperScope:
if(dynamic_cast<SuperScope*>(peripherals.controllerPort2)) {
auto& controller = (SuperScope&)*peripherals.controllerPort2;
drawCursor(0xff0000ff, controller.x, controller.y);
}
break;
case Device::Justifier:
case Device::Justifiers:
if(dynamic_cast<Justifier*>(peripherals.controllerPort2)) {
auto& controller = (Justifier&)*peripherals.controllerPort2;
drawCursor(0xffff0000, controller.player1.x, controller.player1.y);
if(!controller.chained) break;
drawCursor(0xff00bf00, controller.player2.x, controller.player2.y);
}
break;
}
}

View File

@ -22,13 +22,13 @@ auto BSMemory::power() -> void {
auto BSMemory::reset() -> void {
regs.command = 0;
regs.write_old = 0x00;
regs.write_new = 0x00;
regs.writeOld = 0x00;
regs.writeNew = 0x00;
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
memory.write_protect(!regs.write_enable);
regs.flashEnable = false;
regs.readEnable = false;
regs.writeEnable = false;
memory.writeProtect(!regs.writeEnable);
}
auto BSMemory::size() const -> uint {
@ -41,14 +41,14 @@ auto BSMemory::read(uint24 addr, uint8 data) -> uint8 {
}
if(addr == 0x0002) {
if(regs.flash_enable) return 0x80;
if(regs.flashEnable) return 0x80;
}
if(addr == 0x5555) {
if(regs.flash_enable) return 0x80;
if(regs.flashEnable) return 0x80;
}
if(regs.read_enable && addr >= 0xff00 && addr <= 0xff13) {
if(regs.readEnable && addr >= 0xff00 && addr <= 0xff13) {
//read flash cartridge vendor information
switch(addr - 0xff00) {
case 0x00: return 0x4d;
@ -72,14 +72,14 @@ auto BSMemory::write(uint24 addr, uint8 data) -> void {
}
if((addr & 0xff0000) == 0) {
regs.write_old = regs.write_new;
regs.write_new = data;
regs.writeOld = regs.writeNew;
regs.writeNew = data;
if(regs.write_enable && regs.write_old == regs.write_new) {
if(regs.writeEnable && regs.writeOld == regs.writeNew) {
return memory.write(addr, data);
}
} else {
if(regs.write_enable) {
if(regs.writeEnable) {
return memory.write(addr, data);
}
}
@ -89,8 +89,8 @@ auto BSMemory::write(uint24 addr, uint8 data) -> void {
regs.command |= data;
if((regs.command & 0xffff) == 0x38d0) {
regs.flash_enable = true;
regs.read_enable = true;
regs.flashEnable = true;
regs.readEnable = true;
}
}
@ -104,23 +104,23 @@ auto BSMemory::write(uint24 addr, uint8 data) -> void {
regs.command |= data;
if((regs.command & 0xffffff) == 0xaa5570) {
regs.write_enable = false;
regs.writeEnable = false;
}
if((regs.command & 0xffffff) == 0xaa55a0) {
regs.write_old = 0x00;
regs.write_new = 0x00;
regs.flash_enable = true;
regs.write_enable = true;
regs.writeOld = 0x00;
regs.writeNew = 0x00;
regs.flashEnable = true;
regs.writeEnable = true;
}
if((regs.command & 0xffffff) == 0xaa55f0) {
regs.flash_enable = false;
regs.read_enable = false;
regs.write_enable = false;
regs.flashEnable = false;
regs.readEnable = false;
regs.writeEnable = false;
}
memory.write_protect(!regs.write_enable);
memory.writeProtect(!regs.writeEnable);
}
}

View File

@ -15,12 +15,12 @@ struct BSMemory : Memory {
private:
struct {
uint command;
uint8 write_old;
uint8 write_new;
uint8 writeOld;
uint8 writeNew;
bool flash_enable;
bool read_enable;
bool write_enable;
bool flashEnable;
bool readEnable;
bool writeEnable;
} regs;
};

View File

@ -183,7 +183,7 @@ auto SMP::read(uint16 addr) -> uint8 {
uint8 data = busRead(addr);
addClocks(12);
cycleEdge();
debugger.op_read(addr, data);
debugger.read(addr, data);
return data;
}
@ -191,7 +191,7 @@ auto SMP::write(uint16 addr, uint8 data) -> void {
addClocks(24);
busWrite(addr, data);
cycleEdge();
debugger.op_write(addr, data);
debugger.write(addr, data);
}
auto SMP::disassemblerRead(uint16 addr) -> uint8 {

View File

@ -26,7 +26,7 @@ auto SMP::Enter() -> void {
}
auto SMP::main() -> void {
debugger.op_exec(regs.pc);
debugger.execute(regs.pc);
instruction();
}

View File

@ -46,9 +46,9 @@ privileged:
static auto Enter() -> void;
struct Debugger {
hook<auto (uint16) -> void> op_exec;
hook<auto (uint16, uint8) -> void> op_read;
hook<auto (uint16, uint8) -> void> op_write;
hook<auto (uint16) -> void> execute;
hook<auto (uint16, uint8) -> void> read;
hook<auto (uint16, uint8) -> void> write;
} debugger;
//memory.cpp

View File

@ -26,7 +26,6 @@ auto Peripherals::connect(uint port, uint id) -> void {
case Device::Gamepad: controllerPort1 = new Gamepad(0); break;
case Device::Multitap: controllerPort1 = new Multitap(0); break;
case Device::Mouse: controllerPort1 = new Mouse(0); break;
case Device::USART: controllerPort1 = new USART(0); break;
}
}

View File

@ -14,7 +14,6 @@ struct Device { enum : uint {
SuperScope,
Justifier,
Justifiers,
USART,
//expansion port peripherals
Satellaview,

View File

@ -50,22 +50,22 @@ auto System::serializeAll(serializer& s) -> void {
ppu.serialize(s);
dsp.serialize(s);
if(cartridge.hasICD2()) icd2.serialize(s);
if(cartridge.hasMCC()) mcc.serialize(s);
if(cartridge.hasEvent()) event.serialize(s);
if(cartridge.hasSA1()) sa1.serialize(s);
if(cartridge.hasSuperFX()) superfx.serialize(s);
if(cartridge.hasARMDSP()) armdsp.serialize(s);
if(cartridge.hasHitachiDSP()) hitachidsp.serialize(s);
if(cartridge.hasNECDSP()) necdsp.serialize(s);
if(cartridge.hasEpsonRTC()) epsonrtc.serialize(s);
if(cartridge.hasSharpRTC()) sharprtc.serialize(s);
if(cartridge.hasSPC7110()) spc7110.serialize(s);
if(cartridge.hasSDD1()) sdd1.serialize(s);
if(cartridge.hasOBC1()) obc1.serialize(s);
if(cartridge.hasMSU1()) msu1.serialize(s);
if(cartridge.hasICD2) icd2.serialize(s);
if(cartridge.hasMCC) mcc.serialize(s);
if(cartridge.hasEvent) event.serialize(s);
if(cartridge.hasSA1) sa1.serialize(s);
if(cartridge.hasSuperFX) superfx.serialize(s);
if(cartridge.hasARMDSP) armdsp.serialize(s);
if(cartridge.hasHitachiDSP) hitachidsp.serialize(s);
if(cartridge.hasNECDSP) necdsp.serialize(s);
if(cartridge.hasEpsonRTC) epsonrtc.serialize(s);
if(cartridge.hasSharpRTC) sharprtc.serialize(s);
if(cartridge.hasSPC7110) spc7110.serialize(s);
if(cartridge.hasSDD1) sdd1.serialize(s);
if(cartridge.hasOBC1) obc1.serialize(s);
if(cartridge.hasMSU1) msu1.serialize(s);
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
if(cartridge.hasSufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
}
//perform dry-run state save:

View File

@ -66,24 +66,24 @@ auto System::load() -> void {
_cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370;
_apuFrequency = 24'606'720;
if(cartridge.hasICD2()) icd2.load();
if(cartridge.hasMCC()) mcc.load();
if(cartridge.hasNSSDIP()) nss.load();
if(cartridge.hasEvent()) event.load();
if(cartridge.hasSA1()) sa1.load();
if(cartridge.hasSuperFX()) superfx.load();
if(cartridge.hasARMDSP()) armdsp.load();
if(cartridge.hasHitachiDSP()) hitachidsp.load();
if(cartridge.hasNECDSP()) necdsp.load();
if(cartridge.hasEpsonRTC()) epsonrtc.load();
if(cartridge.hasSharpRTC()) sharprtc.load();
if(cartridge.hasSPC7110()) spc7110.load();
if(cartridge.hasSDD1()) sdd1.load();
if(cartridge.hasOBC1()) obc1.load();
if(cartridge.hasMSU1()) msu1.load();
if(cartridge.hasICD2) icd2.load();
if(cartridge.hasMCC) mcc.load();
if(cartridge.hasNSSDIP) nss.load();
if(cartridge.hasEvent) event.load();
if(cartridge.hasSA1) sa1.load();
if(cartridge.hasSuperFX) superfx.load();
if(cartridge.hasARMDSP) armdsp.load();
if(cartridge.hasHitachiDSP) hitachidsp.load();
if(cartridge.hasNECDSP) necdsp.load();
if(cartridge.hasEpsonRTC) epsonrtc.load();
if(cartridge.hasSharpRTC) sharprtc.load();
if(cartridge.hasSPC7110) spc7110.load();
if(cartridge.hasSDD1) sdd1.load();
if(cartridge.hasOBC1) obc1.load();
if(cartridge.hasMSU1) msu1.load();
if(cartridge.hasBSMemorySlot()) bsmemory.load();
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.load(), sufamiturboB.load();
if(cartridge.hasBSMemorySlot) bsmemory.load();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.load(), sufamiturboB.load();
serializeInit();
_loaded = true;
@ -93,24 +93,24 @@ auto System::unload() -> void {
if(!loaded()) return;
peripherals.unload();
if(cartridge.hasICD2()) icd2.unload();
if(cartridge.hasMCC()) mcc.unload();
if(cartridge.hasNSSDIP()) nss.unload();
if(cartridge.hasEvent()) event.unload();
if(cartridge.hasSA1()) sa1.unload();
if(cartridge.hasSuperFX()) superfx.unload();
if(cartridge.hasARMDSP()) armdsp.unload();
if(cartridge.hasHitachiDSP()) hitachidsp.unload();
if(cartridge.hasNECDSP()) necdsp.unload();
if(cartridge.hasEpsonRTC()) epsonrtc.unload();
if(cartridge.hasSharpRTC()) sharprtc.unload();
if(cartridge.hasSPC7110()) spc7110.unload();
if(cartridge.hasSDD1()) sdd1.unload();
if(cartridge.hasOBC1()) obc1.unload();
if(cartridge.hasMSU1()) msu1.unload();
if(cartridge.hasICD2) icd2.unload();
if(cartridge.hasMCC) mcc.unload();
if(cartridge.hasNSSDIP) nss.unload();
if(cartridge.hasEvent) event.unload();
if(cartridge.hasSA1) sa1.unload();
if(cartridge.hasSuperFX) superfx.unload();
if(cartridge.hasARMDSP) armdsp.unload();
if(cartridge.hasHitachiDSP) hitachidsp.unload();
if(cartridge.hasNECDSP) necdsp.unload();
if(cartridge.hasEpsonRTC) epsonrtc.unload();
if(cartridge.hasSharpRTC) sharprtc.unload();
if(cartridge.hasSPC7110) spc7110.unload();
if(cartridge.hasSDD1) sdd1.unload();
if(cartridge.hasOBC1) obc1.unload();
if(cartridge.hasMSU1) msu1.unload();
if(cartridge.hasBSMemorySlot()) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots()) sufamiturboA.unload(), sufamiturboB.unload();
if(cartridge.hasBSMemorySlot) bsmemory.unload();
if(cartridge.hasSufamiTurboSlots) sufamiturboA.unload(), sufamiturboB.unload();
cartridge.unload();
_loaded = false;
@ -124,23 +124,23 @@ auto System::power() -> void {
dsp.power();
ppu.power();
if(cartridge.hasICD2()) icd2.power();
if(cartridge.hasMCC()) mcc.power();
if(cartridge.hasNSSDIP()) nss.power();
if(cartridge.hasEvent()) event.power();
if(cartridge.hasSA1()) sa1.power();
if(cartridge.hasSuperFX()) superfx.power();
if(cartridge.hasARMDSP()) armdsp.power();
if(cartridge.hasHitachiDSP()) hitachidsp.power();
if(cartridge.hasNECDSP()) necdsp.power();
if(cartridge.hasEpsonRTC()) epsonrtc.power();
if(cartridge.hasSharpRTC()) sharprtc.power();
if(cartridge.hasSPC7110()) spc7110.power();
if(cartridge.hasSDD1()) sdd1.power();
if(cartridge.hasOBC1()) obc1.power();
if(cartridge.hasMSU1()) msu1.power();
if(cartridge.hasICD2) icd2.power();
if(cartridge.hasMCC) mcc.power();
if(cartridge.hasNSSDIP) nss.power();
if(cartridge.hasEvent) event.power();
if(cartridge.hasSA1) sa1.power();
if(cartridge.hasSuperFX) superfx.power();
if(cartridge.hasARMDSP) armdsp.power();
if(cartridge.hasHitachiDSP) hitachidsp.power();
if(cartridge.hasNECDSP) necdsp.power();
if(cartridge.hasEpsonRTC) epsonrtc.power();
if(cartridge.hasSharpRTC) sharprtc.power();
if(cartridge.hasSPC7110) spc7110.power();
if(cartridge.hasSDD1) sdd1.power();
if(cartridge.hasOBC1) obc1.power();
if(cartridge.hasMSU1) msu1.power();
if(cartridge.hasBSMemorySlot()) bsmemory.power();
if(cartridge.hasBSMemorySlot) bsmemory.power();
reset();
}
@ -159,35 +159,35 @@ auto System::reset() -> void {
dsp.reset();
ppu.reset();
if(cartridge.hasICD2()) icd2.reset();
if(cartridge.hasMCC()) mcc.reset();
if(cartridge.hasNSSDIP()) nss.reset();
if(cartridge.hasEvent()) event.reset();
if(cartridge.hasSA1()) sa1.reset();
if(cartridge.hasSuperFX()) superfx.reset();
if(cartridge.hasARMDSP()) armdsp.reset();
if(cartridge.hasHitachiDSP()) hitachidsp.reset();
if(cartridge.hasNECDSP()) necdsp.reset();
if(cartridge.hasEpsonRTC()) epsonrtc.reset();
if(cartridge.hasSharpRTC()) sharprtc.reset();
if(cartridge.hasSPC7110()) spc7110.reset();
if(cartridge.hasSDD1()) sdd1.reset();
if(cartridge.hasOBC1()) obc1.reset();
if(cartridge.hasMSU1()) msu1.reset();
if(cartridge.hasICD2) icd2.reset();
if(cartridge.hasMCC) mcc.reset();
if(cartridge.hasNSSDIP) nss.reset();
if(cartridge.hasEvent) event.reset();
if(cartridge.hasSA1) sa1.reset();
if(cartridge.hasSuperFX) superfx.reset();
if(cartridge.hasARMDSP) armdsp.reset();
if(cartridge.hasHitachiDSP) hitachidsp.reset();
if(cartridge.hasNECDSP) necdsp.reset();
if(cartridge.hasEpsonRTC) epsonrtc.reset();
if(cartridge.hasSharpRTC) sharprtc.reset();
if(cartridge.hasSPC7110) spc7110.reset();
if(cartridge.hasSDD1) sdd1.reset();
if(cartridge.hasOBC1) obc1.reset();
if(cartridge.hasMSU1) msu1.reset();
if(cartridge.hasBSMemorySlot()) bsmemory.reset();
if(cartridge.hasBSMemorySlot) bsmemory.reset();
if(cartridge.hasICD2()) cpu.coprocessors.append(&icd2);
if(cartridge.hasEvent()) cpu.coprocessors.append(&event);
if(cartridge.hasSA1()) cpu.coprocessors.append(&sa1);
if(cartridge.hasSuperFX()) cpu.coprocessors.append(&superfx);
if(cartridge.hasARMDSP()) cpu.coprocessors.append(&armdsp);
if(cartridge.hasHitachiDSP()) cpu.coprocessors.append(&hitachidsp);
if(cartridge.hasNECDSP()) cpu.coprocessors.append(&necdsp);
if(cartridge.hasEpsonRTC()) cpu.coprocessors.append(&epsonrtc);
if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc);
if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110);
if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1);
if(cartridge.hasICD2) cpu.coprocessors.append(&icd2);
if(cartridge.hasEvent) cpu.coprocessors.append(&event);
if(cartridge.hasSA1) cpu.coprocessors.append(&sa1);
if(cartridge.hasSuperFX) cpu.coprocessors.append(&superfx);
if(cartridge.hasARMDSP) cpu.coprocessors.append(&armdsp);
if(cartridge.hasHitachiDSP) cpu.coprocessors.append(&hitachidsp);
if(cartridge.hasNECDSP) cpu.coprocessors.append(&necdsp);
if(cartridge.hasEpsonRTC) cpu.coprocessors.append(&epsonrtc);
if(cartridge.hasSharpRTC) cpu.coprocessors.append(&sharprtc);
if(cartridge.hasSPC7110) cpu.coprocessors.append(&spc7110);
if(cartridge.hasMSU1) cpu.coprocessors.append(&msu1);
scheduler.reset();
peripherals.reset();

View File

@ -72,7 +72,7 @@ Presentation::Presentation() {
settings["Video/ColorEmulation"].setValue(colorEmulation.checked());
if(emulator) emulator->set("Color Emulation", colorEmulation.checked());
});
scanlineEmulation.setVisible(false).setText("Scanlines").setChecked(settings["Video/ScanlineEmulation"].boolean()).onToggle([&] {
scanlineEmulation.setText("Scanlines").setChecked(settings["Video/ScanlineEmulation"].boolean()).setVisible(false).onToggle([&] {
settings["Video/ScanlineEmulation"].setValue(scanlineEmulation.checked());
if(emulator) emulator->set("Scanline Emulation", scanlineEmulation.checked());
});
@ -89,7 +89,7 @@ Presentation::Presentation() {
program->updateVideoShader();
});
loadShaders();
synchronizeVideo.setText("Synchronize Video").setChecked(settings["Video/Synchronize"].boolean()).onToggle([&] {
synchronizeVideo.setText("Synchronize Video").setChecked(settings["Video/Synchronize"].boolean()).setVisible(false).onToggle([&] {
settings["Video/Synchronize"].setValue(synchronizeVideo.checked());
video->set(Video::Synchronize, synchronizeVideo.checked());
});

View File

@ -47,7 +47,7 @@ private:
}
};
template<typename type, uint Lo, uint Hi = ~0> struct BitField {
template<typename type, uint Lo, uint Hi = ~0U> struct BitField {
enum : uint { lo = Lo <= Hi ? Lo : Hi };
enum : uint { hi = Hi >= Lo ? Hi : Lo };
enum : uint { bits = hi - lo + 1 };
@ -94,7 +94,7 @@ private:
}
};
template<typename type, uint Bit> struct BitField<type, Bit, ~0> {
template<typename type, uint Bit> struct BitField<type, Bit, ~0U> {
enum : uint { bit = Bit };
enum : uint { mask = 1ull << bit };
static_assert(bit < sizeof(type) * 8, "");