fix handling of matrix stack busy flag (the fifo seems to track whether whether a matrix operation is pending and set flag if so; if a non-matrix command jams in a busy geometry engine then backed-up matrix command will cause the flag to get set). fixed wild west, which polls this flag to see when it is safe to read the matrix stack cursor while the geometry engine is jammed. our understanding of the gfx fifo behaviour is still incomplete..

This commit is contained in:
zeromus 2011-10-03 03:04:35 +00:00
parent c73a7cb883
commit 236e4b3374
8 changed files with 114 additions and 83 deletions

View File

@ -1,6 +1,6 @@
/* Copyright (C) 2006 yopyop
/* Copyright 2006 yopyop
Copyright 2007 shash
Copyright 2007-2010 DeSmuME team
Copyright 2007-2011 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -169,6 +169,7 @@ void GFX_PIPEclear()
gxPIPE.head = 0;
gxPIPE.tail = 0;
gxPIPE.size = 0;
gxFIFO.matrix_stack_op_size = 0;
}
void GFX_FIFOclear()
@ -176,6 +177,7 @@ void GFX_FIFOclear()
gxFIFO.head = 0;
gxFIFO.tail = 0;
gxFIFO.size = 0;
gxFIFO.matrix_stack_op_size = 0;
}
static void GXF_FIFO_handleEvents()
@ -189,6 +191,9 @@ static void GXF_FIFO_handleEvents()
bool emptychange = MMU_new.gxstat.fifo_empty ^ empty;
MMU_new.gxstat.fifo_empty = empty;
MMU_new.gxstat.sb = gxFIFO.matrix_stack_op_size != 0;
if(emptychange||lowchange) NDS_Reschedule();
}
@ -220,6 +225,12 @@ void GFX_FIFOsend(u8 cmd, u32 param)
gxFIFO.size++;
if (gxFIFO.tail > HACK_GXIFO_SIZE-1) gxFIFO.tail = 0;
//if a matrix op is entering the pipeline, do accounting for it
//(this is tested by wild west, which will jam a few ops in the fifo and then wait for the matrix stack to be
//un-busy so it can read back the current matrix stack position)
if((cmd & 0xF0) == 0x10)
gxFIFO.matrix_stack_op_size++;
if(gxFIFO.size>=HACK_GXIFO_SIZE) {
printf("--FIFO FULL-- : %d\n",gxFIFO.size);
}
@ -245,6 +256,14 @@ BOOL GFX_PIPErecv(u8 *cmd, u32 *param)
*cmd = gxFIFO.cmd[gxFIFO.head];
*param = gxFIFO.param[gxFIFO.head];
//see the associated increment in another function
if((*cmd & 0xF0) == 0x10)
{
gxFIFO.matrix_stack_op_size--;
if(gxFIFO.matrix_stack_op_size>0x10000000)
printf("bad news disaster in matrix_stack_op_size\n");
}
gxFIFO.head++;
gxFIFO.size--;
if (gxFIFO.head > HACK_GXIFO_SIZE-1) gxFIFO.head = 0;

View File

@ -1,25 +1,20 @@
/* Copyright (C) 2006 yopyop
yopyop156@ifrance.com
yopyop156.ifrance.com
/*
Copyright 2006 yopyop
Copyright 2007 shash
Copyright 2007-2011 DeSmuME team
Copyright 2007 shash
Copyright 2007-2009 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This file is part of DeSmuME
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
DeSmuME is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
DeSmuME is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
You should have received a copy of the GNU General Public License
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
@ -59,6 +54,7 @@ typedef struct
u32 head; // start position
u32 tail; // tail
u32 size; // size FIFO buffer
u32 matrix_stack_op_size; //number of matrix stack items in the fifo (stack is busy when this is nonzero)
} GFX_FIFO;
typedef struct

View File

@ -1636,7 +1636,9 @@ u32 TGXSTAT::read32()
// stack position always equal zero. possible timings is wrong
// using in "The Wild West"
ret |= ((_hack_getMatrixStackLevel(0) << 13) | (_hack_getMatrixStackLevel(1) << 8)); //matrix stack levels //no proof that these are needed yet
int proj_level = _hack_getMatrixStackLevel(0);
int mv_level = _hack_getMatrixStackLevel(1);
ret |= ((proj_level << 13) | (mv_level << 8)); //matrix stack levels //no proof that these are needed yet
ret |= sb<<14; //stack busy
ret |= se<<15;
@ -1649,10 +1651,13 @@ u32 TGXSTAT::read32()
if(isSwapBuffers) ret |= BIT(27);
//if fifo is nonempty, we're busy
if(gxFIFO.size!=0) ret |= BIT(27);
//printf("[%d] %d %d %d\n",currFrameCounter,se,sb,gxFIFO.size!=0);
ret |= ((gxfifo_irq & 0x3) << 30); //user's irq flags
//printf("vc=%03d Returning gxstat read: %08X\n",nds.VCount,ret);
//printf("vc=%03d Returning gxstat read: %08X (isSwapBuffers=%d)\n",nds.VCount,ret,isSwapBuffers);
//ret = (2 << 8);
//INFO("gxSTAT 0x%08X (proj %i, pos %i)\n", ret, _hack_getMatrixStackLevel(1), _hack_getMatrixStackLevel(2));

View File

@ -1776,7 +1776,7 @@ FORCEINLINE void arm9log()
INFO("Disassembler is stopped\n");
}*/
#else
printf("%05d:%03d %12lld 9:%08X %08X %-30s\nR00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
printf("%05d:%03d %12lld 9:%08X %08X %-30s R00:%08X R01:%08X R02:%08X R03:%08X R04:%08X R05:%08X R06:%08X R07:%08X R08:%08X R09:%08X R10:%08X R11:%08X R12:%08X R13:%08X R14:%08X R15:%08X\n",
currFrameCounter, nds.VCount, nds_timer,
NDS_ARM9.instruct_adr,NDS_ARM9.instruction, dasmbuf,
NDS_ARM9.R[0], NDS_ARM9.R[1], NDS_ARM9.R[2], NDS_ARM9.R[3], NDS_ARM9.R[4], NDS_ARM9.R[5], NDS_ARM9.R[6], NDS_ARM9.R[7],
@ -1889,7 +1889,6 @@ static /*donotinline*/ std::pair<s32,s32> armInnerLoop(
timer = minarmtime<doarm9,doarm7>(arm9,arm7);
nds_timer = nds_timer_base + timer;
if (nds_timer >= MMU.gfx3dCycles) MMU_new.gxstat.sb = 0; // clear stack busy flag
}
return std::make_pair(arm9, arm7);

View File

@ -1,6 +1,7 @@
/* Copyright (C) 2006 yopyop
/*
Copyright (C) 2006 yopyop
Copyright (C) 2006-2007 shash
Copyright (C) 2008-2010 DeSmuME team
Copyright (C) 2008-2011 DeSmuME team
This file is part of DeSmuME
@ -3023,6 +3024,7 @@ TEMPLATE static u32 FASTCALL OP_MSR_CPSR(const u32 i)
}
cpu->CPSR.val = ((cpu->CPSR.val & (~mask)) | (operand & mask));
if (BIT16(i)) armcpu_switchMode(cpu, cpu->CPSR.bits.mode);
cpu->changeCPSR();
#else
if(cpu->CPSR.bits.mode!=USR)
{
@ -3070,6 +3072,7 @@ TEMPLATE static u32 FASTCALL OP_MSR_SPSR(const u32 i)
mask = byte_mask & (v4_USER_MASK | v4_PRIV_MASK | v4_STATE_MASK);
}
cpu->SPSR.val = ((cpu->SPSR.val & (~mask)) | (operand & mask));
cpu->changeCPSR();
#else
if(cpu->CPSR.bits.mode!=USR)
{
@ -3084,6 +3087,7 @@ TEMPLATE static u32 FASTCALL OP_MSR_SPSR(const u32 i)
}
if(BIT19(i))
cpu->SPSR.val = (cpu->SPSR.val & 0x00FFFFFF) | (operand & 0xFF000000);
cpu->changeCPSR();
#endif
return 1;
@ -3126,6 +3130,7 @@ TEMPLATE static u32 FASTCALL OP_MSR_CPSR_IMM_VAL(const u32 i)
}
cpu->CPSR.val = ((cpu->CPSR.val & (~mask)) | (operand & mask));
if (BIT16(i)) armcpu_switchMode(cpu, cpu->CPSR.bits.mode);
cpu->changeCPSR();
#else
if(cpu->CPSR.bits.mode!=USR)
{

View File

@ -1,5 +1,6 @@
/* Copyright (C) 2006 yopyop
Copyright (C) 2008-2010 DeSmuME team
/*
Copyright (C) 2006 yopyop
Copyright (C) 2008-2011 DeSmuME team
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -851,8 +852,6 @@ static void gfx3d_glPushMatrix()
if(mymode==2)
MatrixStackPushMatrix (&mtxStack[1], mtxCurrent[1]);
MMU_new.gxstat.sb = 1; // set busy
}
static void gfx3d_glPopMatrix(s32 i)
@ -874,8 +873,6 @@ static void gfx3d_glPopMatrix(s32 i)
if (mymode == 2)
MatrixStackPopMatrix(mtxCurrent[1], &mtxStack[1], i);
MMU_new.gxstat.sb = 1; // set busy
}
static void gfx3d_glStoreMatrix(u32 v)
@ -888,7 +885,9 @@ static void gfx3d_glStoreMatrix(u32 v)
if(mymode==0 || mymode==3)
v = 0;
if (v >= 31) return;
v &= 31;
//this behaviour is unverified. gbatek suggests that it may be meaningful somehow.
if(v==31) return;
MatrixStackLoadMatrix (&mtxStack[mymode], v, mtxCurrent[mymode]);
@ -908,7 +907,14 @@ static void gfx3d_glRestoreMatrix(u32 v)
if(mymode==0 || mymode==3)
v = 0;
if (v >= 31) return;
v &= 31;
//this seems to do something irrational if v==31, as far as we know.
//lets arbitrarily choose to use entry -
if(v==31) {
v = 0;
printf("gfx3d_glRestoreMatrix is using -1. why would anyone do this? please report!\n");
}
MatrixCopy (mtxCurrent[mymode], MatrixStackGetPos(&mtxStack[mymode], v));
@ -916,9 +922,6 @@ static void gfx3d_glRestoreMatrix(u32 v)
if (mymode == 2)
MatrixCopy (mtxCurrent[1], MatrixStackGetPos(&mtxStack[1], v));
//printf("restore: matrix %d to: \n",mymode); MatrixPrint(mtxCurrent[1]);
}
static void gfx3d_glLoadIdentity()
@ -1672,7 +1675,7 @@ s32 gfx3d_GetClipMatrix (unsigned int index)
{
s32 val = MatrixGetMultipliedIndex (index, mtxCurrent[0], mtxCurrent[1]);
//val *= (1<<12);
//printf("reading clip matrix: %d\n",index);
return (s32)val;
}
@ -1827,7 +1830,6 @@ static void gfx3d_execute(u8 cmd, u32 param)
log3D(cmd, param);
#endif
MMU_new.gxstat.sb = 0; // clear stack busy flag
switch (cmd)
{
case 0x10: // MTX_MODE - Set Matrix Mode (W)
@ -2001,6 +2003,8 @@ void gfx3d_glFlush(u32 v)
#endif
isSwapBuffers = TRUE;
//printf("%05d:%03d:%12lld: FLUSH\n",currFrameCounter, nds.VCount, nds_timer);
//well, the game wanted us to flush.
//it may be badly timed. lets just flush it.
@ -2173,6 +2177,8 @@ void gfx3d_VBlankEndSignal(bool skipFrame)
void gfx3d_sendCommandToFIFO(u32 val)
{
//printf("gxFIFO: send val=0x%08X, size=%03i (fifo)\n", val, gxFIFO.size);
gxf_hardware.receive(val);
}
@ -2338,6 +2344,7 @@ SFORMAT SF_GFX3D[]={
{ "GFHE", 4, 1, &gxFIFO.head},
{ "GFTA", 4, 1, &gxFIFO.tail},
{ "GFSZ", 4, 1, &gxFIFO.size},
{ "GFMS", 4, 1, &gxFIFO.matrix_stack_op_size},
{ "GFCM", 1, HACK_GXIFO_SIZE, &gxFIFO.cmd[0]},
{ "GFPM", 4, HACK_GXIFO_SIZE, &gxFIFO.param[0]},
{ "GPHE", 1, 1, &gxPIPE.head},

View File

@ -1,21 +1,19 @@
/*
Copyright (C) 2006-2007 shash
Copyright (C) 2007-2011 DeSmuME team
This file is part of DeSmuME
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
DeSmuME is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
DeSmuME is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
@ -274,7 +272,13 @@ static void MatrixStackSetStackPosition (MatrixStack *stack, int pos)
if((stack->position < 0) || (stack->position > stack->size))
MMU_new.gxstat.se = 1;
stack->position &= stack->size;
//this behaviour is unverified, but its more logical than the old code which would wrap around and turn negative
//it may still be right to wrap around, but we have no proof right now one way or another
if(stack->position < 0)
stack->position = 0;
if(stack->position > stack->size)
stack->position = stack->size;
}
void MatrixStackPushMatrix (MatrixStack *stack, const s32 *ptr)

View File

@ -1,25 +1,20 @@
/* Copyright (C) 2006 yopyop
Copyright (C) 2008-2010 DeSmuME team
/*
Copyright (C) 2006 yopyop
Copyright (C) 2008 shash
Copyright (C) 2008-2011 DeSmuME team
Code added on 18/08/2006 by shash
- Missing missaligned addresses correction
(reference in http://nocash.emubase.de/gbatek.htm#cpumemoryalignments)
This file is part of DeSmuME
DeSmuME is free software; you can redistribute it and/or modify
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
DeSmuME is distributed in the hope that it will be useful,
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DeSmuME; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
along with the this software. If not, see <http://www.gnu.org/licenses/>.
*/
// THUMB core TODO:
@ -1025,26 +1020,27 @@ TEMPLATE static u32 FASTCALL OP_SWI_THUMB(const u32 i)
|| (cpu->intVector == 0xFFFF0000 && PROCNUM==1);
if(cpu->swi_tab && !bypassBuiltinSWI) {
//zero 25-dec-2008 - in arm, we were masking to 0x1F.
//this is probably safer since an invalid opcode could crash the emu
//zero 30-jun-2009 - but they say that the ideas 0xFF should crash the device...
//u32 swinum = cpu->instruction & 0xFF;
//zero 25-dec-2008 - in arm, we were masking to 0x1F.
//this is probably safer since an invalid opcode could crash the emu
//zero 30-jun-2009 - but they say that the ideas 0xFF should crash the device...
//u32 swinum = cpu->instruction & 0xFF;
swinum &= 0x1F;
//printf("%d ARM SWI %d\n",PROCNUM,swinum);
return cpu->swi_tab[swinum]() + 3;
return cpu->swi_tab[swinum]() + 3;
}
else {
/* we use an irq thats not in the irq tab, as
it was replaced due to a changed intVector */
Status_Reg tmp = cpu->CPSR;
armcpu_switchMode(cpu, SVC); /* enter svc mode */
cpu->R[14] = cpu->next_instruction; /* jump to swi Vector */
cpu->SPSR = tmp; /* save old CPSR as new SPSR */
cpu->CPSR.bits.T = 0; /* handle as ARM32 code */
cpu->CPSR.bits.I = 1;
cpu->R[15] = cpu->intVector + 0x08;
cpu->next_instruction = cpu->R[15];
return 3;
/* we use an irq thats not in the irq tab, as
it was replaced due to a changed intVector */
Status_Reg tmp = cpu->CPSR;
armcpu_switchMode(cpu, SVC); /* enter svc mode */
cpu->R[14] = cpu->next_instruction; /* jump to swi Vector */
cpu->SPSR = tmp; /* save old CPSR as new SPSR */
cpu->CPSR.bits.T = 0; /* handle as ARM32 code */
cpu->CPSR.bits.I = 1;
cpu->changeCPSR();
cpu->R[15] = cpu->intVector + 0x08;
cpu->next_instruction = cpu->R[15];
return 3;
}
}