mirror of https://github.com/bsnes-emu/bsnes.git
Update to v099r11 release.
byuu says: Changelog: - NES PPU core updated to use BitFields (absolutely massive improvement in code readability) - NES APU core updated to new coding style - NES cartridge/board and cartridge/chip updated to new coding style - pushed NES PPU rendering one dot forward (doesn't fix King's Quest V yet, sadly) - fixed SNES PPU BG tilemask for 128KiB VRAM mode (doesn't fix Yoshi's Island, though) So ... I kind of went overboard with the fc/cartridge changes. This WIP diff is 185KiB >_> I didn't realize it was going to be as big a task as it was, but once I started everything broke in a chain reaction, so I had to do it all at once. There's a massive chance we've broken a bunch of NES things. Any typos in this WIP are going to be absolutely insidious to track down =( But ... supposing I pulled it off, this means the Famicom core is now fully converted to the new coding style as well. That leaves only the GB and GBA cores. Once those are finished, then we'll finally be free of these gigantic hellspawn diffs.
This commit is contained in:
parent
a816998122
commit
3e807946b8
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "099.10";
|
||||
static const string Version = "099.11";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -14,9 +14,9 @@ APU apu;
|
|||
APU::APU() {
|
||||
for(uint amp : range(32)) {
|
||||
if(amp == 0) {
|
||||
pulse_dac[amp] = 0;
|
||||
pulseDAC[amp] = 0;
|
||||
} else {
|
||||
pulse_dac[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0);
|
||||
pulseDAC[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ APU::APU() {
|
|||
for(uint triangle_amp : range(16)) {
|
||||
for(uint noise_amp : range(16)) {
|
||||
if(dmc_amp == 0 && triangle_amp == 0 && noise_amp == 0) {
|
||||
dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp] = 0;
|
||||
dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp] = 0;
|
||||
} else {
|
||||
dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp]
|
||||
dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp]
|
||||
= 16384.0 * 159.79 / (100.0 + 1.0 / (triangle_amp / 8227.0 + noise_amp / 12241.0 + dmc_amp / 22638.0));
|
||||
}
|
||||
}
|
||||
|
@ -47,14 +47,14 @@ auto APU::main() -> void {
|
|||
noise_output = noise.clock();
|
||||
dmc_output = dmc.clock();
|
||||
|
||||
clock_frame_counter_divider();
|
||||
clockFrameCounterDivider();
|
||||
|
||||
int output = pulse_dac[pulse_output] + dmc_triangle_noise_dac[dmc_output][triangle_output][noise_output];
|
||||
int output = pulseDAC[pulse_output] + dmcTriangleNoiseDAC[dmc_output][triangle_output][noise_output];
|
||||
|
||||
output = filter.run_hipass_strong(output);
|
||||
output += cartridge_sample;
|
||||
output = filter.run_hipass_weak(output);
|
||||
//output = filter.run_lopass(output);
|
||||
output = filter.runHipassStrong(output);
|
||||
output += cartridgeSample;
|
||||
output = filter.runHipassWeak(output);
|
||||
//output = filter.runLopass(output);
|
||||
output = sclamp<16>(output);
|
||||
|
||||
stream->sample(output / 32768.0);
|
||||
|
@ -67,17 +67,17 @@ auto APU::tick() -> void {
|
|||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
auto APU::set_irq_line() -> void {
|
||||
cpu.apuLine(frame.irq_pending || dmc.irq_pending);
|
||||
auto APU::setIRQ() -> void {
|
||||
cpu.apuLine(frame.irqPending || dmc.irqPending);
|
||||
}
|
||||
|
||||
auto APU::set_sample(int16 sample) -> void {
|
||||
cartridge_sample = sample;
|
||||
auto APU::setSample(int16 sample) -> void {
|
||||
cartridgeSample = sample;
|
||||
}
|
||||
|
||||
auto APU::power() -> void {
|
||||
filter.hipass_strong = 0;
|
||||
filter.hipass_weak = 0;
|
||||
filter.hipassStrong = 0;
|
||||
filter.hipassWeak = 0;
|
||||
filter.lopass = 0;
|
||||
|
||||
pulse[0].power();
|
||||
|
@ -97,16 +97,16 @@ auto APU::reset() -> void {
|
|||
noise.reset();
|
||||
dmc.reset();
|
||||
|
||||
frame.irq_pending = 0;
|
||||
frame.irqPending = 0;
|
||||
|
||||
frame.mode = 0;
|
||||
frame.counter = 0;
|
||||
frame.divider = 1;
|
||||
|
||||
enabled_channels = 0;
|
||||
cartridge_sample = 0;
|
||||
enabledChannels = 0;
|
||||
cartridgeSample = 0;
|
||||
|
||||
set_irq_line();
|
||||
setIRQ();
|
||||
}
|
||||
|
||||
auto APU::readIO(uint16 addr) -> uint8 {
|
||||
|
@ -114,16 +114,16 @@ auto APU::readIO(uint16 addr) -> uint8 {
|
|||
|
||||
case 0x4015: {
|
||||
uint8 result = 0x00;
|
||||
result |= pulse[0].length_counter ? 0x01 : 0;
|
||||
result |= pulse[1].length_counter ? 0x02 : 0;
|
||||
result |= triangle.length_counter ? 0x04 : 0;
|
||||
result |= noise.length_counter ? 0x08 : 0;
|
||||
result |= dmc.length_counter ? 0x10 : 0;
|
||||
result |= frame.irq_pending ? 0x40 : 0;
|
||||
result |= dmc.irq_pending ? 0x80 : 0;
|
||||
result |= pulse[0].lengthCounter ? 0x01 : 0;
|
||||
result |= pulse[1].lengthCounter ? 0x02 : 0;
|
||||
result |= triangle.lengthCounter ? 0x04 : 0;
|
||||
result |= noise.lengthCounter ? 0x08 : 0;
|
||||
result |= dmc.lengthCounter ? 0x10 : 0;
|
||||
result |= frame.irqPending ? 0x40 : 0;
|
||||
result |= dmc.irqPending ? 0x80 : 0;
|
||||
|
||||
frame.irq_pending = false;
|
||||
set_irq_line();
|
||||
frame.irqPending = false;
|
||||
setIRQ();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
|
||||
case 0x4000: case 0x4004: {
|
||||
pulse[n].duty = data >> 6;
|
||||
pulse[n].envelope.loop_mode = data & 0x20;
|
||||
pulse[n].envelope.use_speed_as_volume = data & 0x10;
|
||||
pulse[n].envelope.loopMode = data & 0x20;
|
||||
pulse[n].envelope.useSpeedAsVolume = data & 0x10;
|
||||
pulse[n].envelope.speed = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
@ -157,26 +157,26 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
|
||||
case 0x4002: case 0x4006: {
|
||||
pulse[n].period = (pulse[n].period & 0x0700) | (data << 0);
|
||||
pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x0700) | (data << 0);
|
||||
pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x0700) | (data << 0);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4003: case 0x4007: {
|
||||
pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8);
|
||||
pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x00ff) | (data << 8);
|
||||
pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x00ff) | (data << 8);
|
||||
|
||||
pulse[n].duty_counter = 7;
|
||||
pulse[n].envelope.reload_decay = true;
|
||||
pulse[n].dutyCounter = 7;
|
||||
pulse[n].envelope.reloadDecay = true;
|
||||
|
||||
if(enabled_channels & (1 << n)) {
|
||||
pulse[n].length_counter = length_counter_table[(data >> 3) & 0x1f];
|
||||
if(enabledChannels & (1 << n)) {
|
||||
pulse[n].lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4008: {
|
||||
triangle.halt_length_counter = data & 0x80;
|
||||
triangle.linear_length = data & 0x7f;
|
||||
triangle.haltLengthCounter = data & 0x80;
|
||||
triangle.linearLength = data & 0x7f;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -188,72 +188,72 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
case 0x400b: {
|
||||
triangle.period = (triangle.period & 0x00ff) | (data << 8);
|
||||
|
||||
triangle.reload_linear = true;
|
||||
triangle.reloadLinear = true;
|
||||
|
||||
if(enabled_channels & (1 << 2)) {
|
||||
triangle.length_counter = length_counter_table[(data >> 3) & 0x1f];
|
||||
if(enabledChannels & (1 << 2)) {
|
||||
triangle.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x400c: {
|
||||
noise.envelope.loop_mode = data & 0x20;
|
||||
noise.envelope.use_speed_as_volume = data & 0x10;
|
||||
noise.envelope.loopMode = data & 0x20;
|
||||
noise.envelope.useSpeedAsVolume = data & 0x10;
|
||||
noise.envelope.speed = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x400e: {
|
||||
noise.short_mode = data & 0x80;
|
||||
noise.shortMode = data & 0x80;
|
||||
noise.period = data & 0x0f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x400f: {
|
||||
noise.envelope.reload_decay = true;
|
||||
noise.envelope.reloadDecay = true;
|
||||
|
||||
if(enabled_channels & (1 << 3)) {
|
||||
noise.length_counter = length_counter_table[(data >> 3) & 0x1f];
|
||||
if(enabledChannels & (1 << 3)) {
|
||||
noise.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4010: {
|
||||
dmc.irq_enable = data & 0x80;
|
||||
dmc.loop_mode = data & 0x40;
|
||||
dmc.irqEnable = data & 0x80;
|
||||
dmc.loopMode = data & 0x40;
|
||||
dmc.period = data & 0x0f;
|
||||
|
||||
dmc.irq_pending = dmc.irq_pending && dmc.irq_enable && !dmc.loop_mode;
|
||||
set_irq_line();
|
||||
dmc.irqPending = dmc.irqPending && dmc.irqEnable && !dmc.loopMode;
|
||||
setIRQ();
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4011: {
|
||||
dmc.dac_latch = data & 0x7f;
|
||||
dmc.dacLatch = data & 0x7f;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4012: {
|
||||
dmc.addr_latch = data;
|
||||
dmc.addrLatch = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4013: {
|
||||
dmc.length_latch = data;
|
||||
dmc.lengthLatch = data;
|
||||
return;
|
||||
}
|
||||
|
||||
case 0x4015: {
|
||||
if((data & 0x01) == 0) pulse[0].length_counter = 0;
|
||||
if((data & 0x02) == 0) pulse[1].length_counter = 0;
|
||||
if((data & 0x04) == 0) triangle.length_counter = 0;
|
||||
if((data & 0x08) == 0) noise.length_counter = 0;
|
||||
if((data & 0x01) == 0) pulse[0].lengthCounter = 0;
|
||||
if((data & 0x02) == 0) pulse[1].lengthCounter = 0;
|
||||
if((data & 0x04) == 0) triangle.lengthCounter = 0;
|
||||
if((data & 0x08) == 0) noise.lengthCounter = 0;
|
||||
|
||||
(data & 0x10) ? dmc.start() : dmc.stop();
|
||||
dmc.irq_pending = false;
|
||||
dmc.irqPending = false;
|
||||
|
||||
set_irq_line();
|
||||
enabled_channels = data & 0x1f;
|
||||
setIRQ();
|
||||
enabledChannels = data & 0x1f;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -261,10 +261,10 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
frame.mode = data >> 6;
|
||||
|
||||
frame.counter = 0;
|
||||
if(frame.mode & 2) clock_frame_counter();
|
||||
if(frame.mode & 2) clockFrameCounter();
|
||||
if(frame.mode & 1) {
|
||||
frame.irq_pending = false;
|
||||
set_irq_line();
|
||||
frame.irqPending = false;
|
||||
setIRQ();
|
||||
}
|
||||
frame.divider = FrameCounter::NtscPeriod;
|
||||
return;
|
||||
|
@ -273,73 +273,73 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto APU::Filter::run_hipass_strong(int sample) -> int {
|
||||
hipass_strong += ((((int64)sample << 16) - (hipass_strong >> 16)) * HiPassStrong) >> 16;
|
||||
return sample - (hipass_strong >> 32);
|
||||
auto APU::Filter::runHipassStrong(int sample) -> int {
|
||||
hipassStrong += ((((int64)sample << 16) - (hipassStrong >> 16)) * HiPassStrong) >> 16;
|
||||
return sample - (hipassStrong >> 32);
|
||||
}
|
||||
|
||||
auto APU::Filter::run_hipass_weak(int sample) -> int {
|
||||
hipass_weak += ((((int64)sample << 16) - (hipass_weak >> 16)) * HiPassWeak) >> 16;
|
||||
return sample - (hipass_weak >> 32);
|
||||
auto APU::Filter::runHipassWeak(int sample) -> int {
|
||||
hipassWeak += ((((int64)sample << 16) - (hipassWeak >> 16)) * HiPassWeak) >> 16;
|
||||
return sample - (hipassWeak >> 32);
|
||||
}
|
||||
|
||||
auto APU::Filter::run_lopass(int sample) -> int {
|
||||
auto APU::Filter::runLopass(int sample) -> int {
|
||||
lopass += ((((int64)sample << 16) - (lopass >> 16)) * LoPass) >> 16;
|
||||
return (lopass >> 32);
|
||||
}
|
||||
|
||||
auto APU::clock_frame_counter() -> void {
|
||||
auto APU::clockFrameCounter() -> void {
|
||||
frame.counter++;
|
||||
|
||||
if(frame.counter & 1) {
|
||||
pulse[0].clock_length();
|
||||
pulse[0].clockLength();
|
||||
pulse[0].sweep.clock(0);
|
||||
pulse[1].clock_length();
|
||||
pulse[1].clockLength();
|
||||
pulse[1].sweep.clock(1);
|
||||
triangle.clock_length();
|
||||
noise.clock_length();
|
||||
triangle.clockLength();
|
||||
noise.clockLength();
|
||||
}
|
||||
|
||||
pulse[0].envelope.clock();
|
||||
pulse[1].envelope.clock();
|
||||
triangle.clock_linear_length();
|
||||
triangle.clockLinearLength();
|
||||
noise.envelope.clock();
|
||||
|
||||
if(frame.counter == 0) {
|
||||
if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod;
|
||||
if(frame.mode == 0) {
|
||||
frame.irq_pending = true;
|
||||
set_irq_line();
|
||||
frame.irqPending = true;
|
||||
setIRQ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::clock_frame_counter_divider() -> void {
|
||||
auto APU::clockFrameCounterDivider() -> void {
|
||||
frame.divider -= 2;
|
||||
if(frame.divider <= 0) {
|
||||
clock_frame_counter();
|
||||
clockFrameCounter();
|
||||
frame.divider += FrameCounter::NtscPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8 APU::length_counter_table[32] = {
|
||||
const uint8 APU::lengthCounterTable[32] = {
|
||||
0x0a, 0xfe, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, 0xa0, 0x08, 0x3c, 0x0a, 0x0e, 0x0c, 0x1a, 0x0e,
|
||||
0x0c, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xc0, 0x18, 0x48, 0x1a, 0x10, 0x1c, 0x20, 0x1e,
|
||||
};
|
||||
|
||||
const uint16 APU::ntsc_noise_period_table[16] = {
|
||||
const uint16 APU::noisePeriodTableNTSC[16] = {
|
||||
4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068,
|
||||
};
|
||||
|
||||
const uint16 APU::pal_noise_period_table[16] = {
|
||||
const uint16 APU::noisePeriodTablePAL[16] = {
|
||||
4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778,
|
||||
};
|
||||
|
||||
const uint16 APU::ntsc_dmc_period_table[16] = {
|
||||
const uint16 APU::dmcPeriodTableNTSC[16] = {
|
||||
428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54,
|
||||
};
|
||||
|
||||
const uint16 APU::pal_dmc_period_table[16] = {
|
||||
const uint16 APU::dmcPeriodTablePAL[16] = {
|
||||
398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ struct APU : Thread {
|
|||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto tick() -> void;
|
||||
auto set_irq_line() -> void;
|
||||
auto set_sample(int16 sample) -> void;
|
||||
auto setIRQ() -> void;
|
||||
auto setSample(int16 sample) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
@ -18,55 +18,183 @@ struct APU : Thread {
|
|||
auto serialize(serializer&) -> void;
|
||||
|
||||
struct Filter {
|
||||
auto run_hipass_strong(int sample) -> int;
|
||||
auto run_hipass_weak(int sample) -> int;
|
||||
auto run_lopass(int sample) -> int;
|
||||
auto runHipassStrong(int sample) -> int;
|
||||
auto runHipassWeak(int sample) -> int;
|
||||
auto runLopass(int sample) -> int;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
enum : int { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 };
|
||||
|
||||
int64 hipass_strong;
|
||||
int64 hipass_weak;
|
||||
int64 hipassStrong;
|
||||
int64 hipassWeak;
|
||||
int64 lopass;
|
||||
};
|
||||
|
||||
#include "envelope.hpp"
|
||||
#include "sweep.hpp"
|
||||
#include "pulse.hpp"
|
||||
#include "triangle.hpp"
|
||||
#include "noise.hpp"
|
||||
#include "dmc.hpp"
|
||||
struct Envelope {
|
||||
auto volume() const -> uint;
|
||||
auto clock() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint4 speed;
|
||||
bool useSpeedAsVolume;
|
||||
bool loopMode;
|
||||
|
||||
bool reloadDecay;
|
||||
uint8 decayCounter;
|
||||
uint4 decayVolume;
|
||||
};
|
||||
|
||||
struct Sweep {
|
||||
auto checkPeriod() -> bool;
|
||||
auto clock(uint channel) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 shift;
|
||||
bool decrement;
|
||||
uint3 period;
|
||||
uint8 counter;
|
||||
bool enable;
|
||||
bool reload;
|
||||
uint11 pulsePeriod;
|
||||
};
|
||||
|
||||
struct Pulse {
|
||||
auto clockLength() -> void;
|
||||
auto checkPeriod() -> bool;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint lengthCounter;
|
||||
|
||||
Envelope envelope;
|
||||
Sweep sweep;
|
||||
|
||||
uint2 duty;
|
||||
uint3 dutyCounter;
|
||||
|
||||
uint11 period;
|
||||
uint periodCounter;
|
||||
} pulse[2];
|
||||
|
||||
struct Triangle {
|
||||
auto clockLength() -> void;
|
||||
auto clockLinearLength() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint lengthCounter;
|
||||
|
||||
uint8 linearLength;
|
||||
bool haltLengthCounter;
|
||||
|
||||
uint11 period;
|
||||
uint periodCounter;
|
||||
|
||||
uint5 stepCounter;
|
||||
uint8 linearLengthCounter;
|
||||
bool reloadLinear;
|
||||
} triangle;
|
||||
|
||||
struct Noise {
|
||||
auto clockLength() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint lengthCounter;
|
||||
|
||||
Envelope envelope;
|
||||
|
||||
uint4 period;
|
||||
uint periodCounter;
|
||||
|
||||
bool shortMode;
|
||||
uint15 lfsr;
|
||||
} noise;
|
||||
|
||||
struct DMC {
|
||||
auto start() -> void;
|
||||
auto stop() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint lengthCounter;
|
||||
bool irqPending;
|
||||
|
||||
uint4 period;
|
||||
uint periodCounter;
|
||||
|
||||
bool irqEnable;
|
||||
bool loopMode;
|
||||
|
||||
uint8 dacLatch;
|
||||
uint8 addrLatch;
|
||||
uint8 lengthLatch;
|
||||
|
||||
uint15 readAddr;
|
||||
uint dmaDelayCounter;
|
||||
|
||||
uint3 bitCounter;
|
||||
bool dmaBufferValid;
|
||||
uint8 dmaBuffer;
|
||||
|
||||
bool sampleValid;
|
||||
uint8 sample;
|
||||
} dmc;
|
||||
|
||||
struct FrameCounter {
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
enum : uint { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz)
|
||||
|
||||
bool irq_pending;
|
||||
bool irqPending;
|
||||
|
||||
uint2 mode;
|
||||
uint2 counter;
|
||||
int divider;
|
||||
};
|
||||
|
||||
auto clock_frame_counter() -> void;
|
||||
auto clock_frame_counter_divider() -> void;
|
||||
auto clockFrameCounter() -> void;
|
||||
auto clockFrameCounterDivider() -> void;
|
||||
|
||||
Filter filter;
|
||||
FrameCounter frame;
|
||||
|
||||
uint8 enabled_channels;
|
||||
int16 cartridge_sample;
|
||||
uint8 enabledChannels;
|
||||
int16 cartridgeSample;
|
||||
|
||||
int16 pulse_dac[32];
|
||||
int16 dmc_triangle_noise_dac[128][16][16];
|
||||
int16 pulseDAC[32];
|
||||
int16 dmcTriangleNoiseDAC[128][16][16];
|
||||
|
||||
static const uint8 length_counter_table[32];
|
||||
static const uint16 ntsc_dmc_period_table[16];
|
||||
static const uint16 pal_dmc_period_table[16];
|
||||
static const uint16 ntsc_noise_period_table[16];
|
||||
static const uint16 pal_noise_period_table[16];
|
||||
static const uint8 lengthCounterTable[32];
|
||||
static const uint16 dmcPeriodTableNTSC[16];
|
||||
static const uint16 dmcPeriodTablePAL[16];
|
||||
static const uint16 noisePeriodTableNTSC[16];
|
||||
static const uint16 noisePeriodTablePAL[16];
|
||||
};
|
||||
|
||||
extern APU apu;
|
||||
|
|
|
@ -1,68 +1,68 @@
|
|||
auto APU::DMC::start() -> void {
|
||||
if(length_counter == 0) {
|
||||
read_addr = 0x4000 + (addr_latch << 6);
|
||||
length_counter = (length_latch << 4) + 1;
|
||||
if(lengthCounter == 0) {
|
||||
readAddr = 0x4000 + (addrLatch << 6);
|
||||
lengthCounter = (lengthLatch << 4) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::DMC::stop() -> void {
|
||||
length_counter = 0;
|
||||
dma_delay_counter = 0;
|
||||
lengthCounter = 0;
|
||||
dmaDelayCounter = 0;
|
||||
cpu.rdyLine(1);
|
||||
cpu.rdyAddr(false);
|
||||
}
|
||||
|
||||
auto APU::DMC::clock() -> uint8 {
|
||||
uint8 result = dac_latch;
|
||||
uint8 result = dacLatch;
|
||||
|
||||
if(dma_delay_counter > 0) {
|
||||
dma_delay_counter--;
|
||||
if(dmaDelayCounter > 0) {
|
||||
dmaDelayCounter--;
|
||||
|
||||
if(dma_delay_counter == 1) {
|
||||
cpu.rdyAddr(true, 0x8000 | read_addr);
|
||||
} else if(dma_delay_counter == 0) {
|
||||
if(dmaDelayCounter == 1) {
|
||||
cpu.rdyAddr(true, 0x8000 | readAddr);
|
||||
} else if(dmaDelayCounter == 0) {
|
||||
cpu.rdyLine(1);
|
||||
cpu.rdyAddr(false);
|
||||
|
||||
dma_buffer = cpu.mdr();
|
||||
have_dma_buffer = true;
|
||||
length_counter--;
|
||||
read_addr++;
|
||||
dmaBuffer = cpu.mdr();
|
||||
dmaBufferValid = true;
|
||||
lengthCounter--;
|
||||
readAddr++;
|
||||
|
||||
if(length_counter == 0) {
|
||||
if(loop_mode) {
|
||||
if(lengthCounter == 0) {
|
||||
if(loopMode) {
|
||||
start();
|
||||
} else if(irq_enable) {
|
||||
irq_pending = true;
|
||||
apu.set_irq_line();
|
||||
} else if(irqEnable) {
|
||||
irqPending = true;
|
||||
apu.setIRQ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(--period_counter == 0) {
|
||||
if(have_sample) {
|
||||
int delta = (((sample >> bit_counter) & 1) << 2) - 2;
|
||||
uint data = dac_latch + delta;
|
||||
if((data & 0x80) == 0) dac_latch = data;
|
||||
if(--periodCounter == 0) {
|
||||
if(sampleValid) {
|
||||
int delta = (((sample >> bitCounter) & 1) << 2) - 2;
|
||||
uint data = dacLatch + delta;
|
||||
if((data & 0x80) == 0) dacLatch = data;
|
||||
}
|
||||
|
||||
if(++bit_counter == 0) {
|
||||
if(have_dma_buffer) {
|
||||
have_sample = true;
|
||||
sample = dma_buffer;
|
||||
have_dma_buffer = false;
|
||||
if(++bitCounter == 0) {
|
||||
if(dmaBufferValid) {
|
||||
sampleValid = true;
|
||||
sample = dmaBuffer;
|
||||
dmaBufferValid = false;
|
||||
} else {
|
||||
have_sample = false;
|
||||
sampleValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
period_counter = ntsc_dmc_period_table[period];
|
||||
periodCounter = dmcPeriodTableNTSC[period];
|
||||
}
|
||||
|
||||
if(length_counter > 0 && have_dma_buffer == false && dma_delay_counter == 0) {
|
||||
if(lengthCounter > 0 && !dmaBufferValid && dmaDelayCounter == 0) {
|
||||
cpu.rdyLine(0);
|
||||
dma_delay_counter = 4;
|
||||
dmaDelayCounter = 4;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -72,46 +72,21 @@ auto APU::DMC::power() -> void {
|
|||
}
|
||||
|
||||
auto APU::DMC::reset() -> void {
|
||||
length_counter = 0;
|
||||
irq_pending = 0;
|
||||
lengthCounter = 0;
|
||||
irqPending = 0;
|
||||
|
||||
period = 0;
|
||||
period_counter = ntsc_dmc_period_table[0];
|
||||
irq_enable = 0;
|
||||
loop_mode = 0;
|
||||
dac_latch = 0;
|
||||
addr_latch = 0;
|
||||
length_latch = 0;
|
||||
read_addr = 0;
|
||||
dma_delay_counter = 0;
|
||||
bit_counter = 0;
|
||||
have_dma_buffer = 0;
|
||||
dma_buffer = 0;
|
||||
have_sample = 0;
|
||||
periodCounter = dmcPeriodTableNTSC[0];
|
||||
irqEnable = 0;
|
||||
loopMode = 0;
|
||||
dacLatch = 0;
|
||||
addrLatch = 0;
|
||||
lengthLatch = 0;
|
||||
readAddr = 0;
|
||||
dmaDelayCounter = 0;
|
||||
bitCounter = 0;
|
||||
dmaBufferValid = 0;
|
||||
dmaBuffer = 0;
|
||||
sampleValid = 0;
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
auto APU::DMC::serialize(serializer& s) -> void {
|
||||
s.integer(length_counter);
|
||||
s.integer(irq_pending);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(period_counter);
|
||||
|
||||
s.integer(irq_enable);
|
||||
s.integer(loop_mode);
|
||||
|
||||
s.integer(dac_latch);
|
||||
s.integer(addr_latch);
|
||||
s.integer(length_latch);
|
||||
|
||||
s.integer(read_addr);
|
||||
s.integer(dma_delay_counter);
|
||||
|
||||
s.integer(bit_counter);
|
||||
s.integer(have_dma_buffer);
|
||||
s.integer(dma_buffer);
|
||||
|
||||
s.integer(have_sample);
|
||||
s.integer(sample);
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
struct DMC {
|
||||
auto start() -> void;
|
||||
auto stop() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint length_counter;
|
||||
bool irq_pending;
|
||||
|
||||
uint4 period;
|
||||
uint period_counter;
|
||||
|
||||
bool irq_enable;
|
||||
bool loop_mode;
|
||||
|
||||
uint8 dac_latch;
|
||||
uint8 addr_latch;
|
||||
uint8 length_latch;
|
||||
|
||||
uint15 read_addr;
|
||||
uint dma_delay_counter;
|
||||
|
||||
uint3 bit_counter;
|
||||
bool have_dma_buffer;
|
||||
uint8 dma_buffer;
|
||||
|
||||
bool have_sample;
|
||||
uint8 sample;
|
||||
} dmc;
|
|
@ -1,18 +1,18 @@
|
|||
auto APU::Envelope::volume() const -> uint {
|
||||
return use_speed_as_volume ? speed : decay_volume;
|
||||
return useSpeedAsVolume ? speed : decayVolume;
|
||||
}
|
||||
|
||||
auto APU::Envelope::clock() -> void {
|
||||
if(reload_decay) {
|
||||
reload_decay = false;
|
||||
decay_volume = 0x0f;
|
||||
decay_counter = speed + 1;
|
||||
if(reloadDecay) {
|
||||
reloadDecay = false;
|
||||
decayVolume = 0x0f;
|
||||
decayCounter = speed + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(--decay_counter == 0) {
|
||||
decay_counter = speed + 1;
|
||||
if(decay_volume || loop_mode) decay_volume--;
|
||||
if(--decayCounter == 0) {
|
||||
decayCounter = speed + 1;
|
||||
if(decayVolume || loopMode) decayVolume--;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,19 +21,9 @@ auto APU::Envelope::power() -> void {
|
|||
|
||||
auto APU::Envelope::reset() -> void {
|
||||
speed = 0;
|
||||
use_speed_as_volume = 0;
|
||||
loop_mode = 0;
|
||||
reload_decay = 0;
|
||||
decay_counter = 0;
|
||||
decay_volume = 0;
|
||||
}
|
||||
|
||||
auto APU::Envelope::serialize(serializer& s) -> void {
|
||||
s.integer(speed);
|
||||
s.integer(use_speed_as_volume);
|
||||
s.integer(loop_mode);
|
||||
|
||||
s.integer(reload_decay);
|
||||
s.integer(decay_counter);
|
||||
s.integer(decay_volume);
|
||||
useSpeedAsVolume = 0;
|
||||
loopMode = 0;
|
||||
reloadDecay = 0;
|
||||
decayCounter = 0;
|
||||
decayVolume = 0;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
struct Envelope {
|
||||
auto volume() const -> uint;
|
||||
auto clock() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint4 speed;
|
||||
bool use_speed_as_volume;
|
||||
bool loop_mode;
|
||||
|
||||
bool reload_decay;
|
||||
uint8 decay_counter;
|
||||
uint4 decay_volume;
|
||||
};
|
|
@ -1,25 +1,25 @@
|
|||
auto APU::Noise::clock_length() -> void {
|
||||
if(envelope.loop_mode == 0) {
|
||||
if(length_counter > 0) length_counter--;
|
||||
auto APU::Noise::clockLength() -> void {
|
||||
if(envelope.loopMode == 0) {
|
||||
if(lengthCounter > 0) lengthCounter--;
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::Noise::clock() -> uint8 {
|
||||
if(length_counter == 0) return 0;
|
||||
if(lengthCounter == 0) return 0;
|
||||
|
||||
uint8 result = (lfsr & 1) ? envelope.volume() : 0;
|
||||
|
||||
if(--period_counter == 0) {
|
||||
if(--periodCounter == 0) {
|
||||
uint feedback;
|
||||
|
||||
if(short_mode) {
|
||||
if(shortMode) {
|
||||
feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 6) & 1);
|
||||
} else {
|
||||
feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 1) & 1);
|
||||
}
|
||||
|
||||
lfsr = (lfsr >> 1) | (feedback << 14);
|
||||
period_counter = apu.ntsc_noise_period_table[period];
|
||||
periodCounter = apu.noisePeriodTableNTSC[period];
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -29,29 +29,17 @@ auto APU::Noise::power() -> void {
|
|||
}
|
||||
|
||||
auto APU::Noise::reset() -> void {
|
||||
length_counter = 0;
|
||||
lengthCounter = 0;
|
||||
|
||||
envelope.speed = 0;
|
||||
envelope.use_speed_as_volume = 0;
|
||||
envelope.loop_mode = 0;
|
||||
envelope.reload_decay = 0;
|
||||
envelope.decay_counter = 0;
|
||||
envelope.decay_volume = 0;
|
||||
envelope.useSpeedAsVolume = 0;
|
||||
envelope.loopMode = 0;
|
||||
envelope.reloadDecay = 0;
|
||||
envelope.decayCounter = 0;
|
||||
envelope.decayVolume = 0;
|
||||
|
||||
period = 0;
|
||||
period_counter = 1;
|
||||
short_mode = 0;
|
||||
periodCounter = 1;
|
||||
shortMode = 0;
|
||||
lfsr = 1;
|
||||
}
|
||||
|
||||
auto APU::Noise::serialize(serializer& s) -> void {
|
||||
s.integer(length_counter);
|
||||
|
||||
envelope.serialize(s);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(period_counter);
|
||||
|
||||
s.integer(short_mode);
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
struct Noise {
|
||||
auto clock_length() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint length_counter;
|
||||
|
||||
Envelope envelope;
|
||||
|
||||
uint4 period;
|
||||
uint period_counter;
|
||||
|
||||
bool short_mode;
|
||||
uint15 lfsr;
|
||||
} noise;
|
|
@ -1,20 +1,20 @@
|
|||
auto APU::Pulse::clock_length() -> void {
|
||||
if(envelope.loop_mode == 0) {
|
||||
if(length_counter) length_counter--;
|
||||
auto APU::Pulse::clockLength() -> void {
|
||||
if(envelope.loopMode == 0) {
|
||||
if(lengthCounter) lengthCounter--;
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::Pulse::clock() -> uint8 {
|
||||
if(sweep.check_period() == false) return 0;
|
||||
if(length_counter == 0) return 0;
|
||||
if(!sweep.checkPeriod()) return 0;
|
||||
if(lengthCounter == 0) return 0;
|
||||
|
||||
static const uint duty_table[] = {1, 2, 4, 6};
|
||||
uint8 result = (duty_counter < duty_table[duty]) ? envelope.volume() : 0;
|
||||
if(sweep.pulse_period < 0x008) result = 0;
|
||||
static const uint dutyTable[] = {1, 2, 4, 6};
|
||||
uint8 result = (dutyCounter < dutyTable[duty]) ? envelope.volume() : 0;
|
||||
if(sweep.pulsePeriod < 0x008) result = 0;
|
||||
|
||||
if(--period_counter == 0) {
|
||||
period_counter = (sweep.pulse_period + 1) * 2;
|
||||
duty_counter++;
|
||||
if(--periodCounter == 0) {
|
||||
periodCounter = (sweep.pulsePeriod + 1) * 2;
|
||||
dutyCounter++;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -29,23 +29,10 @@ auto APU::Pulse::reset() -> void {
|
|||
envelope.reset();
|
||||
sweep.reset();
|
||||
|
||||
length_counter = 0;
|
||||
lengthCounter = 0;
|
||||
|
||||
duty = 0;
|
||||
duty_counter = 0;
|
||||
dutyCounter = 0;
|
||||
period = 0;
|
||||
period_counter = 1;
|
||||
}
|
||||
|
||||
auto APU::Pulse::serialize(serializer& s) -> void {
|
||||
s.integer(length_counter);
|
||||
|
||||
envelope.serialize(s);
|
||||
sweep.serialize(s);
|
||||
|
||||
s.integer(duty);
|
||||
s.integer(duty_counter);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(period_counter);
|
||||
periodCounter = 1;
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
struct Pulse {
|
||||
auto clock_length() -> void;
|
||||
auto check_period() -> bool;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint length_counter;
|
||||
|
||||
Envelope envelope;
|
||||
Sweep sweep;
|
||||
|
||||
uint2 duty;
|
||||
uint3 duty_counter;
|
||||
|
||||
uint11 period;
|
||||
uint period_counter;
|
||||
} pulse[2];
|
|
@ -9,18 +9,102 @@ auto APU::serialize(serializer& s) -> void {
|
|||
dmc.serialize(s);
|
||||
frame.serialize(s);
|
||||
|
||||
s.integer(enabled_channels);
|
||||
s.integer(cartridge_sample);
|
||||
s.integer(enabledChannels);
|
||||
s.integer(cartridgeSample);
|
||||
}
|
||||
|
||||
auto APU::Filter::serialize(serializer& s) -> void {
|
||||
s.integer(hipass_strong);
|
||||
s.integer(hipass_weak);
|
||||
s.integer(hipassStrong);
|
||||
s.integer(hipassWeak);
|
||||
s.integer(lopass);
|
||||
}
|
||||
|
||||
auto APU::Envelope::serialize(serializer& s) -> void {
|
||||
s.integer(speed);
|
||||
s.integer(useSpeedAsVolume);
|
||||
s.integer(loopMode);
|
||||
|
||||
s.integer(reloadDecay);
|
||||
s.integer(decayCounter);
|
||||
s.integer(decayVolume);
|
||||
}
|
||||
|
||||
auto APU::Sweep::serialize(serializer& s) -> void {
|
||||
s.integer(shift);
|
||||
s.integer(decrement);
|
||||
s.integer(period);
|
||||
s.integer(counter);
|
||||
s.integer(enable);
|
||||
s.integer(reload);
|
||||
s.integer(pulsePeriod);
|
||||
}
|
||||
|
||||
auto APU::Pulse::serialize(serializer& s) -> void {
|
||||
s.integer(lengthCounter);
|
||||
|
||||
envelope.serialize(s);
|
||||
sweep.serialize(s);
|
||||
|
||||
s.integer(duty);
|
||||
s.integer(dutyCounter);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(periodCounter);
|
||||
}
|
||||
|
||||
auto APU::Triangle::serialize(serializer& s) -> void {
|
||||
s.integer(lengthCounter);
|
||||
|
||||
s.integer(linearLength);
|
||||
s.integer(haltLengthCounter);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(periodCounter);
|
||||
|
||||
s.integer(stepCounter);
|
||||
s.integer(linearLengthCounter);
|
||||
s.integer(reloadLinear);
|
||||
}
|
||||
|
||||
auto APU::Noise::serialize(serializer& s) -> void {
|
||||
s.integer(lengthCounter);
|
||||
|
||||
envelope.serialize(s);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(periodCounter);
|
||||
|
||||
s.integer(shortMode);
|
||||
s.integer(lfsr);
|
||||
}
|
||||
|
||||
auto APU::DMC::serialize(serializer& s) -> void {
|
||||
s.integer(lengthCounter);
|
||||
s.integer(irqPending);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(periodCounter);
|
||||
|
||||
s.integer(irqEnable);
|
||||
s.integer(loopMode);
|
||||
|
||||
s.integer(dacLatch);
|
||||
s.integer(addrLatch);
|
||||
s.integer(lengthLatch);
|
||||
|
||||
s.integer(readAddr);
|
||||
s.integer(dmaDelayCounter);
|
||||
|
||||
s.integer(bitCounter);
|
||||
s.integer(dmaBufferValid);
|
||||
s.integer(dmaBuffer);
|
||||
|
||||
s.integer(sampleValid);
|
||||
s.integer(sample);
|
||||
}
|
||||
|
||||
auto APU::FrameCounter::serialize(serializer& s) -> void {
|
||||
s.integer(irq_pending);
|
||||
s.integer(irqPending);
|
||||
|
||||
s.integer(mode);
|
||||
s.integer(counter);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
auto APU::Sweep::check_period() -> bool {
|
||||
if(pulse_period > 0x7ff) return false;
|
||||
auto APU::Sweep::checkPeriod() -> bool {
|
||||
if(pulsePeriod > 0x7ff) return false;
|
||||
|
||||
if(decrement == 0) {
|
||||
if((pulse_period + (pulse_period >> shift)) & 0x800) return false;
|
||||
if((pulsePeriod + (pulsePeriod >> shift)) & 0x800) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -11,14 +11,14 @@ auto APU::Sweep::check_period() -> bool {
|
|||
auto APU::Sweep::clock(uint channel) -> void {
|
||||
if(--counter == 0) {
|
||||
counter = period + 1;
|
||||
if(enable && shift && pulse_period > 8) {
|
||||
int delta = pulse_period >> shift;
|
||||
if(enable && shift && pulsePeriod > 8) {
|
||||
int delta = pulsePeriod >> shift;
|
||||
|
||||
if(decrement) {
|
||||
pulse_period -= delta;
|
||||
if(channel == 0) pulse_period--;
|
||||
} else if((pulse_period + delta) < 0x800) {
|
||||
pulse_period += delta;
|
||||
pulsePeriod -= delta;
|
||||
if(channel == 0) pulsePeriod--;
|
||||
} else if((pulsePeriod + delta) < 0x800) {
|
||||
pulsePeriod += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,18 +36,8 @@ auto APU::Sweep::power() -> void {
|
|||
counter = 1;
|
||||
enable = 0;
|
||||
reload = 0;
|
||||
pulse_period = 0;
|
||||
pulsePeriod = 0;
|
||||
}
|
||||
|
||||
auto APU::Sweep::reset() -> void {
|
||||
}
|
||||
|
||||
auto APU::Sweep::serialize(serializer& s) -> void {
|
||||
s.integer(shift);
|
||||
s.integer(decrement);
|
||||
s.integer(period);
|
||||
s.integer(counter);
|
||||
s.integer(enable);
|
||||
s.integer(reload);
|
||||
s.integer(pulse_period);
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
struct Sweep {
|
||||
auto check_period() -> bool;
|
||||
auto clock(uint channel) -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint8 shift;
|
||||
bool decrement;
|
||||
uint3 period;
|
||||
uint8 counter;
|
||||
bool enable;
|
||||
bool reload;
|
||||
uint11 pulse_period;
|
||||
};
|
|
@ -1,27 +1,27 @@
|
|||
auto APU::Triangle::clock_length() -> void {
|
||||
if(halt_length_counter == 0) {
|
||||
if(length_counter > 0) length_counter--;
|
||||
auto APU::Triangle::clockLength() -> void {
|
||||
if(haltLengthCounter == 0) {
|
||||
if(lengthCounter > 0) lengthCounter--;
|
||||
}
|
||||
}
|
||||
|
||||
auto APU::Triangle::clock_linear_length() -> void {
|
||||
if(reload_linear) {
|
||||
linear_length_counter = linear_length;
|
||||
} else if(linear_length_counter) {
|
||||
linear_length_counter--;
|
||||
auto APU::Triangle::clockLinearLength() -> void {
|
||||
if(reloadLinear) {
|
||||
linearLengthCounter = linearLength;
|
||||
} else if(linearLengthCounter) {
|
||||
linearLengthCounter--;
|
||||
}
|
||||
|
||||
if(halt_length_counter == 0) reload_linear = false;
|
||||
if(haltLengthCounter == 0) reloadLinear = false;
|
||||
}
|
||||
|
||||
auto APU::Triangle::clock() -> uint8 {
|
||||
uint8 result = step_counter & 0x0f;
|
||||
if((step_counter & 0x10) == 0) result ^= 0x0f;
|
||||
if(length_counter == 0 || linear_length_counter == 0) return result;
|
||||
uint8 result = stepCounter & 0x0f;
|
||||
if((stepCounter & 0x10) == 0) result ^= 0x0f;
|
||||
if(lengthCounter == 0 || linearLengthCounter == 0) return result;
|
||||
|
||||
if(--period_counter == 0) {
|
||||
step_counter++;
|
||||
period_counter = period + 1;
|
||||
if(--periodCounter == 0) {
|
||||
stepCounter++;
|
||||
periodCounter = period + 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -32,27 +32,13 @@ auto APU::Triangle::power() -> void {
|
|||
}
|
||||
|
||||
auto APU::Triangle::reset() -> void {
|
||||
length_counter = 0;
|
||||
lengthCounter = 0;
|
||||
|
||||
linear_length = 0;
|
||||
halt_length_counter = 0;
|
||||
linearLength = 0;
|
||||
haltLengthCounter = 0;
|
||||
period = 0;
|
||||
period_counter = 1;
|
||||
step_counter = 0;
|
||||
linear_length_counter = 0;
|
||||
reload_linear = 0;
|
||||
}
|
||||
|
||||
auto APU::Triangle::serialize(serializer& s) -> void {
|
||||
s.integer(length_counter);
|
||||
|
||||
s.integer(linear_length);
|
||||
s.integer(halt_length_counter);
|
||||
|
||||
s.integer(period);
|
||||
s.integer(period_counter);
|
||||
|
||||
s.integer(step_counter);
|
||||
s.integer(linear_length_counter);
|
||||
s.integer(reload_linear);
|
||||
periodCounter = 1;
|
||||
stepCounter = 0;
|
||||
linearLengthCounter = 0;
|
||||
reloadLinear = 0;
|
||||
}
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
struct Triangle {
|
||||
auto clock_length() -> void;
|
||||
auto clock_linear_length() -> void;
|
||||
auto clock() -> uint8;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
uint length_counter;
|
||||
|
||||
uint8 linear_length;
|
||||
bool halt_length_counter;
|
||||
|
||||
uint11 period;
|
||||
uint period_counter;
|
||||
|
||||
uint5 step_counter;
|
||||
uint8 linear_length_counter;
|
||||
bool reload_linear;
|
||||
} triangle;
|
|
@ -5,17 +5,17 @@ struct BandaiFCG : Board {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_counter_enable) {
|
||||
if(--irq_counter == 0xffff) {
|
||||
if(irqCounterEnable) {
|
||||
if(--irqCounter == 0xffff) {
|
||||
cpu.irqLine(1);
|
||||
irq_counter_enable = false;
|
||||
irqCounterEnable = false;
|
||||
}
|
||||
}
|
||||
|
||||
tick();
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
|
@ -24,38 +24,38 @@ struct BandaiFCG : Board {
|
|||
}
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) {
|
||||
bool region = addr & 0x4000;
|
||||
uint bank = (region == 0 ? prg_bank : (uint8)0x0f);
|
||||
uint bank = (region == 0 ? prgBank : (uint8)0x0f);
|
||||
return prgrom.read((bank << 14) | (addr & 0x3fff));
|
||||
}
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr >= 0x6000) {
|
||||
switch(addr & 15) {
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x04: case 0x05: case 0x06: case 0x07:
|
||||
chr_bank[addr & 7] = data;
|
||||
chrBank[addr & 7] = data;
|
||||
break;
|
||||
case 0x08:
|
||||
prg_bank = data & 0x0f;
|
||||
prgBank = data & 0x0f;
|
||||
break;
|
||||
case 0x09:
|
||||
mirror = data & 0x03;
|
||||
break;
|
||||
case 0x0a:
|
||||
cpu.irqLine(0);
|
||||
irq_counter_enable = data & 0x01;
|
||||
irq_counter = irq_latch;
|
||||
irqCounterEnable = data & 0x01;
|
||||
irqCounter = irqLatch;
|
||||
break;
|
||||
case 0x0b:
|
||||
irq_latch = (irq_latch & 0xff00) | (data << 0);
|
||||
irqLatch = (irqLatch & 0xff00) | (data << 0);
|
||||
break;
|
||||
case 0x0c:
|
||||
irq_latch = (irq_latch & 0x00ff) | (data << 8);
|
||||
irqLatch = (irqLatch & 0x00ff) | (data << 8);
|
||||
break;
|
||||
case 0x0d:
|
||||
//todo: serial EEPROM support
|
||||
|
@ -64,16 +64,16 @@ struct BandaiFCG : Board {
|
|||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr));
|
||||
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
|
||||
return Board::chr_read(addr);
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
|
||||
addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff);
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data);
|
||||
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff);
|
||||
return Board::chr_write(addr, data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
|
||||
addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff);
|
||||
return Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
@ -81,29 +81,29 @@ struct BandaiFCG : Board {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
for(auto &n : chr_bank) n = 0;
|
||||
prg_bank = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
prgBank = 0;
|
||||
mirror = 0;
|
||||
irq_counter_enable = 0;
|
||||
irq_counter = 0;
|
||||
irq_latch = 0;
|
||||
irqCounterEnable = 0;
|
||||
irqCounter = 0;
|
||||
irqLatch = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.array(chr_bank);
|
||||
s.integer(prg_bank);
|
||||
s.array(chrBank);
|
||||
s.integer(prgBank);
|
||||
s.integer(mirror);
|
||||
s.integer(irq_counter_enable);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irqCounterEnable);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqLatch);
|
||||
}
|
||||
|
||||
uint8 chr_bank[8];
|
||||
uint8 prg_bank;
|
||||
uint8 chrBank[8];
|
||||
uint8 prgBank;
|
||||
uint2 mirror;
|
||||
bool irq_counter_enable;
|
||||
uint16 irq_counter;
|
||||
uint16 irq_latch;
|
||||
bool irqCounterEnable;
|
||||
uint16 irqCounter;
|
||||
uint16 irqLatch;
|
||||
};
|
||||
|
|
|
@ -118,13 +118,13 @@ auto Board::tick() -> void {
|
|||
if(cartridge.clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
auto Board::chr_read(uint addr) -> uint8 {
|
||||
auto Board::readCHR(uint addr) -> uint8 {
|
||||
if(chrram.size) return chrram.data[mirror(addr, chrram.size)];
|
||||
if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)];
|
||||
return 0u;
|
||||
}
|
||||
|
||||
auto Board::chr_write(uint addr, uint8 data) -> void {
|
||||
auto Board::writeCHR(uint addr, uint8 data) -> void {
|
||||
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@ struct Board {
|
|||
virtual auto main() -> void;
|
||||
virtual auto tick() -> void;
|
||||
|
||||
virtual auto prg_read(uint addr) -> uint8 = 0;
|
||||
virtual auto prg_write(uint addr, uint8 data) -> void = 0;
|
||||
virtual auto readPRG(uint addr) -> uint8 = 0;
|
||||
virtual auto writePRG(uint addr, uint8 data) -> void = 0;
|
||||
|
||||
virtual auto chr_read(uint addr) -> uint8;
|
||||
virtual auto chr_write(uint addr, uint8 data) -> void;
|
||||
virtual auto readCHR(uint addr) -> uint8;
|
||||
virtual auto writeCHR(uint addr, uint8 data) -> void;
|
||||
|
||||
virtual inline auto scanline(uint y) -> void {}
|
||||
|
||||
|
|
|
@ -2,23 +2,23 @@ struct KonamiVRC1 : Board {
|
|||
KonamiVRC1(Markup::Node& document) : Board(document), vrc1(*this) {
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read(vrc1.prg_addr(addr));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read(vrc1.addrPRG(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) return vrc1.reg_write(addr, data);
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) return vrc1.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc1.ciram_addr(addr));
|
||||
return Board::chr_read(vrc1.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc1.addrCIRAM(addr));
|
||||
return Board::readCHR(vrc1.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc1.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc1.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc1.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(vrc1.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -4,31 +4,31 @@ struct KonamiVRC2 : Board {
|
|||
settings.pinout.a1 = 1 << document["board/chip/pinout/a1"].natural();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return vrc2.ram_read(addr);
|
||||
return prgrom.read(vrc2.prg_addr(addr));
|
||||
if(addr < 0x8000) return vrc2.readRAM(addr);
|
||||
return prgrom.read(vrc2.addrPRG(addr));
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return vrc2.ram_write(addr, data);
|
||||
if(addr < 0x8000) return vrc2.writeRAM(addr, data);
|
||||
|
||||
bool a0 = (addr & settings.pinout.a0);
|
||||
bool a1 = (addr & settings.pinout.a1);
|
||||
addr &= 0xfff0;
|
||||
addr |= (a0 << 0) | (a1 << 1);
|
||||
return vrc2.reg_write(addr, data);
|
||||
return vrc2.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc2.ciram_addr(addr));
|
||||
return Board::chr_read(vrc2.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc2.addrCIRAM(addr));
|
||||
return Board::readCHR(vrc2.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc2.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc2.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc2.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(vrc2.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -7,18 +7,18 @@ struct KonamiVRC3 : Board {
|
|||
vrc3.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff);
|
||||
if(addr & 0x8000) return prgrom.read(vrc3.prg_addr(addr));
|
||||
if(addr & 0x8000) return prgrom.read(vrc3.addrPRG(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data);
|
||||
if(addr & 0x8000) return vrc3.reg_write(addr, data);
|
||||
if(addr & 0x8000) return vrc3.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr & 0x07ff);
|
||||
|
@ -26,7 +26,7 @@ struct KonamiVRC3 : Board {
|
|||
return chrram.read(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr & 0x07ff, data);
|
||||
|
|
|
@ -8,13 +8,13 @@ struct KonamiVRC4 : Board {
|
|||
return vrc4.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return prgram.read(addr);
|
||||
return prgrom.read(vrc4.prg_addr(addr));
|
||||
return prgrom.read(vrc4.addrPRG(addr));
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return prgram.write(addr, data);
|
||||
|
||||
|
@ -22,17 +22,17 @@ struct KonamiVRC4 : Board {
|
|||
bool a1 = (addr & settings.pinout.a1);
|
||||
addr &= 0xfff0;
|
||||
addr |= (a1 << 1) | (a0 << 0);
|
||||
return vrc4.reg_write(addr, data);
|
||||
return vrc4.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc4.ciram_addr(addr));
|
||||
return Board::chr_read(vrc4.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc4.addrCIRAM(addr));
|
||||
return Board::readCHR(vrc4.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc4.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc4.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc4.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(vrc4.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -2,29 +2,29 @@ struct KonamiVRC6 : Board {
|
|||
KonamiVRC6(Markup::Node& document) : Board(document), vrc6(*this) {
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8{
|
||||
if((addr & 0xe000) == 0x6000) return vrc6.ram_read(addr);
|
||||
if(addr & 0x8000) return prgrom.read(vrc6.prg_addr(addr));
|
||||
auto readPRG(uint addr) -> uint8{
|
||||
if((addr & 0xe000) == 0x6000) return vrc6.readRAM(addr);
|
||||
if(addr & 0x8000) return prgrom.read(vrc6.addrPRG(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) return vrc6.ram_write(addr, data);
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) return vrc6.writeRAM(addr, data);
|
||||
if(addr & 0x8000) {
|
||||
addr = (addr & 0xf003);
|
||||
if(prgram.size) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1);
|
||||
return vrc6.reg_write(addr, data);
|
||||
return vrc6.writeIO(addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc6.ciram_addr(addr));
|
||||
return Board::chr_read(vrc6.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc6.addrCIRAM(addr));
|
||||
return Board::readCHR(vrc6.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc6.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc6.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc6.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(vrc6.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
|
|
|
@ -6,26 +6,26 @@ struct KonamiVRC7 : Board {
|
|||
return vrc7.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return prgram.read(addr);
|
||||
return prgrom.read(vrc7.prg_addr(addr));
|
||||
return prgrom.read(vrc7.addrPRG(addr));
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return prgram.write(addr, data);
|
||||
return vrc7.reg_write(addr, data);
|
||||
return vrc7.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc7.ciram_addr(addr));
|
||||
return chrram.read(vrc7.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(vrc7.addrCIRAM(addr));
|
||||
return chrram.read(vrc7.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.ciram_addr(addr), data);
|
||||
return chrram.write(vrc7.chr_addr(addr), data);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.addrCIRAM(addr), data);
|
||||
return chrram.write(vrc7.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -7,43 +7,43 @@ struct NES_AxROM : Board {
|
|||
NES_AxROM(Markup::Node& document) : Board(document) {
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) {
|
||||
prg_bank = data & 0x0f;
|
||||
mirror_select = data & 0x10;
|
||||
prgBank = data & 0x0f;
|
||||
mirrorSelect = data & 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM((mirror_select << 10) | (addr & 0x03ff));
|
||||
return Board::chr_read(addr);
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM((mirrorSelect << 10) | (addr & 0x03ff));
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM((mirror_select << 10) | (addr & 0x03ff), data);
|
||||
return Board::chr_write(addr, data);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM((mirrorSelect << 10) | (addr & 0x03ff), data);
|
||||
return Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0x0f;
|
||||
mirror_select = 0;
|
||||
prgBank = 0x0f;
|
||||
mirrorSelect = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.integer(prg_bank);
|
||||
s.integer(mirror_select);
|
||||
s.integer(prgBank);
|
||||
s.integer(mirrorSelect);
|
||||
}
|
||||
|
||||
uint4 prg_bank;
|
||||
bool mirror_select;
|
||||
uint4 prgBank;
|
||||
bool mirrorSelect;
|
||||
};
|
||||
|
|
|
@ -5,46 +5,46 @@ struct NES_BNROM : Board {
|
|||
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) prg_bank = data & 0x03;
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) prgBank = data & 0x03;
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr);
|
||||
}
|
||||
return Board::chr_read(addr);
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr, data);
|
||||
}
|
||||
return Board::chr_write(addr, data);
|
||||
return Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
prgBank = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
s.integer(prg_bank);
|
||||
s.integer(prgBank);
|
||||
}
|
||||
|
||||
struct Settings {
|
||||
bool mirror; //0 = horizontal, 1 = vertical
|
||||
} settings;
|
||||
|
||||
uint2 prg_bank;
|
||||
uint2 prgBank;
|
||||
};
|
||||
|
|
|
@ -5,48 +5,48 @@ struct NES_CNROM : Board {
|
|||
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read(addr & 0x7fff);
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) chr_bank = data & 0x03;
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) chrBank = data & 0x03;
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr & 0x07ff);
|
||||
}
|
||||
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||
return Board::chr_read(addr);
|
||||
addr = (chrBank * 0x2000) + (addr & 0x1fff);
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr & 0x07ff, data);
|
||||
}
|
||||
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||
Board::chr_write(addr, data);
|
||||
addr = (chrBank * 0x2000) + (addr & 0x1fff);
|
||||
Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
chr_bank = 0;
|
||||
chrBank = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
s.integer(chr_bank);
|
||||
s.integer(chrBank);
|
||||
}
|
||||
|
||||
struct Settings {
|
||||
bool mirror; //0 = horizontal, 1 = vertical
|
||||
} settings;
|
||||
|
||||
uint2 chr_bank;
|
||||
uint2 chrBank;
|
||||
};
|
||||
|
|
|
@ -7,20 +7,20 @@ struct NES_ExROM : Board {
|
|||
mmc5.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
return mmc5.prg_read(addr);
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
return mmc5.readPRG(addr);
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
mmc5.prg_write(addr, data);
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
mmc5.writePRG(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
return mmc5.chr_read(addr);
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
return mmc5.readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
mmc5.chr_write(addr, data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
mmc5.writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto scanline(uint y) -> void {
|
||||
|
|
|
@ -5,61 +5,61 @@ struct NES_FxROM : Board {
|
|||
revision = Revision::FKROM;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return prgram.read(addr);
|
||||
uint bank = addr < 0xc000 ? prg_bank : (uint4)0x0f;
|
||||
uint bank = addr < 0xc000 ? prgBank : (uint4)0x0f;
|
||||
return prgrom.read((bank * 0x4000) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return prgram.write(addr, data);
|
||||
|
||||
switch(addr & 0xf000) {
|
||||
case 0xa000: prg_bank = data & 0x0f; break;
|
||||
case 0xb000: chr_bank[0][0] = data & 0x1f; break;
|
||||
case 0xc000: chr_bank[0][1] = data & 0x1f; break;
|
||||
case 0xd000: chr_bank[1][0] = data & 0x1f; break;
|
||||
case 0xe000: chr_bank[1][1] = data & 0x1f; break;
|
||||
case 0xa000: prgBank = data & 0x0f; break;
|
||||
case 0xb000: chrBank[0][0] = data & 0x1f; break;
|
||||
case 0xc000: chrBank[0][1] = data & 0x1f; break;
|
||||
case 0xd000: chrBank[1][0] = data & 0x1f; break;
|
||||
case 0xe000: chrBank[1][1] = data & 0x1f; break;
|
||||
case 0xf000: mirror = data & 0x01; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
|
||||
bool region = addr & 0x1000;
|
||||
uint bank = chr_bank[region][latch[region]];
|
||||
uint bank = chrBank[region][latch[region]];
|
||||
if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0;
|
||||
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1;
|
||||
return Board::chr_read((bank * 0x1000) | (addr & 0x0fff));
|
||||
return Board::readCHR((bank * 0x1000) | (addr & 0x0fff));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
|
||||
bool region = addr & 0x1000;
|
||||
uint bank = chr_bank[region][latch[region]];
|
||||
uint bank = chrBank[region][latch[region]];
|
||||
if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0;
|
||||
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1;
|
||||
return Board::chr_write((bank * 0x1000) | (addr & 0x0fff), data);
|
||||
return Board::writeCHR((bank * 0x1000) | (addr & 0x0fff), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
chr_bank[0][0] = 0;
|
||||
chr_bank[0][1] = 0;
|
||||
chr_bank[1][0] = 0;
|
||||
chr_bank[1][1] = 0;
|
||||
prgBank = 0;
|
||||
chrBank[0][0] = 0;
|
||||
chrBank[0][1] = 0;
|
||||
chrBank[1][0] = 0;
|
||||
chrBank[1][1] = 0;
|
||||
mirror = 0;
|
||||
latch[0] = 0;
|
||||
latch[1] = 0;
|
||||
|
@ -68,11 +68,11 @@ struct NES_FxROM : Board {
|
|||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.integer(prg_bank);
|
||||
s.integer(chr_bank[0][0]);
|
||||
s.integer(chr_bank[0][1]);
|
||||
s.integer(chr_bank[1][0]);
|
||||
s.integer(chr_bank[1][1]);
|
||||
s.integer(prgBank);
|
||||
s.integer(chrBank[0][0]);
|
||||
s.integer(chrBank[0][1]);
|
||||
s.integer(chrBank[1][0]);
|
||||
s.integer(chrBank[1][1]);
|
||||
s.integer(mirror);
|
||||
s.array(latch);
|
||||
}
|
||||
|
@ -82,8 +82,8 @@ struct NES_FxROM : Board {
|
|||
FKROM,
|
||||
} revision;
|
||||
|
||||
uint4 prg_bank;
|
||||
uint5 chr_bank[2][2];
|
||||
uint4 prgBank;
|
||||
uint5 chrBank[2][2];
|
||||
bool mirror;
|
||||
bool latch[2];
|
||||
};
|
||||
|
|
|
@ -6,54 +6,54 @@ struct NES_GxROM : Board {
|
|||
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) {
|
||||
prg_bank = (data & 0x30) >> 4;
|
||||
chr_bank = (data & 0x03) >> 0;
|
||||
prgBank = (data & 0x30) >> 4;
|
||||
chrBank = (data & 0x03) >> 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr & 0x07ff);
|
||||
}
|
||||
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||
return Board::chr_read(addr);
|
||||
addr = (chrBank * 0x2000) + (addr & 0x1fff);
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr & 0x07ff, data);
|
||||
}
|
||||
addr = (chr_bank * 0x2000) + (addr & 0x1fff);
|
||||
Board::chr_write(addr, data);
|
||||
addr = (chrBank * 0x2000) + (addr & 0x1fff);
|
||||
Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
chr_bank = 0;
|
||||
prgBank = 0;
|
||||
chrBank = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
s.integer(prg_bank);
|
||||
s.integer(chr_bank);
|
||||
s.integer(prgBank);
|
||||
s.integer(chrBank);
|
||||
}
|
||||
|
||||
struct Settings {
|
||||
bool mirror; //0 = horizontal, 1 = vertical
|
||||
} settings;
|
||||
|
||||
uint2 prg_bank;
|
||||
uint2 chr_bank;
|
||||
uint2 prgBank;
|
||||
uint2 chrBank;
|
||||
};
|
||||
|
|
|
@ -6,27 +6,27 @@ struct NES_HKROM : Board {
|
|||
mmc6.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.ram_read(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc6.prg_addr(addr));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.readRAM(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc6.addrPRG(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.ram_write(addr, data);
|
||||
if(addr & 0x8000) return mmc6.reg_write(addr, data);
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.writeRAM(addr, data);
|
||||
if(addr & 0x8000) return mmc6.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
mmc6.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc6.ciram_addr(addr));
|
||||
return Board::chr_read(mmc6.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
mmc6.irqTest(addr);
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc6.addrCIRAM(addr));
|
||||
return Board::readCHR(mmc6.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
mmc6.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc6.ciram_addr(addr), data);
|
||||
return Board::chr_write(mmc6.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
mmc6.irqTest(addr);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc6.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(mmc6.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -6,15 +6,15 @@ struct NES_NROM : Board {
|
|||
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr & 0x8000) return prgrom.read(addr);
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr & 0x07ff);
|
||||
|
@ -23,7 +23,7 @@ struct NES_NROM : Board {
|
|||
return chrrom.read(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr & 0x07ff, data);
|
||||
|
|
|
@ -5,12 +5,12 @@ struct NES_PxROM : Board {
|
|||
revision = Revision::PNROM;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return prgram.read(addr);
|
||||
uint bank = 0;
|
||||
switch((addr / 0x2000) & 3) {
|
||||
case 0: bank = prg_bank; break;
|
||||
case 0: bank = prgBank; break;
|
||||
case 1: bank = 0x0d; break;
|
||||
case 2: bank = 0x0e; break;
|
||||
case 3: bank = 0x0f; break;
|
||||
|
@ -18,54 +18,54 @@ struct NES_PxROM : Board {
|
|||
return prgrom.read((bank * 0x2000) | (addr & 0x1fff));
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return prgram.write(addr, data);
|
||||
|
||||
switch(addr & 0xf000) {
|
||||
case 0xa000: prg_bank = data & 0x0f; break;
|
||||
case 0xb000: chr_bank[0][0] = data & 0x1f; break;
|
||||
case 0xc000: chr_bank[0][1] = data & 0x1f; break;
|
||||
case 0xd000: chr_bank[1][0] = data & 0x1f; break;
|
||||
case 0xe000: chr_bank[1][1] = data & 0x1f; break;
|
||||
case 0xa000: prgBank = data & 0x0f; break;
|
||||
case 0xb000: chrBank[0][0] = data & 0x1f; break;
|
||||
case 0xc000: chrBank[0][1] = data & 0x1f; break;
|
||||
case 0xd000: chrBank[1][0] = data & 0x1f; break;
|
||||
case 0xe000: chrBank[1][1] = data & 0x1f; break;
|
||||
case 0xf000: mirror = data & 0x01; break;
|
||||
}
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
|
||||
bool region = addr & 0x1000;
|
||||
uint bank = chr_bank[region][latch[region]];
|
||||
uint bank = chrBank[region][latch[region]];
|
||||
if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0;
|
||||
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1;
|
||||
return Board::chr_read((bank * 0x1000) | (addr & 0x0fff));
|
||||
return Board::readCHR((bank * 0x1000) | (addr & 0x0fff));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
|
||||
bool region = addr & 0x1000;
|
||||
uint bank = chr_bank[region][latch[region]];
|
||||
uint bank = chrBank[region][latch[region]];
|
||||
if((addr & 0x0ff8) == 0x0fd8) latch[region] = 0;
|
||||
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1;
|
||||
return Board::chr_write((bank * 0x1000) | (addr & 0x0fff), data);
|
||||
return Board::writeCHR((bank * 0x1000) | (addr & 0x0fff), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
chr_bank[0][0] = 0;
|
||||
chr_bank[0][1] = 0;
|
||||
chr_bank[1][0] = 0;
|
||||
chr_bank[1][1] = 0;
|
||||
prgBank = 0;
|
||||
chrBank[0][0] = 0;
|
||||
chrBank[0][1] = 0;
|
||||
chrBank[1][0] = 0;
|
||||
chrBank[1][1] = 0;
|
||||
mirror = 0;
|
||||
latch[0] = 0;
|
||||
latch[1] = 0;
|
||||
|
@ -74,11 +74,11 @@ struct NES_PxROM : Board {
|
|||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.integer(prg_bank);
|
||||
s.integer(chr_bank[0][0]);
|
||||
s.integer(chr_bank[0][1]);
|
||||
s.integer(chr_bank[1][0]);
|
||||
s.integer(chr_bank[1][1]);
|
||||
s.integer(prgBank);
|
||||
s.integer(chrBank[0][0]);
|
||||
s.integer(chrBank[0][1]);
|
||||
s.integer(chrBank[1][0]);
|
||||
s.integer(chrBank[1][1]);
|
||||
s.integer(mirror);
|
||||
s.array(latch);
|
||||
}
|
||||
|
@ -88,8 +88,8 @@ struct NES_PxROM : Board {
|
|||
PNROM,
|
||||
} revision;
|
||||
|
||||
uint4 prg_bank;
|
||||
uint5 chr_bank[2][2];
|
||||
uint4 prgBank;
|
||||
uint5 chrBank[2][2];
|
||||
bool mirror;
|
||||
bool latch[2];
|
||||
};
|
||||
|
|
|
@ -7,27 +7,27 @@ struct NES_SxROM : Board {
|
|||
return mmc1.main();
|
||||
}
|
||||
|
||||
auto ram_addr(uint addr) -> uint {
|
||||
auto addrRAM(uint addr) -> uint {
|
||||
uint bank = 0;
|
||||
if(revision == Revision::SOROM) bank = (mmc1.chr_bank[0] & 0x08) >> 3;
|
||||
if(revision == Revision::SUROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2;
|
||||
if(revision == Revision::SXROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2;
|
||||
if(revision == Revision::SOROM) bank = (mmc1.chrBank[0] & 0x08) >> 3;
|
||||
if(revision == Revision::SUROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2;
|
||||
if(revision == Revision::SXROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2;
|
||||
return (bank << 13) | (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xe000) == 0x6000) {
|
||||
if(revision == Revision::SNROM) {
|
||||
if(mmc1.chr_bank[0] & 0x10) return cpu.mdr();
|
||||
if(mmc1.chrBank[0] & 0x10) return cpu.mdr();
|
||||
}
|
||||
if(mmc1.ram_disable) return 0x00;
|
||||
return prgram.read(ram_addr(addr));
|
||||
if(mmc1.ramDisable) return 0x00;
|
||||
return prgram.read(addrRAM(addr));
|
||||
}
|
||||
|
||||
if(addr & 0x8000) {
|
||||
addr = mmc1.prg_addr(addr);
|
||||
addr = mmc1.addrPRG(addr);
|
||||
if(revision == Revision::SXROM) {
|
||||
addr |= ((mmc1.chr_bank[0] & 0x10) >> 4) << 18;
|
||||
addr |= ((mmc1.chrBank[0] & 0x10) >> 4) << 18;
|
||||
}
|
||||
return prgrom.read(addr);
|
||||
}
|
||||
|
@ -35,26 +35,26 @@ struct NES_SxROM : Board {
|
|||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) {
|
||||
if(revision == Revision::SNROM) {
|
||||
if(mmc1.chr_bank[0] & 0x10) return;
|
||||
if(mmc1.chrBank[0] & 0x10) return;
|
||||
}
|
||||
if(mmc1.ram_disable) return;
|
||||
return prgram.write(ram_addr(addr), data);
|
||||
if(mmc1.ramDisable) return;
|
||||
return prgram.write(addrRAM(addr), data);
|
||||
}
|
||||
|
||||
if(addr & 0x8000) return mmc1.mmio_write(addr, data);
|
||||
if(addr & 0x8000) return mmc1.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc1.ciram_addr(addr));
|
||||
return Board::chr_read(mmc1.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc1.addrCIRAM(addr));
|
||||
return Board::readCHR(mmc1.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc1.ciram_addr(addr), data);
|
||||
return Board::chr_write(mmc1.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc1.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(mmc1.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -7,27 +7,27 @@ struct NES_TxROM : Board {
|
|||
mmc3.main();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.ram_read(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc3.prg_addr(addr));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.readRAM(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc3.addrPRG(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data);
|
||||
if(addr & 0x8000) return mmc3.reg_write(addr, data);
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.writeRAM(addr, data);
|
||||
if(addr & 0x8000) return mmc3.writeIO(addr, data);
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
mmc3.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc3.ciram_addr(addr));
|
||||
return Board::chr_read(mmc3.chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
mmc3.irqTest(addr);
|
||||
if(addr & 0x2000) return ppu.readCIRAM(mmc3.addrCIRAM(addr));
|
||||
return Board::readCHR(mmc3.addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
mmc3.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc3.ciram_addr(addr), data);
|
||||
return Board::chr_write(mmc3.chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
mmc3.irqTest(addr);
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(mmc3.addrCIRAM(addr), data);
|
||||
return Board::writeCHR(mmc3.addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
|
|
@ -6,48 +6,48 @@ struct NES_UxROM : Board {
|
|||
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x8000) return prgrom.read((prg_bank << 14) | (addr & 0x3fff));
|
||||
if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff));
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xc000) == 0x8000) return prgrom.read((prgBank << 14) | (addr & 0x3fff));
|
||||
if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) prg_bank = data & 0x0f;
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x8000) prgBank = data & 0x0f;
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.readCIRAM(addr);
|
||||
}
|
||||
return Board::chr_read(addr);
|
||||
return Board::readCHR(addr);
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.writeCIRAM(addr, data);
|
||||
}
|
||||
return Board::chr_write(addr, data);
|
||||
return Board::writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
prgBank = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.integer(prg_bank);
|
||||
s.integer(prgBank);
|
||||
}
|
||||
|
||||
struct Settings {
|
||||
bool mirror; //0 = horizontal, 1 = vertical
|
||||
} settings;
|
||||
|
||||
uint4 prg_bank;
|
||||
uint4 prgBank;
|
||||
};
|
||||
|
|
|
@ -44,9 +44,9 @@ struct Sunsoft5B : Board {
|
|||
} pulse[3];
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_counter_enable) {
|
||||
if(--irq_counter == 0xffff) {
|
||||
cpu.irqLine(irq_enable);
|
||||
if(irqCounterEnable) {
|
||||
if(--irqCounter == 0xffff) {
|
||||
cpu.irqLine(irqEnable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,26 +54,26 @@ struct Sunsoft5B : Board {
|
|||
pulse[1].clock();
|
||||
pulse[2].clock();
|
||||
int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output];
|
||||
apu.set_sample(-output);
|
||||
apu.setSample(-output);
|
||||
|
||||
tick();
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
|
||||
uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000
|
||||
if((addr & 0xe000) == 0x6000) bank = prg_bank[0];
|
||||
if((addr & 0xe000) == 0x8000) bank = prg_bank[1];
|
||||
if((addr & 0xe000) == 0xa000) bank = prg_bank[2];
|
||||
if((addr & 0xe000) == 0xc000) bank = prg_bank[3];
|
||||
if((addr & 0xe000) == 0x6000) bank = prgBank[0];
|
||||
if((addr & 0xe000) == 0x8000) bank = prgBank[1];
|
||||
if((addr & 0xe000) == 0xa000) bank = prgBank[2];
|
||||
if((addr & 0xe000) == 0xc000) bank = prgBank[3];
|
||||
|
||||
bool ram_enable = bank & 0x80;
|
||||
bool ram_select = bank & 0x40;
|
||||
bool ramEnable = bank & 0x80;
|
||||
bool ramSelect = bank & 0x40;
|
||||
bank &= 0x3f;
|
||||
|
||||
if(ram_select) {
|
||||
if(ram_enable == false) return cpu.mdr();
|
||||
if(ramSelect) {
|
||||
if(!ramEnable) return cpu.mdr();
|
||||
return prgram.data[addr & 0x1fff];
|
||||
}
|
||||
|
||||
|
@ -81,46 +81,46 @@ struct Sunsoft5B : Board {
|
|||
return prgrom.read(addr);
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xe000) == 0x6000) {
|
||||
prgram.data[addr & 0x1fff] = data;
|
||||
}
|
||||
|
||||
if(addr == 0x8000) {
|
||||
mmu_port = data & 0x0f;
|
||||
mmuPort = data & 0x0f;
|
||||
}
|
||||
|
||||
if(addr == 0xa000) {
|
||||
switch(mmu_port) {
|
||||
case 0: chr_bank[0] = data; break;
|
||||
case 1: chr_bank[1] = data; break;
|
||||
case 2: chr_bank[2] = data; break;
|
||||
case 3: chr_bank[3] = data; break;
|
||||
case 4: chr_bank[4] = data; break;
|
||||
case 5: chr_bank[5] = data; break;
|
||||
case 6: chr_bank[6] = data; break;
|
||||
case 7: chr_bank[7] = data; break;
|
||||
case 8: prg_bank[0] = data; break;
|
||||
case 9: prg_bank[1] = data; break;
|
||||
case 10: prg_bank[2] = data; break;
|
||||
case 11: prg_bank[3] = data; break;
|
||||
switch(mmuPort) {
|
||||
case 0: chrBank[0] = data; break;
|
||||
case 1: chrBank[1] = data; break;
|
||||
case 2: chrBank[2] = data; break;
|
||||
case 3: chrBank[3] = data; break;
|
||||
case 4: chrBank[4] = data; break;
|
||||
case 5: chrBank[5] = data; break;
|
||||
case 6: chrBank[6] = data; break;
|
||||
case 7: chrBank[7] = data; break;
|
||||
case 8: prgBank[0] = data; break;
|
||||
case 9: prgBank[1] = data; break;
|
||||
case 10: prgBank[2] = data; break;
|
||||
case 11: prgBank[3] = data; break;
|
||||
case 12: mirror = data & 3; break;
|
||||
case 13:
|
||||
irq_enable = data & 0x80;
|
||||
irq_counter_enable = data & 0x01;
|
||||
if(irq_enable == 0) cpu.irqLine(0);
|
||||
irqEnable = data & 0x80;
|
||||
irqCounterEnable = data & 0x01;
|
||||
if(irqEnable == 0) cpu.irqLine(0);
|
||||
break;
|
||||
case 14: irq_counter = (irq_counter & 0xff00) | (data << 0); break;
|
||||
case 15: irq_counter = (irq_counter & 0x00ff) | (data << 8); break;
|
||||
case 14: irqCounter = (irqCounter & 0xff00) | (data << 0); break;
|
||||
case 15: irqCounter = (irqCounter & 0x00ff) | (data << 8); break;
|
||||
}
|
||||
}
|
||||
|
||||
if(addr == 0xc000) {
|
||||
apu_port = data & 0x0f;
|
||||
apuPort = data & 0x0f;
|
||||
}
|
||||
|
||||
if(addr == 0xe000) {
|
||||
switch(apu_port) {
|
||||
switch(apuPort) {
|
||||
case 0: pulse[0].frequency = (pulse[0].frequency & 0xff00) | (data << 0); break;
|
||||
case 1: pulse[0].frequency = (pulse[0].frequency & 0x00ff) | (data << 8); break;
|
||||
case 2: pulse[1].frequency = (pulse[1].frequency & 0xff00) | (data << 0); break;
|
||||
|
@ -139,12 +139,12 @@ struct Sunsoft5B : Board {
|
|||
}
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) -> uint {
|
||||
auto addrCHR(uint addr) -> uint {
|
||||
uint8 bank = (addr >> 10) & 7;
|
||||
return (chr_bank[bank] << 10) | (addr & 0x03ff);
|
||||
return (chrBank[bank] << 10) | (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) -> uint {
|
||||
auto addrCIRAM(uint addr) -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal
|
||||
|
@ -153,14 +153,14 @@ struct Sunsoft5B : Board {
|
|||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr));
|
||||
return Board::chr_read(chr_addr(addr));
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
|
||||
return Board::readCHR(addrCHR(addr));
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data);
|
||||
return Board::chr_write(chr_addr(addr), data);
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
|
||||
return Board::writeCHR(addrCHR(addr), data);
|
||||
}
|
||||
|
||||
auto power() -> void {
|
||||
|
@ -171,15 +171,15 @@ struct Sunsoft5B : Board {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
mmu_port = 0;
|
||||
apu_port = 0;
|
||||
mmuPort = 0;
|
||||
apuPort = 0;
|
||||
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
for(auto& n : chr_bank) n = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
mirror = 0;
|
||||
irq_enable = 0;
|
||||
irq_counter_enable = 0;
|
||||
irq_counter = 0;
|
||||
irqEnable = 0;
|
||||
irqCounterEnable = 0;
|
||||
irqCounter = 0;
|
||||
|
||||
pulse[0].reset();
|
||||
pulse[1].reset();
|
||||
|
@ -189,30 +189,30 @@ struct Sunsoft5B : Board {
|
|||
auto serialize(serializer& s) -> void {
|
||||
Board::serialize(s);
|
||||
|
||||
s.integer(mmu_port);
|
||||
s.integer(apu_port);
|
||||
s.integer(mmuPort);
|
||||
s.integer(apuPort);
|
||||
|
||||
s.array(prg_bank);
|
||||
s.array(chr_bank);
|
||||
s.array(prgBank);
|
||||
s.array(chrBank);
|
||||
s.integer(mirror);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_counter_enable);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqCounterEnable);
|
||||
s.integer(irqCounter);
|
||||
|
||||
pulse[0].serialize(s);
|
||||
pulse[1].serialize(s);
|
||||
pulse[2].serialize(s);
|
||||
}
|
||||
|
||||
uint4 mmu_port;
|
||||
uint4 apu_port;
|
||||
uint4 mmuPort;
|
||||
uint4 apuPort;
|
||||
|
||||
uint8 prg_bank[4];
|
||||
uint8 chr_bank[8];
|
||||
uint8 prgBank[4];
|
||||
uint8 chrBank[8];
|
||||
uint2 mirror;
|
||||
bool irq_enable;
|
||||
bool irq_counter_enable;
|
||||
uint16 irq_counter;
|
||||
bool irqEnable;
|
||||
bool irqCounterEnable;
|
||||
uint16 irqCounter;
|
||||
|
||||
int16 dac[16];
|
||||
};
|
||||
|
|
|
@ -54,19 +54,19 @@ auto Cartridge::reset() -> void {
|
|||
}
|
||||
|
||||
auto Cartridge::readPRG(uint addr) -> uint8 {
|
||||
return board->prg_read(addr);
|
||||
return board->readPRG(addr);
|
||||
}
|
||||
|
||||
auto Cartridge::writePRG(uint addr, uint8 data) -> void {
|
||||
return board->prg_write(addr, data);
|
||||
return board->writePRG(addr, data);
|
||||
}
|
||||
|
||||
auto Cartridge::readCHR(uint addr) -> uint8 {
|
||||
return board->chr_read(addr);
|
||||
return board->readCHR(addr);
|
||||
}
|
||||
|
||||
auto Cartridge::writeCHR(uint addr, uint8 data) -> void {
|
||||
return board->chr_write(addr, data);
|
||||
return board->writeCHR(addr, data);
|
||||
}
|
||||
|
||||
auto Cartridge::scanline(uint y) -> void {
|
||||
|
|
|
@ -8,26 +8,26 @@ struct MMC1 : Chip {
|
|||
tick();
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) -> uint {
|
||||
auto addrPRG(uint addr) -> uint {
|
||||
bool region = addr & 0x4000;
|
||||
uint bank = (prg_bank & ~1) + region;
|
||||
uint bank = (prgBank & ~1) + region;
|
||||
|
||||
if(prg_size) {
|
||||
if(prgSize) {
|
||||
bank = (region == 0 ? 0x0 : 0xf);
|
||||
if(region != prg_mode) bank = prg_bank;
|
||||
if(region != prgMode) bank = prgBank;
|
||||
}
|
||||
|
||||
return (bank << 14) | (addr & 0x3fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) -> uint {
|
||||
auto addrCHR(uint addr) -> uint {
|
||||
bool region = addr & 0x1000;
|
||||
uint bank = chr_bank[region];
|
||||
if(chr_mode == 0) bank = (chr_bank[0] & ~1) | region;
|
||||
uint bank = chrBank[region];
|
||||
if(chrMode == 0) bank = (chrBank[0] & ~1) | region;
|
||||
return (bank << 12) | (addr & 0x0fff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) -> uint {
|
||||
auto addrCIRAM(uint addr) -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return 0x0000 | (addr & 0x03ff);
|
||||
case 1: return 0x0400 | (addr & 0x03ff);
|
||||
|
@ -36,37 +36,37 @@ struct MMC1 : Chip {
|
|||
}
|
||||
}
|
||||
|
||||
auto mmio_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
if(writedelay) return;
|
||||
writedelay = 2;
|
||||
|
||||
if(data & 0x80) {
|
||||
shiftaddr = 0;
|
||||
prg_size = 1;
|
||||
prg_mode = 1;
|
||||
prgSize = 1;
|
||||
prgMode = 1;
|
||||
} else {
|
||||
shiftdata = ((data & 1) << 4) | (shiftdata >> 1);
|
||||
if(++shiftaddr == 5) {
|
||||
shiftaddr = 0;
|
||||
switch((addr >> 13) & 3) {
|
||||
case 0:
|
||||
chr_mode = (shiftdata & 0x10);
|
||||
prg_size = (shiftdata & 0x08);
|
||||
prg_mode = (shiftdata & 0x04);
|
||||
chrMode = (shiftdata & 0x10);
|
||||
prgSize = (shiftdata & 0x08);
|
||||
prgMode = (shiftdata & 0x04);
|
||||
mirror = (shiftdata & 0x03);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
chr_bank[0] = (shiftdata & 0x1f);
|
||||
chrBank[0] = (shiftdata & 0x1f);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
chr_bank[1] = (shiftdata & 0x1f);
|
||||
chrBank[1] = (shiftdata & 0x1f);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ram_disable = (shiftdata & 0x10);
|
||||
prg_bank = (shiftdata & 0x0f);
|
||||
ramDisable = (shiftdata & 0x10);
|
||||
prgBank = (shiftdata & 0x0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -81,14 +81,14 @@ struct MMC1 : Chip {
|
|||
shiftaddr = 0;
|
||||
shiftdata = 0;
|
||||
|
||||
chr_mode = 0;
|
||||
prg_size = 1;
|
||||
prg_mode = 1;
|
||||
chrMode = 0;
|
||||
prgSize = 1;
|
||||
prgMode = 1;
|
||||
mirror = 0;
|
||||
chr_bank[0] = 0;
|
||||
chr_bank[1] = 1;
|
||||
ram_disable = 0;
|
||||
prg_bank = 0;
|
||||
chrBank[0] = 0;
|
||||
chrBank[1] = 1;
|
||||
ramDisable = 0;
|
||||
prgBank = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
|
@ -96,13 +96,13 @@ struct MMC1 : Chip {
|
|||
s.integer(shiftaddr);
|
||||
s.integer(shiftdata);
|
||||
|
||||
s.integer(chr_mode);
|
||||
s.integer(prg_size);
|
||||
s.integer(prg_mode);
|
||||
s.integer(chrMode);
|
||||
s.integer(prgSize);
|
||||
s.integer(prgMode);
|
||||
s.integer(mirror);
|
||||
s.array(chr_bank);
|
||||
s.integer(ram_disable);
|
||||
s.integer(prg_bank);
|
||||
s.array(chrBank);
|
||||
s.integer(ramDisable);
|
||||
s.integer(prgBank);
|
||||
}
|
||||
|
||||
enum class Revision : uint {
|
||||
|
@ -118,11 +118,11 @@ struct MMC1 : Chip {
|
|||
uint shiftaddr;
|
||||
uint shiftdata;
|
||||
|
||||
bool chr_mode;
|
||||
bool prg_size; //0 = 32K, 1 = 16K
|
||||
bool prg_mode;
|
||||
bool chrMode;
|
||||
bool prgSize; //0 = 32K, 1 = 16K
|
||||
bool prgMode;
|
||||
uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal
|
||||
uint5 chr_bank[2];
|
||||
bool ram_disable;
|
||||
uint4 prg_bank;
|
||||
uint5 chrBank[2];
|
||||
bool ramDisable;
|
||||
uint4 prgBank;
|
||||
};
|
||||
|
|
|
@ -3,90 +3,90 @@ struct MMC3 : Chip {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_delay) irq_delay--;
|
||||
cpu.irqLine(irq_line);
|
||||
if(irqDelay) irqDelay--;
|
||||
cpu.irqLine(irqLine);
|
||||
tick();
|
||||
}
|
||||
|
||||
auto irq_test(uint addr) -> void {
|
||||
if(!(chr_abus & 0x1000) && (addr & 0x1000)) {
|
||||
if(irq_delay == 0) {
|
||||
if(irq_counter == 0) {
|
||||
irq_counter = irq_latch;
|
||||
} else if(--irq_counter == 0) {
|
||||
if(irq_enable) irq_line = 1;
|
||||
auto irqTest(uint addr) -> void {
|
||||
if(!(chrAbus & 0x1000) && (addr & 0x1000)) {
|
||||
if(irqDelay == 0) {
|
||||
if(irqCounter == 0) {
|
||||
irqCounter = irqLatch;
|
||||
} else if(--irqCounter == 0) {
|
||||
if(irqEnable) irqLine = 1;
|
||||
}
|
||||
}
|
||||
irq_delay = 6;
|
||||
irqDelay = 6;
|
||||
}
|
||||
chr_abus = addr;
|
||||
chrAbus = addr;
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
switch((addr >> 13) & 3) {
|
||||
case 0:
|
||||
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prgBank[0] << 13) | (addr & 0x1fff);
|
||||
case 1:
|
||||
return (prg_bank[1] << 13) | (addr & 0x1fff);
|
||||
return (prgBank[1] << 13) | (addr & 0x1fff);
|
||||
case 2:
|
||||
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prgBank[0] << 13) | (addr & 0x1fff);
|
||||
case 3:
|
||||
return (0x3f << 13) | (addr & 0x1fff);
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
if(chr_mode == 0) {
|
||||
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
if(chrMode == 0) {
|
||||
if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff);
|
||||
} else {
|
||||
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x1fff) return (chrBank[1] << 10) | (addr & 0x07ff);
|
||||
}
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
|
||||
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ram_read(uint addr) -> uint8 {
|
||||
if(ram_enable) return board.prgram.data[addr & 0x1fff];
|
||||
auto readRAM(uint addr) -> uint8 {
|
||||
if(ramEnable) return board.prgram.data[addr & 0x1fff];
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto ram_write(uint addr, uint8 data) -> void {
|
||||
if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data;
|
||||
auto writeRAM(uint addr, uint8 data) -> void {
|
||||
if(ramEnable && !ramWriteProtect) board.prgram.data[addr & 0x1fff] = data;
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr & 0xe001) {
|
||||
case 0x8000:
|
||||
chr_mode = data & 0x80;
|
||||
prg_mode = data & 0x40;
|
||||
bank_select = data & 0x07;
|
||||
chrMode = data & 0x80;
|
||||
prgMode = data & 0x40;
|
||||
bankSelect = data & 0x07;
|
||||
break;
|
||||
|
||||
case 0x8001:
|
||||
switch(bank_select) {
|
||||
case 0: chr_bank[0] = data & ~1; break;
|
||||
case 1: chr_bank[1] = data & ~1; break;
|
||||
case 2: chr_bank[2] = data; break;
|
||||
case 3: chr_bank[3] = data; break;
|
||||
case 4: chr_bank[4] = data; break;
|
||||
case 5: chr_bank[5] = data; break;
|
||||
case 6: prg_bank[0] = data & 0x3f; break;
|
||||
case 7: prg_bank[1] = data & 0x3f; break;
|
||||
switch(bankSelect) {
|
||||
case 0: chrBank[0] = data & ~1; break;
|
||||
case 1: chrBank[1] = data & ~1; break;
|
||||
case 2: chrBank[2] = data; break;
|
||||
case 3: chrBank[3] = data; break;
|
||||
case 4: chrBank[4] = data; break;
|
||||
case 5: chrBank[5] = data; break;
|
||||
case 6: prgBank[0] = data & 0x3f; break;
|
||||
case 7: prgBank[1] = data & 0x3f; break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -95,25 +95,25 @@ struct MMC3 : Chip {
|
|||
break;
|
||||
|
||||
case 0xa001:
|
||||
ram_enable = data & 0x80;
|
||||
ram_write_protect = data & 0x40;
|
||||
ramEnable = data & 0x80;
|
||||
ramWriteProtect = data & 0x40;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
irq_latch = data;
|
||||
irqLatch = data;
|
||||
break;
|
||||
|
||||
case 0xc001:
|
||||
irq_counter = 0;
|
||||
irqCounter = 0;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
irq_enable = false;
|
||||
irq_line = 0;
|
||||
irqEnable = false;
|
||||
irqLine = 0;
|
||||
break;
|
||||
|
||||
case 0xe001:
|
||||
irq_enable = true;
|
||||
irqEnable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -122,60 +122,60 @@ struct MMC3 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
chr_mode = 0;
|
||||
prg_mode = 0;
|
||||
bank_select = 0;
|
||||
prg_bank[0] = 0;
|
||||
prg_bank[1] = 0;
|
||||
chr_bank[0] = 0;
|
||||
chr_bank[1] = 0;
|
||||
chr_bank[2] = 0;
|
||||
chr_bank[3] = 0;
|
||||
chr_bank[4] = 0;
|
||||
chr_bank[5] = 0;
|
||||
chrMode = 0;
|
||||
prgMode = 0;
|
||||
bankSelect = 0;
|
||||
prgBank[0] = 0;
|
||||
prgBank[1] = 0;
|
||||
chrBank[0] = 0;
|
||||
chrBank[1] = 0;
|
||||
chrBank[2] = 0;
|
||||
chrBank[3] = 0;
|
||||
chrBank[4] = 0;
|
||||
chrBank[5] = 0;
|
||||
mirror = 0;
|
||||
ram_enable = 1;
|
||||
ram_write_protect = 0;
|
||||
irq_latch = 0;
|
||||
irq_counter = 0;
|
||||
irq_enable = false;
|
||||
irq_delay = 0;
|
||||
irq_line = 0;
|
||||
ramEnable = 1;
|
||||
ramWriteProtect = 0;
|
||||
irqLatch = 0;
|
||||
irqCounter = 0;
|
||||
irqEnable = false;
|
||||
irqDelay = 0;
|
||||
irqLine = 0;
|
||||
|
||||
chr_abus = 0;
|
||||
chrAbus = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(chr_mode);
|
||||
s.integer(prg_mode);
|
||||
s.integer(bank_select);
|
||||
s.array(prg_bank);
|
||||
s.array(chr_bank);
|
||||
s.integer(chrMode);
|
||||
s.integer(prgMode);
|
||||
s.integer(bankSelect);
|
||||
s.array(prgBank);
|
||||
s.array(chrBank);
|
||||
s.integer(mirror);
|
||||
s.integer(ram_enable);
|
||||
s.integer(ram_write_protect);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_delay);
|
||||
s.integer(irq_line);
|
||||
s.integer(ramEnable);
|
||||
s.integer(ramWriteProtect);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqDelay);
|
||||
s.integer(irqLine);
|
||||
|
||||
s.integer(chr_abus);
|
||||
s.integer(chrAbus);
|
||||
}
|
||||
|
||||
bool chr_mode;
|
||||
bool prg_mode;
|
||||
uint3 bank_select;
|
||||
uint8 prg_bank[2];
|
||||
uint8 chr_bank[6];
|
||||
bool chrMode;
|
||||
bool prgMode;
|
||||
uint3 bankSelect;
|
||||
uint8 prgBank[2];
|
||||
uint8 chrBank[6];
|
||||
bool mirror;
|
||||
bool ram_enable;
|
||||
bool ram_write_protect;
|
||||
uint8 irq_latch;
|
||||
uint8 irq_counter;
|
||||
bool irq_enable;
|
||||
uint irq_delay;
|
||||
bool irq_line;
|
||||
bool ramEnable;
|
||||
bool ramWriteProtect;
|
||||
uint8 irqLatch;
|
||||
uint8 irqCounter;
|
||||
bool irqEnable;
|
||||
uint irqDelay;
|
||||
bool irqLine;
|
||||
|
||||
uint16 chr_abus;
|
||||
uint16 chrAbus;
|
||||
};
|
||||
|
|
|
@ -5,9 +5,9 @@ struct MMC5 : Chip {
|
|||
|
||||
auto main() -> void {
|
||||
//scanline() resets this; if no scanlines detected, enter video blanking period
|
||||
if(++cpu_cycle_counter >= 200) blank(); //113-114 normal; ~2500 across Vblank period
|
||||
if(++cpuCycleCounter >= 200) blank(); //113-114 normal; ~2500 across Vblank period
|
||||
|
||||
cpu.irqLine(irq_enable && irq_pending);
|
||||
cpu.irqLine(irqEnable && irqPending);
|
||||
tick();
|
||||
}
|
||||
|
||||
|
@ -16,30 +16,30 @@ struct MMC5 : Chip {
|
|||
//if(y != vcounter && y <= 240) print(y, " vs ", vcounter, "\n");
|
||||
}
|
||||
|
||||
auto prg_access(bool write, uint addr, uint8 data = 0x00) -> uint8 {
|
||||
auto accessPRG(bool write, uint addr, uint8 data = 0x00) -> uint8 {
|
||||
uint bank;
|
||||
|
||||
if((addr & 0xe000) == 0x6000) {
|
||||
bank = (ram_select << 2) | ram_bank;
|
||||
bank = (ramSelect << 2) | ramBank;
|
||||
addr &= 0x1fff;
|
||||
} else if(prg_mode == 0) {
|
||||
bank = prg_bank[3] & ~3;
|
||||
} else if(prgMode == 0) {
|
||||
bank = prgBank[3] & ~3;
|
||||
addr &= 0x7fff;
|
||||
} else if(prg_mode == 1) {
|
||||
if((addr & 0xc000) == 0x8000) bank = (prg_bank[1] & ~1);
|
||||
if((addr & 0xe000) == 0xc000) bank = (prg_bank[3] & ~1);
|
||||
} else if(prgMode == 1) {
|
||||
if((addr & 0xc000) == 0x8000) bank = (prgBank[1] & ~1);
|
||||
if((addr & 0xe000) == 0xc000) bank = (prgBank[3] & ~1);
|
||||
addr &= 0x3fff;
|
||||
} else if(prg_mode == 2) {
|
||||
if((addr & 0xe000) == 0x8000) bank = (prg_bank[1] & ~1) | 0;
|
||||
if((addr & 0xe000) == 0xa000) bank = (prg_bank[1] & ~1) | 1;
|
||||
if((addr & 0xe000) == 0xc000) bank = (prg_bank[2]);
|
||||
if((addr & 0xe000) == 0xe000) bank = (prg_bank[3]);
|
||||
} else if(prgMode == 2) {
|
||||
if((addr & 0xe000) == 0x8000) bank = (prgBank[1] & ~1) | 0;
|
||||
if((addr & 0xe000) == 0xa000) bank = (prgBank[1] & ~1) | 1;
|
||||
if((addr & 0xe000) == 0xc000) bank = (prgBank[2]);
|
||||
if((addr & 0xe000) == 0xe000) bank = (prgBank[3]);
|
||||
addr &= 0x1fff;
|
||||
} else if(prg_mode == 3) {
|
||||
if((addr & 0xe000) == 0x8000) bank = prg_bank[0];
|
||||
if((addr & 0xe000) == 0xa000) bank = prg_bank[1];
|
||||
if((addr & 0xe000) == 0xc000) bank = prg_bank[2];
|
||||
if((addr & 0xe000) == 0xe000) bank = prg_bank[3];
|
||||
} else if(prgMode == 3) {
|
||||
if((addr & 0xe000) == 0x8000) bank = prgBank[0];
|
||||
if((addr & 0xe000) == 0xa000) bank = prgBank[1];
|
||||
if((addr & 0xe000) == 0xc000) bank = prgBank[2];
|
||||
if((addr & 0xe000) == 0xe000) bank = prgBank[3];
|
||||
addr &= 0x1fff;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ struct MMC5 : Chip {
|
|||
if(rom) {
|
||||
board.prgrom.write((bank << 13) | addr, data);
|
||||
} else {
|
||||
if(prgram_write_protect[0] == 2 && prgram_write_protect[1] == 1) {
|
||||
if(prgramWriteProtect[0] == 2 && prgramWriteProtect[1] == 1) {
|
||||
board.prgram.write((bank << 13) | addr, data);
|
||||
}
|
||||
}
|
||||
|
@ -64,20 +64,20 @@ struct MMC5 : Chip {
|
|||
}
|
||||
}
|
||||
|
||||
auto prg_read(uint addr) -> uint8 {
|
||||
auto readPRG(uint addr) -> uint8 {
|
||||
if((addr & 0xfc00) == 0x5c00) {
|
||||
if(exram_mode >= 2) return exram[addr & 0x03ff];
|
||||
if(exramMode >= 2) return exram[addr & 0x03ff];
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
if(addr >= 0x6000) {
|
||||
return prg_access(0, addr);
|
||||
return accessPRG(0, addr);
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x5204: {
|
||||
uint8 result = (irq_pending << 7) | (in_frame << 6);
|
||||
irq_pending = false;
|
||||
uint8 result = (irqPending << 7) | (inFrame << 6);
|
||||
irqPending = false;
|
||||
return result;
|
||||
}
|
||||
case 0x5205: return (multiplier * multiplicand) >> 0;
|
||||
|
@ -85,22 +85,22 @@ struct MMC5 : Chip {
|
|||
}
|
||||
}
|
||||
|
||||
auto prg_write(uint addr, uint8 data) -> void {
|
||||
auto writePRG(uint addr, uint8 data) -> void {
|
||||
if((addr & 0xfc00) == 0x5c00) {
|
||||
//writes 0x00 *during* Vblank (not during screen rendering ...)
|
||||
if(exram_mode == 0 || exram_mode == 1) exram[addr & 0x03ff] = in_frame ? data : (uint8)0x00;
|
||||
if(exram_mode == 2) exram[addr & 0x03ff] = data;
|
||||
if(exramMode == 0 || exramMode == 1) exram[addr & 0x03ff] = inFrame ? data : (uint8)0x00;
|
||||
if(exramMode == 2) exram[addr & 0x03ff] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr >= 0x6000) {
|
||||
prg_access(1, addr, data);
|
||||
accessPRG(1, addr, data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch(addr) {
|
||||
case 0x2000:
|
||||
sprite_8x16 = data & 0x20;
|
||||
sprite8x16 = data & 0x20;
|
||||
break;
|
||||
|
||||
case 0x2001:
|
||||
|
@ -108,81 +108,81 @@ struct MMC5 : Chip {
|
|||
if((data & 0x18) == 0) blank();
|
||||
break;
|
||||
|
||||
case 0x5100: prg_mode = data & 3; break;
|
||||
case 0x5101: chr_mode = data & 3; break;
|
||||
case 0x5100: prgMode = data & 3; break;
|
||||
case 0x5101: chrMode = data & 3; break;
|
||||
|
||||
case 0x5102: prgram_write_protect[0] = data & 3; break;
|
||||
case 0x5103: prgram_write_protect[1] = data & 3; break;
|
||||
case 0x5102: prgramWriteProtect[0] = data & 3; break;
|
||||
case 0x5103: prgramWriteProtect[1] = data & 3; break;
|
||||
|
||||
case 0x5104:
|
||||
exram_mode = data & 3;
|
||||
exramMode = data & 3;
|
||||
break;
|
||||
|
||||
case 0x5105:
|
||||
nametable_mode[0] = (data & 0x03) >> 0;
|
||||
nametable_mode[1] = (data & 0x0c) >> 2;
|
||||
nametable_mode[2] = (data & 0x30) >> 4;
|
||||
nametable_mode[3] = (data & 0xc0) >> 6;
|
||||
nametableMode[0] = (data & 0x03) >> 0;
|
||||
nametableMode[1] = (data & 0x0c) >> 2;
|
||||
nametableMode[2] = (data & 0x30) >> 4;
|
||||
nametableMode[3] = (data & 0xc0) >> 6;
|
||||
break;
|
||||
|
||||
case 0x5106:
|
||||
fillmode_tile = data;
|
||||
fillmodeTile = data;
|
||||
break;
|
||||
|
||||
case 0x5107:
|
||||
fillmode_color = data & 3;
|
||||
fillmode_color |= fillmode_color << 2;
|
||||
fillmode_color |= fillmode_color << 4;
|
||||
fillmodeColor = data & 3;
|
||||
fillmodeColor |= fillmodeColor << 2;
|
||||
fillmodeColor |= fillmodeColor << 4;
|
||||
break;
|
||||
|
||||
case 0x5113:
|
||||
ram_select = data & 0x04;
|
||||
ram_bank = data & 0x03;
|
||||
ramSelect = data & 0x04;
|
||||
ramBank = data & 0x03;
|
||||
break;
|
||||
|
||||
case 0x5114: prg_bank[0] = data; break;
|
||||
case 0x5115: prg_bank[1] = data; break;
|
||||
case 0x5116: prg_bank[2] = data; break;
|
||||
case 0x5117: prg_bank[3] = data | 0x80; break;
|
||||
case 0x5114: prgBank[0] = data; break;
|
||||
case 0x5115: prgBank[1] = data; break;
|
||||
case 0x5116: prgBank[2] = data; break;
|
||||
case 0x5117: prgBank[3] = data | 0x80; break;
|
||||
|
||||
case 0x5120: chr_sprite_bank[0] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5121: chr_sprite_bank[1] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5122: chr_sprite_bank[2] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5123: chr_sprite_bank[3] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5124: chr_sprite_bank[4] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5125: chr_sprite_bank[5] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5126: chr_sprite_bank[6] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5127: chr_sprite_bank[7] = (chr_bank_hi << 8) | data; chr_active = 0; break;
|
||||
case 0x5120: chrSpriteBank[0] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5121: chrSpriteBank[1] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5122: chrSpriteBank[2] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5123: chrSpriteBank[3] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5124: chrSpriteBank[4] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5125: chrSpriteBank[5] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5126: chrSpriteBank[6] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
case 0x5127: chrSpriteBank[7] = (chrBankHi << 8) | data; chrActive = 0; break;
|
||||
|
||||
case 0x5128: chr_bg_bank[0] = (chr_bank_hi << 8) | data; chr_active = 1; break;
|
||||
case 0x5129: chr_bg_bank[1] = (chr_bank_hi << 8) | data; chr_active = 1; break;
|
||||
case 0x512a: chr_bg_bank[2] = (chr_bank_hi << 8) | data; chr_active = 1; break;
|
||||
case 0x512b: chr_bg_bank[3] = (chr_bank_hi << 8) | data; chr_active = 1; break;
|
||||
case 0x5128: chrBGBank[0] = (chrBankHi << 8) | data; chrActive = 1; break;
|
||||
case 0x5129: chrBGBank[1] = (chrBankHi << 8) | data; chrActive = 1; break;
|
||||
case 0x512a: chrBGBank[2] = (chrBankHi << 8) | data; chrActive = 1; break;
|
||||
case 0x512b: chrBGBank[3] = (chrBankHi << 8) | data; chrActive = 1; break;
|
||||
|
||||
case 0x5130:
|
||||
chr_bank_hi = data & 3;
|
||||
chrBankHi = data & 3;
|
||||
break;
|
||||
|
||||
case 0x5200:
|
||||
vs_enable = data & 0x80;
|
||||
vs_side = data & 0x40;
|
||||
vs_tile = data & 0x1f;
|
||||
vsEnable = data & 0x80;
|
||||
vsSide = data & 0x40;
|
||||
vsTile = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x5201:
|
||||
vs_scroll = data;
|
||||
vsScroll = data;
|
||||
break;
|
||||
|
||||
case 0x5202:
|
||||
vs_bank = data;
|
||||
vsBank = data;
|
||||
break;
|
||||
|
||||
case 0x5203:
|
||||
irq_line = data;
|
||||
irqLine = data;
|
||||
break;
|
||||
|
||||
case 0x5204:
|
||||
irq_enable = data & 0x80;
|
||||
irqEnable = data & 0x80;
|
||||
break;
|
||||
|
||||
case 0x5205:
|
||||
|
@ -195,138 +195,138 @@ struct MMC5 : Chip {
|
|||
}
|
||||
}
|
||||
|
||||
auto chr_sprite_addr(uint addr) -> uint {
|
||||
if(chr_mode == 0) {
|
||||
auto bank = chr_sprite_bank[7];
|
||||
auto chrSpriteAddr(uint addr) -> uint {
|
||||
if(chrMode == 0) {
|
||||
auto bank = chrSpriteBank[7];
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 1) {
|
||||
auto bank = chr_sprite_bank[(addr / 0x1000) * 4 + 3];
|
||||
if(chrMode == 1) {
|
||||
auto bank = chrSpriteBank[(addr / 0x1000) * 4 + 3];
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 2) {
|
||||
auto bank = chr_sprite_bank[(addr / 0x0800) * 2 + 1];
|
||||
if(chrMode == 2) {
|
||||
auto bank = chrSpriteBank[(addr / 0x0800) * 2 + 1];
|
||||
return (bank * 0x0800) + (addr & 0x07ff);
|
||||
}
|
||||
|
||||
if(chr_mode == 3) {
|
||||
auto bank = chr_sprite_bank[(addr / 0x0400)];
|
||||
if(chrMode == 3) {
|
||||
auto bank = chrSpriteBank[(addr / 0x0400)];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_bg_addr(uint addr) -> uint {
|
||||
auto chrBGAddr(uint addr) -> uint {
|
||||
addr &= 0x0fff;
|
||||
|
||||
if(chr_mode == 0) {
|
||||
auto bank = chr_bg_bank[3];
|
||||
if(chrMode == 0) {
|
||||
auto bank = chrBGBank[3];
|
||||
return (bank * 0x2000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 1) {
|
||||
auto bank = chr_bg_bank[3];
|
||||
if(chrMode == 1) {
|
||||
auto bank = chrBGBank[3];
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 2) {
|
||||
auto bank = chr_bg_bank[(addr / 0x0800) * 2 + 1];
|
||||
if(chrMode == 2) {
|
||||
auto bank = chrBGBank[(addr / 0x0800) * 2 + 1];
|
||||
return (bank * 0x0800) + (addr & 0x07ff);
|
||||
}
|
||||
|
||||
if(chr_mode == 3) {
|
||||
auto bank = chr_bg_bank[(addr / 0x0400)];
|
||||
if(chrMode == 3) {
|
||||
auto bank = chrBGBank[(addr / 0x0400)];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_vs_addr(uint addr) -> uint {
|
||||
return (vs_bank * 0x1000) + (addr & 0x0ff8) + (vs_vpos & 7);
|
||||
auto chrVSAddr(uint addr) -> uint {
|
||||
return (vsBank * 0x1000) + (addr & 0x0ff8) + (vsVpos & 7);
|
||||
}
|
||||
|
||||
auto blank() -> void {
|
||||
in_frame = false;
|
||||
inFrame = false;
|
||||
}
|
||||
|
||||
auto scanline() -> void {
|
||||
hcounter = 0;
|
||||
|
||||
if(in_frame == false) {
|
||||
in_frame = true;
|
||||
irq_pending = false;
|
||||
if(inFrame == false) {
|
||||
inFrame = true;
|
||||
irqPending = false;
|
||||
vcounter = 0;
|
||||
} else {
|
||||
if(vcounter == irq_line) irq_pending = true;
|
||||
if(vcounter == irqLine) irqPending = true;
|
||||
vcounter++;
|
||||
}
|
||||
|
||||
cpu_cycle_counter = 0;
|
||||
cpuCycleCounter = 0;
|
||||
}
|
||||
|
||||
auto ciram_read(uint addr) -> uint8 {
|
||||
if(vs_fetch && (hcounter & 2) == 0) return exram[vs_vpos / 8 * 32 + vs_hpos / 8];
|
||||
if(vs_fetch && (hcounter & 2) != 0) return exram[vs_vpos / 32 * 8 + vs_hpos / 32 + 0x03c0];
|
||||
auto readCIRAM(uint addr) -> uint8 {
|
||||
if(vsFetch && (hcounter & 2) == 0) return exram[vsVpos / 8 * 32 + vsHpos / 8];
|
||||
if(vsFetch && (hcounter & 2) != 0) return exram[vsVpos / 32 * 8 + vsHpos / 32 + 0x03c0];
|
||||
|
||||
switch(nametable_mode[(addr >> 10) & 3]) {
|
||||
switch(nametableMode[(addr >> 10) & 3]) {
|
||||
case 0: return ppu.readCIRAM(0x0000 | (addr & 0x03ff));
|
||||
case 1: return ppu.readCIRAM(0x0400 | (addr & 0x03ff));
|
||||
case 2: return exram_mode < 2 ? exram[addr & 0x03ff] : (uint8)0x00;
|
||||
case 3: return (hcounter & 2) == 0 ? fillmode_tile : fillmode_color;
|
||||
case 2: return exramMode < 2 ? exram[addr & 0x03ff] : (uint8)0x00;
|
||||
case 3: return (hcounter & 2) == 0 ? fillmodeTile : fillmodeColor;
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_read(uint addr) -> uint8 {
|
||||
chr_access[0] = chr_access[1];
|
||||
chr_access[1] = chr_access[2];
|
||||
chr_access[2] = chr_access[3];
|
||||
chr_access[3] = addr;
|
||||
auto readCHR(uint addr) -> uint8 {
|
||||
chrAccess[0] = chrAccess[1];
|
||||
chrAccess[1] = chrAccess[2];
|
||||
chrAccess[2] = chrAccess[3];
|
||||
chrAccess[3] = addr;
|
||||
|
||||
//detect two unused nametable fetches at end of each scanline
|
||||
if((chr_access[0] & 0x2000) == 0
|
||||
&& (chr_access[1] & 0x2000)
|
||||
&& (chr_access[2] & 0x2000)
|
||||
&& (chr_access[3] & 0x2000)) scanline();
|
||||
if((chrAccess[0] & 0x2000) == 0
|
||||
&& (chrAccess[1] & 0x2000)
|
||||
&& (chrAccess[2] & 0x2000)
|
||||
&& (chrAccess[3] & 0x2000)) scanline();
|
||||
|
||||
if(in_frame == false) {
|
||||
vs_fetch = false;
|
||||
if(addr & 0x2000) return ciram_read(addr);
|
||||
return board.chrrom.read(chr_active ? chr_bg_addr(addr) : chr_sprite_addr(addr));
|
||||
if(inFrame == false) {
|
||||
vsFetch = false;
|
||||
if(addr & 0x2000) return readCIRAM(addr);
|
||||
return board.chrrom.read(chrActive ? chrBGAddr(addr) : chrSpriteAddr(addr));
|
||||
}
|
||||
|
||||
bool bg_fetch = (hcounter < 256 || hcounter >= 320);
|
||||
bool bgFetch = (hcounter < 256 || hcounter >= 320);
|
||||
uint8 result = 0x00;
|
||||
|
||||
if((hcounter & 7) == 0) {
|
||||
vs_hpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16;
|
||||
vs_vpos = vcounter + vs_scroll;
|
||||
vs_fetch = vs_enable && bg_fetch && exram_mode < 2
|
||||
&& (vs_side ? vs_hpos / 8 >= vs_tile : vs_hpos / 8 < vs_tile);
|
||||
if(vs_vpos >= 240) vs_vpos -= 240;
|
||||
vsHpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16;
|
||||
vsVpos = vcounter + vsScroll;
|
||||
vsFetch = vsEnable && bgFetch && exramMode < 2
|
||||
&& (vsSide ? vsHpos / 8 >= vsTile : vsHpos / 8 < vsTile);
|
||||
if(vsVpos >= 240) vsVpos -= 240;
|
||||
|
||||
result = ciram_read(addr);
|
||||
result = readCIRAM(addr);
|
||||
|
||||
exbank = (chr_bank_hi << 6) | (exram[addr & 0x03ff] & 0x3f);
|
||||
exbank = (chrBankHi << 6) | (exram[addr & 0x03ff] & 0x3f);
|
||||
exattr = exram[addr & 0x03ff] >> 6;
|
||||
exattr |= exattr << 2;
|
||||
exattr |= exattr << 4;
|
||||
} else if((hcounter & 7) == 2) {
|
||||
result = ciram_read(addr);
|
||||
if(bg_fetch && exram_mode == 1) result = exattr;
|
||||
result = readCIRAM(addr);
|
||||
if(bgFetch && exramMode == 1) result = exattr;
|
||||
} else {
|
||||
if(vs_fetch) result = board.chrrom.read(chr_vs_addr(addr));
|
||||
else if(sprite_8x16 ? bg_fetch : chr_active) result = board.chrrom.read(chr_bg_addr(addr));
|
||||
else result = board.chrrom.read(chr_sprite_addr(addr));
|
||||
if(bg_fetch && exram_mode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff));
|
||||
if(vsFetch) result = board.chrrom.read(chrVSAddr(addr));
|
||||
else if(sprite8x16 ? bgFetch : chrActive) result = board.chrrom.read(chrBGAddr(addr));
|
||||
else result = board.chrrom.read(chrSpriteAddr(addr));
|
||||
if(bgFetch && exramMode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff));
|
||||
}
|
||||
|
||||
hcounter += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
auto chr_write(uint addr, uint8 data) -> void {
|
||||
auto writeCHR(uint addr, uint8 data) -> void {
|
||||
if(addr & 0x2000) {
|
||||
switch(nametable_mode[(addr >> 10) & 3]) {
|
||||
switch(nametableMode[(addr >> 10) & 3]) {
|
||||
case 0: return ppu.writeCIRAM(0x0000 | (addr & 0x03ff), data);
|
||||
case 1: return ppu.writeCIRAM(0x0400 | (addr & 0x03ff), data);
|
||||
case 2: exram[addr & 0x03ff] = data; break;
|
||||
|
@ -340,93 +340,93 @@ struct MMC5 : Chip {
|
|||
auto reset() -> void {
|
||||
for(auto& n : exram) n = 0xff;
|
||||
|
||||
prg_mode = 3;
|
||||
chr_mode = 0;
|
||||
for(auto& n : prgram_write_protect) n = 0;
|
||||
exram_mode = 0;
|
||||
for(auto& n : nametable_mode) n = 0;
|
||||
fillmode_tile = 0;
|
||||
fillmode_color = 0;
|
||||
ram_select = 0;
|
||||
ram_bank = 0;
|
||||
prg_bank[0] = 0x00;
|
||||
prg_bank[1] = 0x00;
|
||||
prg_bank[2] = 0x00;
|
||||
prg_bank[3] = 0xff;
|
||||
for(auto& n : chr_sprite_bank) n = 0;
|
||||
for(auto& n : chr_bg_bank) n = 0;
|
||||
chr_bank_hi = 0;
|
||||
vs_enable = 0;
|
||||
vs_side = 0;
|
||||
vs_tile = 0;
|
||||
vs_scroll = 0;
|
||||
vs_bank = 0;
|
||||
irq_line = 0;
|
||||
irq_enable = 0;
|
||||
prgMode = 3;
|
||||
chrMode = 0;
|
||||
for(auto& n : prgramWriteProtect) n = 0;
|
||||
exramMode = 0;
|
||||
for(auto& n : nametableMode) n = 0;
|
||||
fillmodeTile = 0;
|
||||
fillmodeColor = 0;
|
||||
ramSelect = 0;
|
||||
ramBank = 0;
|
||||
prgBank[0] = 0x00;
|
||||
prgBank[1] = 0x00;
|
||||
prgBank[2] = 0x00;
|
||||
prgBank[3] = 0xff;
|
||||
for(auto& n : chrSpriteBank) n = 0;
|
||||
for(auto& n : chrBGBank) n = 0;
|
||||
chrBankHi = 0;
|
||||
vsEnable = 0;
|
||||
vsSide = 0;
|
||||
vsTile = 0;
|
||||
vsScroll = 0;
|
||||
vsBank = 0;
|
||||
irqLine = 0;
|
||||
irqEnable = 0;
|
||||
multiplicand = 0;
|
||||
multiplier = 0;
|
||||
|
||||
cpu_cycle_counter = 0;
|
||||
irq_counter = 0;
|
||||
irq_pending = 0;
|
||||
in_frame = 0;
|
||||
cpuCycleCounter = 0;
|
||||
irqCounter = 0;
|
||||
irqPending = 0;
|
||||
inFrame = 0;
|
||||
vcounter = 0;
|
||||
hcounter = 0;
|
||||
for(auto& n : chr_access) n = 0;
|
||||
chr_active = 0;
|
||||
sprite_8x16 = 0;
|
||||
for(auto& n : chrAccess) n = 0;
|
||||
chrActive = 0;
|
||||
sprite8x16 = 0;
|
||||
|
||||
exbank = 0;
|
||||
exattr = 0;
|
||||
|
||||
vs_fetch = 0;
|
||||
vs_vpos = 0;
|
||||
vs_hpos = 0;
|
||||
vsFetch = 0;
|
||||
vsVpos = 0;
|
||||
vsHpos = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.array(exram);
|
||||
|
||||
s.integer(prg_mode);
|
||||
s.integer(chr_mode);
|
||||
for(auto& n : prgram_write_protect) s.integer(n);
|
||||
s.integer(exram_mode);
|
||||
for(auto& n : nametable_mode) s.integer(n);
|
||||
s.integer(fillmode_tile);
|
||||
s.integer(fillmode_color);
|
||||
s.integer(ram_select);
|
||||
s.integer(ram_bank);
|
||||
for(auto& n : prg_bank) s.integer(n);
|
||||
for(auto& n : chr_sprite_bank) s.integer(n);
|
||||
for(auto& n : chr_bg_bank) s.integer(n);
|
||||
s.integer(chr_bank_hi);
|
||||
s.integer(vs_enable);
|
||||
s.integer(vs_side);
|
||||
s.integer(vs_tile);
|
||||
s.integer(vs_scroll);
|
||||
s.integer(vs_bank);
|
||||
s.integer(irq_line);
|
||||
s.integer(irq_enable);
|
||||
s.integer(prgMode);
|
||||
s.integer(chrMode);
|
||||
for(auto& n : prgramWriteProtect) s.integer(n);
|
||||
s.integer(exramMode);
|
||||
for(auto& n : nametableMode) s.integer(n);
|
||||
s.integer(fillmodeTile);
|
||||
s.integer(fillmodeColor);
|
||||
s.integer(ramSelect);
|
||||
s.integer(ramBank);
|
||||
for(auto& n : prgBank) s.integer(n);
|
||||
for(auto& n : chrSpriteBank) s.integer(n);
|
||||
for(auto& n : chrBGBank) s.integer(n);
|
||||
s.integer(chrBankHi);
|
||||
s.integer(vsEnable);
|
||||
s.integer(vsSide);
|
||||
s.integer(vsTile);
|
||||
s.integer(vsScroll);
|
||||
s.integer(vsBank);
|
||||
s.integer(irqLine);
|
||||
s.integer(irqEnable);
|
||||
s.integer(multiplicand);
|
||||
s.integer(multiplier);
|
||||
|
||||
s.integer(cpu_cycle_counter);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_pending);
|
||||
s.integer(in_frame);
|
||||
s.integer(cpuCycleCounter);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqPending);
|
||||
s.integer(inFrame);
|
||||
|
||||
s.integer(vcounter);
|
||||
s.integer(hcounter);
|
||||
for(auto& n : chr_access) s.integer(n);
|
||||
s.integer(chr_active);
|
||||
s.integer(sprite_8x16);
|
||||
for(auto& n : chrAccess) s.integer(n);
|
||||
s.integer(chrActive);
|
||||
s.integer(sprite8x16);
|
||||
|
||||
s.integer(exbank);
|
||||
s.integer(exattr);
|
||||
|
||||
s.integer(vs_fetch);
|
||||
s.integer(vs_vpos);
|
||||
s.integer(vs_hpos);
|
||||
s.integer(vsFetch);
|
||||
s.integer(vsVpos);
|
||||
s.integer(vsHpos);
|
||||
}
|
||||
|
||||
enum class Revision : uint {
|
||||
|
@ -438,52 +438,52 @@ struct MMC5 : Chip {
|
|||
|
||||
//programmable registers
|
||||
|
||||
uint2 prg_mode; //$5100
|
||||
uint2 chr_mode; //$5101
|
||||
uint2 prgMode; //$5100
|
||||
uint2 chrMode; //$5101
|
||||
|
||||
uint2 prgram_write_protect[2]; //$5102,$5103
|
||||
uint2 prgramWriteProtect[2]; //$5102,$5103
|
||||
|
||||
uint2 exram_mode; //$5104
|
||||
uint2 nametable_mode[4]; //$5105
|
||||
uint8 fillmode_tile; //$5106
|
||||
uint8 fillmode_color; //$5107
|
||||
uint2 exramMode; //$5104
|
||||
uint2 nametableMode[4]; //$5105
|
||||
uint8 fillmodeTile; //$5106
|
||||
uint8 fillmodeColor; //$5107
|
||||
|
||||
bool ram_select; //$5113
|
||||
uint2 ram_bank; //$5113
|
||||
uint8 prg_bank[4]; //$5114-5117
|
||||
uint10 chr_sprite_bank[8]; //$5120-5127
|
||||
uint10 chr_bg_bank[4]; //$5128-512b
|
||||
uint2 chr_bank_hi; //$5130
|
||||
bool ramSelect; //$5113
|
||||
uint2 ramBank; //$5113
|
||||
uint8 prgBank[4]; //$5114-5117
|
||||
uint10 chrSpriteBank[8]; //$5120-5127
|
||||
uint10 chrBGBank[4]; //$5128-512b
|
||||
uint2 chrBankHi; //$5130
|
||||
|
||||
bool vs_enable; //$5200
|
||||
bool vs_side; //$5200
|
||||
uint5 vs_tile; //$5200
|
||||
uint8 vs_scroll; //$5201
|
||||
uint8 vs_bank; //$5202
|
||||
bool vsEnable; //$5200
|
||||
bool vsSide; //$5200
|
||||
uint5 vsTile; //$5200
|
||||
uint8 vsScroll; //$5201
|
||||
uint8 vsBank; //$5202
|
||||
|
||||
uint8 irq_line; //$5203
|
||||
bool irq_enable; //$5204
|
||||
uint8 irqLine; //$5203
|
||||
bool irqEnable; //$5204
|
||||
|
||||
uint8 multiplicand; //$5205
|
||||
uint8 multiplier; //$5206
|
||||
|
||||
//status registers
|
||||
|
||||
uint cpu_cycle_counter;
|
||||
uint irq_counter;
|
||||
bool irq_pending;
|
||||
bool in_frame;
|
||||
uint cpuCycleCounter;
|
||||
uint irqCounter;
|
||||
bool irqPending;
|
||||
bool inFrame;
|
||||
|
||||
uint vcounter;
|
||||
uint hcounter;
|
||||
uint16 chr_access[4];
|
||||
bool chr_active;
|
||||
bool sprite_8x16;
|
||||
uint16 chrAccess[4];
|
||||
bool chrActive;
|
||||
bool sprite8x16;
|
||||
|
||||
uint8 exbank;
|
||||
uint8 exattr;
|
||||
|
||||
bool vs_fetch;
|
||||
uint8 vs_vpos;
|
||||
uint8 vs_hpos;
|
||||
bool vsFetch;
|
||||
uint8 vsVpos;
|
||||
uint8 vsHpos;
|
||||
};
|
||||
|
|
|
@ -3,101 +3,101 @@ struct MMC6 : Chip {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_delay) irq_delay--;
|
||||
cpu.irqLine(irq_line);
|
||||
if(irqDelay) irqDelay--;
|
||||
cpu.irqLine(irqLine);
|
||||
tick();
|
||||
}
|
||||
|
||||
auto irq_test(uint addr) -> void {
|
||||
if(!(chr_abus & 0x1000) && (addr & 0x1000)) {
|
||||
if(irq_delay == 0) {
|
||||
if(irq_counter == 0) {
|
||||
irq_counter = irq_latch;
|
||||
} else if(--irq_counter == 0) {
|
||||
if(irq_enable) irq_line = 1;
|
||||
auto irqTest(uint addr) -> void {
|
||||
if(!(chrAbus & 0x1000) && (addr & 0x1000)) {
|
||||
if(irqDelay == 0) {
|
||||
if(irqCounter == 0) {
|
||||
irqCounter = irqLatch;
|
||||
} else if(--irqCounter == 0) {
|
||||
if(irqEnable) irqLine = 1;
|
||||
}
|
||||
}
|
||||
irq_delay = 6;
|
||||
irqDelay = 6;
|
||||
}
|
||||
chr_abus = addr;
|
||||
chrAbus = addr;
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
switch((addr >> 13) & 3) {
|
||||
case 0:
|
||||
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prgBank[0] << 13) | (addr & 0x1fff);
|
||||
case 1:
|
||||
return (prg_bank[1] << 13) | (addr & 0x1fff);
|
||||
return (prgBank[1] << 13) | (addr & 0x1fff);
|
||||
case 2:
|
||||
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prgBank[0] << 13) | (addr & 0x1fff);
|
||||
case 3:
|
||||
return (0x3f << 13) | (addr & 0x1fff);
|
||||
}
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
if(chr_mode == 0) {
|
||||
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
if(chrMode == 0) {
|
||||
if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff);
|
||||
} else {
|
||||
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x1fff) return (chrBank[1] << 10) | (addr & 0x07ff);
|
||||
}
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
|
||||
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ram_read(uint addr) -> uint8 {
|
||||
if(ram_enable == false) return cpu.mdr();
|
||||
if(ram_readable[0] == false && ram_readable[1] == false) return cpu.mdr();
|
||||
auto readRAM(uint addr) -> uint8 {
|
||||
if(ramEnable == false) return cpu.mdr();
|
||||
if(ramReadable[0] == false && ramReadable[1] == false) return cpu.mdr();
|
||||
bool region = addr & 0x0200;
|
||||
if(ram_readable[region] == false) return 0x00;
|
||||
if(ramReadable[region] == false) return 0x00;
|
||||
return board.prgram.read((region * 0x0200) + (addr & 0x01ff));
|
||||
}
|
||||
|
||||
auto ram_write(uint addr, uint8 data) -> void {
|
||||
if(ram_enable == false) return;
|
||||
auto writeRAM(uint addr, uint8 data) -> void {
|
||||
if(ramEnable == false) return;
|
||||
bool region = addr & 0x0200;
|
||||
if(ram_writable[region] == false) return;
|
||||
if(ramWritable[region] == false) return;
|
||||
return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data);
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr & 0xe001) {
|
||||
case 0x8000:
|
||||
chr_mode = data & 0x80;
|
||||
prg_mode = data & 0x40;
|
||||
ram_enable = data & 0x20;
|
||||
bank_select = data & 0x07;
|
||||
if(ram_enable == false) {
|
||||
for(auto &n : ram_readable) n = false;
|
||||
for(auto &n : ram_writable) n = false;
|
||||
chrMode = data & 0x80;
|
||||
prgMode = data & 0x40;
|
||||
ramEnable = data & 0x20;
|
||||
bankSelect = data & 0x07;
|
||||
if(ramEnable == false) {
|
||||
for(auto &n : ramReadable) n = false;
|
||||
for(auto &n : ramWritable) n = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8001:
|
||||
switch(bank_select) {
|
||||
case 0: chr_bank[0] = data & ~1; break;
|
||||
case 1: chr_bank[1] = data & ~1; break;
|
||||
case 2: chr_bank[2] = data; break;
|
||||
case 3: chr_bank[3] = data; break;
|
||||
case 4: chr_bank[4] = data; break;
|
||||
case 5: chr_bank[5] = data; break;
|
||||
case 6: prg_bank[0] = data & 0x3f; break;
|
||||
case 7: prg_bank[1] = data & 0x3f; break;
|
||||
switch(bankSelect) {
|
||||
case 0: chrBank[0] = data & ~1; break;
|
||||
case 1: chrBank[1] = data & ~1; break;
|
||||
case 2: chrBank[2] = data; break;
|
||||
case 3: chrBank[3] = data; break;
|
||||
case 4: chrBank[4] = data; break;
|
||||
case 5: chrBank[5] = data; break;
|
||||
case 6: prgBank[0] = data & 0x3f; break;
|
||||
case 7: prgBank[1] = data & 0x3f; break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -106,28 +106,28 @@ struct MMC6 : Chip {
|
|||
break;
|
||||
|
||||
case 0xa001:
|
||||
if(ram_enable == false) break;
|
||||
ram_readable[1] = data & 0x80;
|
||||
ram_writable[1] = data & 0x40;
|
||||
ram_readable[0] = data & 0x20;
|
||||
ram_writable[0] = data & 0x10;
|
||||
if(ramEnable == false) break;
|
||||
ramReadable[1] = data & 0x80;
|
||||
ramWritable[1] = data & 0x40;
|
||||
ramReadable[0] = data & 0x20;
|
||||
ramWritable[0] = data & 0x10;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
irq_latch = data;
|
||||
irqLatch = data;
|
||||
break;
|
||||
|
||||
case 0xc001:
|
||||
irq_counter = 0;
|
||||
irqCounter = 0;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
irq_enable = false;
|
||||
irq_line = 0;
|
||||
irqEnable = false;
|
||||
irqLine = 0;
|
||||
break;
|
||||
|
||||
case 0xe001:
|
||||
irq_enable = true;
|
||||
irqEnable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -136,57 +136,57 @@ struct MMC6 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
chr_mode = 0;
|
||||
prg_mode = 0;
|
||||
ram_enable = 0;
|
||||
bank_select = 0;
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
for(auto& n : chr_bank) n = 0;
|
||||
chrMode = 0;
|
||||
prgMode = 0;
|
||||
ramEnable = 0;
|
||||
bankSelect = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
mirror = 0;
|
||||
for(auto& n : ram_readable) n = 0;
|
||||
for(auto& n : ram_writable) n = 0;
|
||||
irq_latch = 0;
|
||||
irq_counter = 0;
|
||||
irq_enable = 0;
|
||||
irq_delay = 0;
|
||||
irq_line = 0;
|
||||
for(auto& n : ramReadable) n = 0;
|
||||
for(auto& n : ramWritable) n = 0;
|
||||
irqLatch = 0;
|
||||
irqCounter = 0;
|
||||
irqEnable = 0;
|
||||
irqDelay = 0;
|
||||
irqLine = 0;
|
||||
|
||||
chr_abus = 0;
|
||||
chrAbus = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(chr_mode);
|
||||
s.integer(prg_mode);
|
||||
s.integer(ram_enable);
|
||||
s.integer(bank_select);
|
||||
for(auto& n : prg_bank) s.integer(n);
|
||||
for(auto& n : chr_bank) s.integer(n);
|
||||
s.integer(chrMode);
|
||||
s.integer(prgMode);
|
||||
s.integer(ramEnable);
|
||||
s.integer(bankSelect);
|
||||
for(auto& n : prgBank) s.integer(n);
|
||||
for(auto& n : chrBank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
for(auto& n : ram_readable) s.integer(n);
|
||||
for(auto& n : ram_writable) s.integer(n);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_delay);
|
||||
s.integer(irq_line);
|
||||
for(auto& n : ramReadable) s.integer(n);
|
||||
for(auto& n : ramWritable) s.integer(n);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqDelay);
|
||||
s.integer(irqLine);
|
||||
|
||||
s.integer(chr_abus);
|
||||
s.integer(chrAbus);
|
||||
}
|
||||
|
||||
bool chr_mode;
|
||||
bool prg_mode;
|
||||
bool ram_enable;
|
||||
uint3 bank_select;
|
||||
uint8 prg_bank[2];
|
||||
uint8 chr_bank[6];
|
||||
bool chrMode;
|
||||
bool prgMode;
|
||||
bool ramEnable;
|
||||
uint3 bankSelect;
|
||||
uint8 prgBank[2];
|
||||
uint8 chrBank[6];
|
||||
bool mirror;
|
||||
bool ram_readable[2];
|
||||
bool ram_writable[2];
|
||||
uint8 irq_latch;
|
||||
uint8 irq_counter;
|
||||
bool irq_enable;
|
||||
uint irq_delay;
|
||||
bool irq_line;
|
||||
bool ramReadable[2];
|
||||
bool ramWritable[2];
|
||||
uint8 irqLatch;
|
||||
uint8 irqCounter;
|
||||
bool irqEnable;
|
||||
uint irqDelay;
|
||||
bool irqLine;
|
||||
|
||||
uint16 chr_abus;
|
||||
uint16 chrAbus;
|
||||
};
|
||||
|
|
|
@ -2,21 +2,21 @@ struct VRC1 : Chip {
|
|||
VRC1(Board& board) : Chip(board) {
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
uint bank = 0x0f;
|
||||
if((addr & 0xe000) == 0x8000) bank = prg_bank[0];
|
||||
if((addr & 0xe000) == 0xa000) bank = prg_bank[1];
|
||||
if((addr & 0xe000) == 0xc000) bank = prg_bank[2];
|
||||
if((addr & 0xe000) == 0x8000) bank = prgBank[0];
|
||||
if((addr & 0xe000) == 0xa000) bank = prgBank[1];
|
||||
if((addr & 0xe000) == 0xc000) bank = prgBank[2];
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
uint bank = chr_banklo[(bool)(addr & 0x1000)];
|
||||
bank |= chr_bankhi[(bool)(addr & 0x1000)] << 4;
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
uint bank = chrBankLo[(bool)(addr & 0x1000)];
|
||||
bank |= chrBankHi[(bool)(addr & 0x1000)] << 4;
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
|
@ -24,32 +24,32 @@ struct VRC1 : Chip {
|
|||
throw;
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr & 0xf000) {
|
||||
case 0x8000:
|
||||
prg_bank[0] = data & 0x0f;
|
||||
prgBank[0] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0x9000:
|
||||
chr_bankhi[1] = data & 0x04;
|
||||
chr_bankhi[0] = data & 0x02;
|
||||
chrBankHi[1] = data & 0x04;
|
||||
chrBankHi[0] = data & 0x02;
|
||||
mirror = data & 0x01;
|
||||
break;
|
||||
|
||||
case 0xa000:
|
||||
prg_bank[1] = data & 0x0f;
|
||||
prgBank[1] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
prg_bank[2] = data & 0x0f;
|
||||
prgBank[2] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
chr_banklo[0] = data & 0x0f;
|
||||
chrBankLo[0] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
chr_banklo[1] = data & 0x0f;
|
||||
chrBankLo[1] = data & 0x0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -58,21 +58,21 @@ struct VRC1 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
for(auto& n : chr_banklo) n = 0;
|
||||
for(auto& n : chr_bankhi) n = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
for(auto& n : chrBankLo) n = 0;
|
||||
for(auto& n : chrBankHi) n = 0;
|
||||
mirror = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
for(auto& n : prg_bank) s.integer(n);
|
||||
for(auto& n : chr_banklo) s.integer(n);
|
||||
for(auto& n : chr_bankhi) s.integer(n);
|
||||
for(auto& n : prgBank) s.integer(n);
|
||||
for(auto& n : chrBankLo) s.integer(n);
|
||||
for(auto& n : chrBankHi) s.integer(n);
|
||||
s.integer(mirror);
|
||||
}
|
||||
|
||||
uint4 prg_bank[3];
|
||||
uint4 chr_banklo[2];
|
||||
bool chr_bankhi[2];
|
||||
uint4 prgBank[3];
|
||||
uint4 chrBankLo[2];
|
||||
bool chrBankHi[2];
|
||||
bool mirror;
|
||||
};
|
||||
|
|
|
@ -2,23 +2,23 @@ struct VRC2 : Chip {
|
|||
VRC2(Board& board) : Chip(board) {
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
uint bank;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_bank[0]; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0x8000: bank = prgBank[0]; break;
|
||||
case 0xa000: bank = prgBank[1]; break;
|
||||
case 0xc000: bank = 0x1e; break;
|
||||
case 0xe000: bank = 0x1f; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
uint bank = chr_bank[addr / 0x0400];
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
uint bank = chrBank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
|
@ -28,7 +28,7 @@ struct VRC2 : Chip {
|
|||
throw;
|
||||
}
|
||||
|
||||
auto ram_read(uint addr) -> uint8 {
|
||||
auto readRAM(uint addr) -> uint8 {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch;
|
||||
return cpu.mdr();
|
||||
|
@ -36,7 +36,7 @@ struct VRC2 : Chip {
|
|||
return board.prgram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto ram_write(uint addr, uint8 data) -> void {
|
||||
auto writeRAM(uint addr, uint8 data) -> void {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) latch = data & 0x01;
|
||||
return;
|
||||
|
@ -44,10 +44,10 @@ struct VRC2 : Chip {
|
|||
return board.prgram.write(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
prg_bank[0] = data & 0x1f;
|
||||
prgBank[0] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x9000: case 0x9001: case 0x9002: case 0x9003:
|
||||
|
@ -55,32 +55,32 @@ struct VRC2 : Chip {
|
|||
break;
|
||||
|
||||
case 0xa000: case 0xa001: case 0xa002: case 0xa003:
|
||||
prg_bank[1] = data & 0x1f;
|
||||
prgBank[1] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb001: chrBank[0] = (chrBank[0] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb003: chrBank[1] = (chrBank[1] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc001: chrBank[2] = (chrBank[2] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc003: chrBank[3] = (chrBank[3] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd001: chrBank[4] = (chrBank[4] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd003: chrBank[5] = (chrBank[5] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe001: chrBank[6] = (chrBank[6] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,21 +88,21 @@ struct VRC2 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
for(auto& n : chr_bank) n = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
mirror = 0;
|
||||
latch = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
for(auto& n : prg_bank) s.integer(n);
|
||||
for(auto& n : chr_bank) s.integer(n);
|
||||
for(auto& n : prgBank) s.integer(n);
|
||||
for(auto& n : chrBank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
s.integer(latch);
|
||||
}
|
||||
|
||||
uint5 prg_bank[2];
|
||||
uint8 chr_bank[8];
|
||||
uint5 prgBank[2];
|
||||
uint8 chrBank[8];
|
||||
uint2 mirror;
|
||||
bool latch;
|
||||
};
|
||||
|
|
|
@ -3,53 +3,53 @@ struct VRC3 : Chip {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_enable) {
|
||||
if(irq_mode == 0) { //16-bit
|
||||
if(++irq_counter.w == 0) {
|
||||
irq_line = 1;
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_counter.w = irq_latch;
|
||||
if(irqEnable) {
|
||||
if(irqMode == 0) { //16-bit
|
||||
if(++irqCounter.w == 0) {
|
||||
irqLine = 1;
|
||||
irqEnable = irqAcknowledge;
|
||||
irqCounter.w = irqLatch;
|
||||
}
|
||||
}
|
||||
if(irq_mode == 1) { //8-bit
|
||||
if(++irq_counter.l == 0) {
|
||||
irq_line = 1;
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_counter.l = irq_latch;
|
||||
if(irqMode == 1) { //8-bit
|
||||
if(++irqCounter.l == 0) {
|
||||
irqLine = 1;
|
||||
irqEnable = irqAcknowledge;
|
||||
irqCounter.l = irqLatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu.irqLine(irq_line);
|
||||
cpu.irqLine(irqLine);
|
||||
tick();
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
uint bank = (addr < 0xc000 ? (uint)prg_bank : 0x0f);
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
uint bank = (addr < 0xc000 ? (uint)prgBank : 0x0f);
|
||||
return (bank * 0x4000) + (addr & 0x3fff);
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr & 0xf000) {
|
||||
case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) << 0); break;
|
||||
case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) << 8); break;
|
||||
case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break;
|
||||
case 0x8000: irqLatch = (irqLatch & 0xfff0) | ((data & 0x0f) << 0); break;
|
||||
case 0x9000: irqLatch = (irqLatch & 0xff0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xa000: irqLatch = (irqLatch & 0xf0ff) | ((data & 0x0f) << 8); break;
|
||||
case 0xb000: irqLatch = (irqLatch & 0x0fff) | ((data & 0x0f) << 12); break;
|
||||
|
||||
case 0xc000:
|
||||
irq_mode = data & 0x04;
|
||||
irq_enable = data & 0x02;
|
||||
irq_acknowledge = data & 0x01;
|
||||
if(irq_enable) irq_counter.w = irq_latch;
|
||||
irqMode = data & 0x04;
|
||||
irqEnable = data & 0x02;
|
||||
irqAcknowledge = data & 0x01;
|
||||
if(irqEnable) irqCounter.w = irqLatch;
|
||||
break;
|
||||
|
||||
case 0xd000:
|
||||
irq_line = 0;
|
||||
irq_enable = irq_acknowledge;
|
||||
irqLine = 0;
|
||||
irqEnable = irqAcknowledge;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
prg_bank = data & 0x0f;
|
||||
prgBank = data & 0x0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -58,35 +58,35 @@ struct VRC3 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank = 0;
|
||||
irq_mode = 0;
|
||||
irq_enable = 0;
|
||||
irq_acknowledge = 0;
|
||||
irq_latch = 0;
|
||||
irq_counter.w = 0;
|
||||
irq_line = 0;
|
||||
prgBank = 0;
|
||||
irqMode = 0;
|
||||
irqEnable = 0;
|
||||
irqAcknowledge = 0;
|
||||
irqLatch = 0;
|
||||
irqCounter.w = 0;
|
||||
irqLine = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(prg_bank);
|
||||
s.integer(irq_mode);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_acknowledge);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_counter.w);
|
||||
s.integer(irq_line);
|
||||
s.integer(prgBank);
|
||||
s.integer(irqMode);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqAcknowledge);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqCounter.w);
|
||||
s.integer(irqLine);
|
||||
}
|
||||
|
||||
uint4 prg_bank;
|
||||
bool irq_mode;
|
||||
bool irq_enable;
|
||||
bool irq_acknowledge;
|
||||
uint16 irq_latch;
|
||||
uint4 prgBank;
|
||||
bool irqMode;
|
||||
bool irqEnable;
|
||||
bool irqAcknowledge;
|
||||
uint16 irqLatch;
|
||||
struct {
|
||||
union {
|
||||
uint16_t w;
|
||||
struct { uint8_t order_lsb2(l, h); };
|
||||
};
|
||||
} irq_counter;
|
||||
bool irq_line;
|
||||
} irqCounter;
|
||||
bool irqLine;
|
||||
};
|
||||
|
|
|
@ -3,51 +3,51 @@ struct VRC4 : Chip {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_enable) {
|
||||
if(irq_mode == 0) {
|
||||
irq_scalar -= 3;
|
||||
if(irq_scalar <= 0) {
|
||||
irq_scalar += 341;
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqEnable) {
|
||||
if(irqMode == 0) {
|
||||
irqScalar -= 3;
|
||||
if(irqScalar <= 0) {
|
||||
irqScalar += 341;
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(irq_mode == 1) {
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqMode == 1) {
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu.irqLine(irq_line);
|
||||
cpu.irqLine(irqLine);
|
||||
tick();
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
uint bank = 0, banks = board.prgrom.size / 0x2000;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break;
|
||||
case 0x8000: bank = prgMode == 0 ? (uint)prgBank[0] : banks - 2; break;
|
||||
case 0xa000: bank = prgBank[1]; break;
|
||||
case 0xc000: bank = prgMode == 0 ? banks - 2 : (uint)prgBank[0]; break;
|
||||
case 0xe000: bank = banks - 1; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
uint bank = chr_bank[addr / 0x0400];
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
uint bank = chrBank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
|
@ -57,10 +57,10 @@ struct VRC4 : Chip {
|
|||
throw;
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
prg_bank[0] = data & 0x1f;
|
||||
prgBank[0] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x9000: case 0x9001:
|
||||
|
@ -68,59 +68,59 @@ struct VRC4 : Chip {
|
|||
break;
|
||||
|
||||
case 0x9002: case 0x9003:
|
||||
prg_mode = data & 0x02;
|
||||
prgMode = data & 0x02;
|
||||
break;
|
||||
|
||||
case 0xa000: case 0xa001: case 0xa002: case 0xa003:
|
||||
prg_bank[1] = data & 0x1f;
|
||||
prgBank[1] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb001: chrBank[0] = (chrBank[0] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb003: chrBank[1] = (chrBank[1] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc001: chrBank[2] = (chrBank[2] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc003: chrBank[3] = (chrBank[3] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd001: chrBank[4] = (chrBank[4] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd003: chrBank[5] = (chrBank[5] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe001: chrBank[6] = (chrBank[6] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xf000:
|
||||
irq_latch = (irq_latch & 0xf0) | ((data & 0x0f) << 0);
|
||||
irqLatch = (irqLatch & 0xf0) | ((data & 0x0f) << 0);
|
||||
break;
|
||||
|
||||
case 0xf001:
|
||||
irq_latch = (irq_latch & 0x0f) | ((data & 0x0f) << 4);
|
||||
irqLatch = (irqLatch & 0x0f) | ((data & 0x0f) << 4);
|
||||
break;
|
||||
|
||||
case 0xf002:
|
||||
irq_mode = data & 0x04;
|
||||
irq_enable = data & 0x02;
|
||||
irq_acknowledge = data & 0x01;
|
||||
if(irq_enable) {
|
||||
irq_counter = irq_latch;
|
||||
irq_scalar = 341;
|
||||
irqMode = data & 0x04;
|
||||
irqEnable = data & 0x02;
|
||||
irqAcknowledge = data & 0x01;
|
||||
if(irqEnable) {
|
||||
irqCounter = irqLatch;
|
||||
irqScalar = 341;
|
||||
}
|
||||
irq_line = 0;
|
||||
irqLine = 0;
|
||||
break;
|
||||
|
||||
case 0xf003:
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_line = 0;
|
||||
irqEnable = irqAcknowledge;
|
||||
irqLine = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -129,48 +129,48 @@ struct VRC4 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_mode = 0;
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
prgMode = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
mirror = 0;
|
||||
for(auto& n : chr_bank) n = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
|
||||
irq_latch = 0;
|
||||
irq_mode = 0;
|
||||
irq_enable = 0;
|
||||
irq_acknowledge = 0;
|
||||
irqLatch = 0;
|
||||
irqMode = 0;
|
||||
irqEnable = 0;
|
||||
irqAcknowledge = 0;
|
||||
|
||||
irq_counter = 0;
|
||||
irq_scalar = 0;
|
||||
irq_line = 0;
|
||||
irqCounter = 0;
|
||||
irqScalar = 0;
|
||||
irqLine = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(prg_mode);
|
||||
for(auto& n : prg_bank) s.integer(n);
|
||||
s.integer(prgMode);
|
||||
for(auto& n : prgBank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
for(auto& n : chr_bank) s.integer(n);
|
||||
for(auto& n : chrBank) s.integer(n);
|
||||
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_mode);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_acknowledge);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqMode);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqAcknowledge);
|
||||
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_scalar);
|
||||
s.integer(irq_line);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqScalar);
|
||||
s.integer(irqLine);
|
||||
}
|
||||
|
||||
bool prg_mode;
|
||||
uint5 prg_bank[2];
|
||||
bool prgMode;
|
||||
uint5 prgBank[2];
|
||||
uint2 mirror;
|
||||
uint8 chr_bank[8];
|
||||
uint8 chrBank[8];
|
||||
|
||||
uint8 irq_latch;
|
||||
bool irq_mode;
|
||||
bool irq_enable;
|
||||
bool irq_acknowledge;
|
||||
uint8 irqLatch;
|
||||
bool irqMode;
|
||||
bool irqEnable;
|
||||
bool irqAcknowledge;
|
||||
|
||||
uint8 irq_counter;
|
||||
int irq_scalar;
|
||||
bool irq_line;
|
||||
uint8 irqCounter;
|
||||
int irqScalar;
|
||||
bool irqLine;
|
||||
};
|
||||
|
|
|
@ -77,52 +77,52 @@ struct VRC6 : Chip {
|
|||
} sawtooth;
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_enable) {
|
||||
if(irq_mode == 0) {
|
||||
irq_scalar -= 3;
|
||||
if(irq_scalar <= 0) {
|
||||
irq_scalar += 341;
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqEnable) {
|
||||
if(irqMode == 0) {
|
||||
irqScalar -= 3;
|
||||
if(irqScalar <= 0) {
|
||||
irqScalar += 341;
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(irq_mode == 1) {
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqMode == 1) {
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
cpu.irqLine(irq_line);
|
||||
cpu.irqLine(irqLine);
|
||||
|
||||
pulse1.clock();
|
||||
pulse2.clock();
|
||||
sawtooth.clock();
|
||||
int output = (pulse1.output + pulse2.output + sawtooth.output) << 7;
|
||||
apu.set_sample(-output);
|
||||
apu.setSample(-output);
|
||||
|
||||
tick();
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
if((addr & 0xc000) == 0x8000) return (prg_bank[0] << 14) | (addr & 0x3fff);
|
||||
if((addr & 0xe000) == 0xc000) return (prg_bank[1] << 13) | (addr & 0x1fff);
|
||||
if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff);
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
if((addr & 0xc000) == 0x8000) return (prgBank[0] << 14) | (addr & 0x3fff);
|
||||
if((addr & 0xe000) == 0xc000) return (prgBank[1] << 13) | (addr & 0x1fff);
|
||||
if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
uint bank = chr_bank[(addr >> 10) & 7];
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
uint bank = chrBank[(addr >> 10) & 7];
|
||||
return (bank << 10) | (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
|
@ -131,18 +131,18 @@ struct VRC6 : Chip {
|
|||
}
|
||||
}
|
||||
|
||||
auto ram_read(uint addr) -> uint8 {
|
||||
auto readRAM(uint addr) -> uint8 {
|
||||
return board.prgram.data[addr & 0x1fff];
|
||||
}
|
||||
|
||||
auto ram_write(uint addr, uint8 data) -> void {
|
||||
auto writeRAM(uint addr, uint8 data) -> void {
|
||||
board.prgram.data[addr & 0x1fff] = data;
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
prg_bank[0] = data;
|
||||
prgBank[0] = data;
|
||||
break;
|
||||
|
||||
case 0x9000:
|
||||
|
@ -193,35 +193,35 @@ struct VRC6 : Chip {
|
|||
break;
|
||||
|
||||
case 0xc000: case 0xc001: case 0xc002: case 0xc003:
|
||||
prg_bank[1] = data;
|
||||
prgBank[1] = data;
|
||||
break;
|
||||
|
||||
case 0xd000: case 0xd001: case 0xd002: case 0xd003:
|
||||
chr_bank[0 + (addr & 3)] = data;
|
||||
chrBank[0 + (addr & 3)] = data;
|
||||
break;
|
||||
|
||||
case 0xe000: case 0xe001: case 0xe002: case 0xe003:
|
||||
chr_bank[4 + (addr & 3)] = data;
|
||||
chrBank[4 + (addr & 3)] = data;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
irq_latch = data;
|
||||
irqLatch = data;
|
||||
break;
|
||||
|
||||
case 0xf001:
|
||||
irq_mode = data & 0x04;
|
||||
irq_enable = data & 0x02;
|
||||
irq_acknowledge = data & 0x01;
|
||||
if(irq_enable) {
|
||||
irq_counter = irq_latch;
|
||||
irq_scalar = 341;
|
||||
irqMode = data & 0x04;
|
||||
irqEnable = data & 0x02;
|
||||
irqAcknowledge = data & 0x01;
|
||||
if(irqEnable) {
|
||||
irqCounter = irqLatch;
|
||||
irqScalar = 341;
|
||||
}
|
||||
irq_line = 0;
|
||||
irqLine = 0;
|
||||
break;
|
||||
|
||||
case 0xf002:
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_line = 0;
|
||||
irqEnable = irqAcknowledge;
|
||||
irqLine = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -230,25 +230,25 @@ struct VRC6 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
prg_bank[0] = 0;
|
||||
prg_bank[1] = 0;
|
||||
chr_bank[0] = 0;
|
||||
chr_bank[1] = 0;
|
||||
chr_bank[2] = 0;
|
||||
chr_bank[3] = 0;
|
||||
chr_bank[4] = 0;
|
||||
chr_bank[5] = 0;
|
||||
chr_bank[6] = 0;
|
||||
chr_bank[7] = 0;
|
||||
prgBank[0] = 0;
|
||||
prgBank[1] = 0;
|
||||
chrBank[0] = 0;
|
||||
chrBank[1] = 0;
|
||||
chrBank[2] = 0;
|
||||
chrBank[3] = 0;
|
||||
chrBank[4] = 0;
|
||||
chrBank[5] = 0;
|
||||
chrBank[6] = 0;
|
||||
chrBank[7] = 0;
|
||||
mirror = 0;
|
||||
irq_latch = 0;
|
||||
irq_mode = 0;
|
||||
irq_enable = 0;
|
||||
irq_acknowledge = 0;
|
||||
irqLatch = 0;
|
||||
irqMode = 0;
|
||||
irqEnable = 0;
|
||||
irqAcknowledge = 0;
|
||||
|
||||
irq_counter = 0;
|
||||
irq_scalar = 0;
|
||||
irq_line = 0;
|
||||
irqCounter = 0;
|
||||
irqScalar = 0;
|
||||
irqLine = 0;
|
||||
|
||||
pulse1.mode = 0;
|
||||
pulse1.duty = 0;
|
||||
|
@ -286,28 +286,28 @@ struct VRC6 : Chip {
|
|||
pulse2.serialize(s);
|
||||
sawtooth.serialize(s);
|
||||
|
||||
s.array(prg_bank);
|
||||
s.array(chr_bank);
|
||||
s.array(prgBank);
|
||||
s.array(chrBank);
|
||||
s.integer(mirror);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_mode);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_acknowledge);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqMode);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqAcknowledge);
|
||||
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_scalar);
|
||||
s.integer(irq_line);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqScalar);
|
||||
s.integer(irqLine);
|
||||
}
|
||||
|
||||
uint8 prg_bank[2];
|
||||
uint8 chr_bank[8];
|
||||
uint8 prgBank[2];
|
||||
uint8 chrBank[8];
|
||||
uint2 mirror;
|
||||
uint8 irq_latch;
|
||||
bool irq_mode;
|
||||
bool irq_enable;
|
||||
bool irq_acknowledge;
|
||||
uint8 irqLatch;
|
||||
bool irqMode;
|
||||
bool irqEnable;
|
||||
bool irqAcknowledge;
|
||||
|
||||
uint8 irq_counter;
|
||||
int irq_scalar;
|
||||
bool irq_line;
|
||||
uint8 irqCounter;
|
||||
int irqScalar;
|
||||
bool irqLine;
|
||||
};
|
||||
|
|
|
@ -6,90 +6,90 @@ struct VRC7 : Chip {
|
|||
}
|
||||
|
||||
auto main() -> void {
|
||||
if(irq_enable) {
|
||||
if(irq_mode == 0) {
|
||||
irq_scalar -= 3;
|
||||
if(irq_scalar <= 0) {
|
||||
irq_scalar += 341;
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqEnable) {
|
||||
if(irqMode == 0) {
|
||||
irqScalar -= 3;
|
||||
if(irqScalar <= 0) {
|
||||
irqScalar += 341;
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(irq_mode == 1) {
|
||||
if(irq_counter == 0xff) {
|
||||
irq_counter = irq_latch;
|
||||
irq_line = 1;
|
||||
if(irqMode == 1) {
|
||||
if(irqCounter == 0xff) {
|
||||
irqCounter = irqLatch;
|
||||
irqLine = 1;
|
||||
} else {
|
||||
irq_counter++;
|
||||
irqCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
cpu.irqLine(irq_line);
|
||||
cpu.irqLine(irqLine);
|
||||
|
||||
tick();
|
||||
}
|
||||
|
||||
auto reg_write(uint addr, uint8 data) -> void {
|
||||
auto writeIO(uint addr, uint8 data) -> void {
|
||||
switch(addr) {
|
||||
case 0x8000: prg_bank[0] = data; break;
|
||||
case 0x8010: prg_bank[1] = data; break;
|
||||
case 0x9000: prg_bank[2] = data; break;
|
||||
case 0x8000: prgBank[0] = data; break;
|
||||
case 0x8010: prgBank[1] = data; break;
|
||||
case 0x9000: prgBank[2] = data; break;
|
||||
case 0x9010: break; //APU addr port
|
||||
case 0x9030: break; //APU data port
|
||||
case 0xa000: chr_bank[0] = data; break;
|
||||
case 0xa010: chr_bank[1] = data; break;
|
||||
case 0xb000: chr_bank[2] = data; break;
|
||||
case 0xb010: chr_bank[3] = data; break;
|
||||
case 0xc000: chr_bank[4] = data; break;
|
||||
case 0xc010: chr_bank[5] = data; break;
|
||||
case 0xd000: chr_bank[6] = data; break;
|
||||
case 0xd010: chr_bank[7] = data; break;
|
||||
case 0xa000: chrBank[0] = data; break;
|
||||
case 0xa010: chrBank[1] = data; break;
|
||||
case 0xb000: chrBank[2] = data; break;
|
||||
case 0xb010: chrBank[3] = data; break;
|
||||
case 0xc000: chrBank[4] = data; break;
|
||||
case 0xc010: chrBank[5] = data; break;
|
||||
case 0xd000: chrBank[6] = data; break;
|
||||
case 0xd010: chrBank[7] = data; break;
|
||||
case 0xe000: mirror = data & 0x03; break;
|
||||
|
||||
case 0xe010:
|
||||
irq_latch = data;
|
||||
irqLatch = data;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
irq_mode = data & 0x04;
|
||||
irq_enable = data & 0x02;
|
||||
irq_acknowledge = data & 0x01;
|
||||
if(irq_enable) {
|
||||
irq_counter = irq_latch;
|
||||
irq_scalar = 341;
|
||||
irqMode = data & 0x04;
|
||||
irqEnable = data & 0x02;
|
||||
irqAcknowledge = data & 0x01;
|
||||
if(irqEnable) {
|
||||
irqCounter = irqLatch;
|
||||
irqScalar = 341;
|
||||
}
|
||||
irq_line = 0;
|
||||
irqLine = 0;
|
||||
break;
|
||||
|
||||
case 0xf010:
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_line = 0;
|
||||
irqEnable = irqAcknowledge;
|
||||
irqLine = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto prg_addr(uint addr) const -> uint {
|
||||
auto addrPRG(uint addr) const -> uint {
|
||||
uint bank = 0;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_bank[0]; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = prg_bank[2]; break;
|
||||
case 0x8000: bank = prgBank[0]; break;
|
||||
case 0xa000: bank = prgBank[1]; break;
|
||||
case 0xc000: bank = prgBank[2]; break;
|
||||
case 0xe000: bank = 0xff; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
auto chr_addr(uint addr) const -> uint {
|
||||
uint bank = chr_bank[addr / 0x0400];
|
||||
auto addrCHR(uint addr) const -> uint {
|
||||
uint bank = chrBank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
auto ciram_addr(uint addr) const -> uint {
|
||||
auto addrCIRAM(uint addr) const -> uint {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
|
@ -102,45 +102,45 @@ struct VRC7 : Chip {
|
|||
}
|
||||
|
||||
auto reset() -> void {
|
||||
for(auto& n : prg_bank) n = 0;
|
||||
for(auto& n : chr_bank) n = 0;
|
||||
for(auto& n : prgBank) n = 0;
|
||||
for(auto& n : chrBank) n = 0;
|
||||
mirror = 0;
|
||||
|
||||
irq_latch = 0;
|
||||
irq_mode = 0;
|
||||
irq_enable = 0;
|
||||
irq_acknowledge = 0;
|
||||
irqLatch = 0;
|
||||
irqMode = 0;
|
||||
irqEnable = 0;
|
||||
irqAcknowledge = 0;
|
||||
|
||||
irq_counter = 0;
|
||||
irq_scalar = 0;
|
||||
irq_line = 0;
|
||||
irqCounter = 0;
|
||||
irqScalar = 0;
|
||||
irqLine = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.array(prg_bank);
|
||||
s.array(chr_bank);
|
||||
s.array(prgBank);
|
||||
s.array(chrBank);
|
||||
s.integer(mirror);
|
||||
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_mode);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_acknowledge);
|
||||
s.integer(irqLatch);
|
||||
s.integer(irqMode);
|
||||
s.integer(irqEnable);
|
||||
s.integer(irqAcknowledge);
|
||||
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_scalar);
|
||||
s.integer(irq_line);
|
||||
s.integer(irqCounter);
|
||||
s.integer(irqScalar);
|
||||
s.integer(irqLine);
|
||||
}
|
||||
|
||||
uint8 prg_bank[3];
|
||||
uint8 chr_bank[8];
|
||||
uint8 prgBank[3];
|
||||
uint8 chrBank[8];
|
||||
uint2 mirror;
|
||||
|
||||
uint8 irq_latch;
|
||||
bool irq_mode;
|
||||
bool irq_enable;
|
||||
bool irq_acknowledge;
|
||||
uint8 irqLatch;
|
||||
bool irqMode;
|
||||
bool irqEnable;
|
||||
bool irqAcknowledge;
|
||||
|
||||
uint8 irq_counter;
|
||||
int irq_scalar;
|
||||
bool irq_line;
|
||||
uint8 irqCounter;
|
||||
int irqScalar;
|
||||
bool irqLine;
|
||||
};
|
||||
|
|
|
@ -21,23 +21,29 @@ auto PPU::writeCGRAM(uint5 addr, uint8 data) -> void {
|
|||
auto PPU::readIO(uint16 addr) -> uint8 {
|
||||
uint8 result = 0x00;
|
||||
|
||||
switch(addr & 7) {
|
||||
case 2: //PPUSTATUS
|
||||
result |= r.nmiFlag << 7;
|
||||
result |= r.spriteZeroHit << 6;
|
||||
switch(addr.bits(0,2)) {
|
||||
|
||||
//PPUSTATUS
|
||||
case 2:
|
||||
result |= r.mdr.bits(0,4);
|
||||
result |= r.spriteOverflow << 5;
|
||||
result |= r.mdr & 0x1f;
|
||||
r.addressLatch = 0;
|
||||
result |= r.spriteZeroHit << 6;
|
||||
result |= r.nmiFlag << 7;
|
||||
r.v.latch = 0;
|
||||
r.nmiHold = 0;
|
||||
cpu.nmiLine(r.nmiFlag = 0);
|
||||
break;
|
||||
case 4: //OAMDATA
|
||||
|
||||
//OAMDATA
|
||||
case 4:
|
||||
result = oam[r.oamAddress];
|
||||
break;
|
||||
case 7: //PPUDATA
|
||||
|
||||
//PPUDATA
|
||||
case 7:
|
||||
if(enable() && (r.ly <= 240 || r.ly == 261)) return 0x00;
|
||||
|
||||
addr = r.vaddr & 0x3fff;
|
||||
addr = (uint14)r.v.address;
|
||||
if(addr <= 0x1fff) {
|
||||
result = r.busData;
|
||||
r.busData = cartridge.readCHR(addr);
|
||||
|
@ -48,8 +54,9 @@ auto PPU::readIO(uint16 addr) -> uint8 {
|
|||
result = readCGRAM(addr);
|
||||
r.busData = cartridge.readCHR(addr);
|
||||
}
|
||||
r.vaddr += r.vramIncrement;
|
||||
r.v.address += r.vramIncrement;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -58,56 +65,73 @@ auto PPU::readIO(uint16 addr) -> uint8 {
|
|||
auto PPU::writeIO(uint16 addr, uint8 data) -> void {
|
||||
r.mdr = data;
|
||||
|
||||
switch(addr & 7) {
|
||||
case 0: //PPUCTRL
|
||||
r.nmiEnable = data & 0x80;
|
||||
r.masterSelect = data & 0x40;
|
||||
r.spriteHeight = data & 0x20 ? 16 : 8;
|
||||
r.bgAddress = (data & 0x10) ? 0x1000 : 0x0000;
|
||||
r.spriteAddress = (data & 0x08) ? 0x1000 : 0x0000;
|
||||
r.vramIncrement = (data & 0x04) ? 32 : 1;
|
||||
r.taddr = (r.taddr & 0x73ff) | ((data & 0x03) << 10);
|
||||
switch(addr.bits(0,2)) {
|
||||
|
||||
//PPUCTRL
|
||||
case 0:
|
||||
r.t.nametable = data.bits(0,1);
|
||||
r.vramIncrement = data.bit (2) ? 32 : 1;
|
||||
r.spriteAddress = data.bit (3) ? 0x1000 : 0x0000;
|
||||
r.bgAddress = data.bit (4) ? 0x1000 : 0x0000;
|
||||
r.spriteHeight = data.bit (5) ? 16 : 8;
|
||||
r.masterSelect = data.bit (6);
|
||||
r.nmiEnable = data.bit (7);
|
||||
cpu.nmiLine(r.nmiEnable && r.nmiHold && r.nmiFlag);
|
||||
return;
|
||||
case 1: //PPUMASK
|
||||
r.emphasis = data >> 5;
|
||||
r.spriteEnable = data & 0x10;
|
||||
r.bgEnable = data & 0x08;
|
||||
r.spriteEdgeEnable = data & 0x04;
|
||||
r.bgEdgeEnable = data & 0x02;
|
||||
r.grayscale = data & 0x01;
|
||||
return;
|
||||
case 2: //PPUSTATUS
|
||||
return;
|
||||
case 3: //OAMADDR
|
||||
break;
|
||||
|
||||
//PPUMASK
|
||||
case 1:
|
||||
r.grayscale = data.bit (0);
|
||||
r.bgEdgeEnable = data.bit (1);
|
||||
r.spriteEdgeEnable = data.bit (2);
|
||||
r.bgEnable = data.bit (3);
|
||||
r.spriteEnable = data.bit (4);
|
||||
r.emphasis = data.bits(5,7);
|
||||
break;
|
||||
|
||||
//PPUSTATUS
|
||||
case 2:
|
||||
break;
|
||||
|
||||
//OAMADDR
|
||||
case 3:
|
||||
r.oamAddress = data;
|
||||
return;
|
||||
case 4: //OAMDATA
|
||||
break;
|
||||
|
||||
//OAMDATA
|
||||
case 4:
|
||||
if(r.oamAddress.bits(0,1) == 2) data.bits(2,4) = 0; //clear non-existent bits (always read back as 0)
|
||||
oam[r.oamAddress++] = data;
|
||||
return;
|
||||
case 5: //PPUSCROLL
|
||||
if(r.addressLatch == 0) {
|
||||
r.xaddr = data & 0x07;
|
||||
r.taddr = (r.taddr & 0x7fe0) | (data >> 3);
|
||||
break;
|
||||
|
||||
//PPUSCROLL
|
||||
case 5:
|
||||
if(!r.v.latch) {
|
||||
r.v.fineX = data.bits(0,2);
|
||||
r.t.tileX = data.bits(3,7);
|
||||
} else {
|
||||
r.taddr = (r.taddr & 0x0c1f) | ((data & 0x07) << 12) | ((data >> 3) << 5);
|
||||
r.t.fineY = data.bits(0,2);
|
||||
r.t.tileY = data.bits(3,7);
|
||||
}
|
||||
r.addressLatch ^= 1;
|
||||
return;
|
||||
case 6: //PPUADDR
|
||||
if(r.addressLatch == 0) {
|
||||
r.taddr = (r.taddr & 0x00ff) | ((data & 0x3f) << 8);
|
||||
r.v.latch ^= 1;
|
||||
break;
|
||||
|
||||
//PPUADDR
|
||||
case 6:
|
||||
if(!r.v.latch) {
|
||||
r.t.addressHi = data.bits(0,5);
|
||||
} else {
|
||||
r.taddr = (r.taddr & 0x7f00) | data;
|
||||
r.vaddr = r.taddr;
|
||||
r.t.addressLo = data.bits(0,7);
|
||||
r.v.address = r.t.address;
|
||||
}
|
||||
r.addressLatch ^= 1;
|
||||
return;
|
||||
case 7: //PPUDATA
|
||||
r.v.latch ^= 1;
|
||||
break;
|
||||
|
||||
//PPUDATA
|
||||
case 7:
|
||||
if(enable() && (r.ly <= 240 || r.ly == 261)) return;
|
||||
|
||||
addr = r.vaddr & 0x3fff;
|
||||
addr = (uint14)r.v.address;
|
||||
if(addr <= 0x1fff) {
|
||||
cartridge.writeCHR(addr, data);
|
||||
} else if(addr <= 0x3eff) {
|
||||
|
@ -115,7 +139,8 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
|
|||
} else if(addr <= 0x3fff) {
|
||||
writeCGRAM(addr, data);
|
||||
}
|
||||
r.vaddr += r.vramIncrement;
|
||||
return;
|
||||
r.v.address += r.vramIncrement;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,21 +15,23 @@ auto PPU::main() -> void {
|
|||
renderScanline();
|
||||
}
|
||||
|
||||
auto PPU::tick() -> void {
|
||||
if(r.ly == 240 && r.lx == 340) r.nmiHold = 1;
|
||||
if(r.ly == 241 && r.lx == 0) r.nmiFlag = r.nmiHold;
|
||||
if(r.ly == 241 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag);
|
||||
auto PPU::step(uint clocks) -> void {
|
||||
while(clocks--) {
|
||||
if(r.ly == 240 && r.lx == 340) r.nmiHold = 1;
|
||||
if(r.ly == 241 && r.lx == 0) r.nmiFlag = r.nmiHold;
|
||||
if(r.ly == 241 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag);
|
||||
|
||||
if(r.ly == 260 && r.lx == 340) r.spriteZeroHit = 0, r.spriteOverflow = 0;
|
||||
if(r.ly == 260 && r.lx == 340) r.spriteZeroHit = 0, r.spriteOverflow = 0;
|
||||
|
||||
if(r.ly == 260 && r.lx == 340) r.nmiHold = 0;
|
||||
if(r.ly == 261 && r.lx == 0) r.nmiFlag = r.nmiHold;
|
||||
if(r.ly == 261 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag);
|
||||
if(r.ly == 260 && r.lx == 340) r.nmiHold = 0;
|
||||
if(r.ly == 261 && r.lx == 0) r.nmiFlag = r.nmiHold;
|
||||
if(r.ly == 261 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag);
|
||||
|
||||
clock += 4;
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
clock += 4;
|
||||
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
|
||||
|
||||
r.lx++;
|
||||
r.lx++;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::scanline() -> void {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
struct PPU : Thread {
|
||||
static auto Enter() -> void;
|
||||
auto main() -> void;
|
||||
auto tick() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto scanline() -> void;
|
||||
auto frame() -> void;
|
||||
|
@ -22,15 +22,8 @@ struct PPU : Thread {
|
|||
|
||||
//render.cpp
|
||||
auto enable() const -> bool;
|
||||
auto nametableAddress() const -> uint;
|
||||
auto scrollX() const -> uint;
|
||||
auto scrollY() const -> uint;
|
||||
|
||||
auto loadCHR(uint16 addr) -> uint8;
|
||||
|
||||
auto scrollX_increment() -> void;
|
||||
auto scrollY_increment() -> void;
|
||||
|
||||
auto renderPixel() -> void;
|
||||
auto renderSprite() -> void;
|
||||
auto renderScanline() -> void;
|
||||
|
@ -48,34 +41,43 @@ struct PPU : Thread {
|
|||
|
||||
uint8 busData;
|
||||
|
||||
bool addressLatch;
|
||||
|
||||
uint15 vaddr;
|
||||
uint15 taddr;
|
||||
uint8 xaddr;
|
||||
union {
|
||||
uint value;
|
||||
BitField<uint, 0, 4> tileX;
|
||||
BitField<uint, 5, 9> tileY;
|
||||
BitField<uint,10,11> nametable;
|
||||
BitField<uint, 10> nametableX;
|
||||
BitField<uint, 11> nametableY;
|
||||
BitField<uint,12,14> fineY;
|
||||
BitField<uint, 0,14> address;
|
||||
BitField<uint, 0, 7> addressLo;
|
||||
BitField<uint, 8,14> addressHi;
|
||||
BitField<uint, 15> latch;
|
||||
BitField<uint,16,18> fineX;
|
||||
} v, t;
|
||||
|
||||
bool nmiHold;
|
||||
bool nmiFlag;
|
||||
|
||||
//$2000
|
||||
bool nmiEnable;
|
||||
bool masterSelect;
|
||||
uint spriteHeight;
|
||||
uint bgAddress;
|
||||
uint spriteAddress;
|
||||
uint vramIncrement;
|
||||
uint spriteAddress;
|
||||
uint bgAddress;
|
||||
uint spriteHeight;
|
||||
bool masterSelect;
|
||||
bool nmiEnable;
|
||||
|
||||
//$2001
|
||||
uint3 emphasis;
|
||||
bool spriteEnable;
|
||||
bool bgEnable;
|
||||
bool spriteEdgeEnable;
|
||||
bool bgEdgeEnable;
|
||||
bool grayscale;
|
||||
bool bgEdgeEnable;
|
||||
bool spriteEdgeEnable;
|
||||
bool bgEnable;
|
||||
bool spriteEnable;
|
||||
uint3 emphasis;
|
||||
|
||||
//$2002
|
||||
bool spriteZeroHit;
|
||||
bool spriteOverflow;
|
||||
bool spriteZeroHit;
|
||||
|
||||
//$2003
|
||||
uint8 oamAddress;
|
||||
|
|
|
@ -1,66 +1,22 @@
|
|||
//vaddr = 0yyy VHYY YYYX XXXX
|
||||
//yyy = fine Yscroll (y:d0-d2)
|
||||
//V = V nametable (y:d8)
|
||||
//H = H nametable (x:d8)
|
||||
//YYYYY = Y nametable (y:d3-d7)
|
||||
//XXXXX = X nametable (x:d3-d7)
|
||||
|
||||
auto PPU::enable() const -> bool {
|
||||
return r.bgEnable || r.spriteEnable;
|
||||
}
|
||||
|
||||
auto PPU::nametableAddress() const -> uint {
|
||||
return 0x2000 + (r.vaddr & 0x0c00);
|
||||
}
|
||||
|
||||
auto PPU::scrollX() const -> uint {
|
||||
return ((r.vaddr & 0x1f) << 3) | r.xaddr;
|
||||
}
|
||||
|
||||
auto PPU::scrollY() const -> uint {
|
||||
return (((r.vaddr >> 5) & 0x1f) << 3) | ((r.vaddr >> 12) & 7);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto PPU::loadCHR(uint16 addr) -> uint8 {
|
||||
if(!enable()) return 0x00;
|
||||
return cartridge.readCHR(addr);
|
||||
return enable() ? cartridge.readCHR(addr) : (uint8)0x00;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto PPU::scrollX_increment() -> void {
|
||||
if(!enable()) return;
|
||||
r.vaddr = (r.vaddr & 0x7fe0) | ((r.vaddr + 0x0001) & 0x001f);
|
||||
if((r.vaddr & 0x001f) == 0x0000) {
|
||||
r.vaddr ^= 0x0400;
|
||||
}
|
||||
}
|
||||
|
||||
auto PPU::scrollY_increment() -> void {
|
||||
if(!enable()) return;
|
||||
r.vaddr = (r.vaddr & 0x0fff) | ((r.vaddr + 0x1000) & 0x7000);
|
||||
if((r.vaddr & 0x7000) == 0x0000) {
|
||||
r.vaddr = (r.vaddr & 0x7c1f) | ((r.vaddr + 0x0020) & 0x03e0);
|
||||
if((r.vaddr & 0x03e0) == 0x03c0) { //0x03c0 == 30 << 5; 30 * 8 = 240
|
||||
r.vaddr &= 0x7c1f;
|
||||
r.vaddr ^= 0x0800;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto PPU::renderPixel() -> void {
|
||||
uint32* output = buffer + r.ly * 256;
|
||||
|
||||
uint mask = 0x8000 >> (r.xaddr + (r.lx & 7));
|
||||
uint x = r.lx - 1;
|
||||
uint mask = 0x8000 >> (r.v.fineX + (x & 7));
|
||||
uint palette = 0;
|
||||
uint objectPalette = 0;
|
||||
bool objectPriority = 0;
|
||||
palette |= (l.tiledataLo & mask) ? 1 : 0;
|
||||
palette |= (l.tiledataHi & mask) ? 2 : 0;
|
||||
|
||||
palette |= l.tiledataLo & mask ? 1 : 0;
|
||||
palette |= l.tiledataHi & mask ? 2 : 0;
|
||||
if(palette) {
|
||||
uint attr = l.attribute;
|
||||
if(mask >= 256) attr >>= 2;
|
||||
|
@ -68,24 +24,24 @@ auto PPU::renderPixel() -> void {
|
|||
}
|
||||
|
||||
if(!r.bgEnable) palette = 0;
|
||||
if(!r.bgEdgeEnable && r.lx < 8) palette = 0;
|
||||
if(!r.bgEdgeEnable && x < 8) palette = 0;
|
||||
|
||||
if(r.spriteEnable)
|
||||
for(int sprite = 7; sprite >= 0; sprite--) {
|
||||
if(!r.spriteEdgeEnable && r.lx < 8) continue;
|
||||
if(!r.spriteEdgeEnable && x < 8) continue;
|
||||
if(l.oam[sprite].id == 64) continue;
|
||||
|
||||
uint spriteX = r.lx - l.oam[sprite].x;
|
||||
uint spriteX = x - l.oam[sprite].x;
|
||||
if(spriteX >= 8) continue;
|
||||
|
||||
if(l.oam[sprite].attr & 0x40) spriteX ^= 7;
|
||||
uint mask = 0x80 >> spriteX;
|
||||
uint spritePalette = 0;
|
||||
spritePalette |= (l.oam[sprite].tiledataLo & mask) ? 1 : 0;
|
||||
spritePalette |= (l.oam[sprite].tiledataHi & mask) ? 2 : 0;
|
||||
spritePalette |= l.oam[sprite].tiledataLo & mask ? 1 : 0;
|
||||
spritePalette |= l.oam[sprite].tiledataHi & mask ? 2 : 0;
|
||||
if(spritePalette == 0) continue;
|
||||
|
||||
if(l.oam[sprite].id == 0 && palette && r.lx != 255) r.spriteZeroHit = 1;
|
||||
if(l.oam[sprite].id == 0 && palette && x != 255) r.spriteZeroHit = 1;
|
||||
spritePalette |= (l.oam[sprite].attr & 3) << 2;
|
||||
|
||||
objectPriority = l.oam[sprite].attr & 0x20;
|
||||
|
@ -97,15 +53,15 @@ auto PPU::renderPixel() -> void {
|
|||
}
|
||||
|
||||
if(!enable()) palette = 0;
|
||||
output[r.lx] = r.emphasis << 6 | readCGRAM(palette);
|
||||
output[x] = r.emphasis << 6 | readCGRAM(palette);
|
||||
}
|
||||
|
||||
auto PPU::renderSprite() -> void {
|
||||
if(!enable()) return;
|
||||
|
||||
uint n = l.oamIterator++;
|
||||
int ly = (r.ly == 261 ? -1 : r.ly);
|
||||
uint y = ly - oam[(n * 4) + 0];
|
||||
int ly = r.ly == 261 ? -1 : r.ly;
|
||||
uint y = ly - oam[n * 4 + 0];
|
||||
|
||||
if(y >= r.spriteHeight) return;
|
||||
if(l.oamCounter == 8) {
|
||||
|
@ -115,58 +71,60 @@ auto PPU::renderSprite() -> void {
|
|||
|
||||
auto& o = l.soam[l.oamCounter++];
|
||||
o.id = n;
|
||||
o.y = oam[(n * 4) + 0];
|
||||
o.tile = oam[(n * 4) + 1];
|
||||
o.attr = oam[(n * 4) + 2];
|
||||
o.x = oam[(n * 4) + 3];
|
||||
o.y = oam[n * 4 + 0];
|
||||
o.tile = oam[n * 4 + 1];
|
||||
o.attr = oam[n * 4 + 2];
|
||||
o.x = oam[n * 4 + 3];
|
||||
}
|
||||
|
||||
auto PPU::renderScanline() -> void {
|
||||
if(r.ly >= 240 && r.ly <= 260) {
|
||||
for(auto x : range(341)) tick();
|
||||
return scanline();
|
||||
}
|
||||
//Vblank
|
||||
if(r.ly >= 240 && r.ly <= 260) return step(341), scanline();
|
||||
|
||||
l.oamIterator = 0;
|
||||
l.oamCounter = 0;
|
||||
|
||||
for(auto n : range(8)) l.soam[n] = {};
|
||||
|
||||
for(uint tile : range(32)) { // 0-255
|
||||
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff));
|
||||
uint tileaddr = r.bgAddress + (nametable << 4) + (scrollY() & 7);
|
||||
// 0
|
||||
step(1);
|
||||
|
||||
// 1-256
|
||||
for(uint tile : range(32)) {
|
||||
uint nametable = loadCHR(0x2000 | (uint12)r.v.address);
|
||||
uint tileaddr = r.bgAddress | nametable << 4 | r.v.fineY;
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
uint attribute = loadCHR(0x23c0 | (r.vaddr & 0x0fc0) | ((scrollY() >> 5) << 3) | (scrollX() >> 5));
|
||||
if(scrollY() & 16) attribute >>= 4;
|
||||
if(scrollX() & 16) attribute >>= 2;
|
||||
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
|
||||
if(r.v.tileY & 2) attribute >>= 4;
|
||||
if(r.v.tileX & 2) attribute >>= 2;
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
scrollX_increment();
|
||||
if(tile == 31) scrollY_increment();
|
||||
if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
|
||||
if(enable() && tile == 31 && ++r.v.fineY == 0 && ++r.v.tileY == 30) r.v.nametableY ^= 1, r.v.tileY = 0;
|
||||
renderPixel();
|
||||
renderSprite();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
uint tiledataLo = loadCHR(tileaddr + 0);
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
uint tiledataHi = loadCHR(tileaddr + 8);
|
||||
renderPixel();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
renderPixel();
|
||||
renderSprite();
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
l.nametable = l.nametable << 8 | nametable;
|
||||
l.attribute = l.attribute << 2 | (attribute & 3);
|
||||
|
@ -176,56 +134,59 @@ auto PPU::renderScanline() -> void {
|
|||
|
||||
for(auto n : range(8)) l.oam[n] = l.soam[n];
|
||||
|
||||
for(uint sprite : range(8)) { //256-319
|
||||
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff));
|
||||
tick();
|
||||
//257-320
|
||||
for(uint sprite : range(8)) {
|
||||
uint nametable = loadCHR(0x2000 | (uint12)r.v.address);
|
||||
step(1);
|
||||
|
||||
if(enable() && sprite == 0) r.vaddr = (r.vaddr & 0x7be0) | (r.taddr & 0x041f); //257
|
||||
tick();
|
||||
if(enable() && sprite == 0) {
|
||||
//258
|
||||
r.v.nametableX = r.t.nametableX;
|
||||
r.v.tileX = r.t.tileX;
|
||||
}
|
||||
step(1);
|
||||
|
||||
uint attribute = loadCHR(0x23c0 | (r.vaddr & 0x0fc0) | ((scrollY() >> 5) << 3) | (scrollX() >> 5));
|
||||
uint tileaddr = (r.spriteHeight == 8)
|
||||
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
|
||||
uint tileaddr = r.spriteHeight == 8
|
||||
? r.spriteAddress + l.oam[sprite].tile * 16
|
||||
: ((l.oam[sprite].tile & ~1) * 16) + ((l.oam[sprite].tile & 1) * 0x1000);
|
||||
tick();
|
||||
tick();
|
||||
: (l.oam[sprite].tile & ~1) * 16 + (l.oam[sprite].tile & 1) * 0x1000;
|
||||
step(2);
|
||||
|
||||
uint spriteY = (r.ly - l.oam[sprite].y) & (r.spriteHeight - 1);
|
||||
if(l.oam[sprite].attr & 0x80) spriteY ^= (r.spriteHeight - 1);
|
||||
if(l.oam[sprite].attr & 0x80) spriteY ^= r.spriteHeight - 1;
|
||||
tileaddr += spriteY + (spriteY & 8);
|
||||
|
||||
l.oam[sprite].tiledataLo = loadCHR(tileaddr + 0);
|
||||
tick();
|
||||
tick();
|
||||
step(2);
|
||||
|
||||
l.oam[sprite].tiledataHi = loadCHR(tileaddr + 8);
|
||||
tick();
|
||||
tick();
|
||||
step(2);
|
||||
|
||||
if(enable() && sprite == 6 && r.ly == 261) r.vaddr = r.taddr; //304
|
||||
if(enable() && sprite == 6 && r.ly == 261) {
|
||||
//305
|
||||
r.v.address = r.t.address;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint tile : range(2)) { //320-335
|
||||
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff));
|
||||
uint tileaddr = r.bgAddress + (nametable << 4) + (scrollY() & 7);
|
||||
tick();
|
||||
tick();
|
||||
//321-336
|
||||
for(uint tile : range(2)) {
|
||||
uint nametable = loadCHR(0x2000 | (uint12)r.v.address);
|
||||
uint tileaddr = r.bgAddress | nametable << 4 | r.v.fineY;
|
||||
step(2);
|
||||
|
||||
uint attribute = loadCHR(0x23c0 | (r.vaddr & 0x0fc0) | ((scrollY() >> 5) << 3) | (scrollX() >> 5));
|
||||
if(scrollY() & 16) attribute >>= 4;
|
||||
if(scrollX() & 16) attribute >>= 2;
|
||||
tick();
|
||||
uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
|
||||
if(r.v.tileY & 2) attribute >>= 4;
|
||||
if(r.v.tileX & 2) attribute >>= 2;
|
||||
step(1);
|
||||
|
||||
scrollX_increment();
|
||||
tick();
|
||||
if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
|
||||
step(1);
|
||||
|
||||
uint tiledataLo = loadCHR(tileaddr + 0);
|
||||
tick();
|
||||
tick();
|
||||
step(2);
|
||||
|
||||
uint tiledataHi = loadCHR(tileaddr + 8);
|
||||
tick();
|
||||
tick();
|
||||
step(2);
|
||||
|
||||
l.nametable = l.nametable << 8 | nametable;
|
||||
l.attribute = l.attribute << 2 | (attribute & 3);
|
||||
|
@ -233,18 +194,18 @@ auto PPU::renderScanline() -> void {
|
|||
l.tiledataHi = l.tiledataHi << 8 | tiledataHi;
|
||||
}
|
||||
|
||||
//336-339
|
||||
loadCHR(0x2000 | (r.vaddr & 0x0fff));
|
||||
tick();
|
||||
//337-338
|
||||
loadCHR(0x2000 | (uint12)r.v.address);
|
||||
step(1);
|
||||
bool skip = enable() && r.field == 1 && r.ly == 261;
|
||||
tick();
|
||||
step(1);
|
||||
|
||||
loadCHR(0x2000 | (r.vaddr & 0x0fff));
|
||||
tick();
|
||||
tick();
|
||||
//339
|
||||
loadCHR(0x2000 | (uint12)r.v.address);
|
||||
step(1);
|
||||
|
||||
//340
|
||||
if(!skip) tick();
|
||||
if(!skip) step(1);
|
||||
|
||||
return scanline();
|
||||
}
|
||||
|
|
|
@ -9,31 +9,28 @@ auto PPU::serialize(serializer& s) -> void {
|
|||
|
||||
s.integer(r.busData);
|
||||
|
||||
s.integer(r.addressLatch);
|
||||
|
||||
s.integer(r.vaddr);
|
||||
s.integer(r.taddr);
|
||||
s.integer(r.xaddr);
|
||||
s.integer(r.v.value);
|
||||
s.integer(r.t.value);
|
||||
|
||||
s.integer(r.nmiHold);
|
||||
s.integer(r.nmiFlag);
|
||||
|
||||
s.integer(r.nmiEnable);
|
||||
s.integer(r.masterSelect);
|
||||
s.integer(r.spriteHeight);
|
||||
s.integer(r.bgAddress);
|
||||
s.integer(r.spriteAddress);
|
||||
s.integer(r.vramIncrement);
|
||||
s.integer(r.spriteAddress);
|
||||
s.integer(r.bgAddress);
|
||||
s.integer(r.spriteHeight);
|
||||
s.integer(r.masterSelect);
|
||||
s.integer(r.nmiEnable);
|
||||
|
||||
s.integer(r.emphasis);
|
||||
s.integer(r.spriteEnable);
|
||||
s.integer(r.bgEnable);
|
||||
s.integer(r.spriteEdgeEnable);
|
||||
s.integer(r.bgEdgeEnable);
|
||||
s.integer(r.grayscale);
|
||||
s.integer(r.bgEdgeEnable);
|
||||
s.integer(r.spriteEdgeEnable);
|
||||
s.integer(r.bgEnable);
|
||||
s.integer(r.spriteEnable);
|
||||
s.integer(r.emphasis);
|
||||
|
||||
s.integer(r.spriteZeroHit);
|
||||
s.integer(r.spriteOverflow);
|
||||
s.integer(r.spriteZeroHit);
|
||||
|
||||
s.integer(r.oamAddress);
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
struct Peripherals {
|
||||
auto unload() -> void;
|
||||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* controllerPort1 = nullptr;
|
||||
Controller* controllerPort2 = nullptr;
|
||||
};
|
||||
|
||||
extern Peripherals peripherals;
|
|
@ -22,6 +22,7 @@ auto System::runToSave() -> void {
|
|||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
information = Information();
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else {
|
||||
|
@ -30,7 +31,7 @@ auto System::load() -> bool {
|
|||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
serializeInit();
|
||||
return _loaded = true;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
||||
auto System::save() -> void {
|
||||
|
@ -41,7 +42,7 @@ auto System::unload() -> void {
|
|||
if(!loaded()) return;
|
||||
peripherals.unload();
|
||||
cartridge.unload();
|
||||
_loaded = false;
|
||||
information.loaded = false;
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#include "peripherals.hpp"
|
||||
|
||||
struct System {
|
||||
auto loaded() const -> bool { return _loaded; }
|
||||
auto loaded() const -> bool { return information.loaded; }
|
||||
|
||||
auto run() -> void;
|
||||
auto runToSave() -> void;
|
||||
|
@ -28,12 +26,22 @@ struct System {
|
|||
auto serializeInit() -> void;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
string manifest;
|
||||
} information;
|
||||
|
||||
private:
|
||||
bool _loaded = false;
|
||||
uint _serializeSize = 0;
|
||||
};
|
||||
|
||||
struct Peripherals {
|
||||
auto unload() -> void;
|
||||
auto reset() -> void;
|
||||
auto connect(uint port, uint device) -> void;
|
||||
|
||||
Controller* controllerPort1 = nullptr;
|
||||
Controller* controllerPort2 = nullptr;
|
||||
};
|
||||
|
||||
extern System system;
|
||||
extern Peripherals peripherals;
|
||||
|
|
|
@ -55,7 +55,7 @@ auto PPU::Background::getTile() -> void {
|
|||
uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2);
|
||||
uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0);
|
||||
uint paletteSize = 2 << colorDepth;
|
||||
uint tileMask = 0x0fff >> colorDepth;
|
||||
uint tileMask = ppu.vram.mask >> (3 + colorDepth);
|
||||
uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth);
|
||||
|
||||
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
|
||||
|
@ -207,8 +207,8 @@ auto PPU::Background::getTileColor() -> uint {
|
|||
}
|
||||
|
||||
auto PPU::Background::reset() -> void {
|
||||
r.tiledataAddress = (random(0x0000) & 0x07) << 12;
|
||||
r.screenAddress = (random(0x0000) & 0x7c) << 8;
|
||||
r.tiledataAddress = (random(0x0000) & 0x0f) << 12;
|
||||
r.screenAddress = (random(0x0000) & 0xfc) << 8;
|
||||
r.screenSize = random(0);
|
||||
r.mosaic = random(0);
|
||||
r.tileSize = random(0);
|
||||
|
|
|
@ -113,6 +113,8 @@ template<typename type, uint Bit> struct BitField<type, Bit, ~0U> {
|
|||
inline auto& operator|=(const bool value) { return set(get() | value); }
|
||||
inline auto& operator^=(const bool value) { return set(get() ^ value); }
|
||||
|
||||
inline auto& invert() { return set(get() ^ 1); }
|
||||
|
||||
private:
|
||||
type data;
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ struct maybe {
|
|||
if(this == &source) return *this;
|
||||
reset();
|
||||
if(_valid = source._valid) new(&_value.t) T(move(source.get()));
|
||||
source._valid = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue