From: <ze...@us...> - 2012-03-29 22:45:11
|
Revision: 4221 http://desmume.svn.sourceforge.net/desmume/?rev=4221&view=rev Author: zeromus Date: 2012-03-29 22:45:05 +0000 (Thu, 29 Mar 2012) Log Message: ----------- re-time LCD state machine to conform more closely to reality. also, delay IRQ for vmatch and vblank by 1 dot from their flag settings to act very crudely like a pipeline and fix games with race conditions between flag-read and irq by allowing the flag-read to win sometimes (e.g. egokoro kyoushitsu). check for regressions in any raster fx. Modified Paths: -------------- trunk/desmume/src/MMU.cpp trunk/desmume/src/MMU.h trunk/desmume/src/NDSSystem.cpp trunk/desmume/src/saves.cpp Modified: trunk/desmume/src/MMU.cpp =================================================================== --- trunk/desmume/src/MMU.cpp 2012-03-29 21:01:24 UTC (rev 4220) +++ trunk/desmume/src/MMU.cpp 2012-03-29 22:45:05 UTC (rev 4221) @@ -913,6 +913,7 @@ memset(MMU.reg_IME, 0, sizeof(u32) * 2); memset(MMU.reg_IE, 0, sizeof(u32) * 2); memset(MMU.reg_IF_bits, 0, sizeof(u32) * 2); + memset(MMU.reg_IF_pending, 0, sizeof(u32) * 2); memset(MMU.dscard, 0, sizeof(nds_dscard) * 2); @@ -3461,7 +3462,9 @@ { nds.ensataHandshake = ENSATA_HANDSHAKE_ack; return 270; - } else return nds.VCount; + } + else + return nds.VCount; // ============================================= 3D case eng_3D_RAM_COUNT: Modified: trunk/desmume/src/MMU.h =================================================================== --- trunk/desmume/src/MMU.h 2012-03-29 21:01:24 UTC (rev 4220) +++ trunk/desmume/src/MMU.h 2012-03-29 22:45:05 UTC (rev 4221) @@ -390,6 +390,8 @@ //these are the user-controlled IF bits. some IF bits are generated as necessary from hardware conditions u32 reg_IF_bits[2]; + //these flags are set occasionally to indicate that an irq should have entered the pipeline, and processing will be deferred a tiny bit to help emulate things + u32 reg_IF_pending[2]; u32 reg_DISP3DCNT_bits; Modified: trunk/desmume/src/NDSSystem.cpp =================================================================== --- trunk/desmume/src/NDSSystem.cpp 2012-03-29 21:01:24 UTC (rev 4220) +++ trunk/desmume/src/NDSSystem.cpp 2012-03-29 22:45:05 UTC (rev 4221) @@ -1050,7 +1050,7 @@ enum ESI_DISPCNT { - ESI_DISPCNT_HStart, ESI_DISPCNT_HBlank + ESI_DISPCNT_HStart, ESI_DISPCNT_HStartIRQ, ESI_DISPCNT_HDraw, ESI_DISPCNT_HBlank }; u64 nds_timer; @@ -1505,8 +1505,8 @@ sequencer.reschedule = true; //turn off vblank status bit - T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & 0xFFFE); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFE); + T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) & ~1); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & ~1); //some emulation housekeeping frameSkipper.Advance(); @@ -1516,17 +1516,14 @@ { //printf("--------VBLANK!!!--------\n"); - //turn on vblank status bit - T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1); - T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); - //fire vblank interrupts if necessary - if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VBLANK); - if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VBLANK); + for(int i=0;i<2;i++) + if(MMU.reg_IF_pending[i] & (1<<IRQ_BIT_LCD_VBLANK)) + { + MMU.reg_IF_pending[i] &= ~(1<<IRQ_BIT_LCD_VBLANK); + NDS_makeIrq(i,IRQ_BIT_LCD_VBLANK); + } - //some emulation housekeeping - gfx3d_VBlankSignal(); - //trigger vblank dmas triggerDma(EDMAMode_VBlank); @@ -1539,16 +1536,37 @@ nds.idleCycles[1] = 0; } -static void execHardware_hstart_vcount() +static u16 execHardware_gen_vmatch_goal() { u16 vmatch = T1ReadWord(MMU.ARM9_REG, 4); vmatch = ((vmatch>>8)|((vmatch<<1)&(1<<8))); + return vmatch; +} + +static void execHardware_hstart_vcount_irq() +{ + //trigger pending VMATCH irqs + if(MMU.reg_IF_pending[ARMCPU_ARM9] & (1<<IRQ_BIT_LCD_VMATCH)) + { + MMU.reg_IF_pending[ARMCPU_ARM9] &= ~(1<<IRQ_BIT_LCD_VMATCH); + NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH); + } + if(MMU.reg_IF_pending[ARMCPU_ARM7] & (1<<IRQ_BIT_LCD_VMATCH)) + { + MMU.reg_IF_pending[ARMCPU_ARM7] &= ~(1<<IRQ_BIT_LCD_VMATCH); + NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH); + } +} + +static void execHardware_hstart_vcount() +{ + u16 vmatch = execHardware_gen_vmatch_goal(); if(nds.VCount==vmatch) { //arm9 vmatch T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 4); if(T1ReadWord(MMU.ARM9_REG, 4) & 32) { - NDS_makeIrq(ARMCPU_ARM9,IRQ_BIT_LCD_VMATCH); + MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VMATCH); } } else @@ -1561,12 +1579,36 @@ //arm7 vmatch T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 4); if(T1ReadWord(MMU.ARM7_REG, 4) & 32) - NDS_makeIrq(ARMCPU_ARM7,IRQ_BIT_LCD_VMATCH); + MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VMATCH); } else T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) & 0xFFFB); } +static void execHardware_hdraw() +{ + //due to hacks in our selection of rendering time, we do not actually render here as intended. + //consider changing this if there is some problem with raster fx timing but check the documentation near the gpu rendering calls + //to make sure you check for regressions (nsmb, sonic classics, et al) +} + +static void execHardware_hstart_irq() +{ + //this function very soon after the registers get updated to trigger IRQs + //this is necessary to fix "egokoro kyoushitsu" which idles waiting for vcount=192, which never happens due to a long vblank irq + //100% accurate emulation would require the read of VCOUNT to be in the pipeline already with the irq coming in behind it, thus + //allowing the vcount to register as 192 occasionally (maybe about 1 out of 28 frames) + //the actual length of the delay is in execHardware() where the events are scheduled + sequencer.reschedule = true; + if(nds.VCount==192) + { + //when the vcount hits 192, vblank begins + execHardware_hstart_vblankStart(); + } + + execHardware_hstart_vcount_irq(); +} + static void execHardware_hstart() { nds.VCount++; @@ -1582,16 +1624,30 @@ if(nds.VCount==263) { + //when the vcount hits 263 it rolls over to 0 nds.VCount=0; } if(nds.VCount==262) { + //when the vcount hits 262, vblank ends (oam pre-renders by one scanline) execHardware_hstart_vblankEnd(); - } else if(nds.VCount==192) + } + else if(nds.VCount==191) { - execHardware_hstart_vblankStart(); + //when the vcount hits 191, the 3d vblank occurs (maybe because OAM doesnt need to run anymore, so we can power it down, and give the 3d as much time as possible?) + gfx3d_VBlankSignal(); } + else if(nds.VCount==192) + { + //turn on vblank status bit + T1WriteWord(MMU.ARM9_REG, 4, T1ReadWord(MMU.ARM9_REG, 4) | 1); + T1WriteWord(MMU.ARM7_REG, 4, T1ReadWord(MMU.ARM7_REG, 4) | 1); + //check whether we'll need to fire vblank irqs + if(T1ReadWord(MMU.ARM9_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM9] |= (1<<IRQ_BIT_LCD_VBLANK); + if(T1ReadWord(MMU.ARM7_REG, 4) & 0x8) MMU.reg_IF_pending[ARMCPU_ARM7] |= (1<<IRQ_BIT_LCD_VBLANK); + } + //write the new vcount T1WriteWord(MMU.ARM9_REG, 6, nds.VCount); T1WriteWord(MMU.ARM9_REG, 0x1006, nds.VCount); @@ -1691,12 +1747,32 @@ { case ESI_DISPCNT_HStart: execHardware_hstart(); - dispcnt.timestamp += 3168; + //(used to be 3168) + //hstart is actually 8 dots before the visible drawing begins + //we're going to run 1 here and then run 7 in the next case + dispcnt.timestamp += 1*6*2; + dispcnt.param = ESI_DISPCNT_HStartIRQ; + break; + case ESI_DISPCNT_HStartIRQ: + execHardware_hstart_irq(); + dispcnt.timestamp += 7*6*2; + dispcnt.param = ESI_DISPCNT_HDraw; + break; + + case ESI_DISPCNT_HDraw: + execHardware_hdraw(); + //duration of non-blanking period is ~1606 clocks (gbatek agrees) [but says its different on arm7] + //im gonna call this 267 dots = 267*6=1602 + //so, this event lasts 267 dots minus the 8 dot preroll + dispcnt.timestamp += (267-8)*6*2; dispcnt.param = ESI_DISPCNT_HBlank; break; + case ESI_DISPCNT_HBlank: execHardware_hblank(); - dispcnt.timestamp += 1092; + //(once this was 1092 or 1092/12=91 dots.) + //there are surely 355 dots per scanline, less 267 for non-blanking period. the rest is hblank and then after that is hstart + dispcnt.timestamp += (355-267)*6*2; dispcnt.param = ESI_DISPCNT_HStart; break; } Modified: trunk/desmume/src/saves.cpp =================================================================== --- trunk/desmume/src/saves.cpp 2012-03-29 21:01:24 UTC (rev 4220) +++ trunk/desmume/src/saves.cpp 2012-03-29 22:45:05 UTC (rev 4221) @@ -205,6 +205,7 @@ { "MIME", 4, 2, MMU.reg_IME}, { "MIE_", 4, 2, MMU.reg_IE}, { "MIF_", 4, 2, MMU.reg_IF_bits}, + { "MIFP", 4, 2, MMU.reg_IF_pending}, { "MGXC", 8, 1, &MMU.gfx3dCycles}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |