diff --git a/Src/CPU/PowerPC/ppc.cpp b/Src/CPU/PowerPC/ppc.cpp index 326b83b..4f8b8b4 100644 --- a/Src/CPU/PowerPC/ppc.cpp +++ b/Src/CPU/PowerPC/ppc.cpp @@ -868,9 +868,15 @@ void ppc_shutdown(void) void ppc_set_irq_line(int irqline) { - ppc.interrupt_pending |= 0x1; - - ppc603_check_interrupts(); + if (irqline) + { + ppc.interrupt_pending |= 0x1; + ppc603_check_interrupts(); + } + else + { + ppc.interrupt_pending &= ~0x1; + } } UINT32 ppc_get_pc(void) diff --git a/Src/CPU/PowerPC/ppc603.c b/Src/CPU/PowerPC/ppc603.c index fbae6ae..1e1faa1 100644 --- a/Src/CPU/PowerPC/ppc603.c +++ b/Src/CPU/PowerPC/ppc603.c @@ -53,7 +53,6 @@ void ppc603_exception(int exception) else ppc.npc = 0x00000000 | 0x0500; - ppc.interrupt_pending &= ~0x1; ppc_change_pc(ppc.npc); } break; diff --git a/Src/Model3/53C810.cpp b/Src/Model3/53C810.cpp index 1fa34bb..8c893e4 100644 --- a/Src/Model3/53C810.cpp +++ b/Src/Model3/53C810.cpp @@ -65,6 +65,7 @@ void C53C810::SaveState(CBlockFile *SaveState) SaveState->Write(&Ctx.regDCNTL, sizeof(Ctx.regDCNTL)); SaveState->Write(&Ctx.regDMODE, sizeof(Ctx.regDMODE)); SaveState->Write(&Ctx.regDSTAT, sizeof(Ctx.regDSTAT)); + SaveState->Write(&Ctx.regDIEN, sizeof(Ctx.regDIEN)); SaveState->Write(&Ctx.regISTAT, sizeof(Ctx.regISTAT)); } @@ -85,6 +86,7 @@ void C53C810::LoadState(CBlockFile *SaveState) SaveState->Read(&Ctx.regDCNTL, sizeof(Ctx.regDCNTL)); SaveState->Read(&Ctx.regDMODE, sizeof(Ctx.regDMODE)); SaveState->Read(&Ctx.regDSTAT, sizeof(Ctx.regDSTAT)); + SaveState->Read(&Ctx.regDIEN, sizeof(Ctx.regDIEN)); SaveState->Read(&Ctx.regISTAT, sizeof(Ctx.regISTAT)); } @@ -105,7 +107,8 @@ static bool SCRIPTS_Int_IntFly(struct NCR53C810Context *Ctx) Ctx->halt = true; // halt SCRIPTS execution Ctx->regISTAT |= 1; // DMA interrupt pending Ctx->regDSTAT |= 4; // SCRIPTS interrupt instruction received - Ctx->IRQ->Assert(Ctx->scsiIRQ); + if (Ctx->regDIEN & 4) + Ctx->IRQ->Assert(Ctx->scsiIRQ); if ((Ctx->regDBC&0x100000)) // INTFLY return ErrorLog("53C810 INTFLY instruction not emulated!"); // DSP not incremented (VF3 relies on this) @@ -124,7 +127,7 @@ static bool SCRIPTS_MoveMemory(struct NCR53C810Context *Ctx) // Not implemented: illegal instruction interrupt when src and dest are not aligned the same way DebugLog("53C810: Move Memory %08X -> %08X, %X\n", src, dest, numBytes); - //if (dest==0x94000000)printf("53C810: Move Memory %08X -> %08X, %X\n", src, dest, numBytes); + //if (dest==0x94000000)printf("53C810: Move Memory %08X -> %08X, %X\n", src, dest, numBytes); // Perform a 32-bit copy if possible for (i = 0; i < (numBytes/4); i++) @@ -177,8 +180,11 @@ void C53C810::Run(bool singleStep) // Issue IRQ and finish Ctx.regISTAT |= 1; // DMA interrupt pending Ctx.regDSTAT |= 8; // single step interrupt - Ctx.IRQ->Assert(Ctx.scsiIRQ); // generate an interrupt - DebugLog("53C810: Asserted IRQ\n"); + if (Ctx.regDIEN & 8) + { + Ctx.IRQ->Assert(Ctx.scsiIRQ); // generate an interrupt + DebugLog("53C810: Asserted IRQ\n"); + } } else { @@ -317,6 +323,9 @@ void C53C810::WriteRegister(unsigned reg, UINT8 data) case 0x38: // DMODE Ctx.regDMODE = data; break; + case 0x39: // DIEN + Ctx.regDIEN = data; + break; case 0x3B: // DCNTL Ctx.regDCNTL = data; if ((Ctx.regDCNTL&0x14) == 0x14) // single step @@ -396,8 +405,10 @@ UINT8 C53C810::ReadRegister(unsigned reg) return (Ctx.regDSPS>>16)&0xFF; case 0x33: // DSPS 31-24 return (Ctx.regDSPS>>24)&0xFF; - case 0x38: + case 0x38: // DMODE return Ctx.regDMODE; + case 0x39: // DIEN + return Ctx.regDIEN; case 0x3B: // DCNTL return Ctx.regDCNTL; default: // get it from the register file @@ -469,6 +480,7 @@ void C53C810::Reset(void) Ctx.regDCNTL = 0; Ctx.regDMODE = 0; Ctx.regDSTAT = 0x80; // DMA FIFO empty + Ctx.regDIEN = 0; Ctx.regISTAT = 0; Ctx.halt = false; diff --git a/Src/Model3/53C810.h b/Src/Model3/53C810.h index 44c245b..4915317 100644 --- a/Src/Model3/53C810.h +++ b/Src/Model3/53C810.h @@ -52,6 +52,7 @@ struct NCR53C810Context UINT8 regDCNTL; // DCNTL: DMA Control UINT8 regDMODE; // DMODE: DMA Mode UINT8 regDSTAT; // DSTAT: DMA Status (read only) + UINT8 regDIEN; // DIEN: DMA Interrupt Enable UINT8 regISTAT; // ISTAT: Interrupt Status // Operational status diff --git a/Src/Model3/IRQ.cpp b/Src/Model3/IRQ.cpp index 27a288e..5183626 100644 --- a/Src/Model3/IRQ.cpp +++ b/Src/Model3/IRQ.cpp @@ -69,17 +69,16 @@ void CIRQ::Assert(unsigned irqBits) { irqState |= irqBits; if ((irqState&irqEnable)) // low 8 bits are maskable interrupts - //ppc_set_irq_line(0); ppc_set_irq_line(1); if ((irqState&(~0xFF))) // any non-maskable interrupts pending? - //ppc_set_irq_line(0); ppc_set_irq_line(1); } -//TO-DO: CPU needs to have deassert logic! void CIRQ::Deassert(unsigned irqBits) { irqState &= ~irqBits; + if (!(irqState & irqEnable) && !(irqState & (~0xFF))) + ppc_set_irq_line(0); // if no pending IRQs, deassert CPU IRQ line } void CIRQ::WriteIRQEnable(UINT8 data) diff --git a/Src/Model3/Model3.cpp b/Src/Model3/Model3.cpp index 42ed635..08fd885 100644 --- a/Src/Model3/Model3.cpp +++ b/Src/Model3/Model3.cpp @@ -840,13 +840,8 @@ void CModel3::WritePCIConfigSpace(unsigned device, unsigned reg, unsigned bits, /****************************************************************************** Model 3 System Registers - NOTE: Proper IRQ handling requires a "deassert" function in the PowerPC core, - which the interpreter presently lacks. This is because different modules that - generate IRQs, like the tilegen, Real3D, and SCSP, should each call - IRQ.Assert() on their own, which will assert the CPU IRQ line. Right now, - the CPU processes an interrupt and clears the line by itself, which means that - if multiple interrupts are asserted simultaneously, depending on the IRQ - handler code, only one may be processed. Keep an eye on this! + NOTE: Different modules that generate IRQs, like the tilegen, Real3D, and + SCSP, should each call IRQ.Assert() on their own. ******************************************************************************/ // Set the CROM bank index (active low logic) @@ -2003,16 +1998,7 @@ void CModel3::RunFrame(void) #ifdef NET_BOARD if (NetBoard->IsRunning() && m_config["SimulateNet"].ValueAs()) - { - // ppc irq network needed ? no effect, is it really active/needed ? - IRQ.Assert(0x10); - ppc_execute(200); // give PowerPC time to acknowledge IRQ - IRQ.Deassert(0x10); - ppc_execute(200); // acknowledge that IRQ was deasserted (TODO: is this really needed?) RunNetBoardFrame(); - // Hum hum, if runnetboardframe is called at 1st place or between ppc irq assert/deassert, spikout freezes just after the gate with net error - // if runnetboardframe is called after ppc irq assert/deassert, spikout works - } #endif } else @@ -2026,16 +2012,7 @@ void CModel3::RunFrame(void) RunDriveBoardFrame(); #ifdef NET_BOARD if (NetBoard->IsRunning()) - { - // ppc irq network needed ? no effect, is it really active/needed ? - IRQ.Assert(0x10); - ppc_execute(200); // give PowerPC time to acknowledge IRQ - IRQ.Deassert(0x10); - ppc_execute(200); // acknowledge that IRQ was deasserted (TODO: is this really needed?) RunNetBoardFrame(); - // Hum hum, if runnetboardframe is called at 1st place or between ppc irq assert/deassert, spikout freezes just after the gate with net error - // if runnetboardframe is called after ppc irq assert/deassert, spikout works - } #endif } diff --git a/Src/Model3/Real3D.cpp b/Src/Model3/Real3D.cpp index 30a00ee..609b340 100644 --- a/Src/Model3/Real3D.cpp +++ b/Src/Model3/Real3D.cpp @@ -619,8 +619,11 @@ void CReal3D::WriteDMARegister32(unsigned reg, uint32_t data) case 0x08: // DMA length dmaLength = data; DMACopy(); - dmaStatus |= 1; - IRQ->Assert(dmaIRQ); + if (dmaConfig & 1) // only fire an IRQ if the low bit of dmaConfig is set + { + dmaStatus |= 1; + IRQ->Assert(dmaIRQ); + } break; case 0x10: // command register if ((data&0x20000000)) // DMA ID command