mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-12-11 19:13:34 +00:00
Update to v103r04 release.
byuu says: Changelog: - fc/apu: $4003,$4007 writes initialize duty counter to 0 instead of 7 - fc/apu: corrected duty table entries for use with decrementing duty counter - processor/spc700: emulated the behavior of cycle 3 of (x)+ instructions to not read I/O registers - specifically, this prevents reads from $fd-ff from resetting the timers, as observed on real hardware - sfc/controller: added ControllerPort class to match Mega Drive design - sfc/expansion: added ExpansionPort class to match Mega Drive design - sfc/system: removed Peripherals class - sfc/system: changed `colorburst()` to `cpuFrequency()`; added `apuFrequency()` - sfc: replaced calls to `system.region == System::Region::*` with `Region::*()` - sfc/expansion: remove thread from scheduler when device is destroyed - sfc/smp: `{read,write}Port` now use a separate 4x8-bit buffer instead of underlying APU RAM [hex\_usr]
This commit is contained in:
parent
78f341489e
commit
ff3750de4f
@ -12,7 +12,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "103.03";
|
||||
static const string Version = "103.04";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
@ -153,7 +153,7 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
||||
pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8);
|
||||
pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x00ff) | (data << 8);
|
||||
|
||||
pulse[n].dutyCounter = 7;
|
||||
pulse[n].dutyCounter = 0;
|
||||
pulse[n].envelope.reloadDecay = true;
|
||||
|
||||
if(enabledChannels & (1 << n)) {
|
||||
|
@ -9,10 +9,10 @@ auto APU::Pulse::clock() -> uint8 {
|
||||
if(lengthCounter == 0) return 0;
|
||||
|
||||
static const uint dutyTable[4][8] = {
|
||||
{0, 1, 0, 0, 0, 0, 0, 0}, //12.5%
|
||||
{0, 1, 1, 0, 0, 0, 0, 0}, //25.0%
|
||||
{0, 1, 1, 1, 1, 0, 0, 0}, //50.0%
|
||||
{1, 0, 0, 1, 1, 1, 1, 1}, //25.0% (inverted)
|
||||
{0, 0, 0, 0, 0, 0, 0, 1}, //12.5%
|
||||
{0, 0, 0, 0, 0, 0, 1, 1}, //25.0%
|
||||
{0, 0, 0, 0, 1, 1, 1, 1}, //50.0%
|
||||
{1, 1, 1, 1, 1, 1, 0, 0}, //25.0% (negated)
|
||||
};
|
||||
uint8 result = dutyTable[duty][dutyCounter] ? envelope.volume() : 0;
|
||||
if(sweep.pulsePeriod < 0x008) result = 0;
|
||||
|
@ -73,9 +73,9 @@ auto BusCPU::readIO(uint24 addr) -> uint16 {
|
||||
| 0 << 0 //0 = Model 1; 1 = Model 2+
|
||||
);
|
||||
|
||||
case 0xa10002: return controllerPort1.readData();
|
||||
case 0xa10004: return controllerPort2.readData();
|
||||
case 0xa10006: return extensionPort.readData();
|
||||
case 0xa10002: return controllerPort1.device->readData();
|
||||
case 0xa10004: return controllerPort2.device->readData();
|
||||
case 0xa10006: return extensionPort.device->readData();
|
||||
|
||||
case 0xa10008: return controllerPort1.readControl();
|
||||
case 0xa1000a: return controllerPort2.readControl();
|
||||
@ -89,9 +89,9 @@ auto BusCPU::readIO(uint24 addr) -> uint16 {
|
||||
|
||||
auto BusCPU::writeIO(uint24 addr, uint16 data) -> void {
|
||||
switch(addr & ~1) {
|
||||
case 0xa10002: return controllerPort1.writeData(data);
|
||||
case 0xa10004: return controllerPort2.writeData(data);
|
||||
case 0xa10006: return extensionPort.writeData(data);
|
||||
case 0xa10002: return controllerPort1.device->writeData(data);
|
||||
case 0xa10004: return controllerPort2.device->writeData(data);
|
||||
case 0xa10006: return extensionPort.device->writeData(data);
|
||||
|
||||
case 0xa10008: return controllerPort1.writeControl(data);
|
||||
case 0xa1000a: return controllerPort2.writeControl(data);
|
||||
|
@ -8,7 +8,7 @@ ControllerPort extensionPort;
|
||||
#include "gamepad/gamepad.cpp"
|
||||
|
||||
Controller::Controller(uint port) : port(port) {
|
||||
if(!handle()) create(Controller::Enter, 100);
|
||||
if(!handle()) create(Controller::Enter, 1);
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
@ -18,9 +18,9 @@ Controller::~Controller() {
|
||||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
if(controllerPort1.controller->active()) controllerPort1.controller->main();
|
||||
if(controllerPort2.controller->active()) controllerPort2.controller->main();
|
||||
if(extensionPort.controller->active()) extensionPort.controller->main();
|
||||
if(controllerPort1.device->active()) controllerPort1.device->main();
|
||||
if(controllerPort2.device->active()) controllerPort2.device->main();
|
||||
if(extensionPort.device->active()) extensionPort.device->main();
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,27 +31,19 @@ auto Controller::main() -> void {
|
||||
|
||||
//
|
||||
|
||||
auto ControllerPort::connect(uint device) -> void {
|
||||
auto ControllerPort::connect(uint deviceID) -> void {
|
||||
if(!system.loaded()) return;
|
||||
delete controller;
|
||||
delete device;
|
||||
|
||||
switch(device) { default:
|
||||
case ID::Device::None: controller = new Controller(port); break;
|
||||
case ID::Device::Gamepad: controller = new Gamepad(port); break;
|
||||
switch(deviceID) { default:
|
||||
case ID::Device::None: device = new Controller(port); break;
|
||||
case ID::Device::Gamepad: device = new Gamepad(port); break;
|
||||
}
|
||||
|
||||
cpu.peripherals.reset();
|
||||
cpu.peripherals.append(controllerPort1.controller);
|
||||
cpu.peripherals.append(controllerPort2.controller);
|
||||
cpu.peripherals.append(extensionPort.controller);
|
||||
}
|
||||
|
||||
auto ControllerPort::readData() -> uint8 {
|
||||
return controller->readData();
|
||||
}
|
||||
|
||||
auto ControllerPort::writeData(uint8 data) -> void {
|
||||
return controller->writeData(data);
|
||||
if(auto device = controllerPort1.device) cpu.peripherals.append(device);
|
||||
if(auto device = controllerPort2.device) cpu.peripherals.append(device);
|
||||
if(auto device = extensionPort.device) cpu.peripherals.append(device);
|
||||
}
|
||||
|
||||
auto ControllerPort::readControl() -> uint8 {
|
||||
@ -68,8 +60,8 @@ auto ControllerPort::power(uint port) -> void {
|
||||
}
|
||||
|
||||
auto ControllerPort::unload() -> void {
|
||||
delete controller;
|
||||
controller = nullptr;
|
||||
delete device;
|
||||
device = nullptr;
|
||||
}
|
||||
|
||||
auto ControllerPort::serialize(serializer& s) -> void {
|
||||
|
@ -12,10 +12,7 @@ struct Controller : Thread {
|
||||
};
|
||||
|
||||
struct ControllerPort {
|
||||
auto connect(uint device) -> void;
|
||||
|
||||
auto readData() -> uint8;
|
||||
auto writeData(uint8 data) -> void;
|
||||
auto connect(uint deviceID) -> void;
|
||||
|
||||
auto readControl() -> uint8;
|
||||
auto writeControl(uint8 data) -> void;
|
||||
@ -26,7 +23,7 @@ struct ControllerPort {
|
||||
|
||||
uint port;
|
||||
uint8 control;
|
||||
Controller* controller = nullptr;
|
||||
Controller* device = nullptr;
|
||||
};
|
||||
|
||||
extern ControllerPort controllerPort1;
|
||||
|
@ -52,6 +52,7 @@ auto System::save() -> void {
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
cpu.peripherals.reset();
|
||||
controllerPort1.unload();
|
||||
controllerPort2.unload();
|
||||
extensionPort.unload();
|
||||
|
@ -413,15 +413,15 @@ auto SPC700::instructionIndirectXWrite(uint8& data) -> void {
|
||||
|
||||
auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void {
|
||||
idle(PC);
|
||||
data = read(page(X)); //todo: $f0-ff not accessible on this cycle?
|
||||
idle(page(X++));
|
||||
idle(); //quirk: does not read internal SMP registers
|
||||
data = read(page(X++));
|
||||
ZF = data == 0;
|
||||
NF = data & 0x80;
|
||||
}
|
||||
|
||||
auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void {
|
||||
idle(PC);
|
||||
idle(page(X)); //todo: $f0-ff not accessible on this cycle?
|
||||
idle(); //quirk: does not read internal SMP registers
|
||||
write(page(X++), data);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Processor {
|
||||
|
||||
struct SPC700 {
|
||||
virtual auto idle() -> void = 0;
|
||||
virtual auto read(uint16 address) -> uint8 = 0;
|
||||
virtual auto write(uint16 addessr, uint8 data) -> void = 0;
|
||||
virtual auto synchronizing() const -> bool = 0;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
ControllerPort controllerPort1;
|
||||
ControllerPort controllerPort2;
|
||||
#include "gamepad/gamepad.cpp"
|
||||
#include "mouse/mouse.cpp"
|
||||
#include "super-multitap/super-multitap.cpp"
|
||||
@ -19,8 +21,8 @@ Controller::~Controller() {
|
||||
auto Controller::Enter() -> void {
|
||||
while(true) {
|
||||
scheduler.synchronize();
|
||||
if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main();
|
||||
if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main();
|
||||
if(controllerPort1.device->active()) controllerPort1.device->main();
|
||||
if(controllerPort2.device->active()) controllerPort2.device->main();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,4 +45,38 @@ auto Controller::iobit(bool data) -> void {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ControllerPort::connect(uint deviceID) -> void {
|
||||
if(!system.loaded()) return;
|
||||
delete device;
|
||||
|
||||
switch(deviceID) { default:
|
||||
case ID::Device::None: device = new Controller(port); break;
|
||||
case ID::Device::Gamepad: device = new Gamepad(port); break;
|
||||
case ID::Device::Mouse: device = new Mouse(port); break;
|
||||
case ID::Device::SuperMultitap: device = new SuperMultitap(port); break;
|
||||
case ID::Device::SuperScope: device = new SuperScope(port); break;
|
||||
case ID::Device::Justifier: device = new Justifier(port, false); break;
|
||||
case ID::Device::Justifiers: device = new Justifier(port, true); break;
|
||||
}
|
||||
|
||||
cpu.peripherals.reset();
|
||||
if(auto device = controllerPort1.device) cpu.peripherals.append(device);
|
||||
if(auto device = controllerPort2.device) cpu.peripherals.append(device);
|
||||
if(auto device = expansionPort.device) cpu.peripherals.append(device);
|
||||
}
|
||||
|
||||
auto ControllerPort::power(uint port) -> void {
|
||||
this->port = port;
|
||||
}
|
||||
|
||||
auto ControllerPort::unload() -> void {
|
||||
delete device;
|
||||
device = nullptr;
|
||||
}
|
||||
|
||||
auto ControllerPort::serialize(serializer& s) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,20 @@ struct Controller : Thread {
|
||||
const bool port;
|
||||
};
|
||||
|
||||
struct ControllerPort {
|
||||
auto connect(uint deviceID) -> void;
|
||||
|
||||
auto power(uint port) -> void;
|
||||
auto unload() -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint port;
|
||||
Controller* device = nullptr;
|
||||
};
|
||||
|
||||
extern ControllerPort controllerPort1;
|
||||
extern ControllerPort controllerPort2;
|
||||
|
||||
#include "gamepad/gamepad.hpp"
|
||||
#include "mouse/mouse.hpp"
|
||||
#include "super-multitap/super-multitap.hpp"
|
||||
|
@ -46,7 +46,7 @@ auto ICD2::unload() -> void {
|
||||
}
|
||||
|
||||
auto ICD2::power() -> void {
|
||||
create(ICD2::Enter, system.colorburst() * 6.0 / 5.0);
|
||||
create(ICD2::Enter, system.cpuFrequency() / 5.0);
|
||||
stream = Emulator::audio.createStream(2, frequency() / 2.0);
|
||||
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);
|
||||
stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3);
|
||||
@ -76,8 +76,7 @@ auto ICD2::power() -> void {
|
||||
}
|
||||
|
||||
auto ICD2::reset() -> void {
|
||||
auto frequency = system.colorburst() * 6.0;
|
||||
create(ICD2::Enter, frequency / 5);
|
||||
create(ICD2::Enter, system.cpuFrequency() / 5.0);
|
||||
|
||||
r6003 = 0x00;
|
||||
r6004 = 0xff;
|
||||
|
@ -56,7 +56,7 @@ auto ICD2::writeIO(uint24 addr, uint8 data) -> void {
|
||||
if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) {
|
||||
reset();
|
||||
}
|
||||
auto frequency = system.colorburst() * 6.0;
|
||||
auto frequency = system.cpuFrequency();
|
||||
switch(data & 3) {
|
||||
case 0: setFrequency(frequency / 4); break; //fast (glitchy, even on real hardware)
|
||||
case 1: setFrequency(frequency / 5); break; //normal
|
||||
|
@ -131,7 +131,7 @@ auto SA1::unload() -> void {
|
||||
|
||||
auto SA1::power() -> void {
|
||||
WDC65816::power();
|
||||
create(SA1::Enter, system.colorburst() * 6.0);
|
||||
create(SA1::Enter, system.cpuFrequency());
|
||||
|
||||
cpubwram.dma = false;
|
||||
for(auto addr : range(iram.size())) {
|
||||
@ -142,7 +142,7 @@ auto SA1::power() -> void {
|
||||
|
||||
status.interruptPending = false;
|
||||
|
||||
status.scanlines = (system.region() == System::Region::NTSC ? 262 : 312);
|
||||
status.scanlines = Region::PAL() ? 312 : 262;
|
||||
status.vcounter = 0;
|
||||
status.hcounter = 0;
|
||||
|
||||
|
@ -44,7 +44,7 @@ auto SuperFX::unload() -> void {
|
||||
|
||||
auto SuperFX::power() -> void {
|
||||
GSU::power();
|
||||
create(SuperFX::Enter, system.colorburst() * 6.0);
|
||||
create(SuperFX::Enter, system.cpuFrequency());
|
||||
|
||||
romMask = rom.size() - 1;
|
||||
ramMask = ram.size() - 1;
|
||||
|
@ -62,7 +62,7 @@ auto CPU::load(Markup::Node node) -> bool {
|
||||
|
||||
auto CPU::power() -> void {
|
||||
WDC65816::power();
|
||||
create(Enter, system.colorburst() * 6.0);
|
||||
create(Enter, system.cpuFrequency());
|
||||
coprocessors.reset();
|
||||
PPUcounter::reset();
|
||||
|
||||
|
@ -16,7 +16,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
||||
//1-0 = Joypad serial data
|
||||
case 0x4016: {
|
||||
uint8 v = r.mdr & 0xfc;
|
||||
v |= SuperFamicom::peripherals.controllerPort1->data();
|
||||
v |= controllerPort1.device->data();
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 {
|
||||
//4-2 = Always 1 (pins are connected to GND)
|
||||
//1-0 = Joypad serial data
|
||||
uint8 v = (r.mdr & 0xe0) | 0x1c;
|
||||
v |= SuperFamicom::peripherals.controllerPort2->data();
|
||||
v |= controllerPort2.device->data();
|
||||
return v;
|
||||
}
|
||||
|
||||
@ -178,8 +178,8 @@ auto CPU::writeCPU(uint24 addr, uint8 data) -> void {
|
||||
//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));
|
||||
controllerPort1.device->latch(data.bit(0));
|
||||
controllerPort2.device->latch(data.bit(0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -145,14 +145,14 @@ auto CPU::joypadEdge() -> void {
|
||||
|
||||
if(status.autoJoypadActive && status.autoJoypadLatch) {
|
||||
if(status.autoJoypadCounter == 0) {
|
||||
SuperFamicom::peripherals.controllerPort1->latch(1);
|
||||
SuperFamicom::peripherals.controllerPort2->latch(1);
|
||||
SuperFamicom::peripherals.controllerPort1->latch(0);
|
||||
SuperFamicom::peripherals.controllerPort2->latch(0);
|
||||
controllerPort1.device->latch(1);
|
||||
controllerPort2.device->latch(1);
|
||||
controllerPort1.device->latch(0);
|
||||
controllerPort2.device->latch(0);
|
||||
}
|
||||
|
||||
uint2 port0 = SuperFamicom::peripherals.controllerPort1->data();
|
||||
uint2 port1 = SuperFamicom::peripherals.controllerPort2->data();
|
||||
uint2 port0 = controllerPort1.device->data();
|
||||
uint2 port1 = controllerPort2.device->data();
|
||||
|
||||
io.joy1 = io.joy1 << 1 | port0.bit(0);
|
||||
io.joy2 = io.joy2 << 1 | port1.bit(0);
|
||||
|
@ -229,7 +229,7 @@ auto DSP::load(Markup::Node node) -> bool {
|
||||
}
|
||||
|
||||
auto DSP::power() -> void {
|
||||
create(Enter, 32040.0 * 768.0);
|
||||
create(Enter, system.apuFrequency());
|
||||
stream = Emulator::audio.createStream(2, frequency() / 768.0);
|
||||
|
||||
memory::fill(&state, sizeof(State));
|
||||
|
@ -52,7 +52,7 @@ S21FX::~S21FX() {
|
||||
}
|
||||
|
||||
auto S21FX::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), peripherals.expansionPort->main();
|
||||
while(true) scheduler.synchronize(), expansionPort.device->main();
|
||||
}
|
||||
|
||||
auto S21FX::step(uint clocks) -> void {
|
||||
|
@ -2,12 +2,18 @@
|
||||
|
||||
namespace SuperFamicom {
|
||||
|
||||
ExpansionPort expansionPort;
|
||||
|
||||
Expansion::Expansion() {
|
||||
if(!handle()) create(Expansion::Enter, 1);
|
||||
}
|
||||
|
||||
Expansion::~Expansion() {
|
||||
scheduler.remove(*this);
|
||||
}
|
||||
|
||||
auto Expansion::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), peripherals.expansionPort->main();
|
||||
while(true) scheduler.synchronize(), expansionPort.device->main();
|
||||
}
|
||||
|
||||
auto Expansion::main() -> void {
|
||||
@ -15,4 +21,33 @@ auto Expansion::main() -> void {
|
||||
synchronize(cpu);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ExpansionPort::connect(uint deviceID) -> void {
|
||||
if(!system.loaded()) return;
|
||||
delete device;
|
||||
|
||||
switch(deviceID) { default:
|
||||
case ID::Device::None: device = new Expansion; break;
|
||||
case ID::Device::Satellaview: device = new Satellaview; break;
|
||||
case ID::Device::S21FX: device = new S21FX; break;
|
||||
}
|
||||
|
||||
cpu.peripherals.reset();
|
||||
if(auto device = controllerPort1.device) cpu.peripherals.append(device);
|
||||
if(auto device = controllerPort2.device) cpu.peripherals.append(device);
|
||||
if(auto device = expansionPort.device) cpu.peripherals.append(device);
|
||||
}
|
||||
|
||||
auto ExpansionPort::power() -> void {
|
||||
}
|
||||
|
||||
auto ExpansionPort::unload() -> void {
|
||||
delete device;
|
||||
device = nullptr;
|
||||
}
|
||||
|
||||
auto ExpansionPort::serialize(serializer& s) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,21 @@
|
||||
struct Expansion : Thread {
|
||||
Expansion();
|
||||
virtual ~Expansion();
|
||||
static auto Enter() -> void;
|
||||
virtual auto main() -> void;
|
||||
};
|
||||
|
||||
struct ExpansionPort {
|
||||
auto connect(uint deviceID) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto unload() -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
Expansion* device = nullptr;
|
||||
};
|
||||
|
||||
extern ExpansionPort expansionPort;
|
||||
|
||||
#include <sfc/expansion/satellaview/satellaview.hpp>
|
||||
#include <sfc/expansion/21fx/21fx.hpp>
|
||||
|
@ -187,7 +187,9 @@ auto Interface::unload() -> void {
|
||||
}
|
||||
|
||||
auto Interface::connect(uint port, uint device) -> void {
|
||||
peripherals.connect(port, device);
|
||||
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
|
||||
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);
|
||||
if(port == ID::Port::Expansion) expansionPort.connect(settings.expansionPort = device);
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
|
@ -27,12 +27,12 @@ auto PPUcounter::tick(uint clocks) -> void {
|
||||
auto PPUcounter::vcounterTick() -> void {
|
||||
if(++status.vcounter == 128) status.interlace = ppu.interlace();
|
||||
|
||||
if((system.region() == System::Region::NTSC && status.interlace == 0 && status.vcounter == 262)
|
||||
|| (system.region() == System::Region::NTSC && status.interlace == 1 && status.vcounter == 263)
|
||||
|| (system.region() == System::Region::NTSC && status.interlace == 1 && status.vcounter == 262 && status.field == 1)
|
||||
|| (system.region() == System::Region::PAL && status.interlace == 0 && status.vcounter == 312)
|
||||
|| (system.region() == System::Region::PAL && status.interlace == 1 && status.vcounter == 313)
|
||||
|| (system.region() == System::Region::PAL && status.interlace == 1 && status.vcounter == 312 && status.field == 1)
|
||||
if((Region::NTSC() && status.interlace == 0 && status.vcounter == 262)
|
||||
|| (Region::NTSC() && status.interlace == 1 && status.vcounter == 263)
|
||||
|| (Region::NTSC() && status.interlace == 1 && status.vcounter == 262 && status.field == 1)
|
||||
|| (Region::PAL() && status.interlace == 0 && status.vcounter == 312)
|
||||
|| (Region::PAL() && status.interlace == 1 && status.vcounter == 313)
|
||||
|| (Region::PAL() && status.interlace == 1 && status.vcounter == 312 && status.field == 1)
|
||||
) {
|
||||
status.vcounter = 0;
|
||||
status.field = !status.field;
|
||||
@ -58,7 +58,7 @@ auto PPUcounter::hcounter(uint offset) const -> uint16 { return history.hcounter
|
||||
//dot 327 range = {1310, 1312, 1314}
|
||||
|
||||
auto PPUcounter::hdot() const -> uint16 {
|
||||
if(system.region() == System::Region::NTSC && status.interlace == 0 && vcounter() == 240 && field() == 1) {
|
||||
if(Region::NTSC() && status.interlace == 0 && vcounter() == 240 && field() == 1) {
|
||||
return (hcounter() >> 2);
|
||||
} else {
|
||||
return (hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1)) >> 2;
|
||||
@ -66,7 +66,7 @@ auto PPUcounter::hdot() const -> uint16 {
|
||||
}
|
||||
|
||||
auto PPUcounter::lineclocks() const -> uint16 {
|
||||
if(system.region() == System::Region::NTSC && status.interlace == 0 && vcounter() == 240 && field() == 1) return 1360;
|
||||
if(Region::NTSC() && status.interlace == 0 && vcounter() == 240 && field() == 1) return 1360;
|
||||
return 1364;
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 {
|
||||
latch.vcounter = 0;
|
||||
|
||||
ppu2.mdr.bits(0,3) = ppu2.version;
|
||||
ppu2.mdr.bit ( 4) = system.region() == System::Region::PAL; //0 = NTSC
|
||||
ppu2.mdr.bit ( 4) = Region::PAL(); //0 = NTSC, 1 = PAL
|
||||
if(!cpu.pio().bit(7)) {
|
||||
ppu2.mdr.bit( 6) = 1;
|
||||
} else {
|
||||
|
@ -87,7 +87,7 @@ auto PPU::load(Markup::Node node) -> bool {
|
||||
}
|
||||
|
||||
auto PPU::power() -> void {
|
||||
create(Enter, system.colorburst() * 6.0);
|
||||
create(Enter, system.cpuFrequency());
|
||||
PPUcounter::reset();
|
||||
memory::fill(output, 512 * 480 * sizeof(uint32));
|
||||
|
||||
|
@ -10,11 +10,11 @@ alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto SMP::readPort(uint2 port) const -> uint8 {
|
||||
return apuram[0xf4 + port];
|
||||
return io.port[0xf4 + port];
|
||||
}
|
||||
|
||||
auto SMP::writePort(uint2 port, uint8 data) -> void {
|
||||
apuram[0xf4 + port] = data;
|
||||
io.port[0xf4 + port] = data;
|
||||
}
|
||||
|
||||
auto SMP::readBus(uint16 addr) -> uint8 {
|
||||
@ -173,6 +173,11 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void {
|
||||
writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus
|
||||
}
|
||||
|
||||
auto SMP::idle() -> void {
|
||||
step(24);
|
||||
cycleEdge();
|
||||
}
|
||||
|
||||
auto SMP::read(uint16 addr) -> uint8 {
|
||||
step(12);
|
||||
uint8 data = readBus(addr);
|
||||
|
@ -19,6 +19,8 @@ auto SMP::serialize(serializer& s) -> void {
|
||||
|
||||
s.integer(io.dspAddr);
|
||||
|
||||
s.array(io.port);
|
||||
|
||||
s.integer(io.ram00f8);
|
||||
s.integer(io.ram00f9);
|
||||
|
||||
|
@ -34,16 +34,12 @@ auto SMP::load(Markup::Node node) -> bool {
|
||||
|
||||
auto SMP::power() -> void {
|
||||
SPC700::power();
|
||||
create(Enter, 32040.0 * 768.0);
|
||||
create(Enter, system.apuFrequency());
|
||||
|
||||
r.pc.byte.l = iplrom[62];
|
||||
r.pc.byte.h = iplrom[63];
|
||||
|
||||
for(auto& byte : apuram) byte = random(0x00);
|
||||
apuram[0x00f4] = 0x00;
|
||||
apuram[0x00f5] = 0x00;
|
||||
apuram[0x00f6] = 0x00;
|
||||
apuram[0x00f7] = 0x00;
|
||||
|
||||
io.clockCounter = 0;
|
||||
io.dspCounter = 0;
|
||||
@ -63,6 +59,12 @@ auto SMP::power() -> void {
|
||||
//$00f2
|
||||
io.dspAddr = 0x00;
|
||||
|
||||
//$00f4-00f7
|
||||
io.port[0] = 0x00;
|
||||
io.port[1] = 0x00;
|
||||
io.port[2] = 0x00;
|
||||
io.port[3] = 0x00;
|
||||
|
||||
//$00f8,$00f9
|
||||
io.ram00f8 = 0x00;
|
||||
io.ram00f9 = 0x00;
|
||||
|
@ -38,6 +38,9 @@ private:
|
||||
//$00f2
|
||||
uint8 dspAddr;
|
||||
|
||||
//$00f4-00f7
|
||||
uint8 port[4];
|
||||
|
||||
//$00f8,$00f9
|
||||
uint8 ram00f8;
|
||||
uint8 ram00f9;
|
||||
@ -52,6 +55,7 @@ private:
|
||||
auto readBus(uint16 addr) -> uint8;
|
||||
auto writeBus(uint16 addr, uint8 data) -> void;
|
||||
|
||||
auto idle() -> void override;
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
Peripherals peripherals;
|
||||
|
||||
auto Peripherals::unload() -> void {
|
||||
delete controllerPort1;
|
||||
delete controllerPort2;
|
||||
delete expansionPort;
|
||||
controllerPort1 = nullptr;
|
||||
controllerPort2 = nullptr;
|
||||
expansionPort = nullptr;
|
||||
}
|
||||
|
||||
auto Peripherals::reset() -> void {
|
||||
connect(ID::Port::Controller1, settings.controllerPort1);
|
||||
connect(ID::Port::Controller2, settings.controllerPort2);
|
||||
connect(ID::Port::Expansion, settings.expansionPort);
|
||||
}
|
||||
|
||||
auto Peripherals::connect(uint port, uint device) -> void {
|
||||
if(port == ID::Port::Controller1) {
|
||||
settings.controllerPort1 = device;
|
||||
if(!system.loaded()) return;
|
||||
|
||||
delete controllerPort1;
|
||||
switch(device) { default:
|
||||
case ID::Device::None: controllerPort1 = new Controller(0); break;
|
||||
case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break;
|
||||
case ID::Device::Mouse: controllerPort1 = new Mouse(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(port == ID::Port::Controller2) {
|
||||
settings.controllerPort2 = device;
|
||||
if(!system.loaded()) return;
|
||||
|
||||
delete controllerPort2;
|
||||
switch(device) { default:
|
||||
case ID::Device::None: controllerPort2 = new Controller(1); break;
|
||||
case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break;
|
||||
case ID::Device::Mouse: controllerPort2 = new Mouse(1); break;
|
||||
case ID::Device::SuperMultitap: controllerPort2 = new SuperMultitap(1); break;
|
||||
case ID::Device::SuperScope: controllerPort2 = new SuperScope(1); break;
|
||||
case ID::Device::Justifier: controllerPort2 = new Justifier(1, false); break;
|
||||
case ID::Device::Justifiers: controllerPort2 = new Justifier(1, true); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(port == ID::Port::Expansion) {
|
||||
settings.expansionPort = device;
|
||||
if(!system.loaded()) return;
|
||||
|
||||
delete expansionPort;
|
||||
switch(device) { default:
|
||||
case ID::Device::None: expansionPort = new Expansion; break;
|
||||
case ID::Device::Satellaview: expansionPort = new Satellaview; break;
|
||||
case ID::Device::S21FX: expansionPort = new S21FX; break;
|
||||
}
|
||||
}
|
||||
|
||||
cpu.peripherals.reset();
|
||||
cpu.peripherals.append(controllerPort1);
|
||||
cpu.peripherals.append(controllerPort2);
|
||||
cpu.peripherals.append(expansionPort);
|
||||
}
|
@ -66,6 +66,10 @@ auto System::serializeAll(serializer& s) -> void {
|
||||
if(cartridge.has.MSU1) msu1.serialize(s);
|
||||
|
||||
if(cartridge.has.SufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s);
|
||||
|
||||
controllerPort1.serialize(s);
|
||||
controllerPort2.serialize(s);
|
||||
expansionPort.serialize(s);
|
||||
}
|
||||
|
||||
//perform dry-run state save:
|
||||
|
@ -6,7 +6,6 @@ System system;
|
||||
Scheduler scheduler;
|
||||
Cheat cheat;
|
||||
#include "video.cpp"
|
||||
#include "peripherals.cpp"
|
||||
#include "random.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
@ -65,11 +64,11 @@ auto System::load(Emulator::Interface* interface) -> bool {
|
||||
|
||||
if(cartridge.region() == "NTSC") {
|
||||
information.region = Region::NTSC;
|
||||
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
information.cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0;
|
||||
}
|
||||
if(cartridge.region() == "PAL") {
|
||||
information.region = Region::PAL;
|
||||
information.colorburst = Emulator::Constants::Colorburst::PAL * 4.0 / 5.0;
|
||||
information.cpuFrequency = Emulator::Constants::Colorburst::PAL * 4.8;
|
||||
}
|
||||
|
||||
if(cartridge.has.ICD2) icd2.load();
|
||||
@ -98,12 +97,17 @@ auto System::load(Emulator::Interface* interface) -> bool {
|
||||
|
||||
auto System::save() -> void {
|
||||
if(!loaded()) return;
|
||||
|
||||
cartridge.save();
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
if(!loaded()) return;
|
||||
peripherals.unload();
|
||||
|
||||
cpu.peripherals.reset();
|
||||
controllerPort1.unload();
|
||||
controllerPort2.unload();
|
||||
expansionPort.unload();
|
||||
|
||||
if(cartridge.has.ICD2) icd2.unload();
|
||||
if(cartridge.has.MCC) mcc.unload();
|
||||
@ -176,7 +180,14 @@ auto System::power() -> void {
|
||||
if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1);
|
||||
|
||||
scheduler.primary(cpu);
|
||||
peripherals.reset();
|
||||
|
||||
controllerPort1.power(ID::Port::Controller1);
|
||||
controllerPort2.power(ID::Port::Controller2);
|
||||
expansionPort.power();
|
||||
|
||||
controllerPort1.connect(settings.controllerPort1);
|
||||
controllerPort2.connect(settings.controllerPort2);
|
||||
expansionPort.connect(settings.expansionPort);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,7 +3,8 @@ struct System {
|
||||
|
||||
inline auto loaded() const -> bool { return information.loaded; }
|
||||
inline auto region() const -> Region { return information.region; }
|
||||
inline auto colorburst() const -> double { return information.colorburst; }
|
||||
inline auto cpuFrequency() const -> double { return information.cpuFrequency; }
|
||||
inline auto apuFrequency() const -> double { return information.apuFrequency; }
|
||||
|
||||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
@ -30,7 +31,8 @@ private:
|
||||
string manifest;
|
||||
bool loaded = false;
|
||||
Region region = Region::NTSC;
|
||||
double colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||
double cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0;
|
||||
double apuFrequency = 32040.0 * 768.0;
|
||||
} information;
|
||||
|
||||
uint serializeSize = 0;
|
||||
@ -42,16 +44,6 @@ private:
|
||||
friend class Cartridge;
|
||||
};
|
||||
|
||||
struct Peripherals {
|
||||
auto unload() -> void;
|
||||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* controllerPort1 = nullptr;
|
||||
Controller* controllerPort2 = nullptr;
|
||||
Expansion* expansionPort = nullptr;
|
||||
};
|
||||
|
||||
struct Random {
|
||||
auto seed(uint seed) -> void;
|
||||
auto operator()(uint result) -> uint;
|
||||
@ -62,7 +54,6 @@ private:
|
||||
};
|
||||
|
||||
extern System system;
|
||||
extern Peripherals peripherals;
|
||||
extern Random random;
|
||||
|
||||
auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; }
|
||||
|
Loading…
Reference in New Issue
Block a user