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.
*
* TO-DO List:
* -----------
* Notes:
* ------
* - VF3 does something weird: it writes DSP (triggering automatic code
* execution because MAN=0) and THEN sets single step mode, expecting an
* interrupt to occur. I suspect this is incorrect operation and that
@ -39,12 +39,7 @@
* jerky graphics). Enabling automatic execution and also allowing single
* stepping to occur when the processor is halted seems to work, but it
* 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.
* - 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
******************************************************************************/
static inline UINT32 Fetch(struct NCR53C810Context *Ctx)
static inline UINT32 Fetch(struct NCR53C810Context *Ctx, UINT32 offset)
{
UINT32 data = Ctx->Bus->Read32(Ctx->regDSP);
Ctx->regDSP += 4;
UINT32 data = Ctx->Bus->Read32(Ctx->regDSP + offset);
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)
{
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->regDBC&0x100000)) // INTFLY
return ErrorLog("53C810 INTFLY instruction not emulated!");
// DSP not incremented (VF3 relies on this)
return OKAY;
}
@ -123,9 +117,9 @@ static bool SCRIPTS_MoveMemory(struct NCR53C810Context *Ctx)
// Get operands
src = Ctx->regDSPS;
dest = Ctx->regTEMP = Fetch(Ctx);
dest = Ctx->regTEMP = Fetch(Ctx, 8); // word 3
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);
@ -149,6 +143,7 @@ static bool SCRIPTS_MoveMemory(struct NCR53C810Context *Ctx)
Ctx->regDBC = 0;
Ctx->regDSPS = src;
Ctx->regTEMP = dest;
Ctx->regDSP += 12;
return OKAY;
}
@ -168,16 +163,16 @@ void C53C810::Run(bool singleStep)
if (singleStep)// && !Ctx.halt)
{
// Fetch instruction (first two words are always fetched)
op = Fetch(&Ctx); // word 1
op = Fetch(&Ctx, 0); // word 1
Ctx.regDBC = op&0x00FFFFFF;
Ctx.regDCMD = (op>>24)&0xFF;
Ctx.regDSPS = Fetch(&Ctx); // word 2
Ctx.regDSPS = Fetch(&Ctx, 4); // word 2
// Single step
OpTable[Ctx.regDCMD](&Ctx);
// 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.IRQ->Assert(Ctx.scsiIRQ); // generate an interrupt
DebugLog("53C810: Asserted IRQ\n");
@ -188,10 +183,10 @@ void C53C810::Run(bool singleStep)
for (i = 0; (i < 100) && !Ctx.halt; i++)
{
// Fetch instruction (first two words are always fetched)
op = Fetch(&Ctx); // word 1
op = Fetch(&Ctx, 0); // word 1
Ctx.regDBC = op&0x00FFFFFF;
Ctx.regDCMD = (op>>24)&0xFF;
Ctx.regDSPS = Fetch(&Ctx); // word 2
Ctx.regDSPS = Fetch(&Ctx, 4); // word 2
// Execute!
if (OpTable[Ctx.regDCMD](&Ctx) != OKAY)