From 236e4b3374123b24a214f0dc984394936cfff6ab Mon Sep 17 00:00:00 2001 From: zeromus Date: Mon, 3 Oct 2011 03:04:35 +0000 Subject: [PATCH] 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.. --- desmume/src/FIFO.cpp | 23 +++++++++++-- desmume/src/FIFO.h | 34 +++++++++---------- desmume/src/MMU.cpp | 9 +++-- desmume/src/NDSSystem.cpp | 3 +- desmume/src/arm_instructions.cpp | 9 +++-- desmume/src/gfx3d.cpp | 33 +++++++++++------- desmume/src/matrix.cpp | 32 ++++++++++-------- desmume/src/thumb_instructions.cpp | 54 ++++++++++++++---------------- 8 files changed, 114 insertions(+), 83 deletions(-) diff --git a/desmume/src/FIFO.cpp b/desmume/src/FIFO.cpp index 324e2e90f..4e2f5577e 100644 --- a/desmume/src/FIFO.cpp +++ b/desmume/src/FIFO.cpp @@ -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; diff --git a/desmume/src/FIFO.h b/desmume/src/FIFO.h index 40c1057d3..f96c4fa47 100644 --- a/desmume/src/FIFO.h +++ b/desmume/src/FIFO.h @@ -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 . */ @@ -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 diff --git a/desmume/src/MMU.cpp b/desmume/src/MMU.cpp index ca3fcfab8..8c314a511 100644 --- a/desmume/src/MMU.cpp +++ b/desmume/src/MMU.cpp @@ -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)); diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index a66f02773..f4f10e784 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -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 armInnerLoop( timer = minarmtime(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); diff --git a/desmume/src/arm_instructions.cpp b/desmume/src/arm_instructions.cpp index c2d388884..f7680b897 100644 --- a/desmume/src/arm_instructions.cpp +++ b/desmume/src/arm_instructions.cpp @@ -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) { diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index bb326926d..3870583a0 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -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}, diff --git a/desmume/src/matrix.cpp b/desmume/src/matrix.cpp index 4764142b1..f644f4582 100644 --- a/desmume/src/matrix.cpp +++ b/desmume/src/matrix.cpp @@ -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 . */ #include @@ -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) diff --git a/desmume/src/thumb_instructions.cpp b/desmume/src/thumb_instructions.cpp index c6026d4cd..8a9513967 100644 --- a/desmume/src/thumb_instructions.cpp +++ b/desmume/src/thumb_instructions.cpp @@ -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 . */ // 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; } }