flycast/core/hw/sh4/interpr/sh4_interpreter.cpp

313 lines
5.1 KiB
C++

/*
Highly inefficient and boring interpreter. Nothing special here
*/
#include "types.h"
#include "../sh4_interpreter.h"
#include "../sh4_opcode_list.h"
#include "../sh4_core.h"
#include "../sh4_rom.h"
#include "../sh4_if.h"
#include "hw/pvr/pvr_mem.h"
#include "hw/aica/aica_if.h"
#include "../modules/dmac.h"
#include "hw/gdrom/gdrom_if.h"
#include "hw/maple/maple_if.h"
#include "../sh4_interrupts.h"
#include "../modules/tmu.h"
#include "hw/sh4/sh4_mem.h"
#include "../modules/ccn.h"
#include "profiler/profiler.h"
#include "../dyna/blockmanager.h"
#include "../sh4_sched.h"
#include <time.h>
#include <float.h>
#define SH4_TIMESLICE (448)
#define CPU_RATIO (8)
//uh uh
#define GetN(str) ((str>>8) & 0xf)
#define GetM(str) ((str>>4) & 0xf)
void Sh4_int_Run()
{
sh4_int_bCpuRun=true;
s32 l=SH4_TIMESLICE;
#if !defined(TARGET_BOUNDED_EXECUTION)
do
#else
for (int i=0; i<10000; i++)
#endif
{
#if !defined(NO_MMU)
try {
#endif
do
{
u32 addr = next_pc;
next_pc += 2;
u32 op = IReadMem16(addr);
OpPtr[op](op);
l -= CPU_RATIO;
} while (l > 0);
l += SH4_TIMESLICE;
UpdateSystem_INTC();
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
l -= CPU_RATIO * 5;
}
#endif
#if !defined(TARGET_BOUNDED_EXECUTION)
} while(sh4_int_bCpuRun);
sh4_int_bCpuRun=false;
#else
}
#endif
}
void Sh4_int_Stop()
{
if (sh4_int_bCpuRun)
{
sh4_int_bCpuRun=false;
}
}
void Sh4_int_Step()
{
if (sh4_int_bCpuRun)
{
printf("Sh4 Is running , can't step\n");
}
else
{
u32 op=ReadMem16(next_pc);
next_pc+=2;
ExecuteOpcode(op);
}
}
void Sh4_int_Skip()
{
if (sh4_int_bCpuRun)
{
printf("Sh4 Is running, can't Skip\n");
}
else
{
next_pc+=2;
}
}
void Sh4_int_Reset(bool Manual)
{
if (sh4_int_bCpuRun)
{
printf("Sh4 Is running, can't Reset\n");
}
else
{
next_pc = 0xA0000000;
memset(r,0,sizeof(r));
memset(r_bank,0,sizeof(r_bank));
gbr=ssr=spc=sgr=dbr=vbr=0;
mac.full=pr=fpul=0;
sr.SetFull(0x700000F0);
old_sr.status=sr.status;
UpdateSR();
fpscr.full = 0x0004001;
old_fpscr=fpscr;
UpdateFPSCR();
//Any more registers have default value ?
printf("Sh4 Reset\n");
}
}
bool Sh4_int_IsCpuRunning()
{
return sh4_int_bCpuRun;
}
//TODO : Check for valid delayslot instruction
void ExecuteDelayslot()
{
#if !defined(NO_MMU)
try {
#endif
u32 addr = next_pc;
next_pc += 2;
u32 op = IReadMem16(addr);
if (op != 0)
ExecuteOpcode(op);
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
ex.epc -= 2;
//printf("Delay slot exception\n");
throw ex;
}
#endif
}
void ExecuteDelayslot_RTE()
{
u32 oldsr = sr.GetFull();
#if !defined(NO_MMU)
try {
#endif
sr.SetFull(ssr);
ExecuteDelayslot();
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
msgboxf("RTE Exception", MBX_ICONERROR);
}
#endif
}
//General update
//3584 Cycles
#define AICA_SAMPLE_GCM 441
#define AICA_SAMPLE_CYCLES (SH4_MAIN_CLOCK/(44100/AICA_SAMPLE_GCM)*32)
int aica_schid;
int rtc_schid;
//14336 Cycles
const int AICA_TICK=145124;
extern void aica_periodical(u32 cycl);
int AicaUpdate(int tag, int c, int j)
{
//gpc_counter=0;
//bm_Periodical_14k();
//static int aica_sample_cycles=0;
//aica_sample_cycles+=14336*AICA_SAMPLE_GCM;
//if (aica_sample_cycles>=AICA_SAMPLE_CYCLES)
{
UpdateArm(512*32);
UpdateAica(1*32);
//aica_sample_cycles-=AICA_SAMPLE_CYCLES;
}
if (settings.aica.DelayInterrupt)
aica_periodical(3584);
return AICA_TICK;
}
int DreamcastSecond(int tag, int c, int j)
{
settings.dreamcast.RTC++;
#if 1 //HOST_OS==OS_WINDOWS
prof_periodical();
#endif
#if FEAT_SHREC != DYNAREC_NONE
bm_Periodical_1s();
#endif
//printf("%d ticks\n",sh4_sched_intr);
sh4_sched_intr=0;
return SH4_MAIN_CLOCK;
}
int UpdateSystem_rec()
{
//WIP
if (Sh4cntx.sh4_sched_next<0)
sh4_sched_tick(448);
return Sh4cntx.interrupt_pend;
}
//448 Cycles (fixed)
int UpdateSystem()
{
//this is an optimisation (mostly for ARM)
//makes scheduling easier !
//update_fp* tmu=pUpdateTMU;
Sh4cntx.sh4_sched_next-=448;
if (Sh4cntx.sh4_sched_next<0)
sh4_sched_tick(448);
return Sh4cntx.interrupt_pend;
}
int UpdateSystem_INTC()
{
UpdateSystem();
return UpdateINTC();
}
void sh4_int_resetcache() { }
//Get an interface to sh4 interpreter
void Get_Sh4Interpreter(sh4_if* rv)
{
rv->Run=Sh4_int_Run;
rv->Stop=Sh4_int_Stop;
rv->Step=Sh4_int_Step;
rv->Skip=Sh4_int_Skip;
rv->Reset=Sh4_int_Reset;
rv->Init=Sh4_int_Init;
rv->Term=Sh4_int_Term;
rv->IsCpuRunning=Sh4_int_IsCpuRunning;
rv->ResetCache=sh4_int_resetcache;
}
void Sh4_int_Init()
{
verify(sizeof(Sh4cntx)==448);
aica_schid=sh4_sched_register(0,&AicaUpdate);
sh4_sched_request(aica_schid,AICA_TICK);
rtc_schid=sh4_sched_register(0,&DreamcastSecond);
sh4_sched_request(rtc_schid,SH4_MAIN_CLOCK);
memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx));
}
void Sh4_int_Term()
{
Sh4_int_Stop();
printf("Sh4 Term\n");
}
/*
bool sh4_exept_raised;
void sh4_int_RaiseExeption(u32 ExeptionCode, u32 VectorAddress)
{
sh4_exept_raised = true;
sh4_ex_ExeptionCode = ExeptionCode;
sh4_ex_VectorAddress = VectorAddress;
//save reg context
SaveSh4Regs(&sh4_ex_SRC);
}
*/