diff --git a/core/hw/aica/aica_if.cpp b/core/hw/aica/aica_if.cpp index a3306146d..c92bce9b8 100644 --- a/core/hw/aica/aica_if.cpp +++ b/core/hw/aica/aica_if.cpp @@ -178,6 +178,28 @@ void aica_Term() } +s32 aica_pending_dma = 0; + +void aica_periodical(u32 cycl) +{ + if (aica_pending_dma > 0) + { + verify(SB_ADST==1); + + cycl = (aica_pending_dma <= 0) ? 0 : cycl; + aica_pending_dma-=cycl; + + if (aica_pending_dma <= 0) + { + //log("%u %d\n",cycl,(s32)aica_pending_dma); + asic_RaiseInterrupt(holly_SPU_DMA); + aica_pending_dma = 0; + SB_ADST=0; + } + } +} + + void Write_SB_ADST(u32 addr, u32 data) { //0x005F7800 SB_ADSTAG RW AICA:G2-DMA G2 start address @@ -196,6 +218,8 @@ void Write_SB_ADST(u32 addr, u32 data) u32 src=SB_ADSTAR; u32 dst=SB_ADSTAG; u32 len=SB_ADLEN & 0x7FFFFFFF; + + u32 total_bytes=0; if ((SB_ADDIR&1)==1) { @@ -221,11 +245,14 @@ void Write_SB_ADST(u32 addr, u32 data) SB_ADSTAR+=len; SB_ADSTAG+=len; - SB_ADST = 0x00000000;//dma done - SB_ADLEN = 0x00000000; - - - asic_RaiseInterrupt(holly_SPU_DMA); + total_bytes+=len; + SB_ADST = settings.aica.InterruptHack ? 1 : 0x00000000;//dma done + SB_ADLEN = 0x00000000; + + aica_pending_dma = ((total_bytes * 200000000) / 65536) + 1; + + if (!settings.aica.InterruptHack) + asic_RaiseInterruptWait(holly_SPU_DMA); } } } @@ -279,7 +306,7 @@ void Write_SB_E1ST(u32 addr, u32 data) SB_E1LEN = 0x00000000; - asic_RaiseInterrupt(holly_EXT_DMA1); + asic_RaiseInterruptWait(holly_EXT_DMA1); } } } diff --git a/core/hw/gdrom/gdromv3.cpp b/core/hw/gdrom/gdromv3.cpp index fdedd1181..d46c4e5ea 100644 --- a/core/hw/gdrom/gdromv3.cpp +++ b/core/hw/gdrom/gdromv3.cpp @@ -274,7 +274,7 @@ void gd_set_state(gd_states state) GDStatus.DRQ=1; GDStatus.BSY=0; //(4) INTRQ is set, and a host interrupt is issued. - asic_RaiseInterrupt(holly_GDROM_CMD); + asic_RaiseInterruptWait(holly_GDROM_CMD); /* The number of bytes normally is the byte number in the register at the time of receiving the command, but it may also be the total of several devices handled by the buffer at that point. @@ -332,7 +332,7 @@ void gd_set_state(gd_states state) GDStatus.DRQ=0; GDStatus.BSY=0; //Make INTRQ valid - asic_RaiseInterrupt(holly_GDROM_CMD); + asic_RaiseInterruptWait(holly_GDROM_CMD); //command finished ! gd_set_state(gds_waitcmd); @@ -477,7 +477,7 @@ void gd_process_ata_cmd() GDStatus.BSY=0; GDStatus.CHECK=1; - asic_RaiseInterrupt(holly_GDROM_CMD); + asic_RaiseInterruptWait(holly_GDROM_CMD); gd_set_state(gds_waitcmd); break; @@ -516,7 +516,7 @@ void gd_process_ata_cmd() GDStatus.DSC=0; GDStatus.DF=0; GDStatus.CHECK=0; - asic_RaiseInterrupt(holly_GDROM_CMD); //??? + asic_RaiseInterruptWait(holly_GDROM_CMD); //??? gd_set_state(gds_waitcmd); break; @@ -1155,7 +1155,7 @@ int GDRomschd(int i, int c, int j) //printf("Streamed GDMA end - %d bytes transferred\n",SB_GDLEND); SB_GDST=0;//done // The DMA end interrupt flag - asic_RaiseInterrupt(holly_GDROM_DMA); + asic_RaiseInterruptWait(holly_GDROM_DMA); } //Read ALL sectors if (read_params.remaining_sectors==0) diff --git a/core/hw/holly/holly_intc.cpp b/core/hw/holly/holly_intc.cpp index 827406ffe..e31f3120a 100644 --- a/core/hw/holly/holly_intc.cpp +++ b/core/hw/holly/holly_intc.cpp @@ -72,21 +72,60 @@ void RaiseAsicErr(HollyInterruptID inter) asic_RL6Pending(); } +static void asic_RaiseInterruptInternal(HollyInterruptID inter) +{ + u8 m=inter>>8; + switch(m) + { + case 0: + RaiseAsicNormal(inter); + break; + case 1: + RaiseAsicExt(inter); + break; + case 2: + RaiseAsicErr(inter); + break; + } +} + +static HollyInterruptID dmatmp1; +static HollyInterruptID dmatmp2; +static HollyInterruptID OldDmaId; + void asic_RaiseInterrupt(HollyInterruptID inter) { - u8 m=inter>>8; - switch(m) - { - case 0: - RaiseAsicNormal(inter); - break; - case 1: - RaiseAsicExt(inter); - break; - case 2: - RaiseAsicErr(inter); - break; - } + asic_RaiseInterruptInternal(inter); +} + +void asic_RaiseInterruptWait(HollyInterruptID inter) +{ +#if 0 + /* IRQ wait slots are here. This is a hack. + * Up until now, more than 3 and less than 2 wait slots + * break stuff. + * + * Currently using 2 wait slots. */ + OldDmaId = dmatmp2; + dmatmp2 = dmatmp1; + dmatmp1 = inter; + + switch (OldDmaId) + { + case holly_CH2_DMA: + case holly_EXT_DMA1: + case holly_GDROM_CMD: + case holly_MAPLE_DMA: + case holly_YUV_DMA: + case holly_PVR_DMA: + case holly_PVR_SortDMA: + case holly_SPU_DMA: + asic_RaiseInterruptInternal(OldDmaId); + break; + } +#else + asic_RaiseInterruptInternal(inter); +#endif } u32 Read_SB_ISTNRM(u32 addr) diff --git a/core/hw/holly/holly_intc.h b/core/hw/holly/holly_intc.h index 8857a25af..0be8cff65 100644 --- a/core/hw/holly/holly_intc.h +++ b/core/hw/holly/holly_intc.h @@ -2,6 +2,7 @@ #include "types.h" void asic_RaiseInterrupt(HollyInterruptID inter); +void asic_RaiseInterruptWait(HollyInterruptID inter); void asic_CancelInterrupt(HollyInterruptID inter); //Init/Res/Term for regs diff --git a/core/hw/maple/maple_if.cpp b/core/hw/maple/maple_if.cpp index a2bf1ffc3..23ad7f488 100644 --- a/core/hw/maple/maple_if.cpp +++ b/core/hw/maple/maple_if.cpp @@ -187,7 +187,7 @@ int maple_schd(int tag, int c, int j) if (SB_MDEN&1) { SB_MDST=0; - asic_RaiseInterrupt(holly_MAPLE_DMA); + asic_RaiseInterruptWait(holly_MAPLE_DMA); } else { diff --git a/core/hw/pvr/pvr_mem.cpp b/core/hw/pvr/pvr_mem.cpp index 98aa79ddf..dc89e7551 100644 --- a/core/hw/pvr/pvr_mem.cpp +++ b/core/hw/pvr/pvr_mem.cpp @@ -152,7 +152,7 @@ INLINE void YUV_ConvertMacroBlock(u8* datap) { YUV_init(); - asic_RaiseInterrupt(holly_YUV_DMA); + asic_RaiseInterruptWait(holly_YUV_DMA); } } void YUV_data(u32* data , u32 count) diff --git a/core/hw/pvr/pvr_sb_regs.cpp b/core/hw/pvr/pvr_sb_regs.cpp index 75965622a..7b2f5b0e9 100644 --- a/core/hw/pvr/pvr_sb_regs.cpp +++ b/core/hw/pvr/pvr_sb_regs.cpp @@ -68,7 +68,7 @@ void do_pvr_dma() SB_PDST = 0x00000000; //TODO : *CHECKME* is that ok here ? the docs don't say here it's used [PVR-DMA , bit 11] - asic_RaiseInterrupt(holly_PVR_DMA); + asic_RaiseInterruptWait(holly_PVR_DMA); } void RegWrite_SB_PDST(u32 addr, u32 data) { @@ -122,7 +122,7 @@ void pvr_do_sort_dma() // End of DMA :) SB_SDST=0; - asic_RaiseInterrupt(holly_PVR_SortDMA); + asic_RaiseInterruptWait(holly_PVR_SortDMA); } // Auto sort DMA :| void RegWrite_SB_SDST(u32 addr, u32 data) diff --git a/core/hw/sh4/interpr/sh4_interpreter.cpp b/core/hw/sh4/interpr/sh4_interpreter.cpp index 2ce06ba0c..033c8ad43 100644 --- a/core/hw/sh4/interpr/sh4_interpreter.cpp +++ b/core/hw/sh4/interpr/sh4_interpreter.cpp @@ -201,6 +201,8 @@ int AicaUpdate(int tag, int c, int j) //static int aica_sample_cycles=0; //aica_sample_cycles+=14336*AICA_SAMPLE_GCM; + + extern void aica_periodical(u32 cycl); //if (aica_sample_cycles>=AICA_SAMPLE_CYCLES) { @@ -209,6 +211,9 @@ int AicaUpdate(int tag, int c, int j) //aica_sample_cycles-=AICA_SAMPLE_CYCLES; } + if (settings.aica.InterruptHack) + aica_periodical(3584); + return AICA_TICK; } diff --git a/core/hw/sh4/modules/dmac.cpp b/core/hw/sh4/modules/dmac.cpp index 3cd31d26f..397aaa972 100644 --- a/core/hw/sh4/modules/dmac.cpp +++ b/core/hw/sh4/modules/dmac.cpp @@ -135,7 +135,7 @@ void DMAC_Ch2St() // The DMA end interrupt flag (SB_ISTNRM - bit 19: DTDE2INT) is set to "1." //-> fixed , holly_PVR_DMA is for different use now (fixed the interrupts enum too) - asic_RaiseInterrupt(holly_CH2_DMA); + asic_RaiseInterruptWait(holly_CH2_DMA); } //on demand data transfer diff --git a/core/nullDC.cpp b/core/nullDC.cpp index 026a43968..ce9ff7a77 100755 --- a/core/nullDC.cpp +++ b/core/nullDC.cpp @@ -260,6 +260,7 @@ void LoadSettings() settings.aica.LimitFPS = cfgLoadInt("config","aica.LimitFPS",1); settings.aica.NoBatch = cfgLoadInt("config","aica.NoBatch",0); settings.aica.NoSound = cfgLoadInt("config","aica.NoSound",0); + settings.aica.InterruptHack = cfgLoadInt("config","aica.InterruptHack",0); settings.rend.UseMipmaps = cfgLoadInt("config","rend.UseMipmaps",1); settings.rend.WideScreen = cfgLoadInt("config","rend.WideScreen",0); settings.rend.ModifierVolumes = cfgLoadInt("config","rend.ModifierVolumes",1); @@ -317,6 +318,7 @@ void LoadCustom() settings.dynarec.idleskip = cfgGameInt(reios_id,"Dynarec.idleskip", settings.dynarec.idleskip ? 1 : 0) != 0; settings.dynarec.unstable_opt = cfgGameInt(reios_id,"Dynarec.unstable-opt", settings.dynarec.unstable_opt); settings.dynarec.safemode = cfgGameInt(reios_id,"Dynarec.safemode", settings.dynarec.safemode); + settings.aica.InterruptHack = cfgLoadInt(reios_id,"aica.InterruptHack", settings.aica.InterruptHack); settings.rend.ModifierVolumes = cfgGameInt(reios_id,"rend.ModifierVolumes", settings.rend.ModifierVolumes); settings.rend.Clipping = cfgGameInt(reios_id,"rend.Clipping", settings.rend.Clipping); diff --git a/core/types.h b/core/types.h index eb377304a..20404d37b 100644 --- a/core/types.h +++ b/core/types.h @@ -652,7 +652,8 @@ struct settings_t u32 GlobalMute; u32 DSPEnabled; //0 -> no, 1 -> yes u32 NoBatch; - u32 NoSound; //0 ->sound, 1 -> no sound + u32 NoSound; //0 ->sound, 1 -> no sound + u32 InterruptHack; } aica; #if USE_OMX