pass cpu_interrupts_v2/4-irq_and_dma.nes
このコミットが含まれているのは:
コミット
785c148768
|
@ -148,13 +148,14 @@ struct APU : Thread {
|
||||||
auto clock() -> n8;
|
auto clock() -> n8;
|
||||||
|
|
||||||
auto power(bool reset) -> void;
|
auto power(bool reset) -> void;
|
||||||
|
auto setDMABuffer(n8 data) -> void;
|
||||||
|
auto dmaAddress() -> n16 const { return 0x8000 | readAddress; }
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
n16 lengthCounter;
|
n16 lengthCounter;
|
||||||
n16 periodCounter;
|
n16 periodCounter;
|
||||||
n16 dmaDelayCounter;
|
|
||||||
n1 irqPending;
|
n1 irqPending;
|
||||||
n4 period;
|
n4 period;
|
||||||
n1 irqEnable;
|
n1 irqEnable;
|
||||||
|
|
|
@ -2,44 +2,19 @@ auto APU::DMC::start() -> void {
|
||||||
if(lengthCounter == 0) {
|
if(lengthCounter == 0) {
|
||||||
readAddress = 0x4000 + (addressLatch << 6);
|
readAddress = 0x4000 + (addressLatch << 6);
|
||||||
lengthCounter = (lengthLatch << 4) + 1;
|
lengthCounter = (lengthLatch << 4) + 1;
|
||||||
|
|
||||||
|
if (!dmaBufferValid)
|
||||||
|
cpu.dmcDMAPending();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::DMC::stop() -> void {
|
auto APU::DMC::stop() -> void {
|
||||||
lengthCounter = 0;
|
lengthCounter = 0;
|
||||||
dmaDelayCounter = 0;
|
|
||||||
cpu.rdyLine(1);
|
|
||||||
cpu.rdyAddress(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::DMC::clock() -> n8 {
|
auto APU::DMC::clock() -> n8 {
|
||||||
n8 result = dacLatch;
|
n8 result = dacLatch;
|
||||||
|
|
||||||
if(dmaDelayCounter > 0) {
|
|
||||||
dmaDelayCounter--;
|
|
||||||
|
|
||||||
if(dmaDelayCounter == 1) {
|
|
||||||
cpu.rdyAddress(true, 0x8000 | readAddress);
|
|
||||||
} else if(dmaDelayCounter == 0) {
|
|
||||||
cpu.rdyLine(1);
|
|
||||||
cpu.rdyAddress(false);
|
|
||||||
|
|
||||||
dmaBuffer = cpu.io.openBus;
|
|
||||||
dmaBufferValid = true;
|
|
||||||
lengthCounter--;
|
|
||||||
readAddress++;
|
|
||||||
|
|
||||||
if(lengthCounter == 0) {
|
|
||||||
if(loopMode) {
|
|
||||||
start();
|
|
||||||
} else if(irqEnable) {
|
|
||||||
irqPending = true;
|
|
||||||
apu.setIRQ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(--periodCounter == 0) {
|
if(--periodCounter == 0) {
|
||||||
if(sampleValid) {
|
if(sampleValid) {
|
||||||
s32 delta = (((sample >> bitCounter) & 1) << 2) - 2;
|
s32 delta = (((sample >> bitCounter) & 1) << 2) - 2;
|
||||||
|
@ -52,6 +27,9 @@ auto APU::DMC::clock() -> n8 {
|
||||||
sampleValid = true;
|
sampleValid = true;
|
||||||
sample = dmaBuffer;
|
sample = dmaBuffer;
|
||||||
dmaBufferValid = false;
|
dmaBufferValid = false;
|
||||||
|
|
||||||
|
if (lengthCounter > 0)
|
||||||
|
cpu.dmcDMAPending();
|
||||||
} else {
|
} else {
|
||||||
sampleValid = false;
|
sampleValid = false;
|
||||||
}
|
}
|
||||||
|
@ -60,18 +38,12 @@ auto APU::DMC::clock() -> n8 {
|
||||||
periodCounter = Region::PAL() ? dmcPeriodTablePAL[period] : dmcPeriodTableNTSC[period];
|
periodCounter = Region::PAL() ? dmcPeriodTablePAL[period] : dmcPeriodTableNTSC[period];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(lengthCounter > 0 && !dmaBufferValid && dmaDelayCounter == 0) {
|
|
||||||
cpu.rdyLine(0);
|
|
||||||
dmaDelayCounter = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::DMC::power(bool reset) -> void {
|
auto APU::DMC::power(bool reset) -> void {
|
||||||
lengthCounter = 0;
|
lengthCounter = 0;
|
||||||
periodCounter = Region::PAL() ? dmcPeriodTablePAL[0] : dmcPeriodTableNTSC[0];
|
periodCounter = Region::PAL() ? dmcPeriodTablePAL[0] : dmcPeriodTableNTSC[0];
|
||||||
dmaDelayCounter = 0;
|
|
||||||
irqPending = 0;
|
irqPending = 0;
|
||||||
period = 0;
|
period = 0;
|
||||||
irqEnable = 0;
|
irqEnable = 0;
|
||||||
|
@ -86,3 +58,19 @@ auto APU::DMC::power(bool reset) -> void {
|
||||||
sampleValid = 0;
|
sampleValid = 0;
|
||||||
sample = 0;
|
sample = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto APU::DMC::setDMABuffer(n8 data) -> void {
|
||||||
|
dmaBuffer = data;
|
||||||
|
dmaBufferValid = true;
|
||||||
|
lengthCounter--;
|
||||||
|
readAddress++;
|
||||||
|
|
||||||
|
if (lengthCounter == 0) {
|
||||||
|
if (loopMode) {
|
||||||
|
start();
|
||||||
|
} else if (irqEnable) {
|
||||||
|
irqPending = true;
|
||||||
|
apu.setIRQ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -70,7 +70,6 @@ auto APU::Noise::serialize(serializer& s) -> void {
|
||||||
auto APU::DMC::serialize(serializer& s) -> void {
|
auto APU::DMC::serialize(serializer& s) -> void {
|
||||||
s(lengthCounter);
|
s(lengthCounter);
|
||||||
s(periodCounter);
|
s(periodCounter);
|
||||||
s(dmaDelayCounter);
|
|
||||||
s(irqPending);
|
s(irqPending);
|
||||||
s(period);
|
s(period);
|
||||||
s(irqEnable);
|
s(irqEnable);
|
||||||
|
|
|
@ -34,6 +34,7 @@ auto CPU::main() -> void {
|
||||||
|
|
||||||
auto CPU::step(u32 clocks) -> void {
|
auto CPU::step(u32 clocks) -> void {
|
||||||
assert(clocks == rate());
|
assert(clocks == rate());
|
||||||
|
io.oddCycle ^= 1;
|
||||||
Thread::step(clocks);
|
Thread::step(clocks);
|
||||||
Thread::synchronize();
|
Thread::synchronize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,15 +49,13 @@ struct CPU : MOS6502, Thread {
|
||||||
auto irqPending() -> bool override;
|
auto irqPending() -> bool override;
|
||||||
auto nmi(n16& vector) -> void override;
|
auto nmi(n16& vector) -> void override;
|
||||||
|
|
||||||
auto oamDMA() -> void;
|
auto dmcDMAPending() -> void;
|
||||||
|
auto dma(n16 address) -> void;
|
||||||
|
|
||||||
auto nmiLine(bool) -> void;
|
auto nmiLine(bool) -> void;
|
||||||
auto irqLine(bool) -> void;
|
auto irqLine(bool) -> void;
|
||||||
auto apuLine(bool) -> void;
|
auto apuLine(bool) -> void;
|
||||||
|
|
||||||
auto rdyLine(bool) -> void;
|
|
||||||
auto rdyAddress(bool valid, n16 value = 0) -> void;
|
|
||||||
|
|
||||||
//protected:
|
//protected:
|
||||||
struct IO {
|
struct IO {
|
||||||
n1 interruptPending;
|
n1 interruptPending;
|
||||||
|
@ -65,9 +63,8 @@ struct CPU : MOS6502, Thread {
|
||||||
n1 nmiLine;
|
n1 nmiLine;
|
||||||
n1 irqLine;
|
n1 irqLine;
|
||||||
n1 apuLine;
|
n1 apuLine;
|
||||||
n1 rdyLine = 1;
|
n1 oddCycle;
|
||||||
n1 rdyAddressValid;
|
n1 dmcDMAPending;
|
||||||
n16 rdyAddressValue;
|
|
||||||
n1 oamDMAPending;
|
n1 oamDMAPending;
|
||||||
n8 oamDMAPage;
|
n8 oamDMAPage;
|
||||||
n8 openBus;
|
n8 openBus;
|
||||||
|
|
|
@ -7,9 +7,7 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s(io.nmiLine);
|
s(io.nmiLine);
|
||||||
s(io.irqLine);
|
s(io.irqLine);
|
||||||
s(io.apuLine);
|
s(io.apuLine);
|
||||||
s(io.rdyLine);
|
s(io.dmcDMAPending);
|
||||||
s(io.rdyAddressValid);
|
|
||||||
s(io.rdyAddressValue);
|
|
||||||
s(io.oamDMAPending);
|
s(io.oamDMAPending);
|
||||||
s(io.oamDMAPage);
|
s(io.oamDMAPage);
|
||||||
s(io.openBus);
|
s(io.openBus);
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
auto CPU::read(n16 address) -> n8 {
|
auto CPU::read(n16 address) -> n8 {
|
||||||
if(io.oamDMAPending) {
|
if(io.oamDMAPending || io.dmcDMAPending) {
|
||||||
io.oamDMAPending = 0;
|
dma(address);
|
||||||
read(address);
|
|
||||||
oamDMA();
|
|
||||||
}
|
|
||||||
|
|
||||||
while(io.rdyLine == 0) {
|
|
||||||
io.openBus = readBus(io.rdyAddressValid ? io.rdyAddressValue : address);
|
|
||||||
step(rate());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
io.openBus = readBus(address);
|
io.openBus = readBus(address);
|
||||||
|
@ -43,10 +36,63 @@ auto CPU::nmi(n16& vector) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::oamDMA() -> void {
|
auto CPU::dmcDMAPending() -> void {
|
||||||
for(u32 n : range(256)) {
|
io.dmcDMAPending = 1;
|
||||||
n8 data = read(io.oamDMAPage << 8 | n);
|
}
|
||||||
write(0x2004, data);
|
|
||||||
|
auto CPU::dma(n16 address) -> void {
|
||||||
|
bool dmcReady = false;
|
||||||
|
bool oamWriteReady = false;
|
||||||
|
n8 oamCounter = 0;
|
||||||
|
|
||||||
|
// halt read
|
||||||
|
io.openBus = readBus(address);
|
||||||
|
step(rate());
|
||||||
|
|
||||||
|
while (io.dmcDMAPending || io.oamDMAPending) {
|
||||||
|
if (io.oddCycle) {
|
||||||
|
// put_cycle
|
||||||
|
if (io.oamDMAPending && oamWriteReady) {
|
||||||
|
if (io.dmcDMAPending)
|
||||||
|
dmcReady = true;
|
||||||
|
|
||||||
|
// oam write
|
||||||
|
writeBus(0x2004, io.openBus);
|
||||||
|
step(rate());
|
||||||
|
|
||||||
|
oamWriteReady = false;
|
||||||
|
if (++oamCounter == 0)
|
||||||
|
io.oamDMAPending = 0;
|
||||||
|
} else {
|
||||||
|
// oam (re)alignment cycle
|
||||||
|
// dmc alignment cycle
|
||||||
|
if (io.dmcDMAPending)
|
||||||
|
dmcReady = true;
|
||||||
|
|
||||||
|
io.openBus = readBus(address);
|
||||||
|
step(rate());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// get_cycle
|
||||||
|
if (io.dmcDMAPending && dmcReady) {
|
||||||
|
// dmc read
|
||||||
|
io.openBus = readBus(apu.dmc.dmaAddress());
|
||||||
|
step(rate());
|
||||||
|
|
||||||
|
apu.dmc.setDMABuffer(io.openBus);
|
||||||
|
io.dmcDMAPending = 0;
|
||||||
|
dmcReady = false;
|
||||||
|
} else if (io.oamDMAPending) {
|
||||||
|
// oam read
|
||||||
|
io.openBus = readBus(io.oamDMAPage << 8 | oamCounter);
|
||||||
|
step(rate());
|
||||||
|
oamWriteReady = true;
|
||||||
|
} else {
|
||||||
|
// dmc dummy read cycle
|
||||||
|
io.openBus = readBus(address);
|
||||||
|
step(rate());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,12 +111,3 @@ auto CPU::apuLine(bool line) -> void {
|
||||||
//level-sensitive
|
//level-sensitive
|
||||||
io.apuLine = line;
|
io.apuLine = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::rdyLine(bool line) -> void {
|
|
||||||
io.rdyLine = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::rdyAddress(bool valid, n16 value) -> void {
|
|
||||||
io.rdyAddressValid = valid;
|
|
||||||
io.rdyAddressValue = value;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
static const string SerializerVersion = "v140";
|
static const string SerializerVersion = "v141";
|
||||||
|
|
||||||
auto System::serialize(bool synchronize) -> serializer {
|
auto System::serialize(bool synchronize) -> serializer {
|
||||||
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
|
||||||
|
|
読み込み中…
新しいイシューから参照