220 lines
3.5 KiB
C++
220 lines
3.5 KiB
C++
#include "aica.h"
|
|
#include "aica_if.h"
|
|
#include "sgc_if.h"
|
|
#include "aica_mem.h"
|
|
#include <math.h>
|
|
#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 witch)
|
|
{
|
|
if (witch>7)
|
|
witch=7; //higher bits share bit 7
|
|
|
|
u32 bit=1<<witch;
|
|
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)
|
|
AICA_Sample();
|
|
|
|
//Make sure sh4/arm interrupt system is up to date :)
|
|
update_arm_interrupts();
|
|
UpdateSh4Ints();
|
|
}
|
|
|
|
//Memory i/o
|
|
template<u32 sz>
|
|
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();
|
|
for (int i=0;i<3;i++)
|
|
timers[i].Init(aica_reg,i);
|
|
|
|
return rv_ok;
|
|
}
|
|
|
|
void libAICA_Reset(bool manual)
|
|
{
|
|
if (!manual)
|
|
init_mem();
|
|
sgc_Init();
|
|
aica_Reset(manual);
|
|
}
|
|
|
|
void libAICA_Term()
|
|
{
|
|
sgc_Term();
|
|
}
|