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

220 lines
3.5 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
/*
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_interrupts.h"
#include "hw/sh4/sh4_mem.h"
#include "../sh4_sched.h"
#include "hw/holly/sb.h"
#include "../sh4_cache.h"
2013-12-19 17:10:14 +00:00
#define CPU_RATIO (8)
2013-12-19 17:10:14 +00:00
sh4_icache icache;
sh4_ocache ocache;
static s32 l;
static void ExecuteOpcode(u16 op)
{
if (sr.FD == 1 && OpDesc[op]->IsFloatingPoint())
RaiseFPUDisableException();
OpPtr[op](op);
l -= CPU_RATIO;
}
static u16 ReadNexOp()
{
u32 addr = next_pc;
next_pc += 2;
return IReadMem16(addr);
}
2013-12-19 17:10:14 +00:00
void Sh4_int_Run()
{
sh4_int_bCpuRun=true;
l = SH4_TIMESLICE;
2013-12-19 17:10:14 +00:00
do
{
#if !defined(NO_MMU)
try {
#endif
do
{
u32 op = ReadNexOp();
ExecuteOpcode(op);
} while (l > 0);
l += SH4_TIMESLICE;
UpdateSystem_INTC();
#if !defined(NO_MMU)
}
catch (SH4ThrownException& ex) {
2015-09-17 19:31:25 +00:00
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
l -= CPU_RATIO * 5; // an exception requires the instruction pipeline to drain, so approx 5 cycles
}
#endif
} while (sh4_int_bCpuRun);
2013-12-19 17:10:14 +00:00
sh4_int_bCpuRun = false;
2013-12-19 17:10:14 +00:00
}
void Sh4_int_Stop()
{
if (sh4_int_bCpuRun)
sh4_int_bCpuRun=false;
}
2018-09-02 13:49:23 +00:00
void Sh4_int_Start()
{
if (!sh4_int_bCpuRun)
sh4_int_bCpuRun=true;
}
2013-12-19 17:10:14 +00:00
void Sh4_int_Step()
{
if (sh4_int_bCpuRun)
{
2019-07-01 13:22:04 +00:00
WARN_LOG(INTERPRETER, "Sh4 Is running , can't step");
2013-12-19 17:10:14 +00:00
}
else
{
u32 op = ReadNexOp();
2013-12-19 17:10:14 +00:00
ExecuteOpcode(op);
}
}
void Sh4_int_Skip()
{
if (sh4_int_bCpuRun)
2019-07-01 13:22:04 +00:00
WARN_LOG(INTERPRETER, "Sh4 Is running, can't Skip");
2013-12-19 17:10:14 +00:00
else
next_pc += 2;
2013-12-19 17:10:14 +00:00
}
2019-07-10 15:25:11 +00:00
void Sh4_int_Reset(bool hard)
2013-12-19 17:10:14 +00:00
{
if (sh4_int_bCpuRun)
{
2019-07-01 13:22:04 +00:00
WARN_LOG(INTERPRETER, "Sh4 Is running, can't Reset");
2013-12-19 17:10:14 +00:00
}
else
{
2019-09-11 13:00:08 +00:00
if (hard)
memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx));
2013-12-19 17:10:14 +00:00
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;
2018-09-02 13:49:23 +00:00
sh4_sr_SetFull(0x700000F0);
2013-12-19 17:10:14 +00:00
old_sr.status=sr.status;
UpdateSR();
fpscr.full = 0x0004001;
old_fpscr=fpscr;
UpdateFPSCR();
icache.Reset(hard);
ocache.Reset(hard);
2013-12-19 17:10:14 +00:00
//Any more registers have default value ?
2019-07-01 13:22:04 +00:00
INFO_LOG(INTERPRETER, "Sh4 Reset");
2013-12-19 17:10:14 +00:00
}
}
bool Sh4_int_IsCpuRunning()
{
return sh4_int_bCpuRun;
}
//TODO : Check for valid delayslot instruction
void ExecuteDelayslot()
{
#if !defined(NO_MMU)
try {
#endif
u32 op = ReadNexOp();
2020-11-21 19:06:59 +00:00
ExecuteOpcode(op);
#if !defined(NO_MMU)
}
catch (SH4ThrownException& ex) {
AdjustDelaySlotException(ex);
throw ex;
}
#endif
2013-12-19 17:10:14 +00:00
}
void ExecuteDelayslot_RTE()
{
#if !defined(NO_MMU)
try {
#endif
ExecuteDelayslot();
#if !defined(NO_MMU)
}
catch (SH4ThrownException& ex) {
2019-07-01 13:22:04 +00:00
ERROR_LOG(INTERPRETER, "Exception in RTE delay slot");
}
#endif
2013-12-19 17:10:14 +00:00
}
// every SH4_TIMESLICE cycles
2013-12-19 17:10:14 +00:00
int UpdateSystem()
{
2020-11-21 19:06:59 +00:00
Sh4cntx.sh4_sched_next -= SH4_TIMESLICE;
if (Sh4cntx.sh4_sched_next < 0)
sh4_sched_tick(SH4_TIMESLICE);
2013-12-19 17:10:14 +00:00
return Sh4cntx.interrupt_pend;
}
int UpdateSystem_INTC()
{
if (UpdateSystem())
return UpdateINTC();
else
return 0;
2013-12-19 17:10:14 +00:00
}
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;
2018-09-02 13:49:23 +00:00
rv->Start=Sh4_int_Start;
2013-12-19 17:10:14 +00:00
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()
{
static_assert(sizeof(Sh4cntx) == 448, "Invalid Sh4Cntx size");
2013-12-19 17:10:14 +00:00
2015-08-09 04:26:03 +00:00
memset(&p_sh4rcb->cntx, 0, sizeof(p_sh4rcb->cntx));
2013-12-19 17:10:14 +00:00
}
void Sh4_int_Term()
{
Sh4_int_Stop();
2019-07-01 13:22:04 +00:00
INFO_LOG(INTERPRETER, "Sh4 Term");
2013-12-19 17:10:14 +00:00
}