mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
f1a80075fa
commit
44a8c5a2b4
|
@ -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/";
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -32,4 +32,3 @@ struct Controller : Cothread {
|
|||
#include "mouse/mouse.hpp"
|
||||
#include "superscope/superscope.hpp"
|
||||
#include "justifier/justifier.hpp"
|
||||
#include "usart/usart.hpp"
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -6,6 +6,6 @@ struct Multitap : Controller {
|
|||
|
||||
private:
|
||||
bool latched;
|
||||
unsigned counter1;
|
||||
unsigned counter2;
|
||||
uint counter1;
|
||||
uint counter2;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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("+");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -26,7 +26,7 @@ auto SMP::Enter() -> void {
|
|||
}
|
||||
|
||||
auto SMP::main() -> void {
|
||||
debugger.op_exec(regs.pc);
|
||||
debugger.execute(regs.pc);
|
||||
instruction();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ struct Device { enum : uint {
|
|||
SuperScope,
|
||||
Justifier,
|
||||
Justifiers,
|
||||
USART,
|
||||
|
||||
//expansion port peripherals
|
||||
Satellaview,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
|
|
|
@ -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, "");
|
||||
|
|
Loading…
Reference in New Issue