pureikyubu/SRC/Hardware/PI.cpp
2020-07-21 23:28:29 +03:00

214 lines
5.6 KiB
C++

// PI - processor interface (interrupts and console control regs, FIFO)
#include "pch.h"
using namespace Debug;
// PI state (registers and other data)
PIControl pi;
// ---------------------------------------------------------------------------
// interrupts
// return short interrupt description
static const char *intdesc(uint32_t mask)
{
switch(mask & 0xffff)
{
case PI_INTERRUPT_HSP : return "HSP";
case PI_INTERRUPT_DEBUG : return "DEBUG";
case PI_INTERRUPT_CP : return "CP";
case PI_INTERRUPT_PE_FINISH : return "PE_FINISH";
case PI_INTERRUPT_PE_TOKEN : return "PE_TOKEN";
case PI_INTERRUPT_VI : return "VI";
case PI_INTERRUPT_MEM : return "MEM";
case PI_INTERRUPT_DSP : return "DSP";
case PI_INTERRUPT_AI : return "AI";
case PI_INTERRUPT_EXI : return "EXI";
case PI_INTERRUPT_SI : return "SI";
case PI_INTERRUPT_DI : return "DI";
case PI_INTERRUPT_RSW : return "RSW";
case PI_INTERRUPT_ERROR : return "ERROR";
}
// default
return "UNKNOWN";
}
static void printOut(uint32_t mask, const char *fix)
{
char buf[256], *p = buf;
for(uint32_t m=1; m<=PI_INTERRUPT_HSP; m<<=1)
{
if(mask & m) p += sprintf_s(p, sizeof(buf) - (p-buf), "%sINT ", intdesc(m));
}
*p = 0;
Report(Channel::PI, "%s%s (pc: %08X, time: 0x%llx)", buf, fix, Gekko::Gekko->regs.pc, Gekko::Gekko->GetTicks());
}
// assert interrupt
void PIAssertInt(uint32_t mask)
{
pi.intsr |= mask;
if(pi.intmr & mask)
{
if (pi.log)
{
printOut(mask, "asserted");
}
}
if (pi.intsr & pi.intmr)
{
Gekko::Gekko->AssertInterrupt();
}
else
{
Gekko::Gekko->ClearInterrupt();
}
}
// clear interrupt
void PIClearInt(uint32_t mask)
{
if(pi.intsr & mask)
{
if (pi.log)
{
printOut(mask, "cleared");
}
}
pi.intsr &= ~mask;
if (pi.intsr & pi.intmr)
{
Gekko::Gekko->AssertInterrupt();
}
else
{
Gekko::Gekko->ClearInterrupt();
}
}
// ---------------------------------------------------------------------------
// traps for interrupt regs
static void read_intsr(uint32_t addr, uint32_t *reg)
{
*reg = pi.intsr | ((pi.rswhack & 1) << 16);
}
// writes turns them off ?
static void write_intsr(uint32_t addr, uint32_t data)
{
PIClearInt(data);
}
static void read_intmr(uint32_t addr, uint32_t *reg)
{
*reg = pi.intmr;
}
static void write_intmr(uint32_t addr, uint32_t data)
{
pi.intmr = data;
// print out list of masked interrupts
if(pi.intmr && pi.log)
{
char buf[256], *p = buf;
for(uint32_t m=1; m<=PI_INTERRUPT_HSP; m<<=1)
{
if(pi.intmr & m) p += sprintf_s(p, sizeof(buf) - (p-buf), "%s ", intdesc(m));
}
*p = 0;
Report(Channel::PI, "unmasked : %s\n", buf);
}
}
//
// GC revision
//
static void read_mbrev(uint32_t addr, uint32_t *reg)
{
uint32_t ver = pi.consoleVer;
// bootrom using this register in following way :
//
// [8000002C] = 1 // set machine type to retail1
// [8000002C] += [CC00302C] >> 28; // upgrade revision
// set to HW2 final production board
// we need to set [8000002C] with value 3 (retail3)
// so return '2'
*reg = ((ver & 0xf) - 1) << 28;
}
//
// reset register
//
static void write_reset(uint32_t addr, uint32_t data)
{
// reset emulator
if(data)
{
//EMUClose();
//EMUOpen();
}
}
static void read_reset(uint32_t addr, uint32_t *reg)
{
// on system power-on, the code is zero
*reg = 0;
}
//
// PI fifo (CPU)
//
static void read_pi_base(uint32_t addr, uint32_t *reg) { *reg = pi.base & ~0x1f; }
static void write_pi_base(uint32_t addr, uint32_t data) { pi.base = data & ~0x1f; }
static void read_pi_top(uint32_t addr, uint32_t *reg) { *reg = pi.top & ~0x1f; }
static void write_pi_top(uint32_t addr, uint32_t data) { pi.top = data & ~0x1f; }
static void read_pi_wrptr(uint32_t addr, uint32_t *reg) { *reg = pi.wrptr & ~0x1f; }
static void write_pi_wrptr(uint32_t addr, uint32_t data) { pi.wrptr = data & ~0x1f; }
// show PI fifo configuration
void DumpPIFIFO()
{
Report(Channel::Norm, "PI fifo configuration");
Report(Channel::Norm, " base :0x%08X", pi.base);
Report(Channel::Norm, " top :0x%08X", pi.top);
Report(Channel::Norm, " wrptr:0x%08X", pi.wrptr);
Report(Channel::Norm, " wrap :%i", (pi.wrptr & PI_WRPTR_WRAP) ? (1) : (0));
}
// ---------------------------------------------------------------------------
// init
void PIOpen(HWConfig* config)
{
Report(Channel::PI, "Processor interface (interrupts)\n");
pi.rswhack = config->rswhack;
pi.consoleVer = config->consoleVer;
pi.log = false;
// clear interrupt registers
pi.intsr = pi.intmr = 0;
// set interrupt registers hooks
MISetTrap(32, PI_INTSR , read_intsr, write_intsr);
MISetTrap(32, PI_INTMR , read_intmr, write_intmr);
MISetTrap(32, PI_MB_REV , read_mbrev, NULL);
MISetTrap( 8, PI_RST_CODE, read_reset, write_reset);
MISetTrap(32, PI_RST_CODE, read_reset, write_reset);
// processor interface (CPU fifo)
MISetTrap(32, PI_BASE , read_pi_base , write_pi_base);
MISetTrap(32, PI_TOP , read_pi_top , write_pi_top);
MISetTrap(32, PI_WRPTR, read_pi_wrptr, write_pi_wrptr);
}