mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 05:45:38 +00:00
PowerPC IRQ line deassertion; DMA only fires interrupts when required
PowerPC no longer clears its own IRQ line; it is now cleared by the IRQ controller when there are no more pending interrupts. Not all games clear DMA interrupts so it was necessary to tweak the 53C810 SCSI controller and the Real3D DMA interface to only fire interrupts if a certain register is correctly set. 53C810 has the documented DIEN (DMA Interrupt Enable) register; Real3D DMA seems to use the low bit of the dmaConfig register. Also I removed the net IRQ as no games seem to actually use it.
This commit is contained in:
parent
9ffce8b92a
commit
e93c5d710f
|
@ -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)
|
||||
|
|
|
@ -53,7 +53,6 @@ void ppc603_exception(int exception)
|
|||
else
|
||||
ppc.npc = 0x00000000 | 0x0500;
|
||||
|
||||
ppc.interrupt_pending &= ~0x1;
|
||||
ppc_change_pc(ppc.npc);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<bool>())
|
||||
{
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue