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:
Tim Allen 2016-06-27 23:07:57 +10:00
parent a816998122
commit 3e807946b8
60 changed files with 1844 additions and 1858 deletions

View File

@ -11,7 +11,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -14,9 +14,9 @@ APU apu;
APU::APU() { APU::APU() {
for(uint amp : range(32)) { for(uint amp : range(32)) {
if(amp == 0) { if(amp == 0) {
pulse_dac[amp] = 0; pulseDAC[amp] = 0;
} else { } 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 triangle_amp : range(16)) {
for(uint noise_amp : range(16)) { for(uint noise_amp : range(16)) {
if(dmc_amp == 0 && triangle_amp == 0 && noise_amp == 0) { 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 { } 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)); = 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(); noise_output = noise.clock();
dmc_output = dmc.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 = filter.runHipassStrong(output);
output += cartridge_sample; output += cartridgeSample;
output = filter.run_hipass_weak(output); output = filter.runHipassWeak(output);
//output = filter.run_lopass(output); //output = filter.runLopass(output);
output = sclamp<16>(output); output = sclamp<16>(output);
stream->sample(output / 32768.0); stream->sample(output / 32768.0);
@ -67,17 +67,17 @@ auto APU::tick() -> void {
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
} }
auto APU::set_irq_line() -> void { auto APU::setIRQ() -> void {
cpu.apuLine(frame.irq_pending || dmc.irq_pending); cpu.apuLine(frame.irqPending || dmc.irqPending);
} }
auto APU::set_sample(int16 sample) -> void { auto APU::setSample(int16 sample) -> void {
cartridge_sample = sample; cartridgeSample = sample;
} }
auto APU::power() -> void { auto APU::power() -> void {
filter.hipass_strong = 0; filter.hipassStrong = 0;
filter.hipass_weak = 0; filter.hipassWeak = 0;
filter.lopass = 0; filter.lopass = 0;
pulse[0].power(); pulse[0].power();
@ -97,16 +97,16 @@ auto APU::reset() -> void {
noise.reset(); noise.reset();
dmc.reset(); dmc.reset();
frame.irq_pending = 0; frame.irqPending = 0;
frame.mode = 0; frame.mode = 0;
frame.counter = 0; frame.counter = 0;
frame.divider = 1; frame.divider = 1;
enabled_channels = 0; enabledChannels = 0;
cartridge_sample = 0; cartridgeSample = 0;
set_irq_line(); setIRQ();
} }
auto APU::readIO(uint16 addr) -> uint8 { auto APU::readIO(uint16 addr) -> uint8 {
@ -114,16 +114,16 @@ auto APU::readIO(uint16 addr) -> uint8 {
case 0x4015: { case 0x4015: {
uint8 result = 0x00; uint8 result = 0x00;
result |= pulse[0].length_counter ? 0x01 : 0; result |= pulse[0].lengthCounter ? 0x01 : 0;
result |= pulse[1].length_counter ? 0x02 : 0; result |= pulse[1].lengthCounter ? 0x02 : 0;
result |= triangle.length_counter ? 0x04 : 0; result |= triangle.lengthCounter ? 0x04 : 0;
result |= noise.length_counter ? 0x08 : 0; result |= noise.lengthCounter ? 0x08 : 0;
result |= dmc.length_counter ? 0x10 : 0; result |= dmc.lengthCounter ? 0x10 : 0;
result |= frame.irq_pending ? 0x40 : 0; result |= frame.irqPending ? 0x40 : 0;
result |= dmc.irq_pending ? 0x80 : 0; result |= dmc.irqPending ? 0x80 : 0;
frame.irq_pending = false; frame.irqPending = false;
set_irq_line(); setIRQ();
return result; return result;
} }
@ -140,8 +140,8 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x4000: case 0x4004: { case 0x4000: case 0x4004: {
pulse[n].duty = data >> 6; pulse[n].duty = data >> 6;
pulse[n].envelope.loop_mode = data & 0x20; pulse[n].envelope.loopMode = data & 0x20;
pulse[n].envelope.use_speed_as_volume = data & 0x10; pulse[n].envelope.useSpeedAsVolume = data & 0x10;
pulse[n].envelope.speed = data & 0x0f; pulse[n].envelope.speed = data & 0x0f;
return; return;
} }
@ -157,26 +157,26 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x4002: case 0x4006: { case 0x4002: case 0x4006: {
pulse[n].period = (pulse[n].period & 0x0700) | (data << 0); 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; return;
} }
case 0x4003: case 0x4007: { case 0x4003: case 0x4007: {
pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8); 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].dutyCounter = 7;
pulse[n].envelope.reload_decay = true; pulse[n].envelope.reloadDecay = true;
if(enabled_channels & (1 << n)) { if(enabledChannels & (1 << n)) {
pulse[n].length_counter = length_counter_table[(data >> 3) & 0x1f]; pulse[n].lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
} }
return; return;
} }
case 0x4008: { case 0x4008: {
triangle.halt_length_counter = data & 0x80; triangle.haltLengthCounter = data & 0x80;
triangle.linear_length = data & 0x7f; triangle.linearLength = data & 0x7f;
return; return;
} }
@ -188,72 +188,72 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x400b: { case 0x400b: {
triangle.period = (triangle.period & 0x00ff) | (data << 8); triangle.period = (triangle.period & 0x00ff) | (data << 8);
triangle.reload_linear = true; triangle.reloadLinear = true;
if(enabled_channels & (1 << 2)) { if(enabledChannels & (1 << 2)) {
triangle.length_counter = length_counter_table[(data >> 3) & 0x1f]; triangle.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
} }
return; return;
} }
case 0x400c: { case 0x400c: {
noise.envelope.loop_mode = data & 0x20; noise.envelope.loopMode = data & 0x20;
noise.envelope.use_speed_as_volume = data & 0x10; noise.envelope.useSpeedAsVolume = data & 0x10;
noise.envelope.speed = data & 0x0f; noise.envelope.speed = data & 0x0f;
return; return;
} }
case 0x400e: { case 0x400e: {
noise.short_mode = data & 0x80; noise.shortMode = data & 0x80;
noise.period = data & 0x0f; noise.period = data & 0x0f;
return; return;
} }
case 0x400f: { case 0x400f: {
noise.envelope.reload_decay = true; noise.envelope.reloadDecay = true;
if(enabled_channels & (1 << 3)) { if(enabledChannels & (1 << 3)) {
noise.length_counter = length_counter_table[(data >> 3) & 0x1f]; noise.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
} }
return; return;
} }
case 0x4010: { case 0x4010: {
dmc.irq_enable = data & 0x80; dmc.irqEnable = data & 0x80;
dmc.loop_mode = data & 0x40; dmc.loopMode = data & 0x40;
dmc.period = data & 0x0f; dmc.period = data & 0x0f;
dmc.irq_pending = dmc.irq_pending && dmc.irq_enable && !dmc.loop_mode; dmc.irqPending = dmc.irqPending && dmc.irqEnable && !dmc.loopMode;
set_irq_line(); setIRQ();
return; return;
} }
case 0x4011: { case 0x4011: {
dmc.dac_latch = data & 0x7f; dmc.dacLatch = data & 0x7f;
return; return;
} }
case 0x4012: { case 0x4012: {
dmc.addr_latch = data; dmc.addrLatch = data;
return; return;
} }
case 0x4013: { case 0x4013: {
dmc.length_latch = data; dmc.lengthLatch = data;
return; return;
} }
case 0x4015: { case 0x4015: {
if((data & 0x01) == 0) pulse[0].length_counter = 0; if((data & 0x01) == 0) pulse[0].lengthCounter = 0;
if((data & 0x02) == 0) pulse[1].length_counter = 0; if((data & 0x02) == 0) pulse[1].lengthCounter = 0;
if((data & 0x04) == 0) triangle.length_counter = 0; if((data & 0x04) == 0) triangle.lengthCounter = 0;
if((data & 0x08) == 0) noise.length_counter = 0; if((data & 0x08) == 0) noise.lengthCounter = 0;
(data & 0x10) ? dmc.start() : dmc.stop(); (data & 0x10) ? dmc.start() : dmc.stop();
dmc.irq_pending = false; dmc.irqPending = false;
set_irq_line(); setIRQ();
enabled_channels = data & 0x1f; enabledChannels = data & 0x1f;
return; return;
} }
@ -261,10 +261,10 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
frame.mode = data >> 6; frame.mode = data >> 6;
frame.counter = 0; frame.counter = 0;
if(frame.mode & 2) clock_frame_counter(); if(frame.mode & 2) clockFrameCounter();
if(frame.mode & 1) { if(frame.mode & 1) {
frame.irq_pending = false; frame.irqPending = false;
set_irq_line(); setIRQ();
} }
frame.divider = FrameCounter::NtscPeriod; frame.divider = FrameCounter::NtscPeriod;
return; return;
@ -273,73 +273,73 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
} }
} }
auto APU::Filter::run_hipass_strong(int sample) -> int { auto APU::Filter::runHipassStrong(int sample) -> int {
hipass_strong += ((((int64)sample << 16) - (hipass_strong >> 16)) * HiPassStrong) >> 16; hipassStrong += ((((int64)sample << 16) - (hipassStrong >> 16)) * HiPassStrong) >> 16;
return sample - (hipass_strong >> 32); return sample - (hipassStrong >> 32);
} }
auto APU::Filter::run_hipass_weak(int sample) -> int { auto APU::Filter::runHipassWeak(int sample) -> int {
hipass_weak += ((((int64)sample << 16) - (hipass_weak >> 16)) * HiPassWeak) >> 16; hipassWeak += ((((int64)sample << 16) - (hipassWeak >> 16)) * HiPassWeak) >> 16;
return sample - (hipass_weak >> 32); 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; lopass += ((((int64)sample << 16) - (lopass >> 16)) * LoPass) >> 16;
return (lopass >> 32); return (lopass >> 32);
} }
auto APU::clock_frame_counter() -> void { auto APU::clockFrameCounter() -> void {
frame.counter++; frame.counter++;
if(frame.counter & 1) { if(frame.counter & 1) {
pulse[0].clock_length(); pulse[0].clockLength();
pulse[0].sweep.clock(0); pulse[0].sweep.clock(0);
pulse[1].clock_length(); pulse[1].clockLength();
pulse[1].sweep.clock(1); pulse[1].sweep.clock(1);
triangle.clock_length(); triangle.clockLength();
noise.clock_length(); noise.clockLength();
} }
pulse[0].envelope.clock(); pulse[0].envelope.clock();
pulse[1].envelope.clock(); pulse[1].envelope.clock();
triangle.clock_linear_length(); triangle.clockLinearLength();
noise.envelope.clock(); noise.envelope.clock();
if(frame.counter == 0) { if(frame.counter == 0) {
if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod; if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod;
if(frame.mode == 0) { if(frame.mode == 0) {
frame.irq_pending = true; frame.irqPending = true;
set_irq_line(); setIRQ();
} }
} }
} }
auto APU::clock_frame_counter_divider() -> void { auto APU::clockFrameCounterDivider() -> void {
frame.divider -= 2; frame.divider -= 2;
if(frame.divider <= 0) { if(frame.divider <= 0) {
clock_frame_counter(); clockFrameCounter();
frame.divider += FrameCounter::NtscPeriod; 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, 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, 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, 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, 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, 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, 398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50,
}; };

View File

@ -6,8 +6,8 @@ struct APU : Thread {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto tick() -> void; auto tick() -> void;
auto set_irq_line() -> void; auto setIRQ() -> void;
auto set_sample(int16 sample) -> void; auto setSample(int16 sample) -> void;
auto power() -> void; auto power() -> void;
auto reset() -> void; auto reset() -> void;
@ -18,55 +18,183 @@ struct APU : Thread {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
struct Filter { struct Filter {
auto run_hipass_strong(int sample) -> int; auto runHipassStrong(int sample) -> int;
auto run_hipass_weak(int sample) -> int; auto runHipassWeak(int sample) -> int;
auto run_lopass(int sample) -> int; auto runLopass(int sample) -> int;
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
enum : int { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 }; enum : int { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 };
int64 hipass_strong; int64 hipassStrong;
int64 hipass_weak; int64 hipassWeak;
int64 lopass; int64 lopass;
}; };
#include "envelope.hpp" struct Envelope {
#include "sweep.hpp" auto volume() const -> uint;
#include "pulse.hpp" auto clock() -> void;
#include "triangle.hpp"
#include "noise.hpp" auto power() -> void;
#include "dmc.hpp" 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 { struct FrameCounter {
auto serialize(serializer&) -> void; auto serialize(serializer&) -> void;
enum : uint { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz) enum : uint { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz)
bool irq_pending; bool irqPending;
uint2 mode; uint2 mode;
uint2 counter; uint2 counter;
int divider; int divider;
}; };
auto clock_frame_counter() -> void; auto clockFrameCounter() -> void;
auto clock_frame_counter_divider() -> void; auto clockFrameCounterDivider() -> void;
Filter filter; Filter filter;
FrameCounter frame; FrameCounter frame;
uint8 enabled_channels; uint8 enabledChannels;
int16 cartridge_sample; int16 cartridgeSample;
int16 pulse_dac[32]; int16 pulseDAC[32];
int16 dmc_triangle_noise_dac[128][16][16]; int16 dmcTriangleNoiseDAC[128][16][16];
static const uint8 length_counter_table[32]; static const uint8 lengthCounterTable[32];
static const uint16 ntsc_dmc_period_table[16]; static const uint16 dmcPeriodTableNTSC[16];
static const uint16 pal_dmc_period_table[16]; static const uint16 dmcPeriodTablePAL[16];
static const uint16 ntsc_noise_period_table[16]; static const uint16 noisePeriodTableNTSC[16];
static const uint16 pal_noise_period_table[16]; static const uint16 noisePeriodTablePAL[16];
}; };
extern APU apu; extern APU apu;

View File

@ -1,68 +1,68 @@
auto APU::DMC::start() -> void { auto APU::DMC::start() -> void {
if(length_counter == 0) { if(lengthCounter == 0) {
read_addr = 0x4000 + (addr_latch << 6); readAddr = 0x4000 + (addrLatch << 6);
length_counter = (length_latch << 4) + 1; lengthCounter = (lengthLatch << 4) + 1;
} }
} }
auto APU::DMC::stop() -> void { auto APU::DMC::stop() -> void {
length_counter = 0; lengthCounter = 0;
dma_delay_counter = 0; dmaDelayCounter = 0;
cpu.rdyLine(1); cpu.rdyLine(1);
cpu.rdyAddr(false); cpu.rdyAddr(false);
} }
auto APU::DMC::clock() -> uint8 { auto APU::DMC::clock() -> uint8 {
uint8 result = dac_latch; uint8 result = dacLatch;
if(dma_delay_counter > 0) { if(dmaDelayCounter > 0) {
dma_delay_counter--; dmaDelayCounter--;
if(dma_delay_counter == 1) { if(dmaDelayCounter == 1) {
cpu.rdyAddr(true, 0x8000 | read_addr); cpu.rdyAddr(true, 0x8000 | readAddr);
} else if(dma_delay_counter == 0) { } else if(dmaDelayCounter == 0) {
cpu.rdyLine(1); cpu.rdyLine(1);
cpu.rdyAddr(false); cpu.rdyAddr(false);
dma_buffer = cpu.mdr(); dmaBuffer = cpu.mdr();
have_dma_buffer = true; dmaBufferValid = true;
length_counter--; lengthCounter--;
read_addr++; readAddr++;
if(length_counter == 0) { if(lengthCounter == 0) {
if(loop_mode) { if(loopMode) {
start(); start();
} else if(irq_enable) { } else if(irqEnable) {
irq_pending = true; irqPending = true;
apu.set_irq_line(); apu.setIRQ();
} }
} }
} }
} }
if(--period_counter == 0) { if(--periodCounter == 0) {
if(have_sample) { if(sampleValid) {
int delta = (((sample >> bit_counter) & 1) << 2) - 2; int delta = (((sample >> bitCounter) & 1) << 2) - 2;
uint data = dac_latch + delta; uint data = dacLatch + delta;
if((data & 0x80) == 0) dac_latch = data; if((data & 0x80) == 0) dacLatch = data;
} }
if(++bit_counter == 0) { if(++bitCounter == 0) {
if(have_dma_buffer) { if(dmaBufferValid) {
have_sample = true; sampleValid = true;
sample = dma_buffer; sample = dmaBuffer;
have_dma_buffer = false; dmaBufferValid = false;
} else { } 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); cpu.rdyLine(0);
dma_delay_counter = 4; dmaDelayCounter = 4;
} }
return result; return result;
@ -72,46 +72,21 @@ auto APU::DMC::power() -> void {
} }
auto APU::DMC::reset() -> void { auto APU::DMC::reset() -> void {
length_counter = 0; lengthCounter = 0;
irq_pending = 0; irqPending = 0;
period = 0; period = 0;
period_counter = ntsc_dmc_period_table[0]; periodCounter = dmcPeriodTableNTSC[0];
irq_enable = 0; irqEnable = 0;
loop_mode = 0; loopMode = 0;
dac_latch = 0; dacLatch = 0;
addr_latch = 0; addrLatch = 0;
length_latch = 0; lengthLatch = 0;
read_addr = 0; readAddr = 0;
dma_delay_counter = 0; dmaDelayCounter = 0;
bit_counter = 0; bitCounter = 0;
have_dma_buffer = 0; dmaBufferValid = 0;
dma_buffer = 0; dmaBuffer = 0;
have_sample = 0; sampleValid = 0;
sample = 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);
}

View File

@ -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;

View File

@ -1,18 +1,18 @@
auto APU::Envelope::volume() const -> uint { auto APU::Envelope::volume() const -> uint {
return use_speed_as_volume ? speed : decay_volume; return useSpeedAsVolume ? speed : decayVolume;
} }
auto APU::Envelope::clock() -> void { auto APU::Envelope::clock() -> void {
if(reload_decay) { if(reloadDecay) {
reload_decay = false; reloadDecay = false;
decay_volume = 0x0f; decayVolume = 0x0f;
decay_counter = speed + 1; decayCounter = speed + 1;
return; return;
} }
if(--decay_counter == 0) { if(--decayCounter == 0) {
decay_counter = speed + 1; decayCounter = speed + 1;
if(decay_volume || loop_mode) decay_volume--; if(decayVolume || loopMode) decayVolume--;
} }
} }
@ -21,19 +21,9 @@ auto APU::Envelope::power() -> void {
auto APU::Envelope::reset() -> void { auto APU::Envelope::reset() -> void {
speed = 0; speed = 0;
use_speed_as_volume = 0; useSpeedAsVolume = 0;
loop_mode = 0; loopMode = 0;
reload_decay = 0; reloadDecay = 0;
decay_counter = 0; decayCounter = 0;
decay_volume = 0; decayVolume = 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);
} }

View File

@ -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;
};

View File

@ -1,25 +1,25 @@
auto APU::Noise::clock_length() -> void { auto APU::Noise::clockLength() -> void {
if(envelope.loop_mode == 0) { if(envelope.loopMode == 0) {
if(length_counter > 0) length_counter--; if(lengthCounter > 0) lengthCounter--;
} }
} }
auto APU::Noise::clock() -> uint8 { auto APU::Noise::clock() -> uint8 {
if(length_counter == 0) return 0; if(lengthCounter == 0) return 0;
uint8 result = (lfsr & 1) ? envelope.volume() : 0; uint8 result = (lfsr & 1) ? envelope.volume() : 0;
if(--period_counter == 0) { if(--periodCounter == 0) {
uint feedback; uint feedback;
if(short_mode) { if(shortMode) {
feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 6) & 1); feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 6) & 1);
} else { } else {
feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 1) & 1); feedback = ((lfsr >> 0) & 1) ^ ((lfsr >> 1) & 1);
} }
lfsr = (lfsr >> 1) | (feedback << 14); lfsr = (lfsr >> 1) | (feedback << 14);
period_counter = apu.ntsc_noise_period_table[period]; periodCounter = apu.noisePeriodTableNTSC[period];
} }
return result; return result;
@ -29,29 +29,17 @@ auto APU::Noise::power() -> void {
} }
auto APU::Noise::reset() -> void { auto APU::Noise::reset() -> void {
length_counter = 0; lengthCounter = 0;
envelope.speed = 0; envelope.speed = 0;
envelope.use_speed_as_volume = 0; envelope.useSpeedAsVolume = 0;
envelope.loop_mode = 0; envelope.loopMode = 0;
envelope.reload_decay = 0; envelope.reloadDecay = 0;
envelope.decay_counter = 0; envelope.decayCounter = 0;
envelope.decay_volume = 0; envelope.decayVolume = 0;
period = 0; period = 0;
period_counter = 1; periodCounter = 1;
short_mode = 0; shortMode = 0;
lfsr = 1; 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);
}

View File

@ -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;

View File

@ -1,20 +1,20 @@
auto APU::Pulse::clock_length() -> void { auto APU::Pulse::clockLength() -> void {
if(envelope.loop_mode == 0) { if(envelope.loopMode == 0) {
if(length_counter) length_counter--; if(lengthCounter) lengthCounter--;
} }
} }
auto APU::Pulse::clock() -> uint8 { auto APU::Pulse::clock() -> uint8 {
if(sweep.check_period() == false) return 0; if(!sweep.checkPeriod()) return 0;
if(length_counter == 0) return 0; if(lengthCounter == 0) return 0;
static const uint duty_table[] = {1, 2, 4, 6}; static const uint dutyTable[] = {1, 2, 4, 6};
uint8 result = (duty_counter < duty_table[duty]) ? envelope.volume() : 0; uint8 result = (dutyCounter < dutyTable[duty]) ? envelope.volume() : 0;
if(sweep.pulse_period < 0x008) result = 0; if(sweep.pulsePeriod < 0x008) result = 0;
if(--period_counter == 0) { if(--periodCounter == 0) {
period_counter = (sweep.pulse_period + 1) * 2; periodCounter = (sweep.pulsePeriod + 1) * 2;
duty_counter++; dutyCounter++;
} }
return result; return result;
@ -29,23 +29,10 @@ auto APU::Pulse::reset() -> void {
envelope.reset(); envelope.reset();
sweep.reset(); sweep.reset();
length_counter = 0; lengthCounter = 0;
duty = 0; duty = 0;
duty_counter = 0; dutyCounter = 0;
period = 0; period = 0;
period_counter = 1; periodCounter = 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);
} }

View File

@ -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];

View File

@ -9,18 +9,102 @@ auto APU::serialize(serializer& s) -> void {
dmc.serialize(s); dmc.serialize(s);
frame.serialize(s); frame.serialize(s);
s.integer(enabled_channels); s.integer(enabledChannels);
s.integer(cartridge_sample); s.integer(cartridgeSample);
} }
auto APU::Filter::serialize(serializer& s) -> void { auto APU::Filter::serialize(serializer& s) -> void {
s.integer(hipass_strong); s.integer(hipassStrong);
s.integer(hipass_weak); s.integer(hipassWeak);
s.integer(lopass); 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 { auto APU::FrameCounter::serialize(serializer& s) -> void {
s.integer(irq_pending); s.integer(irqPending);
s.integer(mode); s.integer(mode);
s.integer(counter); s.integer(counter);

View File

@ -1,8 +1,8 @@
auto APU::Sweep::check_period() -> bool { auto APU::Sweep::checkPeriod() -> bool {
if(pulse_period > 0x7ff) return false; if(pulsePeriod > 0x7ff) return false;
if(decrement == 0) { if(decrement == 0) {
if((pulse_period + (pulse_period >> shift)) & 0x800) return false; if((pulsePeriod + (pulsePeriod >> shift)) & 0x800) return false;
} }
return true; return true;
@ -11,14 +11,14 @@ auto APU::Sweep::check_period() -> bool {
auto APU::Sweep::clock(uint channel) -> void { auto APU::Sweep::clock(uint channel) -> void {
if(--counter == 0) { if(--counter == 0) {
counter = period + 1; counter = period + 1;
if(enable && shift && pulse_period > 8) { if(enable && shift && pulsePeriod > 8) {
int delta = pulse_period >> shift; int delta = pulsePeriod >> shift;
if(decrement) { if(decrement) {
pulse_period -= delta; pulsePeriod -= delta;
if(channel == 0) pulse_period--; if(channel == 0) pulsePeriod--;
} else if((pulse_period + delta) < 0x800) { } else if((pulsePeriod + delta) < 0x800) {
pulse_period += delta; pulsePeriod += delta;
} }
} }
} }
@ -36,18 +36,8 @@ auto APU::Sweep::power() -> void {
counter = 1; counter = 1;
enable = 0; enable = 0;
reload = 0; reload = 0;
pulse_period = 0; pulsePeriod = 0;
} }
auto APU::Sweep::reset() -> void { 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);
}

View File

@ -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;
};

View File

@ -1,27 +1,27 @@
auto APU::Triangle::clock_length() -> void { auto APU::Triangle::clockLength() -> void {
if(halt_length_counter == 0) { if(haltLengthCounter == 0) {
if(length_counter > 0) length_counter--; if(lengthCounter > 0) lengthCounter--;
} }
} }
auto APU::Triangle::clock_linear_length() -> void { auto APU::Triangle::clockLinearLength() -> void {
if(reload_linear) { if(reloadLinear) {
linear_length_counter = linear_length; linearLengthCounter = linearLength;
} else if(linear_length_counter) { } else if(linearLengthCounter) {
linear_length_counter--; linearLengthCounter--;
} }
if(halt_length_counter == 0) reload_linear = false; if(haltLengthCounter == 0) reloadLinear = false;
} }
auto APU::Triangle::clock() -> uint8 { auto APU::Triangle::clock() -> uint8 {
uint8 result = step_counter & 0x0f; uint8 result = stepCounter & 0x0f;
if((step_counter & 0x10) == 0) result ^= 0x0f; if((stepCounter & 0x10) == 0) result ^= 0x0f;
if(length_counter == 0 || linear_length_counter == 0) return result; if(lengthCounter == 0 || linearLengthCounter == 0) return result;
if(--period_counter == 0) { if(--periodCounter == 0) {
step_counter++; stepCounter++;
period_counter = period + 1; periodCounter = period + 1;
} }
return result; return result;
@ -32,27 +32,13 @@ auto APU::Triangle::power() -> void {
} }
auto APU::Triangle::reset() -> void { auto APU::Triangle::reset() -> void {
length_counter = 0; lengthCounter = 0;
linear_length = 0; linearLength = 0;
halt_length_counter = 0; haltLengthCounter = 0;
period = 0; period = 0;
period_counter = 1; periodCounter = 1;
step_counter = 0; stepCounter = 0;
linear_length_counter = 0; linearLengthCounter = 0;
reload_linear = 0; reloadLinear = 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);
} }

View File

@ -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;

View File

@ -5,17 +5,17 @@ struct BandaiFCG : Board {
} }
auto main() -> void { auto main() -> void {
if(irq_counter_enable) { if(irqCounterEnable) {
if(--irq_counter == 0xffff) { if(--irqCounter == 0xffff) {
cpu.irqLine(1); cpu.irqLine(1);
irq_counter_enable = false; irqCounterEnable = false;
} }
} }
tick(); tick();
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
case 1: return ((addr & 0x0800) >> 1) | (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) { if(addr & 0x8000) {
bool region = addr & 0x4000; 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 prgrom.read((bank << 14) | (addr & 0x3fff));
} }
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr >= 0x6000) { if(addr >= 0x6000) {
switch(addr & 15) { switch(addr & 15) {
case 0x00: case 0x01: case 0x02: case 0x03: case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07: case 0x04: case 0x05: case 0x06: case 0x07:
chr_bank[addr & 7] = data; chrBank[addr & 7] = data;
break; break;
case 0x08: case 0x08:
prg_bank = data & 0x0f; prgBank = data & 0x0f;
break; break;
case 0x09: case 0x09:
mirror = data & 0x03; mirror = data & 0x03;
break; break;
case 0x0a: case 0x0a:
cpu.irqLine(0); cpu.irqLine(0);
irq_counter_enable = data & 0x01; irqCounterEnable = data & 0x01;
irq_counter = irq_latch; irqCounter = irqLatch;
break; break;
case 0x0b: case 0x0b:
irq_latch = (irq_latch & 0xff00) | (data << 0); irqLatch = (irqLatch & 0xff00) | (data << 0);
break; break;
case 0x0c: case 0x0c:
irq_latch = (irq_latch & 0x00ff) | (data << 8); irqLatch = (irqLatch & 0x00ff) | (data << 8);
break; break;
case 0x0d: case 0x0d:
//todo: serial EEPROM support //todo: serial EEPROM support
@ -64,16 +64,16 @@ struct BandaiFCG : Board {
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff);
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) return ppu.writeCIRAM(ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); addr = (chrBank[addr >> 10] << 10) | (addr & 0x03ff);
return Board::chr_write(addr, data); return Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
@ -81,29 +81,29 @@ struct BandaiFCG : Board {
} }
auto reset() -> void { auto reset() -> void {
for(auto &n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
prg_bank = 0; prgBank = 0;
mirror = 0; mirror = 0;
irq_counter_enable = 0; irqCounterEnable = 0;
irq_counter = 0; irqCounter = 0;
irq_latch = 0; irqLatch = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.array(chr_bank); s.array(chrBank);
s.integer(prg_bank); s.integer(prgBank);
s.integer(mirror); s.integer(mirror);
s.integer(irq_counter_enable); s.integer(irqCounterEnable);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_latch); s.integer(irqLatch);
} }
uint8 chr_bank[8]; uint8 chrBank[8];
uint8 prg_bank; uint8 prgBank;
uint2 mirror; uint2 mirror;
bool irq_counter_enable; bool irqCounterEnable;
uint16 irq_counter; uint16 irqCounter;
uint16 irq_latch; uint16 irqLatch;
}; };

View File

@ -118,13 +118,13 @@ auto Board::tick() -> void {
if(cartridge.clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); 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(chrram.size) return chrram.data[mirror(addr, chrram.size)];
if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)]; if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)];
return 0u; 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; if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
} }

View File

@ -23,11 +23,11 @@ struct Board {
virtual auto main() -> void; virtual auto main() -> void;
virtual auto tick() -> void; virtual auto tick() -> void;
virtual auto prg_read(uint addr) -> uint8 = 0; virtual auto readPRG(uint addr) -> uint8 = 0;
virtual auto prg_write(uint addr, uint8 data) -> void = 0; virtual auto writePRG(uint addr, uint8 data) -> void = 0;
virtual auto chr_read(uint addr) -> uint8; virtual auto readCHR(uint addr) -> uint8;
virtual auto chr_write(uint addr, uint8 data) -> void; virtual auto writeCHR(uint addr, uint8 data) -> void;
virtual inline auto scanline(uint y) -> void {} virtual inline auto scanline(uint y) -> void {}

View File

@ -2,23 +2,23 @@ struct KonamiVRC1 : Board {
KonamiVRC1(Markup::Node& document) : Board(document), vrc1(*this) { KonamiVRC1(Markup::Node& document) : Board(document), vrc1(*this) {
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr & 0x8000) return prgrom.read(vrc1.prg_addr(addr)); if(addr & 0x8000) return prgrom.read(vrc1.addrPRG(addr));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr & 0x8000) return vrc1.reg_write(addr, data); if(addr & 0x8000) return vrc1.writeIO(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc1.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(vrc1.addrCIRAM(addr));
return Board::chr_read(vrc1.chr_addr(addr)); return Board::readCHR(vrc1.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc1.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(vrc1.addrCIRAM(addr), data);
return Board::chr_write(vrc1.chr_addr(addr), data); return Board::writeCHR(vrc1.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -4,31 +4,31 @@ struct KonamiVRC2 : Board {
settings.pinout.a1 = 1 << document["board/chip/pinout/a1"].natural(); 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 < 0x6000) return cpu.mdr();
if(addr < 0x8000) return vrc2.ram_read(addr); if(addr < 0x8000) return vrc2.readRAM(addr);
return prgrom.read(vrc2.prg_addr(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 < 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 a0 = (addr & settings.pinout.a0);
bool a1 = (addr & settings.pinout.a1); bool a1 = (addr & settings.pinout.a1);
addr &= 0xfff0; addr &= 0xfff0;
addr |= (a0 << 0) | (a1 << 1); addr |= (a0 << 0) | (a1 << 1);
return vrc2.reg_write(addr, data); return vrc2.writeIO(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc2.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(vrc2.addrCIRAM(addr));
return Board::chr_read(vrc2.chr_addr(addr)); return Board::readCHR(vrc2.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc2.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(vrc2.addrCIRAM(addr), data);
return Board::chr_write(vrc2.chr_addr(addr), data); return Board::writeCHR(vrc2.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -7,18 +7,18 @@ struct KonamiVRC3 : Board {
vrc3.main(); vrc3.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff); 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(); 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 & 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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr & 0x07ff); return ppu.readCIRAM(addr & 0x07ff);
@ -26,7 +26,7 @@ struct KonamiVRC3 : Board {
return chrram.read(addr); return chrram.read(addr);
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr & 0x07ff, data); return ppu.writeCIRAM(addr & 0x07ff, data);

View File

@ -8,13 +8,13 @@ struct KonamiVRC4 : Board {
return vrc4.main(); return vrc4.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr(); if(addr < 0x6000) return cpu.mdr();
if(addr < 0x8000) return prgram.read(addr); 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 < 0x6000) return;
if(addr < 0x8000) return prgram.write(addr, data); if(addr < 0x8000) return prgram.write(addr, data);
@ -22,17 +22,17 @@ struct KonamiVRC4 : Board {
bool a1 = (addr & settings.pinout.a1); bool a1 = (addr & settings.pinout.a1);
addr &= 0xfff0; addr &= 0xfff0;
addr |= (a1 << 1) | (a0 << 0); addr |= (a1 << 1) | (a0 << 0);
return vrc4.reg_write(addr, data); return vrc4.writeIO(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc4.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(vrc4.addrCIRAM(addr));
return Board::chr_read(vrc4.chr_addr(addr)); return Board::readCHR(vrc4.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc4.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(vrc4.addrCIRAM(addr), data);
return Board::chr_write(vrc4.chr_addr(addr), data); return Board::writeCHR(vrc4.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -2,29 +2,29 @@ struct KonamiVRC6 : Board {
KonamiVRC6(Markup::Node& document) : Board(document), vrc6(*this) { KonamiVRC6(Markup::Node& document) : Board(document), vrc6(*this) {
} }
auto prg_read(uint addr) -> uint8{ auto readPRG(uint addr) -> uint8{
if((addr & 0xe000) == 0x6000) return vrc6.ram_read(addr); if((addr & 0xe000) == 0x6000) return vrc6.readRAM(addr);
if(addr & 0x8000) return prgrom.read(vrc6.prg_addr(addr)); if(addr & 0x8000) return prgrom.read(vrc6.addrPRG(addr));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xe000) == 0x6000) return vrc6.ram_write(addr, data); if((addr & 0xe000) == 0x6000) return vrc6.writeRAM(addr, data);
if(addr & 0x8000) { if(addr & 0x8000) {
addr = (addr & 0xf003); addr = (addr & 0xf003);
if(prgram.size) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1); 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 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc6.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(vrc6.addrCIRAM(addr));
return Board::chr_read(vrc6.chr_addr(addr)); return Board::readCHR(vrc6.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc6.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(vrc6.addrCIRAM(addr), data);
return Board::chr_write(vrc6.chr_addr(addr), data); return Board::writeCHR(vrc6.addrCHR(addr), data);
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {

View File

@ -6,26 +6,26 @@ struct KonamiVRC7 : Board {
return vrc7.main(); return vrc7.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr(); if(addr < 0x6000) return cpu.mdr();
if(addr < 0x8000) return prgram.read(addr); 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 < 0x6000) return;
if(addr < 0x8000) return prgram.write(addr, data); 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 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc7.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(vrc7.addrCIRAM(addr));
return chrram.read(vrc7.chr_addr(addr)); return chrram.read(vrc7.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto chr_write(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(vrc7.addrCIRAM(addr), data);
return chrram.write(vrc7.chr_addr(addr), data); return chrram.write(vrc7.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -7,43 +7,43 @@ struct NES_AxROM : Board {
NES_AxROM(Markup::Node& document) : Board(document) { NES_AxROM(Markup::Node& document) : Board(document) {
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr & 0x8000) return prgrom.read((prg_bank << 15) | (addr & 0x7fff)); if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr & 0x8000) { if(addr & 0x8000) {
prg_bank = data & 0x0f; prgBank = data & 0x0f;
mirror_select = data & 0x10; mirrorSelect = data & 0x10;
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM((mirror_select << 10) | (addr & 0x03ff)); if(addr & 0x2000) return ppu.readCIRAM((mirrorSelect << 10) | (addr & 0x03ff));
return Board::chr_read(addr); return Board::readCHR(addr);
} }
auto chr_write(uint addr, uint8 data) -> void { auto chr_write(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM((mirror_select << 10) | (addr & 0x03ff), data); if(addr & 0x2000) return ppu.writeCIRAM((mirrorSelect << 10) | (addr & 0x03ff), data);
return Board::chr_write(addr, data); return Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0x0f; prgBank = 0x0f;
mirror_select = 0; mirrorSelect = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
s.integer(mirror_select); s.integer(mirrorSelect);
} }
uint4 prg_bank; uint4 prgBank;
bool mirror_select; bool mirrorSelect;
}; };

View File

@ -5,46 +5,46 @@ struct NES_BNROM : Board {
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; 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((prg_bank << 15) | (addr & 0x7fff)); if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr & 0x8000) prg_bank = data & 0x03; if(addr & 0x8000) prgBank = data & 0x03;
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr); 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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr, data); return ppu.writeCIRAM(addr, data);
} }
return Board::chr_write(addr, data); return Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
} }
struct Settings { struct Settings {
bool mirror; //0 = horizontal, 1 = vertical bool mirror; //0 = horizontal, 1 = vertical
} settings; } settings;
uint2 prg_bank; uint2 prgBank;
}; };

View File

@ -5,48 +5,48 @@ struct NES_CNROM : Board {
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; 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); if(addr & 0x8000) return prgrom.read(addr & 0x7fff);
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr & 0x8000) chr_bank = data & 0x03; if(addr & 0x8000) chrBank = data & 0x03;
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr & 0x07ff); return ppu.readCIRAM(addr & 0x07ff);
} }
addr = (chr_bank * 0x2000) + (addr & 0x1fff); addr = (chrBank * 0x2000) + (addr & 0x1fff);
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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr & 0x07ff, data); return ppu.writeCIRAM(addr & 0x07ff, data);
} }
addr = (chr_bank * 0x2000) + (addr & 0x1fff); addr = (chrBank * 0x2000) + (addr & 0x1fff);
Board::chr_write(addr, data); Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
} }
auto reset() -> void { auto reset() -> void {
chr_bank = 0; chrBank = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(chr_bank); s.integer(chrBank);
} }
struct Settings { struct Settings {
bool mirror; //0 = horizontal, 1 = vertical bool mirror; //0 = horizontal, 1 = vertical
} settings; } settings;
uint2 chr_bank; uint2 chrBank;
}; };

View File

@ -7,20 +7,20 @@ struct NES_ExROM : Board {
mmc5.main(); mmc5.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
return mmc5.prg_read(addr); return mmc5.readPRG(addr);
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
mmc5.prg_write(addr, data); mmc5.writePRG(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
return mmc5.chr_read(addr); return mmc5.readCHR(addr);
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
mmc5.chr_write(addr, data); mmc5.writeCHR(addr, data);
} }
auto scanline(uint y) -> void { auto scanline(uint y) -> void {

View File

@ -5,61 +5,61 @@ struct NES_FxROM : Board {
revision = Revision::FKROM; revision = Revision::FKROM;
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr(); if(addr < 0x6000) return cpu.mdr();
if(addr < 0x8000) return prgram.read(addr); 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)); 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 < 0x6000) return;
if(addr < 0x8000) return prgram.write(addr, data); if(addr < 0x8000) return prgram.write(addr, data);
switch(addr & 0xf000) { switch(addr & 0xf000) {
case 0xa000: prg_bank = data & 0x0f; break; case 0xa000: prgBank = data & 0x0f; break;
case 0xb000: chr_bank[0][0] = data & 0x1f; break; case 0xb000: chrBank[0][0] = data & 0x1f; break;
case 0xc000: chr_bank[0][1] = data & 0x1f; break; case 0xc000: chrBank[0][1] = data & 0x1f; break;
case 0xd000: chr_bank[1][0] = data & 0x1f; break; case 0xd000: chrBank[1][0] = data & 0x1f; break;
case 0xe000: chr_bank[1][1] = data & 0x1f; break; case 0xe000: chrBank[1][1] = data & 0x1f; break;
case 0xf000: mirror = data & 0x01; break; case 0xf000: mirror = data & 0x01; break;
} }
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
bool region = addr & 0x1000; 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) == 0x0fd8) latch[region] = 0;
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; 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 { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
bool region = addr & 0x1000; 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) == 0x0fd8) latch[region] = 0;
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; 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 power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
chr_bank[0][0] = 0; chrBank[0][0] = 0;
chr_bank[0][1] = 0; chrBank[0][1] = 0;
chr_bank[1][0] = 0; chrBank[1][0] = 0;
chr_bank[1][1] = 0; chrBank[1][1] = 0;
mirror = 0; mirror = 0;
latch[0] = 0; latch[0] = 0;
latch[1] = 0; latch[1] = 0;
@ -68,11 +68,11 @@ struct NES_FxROM : Board {
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
s.integer(chr_bank[0][0]); s.integer(chrBank[0][0]);
s.integer(chr_bank[0][1]); s.integer(chrBank[0][1]);
s.integer(chr_bank[1][0]); s.integer(chrBank[1][0]);
s.integer(chr_bank[1][1]); s.integer(chrBank[1][1]);
s.integer(mirror); s.integer(mirror);
s.array(latch); s.array(latch);
} }
@ -82,8 +82,8 @@ struct NES_FxROM : Board {
FKROM, FKROM,
} revision; } revision;
uint4 prg_bank; uint4 prgBank;
uint5 chr_bank[2][2]; uint5 chrBank[2][2];
bool mirror; bool mirror;
bool latch[2]; bool latch[2];
}; };

View File

@ -6,54 +6,54 @@ struct NES_GxROM : Board {
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; 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((prg_bank << 15) | (addr & 0x7fff)); if(addr & 0x8000) return prgrom.read((prgBank << 15) | (addr & 0x7fff));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if(addr & 0x8000) { if(addr & 0x8000) {
prg_bank = (data & 0x30) >> 4; prgBank = (data & 0x30) >> 4;
chr_bank = (data & 0x03) >> 0; chrBank = (data & 0x03) >> 0;
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr & 0x07ff); return ppu.readCIRAM(addr & 0x07ff);
} }
addr = (chr_bank * 0x2000) + (addr & 0x1fff); addr = (chrBank * 0x2000) + (addr & 0x1fff);
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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr & 0x07ff, data); return ppu.writeCIRAM(addr & 0x07ff, data);
} }
addr = (chr_bank * 0x2000) + (addr & 0x1fff); addr = (chrBank * 0x2000) + (addr & 0x1fff);
Board::chr_write(addr, data); Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
chr_bank = 0; chrBank = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
s.integer(chr_bank); s.integer(chrBank);
} }
struct Settings { struct Settings {
bool mirror; //0 = horizontal, 1 = vertical bool mirror; //0 = horizontal, 1 = vertical
} settings; } settings;
uint2 prg_bank; uint2 prgBank;
uint2 chr_bank; uint2 chrBank;
}; };

View File

@ -6,27 +6,27 @@ struct NES_HKROM : Board {
mmc6.main(); mmc6.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if((addr & 0xf000) == 0x7000) return mmc6.ram_read(addr); if((addr & 0xf000) == 0x7000) return mmc6.readRAM(addr);
if(addr & 0x8000) return prgrom.read(mmc6.prg_addr(addr)); if(addr & 0x8000) return prgrom.read(mmc6.addrPRG(addr));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xf000) == 0x7000) return mmc6.ram_write(addr, data); if((addr & 0xf000) == 0x7000) return mmc6.writeRAM(addr, data);
if(addr & 0x8000) return mmc6.reg_write(addr, data); if(addr & 0x8000) return mmc6.writeIO(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
mmc6.irq_test(addr); mmc6.irqTest(addr);
if(addr & 0x2000) return ppu.readCIRAM(mmc6.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(mmc6.addrCIRAM(addr));
return Board::chr_read(mmc6.chr_addr(addr)); return Board::readCHR(mmc6.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
mmc6.irq_test(addr); mmc6.irqTest(addr);
if(addr & 0x2000) return ppu.writeCIRAM(mmc6.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(mmc6.addrCIRAM(addr), data);
return Board::chr_write(mmc6.chr_addr(addr), data); return Board::writeCHR(mmc6.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -6,15 +6,15 @@ struct NES_NROM : Board {
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; 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); if(addr & 0x8000) return prgrom.read(addr);
return cpu.mdr(); 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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr & 0x07ff); return ppu.readCIRAM(addr & 0x07ff);
@ -23,7 +23,7 @@ struct NES_NROM : Board {
return chrrom.read(addr); return chrrom.read(addr);
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr & 0x07ff, data); return ppu.writeCIRAM(addr & 0x07ff, data);

View File

@ -5,12 +5,12 @@ struct NES_PxROM : Board {
revision = Revision::PNROM; revision = Revision::PNROM;
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr(); if(addr < 0x6000) return cpu.mdr();
if(addr < 0x8000) return prgram.read(addr); if(addr < 0x8000) return prgram.read(addr);
uint bank = 0; uint bank = 0;
switch((addr / 0x2000) & 3) { switch((addr / 0x2000) & 3) {
case 0: bank = prg_bank; break; case 0: bank = prgBank; break;
case 1: bank = 0x0d; break; case 1: bank = 0x0d; break;
case 2: bank = 0x0e; break; case 2: bank = 0x0e; break;
case 3: bank = 0x0f; break; case 3: bank = 0x0f; break;
@ -18,54 +18,54 @@ struct NES_PxROM : Board {
return prgrom.read((bank * 0x2000) | (addr & 0x1fff)); 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 < 0x6000) return;
if(addr < 0x8000) return prgram.write(addr, data); if(addr < 0x8000) return prgram.write(addr, data);
switch(addr & 0xf000) { switch(addr & 0xf000) {
case 0xa000: prg_bank = data & 0x0f; break; case 0xa000: prgBank = data & 0x0f; break;
case 0xb000: chr_bank[0][0] = data & 0x1f; break; case 0xb000: chrBank[0][0] = data & 0x1f; break;
case 0xc000: chr_bank[0][1] = data & 0x1f; break; case 0xc000: chrBank[0][1] = data & 0x1f; break;
case 0xd000: chr_bank[1][0] = data & 0x1f; break; case 0xd000: chrBank[1][0] = data & 0x1f; break;
case 0xe000: chr_bank[1][1] = data & 0x1f; break; case 0xe000: chrBank[1][1] = data & 0x1f; break;
case 0xf000: mirror = data & 0x01; break; case 0xf000: mirror = data & 0x01; break;
} }
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
bool region = addr & 0x1000; 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) == 0x0fd8) latch[region] = 0;
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; 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 { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
bool region = addr & 0x1000; 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) == 0x0fd8) latch[region] = 0;
if((addr & 0x0ff8) == 0x0fe8) latch[region] = 1; 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 power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
chr_bank[0][0] = 0; chrBank[0][0] = 0;
chr_bank[0][1] = 0; chrBank[0][1] = 0;
chr_bank[1][0] = 0; chrBank[1][0] = 0;
chr_bank[1][1] = 0; chrBank[1][1] = 0;
mirror = 0; mirror = 0;
latch[0] = 0; latch[0] = 0;
latch[1] = 0; latch[1] = 0;
@ -74,11 +74,11 @@ struct NES_PxROM : Board {
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
s.integer(chr_bank[0][0]); s.integer(chrBank[0][0]);
s.integer(chr_bank[0][1]); s.integer(chrBank[0][1]);
s.integer(chr_bank[1][0]); s.integer(chrBank[1][0]);
s.integer(chr_bank[1][1]); s.integer(chrBank[1][1]);
s.integer(mirror); s.integer(mirror);
s.array(latch); s.array(latch);
} }
@ -88,8 +88,8 @@ struct NES_PxROM : Board {
PNROM, PNROM,
} revision; } revision;
uint4 prg_bank; uint4 prgBank;
uint5 chr_bank[2][2]; uint5 chrBank[2][2];
bool mirror; bool mirror;
bool latch[2]; bool latch[2];
}; };

View File

@ -7,27 +7,27 @@ struct NES_SxROM : Board {
return mmc1.main(); return mmc1.main();
} }
auto ram_addr(uint addr) -> uint { auto addrRAM(uint addr) -> uint {
uint bank = 0; uint bank = 0;
if(revision == Revision::SOROM) bank = (mmc1.chr_bank[0] & 0x08) >> 3; if(revision == Revision::SOROM) bank = (mmc1.chrBank[0] & 0x08) >> 3;
if(revision == Revision::SUROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2; if(revision == Revision::SUROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2;
if(revision == Revision::SXROM) bank = (mmc1.chr_bank[0] & 0x0c) >> 2; if(revision == Revision::SXROM) bank = (mmc1.chrBank[0] & 0x0c) >> 2;
return (bank << 13) | (addr & 0x1fff); return (bank << 13) | (addr & 0x1fff);
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if((addr & 0xe000) == 0x6000) { if((addr & 0xe000) == 0x6000) {
if(revision == Revision::SNROM) { 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; if(mmc1.ramDisable) return 0x00;
return prgram.read(ram_addr(addr)); return prgram.read(addrRAM(addr));
} }
if(addr & 0x8000) { if(addr & 0x8000) {
addr = mmc1.prg_addr(addr); addr = mmc1.addrPRG(addr);
if(revision == Revision::SXROM) { if(revision == Revision::SXROM) {
addr |= ((mmc1.chr_bank[0] & 0x10) >> 4) << 18; addr |= ((mmc1.chrBank[0] & 0x10) >> 4) << 18;
} }
return prgrom.read(addr); return prgrom.read(addr);
} }
@ -35,26 +35,26 @@ struct NES_SxROM : Board {
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xe000) == 0x6000) { if((addr & 0xe000) == 0x6000) {
if(revision == Revision::SNROM) { if(revision == Revision::SNROM) {
if(mmc1.chr_bank[0] & 0x10) return; if(mmc1.chrBank[0] & 0x10) return;
} }
if(mmc1.ram_disable) return; if(mmc1.ramDisable) return;
return prgram.write(ram_addr(addr), data); 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 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(mmc1.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(mmc1.addrCIRAM(addr));
return Board::chr_read(mmc1.chr_addr(addr)); return Board::readCHR(mmc1.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(mmc1.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(mmc1.addrCIRAM(addr), data);
return Board::chr_write(mmc1.chr_addr(addr), data); return Board::writeCHR(mmc1.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -7,27 +7,27 @@ struct NES_TxROM : Board {
mmc3.main(); mmc3.main();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if((addr & 0xe000) == 0x6000) return mmc3.ram_read(addr); if((addr & 0xe000) == 0x6000) return mmc3.readRAM(addr);
if(addr & 0x8000) return prgrom.read(mmc3.prg_addr(addr)); if(addr & 0x8000) return prgrom.read(mmc3.addrPRG(addr));
return cpu.mdr(); return cpu.mdr();
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data); if((addr & 0xe000) == 0x6000) return mmc3.writeRAM(addr, data);
if(addr & 0x8000) return mmc3.reg_write(addr, data); if(addr & 0x8000) return mmc3.writeIO(addr, data);
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
mmc3.irq_test(addr); mmc3.irqTest(addr);
if(addr & 0x2000) return ppu.readCIRAM(mmc3.ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(mmc3.addrCIRAM(addr));
return Board::chr_read(mmc3.chr_addr(addr)); return Board::readCHR(mmc3.addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
mmc3.irq_test(addr); mmc3.irqTest(addr);
if(addr & 0x2000) return ppu.writeCIRAM(mmc3.ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(mmc3.addrCIRAM(addr), data);
return Board::chr_write(mmc3.chr_addr(addr), data); return Board::writeCHR(mmc3.addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {

View File

@ -6,48 +6,48 @@ struct NES_UxROM : Board {
settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0; settings.mirror = document["board/mirror/mode"].text() == "vertical" ? 1 : 0;
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if((addr & 0xc000) == 0x8000) return prgrom.read((prg_bank << 14) | (addr & 0x3fff)); if((addr & 0xc000) == 0x8000) return prgrom.read((prgBank << 14) | (addr & 0x3fff));
if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff)); if((addr & 0xc000) == 0xc000) return prgrom.read(( 0x0f << 14) | (addr & 0x3fff));
return cpu.mdr(); 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; if(addr & 0x8000) prgBank = data & 0x0f;
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) { if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr); 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(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr, data); return ppu.writeCIRAM(addr, data);
} }
return Board::chr_write(addr, data); return Board::writeCHR(addr, data);
} }
auto power() -> void { auto power() -> void {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(prg_bank); s.integer(prgBank);
} }
struct Settings { struct Settings {
bool mirror; //0 = horizontal, 1 = vertical bool mirror; //0 = horizontal, 1 = vertical
} settings; } settings;
uint4 prg_bank; uint4 prgBank;
}; };

View File

@ -44,9 +44,9 @@ struct Sunsoft5B : Board {
} pulse[3]; } pulse[3];
auto main() -> void { auto main() -> void {
if(irq_counter_enable) { if(irqCounterEnable) {
if(--irq_counter == 0xffff) { if(--irqCounter == 0xffff) {
cpu.irqLine(irq_enable); cpu.irqLine(irqEnable);
} }
} }
@ -54,26 +54,26 @@ struct Sunsoft5B : Board {
pulse[1].clock(); pulse[1].clock();
pulse[2].clock(); pulse[2].clock();
int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output]; int16 output = dac[pulse[0].output] + dac[pulse[1].output] + dac[pulse[2].output];
apu.set_sample(-output); apu.setSample(-output);
tick(); tick();
} }
auto prg_read(uint addr) -> uint8 { auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr(); if(addr < 0x6000) return cpu.mdr();
uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000 uint8 bank = 0x3f; //((addr & 0xe000) == 0xe000
if((addr & 0xe000) == 0x6000) bank = prg_bank[0]; if((addr & 0xe000) == 0x6000) bank = prgBank[0];
if((addr & 0xe000) == 0x8000) bank = prg_bank[1]; if((addr & 0xe000) == 0x8000) bank = prgBank[1];
if((addr & 0xe000) == 0xa000) bank = prg_bank[2]; if((addr & 0xe000) == 0xa000) bank = prgBank[2];
if((addr & 0xe000) == 0xc000) bank = prg_bank[3]; if((addr & 0xe000) == 0xc000) bank = prgBank[3];
bool ram_enable = bank & 0x80; bool ramEnable = bank & 0x80;
bool ram_select = bank & 0x40; bool ramSelect = bank & 0x40;
bank &= 0x3f; bank &= 0x3f;
if(ram_select) { if(ramSelect) {
if(ram_enable == false) return cpu.mdr(); if(!ramEnable) return cpu.mdr();
return prgram.data[addr & 0x1fff]; return prgram.data[addr & 0x1fff];
} }
@ -81,46 +81,46 @@ struct Sunsoft5B : Board {
return prgrom.read(addr); return prgrom.read(addr);
} }
auto prg_write(uint addr, uint8 data) -> void { auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xe000) == 0x6000) { if((addr & 0xe000) == 0x6000) {
prgram.data[addr & 0x1fff] = data; prgram.data[addr & 0x1fff] = data;
} }
if(addr == 0x8000) { if(addr == 0x8000) {
mmu_port = data & 0x0f; mmuPort = data & 0x0f;
} }
if(addr == 0xa000) { if(addr == 0xa000) {
switch(mmu_port) { switch(mmuPort) {
case 0: chr_bank[0] = data; break; case 0: chrBank[0] = data; break;
case 1: chr_bank[1] = data; break; case 1: chrBank[1] = data; break;
case 2: chr_bank[2] = data; break; case 2: chrBank[2] = data; break;
case 3: chr_bank[3] = data; break; case 3: chrBank[3] = data; break;
case 4: chr_bank[4] = data; break; case 4: chrBank[4] = data; break;
case 5: chr_bank[5] = data; break; case 5: chrBank[5] = data; break;
case 6: chr_bank[6] = data; break; case 6: chrBank[6] = data; break;
case 7: chr_bank[7] = data; break; case 7: chrBank[7] = data; break;
case 8: prg_bank[0] = data; break; case 8: prgBank[0] = data; break;
case 9: prg_bank[1] = data; break; case 9: prgBank[1] = data; break;
case 10: prg_bank[2] = data; break; case 10: prgBank[2] = data; break;
case 11: prg_bank[3] = data; break; case 11: prgBank[3] = data; break;
case 12: mirror = data & 3; break; case 12: mirror = data & 3; break;
case 13: case 13:
irq_enable = data & 0x80; irqEnable = data & 0x80;
irq_counter_enable = data & 0x01; irqCounterEnable = data & 0x01;
if(irq_enable == 0) cpu.irqLine(0); if(irqEnable == 0) cpu.irqLine(0);
break; break;
case 14: irq_counter = (irq_counter & 0xff00) | (data << 0); break; case 14: irqCounter = (irqCounter & 0xff00) | (data << 0); break;
case 15: irq_counter = (irq_counter & 0x00ff) | (data << 8); break; case 15: irqCounter = (irqCounter & 0x00ff) | (data << 8); break;
} }
} }
if(addr == 0xc000) { if(addr == 0xc000) {
apu_port = data & 0x0f; apuPort = data & 0x0f;
} }
if(addr == 0xe000) { if(addr == 0xe000) {
switch(apu_port) { switch(apuPort) {
case 0: pulse[0].frequency = (pulse[0].frequency & 0xff00) | (data << 0); break; 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 1: pulse[0].frequency = (pulse[0].frequency & 0x00ff) | (data << 8); break;
case 2: pulse[1].frequency = (pulse[1].frequency & 0xff00) | (data << 0); 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; 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) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal
@ -153,14 +153,14 @@ struct Sunsoft5B : Board {
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(ciram_addr(addr)); if(addr & 0x2000) return ppu.readCIRAM(addrCIRAM(addr));
return Board::chr_read(chr_addr(addr)); return Board::readCHR(addrCHR(addr));
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(ciram_addr(addr), data); if(addr & 0x2000) return ppu.writeCIRAM(addrCIRAM(addr), data);
return Board::chr_write(chr_addr(addr), data); return Board::writeCHR(addrCHR(addr), data);
} }
auto power() -> void { auto power() -> void {
@ -171,15 +171,15 @@ struct Sunsoft5B : Board {
} }
auto reset() -> void { auto reset() -> void {
mmu_port = 0; mmuPort = 0;
apu_port = 0; apuPort = 0;
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
for(auto& n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
mirror = 0; mirror = 0;
irq_enable = 0; irqEnable = 0;
irq_counter_enable = 0; irqCounterEnable = 0;
irq_counter = 0; irqCounter = 0;
pulse[0].reset(); pulse[0].reset();
pulse[1].reset(); pulse[1].reset();
@ -189,30 +189,30 @@ struct Sunsoft5B : Board {
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
Board::serialize(s); Board::serialize(s);
s.integer(mmu_port); s.integer(mmuPort);
s.integer(apu_port); s.integer(apuPort);
s.array(prg_bank); s.array(prgBank);
s.array(chr_bank); s.array(chrBank);
s.integer(mirror); s.integer(mirror);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_counter_enable); s.integer(irqCounterEnable);
s.integer(irq_counter); s.integer(irqCounter);
pulse[0].serialize(s); pulse[0].serialize(s);
pulse[1].serialize(s); pulse[1].serialize(s);
pulse[2].serialize(s); pulse[2].serialize(s);
} }
uint4 mmu_port; uint4 mmuPort;
uint4 apu_port; uint4 apuPort;
uint8 prg_bank[4]; uint8 prgBank[4];
uint8 chr_bank[8]; uint8 chrBank[8];
uint2 mirror; uint2 mirror;
bool irq_enable; bool irqEnable;
bool irq_counter_enable; bool irqCounterEnable;
uint16 irq_counter; uint16 irqCounter;
int16 dac[16]; int16 dac[16];
}; };

View File

@ -54,19 +54,19 @@ auto Cartridge::reset() -> void {
} }
auto Cartridge::readPRG(uint addr) -> uint8 { auto Cartridge::readPRG(uint addr) -> uint8 {
return board->prg_read(addr); return board->readPRG(addr);
} }
auto Cartridge::writePRG(uint addr, uint8 data) -> void { 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 { auto Cartridge::readCHR(uint addr) -> uint8 {
return board->chr_read(addr); return board->readCHR(addr);
} }
auto Cartridge::writeCHR(uint addr, uint8 data) -> void { 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 { auto Cartridge::scanline(uint y) -> void {

View File

@ -8,26 +8,26 @@ struct MMC1 : Chip {
tick(); tick();
} }
auto prg_addr(uint addr) -> uint { auto addrPRG(uint addr) -> uint {
bool region = addr & 0x4000; 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); bank = (region == 0 ? 0x0 : 0xf);
if(region != prg_mode) bank = prg_bank; if(region != prgMode) bank = prgBank;
} }
return (bank << 14) | (addr & 0x3fff); return (bank << 14) | (addr & 0x3fff);
} }
auto chr_addr(uint addr) -> uint { auto addrCHR(uint addr) -> uint {
bool region = addr & 0x1000; bool region = addr & 0x1000;
uint bank = chr_bank[region]; uint bank = chrBank[region];
if(chr_mode == 0) bank = (chr_bank[0] & ~1) | region; if(chrMode == 0) bank = (chrBank[0] & ~1) | region;
return (bank << 12) | (addr & 0x0fff); return (bank << 12) | (addr & 0x0fff);
} }
auto ciram_addr(uint addr) -> uint { auto addrCIRAM(uint addr) -> uint {
switch(mirror) { switch(mirror) {
case 0: return 0x0000 | (addr & 0x03ff); case 0: return 0x0000 | (addr & 0x03ff);
case 1: return 0x0400 | (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; if(writedelay) return;
writedelay = 2; writedelay = 2;
if(data & 0x80) { if(data & 0x80) {
shiftaddr = 0; shiftaddr = 0;
prg_size = 1; prgSize = 1;
prg_mode = 1; prgMode = 1;
} else { } else {
shiftdata = ((data & 1) << 4) | (shiftdata >> 1); shiftdata = ((data & 1) << 4) | (shiftdata >> 1);
if(++shiftaddr == 5) { if(++shiftaddr == 5) {
shiftaddr = 0; shiftaddr = 0;
switch((addr >> 13) & 3) { switch((addr >> 13) & 3) {
case 0: case 0:
chr_mode = (shiftdata & 0x10); chrMode = (shiftdata & 0x10);
prg_size = (shiftdata & 0x08); prgSize = (shiftdata & 0x08);
prg_mode = (shiftdata & 0x04); prgMode = (shiftdata & 0x04);
mirror = (shiftdata & 0x03); mirror = (shiftdata & 0x03);
break; break;
case 1: case 1:
chr_bank[0] = (shiftdata & 0x1f); chrBank[0] = (shiftdata & 0x1f);
break; break;
case 2: case 2:
chr_bank[1] = (shiftdata & 0x1f); chrBank[1] = (shiftdata & 0x1f);
break; break;
case 3: case 3:
ram_disable = (shiftdata & 0x10); ramDisable = (shiftdata & 0x10);
prg_bank = (shiftdata & 0x0f); prgBank = (shiftdata & 0x0f);
break; break;
} }
} }
@ -81,14 +81,14 @@ struct MMC1 : Chip {
shiftaddr = 0; shiftaddr = 0;
shiftdata = 0; shiftdata = 0;
chr_mode = 0; chrMode = 0;
prg_size = 1; prgSize = 1;
prg_mode = 1; prgMode = 1;
mirror = 0; mirror = 0;
chr_bank[0] = 0; chrBank[0] = 0;
chr_bank[1] = 1; chrBank[1] = 1;
ram_disable = 0; ramDisable = 0;
prg_bank = 0; prgBank = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
@ -96,13 +96,13 @@ struct MMC1 : Chip {
s.integer(shiftaddr); s.integer(shiftaddr);
s.integer(shiftdata); s.integer(shiftdata);
s.integer(chr_mode); s.integer(chrMode);
s.integer(prg_size); s.integer(prgSize);
s.integer(prg_mode); s.integer(prgMode);
s.integer(mirror); s.integer(mirror);
s.array(chr_bank); s.array(chrBank);
s.integer(ram_disable); s.integer(ramDisable);
s.integer(prg_bank); s.integer(prgBank);
} }
enum class Revision : uint { enum class Revision : uint {
@ -118,11 +118,11 @@ struct MMC1 : Chip {
uint shiftaddr; uint shiftaddr;
uint shiftdata; uint shiftdata;
bool chr_mode; bool chrMode;
bool prg_size; //0 = 32K, 1 = 16K bool prgSize; //0 = 32K, 1 = 16K
bool prg_mode; bool prgMode;
uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal
uint5 chr_bank[2]; uint5 chrBank[2];
bool ram_disable; bool ramDisable;
uint4 prg_bank; uint4 prgBank;
}; };

View File

@ -3,90 +3,90 @@ struct MMC3 : Chip {
} }
auto main() -> void { auto main() -> void {
if(irq_delay) irq_delay--; if(irqDelay) irqDelay--;
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
tick(); tick();
} }
auto irq_test(uint addr) -> void { auto irqTest(uint addr) -> void {
if(!(chr_abus & 0x1000) && (addr & 0x1000)) { if(!(chrAbus & 0x1000) && (addr & 0x1000)) {
if(irq_delay == 0) { if(irqDelay == 0) {
if(irq_counter == 0) { if(irqCounter == 0) {
irq_counter = irq_latch; irqCounter = irqLatch;
} else if(--irq_counter == 0) { } else if(--irqCounter == 0) {
if(irq_enable) irq_line = 1; 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) { switch((addr >> 13) & 3) {
case 0: case 0:
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff); if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff); return (prgBank[0] << 13) | (addr & 0x1fff);
case 1: case 1:
return (prg_bank[1] << 13) | (addr & 0x1fff); return (prgBank[1] << 13) | (addr & 0x1fff);
case 2: case 2:
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff); if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff); return (prgBank[0] << 13) | (addr & 0x1fff);
case 3: case 3:
return (0x3f << 13) | (addr & 0x1fff); return (0x3f << 13) | (addr & 0x1fff);
} }
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
if(chr_mode == 0) { if(chrMode == 0) {
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff);
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff);
} else { } else {
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x1fff) return (chr_bank[1] << 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 == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
} }
auto ram_read(uint addr) -> uint8 { auto readRAM(uint addr) -> uint8 {
if(ram_enable) return board.prgram.data[addr & 0x1fff]; if(ramEnable) return board.prgram.data[addr & 0x1fff];
return 0x00; return 0x00;
} }
auto ram_write(uint addr, uint8 data) -> void { auto writeRAM(uint addr, uint8 data) -> void {
if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data; 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) { switch(addr & 0xe001) {
case 0x8000: case 0x8000:
chr_mode = data & 0x80; chrMode = data & 0x80;
prg_mode = data & 0x40; prgMode = data & 0x40;
bank_select = data & 0x07; bankSelect = data & 0x07;
break; break;
case 0x8001: case 0x8001:
switch(bank_select) { switch(bankSelect) {
case 0: chr_bank[0] = data & ~1; break; case 0: chrBank[0] = data & ~1; break;
case 1: chr_bank[1] = data & ~1; break; case 1: chrBank[1] = data & ~1; break;
case 2: chr_bank[2] = data; break; case 2: chrBank[2] = data; break;
case 3: chr_bank[3] = data; break; case 3: chrBank[3] = data; break;
case 4: chr_bank[4] = data; break; case 4: chrBank[4] = data; break;
case 5: chr_bank[5] = data; break; case 5: chrBank[5] = data; break;
case 6: prg_bank[0] = data & 0x3f; break; case 6: prgBank[0] = data & 0x3f; break;
case 7: prg_bank[1] = data & 0x3f; break; case 7: prgBank[1] = data & 0x3f; break;
} }
break; break;
@ -95,25 +95,25 @@ struct MMC3 : Chip {
break; break;
case 0xa001: case 0xa001:
ram_enable = data & 0x80; ramEnable = data & 0x80;
ram_write_protect = data & 0x40; ramWriteProtect = data & 0x40;
break; break;
case 0xc000: case 0xc000:
irq_latch = data; irqLatch = data;
break; break;
case 0xc001: case 0xc001:
irq_counter = 0; irqCounter = 0;
break; break;
case 0xe000: case 0xe000:
irq_enable = false; irqEnable = false;
irq_line = 0; irqLine = 0;
break; break;
case 0xe001: case 0xe001:
irq_enable = true; irqEnable = true;
break; break;
} }
} }
@ -122,60 +122,60 @@ struct MMC3 : Chip {
} }
auto reset() -> void { auto reset() -> void {
chr_mode = 0; chrMode = 0;
prg_mode = 0; prgMode = 0;
bank_select = 0; bankSelect = 0;
prg_bank[0] = 0; prgBank[0] = 0;
prg_bank[1] = 0; prgBank[1] = 0;
chr_bank[0] = 0; chrBank[0] = 0;
chr_bank[1] = 0; chrBank[1] = 0;
chr_bank[2] = 0; chrBank[2] = 0;
chr_bank[3] = 0; chrBank[3] = 0;
chr_bank[4] = 0; chrBank[4] = 0;
chr_bank[5] = 0; chrBank[5] = 0;
mirror = 0; mirror = 0;
ram_enable = 1; ramEnable = 1;
ram_write_protect = 0; ramWriteProtect = 0;
irq_latch = 0; irqLatch = 0;
irq_counter = 0; irqCounter = 0;
irq_enable = false; irqEnable = false;
irq_delay = 0; irqDelay = 0;
irq_line = 0; irqLine = 0;
chr_abus = 0; chrAbus = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.integer(chr_mode); s.integer(chrMode);
s.integer(prg_mode); s.integer(prgMode);
s.integer(bank_select); s.integer(bankSelect);
s.array(prg_bank); s.array(prgBank);
s.array(chr_bank); s.array(chrBank);
s.integer(mirror); s.integer(mirror);
s.integer(ram_enable); s.integer(ramEnable);
s.integer(ram_write_protect); s.integer(ramWriteProtect);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_delay); s.integer(irqDelay);
s.integer(irq_line); s.integer(irqLine);
s.integer(chr_abus); s.integer(chrAbus);
} }
bool chr_mode; bool chrMode;
bool prg_mode; bool prgMode;
uint3 bank_select; uint3 bankSelect;
uint8 prg_bank[2]; uint8 prgBank[2];
uint8 chr_bank[6]; uint8 chrBank[6];
bool mirror; bool mirror;
bool ram_enable; bool ramEnable;
bool ram_write_protect; bool ramWriteProtect;
uint8 irq_latch; uint8 irqLatch;
uint8 irq_counter; uint8 irqCounter;
bool irq_enable; bool irqEnable;
uint irq_delay; uint irqDelay;
bool irq_line; bool irqLine;
uint16 chr_abus; uint16 chrAbus;
}; };

View File

@ -5,9 +5,9 @@ struct MMC5 : Chip {
auto main() -> void { auto main() -> void {
//scanline() resets this; if no scanlines detected, enter video blanking period //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(); tick();
} }
@ -16,30 +16,30 @@ struct MMC5 : Chip {
//if(y != vcounter && y <= 240) print(y, " vs ", vcounter, "\n"); //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; uint bank;
if((addr & 0xe000) == 0x6000) { if((addr & 0xe000) == 0x6000) {
bank = (ram_select << 2) | ram_bank; bank = (ramSelect << 2) | ramBank;
addr &= 0x1fff; addr &= 0x1fff;
} else if(prg_mode == 0) { } else if(prgMode == 0) {
bank = prg_bank[3] & ~3; bank = prgBank[3] & ~3;
addr &= 0x7fff; addr &= 0x7fff;
} else if(prg_mode == 1) { } else if(prgMode == 1) {
if((addr & 0xc000) == 0x8000) bank = (prg_bank[1] & ~1); if((addr & 0xc000) == 0x8000) bank = (prgBank[1] & ~1);
if((addr & 0xe000) == 0xc000) bank = (prg_bank[3] & ~1); if((addr & 0xe000) == 0xc000) bank = (prgBank[3] & ~1);
addr &= 0x3fff; addr &= 0x3fff;
} else if(prg_mode == 2) { } else if(prgMode == 2) {
if((addr & 0xe000) == 0x8000) bank = (prg_bank[1] & ~1) | 0; if((addr & 0xe000) == 0x8000) bank = (prgBank[1] & ~1) | 0;
if((addr & 0xe000) == 0xa000) bank = (prg_bank[1] & ~1) | 1; if((addr & 0xe000) == 0xa000) bank = (prgBank[1] & ~1) | 1;
if((addr & 0xe000) == 0xc000) bank = (prg_bank[2]); if((addr & 0xe000) == 0xc000) bank = (prgBank[2]);
if((addr & 0xe000) == 0xe000) bank = (prg_bank[3]); if((addr & 0xe000) == 0xe000) bank = (prgBank[3]);
addr &= 0x1fff; addr &= 0x1fff;
} else if(prg_mode == 3) { } else if(prgMode == 3) {
if((addr & 0xe000) == 0x8000) bank = prg_bank[0]; if((addr & 0xe000) == 0x8000) bank = prgBank[0];
if((addr & 0xe000) == 0xa000) bank = prg_bank[1]; if((addr & 0xe000) == 0xa000) bank = prgBank[1];
if((addr & 0xe000) == 0xc000) bank = prg_bank[2]; if((addr & 0xe000) == 0xc000) bank = prgBank[2];
if((addr & 0xe000) == 0xe000) bank = prg_bank[3]; if((addr & 0xe000) == 0xe000) bank = prgBank[3];
addr &= 0x1fff; addr &= 0x1fff;
} }
@ -56,7 +56,7 @@ struct MMC5 : Chip {
if(rom) { if(rom) {
board.prgrom.write((bank << 13) | addr, data); board.prgrom.write((bank << 13) | addr, data);
} else { } 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); 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((addr & 0xfc00) == 0x5c00) {
if(exram_mode >= 2) return exram[addr & 0x03ff]; if(exramMode >= 2) return exram[addr & 0x03ff];
return cpu.mdr(); return cpu.mdr();
} }
if(addr >= 0x6000) { if(addr >= 0x6000) {
return prg_access(0, addr); return accessPRG(0, addr);
} }
switch(addr) { switch(addr) {
case 0x5204: { case 0x5204: {
uint8 result = (irq_pending << 7) | (in_frame << 6); uint8 result = (irqPending << 7) | (inFrame << 6);
irq_pending = false; irqPending = false;
return result; return result;
} }
case 0x5205: return (multiplier * multiplicand) >> 0; 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) { if((addr & 0xfc00) == 0x5c00) {
//writes 0x00 *during* Vblank (not during screen rendering ...) //writes 0x00 *during* Vblank (not during screen rendering ...)
if(exram_mode == 0 || exram_mode == 1) exram[addr & 0x03ff] = in_frame ? data : (uint8)0x00; if(exramMode == 0 || exramMode == 1) exram[addr & 0x03ff] = inFrame ? data : (uint8)0x00;
if(exram_mode == 2) exram[addr & 0x03ff] = data; if(exramMode == 2) exram[addr & 0x03ff] = data;
return; return;
} }
if(addr >= 0x6000) { if(addr >= 0x6000) {
prg_access(1, addr, data); accessPRG(1, addr, data);
return; return;
} }
switch(addr) { switch(addr) {
case 0x2000: case 0x2000:
sprite_8x16 = data & 0x20; sprite8x16 = data & 0x20;
break; break;
case 0x2001: case 0x2001:
@ -108,81 +108,81 @@ struct MMC5 : Chip {
if((data & 0x18) == 0) blank(); if((data & 0x18) == 0) blank();
break; break;
case 0x5100: prg_mode = data & 3; break; case 0x5100: prgMode = data & 3; break;
case 0x5101: chr_mode = data & 3; break; case 0x5101: chrMode = data & 3; break;
case 0x5102: prgram_write_protect[0] = data & 3; break; case 0x5102: prgramWriteProtect[0] = data & 3; break;
case 0x5103: prgram_write_protect[1] = data & 3; break; case 0x5103: prgramWriteProtect[1] = data & 3; break;
case 0x5104: case 0x5104:
exram_mode = data & 3; exramMode = data & 3;
break; break;
case 0x5105: case 0x5105:
nametable_mode[0] = (data & 0x03) >> 0; nametableMode[0] = (data & 0x03) >> 0;
nametable_mode[1] = (data & 0x0c) >> 2; nametableMode[1] = (data & 0x0c) >> 2;
nametable_mode[2] = (data & 0x30) >> 4; nametableMode[2] = (data & 0x30) >> 4;
nametable_mode[3] = (data & 0xc0) >> 6; nametableMode[3] = (data & 0xc0) >> 6;
break; break;
case 0x5106: case 0x5106:
fillmode_tile = data; fillmodeTile = data;
break; break;
case 0x5107: case 0x5107:
fillmode_color = data & 3; fillmodeColor = data & 3;
fillmode_color |= fillmode_color << 2; fillmodeColor |= fillmodeColor << 2;
fillmode_color |= fillmode_color << 4; fillmodeColor |= fillmodeColor << 4;
break; break;
case 0x5113: case 0x5113:
ram_select = data & 0x04; ramSelect = data & 0x04;
ram_bank = data & 0x03; ramBank = data & 0x03;
break; break;
case 0x5114: prg_bank[0] = data; break; case 0x5114: prgBank[0] = data; break;
case 0x5115: prg_bank[1] = data; break; case 0x5115: prgBank[1] = data; break;
case 0x5116: prg_bank[2] = data; break; case 0x5116: prgBank[2] = data; break;
case 0x5117: prg_bank[3] = data | 0x80; break; case 0x5117: prgBank[3] = data | 0x80; break;
case 0x5120: chr_sprite_bank[0] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5120: chrSpriteBank[0] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5121: chr_sprite_bank[1] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5121: chrSpriteBank[1] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5122: chr_sprite_bank[2] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5122: chrSpriteBank[2] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5123: chr_sprite_bank[3] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5123: chrSpriteBank[3] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5124: chr_sprite_bank[4] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5124: chrSpriteBank[4] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5125: chr_sprite_bank[5] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5125: chrSpriteBank[5] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5126: chr_sprite_bank[6] = (chr_bank_hi << 8) | data; chr_active = 0; break; case 0x5126: chrSpriteBank[6] = (chrBankHi << 8) | data; chrActive = 0; break;
case 0x5127: chr_sprite_bank[7] = (chr_bank_hi << 8) | data; chr_active = 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 0x5128: chrBGBank[0] = (chrBankHi << 8) | data; chrActive = 1; break;
case 0x5129: chr_bg_bank[1] = (chr_bank_hi << 8) | data; chr_active = 1; break; case 0x5129: chrBGBank[1] = (chrBankHi << 8) | data; chrActive = 1; break;
case 0x512a: chr_bg_bank[2] = (chr_bank_hi << 8) | data; chr_active = 1; break; case 0x512a: chrBGBank[2] = (chrBankHi << 8) | data; chrActive = 1; break;
case 0x512b: chr_bg_bank[3] = (chr_bank_hi << 8) | data; chr_active = 1; break; case 0x512b: chrBGBank[3] = (chrBankHi << 8) | data; chrActive = 1; break;
case 0x5130: case 0x5130:
chr_bank_hi = data & 3; chrBankHi = data & 3;
break; break;
case 0x5200: case 0x5200:
vs_enable = data & 0x80; vsEnable = data & 0x80;
vs_side = data & 0x40; vsSide = data & 0x40;
vs_tile = data & 0x1f; vsTile = data & 0x1f;
break; break;
case 0x5201: case 0x5201:
vs_scroll = data; vsScroll = data;
break; break;
case 0x5202: case 0x5202:
vs_bank = data; vsBank = data;
break; break;
case 0x5203: case 0x5203:
irq_line = data; irqLine = data;
break; break;
case 0x5204: case 0x5204:
irq_enable = data & 0x80; irqEnable = data & 0x80;
break; break;
case 0x5205: case 0x5205:
@ -195,138 +195,138 @@ struct MMC5 : Chip {
} }
} }
auto chr_sprite_addr(uint addr) -> uint { auto chrSpriteAddr(uint addr) -> uint {
if(chr_mode == 0) { if(chrMode == 0) {
auto bank = chr_sprite_bank[7]; auto bank = chrSpriteBank[7];
return (bank * 0x2000) + (addr & 0x1fff); return (bank * 0x2000) + (addr & 0x1fff);
} }
if(chr_mode == 1) { if(chrMode == 1) {
auto bank = chr_sprite_bank[(addr / 0x1000) * 4 + 3]; auto bank = chrSpriteBank[(addr / 0x1000) * 4 + 3];
return (bank * 0x1000) + (addr & 0x0fff); return (bank * 0x1000) + (addr & 0x0fff);
} }
if(chr_mode == 2) { if(chrMode == 2) {
auto bank = chr_sprite_bank[(addr / 0x0800) * 2 + 1]; auto bank = chrSpriteBank[(addr / 0x0800) * 2 + 1];
return (bank * 0x0800) + (addr & 0x07ff); return (bank * 0x0800) + (addr & 0x07ff);
} }
if(chr_mode == 3) { if(chrMode == 3) {
auto bank = chr_sprite_bank[(addr / 0x0400)]; auto bank = chrSpriteBank[(addr / 0x0400)];
return (bank * 0x0400) + (addr & 0x03ff); return (bank * 0x0400) + (addr & 0x03ff);
} }
} }
auto chr_bg_addr(uint addr) -> uint { auto chrBGAddr(uint addr) -> uint {
addr &= 0x0fff; addr &= 0x0fff;
if(chr_mode == 0) { if(chrMode == 0) {
auto bank = chr_bg_bank[3]; auto bank = chrBGBank[3];
return (bank * 0x2000) + (addr & 0x0fff); return (bank * 0x2000) + (addr & 0x0fff);
} }
if(chr_mode == 1) { if(chrMode == 1) {
auto bank = chr_bg_bank[3]; auto bank = chrBGBank[3];
return (bank * 0x1000) + (addr & 0x0fff); return (bank * 0x1000) + (addr & 0x0fff);
} }
if(chr_mode == 2) { if(chrMode == 2) {
auto bank = chr_bg_bank[(addr / 0x0800) * 2 + 1]; auto bank = chrBGBank[(addr / 0x0800) * 2 + 1];
return (bank * 0x0800) + (addr & 0x07ff); return (bank * 0x0800) + (addr & 0x07ff);
} }
if(chr_mode == 3) { if(chrMode == 3) {
auto bank = chr_bg_bank[(addr / 0x0400)]; auto bank = chrBGBank[(addr / 0x0400)];
return (bank * 0x0400) + (addr & 0x03ff); return (bank * 0x0400) + (addr & 0x03ff);
} }
} }
auto chr_vs_addr(uint addr) -> uint { auto chrVSAddr(uint addr) -> uint {
return (vs_bank * 0x1000) + (addr & 0x0ff8) + (vs_vpos & 7); return (vsBank * 0x1000) + (addr & 0x0ff8) + (vsVpos & 7);
} }
auto blank() -> void { auto blank() -> void {
in_frame = false; inFrame = false;
} }
auto scanline() -> void { auto scanline() -> void {
hcounter = 0; hcounter = 0;
if(in_frame == false) { if(inFrame == false) {
in_frame = true; inFrame = true;
irq_pending = false; irqPending = false;
vcounter = 0; vcounter = 0;
} else { } else {
if(vcounter == irq_line) irq_pending = true; if(vcounter == irqLine) irqPending = true;
vcounter++; vcounter++;
} }
cpu_cycle_counter = 0; cpuCycleCounter = 0;
} }
auto ciram_read(uint addr) -> uint8 { auto readCIRAM(uint addr) -> uint8 {
if(vs_fetch && (hcounter & 2) == 0) return exram[vs_vpos / 8 * 32 + vs_hpos / 8]; if(vsFetch && (hcounter & 2) == 0) return exram[vsVpos / 8 * 32 + vsHpos / 8];
if(vs_fetch && (hcounter & 2) != 0) return exram[vs_vpos / 32 * 8 + vs_hpos / 32 + 0x03c0]; 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 0: return ppu.readCIRAM(0x0000 | (addr & 0x03ff));
case 1: return ppu.readCIRAM(0x0400 | (addr & 0x03ff)); case 1: return ppu.readCIRAM(0x0400 | (addr & 0x03ff));
case 2: return exram_mode < 2 ? exram[addr & 0x03ff] : (uint8)0x00; case 2: return exramMode < 2 ? exram[addr & 0x03ff] : (uint8)0x00;
case 3: return (hcounter & 2) == 0 ? fillmode_tile : fillmode_color; case 3: return (hcounter & 2) == 0 ? fillmodeTile : fillmodeColor;
} }
} }
auto chr_read(uint addr) -> uint8 { auto readCHR(uint addr) -> uint8 {
chr_access[0] = chr_access[1]; chrAccess[0] = chrAccess[1];
chr_access[1] = chr_access[2]; chrAccess[1] = chrAccess[2];
chr_access[2] = chr_access[3]; chrAccess[2] = chrAccess[3];
chr_access[3] = addr; chrAccess[3] = addr;
//detect two unused nametable fetches at end of each scanline //detect two unused nametable fetches at end of each scanline
if((chr_access[0] & 0x2000) == 0 if((chrAccess[0] & 0x2000) == 0
&& (chr_access[1] & 0x2000) && (chrAccess[1] & 0x2000)
&& (chr_access[2] & 0x2000) && (chrAccess[2] & 0x2000)
&& (chr_access[3] & 0x2000)) scanline(); && (chrAccess[3] & 0x2000)) scanline();
if(in_frame == false) { if(inFrame == false) {
vs_fetch = false; vsFetch = false;
if(addr & 0x2000) return ciram_read(addr); if(addr & 0x2000) return readCIRAM(addr);
return board.chrrom.read(chr_active ? chr_bg_addr(addr) : chr_sprite_addr(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; uint8 result = 0x00;
if((hcounter & 7) == 0) { if((hcounter & 7) == 0) {
vs_hpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16; vsHpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16;
vs_vpos = vcounter + vs_scroll; vsVpos = vcounter + vsScroll;
vs_fetch = vs_enable && bg_fetch && exram_mode < 2 vsFetch = vsEnable && bgFetch && exramMode < 2
&& (vs_side ? vs_hpos / 8 >= vs_tile : vs_hpos / 8 < vs_tile); && (vsSide ? vsHpos / 8 >= vsTile : vsHpos / 8 < vsTile);
if(vs_vpos >= 240) vs_vpos -= 240; 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 = exram[addr & 0x03ff] >> 6;
exattr |= exattr << 2; exattr |= exattr << 2;
exattr |= exattr << 4; exattr |= exattr << 4;
} else if((hcounter & 7) == 2) { } else if((hcounter & 7) == 2) {
result = ciram_read(addr); result = readCIRAM(addr);
if(bg_fetch && exram_mode == 1) result = exattr; if(bgFetch && exramMode == 1) result = exattr;
} else { } else {
if(vs_fetch) result = board.chrrom.read(chr_vs_addr(addr)); if(vsFetch) result = board.chrrom.read(chrVSAddr(addr));
else if(sprite_8x16 ? bg_fetch : chr_active) result = board.chrrom.read(chr_bg_addr(addr)); else if(sprite8x16 ? bgFetch : chrActive) result = board.chrrom.read(chrBGAddr(addr));
else result = board.chrrom.read(chr_sprite_addr(addr)); else result = board.chrrom.read(chrSpriteAddr(addr));
if(bg_fetch && exram_mode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff)); if(bgFetch && exramMode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff));
} }
hcounter += 2; hcounter += 2;
return result; return result;
} }
auto chr_write(uint addr, uint8 data) -> void { auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) { if(addr & 0x2000) {
switch(nametable_mode[(addr >> 10) & 3]) { switch(nametableMode[(addr >> 10) & 3]) {
case 0: return ppu.writeCIRAM(0x0000 | (addr & 0x03ff), data); case 0: return ppu.writeCIRAM(0x0000 | (addr & 0x03ff), data);
case 1: return ppu.writeCIRAM(0x0400 | (addr & 0x03ff), data); case 1: return ppu.writeCIRAM(0x0400 | (addr & 0x03ff), data);
case 2: exram[addr & 0x03ff] = data; break; case 2: exram[addr & 0x03ff] = data; break;
@ -340,93 +340,93 @@ struct MMC5 : Chip {
auto reset() -> void { auto reset() -> void {
for(auto& n : exram) n = 0xff; for(auto& n : exram) n = 0xff;
prg_mode = 3; prgMode = 3;
chr_mode = 0; chrMode = 0;
for(auto& n : prgram_write_protect) n = 0; for(auto& n : prgramWriteProtect) n = 0;
exram_mode = 0; exramMode = 0;
for(auto& n : nametable_mode) n = 0; for(auto& n : nametableMode) n = 0;
fillmode_tile = 0; fillmodeTile = 0;
fillmode_color = 0; fillmodeColor = 0;
ram_select = 0; ramSelect = 0;
ram_bank = 0; ramBank = 0;
prg_bank[0] = 0x00; prgBank[0] = 0x00;
prg_bank[1] = 0x00; prgBank[1] = 0x00;
prg_bank[2] = 0x00; prgBank[2] = 0x00;
prg_bank[3] = 0xff; prgBank[3] = 0xff;
for(auto& n : chr_sprite_bank) n = 0; for(auto& n : chrSpriteBank) n = 0;
for(auto& n : chr_bg_bank) n = 0; for(auto& n : chrBGBank) n = 0;
chr_bank_hi = 0; chrBankHi = 0;
vs_enable = 0; vsEnable = 0;
vs_side = 0; vsSide = 0;
vs_tile = 0; vsTile = 0;
vs_scroll = 0; vsScroll = 0;
vs_bank = 0; vsBank = 0;
irq_line = 0; irqLine = 0;
irq_enable = 0; irqEnable = 0;
multiplicand = 0; multiplicand = 0;
multiplier = 0; multiplier = 0;
cpu_cycle_counter = 0; cpuCycleCounter = 0;
irq_counter = 0; irqCounter = 0;
irq_pending = 0; irqPending = 0;
in_frame = 0; inFrame = 0;
vcounter = 0; vcounter = 0;
hcounter = 0; hcounter = 0;
for(auto& n : chr_access) n = 0; for(auto& n : chrAccess) n = 0;
chr_active = 0; chrActive = 0;
sprite_8x16 = 0; sprite8x16 = 0;
exbank = 0; exbank = 0;
exattr = 0; exattr = 0;
vs_fetch = 0; vsFetch = 0;
vs_vpos = 0; vsVpos = 0;
vs_hpos = 0; vsHpos = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.array(exram); s.array(exram);
s.integer(prg_mode); s.integer(prgMode);
s.integer(chr_mode); s.integer(chrMode);
for(auto& n : prgram_write_protect) s.integer(n); for(auto& n : prgramWriteProtect) s.integer(n);
s.integer(exram_mode); s.integer(exramMode);
for(auto& n : nametable_mode) s.integer(n); for(auto& n : nametableMode) s.integer(n);
s.integer(fillmode_tile); s.integer(fillmodeTile);
s.integer(fillmode_color); s.integer(fillmodeColor);
s.integer(ram_select); s.integer(ramSelect);
s.integer(ram_bank); s.integer(ramBank);
for(auto& n : prg_bank) s.integer(n); for(auto& n : prgBank) s.integer(n);
for(auto& n : chr_sprite_bank) s.integer(n); for(auto& n : chrSpriteBank) s.integer(n);
for(auto& n : chr_bg_bank) s.integer(n); for(auto& n : chrBGBank) s.integer(n);
s.integer(chr_bank_hi); s.integer(chrBankHi);
s.integer(vs_enable); s.integer(vsEnable);
s.integer(vs_side); s.integer(vsSide);
s.integer(vs_tile); s.integer(vsTile);
s.integer(vs_scroll); s.integer(vsScroll);
s.integer(vs_bank); s.integer(vsBank);
s.integer(irq_line); s.integer(irqLine);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(multiplicand); s.integer(multiplicand);
s.integer(multiplier); s.integer(multiplier);
s.integer(cpu_cycle_counter); s.integer(cpuCycleCounter);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_pending); s.integer(irqPending);
s.integer(in_frame); s.integer(inFrame);
s.integer(vcounter); s.integer(vcounter);
s.integer(hcounter); s.integer(hcounter);
for(auto& n : chr_access) s.integer(n); for(auto& n : chrAccess) s.integer(n);
s.integer(chr_active); s.integer(chrActive);
s.integer(sprite_8x16); s.integer(sprite8x16);
s.integer(exbank); s.integer(exbank);
s.integer(exattr); s.integer(exattr);
s.integer(vs_fetch); s.integer(vsFetch);
s.integer(vs_vpos); s.integer(vsVpos);
s.integer(vs_hpos); s.integer(vsHpos);
} }
enum class Revision : uint { enum class Revision : uint {
@ -438,52 +438,52 @@ struct MMC5 : Chip {
//programmable registers //programmable registers
uint2 prg_mode; //$5100 uint2 prgMode; //$5100
uint2 chr_mode; //$5101 uint2 chrMode; //$5101
uint2 prgram_write_protect[2]; //$5102,$5103 uint2 prgramWriteProtect[2]; //$5102,$5103
uint2 exram_mode; //$5104 uint2 exramMode; //$5104
uint2 nametable_mode[4]; //$5105 uint2 nametableMode[4]; //$5105
uint8 fillmode_tile; //$5106 uint8 fillmodeTile; //$5106
uint8 fillmode_color; //$5107 uint8 fillmodeColor; //$5107
bool ram_select; //$5113 bool ramSelect; //$5113
uint2 ram_bank; //$5113 uint2 ramBank; //$5113
uint8 prg_bank[4]; //$5114-5117 uint8 prgBank[4]; //$5114-5117
uint10 chr_sprite_bank[8]; //$5120-5127 uint10 chrSpriteBank[8]; //$5120-5127
uint10 chr_bg_bank[4]; //$5128-512b uint10 chrBGBank[4]; //$5128-512b
uint2 chr_bank_hi; //$5130 uint2 chrBankHi; //$5130
bool vs_enable; //$5200 bool vsEnable; //$5200
bool vs_side; //$5200 bool vsSide; //$5200
uint5 vs_tile; //$5200 uint5 vsTile; //$5200
uint8 vs_scroll; //$5201 uint8 vsScroll; //$5201
uint8 vs_bank; //$5202 uint8 vsBank; //$5202
uint8 irq_line; //$5203 uint8 irqLine; //$5203
bool irq_enable; //$5204 bool irqEnable; //$5204
uint8 multiplicand; //$5205 uint8 multiplicand; //$5205
uint8 multiplier; //$5206 uint8 multiplier; //$5206
//status registers //status registers
uint cpu_cycle_counter; uint cpuCycleCounter;
uint irq_counter; uint irqCounter;
bool irq_pending; bool irqPending;
bool in_frame; bool inFrame;
uint vcounter; uint vcounter;
uint hcounter; uint hcounter;
uint16 chr_access[4]; uint16 chrAccess[4];
bool chr_active; bool chrActive;
bool sprite_8x16; bool sprite8x16;
uint8 exbank; uint8 exbank;
uint8 exattr; uint8 exattr;
bool vs_fetch; bool vsFetch;
uint8 vs_vpos; uint8 vsVpos;
uint8 vs_hpos; uint8 vsHpos;
}; };

View File

@ -3,101 +3,101 @@ struct MMC6 : Chip {
} }
auto main() -> void { auto main() -> void {
if(irq_delay) irq_delay--; if(irqDelay) irqDelay--;
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
tick(); tick();
} }
auto irq_test(uint addr) -> void { auto irqTest(uint addr) -> void {
if(!(chr_abus & 0x1000) && (addr & 0x1000)) { if(!(chrAbus & 0x1000) && (addr & 0x1000)) {
if(irq_delay == 0) { if(irqDelay == 0) {
if(irq_counter == 0) { if(irqCounter == 0) {
irq_counter = irq_latch; irqCounter = irqLatch;
} else if(--irq_counter == 0) { } else if(--irqCounter == 0) {
if(irq_enable) irq_line = 1; 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) { switch((addr >> 13) & 3) {
case 0: case 0:
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff); if(prgMode == 1) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff); return (prgBank[0] << 13) | (addr & 0x1fff);
case 1: case 1:
return (prg_bank[1] << 13) | (addr & 0x1fff); return (prgBank[1] << 13) | (addr & 0x1fff);
case 2: case 2:
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff); if(prgMode == 0) return (0x3e << 13) | (addr & 0x1fff);
return (prg_bank[0] << 13) | (addr & 0x1fff); return (prgBank[0] << 13) | (addr & 0x1fff);
case 3: case 3:
return (0x3f << 13) | (addr & 0x1fff); return (0x3f << 13) | (addr & 0x1fff);
} }
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
if(chr_mode == 0) { if(chrMode == 0) {
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); if(addr <= 0x07ff) return (chrBank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); if(addr <= 0x0fff) return (chrBank[1] << 10) | (addr & 0x07ff);
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); if(addr <= 0x13ff) return (chrBank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); if(addr <= 0x17ff) return (chrBank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); if(addr <= 0x1bff) return (chrBank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); if(addr <= 0x1fff) return (chrBank[5] << 10) | (addr & 0x03ff);
} else { } else {
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); if(addr <= 0x03ff) return (chrBank[2] << 10) | (addr & 0x03ff);
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); if(addr <= 0x07ff) return (chrBank[3] << 10) | (addr & 0x03ff);
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); if(addr <= 0x0bff) return (chrBank[4] << 10) | (addr & 0x03ff);
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); if(addr <= 0x0fff) return (chrBank[5] << 10) | (addr & 0x03ff);
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); if(addr <= 0x17ff) return (chrBank[0] << 10) | (addr & 0x07ff);
if(addr <= 0x1fff) return (chr_bank[1] << 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 == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
} }
auto ram_read(uint addr) -> uint8 { auto readRAM(uint addr) -> uint8 {
if(ram_enable == false) return cpu.mdr(); if(ramEnable == false) return cpu.mdr();
if(ram_readable[0] == false && ram_readable[1] == false) return cpu.mdr(); if(ramReadable[0] == false && ramReadable[1] == false) return cpu.mdr();
bool region = addr & 0x0200; 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)); return board.prgram.read((region * 0x0200) + (addr & 0x01ff));
} }
auto ram_write(uint addr, uint8 data) -> void { auto writeRAM(uint addr, uint8 data) -> void {
if(ram_enable == false) return; if(ramEnable == false) return;
bool region = addr & 0x0200; bool region = addr & 0x0200;
if(ram_writable[region] == false) return; if(ramWritable[region] == false) return;
return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data); 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) { switch(addr & 0xe001) {
case 0x8000: case 0x8000:
chr_mode = data & 0x80; chrMode = data & 0x80;
prg_mode = data & 0x40; prgMode = data & 0x40;
ram_enable = data & 0x20; ramEnable = data & 0x20;
bank_select = data & 0x07; bankSelect = data & 0x07;
if(ram_enable == false) { if(ramEnable == false) {
for(auto &n : ram_readable) n = false; for(auto &n : ramReadable) n = false;
for(auto &n : ram_writable) n = false; for(auto &n : ramWritable) n = false;
} }
break; break;
case 0x8001: case 0x8001:
switch(bank_select) { switch(bankSelect) {
case 0: chr_bank[0] = data & ~1; break; case 0: chrBank[0] = data & ~1; break;
case 1: chr_bank[1] = data & ~1; break; case 1: chrBank[1] = data & ~1; break;
case 2: chr_bank[2] = data; break; case 2: chrBank[2] = data; break;
case 3: chr_bank[3] = data; break; case 3: chrBank[3] = data; break;
case 4: chr_bank[4] = data; break; case 4: chrBank[4] = data; break;
case 5: chr_bank[5] = data; break; case 5: chrBank[5] = data; break;
case 6: prg_bank[0] = data & 0x3f; break; case 6: prgBank[0] = data & 0x3f; break;
case 7: prg_bank[1] = data & 0x3f; break; case 7: prgBank[1] = data & 0x3f; break;
} }
break; break;
@ -106,28 +106,28 @@ struct MMC6 : Chip {
break; break;
case 0xa001: case 0xa001:
if(ram_enable == false) break; if(ramEnable == false) break;
ram_readable[1] = data & 0x80; ramReadable[1] = data & 0x80;
ram_writable[1] = data & 0x40; ramWritable[1] = data & 0x40;
ram_readable[0] = data & 0x20; ramReadable[0] = data & 0x20;
ram_writable[0] = data & 0x10; ramWritable[0] = data & 0x10;
break; break;
case 0xc000: case 0xc000:
irq_latch = data; irqLatch = data;
break; break;
case 0xc001: case 0xc001:
irq_counter = 0; irqCounter = 0;
break; break;
case 0xe000: case 0xe000:
irq_enable = false; irqEnable = false;
irq_line = 0; irqLine = 0;
break; break;
case 0xe001: case 0xe001:
irq_enable = true; irqEnable = true;
break; break;
} }
} }
@ -136,57 +136,57 @@ struct MMC6 : Chip {
} }
auto reset() -> void { auto reset() -> void {
chr_mode = 0; chrMode = 0;
prg_mode = 0; prgMode = 0;
ram_enable = 0; ramEnable = 0;
bank_select = 0; bankSelect = 0;
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
for(auto& n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
mirror = 0; mirror = 0;
for(auto& n : ram_readable) n = 0; for(auto& n : ramReadable) n = 0;
for(auto& n : ram_writable) n = 0; for(auto& n : ramWritable) n = 0;
irq_latch = 0; irqLatch = 0;
irq_counter = 0; irqCounter = 0;
irq_enable = 0; irqEnable = 0;
irq_delay = 0; irqDelay = 0;
irq_line = 0; irqLine = 0;
chr_abus = 0; chrAbus = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.integer(chr_mode); s.integer(chrMode);
s.integer(prg_mode); s.integer(prgMode);
s.integer(ram_enable); s.integer(ramEnable);
s.integer(bank_select); s.integer(bankSelect);
for(auto& n : prg_bank) s.integer(n); for(auto& n : prgBank) s.integer(n);
for(auto& n : chr_bank) s.integer(n); for(auto& n : chrBank) s.integer(n);
s.integer(mirror); s.integer(mirror);
for(auto& n : ram_readable) s.integer(n); for(auto& n : ramReadable) s.integer(n);
for(auto& n : ram_writable) s.integer(n); for(auto& n : ramWritable) s.integer(n);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_delay); s.integer(irqDelay);
s.integer(irq_line); s.integer(irqLine);
s.integer(chr_abus); s.integer(chrAbus);
} }
bool chr_mode; bool chrMode;
bool prg_mode; bool prgMode;
bool ram_enable; bool ramEnable;
uint3 bank_select; uint3 bankSelect;
uint8 prg_bank[2]; uint8 prgBank[2];
uint8 chr_bank[6]; uint8 chrBank[6];
bool mirror; bool mirror;
bool ram_readable[2]; bool ramReadable[2];
bool ram_writable[2]; bool ramWritable[2];
uint8 irq_latch; uint8 irqLatch;
uint8 irq_counter; uint8 irqCounter;
bool irq_enable; bool irqEnable;
uint irq_delay; uint irqDelay;
bool irq_line; bool irqLine;
uint16 chr_abus; uint16 chrAbus;
}; };

View File

@ -2,21 +2,21 @@ struct VRC1 : Chip {
VRC1(Board& board) : Chip(board) { VRC1(Board& board) : Chip(board) {
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
uint bank = 0x0f; uint bank = 0x0f;
if((addr & 0xe000) == 0x8000) bank = prg_bank[0]; if((addr & 0xe000) == 0x8000) bank = prgBank[0];
if((addr & 0xe000) == 0xa000) bank = prg_bank[1]; if((addr & 0xe000) == 0xa000) bank = prgBank[1];
if((addr & 0xe000) == 0xc000) bank = prg_bank[2]; if((addr & 0xe000) == 0xc000) bank = prgBank[2];
return (bank * 0x2000) + (addr & 0x1fff); return (bank * 0x2000) + (addr & 0x1fff);
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
uint bank = chr_banklo[(bool)(addr & 0x1000)]; uint bank = chrBankLo[(bool)(addr & 0x1000)];
bank |= chr_bankhi[(bool)(addr & 0x1000)] << 4; bank |= chrBankHi[(bool)(addr & 0x1000)] << 4;
return (bank * 0x1000) + (addr & 0x0fff); return (bank * 0x1000) + (addr & 0x0fff);
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
@ -24,32 +24,32 @@ struct VRC1 : Chip {
throw; throw;
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr & 0xf000) { switch(addr & 0xf000) {
case 0x8000: case 0x8000:
prg_bank[0] = data & 0x0f; prgBank[0] = data & 0x0f;
break; break;
case 0x9000: case 0x9000:
chr_bankhi[1] = data & 0x04; chrBankHi[1] = data & 0x04;
chr_bankhi[0] = data & 0x02; chrBankHi[0] = data & 0x02;
mirror = data & 0x01; mirror = data & 0x01;
break; break;
case 0xa000: case 0xa000:
prg_bank[1] = data & 0x0f; prgBank[1] = data & 0x0f;
break; break;
case 0xc000: case 0xc000:
prg_bank[2] = data & 0x0f; prgBank[2] = data & 0x0f;
break; break;
case 0xe000: case 0xe000:
chr_banklo[0] = data & 0x0f; chrBankLo[0] = data & 0x0f;
break; break;
case 0xf000: case 0xf000:
chr_banklo[1] = data & 0x0f; chrBankLo[1] = data & 0x0f;
break; break;
} }
} }
@ -58,21 +58,21 @@ struct VRC1 : Chip {
} }
auto reset() -> void { auto reset() -> void {
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
for(auto& n : chr_banklo) n = 0; for(auto& n : chrBankLo) n = 0;
for(auto& n : chr_bankhi) n = 0; for(auto& n : chrBankHi) n = 0;
mirror = 0; mirror = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
for(auto& n : prg_bank) s.integer(n); for(auto& n : prgBank) s.integer(n);
for(auto& n : chr_banklo) s.integer(n); for(auto& n : chrBankLo) s.integer(n);
for(auto& n : chr_bankhi) s.integer(n); for(auto& n : chrBankHi) s.integer(n);
s.integer(mirror); s.integer(mirror);
} }
uint4 prg_bank[3]; uint4 prgBank[3];
uint4 chr_banklo[2]; uint4 chrBankLo[2];
bool chr_bankhi[2]; bool chrBankHi[2];
bool mirror; bool mirror;
}; };

View File

@ -2,23 +2,23 @@ struct VRC2 : Chip {
VRC2(Board& board) : Chip(board) { VRC2(Board& board) : Chip(board) {
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
uint bank; uint bank;
switch(addr & 0xe000) { switch(addr & 0xe000) {
case 0x8000: bank = prg_bank[0]; break; case 0x8000: bank = prgBank[0]; break;
case 0xa000: bank = prg_bank[1]; break; case 0xa000: bank = prgBank[1]; break;
case 0xc000: bank = 0x1e; break; case 0xc000: bank = 0x1e; break;
case 0xe000: bank = 0x1f; break; case 0xe000: bank = 0x1f; break;
} }
return (bank * 0x2000) + (addr & 0x1fff); return (bank * 0x2000) + (addr & 0x1fff);
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
uint bank = chr_bank[addr / 0x0400]; uint bank = chrBank[addr / 0x0400];
return (bank * 0x0400) + (addr & 0x03ff); return (bank * 0x0400) + (addr & 0x03ff);
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
@ -28,7 +28,7 @@ struct VRC2 : Chip {
throw; throw;
} }
auto ram_read(uint addr) -> uint8 { auto readRAM(uint addr) -> uint8 {
if(board.prgram.size == 0) { if(board.prgram.size == 0) {
if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch; if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch;
return cpu.mdr(); return cpu.mdr();
@ -36,7 +36,7 @@ struct VRC2 : Chip {
return board.prgram.read(addr & 0x1fff); 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(board.prgram.size == 0) {
if((addr & 0xf000) == 0x6000) latch = data & 0x01; if((addr & 0xf000) == 0x6000) latch = data & 0x01;
return; return;
@ -44,10 +44,10 @@ struct VRC2 : Chip {
return board.prgram.write(addr & 0x1fff, data); return board.prgram.write(addr & 0x1fff, data);
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr) { switch(addr) {
case 0x8000: case 0x8001: case 0x8002: case 0x8003: case 0x8000: case 0x8001: case 0x8002: case 0x8003:
prg_bank[0] = data & 0x1f; prgBank[0] = data & 0x1f;
break; break;
case 0x9000: case 0x9001: case 0x9002: case 0x9003: case 0x9000: case 0x9001: case 0x9002: case 0x9003:
@ -55,32 +55,32 @@ struct VRC2 : Chip {
break; break;
case 0xa000: case 0xa001: case 0xa002: case 0xa003: case 0xa000: case 0xa001: case 0xa002: case 0xa003:
prg_bank[1] = data & 0x1f; prgBank[1] = data & 0x1f;
break; break;
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break; case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); 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 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); 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 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); 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 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); 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 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); 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 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); 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 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); 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 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break; case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break;
} }
} }
@ -88,21 +88,21 @@ struct VRC2 : Chip {
} }
auto reset() -> void { auto reset() -> void {
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
for(auto& n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
mirror = 0; mirror = 0;
latch = 0; latch = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
for(auto& n : prg_bank) s.integer(n); for(auto& n : prgBank) s.integer(n);
for(auto& n : chr_bank) s.integer(n); for(auto& n : chrBank) s.integer(n);
s.integer(mirror); s.integer(mirror);
s.integer(latch); s.integer(latch);
} }
uint5 prg_bank[2]; uint5 prgBank[2];
uint8 chr_bank[8]; uint8 chrBank[8];
uint2 mirror; uint2 mirror;
bool latch; bool latch;
}; };

View File

@ -3,53 +3,53 @@ struct VRC3 : Chip {
} }
auto main() -> void { auto main() -> void {
if(irq_enable) { if(irqEnable) {
if(irq_mode == 0) { //16-bit if(irqMode == 0) { //16-bit
if(++irq_counter.w == 0) { if(++irqCounter.w == 0) {
irq_line = 1; irqLine = 1;
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
irq_counter.w = irq_latch; irqCounter.w = irqLatch;
} }
} }
if(irq_mode == 1) { //8-bit if(irqMode == 1) { //8-bit
if(++irq_counter.l == 0) { if(++irqCounter.l == 0) {
irq_line = 1; irqLine = 1;
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
irq_counter.l = irq_latch; irqCounter.l = irqLatch;
} }
} }
} }
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
tick(); tick();
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
uint bank = (addr < 0xc000 ? (uint)prg_bank : 0x0f); uint bank = (addr < 0xc000 ? (uint)prgBank : 0x0f);
return (bank * 0x4000) + (addr & 0x3fff); return (bank * 0x4000) + (addr & 0x3fff);
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr & 0xf000) { switch(addr & 0xf000) {
case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) << 0); break; case 0x8000: irqLatch = (irqLatch & 0xfff0) | ((data & 0x0f) << 0); break;
case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) << 4); break; case 0x9000: irqLatch = (irqLatch & 0xff0f) | ((data & 0x0f) << 4); break;
case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) << 8); break; case 0xa000: irqLatch = (irqLatch & 0xf0ff) | ((data & 0x0f) << 8); break;
case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break; case 0xb000: irqLatch = (irqLatch & 0x0fff) | ((data & 0x0f) << 12); break;
case 0xc000: case 0xc000:
irq_mode = data & 0x04; irqMode = data & 0x04;
irq_enable = data & 0x02; irqEnable = data & 0x02;
irq_acknowledge = data & 0x01; irqAcknowledge = data & 0x01;
if(irq_enable) irq_counter.w = irq_latch; if(irqEnable) irqCounter.w = irqLatch;
break; break;
case 0xd000: case 0xd000:
irq_line = 0; irqLine = 0;
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
break; break;
case 0xf000: case 0xf000:
prg_bank = data & 0x0f; prgBank = data & 0x0f;
break; break;
} }
} }
@ -58,35 +58,35 @@ struct VRC3 : Chip {
} }
auto reset() -> void { auto reset() -> void {
prg_bank = 0; prgBank = 0;
irq_mode = 0; irqMode = 0;
irq_enable = 0; irqEnable = 0;
irq_acknowledge = 0; irqAcknowledge = 0;
irq_latch = 0; irqLatch = 0;
irq_counter.w = 0; irqCounter.w = 0;
irq_line = 0; irqLine = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.integer(prg_bank); s.integer(prgBank);
s.integer(irq_mode); s.integer(irqMode);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_acknowledge); s.integer(irqAcknowledge);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_counter.w); s.integer(irqCounter.w);
s.integer(irq_line); s.integer(irqLine);
} }
uint4 prg_bank; uint4 prgBank;
bool irq_mode; bool irqMode;
bool irq_enable; bool irqEnable;
bool irq_acknowledge; bool irqAcknowledge;
uint16 irq_latch; uint16 irqLatch;
struct { struct {
union { union {
uint16_t w; uint16_t w;
struct { uint8_t order_lsb2(l, h); }; struct { uint8_t order_lsb2(l, h); };
}; };
} irq_counter; } irqCounter;
bool irq_line; bool irqLine;
}; };

View File

@ -3,51 +3,51 @@ struct VRC4 : Chip {
} }
auto main() -> void { auto main() -> void {
if(irq_enable) { if(irqEnable) {
if(irq_mode == 0) { if(irqMode == 0) {
irq_scalar -= 3; irqScalar -= 3;
if(irq_scalar <= 0) { if(irqScalar <= 0) {
irq_scalar += 341; irqScalar += 341;
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
if(irq_mode == 1) { if(irqMode == 1) {
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
tick(); tick();
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
uint bank = 0, banks = board.prgrom.size / 0x2000; uint bank = 0, banks = board.prgrom.size / 0x2000;
switch(addr & 0xe000) { switch(addr & 0xe000) {
case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break; case 0x8000: bank = prgMode == 0 ? (uint)prgBank[0] : banks - 2; break;
case 0xa000: bank = prg_bank[1]; break; case 0xa000: bank = prgBank[1]; break;
case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break; case 0xc000: bank = prgMode == 0 ? banks - 2 : (uint)prgBank[0]; break;
case 0xe000: bank = banks - 1; break; case 0xe000: bank = banks - 1; break;
} }
return (bank * 0x2000) + (addr & 0x1fff); return (bank * 0x2000) + (addr & 0x1fff);
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
uint bank = chr_bank[addr / 0x0400]; uint bank = chrBank[addr / 0x0400];
return (bank * 0x0400) + (addr & 0x03ff); return (bank * 0x0400) + (addr & 0x03ff);
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
@ -57,10 +57,10 @@ struct VRC4 : Chip {
throw; throw;
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr) { switch(addr) {
case 0x8000: case 0x8001: case 0x8002: case 0x8003: case 0x8000: case 0x8001: case 0x8002: case 0x8003:
prg_bank[0] = data & 0x1f; prgBank[0] = data & 0x1f;
break; break;
case 0x9000: case 0x9001: case 0x9000: case 0x9001:
@ -68,59 +68,59 @@ struct VRC4 : Chip {
break; break;
case 0x9002: case 0x9003: case 0x9002: case 0x9003:
prg_mode = data & 0x02; prgMode = data & 0x02;
break; break;
case 0xa000: case 0xa001: case 0xa002: case 0xa003: case 0xa000: case 0xa001: case 0xa002: case 0xa003:
prg_bank[1] = data & 0x1f; prgBank[1] = data & 0x1f;
break; break;
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break; case 0xb000: chrBank[0] = (chrBank[0] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); 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 0xb002: chrBank[1] = (chrBank[1] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); 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 0xc000: chrBank[2] = (chrBank[2] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); 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 0xc002: chrBank[3] = (chrBank[3] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); 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 0xd000: chrBank[4] = (chrBank[4] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); 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 0xd002: chrBank[5] = (chrBank[5] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); 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 0xe000: chrBank[6] = (chrBank[6] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); 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 0xe002: chrBank[7] = (chrBank[7] & 0xf0) | ((data & 0x0f) << 0); break;
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break; case 0xe003: chrBank[7] = (chrBank[7] & 0x0f) | ((data & 0x0f) << 4); break;
case 0xf000: case 0xf000:
irq_latch = (irq_latch & 0xf0) | ((data & 0x0f) << 0); irqLatch = (irqLatch & 0xf0) | ((data & 0x0f) << 0);
break; break;
case 0xf001: case 0xf001:
irq_latch = (irq_latch & 0x0f) | ((data & 0x0f) << 4); irqLatch = (irqLatch & 0x0f) | ((data & 0x0f) << 4);
break; break;
case 0xf002: case 0xf002:
irq_mode = data & 0x04; irqMode = data & 0x04;
irq_enable = data & 0x02; irqEnable = data & 0x02;
irq_acknowledge = data & 0x01; irqAcknowledge = data & 0x01;
if(irq_enable) { if(irqEnable) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_scalar = 341; irqScalar = 341;
} }
irq_line = 0; irqLine = 0;
break; break;
case 0xf003: case 0xf003:
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
irq_line = 0; irqLine = 0;
break; break;
} }
} }
@ -129,48 +129,48 @@ struct VRC4 : Chip {
} }
auto reset() -> void { auto reset() -> void {
prg_mode = 0; prgMode = 0;
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
mirror = 0; mirror = 0;
for(auto& n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
irq_latch = 0; irqLatch = 0;
irq_mode = 0; irqMode = 0;
irq_enable = 0; irqEnable = 0;
irq_acknowledge = 0; irqAcknowledge = 0;
irq_counter = 0; irqCounter = 0;
irq_scalar = 0; irqScalar = 0;
irq_line = 0; irqLine = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.integer(prg_mode); s.integer(prgMode);
for(auto& n : prg_bank) s.integer(n); for(auto& n : prgBank) s.integer(n);
s.integer(mirror); s.integer(mirror);
for(auto& n : chr_bank) s.integer(n); for(auto& n : chrBank) s.integer(n);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_mode); s.integer(irqMode);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_acknowledge); s.integer(irqAcknowledge);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_scalar); s.integer(irqScalar);
s.integer(irq_line); s.integer(irqLine);
} }
bool prg_mode; bool prgMode;
uint5 prg_bank[2]; uint5 prgBank[2];
uint2 mirror; uint2 mirror;
uint8 chr_bank[8]; uint8 chrBank[8];
uint8 irq_latch; uint8 irqLatch;
bool irq_mode; bool irqMode;
bool irq_enable; bool irqEnable;
bool irq_acknowledge; bool irqAcknowledge;
uint8 irq_counter; uint8 irqCounter;
int irq_scalar; int irqScalar;
bool irq_line; bool irqLine;
}; };

View File

@ -77,52 +77,52 @@ struct VRC6 : Chip {
} sawtooth; } sawtooth;
auto main() -> void { auto main() -> void {
if(irq_enable) { if(irqEnable) {
if(irq_mode == 0) { if(irqMode == 0) {
irq_scalar -= 3; irqScalar -= 3;
if(irq_scalar <= 0) { if(irqScalar <= 0) {
irq_scalar += 341; irqScalar += 341;
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
if(irq_mode == 1) { if(irqMode == 1) {
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
pulse1.clock(); pulse1.clock();
pulse2.clock(); pulse2.clock();
sawtooth.clock(); sawtooth.clock();
int output = (pulse1.output + pulse2.output + sawtooth.output) << 7; int output = (pulse1.output + pulse2.output + sawtooth.output) << 7;
apu.set_sample(-output); apu.setSample(-output);
tick(); tick();
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
if((addr & 0xc000) == 0x8000) return (prg_bank[0] << 14) | (addr & 0x3fff); if((addr & 0xc000) == 0x8000) return (prgBank[0] << 14) | (addr & 0x3fff);
if((addr & 0xe000) == 0xc000) return (prg_bank[1] << 13) | (addr & 0x1fff); if((addr & 0xe000) == 0xc000) return (prgBank[1] << 13) | (addr & 0x1fff);
if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff); if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff);
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
uint bank = chr_bank[(addr >> 10) & 7]; uint bank = chrBank[(addr >> 10) & 7];
return (bank << 10) | (addr & 0x03ff); return (bank << 10) | (addr & 0x03ff);
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal 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]; 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; board.prgram.data[addr & 0x1fff] = data;
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr) { switch(addr) {
case 0x8000: case 0x8001: case 0x8002: case 0x8003: case 0x8000: case 0x8001: case 0x8002: case 0x8003:
prg_bank[0] = data; prgBank[0] = data;
break; break;
case 0x9000: case 0x9000:
@ -193,35 +193,35 @@ struct VRC6 : Chip {
break; break;
case 0xc000: case 0xc001: case 0xc002: case 0xc003: case 0xc000: case 0xc001: case 0xc002: case 0xc003:
prg_bank[1] = data; prgBank[1] = data;
break; break;
case 0xd000: case 0xd001: case 0xd002: case 0xd003: case 0xd000: case 0xd001: case 0xd002: case 0xd003:
chr_bank[0 + (addr & 3)] = data; chrBank[0 + (addr & 3)] = data;
break; break;
case 0xe000: case 0xe001: case 0xe002: case 0xe003: case 0xe000: case 0xe001: case 0xe002: case 0xe003:
chr_bank[4 + (addr & 3)] = data; chrBank[4 + (addr & 3)] = data;
break; break;
case 0xf000: case 0xf000:
irq_latch = data; irqLatch = data;
break; break;
case 0xf001: case 0xf001:
irq_mode = data & 0x04; irqMode = data & 0x04;
irq_enable = data & 0x02; irqEnable = data & 0x02;
irq_acknowledge = data & 0x01; irqAcknowledge = data & 0x01;
if(irq_enable) { if(irqEnable) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_scalar = 341; irqScalar = 341;
} }
irq_line = 0; irqLine = 0;
break; break;
case 0xf002: case 0xf002:
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
irq_line = 0; irqLine = 0;
break; break;
} }
} }
@ -230,25 +230,25 @@ struct VRC6 : Chip {
} }
auto reset() -> void { auto reset() -> void {
prg_bank[0] = 0; prgBank[0] = 0;
prg_bank[1] = 0; prgBank[1] = 0;
chr_bank[0] = 0; chrBank[0] = 0;
chr_bank[1] = 0; chrBank[1] = 0;
chr_bank[2] = 0; chrBank[2] = 0;
chr_bank[3] = 0; chrBank[3] = 0;
chr_bank[4] = 0; chrBank[4] = 0;
chr_bank[5] = 0; chrBank[5] = 0;
chr_bank[6] = 0; chrBank[6] = 0;
chr_bank[7] = 0; chrBank[7] = 0;
mirror = 0; mirror = 0;
irq_latch = 0; irqLatch = 0;
irq_mode = 0; irqMode = 0;
irq_enable = 0; irqEnable = 0;
irq_acknowledge = 0; irqAcknowledge = 0;
irq_counter = 0; irqCounter = 0;
irq_scalar = 0; irqScalar = 0;
irq_line = 0; irqLine = 0;
pulse1.mode = 0; pulse1.mode = 0;
pulse1.duty = 0; pulse1.duty = 0;
@ -286,28 +286,28 @@ struct VRC6 : Chip {
pulse2.serialize(s); pulse2.serialize(s);
sawtooth.serialize(s); sawtooth.serialize(s);
s.array(prg_bank); s.array(prgBank);
s.array(chr_bank); s.array(chrBank);
s.integer(mirror); s.integer(mirror);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_mode); s.integer(irqMode);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_acknowledge); s.integer(irqAcknowledge);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_scalar); s.integer(irqScalar);
s.integer(irq_line); s.integer(irqLine);
} }
uint8 prg_bank[2]; uint8 prgBank[2];
uint8 chr_bank[8]; uint8 chrBank[8];
uint2 mirror; uint2 mirror;
uint8 irq_latch; uint8 irqLatch;
bool irq_mode; bool irqMode;
bool irq_enable; bool irqEnable;
bool irq_acknowledge; bool irqAcknowledge;
uint8 irq_counter; uint8 irqCounter;
int irq_scalar; int irqScalar;
bool irq_line; bool irqLine;
}; };

View File

@ -6,90 +6,90 @@ struct VRC7 : Chip {
} }
auto main() -> void { auto main() -> void {
if(irq_enable) { if(irqEnable) {
if(irq_mode == 0) { if(irqMode == 0) {
irq_scalar -= 3; irqScalar -= 3;
if(irq_scalar <= 0) { if(irqScalar <= 0) {
irq_scalar += 341; irqScalar += 341;
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
if(irq_mode == 1) { if(irqMode == 1) {
if(irq_counter == 0xff) { if(irqCounter == 0xff) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_line = 1; irqLine = 1;
} else { } else {
irq_counter++; irqCounter++;
} }
} }
} }
cpu.irqLine(irq_line); cpu.irqLine(irqLine);
tick(); tick();
} }
auto reg_write(uint addr, uint8 data) -> void { auto writeIO(uint addr, uint8 data) -> void {
switch(addr) { switch(addr) {
case 0x8000: prg_bank[0] = data; break; case 0x8000: prgBank[0] = data; break;
case 0x8010: prg_bank[1] = data; break; case 0x8010: prgBank[1] = data; break;
case 0x9000: prg_bank[2] = data; break; case 0x9000: prgBank[2] = data; break;
case 0x9010: break; //APU addr port case 0x9010: break; //APU addr port
case 0x9030: break; //APU data port case 0x9030: break; //APU data port
case 0xa000: chr_bank[0] = data; break; case 0xa000: chrBank[0] = data; break;
case 0xa010: chr_bank[1] = data; break; case 0xa010: chrBank[1] = data; break;
case 0xb000: chr_bank[2] = data; break; case 0xb000: chrBank[2] = data; break;
case 0xb010: chr_bank[3] = data; break; case 0xb010: chrBank[3] = data; break;
case 0xc000: chr_bank[4] = data; break; case 0xc000: chrBank[4] = data; break;
case 0xc010: chr_bank[5] = data; break; case 0xc010: chrBank[5] = data; break;
case 0xd000: chr_bank[6] = data; break; case 0xd000: chrBank[6] = data; break;
case 0xd010: chr_bank[7] = data; break; case 0xd010: chrBank[7] = data; break;
case 0xe000: mirror = data & 0x03; break; case 0xe000: mirror = data & 0x03; break;
case 0xe010: case 0xe010:
irq_latch = data; irqLatch = data;
break; break;
case 0xf000: case 0xf000:
irq_mode = data & 0x04; irqMode = data & 0x04;
irq_enable = data & 0x02; irqEnable = data & 0x02;
irq_acknowledge = data & 0x01; irqAcknowledge = data & 0x01;
if(irq_enable) { if(irqEnable) {
irq_counter = irq_latch; irqCounter = irqLatch;
irq_scalar = 341; irqScalar = 341;
} }
irq_line = 0; irqLine = 0;
break; break;
case 0xf010: case 0xf010:
irq_enable = irq_acknowledge; irqEnable = irqAcknowledge;
irq_line = 0; irqLine = 0;
break; break;
} }
} }
auto prg_addr(uint addr) const -> uint { auto addrPRG(uint addr) const -> uint {
uint bank = 0; uint bank = 0;
switch(addr & 0xe000) { switch(addr & 0xe000) {
case 0x8000: bank = prg_bank[0]; break; case 0x8000: bank = prgBank[0]; break;
case 0xa000: bank = prg_bank[1]; break; case 0xa000: bank = prgBank[1]; break;
case 0xc000: bank = prg_bank[2]; break; case 0xc000: bank = prgBank[2]; break;
case 0xe000: bank = 0xff; break; case 0xe000: bank = 0xff; break;
} }
return (bank * 0x2000) + (addr & 0x1fff); return (bank * 0x2000) + (addr & 0x1fff);
} }
auto chr_addr(uint addr) const -> uint { auto addrCHR(uint addr) const -> uint {
uint bank = chr_bank[addr / 0x0400]; uint bank = chrBank[addr / 0x0400];
return (bank * 0x0400) + (addr & 0x03ff); return (bank * 0x0400) + (addr & 0x03ff);
} }
auto ciram_addr(uint addr) const -> uint { auto addrCIRAM(uint addr) const -> uint {
switch(mirror) { switch(mirror) {
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
@ -102,45 +102,45 @@ struct VRC7 : Chip {
} }
auto reset() -> void { auto reset() -> void {
for(auto& n : prg_bank) n = 0; for(auto& n : prgBank) n = 0;
for(auto& n : chr_bank) n = 0; for(auto& n : chrBank) n = 0;
mirror = 0; mirror = 0;
irq_latch = 0; irqLatch = 0;
irq_mode = 0; irqMode = 0;
irq_enable = 0; irqEnable = 0;
irq_acknowledge = 0; irqAcknowledge = 0;
irq_counter = 0; irqCounter = 0;
irq_scalar = 0; irqScalar = 0;
irq_line = 0; irqLine = 0;
} }
auto serialize(serializer& s) -> void { auto serialize(serializer& s) -> void {
s.array(prg_bank); s.array(prgBank);
s.array(chr_bank); s.array(chrBank);
s.integer(mirror); s.integer(mirror);
s.integer(irq_latch); s.integer(irqLatch);
s.integer(irq_mode); s.integer(irqMode);
s.integer(irq_enable); s.integer(irqEnable);
s.integer(irq_acknowledge); s.integer(irqAcknowledge);
s.integer(irq_counter); s.integer(irqCounter);
s.integer(irq_scalar); s.integer(irqScalar);
s.integer(irq_line); s.integer(irqLine);
} }
uint8 prg_bank[3]; uint8 prgBank[3];
uint8 chr_bank[8]; uint8 chrBank[8];
uint2 mirror; uint2 mirror;
uint8 irq_latch; uint8 irqLatch;
bool irq_mode; bool irqMode;
bool irq_enable; bool irqEnable;
bool irq_acknowledge; bool irqAcknowledge;
uint8 irq_counter; uint8 irqCounter;
int irq_scalar; int irqScalar;
bool irq_line; bool irqLine;
}; };

View File

@ -21,23 +21,29 @@ auto PPU::writeCGRAM(uint5 addr, uint8 data) -> void {
auto PPU::readIO(uint16 addr) -> uint8 { auto PPU::readIO(uint16 addr) -> uint8 {
uint8 result = 0x00; uint8 result = 0x00;
switch(addr & 7) { switch(addr.bits(0,2)) {
case 2: //PPUSTATUS
result |= r.nmiFlag << 7; //PPUSTATUS
result |= r.spriteZeroHit << 6; case 2:
result |= r.mdr.bits(0,4);
result |= r.spriteOverflow << 5; result |= r.spriteOverflow << 5;
result |= r.mdr & 0x1f; result |= r.spriteZeroHit << 6;
r.addressLatch = 0; result |= r.nmiFlag << 7;
r.v.latch = 0;
r.nmiHold = 0; r.nmiHold = 0;
cpu.nmiLine(r.nmiFlag = 0); cpu.nmiLine(r.nmiFlag = 0);
break; break;
case 4: //OAMDATA
//OAMDATA
case 4:
result = oam[r.oamAddress]; result = oam[r.oamAddress];
break; break;
case 7: //PPUDATA
//PPUDATA
case 7:
if(enable() && (r.ly <= 240 || r.ly == 261)) return 0x00; if(enable() && (r.ly <= 240 || r.ly == 261)) return 0x00;
addr = r.vaddr & 0x3fff; addr = (uint14)r.v.address;
if(addr <= 0x1fff) { if(addr <= 0x1fff) {
result = r.busData; result = r.busData;
r.busData = cartridge.readCHR(addr); r.busData = cartridge.readCHR(addr);
@ -48,8 +54,9 @@ auto PPU::readIO(uint16 addr) -> uint8 {
result = readCGRAM(addr); result = readCGRAM(addr);
r.busData = cartridge.readCHR(addr); r.busData = cartridge.readCHR(addr);
} }
r.vaddr += r.vramIncrement; r.v.address += r.vramIncrement;
break; break;
} }
return result; return result;
@ -58,56 +65,73 @@ auto PPU::readIO(uint16 addr) -> uint8 {
auto PPU::writeIO(uint16 addr, uint8 data) -> void { auto PPU::writeIO(uint16 addr, uint8 data) -> void {
r.mdr = data; r.mdr = data;
switch(addr & 7) { switch(addr.bits(0,2)) {
case 0: //PPUCTRL
r.nmiEnable = data & 0x80; //PPUCTRL
r.masterSelect = data & 0x40; case 0:
r.spriteHeight = data & 0x20 ? 16 : 8; r.t.nametable = data.bits(0,1);
r.bgAddress = (data & 0x10) ? 0x1000 : 0x0000; r.vramIncrement = data.bit (2) ? 32 : 1;
r.spriteAddress = (data & 0x08) ? 0x1000 : 0x0000; r.spriteAddress = data.bit (3) ? 0x1000 : 0x0000;
r.vramIncrement = (data & 0x04) ? 32 : 1; r.bgAddress = data.bit (4) ? 0x1000 : 0x0000;
r.taddr = (r.taddr & 0x73ff) | ((data & 0x03) << 10); 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); cpu.nmiLine(r.nmiEnable && r.nmiHold && r.nmiFlag);
return; break;
case 1: //PPUMASK
r.emphasis = data >> 5; //PPUMASK
r.spriteEnable = data & 0x10; case 1:
r.bgEnable = data & 0x08; r.grayscale = data.bit (0);
r.spriteEdgeEnable = data & 0x04; r.bgEdgeEnable = data.bit (1);
r.bgEdgeEnable = data & 0x02; r.spriteEdgeEnable = data.bit (2);
r.grayscale = data & 0x01; r.bgEnable = data.bit (3);
return; r.spriteEnable = data.bit (4);
case 2: //PPUSTATUS r.emphasis = data.bits(5,7);
return; break;
case 3: //OAMADDR
//PPUSTATUS
case 2:
break;
//OAMADDR
case 3:
r.oamAddress = data; r.oamAddress = data;
return; break;
case 4: //OAMDATA
//OAMDATA
case 4:
if(r.oamAddress.bits(0,1) == 2) data.bits(2,4) = 0; //clear non-existent bits (always read back as 0) 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; oam[r.oamAddress++] = data;
return; break;
case 5: //PPUSCROLL
if(r.addressLatch == 0) { //PPUSCROLL
r.xaddr = data & 0x07; case 5:
r.taddr = (r.taddr & 0x7fe0) | (data >> 3); if(!r.v.latch) {
r.v.fineX = data.bits(0,2);
r.t.tileX = data.bits(3,7);
} else { } 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; r.v.latch ^= 1;
return; break;
case 6: //PPUADDR
if(r.addressLatch == 0) { //PPUADDR
r.taddr = (r.taddr & 0x00ff) | ((data & 0x3f) << 8); case 6:
if(!r.v.latch) {
r.t.addressHi = data.bits(0,5);
} else { } else {
r.taddr = (r.taddr & 0x7f00) | data; r.t.addressLo = data.bits(0,7);
r.vaddr = r.taddr; r.v.address = r.t.address;
} }
r.addressLatch ^= 1; r.v.latch ^= 1;
return; break;
case 7: //PPUDATA
//PPUDATA
case 7:
if(enable() && (r.ly <= 240 || r.ly == 261)) return; if(enable() && (r.ly <= 240 || r.ly == 261)) return;
addr = r.vaddr & 0x3fff; addr = (uint14)r.v.address;
if(addr <= 0x1fff) { if(addr <= 0x1fff) {
cartridge.writeCHR(addr, data); cartridge.writeCHR(addr, data);
} else if(addr <= 0x3eff) { } else if(addr <= 0x3eff) {
@ -115,7 +139,8 @@ auto PPU::writeIO(uint16 addr, uint8 data) -> void {
} else if(addr <= 0x3fff) { } else if(addr <= 0x3fff) {
writeCGRAM(addr, data); writeCGRAM(addr, data);
} }
r.vaddr += r.vramIncrement; r.v.address += r.vramIncrement;
return; break;
} }
} }

View File

@ -15,21 +15,23 @@ auto PPU::main() -> void {
renderScanline(); renderScanline();
} }
auto PPU::tick() -> void { auto PPU::step(uint clocks) -> void {
if(r.ly == 240 && r.lx == 340) r.nmiHold = 1; while(clocks--) {
if(r.ly == 241 && r.lx == 0) r.nmiFlag = r.nmiHold; if(r.ly == 240 && r.lx == 340) r.nmiHold = 1;
if(r.ly == 241 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag); 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 == 260 && r.lx == 340) r.nmiHold = 0;
if(r.ly == 261 && r.lx == 0) r.nmiFlag = r.nmiHold; 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 == 261 && r.lx == 2) cpu.nmiLine(r.nmiEnable && r.nmiFlag);
clock += 4; clock += 4;
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread); if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
r.lx++; r.lx++;
}
} }
auto PPU::scanline() -> void { auto PPU::scanline() -> void {

View File

@ -1,7 +1,7 @@
struct PPU : Thread { struct PPU : Thread {
static auto Enter() -> void; static auto Enter() -> void;
auto main() -> void; auto main() -> void;
auto tick() -> void; auto step(uint clocks) -> void;
auto scanline() -> void; auto scanline() -> void;
auto frame() -> void; auto frame() -> void;
@ -22,15 +22,8 @@ struct PPU : Thread {
//render.cpp //render.cpp
auto enable() const -> bool; auto enable() const -> bool;
auto nametableAddress() const -> uint;
auto scrollX() const -> uint;
auto scrollY() const -> uint;
auto loadCHR(uint16 addr) -> uint8; auto loadCHR(uint16 addr) -> uint8;
auto scrollX_increment() -> void;
auto scrollY_increment() -> void;
auto renderPixel() -> void; auto renderPixel() -> void;
auto renderSprite() -> void; auto renderSprite() -> void;
auto renderScanline() -> void; auto renderScanline() -> void;
@ -48,34 +41,43 @@ struct PPU : Thread {
uint8 busData; uint8 busData;
bool addressLatch; union {
uint value;
uint15 vaddr; BitField<uint, 0, 4> tileX;
uint15 taddr; BitField<uint, 5, 9> tileY;
uint8 xaddr; 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 nmiHold;
bool nmiFlag; bool nmiFlag;
//$2000 //$2000
bool nmiEnable;
bool masterSelect;
uint spriteHeight;
uint bgAddress;
uint spriteAddress;
uint vramIncrement; uint vramIncrement;
uint spriteAddress;
uint bgAddress;
uint spriteHeight;
bool masterSelect;
bool nmiEnable;
//$2001 //$2001
uint3 emphasis;
bool spriteEnable;
bool bgEnable;
bool spriteEdgeEnable;
bool bgEdgeEnable;
bool grayscale; bool grayscale;
bool bgEdgeEnable;
bool spriteEdgeEnable;
bool bgEnable;
bool spriteEnable;
uint3 emphasis;
//$2002 //$2002
bool spriteZeroHit;
bool spriteOverflow; bool spriteOverflow;
bool spriteZeroHit;
//$2003 //$2003
uint8 oamAddress; uint8 oamAddress;

View File

@ -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 { auto PPU::enable() const -> bool {
return r.bgEnable || r.spriteEnable; 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 { auto PPU::loadCHR(uint16 addr) -> uint8 {
if(!enable()) return 0x00; return enable() ? cartridge.readCHR(addr) : (uint8)0x00;
return cartridge.readCHR(addr);
} }
//
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 { auto PPU::renderPixel() -> void {
uint32* output = buffer + r.ly * 256; 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 palette = 0;
uint objectPalette = 0; uint objectPalette = 0;
bool objectPriority = 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) { if(palette) {
uint attr = l.attribute; uint attr = l.attribute;
if(mask >= 256) attr >>= 2; if(mask >= 256) attr >>= 2;
@ -68,24 +24,24 @@ auto PPU::renderPixel() -> void {
} }
if(!r.bgEnable) palette = 0; if(!r.bgEnable) palette = 0;
if(!r.bgEdgeEnable && r.lx < 8) palette = 0; if(!r.bgEdgeEnable && x < 8) palette = 0;
if(r.spriteEnable) if(r.spriteEnable)
for(int sprite = 7; sprite >= 0; sprite--) { 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; 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(spriteX >= 8) continue;
if(l.oam[sprite].attr & 0x40) spriteX ^= 7; if(l.oam[sprite].attr & 0x40) spriteX ^= 7;
uint mask = 0x80 >> spriteX; uint mask = 0x80 >> spriteX;
uint spritePalette = 0; uint spritePalette = 0;
spritePalette |= (l.oam[sprite].tiledataLo & mask) ? 1 : 0; spritePalette |= l.oam[sprite].tiledataLo & mask ? 1 : 0;
spritePalette |= (l.oam[sprite].tiledataHi & mask) ? 2 : 0; spritePalette |= l.oam[sprite].tiledataHi & mask ? 2 : 0;
if(spritePalette == 0) continue; 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; spritePalette |= (l.oam[sprite].attr & 3) << 2;
objectPriority = l.oam[sprite].attr & 0x20; objectPriority = l.oam[sprite].attr & 0x20;
@ -97,15 +53,15 @@ auto PPU::renderPixel() -> void {
} }
if(!enable()) palette = 0; if(!enable()) palette = 0;
output[r.lx] = r.emphasis << 6 | readCGRAM(palette); output[x] = r.emphasis << 6 | readCGRAM(palette);
} }
auto PPU::renderSprite() -> void { auto PPU::renderSprite() -> void {
if(!enable()) return; if(!enable()) return;
uint n = l.oamIterator++; uint n = l.oamIterator++;
int ly = (r.ly == 261 ? -1 : r.ly); int ly = r.ly == 261 ? -1 : r.ly;
uint y = ly - oam[(n * 4) + 0]; uint y = ly - oam[n * 4 + 0];
if(y >= r.spriteHeight) return; if(y >= r.spriteHeight) return;
if(l.oamCounter == 8) { if(l.oamCounter == 8) {
@ -115,58 +71,60 @@ auto PPU::renderSprite() -> void {
auto& o = l.soam[l.oamCounter++]; auto& o = l.soam[l.oamCounter++];
o.id = n; o.id = n;
o.y = oam[(n * 4) + 0]; o.y = oam[n * 4 + 0];
o.tile = oam[(n * 4) + 1]; o.tile = oam[n * 4 + 1];
o.attr = oam[(n * 4) + 2]; o.attr = oam[n * 4 + 2];
o.x = oam[(n * 4) + 3]; o.x = oam[n * 4 + 3];
} }
auto PPU::renderScanline() -> void { auto PPU::renderScanline() -> void {
if(r.ly >= 240 && r.ly <= 260) { //Vblank
for(auto x : range(341)) tick(); if(r.ly >= 240 && r.ly <= 260) return step(341), scanline();
return scanline();
}
l.oamIterator = 0; l.oamIterator = 0;
l.oamCounter = 0; l.oamCounter = 0;
for(auto n : range(8)) l.soam[n] = {}; for(auto n : range(8)) l.soam[n] = {};
for(uint tile : range(32)) { // 0-255 // 0
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff)); step(1);
uint tileaddr = r.bgAddress + (nametable << 4) + (scrollY() & 7);
// 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(); renderPixel();
tick(); step(1);
renderPixel(); renderPixel();
tick(); step(1);
uint attribute = loadCHR(0x23c0 | (r.vaddr & 0x0fc0) | ((scrollY() >> 5) << 3) | (scrollX() >> 5)); uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
if(scrollY() & 16) attribute >>= 4; if(r.v.tileY & 2) attribute >>= 4;
if(scrollX() & 16) attribute >>= 2; if(r.v.tileX & 2) attribute >>= 2;
renderPixel(); renderPixel();
tick(); step(1);
scrollX_increment(); if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
if(tile == 31) scrollY_increment(); if(enable() && tile == 31 && ++r.v.fineY == 0 && ++r.v.tileY == 30) r.v.nametableY ^= 1, r.v.tileY = 0;
renderPixel(); renderPixel();
renderSprite(); renderSprite();
tick(); step(1);
uint tiledataLo = loadCHR(tileaddr + 0); uint tiledataLo = loadCHR(tileaddr + 0);
renderPixel(); renderPixel();
tick(); step(1);
renderPixel(); renderPixel();
tick(); step(1);
uint tiledataHi = loadCHR(tileaddr + 8); uint tiledataHi = loadCHR(tileaddr + 8);
renderPixel(); renderPixel();
tick(); step(1);
renderPixel(); renderPixel();
renderSprite(); renderSprite();
tick(); step(1);
l.nametable = l.nametable << 8 | nametable; l.nametable = l.nametable << 8 | nametable;
l.attribute = l.attribute << 2 | (attribute & 3); 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(auto n : range(8)) l.oam[n] = l.soam[n];
for(uint sprite : range(8)) { //256-319 //257-320
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff)); for(uint sprite : range(8)) {
tick(); uint nametable = loadCHR(0x2000 | (uint12)r.v.address);
step(1);
if(enable() && sprite == 0) r.vaddr = (r.vaddr & 0x7be0) | (r.taddr & 0x041f); //257 if(enable() && sprite == 0) {
tick(); //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 attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
uint tileaddr = (r.spriteHeight == 8) uint tileaddr = r.spriteHeight == 8
? r.spriteAddress + l.oam[sprite].tile * 16 ? r.spriteAddress + l.oam[sprite].tile * 16
: ((l.oam[sprite].tile & ~1) * 16) + ((l.oam[sprite].tile & 1) * 0x1000); : (l.oam[sprite].tile & ~1) * 16 + (l.oam[sprite].tile & 1) * 0x1000;
tick(); step(2);
tick();
uint spriteY = (r.ly - l.oam[sprite].y) & (r.spriteHeight - 1); 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); tileaddr += spriteY + (spriteY & 8);
l.oam[sprite].tiledataLo = loadCHR(tileaddr + 0); l.oam[sprite].tiledataLo = loadCHR(tileaddr + 0);
tick(); step(2);
tick();
l.oam[sprite].tiledataHi = loadCHR(tileaddr + 8); l.oam[sprite].tiledataHi = loadCHR(tileaddr + 8);
tick(); step(2);
tick();
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 //321-336
uint nametable = loadCHR(0x2000 | (r.vaddr & 0x0fff)); for(uint tile : range(2)) {
uint tileaddr = r.bgAddress + (nametable << 4) + (scrollY() & 7); uint nametable = loadCHR(0x2000 | (uint12)r.v.address);
tick(); uint tileaddr = r.bgAddress | nametable << 4 | r.v.fineY;
tick(); step(2);
uint attribute = loadCHR(0x23c0 | (r.vaddr & 0x0fc0) | ((scrollY() >> 5) << 3) | (scrollX() >> 5)); uint attribute = loadCHR(0x23c0 | r.v.nametable << 10 | (r.v.tileY >> 2) << 3 | r.v.tileX >> 2);
if(scrollY() & 16) attribute >>= 4; if(r.v.tileY & 2) attribute >>= 4;
if(scrollX() & 16) attribute >>= 2; if(r.v.tileX & 2) attribute >>= 2;
tick(); step(1);
scrollX_increment(); if(enable() && ++r.v.tileX == 0) r.v.nametableX ^= 1;
tick(); step(1);
uint tiledataLo = loadCHR(tileaddr + 0); uint tiledataLo = loadCHR(tileaddr + 0);
tick(); step(2);
tick();
uint tiledataHi = loadCHR(tileaddr + 8); uint tiledataHi = loadCHR(tileaddr + 8);
tick(); step(2);
tick();
l.nametable = l.nametable << 8 | nametable; l.nametable = l.nametable << 8 | nametable;
l.attribute = l.attribute << 2 | (attribute & 3); l.attribute = l.attribute << 2 | (attribute & 3);
@ -233,18 +194,18 @@ auto PPU::renderScanline() -> void {
l.tiledataHi = l.tiledataHi << 8 | tiledataHi; l.tiledataHi = l.tiledataHi << 8 | tiledataHi;
} }
//336-339 //337-338
loadCHR(0x2000 | (r.vaddr & 0x0fff)); loadCHR(0x2000 | (uint12)r.v.address);
tick(); step(1);
bool skip = enable() && r.field == 1 && r.ly == 261; bool skip = enable() && r.field == 1 && r.ly == 261;
tick(); step(1);
loadCHR(0x2000 | (r.vaddr & 0x0fff)); //339
tick(); loadCHR(0x2000 | (uint12)r.v.address);
tick(); step(1);
//340 //340
if(!skip) tick(); if(!skip) step(1);
return scanline(); return scanline();
} }

View File

@ -9,31 +9,28 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(r.busData); s.integer(r.busData);
s.integer(r.addressLatch); s.integer(r.v.value);
s.integer(r.t.value);
s.integer(r.vaddr);
s.integer(r.taddr);
s.integer(r.xaddr);
s.integer(r.nmiHold); s.integer(r.nmiHold);
s.integer(r.nmiFlag); 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.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.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.spriteOverflow);
s.integer(r.spriteZeroHit);
s.integer(r.oamAddress); s.integer(r.oamAddress);

View File

@ -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;

View File

@ -22,6 +22,7 @@ auto System::runToSave() -> void {
} }
auto System::load() -> bool { auto System::load() -> bool {
information = Information();
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) { if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
information.manifest = fp->reads(); information.manifest = fp->reads();
} else { } else {
@ -30,7 +31,7 @@ auto System::load() -> bool {
auto document = BML::unserialize(information.manifest); auto document = BML::unserialize(information.manifest);
if(!cartridge.load()) return false; if(!cartridge.load()) return false;
serializeInit(); serializeInit();
return _loaded = true; return information.loaded = true;
} }
auto System::save() -> void { auto System::save() -> void {
@ -41,7 +42,7 @@ auto System::unload() -> void {
if(!loaded()) return; if(!loaded()) return;
peripherals.unload(); peripherals.unload();
cartridge.unload(); cartridge.unload();
_loaded = false; information.loaded = false;
} }
auto System::power() -> void { auto System::power() -> void {

View File

@ -1,7 +1,5 @@
#include "peripherals.hpp"
struct System { struct System {
auto loaded() const -> bool { return _loaded; } auto loaded() const -> bool { return information.loaded; }
auto run() -> void; auto run() -> void;
auto runToSave() -> void; auto runToSave() -> void;
@ -28,12 +26,22 @@ struct System {
auto serializeInit() -> void; auto serializeInit() -> void;
struct Information { struct Information {
bool loaded = false;
string manifest; string manifest;
} information; } information;
private: private:
bool _loaded = false;
uint _serializeSize = 0; 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 System system;
extern Peripherals peripherals;

View File

@ -55,7 +55,7 @@ auto PPU::Background::getTile() -> void {
uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2); uint colorDepth = (r.mode == Mode::BPP2 ? 0 : r.mode == Mode::BPP4 ? 1 : 2);
uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0); uint paletteOffset = (ppu.r.bgMode == 0 ? id << 5 : 0);
uint paletteSize = 2 << colorDepth; uint paletteSize = 2 << colorDepth;
uint tileMask = 0x0fff >> colorDepth; uint tileMask = ppu.vram.mask >> (3 + colorDepth);
uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth); uint tiledataIndex = r.tiledataAddress >> (3 + colorDepth);
uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4); uint tileHeight = (r.tileSize == TileSize::Size8x8 ? 3 : 4);
@ -207,8 +207,8 @@ auto PPU::Background::getTileColor() -> uint {
} }
auto PPU::Background::reset() -> void { auto PPU::Background::reset() -> void {
r.tiledataAddress = (random(0x0000) & 0x07) << 12; r.tiledataAddress = (random(0x0000) & 0x0f) << 12;
r.screenAddress = (random(0x0000) & 0x7c) << 8; r.screenAddress = (random(0x0000) & 0xfc) << 8;
r.screenSize = random(0); r.screenSize = random(0);
r.mosaic = random(0); r.mosaic = random(0);
r.tileSize = random(0); r.tileSize = random(0);

View File

@ -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& 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: private:
type data; type data;

View File

@ -30,7 +30,6 @@ struct maybe {
if(this == &source) return *this; if(this == &source) return *this;
reset(); reset();
if(_valid = source._valid) new(&_value.t) T(move(source.get())); if(_valid = source._valid) new(&_value.t) T(move(source.get()));
source._valid = false;
return *this; return *this;
} }