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:
Bart Trzynadlowski 2016-02-23 05:28:17 +00:00
parent 8e6712d2c7
commit 8f87bb1698

View file

@ -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)