#include "aica.h" #include "aica_if.h" #include "sgc_if.h" #include "aica_mem.h" #include #include "hw/holly/holly_intc.h" #include "hw/holly/sb.h" #define SH4_IRQ_BIT (1<<(holly_SPU_IRQ&255)) CommonData_struct* CommonData; DSPData_struct* DSPData; InterruptInfo* MCIEB; InterruptInfo* MCIPD; InterruptInfo* MCIRE; InterruptInfo* SCIEB; InterruptInfo* SCIPD; InterruptInfo* SCIRE; //Interrupts //arm side u32 GetL(u32 which) { if (which > 7) which = 7; //higher bits share bit 7 u32 bit = 1 << which; u32 rv = 0; if (CommonData->SCILV0 & bit) rv = 1; if (CommonData->SCILV1 & bit) rv |= 2; if (CommonData->SCILV2 & bit) rv |= 4; return rv; } void update_arm_interrupts() { u32 p_ints=SCIEB->full & SCIPD->full; u32 Lval=0; if (p_ints) { u32 bit_value=1;//first bit //scan all interrupts , lo to hi bit.I assume low bit ints have higher priority over others for (u32 i=0;i<11;i++) { if (p_ints & bit_value) { //for the first one , Set the L reg & exit Lval=GetL(i); break; } bit_value<<=1; //next bit } } libARM_InterruptChange(p_ints,Lval); } //sh4 side void UpdateSh4Ints() { u32 p_ints = MCIEB->full & MCIPD->full; if (p_ints) { if ((SB_ISTEXT & SH4_IRQ_BIT )==0) { //if no interrupt is already pending then raise one :) asic_RaiseInterrupt(holly_SPU_IRQ); } } else { if (SB_ISTEXT&SH4_IRQ_BIT) { asic_CancelInterrupt(holly_SPU_IRQ); } } } AicaTimer timers[3]; //Mainloop void libAICA_Update(u32 Samples) { AICA_Sample32(); } void libAICA_TimeStep() { for (int i=0;i<3;i++) timers[i].StepTimer(1); SCIPD->SAMPLE_DONE=1; if (settings.aica.NoBatch || settings.aica.DSPEnabled) AICA_Sample(); //Make sure sh4/arm interrupt system is up to date :) update_arm_interrupts(); UpdateSh4Ints(); } //Memory i/o template void WriteAicaReg(u32 reg,u32 data) { switch (reg) { case SCIPD_addr: verify(sz!=1); if (data & (1<<5)) { SCIPD->SCPU=1; update_arm_interrupts(); } //Read only return; case SCIRE_addr: { verify(sz!=1); SCIPD->full&=~(data /*& SCIEB->full*/ ); //is the & SCIEB->full needed ? doesn't seem like it data=0;//Write only update_arm_interrupts(); } break; case MCIPD_addr: if (data & (1<<5)) { verify(sz!=1); MCIPD->SCPU=1; UpdateSh4Ints(); } //Read only return; case MCIRE_addr: { verify(sz!=1); MCIPD->full&=~data; UpdateSh4Ints(); //Write only } break; case TIMER_A: WriteMemArr(aica_reg,reg,data,sz); timers[0].RegisterWrite(); break; case TIMER_B: WriteMemArr(aica_reg,reg,data,sz); timers[1].RegisterWrite(); break; case TIMER_C: WriteMemArr(aica_reg,reg,data,sz); timers[2].RegisterWrite(); break; default: WriteMemArr(aica_reg,reg,data,sz); break; } } template void WriteAicaReg<1>(u32 reg,u32 data); template void WriteAicaReg<2>(u32 reg,u32 data); //misc :p s32 libAICA_Init() { init_mem(); aica_Init(); verify(sizeof(*CommonData)==0x508); verify(sizeof(*DSPData)==0x15C8); CommonData=(CommonData_struct*)&aica_reg[0x2800]; DSPData=(DSPData_struct*)&aica_reg[0x3000]; //slave cpu (arm7) SCIEB=(InterruptInfo*)&aica_reg[0x289C]; SCIPD=(InterruptInfo*)&aica_reg[0x289C+4]; SCIRE=(InterruptInfo*)&aica_reg[0x289C+8]; //Main cpu (sh4) MCIEB=(InterruptInfo*)&aica_reg[0x28B4]; MCIPD=(InterruptInfo*)&aica_reg[0x28B4+4]; MCIRE=(InterruptInfo*)&aica_reg[0x28B4+8]; sgc_Init(); return rv_ok; } void libAICA_Reset(bool hard) { if (hard) init_mem(); sgc_Init(); for (int i = 0; i < 3; i++) timers[i].Init(aica_reg, i); aica_Reset(hard); } void libAICA_Term() { sgc_Term(); term_mem(); }