mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2025-02-18 10:15:38 +00:00
53c810: do not increment DSP when executing interrupt instruction. Fixes invalid polygons in Virtua Fighter 3. Thanks to Ian Curtis for discovering that the polygons were incorrectly-copied garbage.
This commit is contained in:
parent
8e6712d2c7
commit
8f87bb1698
|
@ -24,8 +24,8 @@
|
||||||
*
|
*
|
||||||
* Implementation of the C53C810 class: NCR 53C810 SCSI controller.
|
* Implementation of the C53C810 class: NCR 53C810 SCSI controller.
|
||||||
*
|
*
|
||||||
* TO-DO List:
|
* Notes:
|
||||||
* -----------
|
* ------
|
||||||
* - VF3 does something weird: it writes DSP (triggering automatic code
|
* - VF3 does something weird: it writes DSP (triggering automatic code
|
||||||
* execution because MAN=0) and THEN sets single step mode, expecting an
|
* execution because MAN=0) and THEN sets single step mode, expecting an
|
||||||
* interrupt to occur. I suspect this is incorrect operation and that
|
* interrupt to occur. I suspect this is incorrect operation and that
|
||||||
|
@ -39,12 +39,7 @@
|
||||||
* jerky graphics). Enabling automatic execution and also allowing single
|
* jerky graphics). Enabling automatic execution and also allowing single
|
||||||
* stepping to occur when the processor is halted seems to work, but it
|
* stepping to occur when the processor is halted seems to work, but it
|
||||||
* causes invalid instructions to be hit each time.
|
* causes invalid instructions to be hit each time.
|
||||||
* - Check to ensure the invalid instructions hit above would never be decoded
|
|
||||||
* as real SCRIPTS instructions (in some cases, appears they can be...)
|
|
||||||
* - Is the SIP bit supposed to be set after single stepping?
|
|
||||||
* - pg 2-22 (42) of the manual has description of how to clear interrupts.
|
* - pg 2-22 (42) of the manual has description of how to clear interrupts.
|
||||||
* - Another way to fix VF3 is to just set the single-step and DMA interrupt
|
|
||||||
* flags at all times.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -96,23 +91,22 @@ void C53C810::LoadState(CBlockFile *SaveState)
|
||||||
SCRIPTS Emulation
|
SCRIPTS Emulation
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
static inline UINT32 Fetch(struct NCR53C810Context *Ctx)
|
static inline UINT32 Fetch(struct NCR53C810Context *Ctx, UINT32 offset)
|
||||||
{
|
{
|
||||||
UINT32 data = Ctx->Bus->Read32(Ctx->regDSP);
|
UINT32 data = Ctx->Bus->Read32(Ctx->regDSP + offset);
|
||||||
Ctx->regDSP += 4;
|
|
||||||
return FLIPENDIAN32(data); // remember: bus is big endian, need to convert to little endian
|
return FLIPENDIAN32(data); // remember: bus is big endian, need to convert to little endian
|
||||||
}
|
}
|
||||||
|
|
||||||
//TO-DO: check if this ever occurs in single-step mode (if so, we would need to stack interrupts)
|
//TODO: what happens if interrupt is executed in single step mode?
|
||||||
static bool SCRIPTS_Int_IntFly(struct NCR53C810Context *Ctx)
|
static bool SCRIPTS_Int_IntFly(struct NCR53C810Context *Ctx)
|
||||||
{
|
{
|
||||||
Ctx->halt = true; // halt SCRIPTS execution
|
Ctx->halt = true; // halt SCRIPTS execution
|
||||||
Ctx->regISTAT |= 1; // DMA interrupt pending
|
Ctx->regISTAT |= 1; // DMA interrupt pending
|
||||||
Ctx->regDSTAT |= 4; // SCRIPTS interrupt instruction received
|
Ctx->regDSTAT |= 4; // SCRIPTS interrupt instruction received
|
||||||
Ctx->IRQ->Assert(Ctx->scsiIRQ);
|
Ctx->IRQ->Assert(Ctx->scsiIRQ);
|
||||||
|
|
||||||
if ((Ctx->regDBC&0x100000)) // INTFLY
|
if ((Ctx->regDBC&0x100000)) // INTFLY
|
||||||
return ErrorLog("53C810 INTFLY instruction not emulated!");
|
return ErrorLog("53C810 INTFLY instruction not emulated!");
|
||||||
|
// DSP not incremented (VF3 relies on this)
|
||||||
return OKAY;
|
return OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,9 +117,9 @@ static bool SCRIPTS_MoveMemory(struct NCR53C810Context *Ctx)
|
||||||
|
|
||||||
// Get operands
|
// Get operands
|
||||||
src = Ctx->regDSPS;
|
src = Ctx->regDSPS;
|
||||||
dest = Ctx->regTEMP = Fetch(Ctx);
|
dest = Ctx->regTEMP = Fetch(Ctx, 8); // word 3
|
||||||
numBytes = Ctx->regDBC;
|
numBytes = Ctx->regDBC;
|
||||||
// not implemented: illegal instruction interrupt when src and dest are not aligned the same way
|
// 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);
|
DebugLog("53C810: Move Memory %08X -> %08X, %X\n", src, dest, numBytes);
|
||||||
|
|
||||||
|
@ -149,6 +143,7 @@ static bool SCRIPTS_MoveMemory(struct NCR53C810Context *Ctx)
|
||||||
Ctx->regDBC = 0;
|
Ctx->regDBC = 0;
|
||||||
Ctx->regDSPS = src;
|
Ctx->regDSPS = src;
|
||||||
Ctx->regTEMP = dest;
|
Ctx->regTEMP = dest;
|
||||||
|
Ctx->regDSP += 12;
|
||||||
|
|
||||||
return OKAY;
|
return OKAY;
|
||||||
}
|
}
|
||||||
|
@ -168,16 +163,16 @@ void C53C810::Run(bool singleStep)
|
||||||
if (singleStep)// && !Ctx.halt)
|
if (singleStep)// && !Ctx.halt)
|
||||||
{
|
{
|
||||||
// Fetch instruction (first two words are always fetched)
|
// Fetch instruction (first two words are always fetched)
|
||||||
op = Fetch(&Ctx); // word 1
|
op = Fetch(&Ctx, 0); // word 1
|
||||||
Ctx.regDBC = op&0x00FFFFFF;
|
Ctx.regDBC = op&0x00FFFFFF;
|
||||||
Ctx.regDCMD = (op>>24)&0xFF;
|
Ctx.regDCMD = (op>>24)&0xFF;
|
||||||
Ctx.regDSPS = Fetch(&Ctx); // word 2
|
Ctx.regDSPS = Fetch(&Ctx, 4); // word 2
|
||||||
|
|
||||||
// Single step
|
// Single step
|
||||||
OpTable[Ctx.regDCMD](&Ctx);
|
OpTable[Ctx.regDCMD](&Ctx);
|
||||||
|
|
||||||
// Issue IRQ and finish
|
// Issue IRQ and finish
|
||||||
Ctx.regISTAT |= 3; // DMA interrupt pending (NOTE: should SIP be set? I don't think so...)
|
Ctx.regISTAT |= 1; // DMA interrupt pending
|
||||||
Ctx.regDSTAT |= 8; // single step interrupt
|
Ctx.regDSTAT |= 8; // single step interrupt
|
||||||
Ctx.IRQ->Assert(Ctx.scsiIRQ); // generate an interrupt
|
Ctx.IRQ->Assert(Ctx.scsiIRQ); // generate an interrupt
|
||||||
DebugLog("53C810: Asserted IRQ\n");
|
DebugLog("53C810: Asserted IRQ\n");
|
||||||
|
@ -188,10 +183,10 @@ void C53C810::Run(bool singleStep)
|
||||||
for (i = 0; (i < 100) && !Ctx.halt; i++)
|
for (i = 0; (i < 100) && !Ctx.halt; i++)
|
||||||
{
|
{
|
||||||
// Fetch instruction (first two words are always fetched)
|
// Fetch instruction (first two words are always fetched)
|
||||||
op = Fetch(&Ctx); // word 1
|
op = Fetch(&Ctx, 0); // word 1
|
||||||
Ctx.regDBC = op&0x00FFFFFF;
|
Ctx.regDBC = op&0x00FFFFFF;
|
||||||
Ctx.regDCMD = (op>>24)&0xFF;
|
Ctx.regDCMD = (op>>24)&0xFF;
|
||||||
Ctx.regDSPS = Fetch(&Ctx); // word 2
|
Ctx.regDSPS = Fetch(&Ctx, 4); // word 2
|
||||||
|
|
||||||
// Execute!
|
// Execute!
|
||||||
if (OpTable[Ctx.regDCMD](&Ctx) != OKAY)
|
if (OpTable[Ctx.regDCMD](&Ctx) != OKAY)
|
||||||
|
|
Loading…
Reference in a new issue