flycast/core/hw/aica/aica.h

387 lines
5.7 KiB
C++

#pragma once
#include "types.h"
#include "oslib/oslib.h"
#include "assert.h"
#define SCIEB_addr 0x289C
#define SCIPD_addr (0x289C+4)
#define SCIRE_addr (0x289C+8)
#define MCIEB_addr 0x28B4
#define MCIPD_addr (0x28B4+4)
#define MCIRE_addr (0x28B4+8)
#define TIMER_A 0x2890
#define TIMER_B (0x2890+4)
#define TIMER_C (0x2890+8)
#define REG_L (0x2D00)
#define REG_M (0x2D04)
#define entry(name,sz) u32 name:sz;
struct CommonData_struct
{
//+0
entry(MVOL,4);
entry(VER,4);
entry(DAC18B,1);
entry(MEM8MB,1);
entry(pad0_0,5);
entry(Mono,1);
u32 :16;
//+4
entry(RBP,12);
entry(pad1_0,1);
entry(RBL,2);
entry(TESTB0,1);
u32 :16;
//+8
entry(MIBUF,8);
entry(MIEMP,1);
entry(MIFUL ,1);
entry(MIOVF ,1);
entry(MOEMP ,1);
entry(MOFUL ,1);
entry(pad3_0,3);
u32 :16;
//+C
entry(MOBUF,8);
entry(MSLC,6);
entry(AFSET,1);
entry(padC_0,1);
u32 :16;
//+10
entry(EG,13);
entry(SGC,2);
entry(LP,1);
u32 :16;
//+14
entry(CA,16);
u32 :16;
//quite a bit padding here :)
u8 pad_med_0[0x6C-4];
//+80
entry(MRWINH,4);
entry($T,1);
entry($TSCD,3);
entry(pad80_0,1);
entry(DMEA_hi,7);
u32 :16;
//+84
entry(pad84_0,2);
entry(DMEA_lo,14);
u32 :16;
//+88
entry(pad88_0,2);
entry(DRGA,13);
entry(DGATE,1);
u32 :16;
//+8C
entry(DEXE,1);
entry(pad8C_0,1);
entry(DLG,13);
entry(DDIR,1);
u32 :16;
//+90
entry(TIMA,8);
entry(TACTL,3);
entry(pad90_0,5);
u32 :16;
//+94
entry(TIMB,8);
entry(TBCTL,3);
entry(pad94_0,5);
u32 :16;
//+98
entry(TIMC,8);
entry(TCCTL,3);
entry(pad98_0,5);
u32 :16;
//+9C
entry(SCIEB,11);
entry(pad9C_0,5);
u32 :16;
//+A0
entry(SCIPD,11);
entry(padA0_0,5);
u32 :16;
//+A4
entry(SCIRE,11);
entry(padA4_0,5);
u32 :16;
//+A8
entry(SCILV0,8);
entry(padA8_0,8);
u32 :16;
//+AC
entry(SCILV1,8);
entry(padAC_0,8);
u32 :16;
//+B0
entry(SCILV2,8);
entry(padB0_0,8);
u32 :16;
//+B4
entry(MCIEB,11);
entry(padB4_0,5)
u32 :16;
//+B8
entry(MCIPD,11);
entry(padB8_0,5)
u32 :16;
//+BC
entry(MCIRE,11);
entry(padBC_0,5)
u32 :16;
//some other misc shit FAR away is here :p
u8 pad_lot_0[0x344-4];
//+400 , hopefully :p
entry(AR,1);
entry(pad400_0,7);
entry(VREG,2);
entry(pad400_1,6);
u32 :16;
//Even more
u8 pad_lot_1[0x100-4];
//+500 , hopefully :p
entry(L0_r,1);
entry(L1_r,1);
entry(L2_r,1);
entry(L3_r,1);
entry(L4_r,1);
entry(L5_r,1);
entry(L6_r,1);
entry(L7_r,1);
entry(pad500_0,8);
u32 :16;
//+504
entry(M0_r,1);
entry(M1_r,1);
entry(M2_r,1);
entry(M3_r,1);
entry(M4_r,1);
entry(M5_r,1);
entry(M6_r,1);
entry(M7_r,1);
entry(RP,1);
entry(pad504_0,7);
u32 :16;
};
//should be 0x15C8 in size
struct DSPData_struct
{
//+0x000
u32 COEF[128]; //15:3
//+0x200
u32 MADRS[64]; //15:0
//+0x300
u8 PAD0[0x100];
//+0x400
u32 MPRO[128*4]; //15:0
//+0xC00
u8 PAD1[0x400];
//+0x1000
struct
{
u32 l; //7:0
u32 h; //15:0 (23:8)
}
TEMP[128];
//+0x1400
struct
{
u32 l; //7:0
u32 h; //15:0 (23:8)
}
MEMS[32];
//+0x1500
struct
{
u32 l; //3:0
u32 h; //15:0 (19:4)
}
MIXS[16];
//+0x1580
u32 EFREG[16]; //15:0
//+0x15C0
u32 EXTS[2]; //15:0
};
union InterruptInfo
{
struct
{
//Bit 0 (R): Requests interrupt to external interrupt input pin "INTON". (SCSI)
entry(INTON,1);
//Bit 1 (R): Reserved.
entry(res_1,1);
//Bit 2 (R): Reserved.
entry(res_3,1);
//Bit 3 (R): MIDI input interrupt.
//(Interrupt request generated when input FIFO has fetched valid data. Hence, if the CPU reads FIFO data, it must read the lot once and leave the FIFO empty. When the FIFO has changed to empty status, the interrupt request is canceled automatically.)
entry(MIDI_IN,1);
//Bit 4 (R): DMA end interrupt
entry(DMA_END,1);
//Bit 5 (R/W): SCPU interrupt caused by data being written to the CPU, so only "1" can be written. (Writing "0" has no effect.) This flag can be set from either the MCPU or the SCPU.
entry(SCPU,1);
//Bit 6 (R): Timer A interrupt
entry(TimerA,1);
//Bit 7 (R): Timer B interrupt
entry(TimerB,1);
//Bit 8 (R): Timer C interrupt
entry(TimerC,1);
//Bit 9 (R): MIDI output interrupt.
//(If the output FIFO changes to empty status, an interrupt request is generated.)
//(If the status is no longer empty because data is written to the output FIFO, the interrupt request is canceled automatically.)
entry(MIDI_OUT,1);
//Bit 10 (R): Interrupt of one sample interval
entry(SAMPLE_DONE,1);
};
u32 full;
};
extern InterruptInfo* MCIEB;
extern InterruptInfo* MCIPD;
extern InterruptInfo* MCIRE;
extern InterruptInfo* SCIEB;
extern InterruptInfo* SCIPD;
extern InterruptInfo* SCIRE;
#undef entry
extern CommonData_struct* CommonData;
extern DSPData_struct* DSPData;
void UpdateAICA(u32 Cycles);
void AICA_Init();
void AICA_Term();
//u32 ReadAicaReg(u32 reg);
void WriteAicaReg8(u32 reg,u32 data);
template<u32 sz>
void WriteAicaReg(u32 reg,u32 data);
////
//Timers :)
struct AicaTimerData
{
union
{
struct
{
u32 count:8;
u32 md:3;
u32 nil:5;
u32 pad:16;
};
u32 data;
};
};
class AicaTimer
{
public:
AicaTimerData* data;
s32 c_step;
u32 m_step;
u32 id;
void Init(u8* regbase,u32 timer)
{
data=(AicaTimerData*)&regbase[0x2890 + timer*4];
id=timer;
m_step=1<<(data->md);
c_step=m_step;
}
void StepTimer(u32 samples)
{
do
{
c_step--;
if (c_step==0)
{
c_step=m_step;
data->count++;
if (data->count==0)
{
if (id==0)
{
SCIPD->TimerA=1;
MCIPD->TimerA=1;
}
else if (id==1)
{
SCIPD->TimerB=1;
MCIPD->TimerB=1;
}
else
{
SCIPD->TimerC=1;
MCIPD->TimerC=1;
}
}
}
} while(--samples);
}
void RegisterWrite()
{
u32 n_step=1<<(data->md);
if (n_step!=m_step)
{
m_step=n_step;
c_step=m_step;
}
}
};