fix(fc): fix fc dma interrupt (#1476)

pass cpu_interrupts_v2/4-irq_and_dma.nes
このコミットが含まれているのは:
曾耿森 2024-05-03 18:14:08 +08:00 committed by GitHub
コミット 785c148768
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: B5690EEEBB952194
8個のファイルの変更90行の追加69行の削除

ファイルの表示

@ -148,13 +148,14 @@ struct APU : Thread {
auto clock() -> n8;
auto power(bool reset) -> void;
auto setDMABuffer(n8 data) -> void;
auto dmaAddress() -> n16 const { return 0x8000 | readAddress; }
//serialization.cpp
auto serialize(serializer&) -> void;
n16 lengthCounter;
n16 periodCounter;
n16 dmaDelayCounter;
n1 irqPending;
n4 period;
n1 irqEnable;

ファイルの表示

@ -2,44 +2,19 @@ auto APU::DMC::start() -> void {
if(lengthCounter == 0) {
readAddress = 0x4000 + (addressLatch << 6);
lengthCounter = (lengthLatch << 4) + 1;
if (!dmaBufferValid)
cpu.dmcDMAPending();
}
}
auto APU::DMC::stop() -> void {
lengthCounter = 0;
dmaDelayCounter = 0;
cpu.rdyLine(1);
cpu.rdyAddress(false);
}
auto APU::DMC::clock() -> n8 {
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(sampleValid) {
s32 delta = (((sample >> bitCounter) & 1) << 2) - 2;
@ -52,6 +27,9 @@ auto APU::DMC::clock() -> n8 {
sampleValid = true;
sample = dmaBuffer;
dmaBufferValid = false;
if (lengthCounter > 0)
cpu.dmcDMAPending();
} else {
sampleValid = false;
}
@ -60,18 +38,12 @@ auto APU::DMC::clock() -> n8 {
periodCounter = Region::PAL() ? dmcPeriodTablePAL[period] : dmcPeriodTableNTSC[period];
}
if(lengthCounter > 0 && !dmaBufferValid && dmaDelayCounter == 0) {
cpu.rdyLine(0);
dmaDelayCounter = 4;
}
return result;
}
auto APU::DMC::power(bool reset) -> void {
lengthCounter = 0;
periodCounter = Region::PAL() ? dmcPeriodTablePAL[0] : dmcPeriodTableNTSC[0];
dmaDelayCounter = 0;
irqPending = 0;
period = 0;
irqEnable = 0;
@ -86,3 +58,19 @@ auto APU::DMC::power(bool reset) -> void {
sampleValid = 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 {
s(lengthCounter);
s(periodCounter);
s(dmaDelayCounter);
s(irqPending);
s(period);
s(irqEnable);

ファイルの表示

@ -34,6 +34,7 @@ auto CPU::main() -> void {
auto CPU::step(u32 clocks) -> void {
assert(clocks == rate());
io.oddCycle ^= 1;
Thread::step(clocks);
Thread::synchronize();
}

ファイルの表示

@ -49,15 +49,13 @@ struct CPU : MOS6502, Thread {
auto irqPending() -> bool override;
auto nmi(n16& vector) -> void override;
auto oamDMA() -> void;
auto dmcDMAPending() -> void;
auto dma(n16 address) -> void;
auto nmiLine(bool) -> void;
auto irqLine(bool) -> void;
auto apuLine(bool) -> void;
auto rdyLine(bool) -> void;
auto rdyAddress(bool valid, n16 value = 0) -> void;
//protected:
struct IO {
n1 interruptPending;
@ -65,9 +63,8 @@ struct CPU : MOS6502, Thread {
n1 nmiLine;
n1 irqLine;
n1 apuLine;
n1 rdyLine = 1;
n1 rdyAddressValid;
n16 rdyAddressValue;
n1 oddCycle;
n1 dmcDMAPending;
n1 oamDMAPending;
n8 oamDMAPage;
n8 openBus;

ファイルの表示

@ -7,9 +7,7 @@ auto CPU::serialize(serializer& s) -> void {
s(io.nmiLine);
s(io.irqLine);
s(io.apuLine);
s(io.rdyLine);
s(io.rdyAddressValid);
s(io.rdyAddressValue);
s(io.dmcDMAPending);
s(io.oamDMAPending);
s(io.oamDMAPage);
s(io.openBus);

ファイルの表示

@ -1,13 +1,6 @@
auto CPU::read(n16 address) -> n8 {
if(io.oamDMAPending) {
io.oamDMAPending = 0;
read(address);
oamDMA();
}
while(io.rdyLine == 0) {
io.openBus = readBus(io.rdyAddressValid ? io.rdyAddressValue : address);
step(rate());
if(io.oamDMAPending || io.dmcDMAPending) {
dma(address);
}
io.openBus = readBus(address);
@ -43,10 +36,63 @@ auto CPU::nmi(n16& vector) -> void {
}
}
auto CPU::oamDMA() -> void {
for(u32 n : range(256)) {
n8 data = read(io.oamDMAPage << 8 | n);
write(0x2004, data);
auto CPU::dmcDMAPending() -> void {
io.dmcDMAPending = 1;
}
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
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 {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);