2008-01-15 20:27:44 +00:00
|
|
|
#include "Iop_Intrman.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "Log.h"
|
2008-01-15 20:27:44 +00:00
|
|
|
#include "../COP_SCU.h"
|
2008-10-27 22:27:25 +00:00
|
|
|
#include "Iop_Intc.h"
|
2008-10-28 01:48:21 +00:00
|
|
|
#include "IopBios.h"
|
2008-01-15 20:27:44 +00:00
|
|
|
|
|
|
|
#define LOGNAME "iop_intrman"
|
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define FUNCTION_REGISTERINTRHANDLER "RegisterIntrHandler"
|
|
|
|
#define FUNCTION_RELEASEINTRHANDLER "ReleaseIntrHandler"
|
|
|
|
#define FUNCTION_ENABLEINTRLINE "EnableIntrLine"
|
|
|
|
#define FUNCTION_DISABLEINTRLINE "DisableIntrLine"
|
|
|
|
#define FUNCTION_DISABLEINTERRUPTS "DisableInterrupts"
|
|
|
|
#define FUNCTION_ENABLEINTERRUPTS "EnableInterrupts"
|
|
|
|
#define FUNCTION_SUSPENDINTERRUPTS "SuspendInterrupts"
|
|
|
|
#define FUNCTION_RESUMEINTERRUPTS "ResumeInterrupts"
|
|
|
|
#define FUNCTION_QUERYINTRCONTEXT "QueryIntrContext"
|
|
|
|
|
|
|
|
CIntrman::CIntrman(CIopBios& bios, uint8* ram)
|
|
|
|
: m_bios(bios)
|
|
|
|
, m_ram(ram)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-04-07 18:56:00 +00:00
|
|
|
std::string CIntrman::GetId() const
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-04-07 18:56:00 +00:00
|
|
|
return "intrman";
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2012-04-07 18:56:00 +00:00
|
|
|
std::string CIntrman::GetFunctionName(unsigned int functionId) const
|
2008-11-28 23:46:52 +00:00
|
|
|
{
|
2012-04-07 18:56:00 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return FUNCTION_REGISTERINTRHANDLER;
|
|
|
|
break;
|
2011-02-26 22:42:59 +00:00
|
|
|
case 5:
|
|
|
|
return FUNCTION_RELEASEINTRHANDLER;
|
|
|
|
break;
|
2012-04-07 18:56:00 +00:00
|
|
|
case 6:
|
|
|
|
return FUNCTION_ENABLEINTRLINE;
|
|
|
|
break;
|
2011-02-26 22:42:59 +00:00
|
|
|
case 7:
|
|
|
|
return FUNCTION_DISABLEINTRLINE;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
return FUNCTION_DISABLEINTERRUPTS;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
return FUNCTION_ENABLEINTERRUPTS;
|
|
|
|
break;
|
2012-04-07 18:56:00 +00:00
|
|
|
case 17:
|
|
|
|
return FUNCTION_SUSPENDINTERRUPTS;
|
|
|
|
break;
|
|
|
|
case 18:
|
|
|
|
return FUNCTION_RESUMEINTERRUPTS;
|
|
|
|
break;
|
2011-02-26 22:42:59 +00:00
|
|
|
case 23:
|
|
|
|
return FUNCTION_QUERYINTRCONTEXT;
|
|
|
|
break;
|
2012-04-07 18:56:00 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
2008-11-28 23:46:52 +00:00
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
void CIntrman::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
2012-04-07 18:56:00 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(RegisterIntrHandler(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A3].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(ReleaseIntrHandler(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(EnableIntrLine(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(DisableIntrLine(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
2011-02-26 22:42:59 +00:00
|
|
|
case 8:
|
2012-04-07 18:56:00 +00:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(DisableInterrupts(
|
2018-04-30 21:01:23 +01:00
|
|
|
context));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(EnableInterrupts(
|
2018-04-30 21:01:23 +01:00
|
|
|
context));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 17:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(SuspendInterrupts(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 18:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(ResumeInterrupts(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
case 23:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(QueryIntrContext(
|
2018-04-30 21:01:23 +01:00
|
|
|
context));
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
default:
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOGNAME, "%08X: Unknown function (%d) called.\r\n", context.m_State.nPC, functionId);
|
2012-04-07 18:56:00 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2008-10-24 13:42:27 +00:00
|
|
|
uint32 CIntrman::RegisterIntrHandler(uint32 line, uint32 mode, uint32 handler, uint32 arg)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_REGISTERINTRHANDLER "(line = %d, mode = %d, handler = 0x%08X, arg = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
line, mode, handler, arg);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2015-10-11 18:52:49 -04:00
|
|
|
return m_bios.RegisterIntrHandler(line, mode, handler, arg);
|
2008-10-24 13:42:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIntrman::ReleaseIntrHandler(uint32 line)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2012-04-07 18:56:00 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_RELEASEINTRHANDLER "(line = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
line);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2015-10-11 19:11:48 -04:00
|
|
|
return m_bios.ReleaseIntrHandler(line);
|
2008-10-24 13:42:27 +00:00
|
|
|
}
|
|
|
|
|
2008-10-27 22:27:25 +00:00
|
|
|
uint32 CIntrman::EnableIntrLine(CMIPS& context, uint32 line)
|
2008-10-24 13:42:27 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2012-04-07 18:56:00 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_ENABLEINTRLINE "(line = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
line);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2008-10-27 22:27:25 +00:00
|
|
|
UNION64_32 mask(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_pMemoryMap->GetWord(CIntc::MASK0),
|
|
|
|
context.m_pMemoryMap->GetWord(CIntc::MASK1));
|
2008-10-27 22:27:25 +00:00
|
|
|
mask.f |= 1LL << line;
|
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK0, mask.h0);
|
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK1, mask.h1);
|
|
|
|
return 0;
|
2008-10-24 13:42:27 +00:00
|
|
|
}
|
|
|
|
|
2008-10-27 22:27:25 +00:00
|
|
|
uint32 CIntrman::DisableIntrLine(CMIPS& context, uint32 line, uint32 res)
|
2008-10-24 13:42:27 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_DISABLEINTRLINE "(line = %d, res = %08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
line, res);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2023-12-19 19:37:44 +00:00
|
|
|
uint32 ret = CIopBios::KERNEL_RESULT_OK;
|
|
|
|
uint32 stat = line;
|
2008-10-27 22:27:25 +00:00
|
|
|
UNION64_32 mask(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_pMemoryMap->GetWord(CIntc::MASK0),
|
|
|
|
context.m_pMemoryMap->GetWord(CIntc::MASK1));
|
2023-12-19 19:37:44 +00:00
|
|
|
if(mask.f & (1LL << line))
|
|
|
|
{
|
|
|
|
mask.f &= ~(1LL << line);
|
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK0, mask.h0);
|
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK1, mask.h1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = CIopBios::KERNEL_RESULT_ERROR_INTRDISABLE;
|
|
|
|
stat = CIopBios::KERNEL_RESULT_ERROR_INTRDISABLE;
|
|
|
|
}
|
|
|
|
if(res != 0)
|
|
|
|
{
|
|
|
|
uint32* state = reinterpret_cast<uint32*>(m_ram + res);
|
|
|
|
(*state) = stat;
|
|
|
|
}
|
|
|
|
return ret;
|
2008-10-24 13:42:27 +00:00
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
uint32 CIntrman::EnableInterrupts(CMIPS& context)
|
|
|
|
{
|
2008-10-24 13:42:27 +00:00
|
|
|
#ifdef _DEBUG
|
2012-04-07 18:56:00 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_ENABLEINTERRUPTS "();\r\n");
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
|
|
|
|
2012-04-07 18:56:00 +00:00
|
|
|
uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
|
2015-04-13 00:24:35 -04:00
|
|
|
statusRegister |= CMIPS::STATUS_IE;
|
2012-04-07 18:56:00 +00:00
|
|
|
return 0;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2011-02-26 22:42:59 +00:00
|
|
|
uint32 CIntrman::DisableInterrupts(CMIPS& context)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2012-04-07 18:56:00 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_DISABLEINTERRUPTS "();\r\n");
|
2011-02-26 22:42:59 +00:00
|
|
|
#endif
|
|
|
|
|
2012-04-07 18:56:00 +00:00
|
|
|
uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
|
2015-04-13 00:24:35 -04:00
|
|
|
statusRegister &= ~CMIPS::STATUS_IE;
|
2012-04-07 18:56:00 +00:00
|
|
|
return 0;
|
2011-02-26 22:42:59 +00:00
|
|
|
}
|
|
|
|
|
2015-03-17 00:29:49 -04:00
|
|
|
uint32 CIntrman::SuspendInterrupts(CMIPS& context, uint32 statePtr)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2008-10-24 13:42:27 +00:00
|
|
|
#ifdef _DEBUG
|
2018-04-30 21:01:23 +01:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_SUSPENDINTERRUPTS "(statePtr = 0x%08X);\r\n",
|
|
|
|
statePtr);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2012-04-07 18:56:00 +00:00
|
|
|
uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
|
2023-09-26 14:29:27 -04:00
|
|
|
uint32 result = ((statusRegister & CMIPS::STATUS_IE) != 0) ? CIopBios::KERNEL_RESULT_OK : CIopBios::KERNEL_RESULT_ERROR_CPUDI;
|
2015-03-17 00:29:49 -04:00
|
|
|
if(statePtr != 0)
|
|
|
|
{
|
|
|
|
uint32* state = reinterpret_cast<uint32*>(m_ram + statePtr);
|
2015-04-13 00:24:35 -04:00
|
|
|
(*state) = statusRegister & CMIPS::STATUS_IE;
|
2015-03-17 00:29:49 -04:00
|
|
|
}
|
2015-04-13 00:24:35 -04:00
|
|
|
statusRegister &= ~CMIPS::STATUS_IE;
|
2015-03-17 00:29:49 -04:00
|
|
|
return result;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIntrman::ResumeInterrupts(CMIPS& context, uint32 state)
|
|
|
|
{
|
2008-10-24 13:42:27 +00:00
|
|
|
#ifdef _DEBUG
|
2023-12-19 19:37:44 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_RESUMEINTERRUPTS "(0x%x);\r\n", state);
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2012-04-07 18:56:00 +00:00
|
|
|
uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
|
|
|
|
if(state)
|
|
|
|
{
|
2015-04-13 00:24:35 -04:00
|
|
|
statusRegister |= CMIPS::STATUS_IE;
|
2012-04-07 18:56:00 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-04-13 00:24:35 -04:00
|
|
|
statusRegister &= ~CMIPS::STATUS_IE;
|
2012-04-07 18:56:00 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CIntrman::QueryIntrContext(CMIPS& context)
|
|
|
|
{
|
2008-10-24 13:42:27 +00:00
|
|
|
#ifdef _DEBUG
|
2012-04-07 18:56:00 +00:00
|
|
|
CLog::GetInstance().Print(LOGNAME, FUNCTION_QUERYINTRCONTEXT "();\r\n");
|
2008-10-24 13:42:27 +00:00
|
|
|
#endif
|
2015-03-17 00:28:56 -04:00
|
|
|
uint32 statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
|
|
|
|
//If we're inside an exception or if interrupts are disabled, we are inside an interrupt context
|
2015-04-13 00:24:35 -04:00
|
|
|
return ((statusRegister & CMIPS::STATUS_EXL) != 0) || ((statusRegister & CMIPS::STATUS_IE) == 0);
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|