mirror of
https://github.com/emu-russia/pureikyubu.git
synced 2025-04-02 10:42:15 -04:00
291 lines
8.3 KiB
C++
291 lines
8.3 KiB
C++
// high level Dolphin OS (experimental)
|
|
#include "pch.h"
|
|
|
|
using namespace Debug;
|
|
|
|
#define PARAM(n) Gekko::Gekko->regs.gpr[3+n]
|
|
#define RET_VAL Gekko::Gekko->regs.gpr[3]
|
|
#define SWAP _BYTESWAP_UINT32
|
|
|
|
// internal OS vars
|
|
static uint32_t __OSPhysicalContext; // OS_PHYSICAL_CONTEXT
|
|
static uint32_t __OSCurrentContext; // OS_CURRENT_CONTEXT
|
|
|
|
static uint32_t __OSDefaultThread; // OS_DEFAULT_THREAD
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Context API, based on Dolphin OS reversing of OSContext module
|
|
--------------------------------------------------------------------------- */
|
|
|
|
// IMPORTANT : FPRs are ALWAYS saved, because FP Unavail handler is not used
|
|
|
|
// stack operations are not emulated, because they are simple
|
|
|
|
// fast longlong swap, invented by org
|
|
static void swap_double(void *srcPtr)
|
|
{
|
|
uint8_t *src = (uint8_t*)srcPtr;
|
|
uint8_t t;
|
|
|
|
for(int i=0; i<4; i++)
|
|
{
|
|
t = src[7-i];
|
|
src[7-i] = src[i];
|
|
src[i] = t;
|
|
}
|
|
}
|
|
|
|
void OSSetCurrentContext(void)
|
|
{
|
|
__OSCurrentContext = PARAM(0);
|
|
__OSPhysicalContext = __OSCurrentContext & RAMMASK; // simple translation
|
|
Gekko::Gekko->WriteWord(OS_CURRENT_CONTEXT, __OSCurrentContext);
|
|
Gekko::Gekko->WriteWord(OS_PHYSICAL_CONTEXT, __OSPhysicalContext);
|
|
|
|
OSContext *c = (OSContext *)(&mi.ram[__OSPhysicalContext]);
|
|
|
|
if(__OSCurrentContext == __OSDefaultThread/*context*/)
|
|
{
|
|
c->srr[1] |= SWAP(MSR_FP);
|
|
}
|
|
else
|
|
{
|
|
// floating point regs are always available!
|
|
//c->srr[1] &= ~SWAP(MSR_FP);
|
|
//MSR &= ~MSR_FP;
|
|
|
|
c->srr[1] |= SWAP(MSR_FP);
|
|
Gekko::Gekko->regs.msr |= MSR_FP;
|
|
}
|
|
|
|
Gekko::Gekko->regs.msr |= MSR_RI;
|
|
}
|
|
|
|
void OSGetCurrentContext(void)
|
|
{
|
|
RET_VAL = __OSCurrentContext;
|
|
}
|
|
|
|
void OSSaveContext(void)
|
|
{
|
|
int i;
|
|
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(0) & RAMMASK]);
|
|
|
|
// always save FP/PS context
|
|
OSSaveFPUContext();
|
|
|
|
// save gprs
|
|
for(i=13; i<32; i++)
|
|
c->gpr[i] = SWAP(Gekko::Gekko->regs.gpr[i]);
|
|
|
|
// save gqrs 1..7 (GRQ0 is always 0)
|
|
for(i=1; i<8; i++)
|
|
c->gqr[i] = SWAP(Gekko::Gekko->regs.spr[(int)Gekko::SPR::GQRs + i]);
|
|
|
|
// misc regs
|
|
c->cr = SWAP(Gekko::Gekko->regs.cr);
|
|
c->lr = SWAP(Gekko::Gekko->regs.spr[(int)Gekko::SPR::LR]);
|
|
c->ctr = SWAP(Gekko::Gekko->regs.spr[(int)Gekko::SPR::CTR]);
|
|
c->xer = SWAP(Gekko::Gekko->regs.spr[(int)Gekko::SPR::XER]);
|
|
c->srr[0] = c->lr;
|
|
c->srr[1] = SWAP(Gekko::Gekko->regs.msr);
|
|
|
|
c->gpr[1] = SWAP(Gekko::Gekko->regs.gpr[1]);
|
|
c->gpr[2] = SWAP(Gekko::Gekko->regs.gpr[2]);
|
|
c->gpr[3] = SWAP(Gekko::Gekko->regs.gpr[0] = 1);
|
|
|
|
RET_VAL = 0;
|
|
// usual blr
|
|
}
|
|
|
|
// OSLoadContext return is patched as RFI (not usual BLR)
|
|
// see Symbols.cpp, SYMSetHighlevel, line 97
|
|
void OSLoadContext(void)
|
|
{
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(0) & RAMMASK]);
|
|
|
|
// thread switch on OSDisableInterrupts is omitted, because
|
|
// interrupts are generated only at branch opcodes;
|
|
// r0, r4, r5, r6 are garbed here ..
|
|
|
|
// load gprs 0..2
|
|
Gekko::Gekko->regs.gpr[0] = SWAP(c->gpr[0]);
|
|
Gekko::Gekko->regs.gpr[1] = SWAP(c->gpr[1]); // SP
|
|
Gekko::Gekko->regs.gpr[2] = SWAP(c->gpr[2]); // SDA2
|
|
|
|
// always load FP/PS context
|
|
OSLoadFPUContext();
|
|
|
|
// load gqrs 1..7 (GRQ0 is always 0)
|
|
for(int i=1; i<8; i++)
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::GQRs + i] = SWAP(c->gqr[i]);
|
|
|
|
// load other gprs
|
|
uint16_t state = (c->state >> 8) | (c->state << 8);
|
|
if(state & OS_CONTEXT_STATE_EXC)
|
|
{
|
|
state &= ~OS_CONTEXT_STATE_EXC;
|
|
c->state = (state >> 8) | (state << 8);
|
|
for(int i=5; i<32; i++)
|
|
Gekko::Gekko->regs.gpr[i] = SWAP(c->gpr[i]);
|
|
}
|
|
else
|
|
{
|
|
for(int i=13; i<32; i++)
|
|
Gekko::Gekko->regs.gpr[i] = SWAP(c->gpr[i]);
|
|
}
|
|
|
|
// misc regs
|
|
Gekko::Gekko->regs.cr = SWAP(c->cr);
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::LR] = SWAP(c->lr);
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::CTR] = SWAP(c->ctr);
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::XER] = SWAP(c->xer);
|
|
|
|
// set srr regs to update msr and pc
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::SRR0] = SWAP(c->srr[0]);
|
|
Gekko::Gekko->regs.spr[(int)Gekko::SPR::SRR1] = SWAP(c->srr[1]);
|
|
|
|
Gekko::Gekko->regs.gpr[3] = SWAP(c->gpr[3]);
|
|
Gekko::Gekko->regs.gpr[4] = SWAP(c->gpr[4]);
|
|
// rfi will be called
|
|
}
|
|
|
|
void OSClearContext(void)
|
|
{
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(0) & RAMMASK]);
|
|
|
|
c->mode = 0;
|
|
c->state = 0;
|
|
|
|
if(PARAM(0) == __OSDefaultThread/*context*/)
|
|
{
|
|
__OSDefaultThread = 0;
|
|
Gekko::Gekko->WriteWord(OS_DEFAULT_THREAD, __OSDefaultThread);
|
|
}
|
|
}
|
|
|
|
void OSInitContext(void)
|
|
{
|
|
int i;
|
|
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(0) & RAMMASK]);
|
|
|
|
c->srr[0] = SWAP(PARAM(1));
|
|
c->gpr[1] = SWAP(PARAM(2));
|
|
c->srr[1] = SWAP(MSR_EE | MSR_ME | MSR_IR | MSR_DR | MSR_RI);
|
|
|
|
c->cr = 0;
|
|
c->xer = 0;
|
|
|
|
for(i=0; i<8; i++)
|
|
c->gqr[i] = 0;
|
|
|
|
OSClearContext();
|
|
|
|
for(i=3; i<32; i++)
|
|
c->gpr[i] = 0;
|
|
c->gpr[2] = SWAP(Gekko::Gekko->regs.gpr[2]);
|
|
c->gpr[13] = SWAP(Gekko::Gekko->regs.gpr[13]);
|
|
}
|
|
|
|
void OSLoadFPUContext(void)
|
|
{
|
|
PARAM(1) = PARAM(0);
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(1) & RAMMASK]);
|
|
|
|
//u16 state = (c->state >> 8) | (c->state << 8);
|
|
//if(! (state & OS_CONTEXT_STATE_FPSAVED) )
|
|
{
|
|
Gekko::Gekko->regs.fpscr = SWAP(c->fpscr);
|
|
|
|
for(int i=0; i<32; i++)
|
|
{
|
|
if(Gekko::Gekko->regs.spr[(int)Gekko::SPR::HID2] & HID2_PSE)
|
|
{
|
|
Gekko::Gekko->regs.ps1[i].uval = *(uint64_t *)(&c->psr[i]);
|
|
swap_double(&Gekko::Gekko->regs.ps1[i].uval);
|
|
}
|
|
Gekko::Gekko->regs.fpr[i].uval = *(uint64_t *)(&c->fpr[i]);
|
|
swap_double(&Gekko::Gekko->regs.fpr[i].uval);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OSSaveFPUContext(void)
|
|
{
|
|
PARAM(2) = PARAM(0);
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(2) & RAMMASK]);
|
|
|
|
//c->state |= (OS_CONTEXT_STATE_FPSAVED >> 8) | (OS_CONTEXT_STATE_FPSAVED << 8);
|
|
c->fpscr = SWAP(Gekko::Gekko->regs.fpscr);
|
|
|
|
for(int i=0; i<32; i++)
|
|
{
|
|
*(uint64_t *)(&c->fpr[i]) = Gekko::Gekko->regs.fpr[i].uval;
|
|
swap_double(&c->fpr[i]);
|
|
if(Gekko::Gekko->regs.spr[(int)Gekko::SPR::HID2] & HID2_PSE)
|
|
{
|
|
*(uint64_t *)(&c->psr[i]) = Gekko::Gekko->regs.ps1[i].uval;
|
|
swap_double(&c->psr[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OSFillFPUContext(void)
|
|
{
|
|
OSContext * c = (OSContext *)(&mi.ram[PARAM(0) & RAMMASK]);
|
|
|
|
Gekko::Gekko->regs.msr |= MSR_FP;
|
|
c->fpscr = SWAP(Gekko::Gekko->regs.fpscr);
|
|
|
|
for(int i=0; i<32; i++)
|
|
{
|
|
*(uint64_t *)(&c->fpr[i]) = Gekko::Gekko->regs.fpr[i].uval;
|
|
swap_double(&c->fpr[i]);
|
|
if(Gekko::Gekko->regs.spr[(int)Gekko::SPR::HID2] & HID2_PSE)
|
|
{
|
|
*(uint64_t *)(&c->psr[i]) = Gekko::Gekko->regs.ps1[i].uval;
|
|
swap_double(&c->psr[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void __OSContextInit(void)
|
|
{
|
|
Report(Channel::HLE, "HLE OS context driver installed.\n");
|
|
Report(Channel::HLE, "Note: FP-Unavail is NOT used and FPRs are always saved.\n\n");
|
|
|
|
__OSDefaultThread = 0;
|
|
Gekko::Gekko->WriteWord(OS_DEFAULT_THREAD, __OSDefaultThread);
|
|
Gekko::Gekko->regs.msr |= (MSR_FP | MSR_RI);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Interrupt handling
|
|
--------------------------------------------------------------------------- */
|
|
|
|
// called VERY often!
|
|
void OSDisableInterrupts(void)
|
|
{
|
|
uint32_t prev = Gekko::Gekko->regs.msr;
|
|
Gekko::Gekko->regs.msr &= ~MSR_EE;
|
|
RET_VAL = (prev >> 15) & 1;
|
|
}
|
|
|
|
// this one is rare
|
|
void OSEnableInterrupts(void)
|
|
{
|
|
uint32_t prev = Gekko::Gekko->regs.msr;
|
|
Gekko::Gekko->regs.msr |= MSR_EE;
|
|
RET_VAL = (prev >> 15) & 1;
|
|
}
|
|
|
|
// called VERY often!
|
|
void OSRestoreInterrupts(void)
|
|
{
|
|
uint32_t prev = Gekko::Gekko->regs.msr;
|
|
if(PARAM(0)) Gekko::Gekko->regs.msr |= MSR_EE;
|
|
else Gekko::Gekko->regs.msr &= ~MSR_EE;
|
|
RET_VAL = (prev >> 15) & 1;
|
|
}
|