pass cpu_interrupts_v2/4-irq_and_dma.nes
このコミットが含まれているのは:
コミット
785c148768
|
@ -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);
|
||||
|
|
読み込み中…
新しいイシューから参照