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 {
static const string Name = "higan";
static const string Version = "099.10";
static const string Version = "099.11";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -14,9 +14,9 @@ APU apu;
APU::APU() {
for(uint amp : range(32)) {
if(amp == 0) {
pulse_dac[amp] = 0;
pulseDAC[amp] = 0;
} else {
pulse_dac[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0);
pulseDAC[amp] = 16384.0 * 95.88 / (8128.0 / amp + 100.0);
}
}
@ -24,9 +24,9 @@ APU::APU() {
for(uint triangle_amp : range(16)) {
for(uint noise_amp : range(16)) {
if(dmc_amp == 0 && triangle_amp == 0 && noise_amp == 0) {
dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp] = 0;
dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp] = 0;
} else {
dmc_triangle_noise_dac[dmc_amp][triangle_amp][noise_amp]
dmcTriangleNoiseDAC[dmc_amp][triangle_amp][noise_amp]
= 16384.0 * 159.79 / (100.0 + 1.0 / (triangle_amp / 8227.0 + noise_amp / 12241.0 + dmc_amp / 22638.0));
}
}
@ -47,14 +47,14 @@ auto APU::main() -> void {
noise_output = noise.clock();
dmc_output = dmc.clock();
clock_frame_counter_divider();
clockFrameCounterDivider();
int output = pulse_dac[pulse_output] + dmc_triangle_noise_dac[dmc_output][triangle_output][noise_output];
int output = pulseDAC[pulse_output] + dmcTriangleNoiseDAC[dmc_output][triangle_output][noise_output];
output = filter.run_hipass_strong(output);
output += cartridge_sample;
output = filter.run_hipass_weak(output);
//output = filter.run_lopass(output);
output = filter.runHipassStrong(output);
output += cartridgeSample;
output = filter.runHipassWeak(output);
//output = filter.runLopass(output);
output = sclamp<16>(output);
stream->sample(output / 32768.0);
@ -67,17 +67,17 @@ auto APU::tick() -> void {
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
}
auto APU::set_irq_line() -> void {
cpu.apuLine(frame.irq_pending || dmc.irq_pending);
auto APU::setIRQ() -> void {
cpu.apuLine(frame.irqPending || dmc.irqPending);
}
auto APU::set_sample(int16 sample) -> void {
cartridge_sample = sample;
auto APU::setSample(int16 sample) -> void {
cartridgeSample = sample;
}
auto APU::power() -> void {
filter.hipass_strong = 0;
filter.hipass_weak = 0;
filter.hipassStrong = 0;
filter.hipassWeak = 0;
filter.lopass = 0;
pulse[0].power();
@ -97,16 +97,16 @@ auto APU::reset() -> void {
noise.reset();
dmc.reset();
frame.irq_pending = 0;
frame.irqPending = 0;
frame.mode = 0;
frame.counter = 0;
frame.divider = 1;
enabled_channels = 0;
cartridge_sample = 0;
enabledChannels = 0;
cartridgeSample = 0;
set_irq_line();
setIRQ();
}
auto APU::readIO(uint16 addr) -> uint8 {
@ -114,16 +114,16 @@ auto APU::readIO(uint16 addr) -> uint8 {
case 0x4015: {
uint8 result = 0x00;
result |= pulse[0].length_counter ? 0x01 : 0;
result |= pulse[1].length_counter ? 0x02 : 0;
result |= triangle.length_counter ? 0x04 : 0;
result |= noise.length_counter ? 0x08 : 0;
result |= dmc.length_counter ? 0x10 : 0;
result |= frame.irq_pending ? 0x40 : 0;
result |= dmc.irq_pending ? 0x80 : 0;
result |= pulse[0].lengthCounter ? 0x01 : 0;
result |= pulse[1].lengthCounter ? 0x02 : 0;
result |= triangle.lengthCounter ? 0x04 : 0;
result |= noise.lengthCounter ? 0x08 : 0;
result |= dmc.lengthCounter ? 0x10 : 0;
result |= frame.irqPending ? 0x40 : 0;
result |= dmc.irqPending ? 0x80 : 0;
frame.irq_pending = false;
set_irq_line();
frame.irqPending = false;
setIRQ();
return result;
}
@ -140,8 +140,8 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x4000: case 0x4004: {
pulse[n].duty = data >> 6;
pulse[n].envelope.loop_mode = data & 0x20;
pulse[n].envelope.use_speed_as_volume = data & 0x10;
pulse[n].envelope.loopMode = data & 0x20;
pulse[n].envelope.useSpeedAsVolume = data & 0x10;
pulse[n].envelope.speed = data & 0x0f;
return;
}
@ -157,26 +157,26 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x4002: case 0x4006: {
pulse[n].period = (pulse[n].period & 0x0700) | (data << 0);
pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x0700) | (data << 0);
pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x0700) | (data << 0);
return;
}
case 0x4003: case 0x4007: {
pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8);
pulse[n].sweep.pulse_period = (pulse[n].sweep.pulse_period & 0x00ff) | (data << 8);
pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x00ff) | (data << 8);
pulse[n].duty_counter = 7;
pulse[n].envelope.reload_decay = true;
pulse[n].dutyCounter = 7;
pulse[n].envelope.reloadDecay = true;
if(enabled_channels & (1 << n)) {
pulse[n].length_counter = length_counter_table[(data >> 3) & 0x1f];
if(enabledChannels & (1 << n)) {
pulse[n].lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
}
return;
}
case 0x4008: {
triangle.halt_length_counter = data & 0x80;
triangle.linear_length = data & 0x7f;
triangle.haltLengthCounter = data & 0x80;
triangle.linearLength = data & 0x7f;
return;
}
@ -188,72 +188,72 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
case 0x400b: {
triangle.period = (triangle.period & 0x00ff) | (data << 8);
triangle.reload_linear = true;
triangle.reloadLinear = true;
if(enabled_channels & (1 << 2)) {
triangle.length_counter = length_counter_table[(data >> 3) & 0x1f];
if(enabledChannels & (1 << 2)) {
triangle.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
}
return;
}
case 0x400c: {
noise.envelope.loop_mode = data & 0x20;
noise.envelope.use_speed_as_volume = data & 0x10;
noise.envelope.loopMode = data & 0x20;
noise.envelope.useSpeedAsVolume = data & 0x10;
noise.envelope.speed = data & 0x0f;
return;
}
case 0x400e: {
noise.short_mode = data & 0x80;
noise.shortMode = data & 0x80;
noise.period = data & 0x0f;
return;
}
case 0x400f: {
noise.envelope.reload_decay = true;
noise.envelope.reloadDecay = true;
if(enabled_channels & (1 << 3)) {
noise.length_counter = length_counter_table[(data >> 3) & 0x1f];
if(enabledChannels & (1 << 3)) {
noise.lengthCounter = lengthCounterTable[(data >> 3) & 0x1f];
}
return;
}
case 0x4010: {
dmc.irq_enable = data & 0x80;
dmc.loop_mode = data & 0x40;
dmc.irqEnable = data & 0x80;
dmc.loopMode = data & 0x40;
dmc.period = data & 0x0f;
dmc.irq_pending = dmc.irq_pending && dmc.irq_enable && !dmc.loop_mode;
set_irq_line();
dmc.irqPending = dmc.irqPending && dmc.irqEnable && !dmc.loopMode;
setIRQ();
return;
}
case 0x4011: {
dmc.dac_latch = data & 0x7f;
dmc.dacLatch = data & 0x7f;
return;
}
case 0x4012: {
dmc.addr_latch = data;
dmc.addrLatch = data;
return;
}
case 0x4013: {
dmc.length_latch = data;
dmc.lengthLatch = data;
return;
}
case 0x4015: {
if((data & 0x01) == 0) pulse[0].length_counter = 0;
if((data & 0x02) == 0) pulse[1].length_counter = 0;
if((data & 0x04) == 0) triangle.length_counter = 0;
if((data & 0x08) == 0) noise.length_counter = 0;
if((data & 0x01) == 0) pulse[0].lengthCounter = 0;
if((data & 0x02) == 0) pulse[1].lengthCounter = 0;
if((data & 0x04) == 0) triangle.lengthCounter = 0;
if((data & 0x08) == 0) noise.lengthCounter = 0;
(data & 0x10) ? dmc.start() : dmc.stop();
dmc.irq_pending = false;
dmc.irqPending = false;
set_irq_line();
enabled_channels = data & 0x1f;
setIRQ();
enabledChannels = data & 0x1f;
return;
}
@ -261,10 +261,10 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
frame.mode = data >> 6;
frame.counter = 0;
if(frame.mode & 2) clock_frame_counter();
if(frame.mode & 2) clockFrameCounter();
if(frame.mode & 1) {
frame.irq_pending = false;
set_irq_line();
frame.irqPending = false;
setIRQ();
}
frame.divider = FrameCounter::NtscPeriod;
return;
@ -273,73 +273,73 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void {
}
}
auto APU::Filter::run_hipass_strong(int sample) -> int {
hipass_strong += ((((int64)sample << 16) - (hipass_strong >> 16)) * HiPassStrong) >> 16;
return sample - (hipass_strong >> 32);
auto APU::Filter::runHipassStrong(int sample) -> int {
hipassStrong += ((((int64)sample << 16) - (hipassStrong >> 16)) * HiPassStrong) >> 16;
return sample - (hipassStrong >> 32);
}
auto APU::Filter::run_hipass_weak(int sample) -> int {
hipass_weak += ((((int64)sample << 16) - (hipass_weak >> 16)) * HiPassWeak) >> 16;
return sample - (hipass_weak >> 32);
auto APU::Filter::runHipassWeak(int sample) -> int {
hipassWeak += ((((int64)sample << 16) - (hipassWeak >> 16)) * HiPassWeak) >> 16;
return sample - (hipassWeak >> 32);
}
auto APU::Filter::run_lopass(int sample) -> int {
auto APU::Filter::runLopass(int sample) -> int {
lopass += ((((int64)sample << 16) - (lopass >> 16)) * LoPass) >> 16;
return (lopass >> 32);
}
auto APU::clock_frame_counter() -> void {
auto APU::clockFrameCounter() -> void {
frame.counter++;
if(frame.counter & 1) {
pulse[0].clock_length();
pulse[0].clockLength();
pulse[0].sweep.clock(0);
pulse[1].clock_length();
pulse[1].clockLength();
pulse[1].sweep.clock(1);
triangle.clock_length();
noise.clock_length();
triangle.clockLength();
noise.clockLength();
}
pulse[0].envelope.clock();
pulse[1].envelope.clock();
triangle.clock_linear_length();
triangle.clockLinearLength();
noise.envelope.clock();
if(frame.counter == 0) {
if(frame.mode & 2) frame.divider += FrameCounter::NtscPeriod;
if(frame.mode == 0) {
frame.irq_pending = true;
set_irq_line();
frame.irqPending = true;
setIRQ();
}
}
}
auto APU::clock_frame_counter_divider() -> void {
auto APU::clockFrameCounterDivider() -> void {
frame.divider -= 2;
if(frame.divider <= 0) {
clock_frame_counter();
clockFrameCounter();
frame.divider += FrameCounter::NtscPeriod;
}
}
const uint8 APU::length_counter_table[32] = {
const uint8 APU::lengthCounterTable[32] = {
0x0a, 0xfe, 0x14, 0x02, 0x28, 0x04, 0x50, 0x06, 0xa0, 0x08, 0x3c, 0x0a, 0x0e, 0x0c, 0x1a, 0x0e,
0x0c, 0x10, 0x18, 0x12, 0x30, 0x14, 0x60, 0x16, 0xc0, 0x18, 0x48, 0x1a, 0x10, 0x1c, 0x20, 0x1e,
};
const uint16 APU::ntsc_noise_period_table[16] = {
const uint16 APU::noisePeriodTableNTSC[16] = {
4, 8, 16, 32, 64, 96, 128, 160, 202, 254, 380, 508, 762, 1016, 2034, 4068,
};
const uint16 APU::pal_noise_period_table[16] = {
const uint16 APU::noisePeriodTablePAL[16] = {
4, 7, 14, 30, 60, 88, 118, 148, 188, 236, 354, 472, 708, 944, 1890, 3778,
};
const uint16 APU::ntsc_dmc_period_table[16] = {
const uint16 APU::dmcPeriodTableNTSC[16] = {
428, 380, 340, 320, 286, 254, 226, 214, 190, 160, 142, 128, 106, 84, 72, 54,
};
const uint16 APU::pal_dmc_period_table[16] = {
const uint16 APU::dmcPeriodTablePAL[16] = {
398, 354, 316, 298, 276, 236, 210, 198, 176, 148, 132, 118, 98, 78, 66, 50,
};

View File

@ -6,8 +6,8 @@ struct APU : Thread {
static auto Enter() -> void;
auto main() -> void;
auto tick() -> void;
auto set_irq_line() -> void;
auto set_sample(int16 sample) -> void;
auto setIRQ() -> void;
auto setSample(int16 sample) -> void;
auto power() -> void;
auto reset() -> void;
@ -18,55 +18,183 @@ struct APU : Thread {
auto serialize(serializer&) -> void;
struct Filter {
auto run_hipass_strong(int sample) -> int;
auto run_hipass_weak(int sample) -> int;
auto run_lopass(int sample) -> int;
auto runHipassStrong(int sample) -> int;
auto runHipassWeak(int sample) -> int;
auto runLopass(int sample) -> int;
auto serialize(serializer&) -> void;
enum : int { HiPassStrong = 225574, HiPassWeak = 57593, LoPass = 86322413 };
int64 hipass_strong;
int64 hipass_weak;
int64 hipassStrong;
int64 hipassWeak;
int64 lopass;
};
#include "envelope.hpp"
#include "sweep.hpp"
#include "pulse.hpp"
#include "triangle.hpp"
#include "noise.hpp"
#include "dmc.hpp"
struct Envelope {
auto volume() const -> uint;
auto clock() -> void;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint4 speed;
bool useSpeedAsVolume;
bool loopMode;
bool reloadDecay;
uint8 decayCounter;
uint4 decayVolume;
};
struct Sweep {
auto checkPeriod() -> bool;
auto clock(uint channel) -> void;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint8 shift;
bool decrement;
uint3 period;
uint8 counter;
bool enable;
bool reload;
uint11 pulsePeriod;
};
struct Pulse {
auto clockLength() -> void;
auto checkPeriod() -> bool;
auto clock() -> uint8;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint lengthCounter;
Envelope envelope;
Sweep sweep;
uint2 duty;
uint3 dutyCounter;
uint11 period;
uint periodCounter;
} pulse[2];
struct Triangle {
auto clockLength() -> void;
auto clockLinearLength() -> void;
auto clock() -> uint8;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint lengthCounter;
uint8 linearLength;
bool haltLengthCounter;
uint11 period;
uint periodCounter;
uint5 stepCounter;
uint8 linearLengthCounter;
bool reloadLinear;
} triangle;
struct Noise {
auto clockLength() -> void;
auto clock() -> uint8;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint lengthCounter;
Envelope envelope;
uint4 period;
uint periodCounter;
bool shortMode;
uint15 lfsr;
} noise;
struct DMC {
auto start() -> void;
auto stop() -> void;
auto clock() -> uint8;
auto power() -> void;
auto reset() -> void;
auto serialize(serializer&) -> void;
uint lengthCounter;
bool irqPending;
uint4 period;
uint periodCounter;
bool irqEnable;
bool loopMode;
uint8 dacLatch;
uint8 addrLatch;
uint8 lengthLatch;
uint15 readAddr;
uint dmaDelayCounter;
uint3 bitCounter;
bool dmaBufferValid;
uint8 dmaBuffer;
bool sampleValid;
uint8 sample;
} dmc;
struct FrameCounter {
auto serialize(serializer&) -> void;
enum : uint { NtscPeriod = 14915 }; //~(21.477MHz / 6 / 240hz)
bool irq_pending;
bool irqPending;
uint2 mode;
uint2 counter;
int divider;
};
auto clock_frame_counter() -> void;
auto clock_frame_counter_divider() -> void;
auto clockFrameCounter() -> void;
auto clockFrameCounterDivider() -> void;
Filter filter;
FrameCounter frame;
uint8 enabled_channels;
int16 cartridge_sample;
uint8 enabledChannels;
int16 cartridgeSample;
int16 pulse_dac[32];
int16 dmc_triangle_noise_dac[128][16][16];
int16 pulseDAC[32];
int16 dmcTriangleNoiseDAC[128][16][16];
static const uint8 length_counter_table[32];
static const uint16 ntsc_dmc_period_table[16];
static const uint16 pal_dmc_period_table[16];
static const uint16 ntsc_noise_period_table[16];
static const uint16 pal_noise_period_table[16];
static const uint8 lengthCounterTable[32];
static const uint16 dmcPeriodTableNTSC[16];
static const uint16 dmcPeriodTablePAL[16];
static const uint16 noisePeriodTableNTSC[16];
static const uint16 noisePeriodTablePAL[16];
};
extern APU apu;

View File

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

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

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

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

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);
frame.serialize(s);
s.integer(enabled_channels);
s.integer(cartridge_sample);
s.integer(enabledChannels);
s.integer(cartridgeSample);
}
auto APU::Filter::serialize(serializer& s) -> void {
s.integer(hipass_strong);
s.integer(hipass_weak);
s.integer(hipassStrong);
s.integer(hipassWeak);
s.integer(lopass);
}
auto APU::Envelope::serialize(serializer& s) -> void {
s.integer(speed);
s.integer(useSpeedAsVolume);
s.integer(loopMode);
s.integer(reloadDecay);
s.integer(decayCounter);
s.integer(decayVolume);
}
auto APU::Sweep::serialize(serializer& s) -> void {
s.integer(shift);
s.integer(decrement);
s.integer(period);
s.integer(counter);
s.integer(enable);
s.integer(reload);
s.integer(pulsePeriod);
}
auto APU::Pulse::serialize(serializer& s) -> void {
s.integer(lengthCounter);
envelope.serialize(s);
sweep.serialize(s);
s.integer(duty);
s.integer(dutyCounter);
s.integer(period);
s.integer(periodCounter);
}
auto APU::Triangle::serialize(serializer& s) -> void {
s.integer(lengthCounter);
s.integer(linearLength);
s.integer(haltLengthCounter);
s.integer(period);
s.integer(periodCounter);
s.integer(stepCounter);
s.integer(linearLengthCounter);
s.integer(reloadLinear);
}
auto APU::Noise::serialize(serializer& s) -> void {
s.integer(lengthCounter);
envelope.serialize(s);
s.integer(period);
s.integer(periodCounter);
s.integer(shortMode);
s.integer(lfsr);
}
auto APU::DMC::serialize(serializer& s) -> void {
s.integer(lengthCounter);
s.integer(irqPending);
s.integer(period);
s.integer(periodCounter);
s.integer(irqEnable);
s.integer(loopMode);
s.integer(dacLatch);
s.integer(addrLatch);
s.integer(lengthLatch);
s.integer(readAddr);
s.integer(dmaDelayCounter);
s.integer(bitCounter);
s.integer(dmaBufferValid);
s.integer(dmaBuffer);
s.integer(sampleValid);
s.integer(sample);
}
auto APU::FrameCounter::serialize(serializer& s) -> void {
s.integer(irq_pending);
s.integer(irqPending);
s.integer(mode);
s.integer(counter);

View File

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

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

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

View File

@ -118,13 +118,13 @@ auto Board::tick() -> void {
if(cartridge.clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
}
auto Board::chr_read(uint addr) -> uint8 {
auto Board::readCHR(uint addr) -> uint8 {
if(chrram.size) return chrram.data[mirror(addr, chrram.size)];
if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)];
return 0u;
}
auto Board::chr_write(uint addr, uint8 data) -> void {
auto Board::writeCHR(uint addr, uint8 data) -> void {
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
}

View File

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

View File

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

View File

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

View File

@ -7,18 +7,18 @@ struct KonamiVRC3 : Board {
vrc3.main();
}
auto prg_read(uint addr) -> uint8 {
auto readPRG(uint addr) -> uint8 {
if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff);
if(addr & 0x8000) return prgrom.read(vrc3.prg_addr(addr));
if(addr & 0x8000) return prgrom.read(vrc3.addrPRG(addr));
return cpu.mdr();
}
auto prg_write(uint addr, uint8 data) -> void {
auto writePRG(uint addr, uint8 data) -> void {
if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data);
if(addr & 0x8000) return vrc3.reg_write(addr, data);
if(addr & 0x8000) return vrc3.writeIO(addr, data);
}
auto chr_read(uint addr) -> uint8 {
auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.readCIRAM(addr & 0x07ff);
@ -26,7 +26,7 @@ struct KonamiVRC3 : Board {
return chrram.read(addr);
}
auto chr_write(uint addr, uint8 data) -> void {
auto writeCHR(uint addr, uint8 data) -> void {
if(addr & 0x2000) {
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
return ppu.writeCIRAM(addr & 0x07ff, data);

View File

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

View File

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

View File

@ -6,26 +6,26 @@ struct KonamiVRC7 : Board {
return vrc7.main();
}
auto prg_read(uint addr) -> uint8 {
auto readPRG(uint addr) -> uint8 {
if(addr < 0x6000) return cpu.mdr();
if(addr < 0x8000) return prgram.read(addr);
return prgrom.read(vrc7.prg_addr(addr));
return prgrom.read(vrc7.addrPRG(addr));
}
auto prg_write(uint addr, uint8 data) -> void {
auto writePRG(uint addr, uint8 data) -> void {
if(addr < 0x6000) return;
if(addr < 0x8000) return prgram.write(addr, data);
return vrc7.reg_write(addr, data);
return vrc7.writeIO(addr, data);
}
auto chr_read(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc7.ciram_addr(addr));
return chrram.read(vrc7.chr_addr(addr));
auto readCHR(uint addr) -> uint8 {
if(addr & 0x2000) return ppu.readCIRAM(vrc7.addrCIRAM(addr));
return chrram.read(vrc7.addrCHR(addr));
}
auto chr_write(uint addr, uint8 data) -> void {
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.ciram_addr(addr), data);
return chrram.write(vrc7.chr_addr(addr), data);
if(addr & 0x2000) return ppu.writeCIRAM(vrc7.addrCIRAM(addr), data);
return chrram.write(vrc7.addrCHR(addr), data);
}
auto power() -> void {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -54,19 +54,19 @@ auto Cartridge::reset() -> void {
}
auto Cartridge::readPRG(uint addr) -> uint8 {
return board->prg_read(addr);
return board->readPRG(addr);
}
auto Cartridge::writePRG(uint addr, uint8 data) -> void {
return board->prg_write(addr, data);
return board->writePRG(addr, data);
}
auto Cartridge::readCHR(uint addr) -> uint8 {
return board->chr_read(addr);
return board->readCHR(addr);
}
auto Cartridge::writeCHR(uint addr, uint8 data) -> void {
return board->chr_write(addr, data);
return board->writeCHR(addr, data);
}
auto Cartridge::scanline(uint y) -> void {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@ -9,31 +9,28 @@ auto PPU::serialize(serializer& s) -> void {
s.integer(r.busData);
s.integer(r.addressLatch);
s.integer(r.vaddr);
s.integer(r.taddr);
s.integer(r.xaddr);
s.integer(r.v.value);
s.integer(r.t.value);
s.integer(r.nmiHold);
s.integer(r.nmiFlag);
s.integer(r.nmiEnable);
s.integer(r.masterSelect);
s.integer(r.spriteHeight);
s.integer(r.bgAddress);
s.integer(r.spriteAddress);
s.integer(r.vramIncrement);
s.integer(r.spriteAddress);
s.integer(r.bgAddress);
s.integer(r.spriteHeight);
s.integer(r.masterSelect);
s.integer(r.nmiEnable);
s.integer(r.emphasis);
s.integer(r.spriteEnable);
s.integer(r.bgEnable);
s.integer(r.spriteEdgeEnable);
s.integer(r.bgEdgeEnable);
s.integer(r.grayscale);
s.integer(r.bgEdgeEnable);
s.integer(r.spriteEdgeEnable);
s.integer(r.bgEnable);
s.integer(r.spriteEnable);
s.integer(r.emphasis);
s.integer(r.spriteZeroHit);
s.integer(r.spriteOverflow);
s.integer(r.spriteZeroHit);
s.integer(r.oamAddress);

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

View File

@ -1,7 +1,5 @@
#include "peripherals.hpp"
struct System {
auto loaded() const -> bool { return _loaded; }
auto loaded() const -> bool { return information.loaded; }
auto run() -> void;
auto runToSave() -> void;
@ -28,12 +26,22 @@ struct System {
auto serializeInit() -> void;
struct Information {
bool loaded = false;
string manifest;
} information;
private:
bool _loaded = false;
uint _serializeSize = 0;
};
struct Peripherals {
auto unload() -> void;
auto reset() -> void;
auto connect(uint port, uint device) -> void;
Controller* controllerPort1 = nullptr;
Controller* controllerPort2 = nullptr;
};
extern System system;
extern Peripherals peripherals;

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

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& invert() { return set(get() ^ 1); }
private:
type data;

View File

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