1 #include "Iop_Intrman.h"
2 #include "../Log.h"
3 #include "../COP_SCU.h"
4 #include "Iop_Intc.h"
5 #include "IopBios.h"
6 
7 #define LOGNAME "iop_intrman"
8 
9 using namespace Iop;
10 
11 #define FUNCTION_REGISTERINTRHANDLER "RegisterIntrHandler"
12 #define FUNCTION_RELEASEINTRHANDLER "ReleaseIntrHandler"
13 #define FUNCTION_ENABLEINTRLINE "EnableIntrLine"
14 #define FUNCTION_DISABLEINTRLINE "DisableIntrLine"
15 #define FUNCTION_DISABLEINTERRUPTS "DisableInterrupts"
16 #define FUNCTION_ENABLEINTERRUPTS "EnableInterrupts"
17 #define FUNCTION_SUSPENDINTERRUPTS "SuspendInterrupts"
18 #define FUNCTION_RESUMEINTERRUPTS "ResumeInterrupts"
19 #define FUNCTION_QUERYINTRCONTEXT "QueryIntrContext"
20 
CIntrman(CIopBios & bios,uint8 * ram)21 CIntrman::CIntrman(CIopBios& bios, uint8* ram)
22     : m_bios(bios)
23     , m_ram(ram)
24 {
25 }
26 
GetId() const27 std::string CIntrman::GetId() const
28 {
29 	return "intrman";
30 }
31 
GetFunctionName(unsigned int functionId) const32 std::string CIntrman::GetFunctionName(unsigned int functionId) const
33 {
34 	switch(functionId)
35 	{
36 	case 4:
37 		return FUNCTION_REGISTERINTRHANDLER;
38 		break;
39 	case 5:
40 		return FUNCTION_RELEASEINTRHANDLER;
41 		break;
42 	case 6:
43 		return FUNCTION_ENABLEINTRLINE;
44 		break;
45 	case 7:
46 		return FUNCTION_DISABLEINTRLINE;
47 		break;
48 	case 8:
49 		return FUNCTION_DISABLEINTERRUPTS;
50 		break;
51 	case 9:
52 		return FUNCTION_ENABLEINTERRUPTS;
53 		break;
54 	case 17:
55 		return FUNCTION_SUSPENDINTERRUPTS;
56 		break;
57 	case 18:
58 		return FUNCTION_RESUMEINTERRUPTS;
59 		break;
60 	case 23:
61 		return FUNCTION_QUERYINTRCONTEXT;
62 		break;
63 	default:
64 		return "unknown";
65 		break;
66 	}
67 }
68 
Invoke(CMIPS & context,unsigned int functionId)69 void CIntrman::Invoke(CMIPS& context, unsigned int functionId)
70 {
71 	switch(functionId)
72 	{
73 	case 4:
74 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(RegisterIntrHandler(
75 		    context.m_State.nGPR[CMIPS::A0].nV0,
76 		    context.m_State.nGPR[CMIPS::A1].nV0,
77 		    context.m_State.nGPR[CMIPS::A2].nV0,
78 		    context.m_State.nGPR[CMIPS::A3].nV0));
79 		break;
80 	case 5:
81 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(ReleaseIntrHandler(
82 		    context.m_State.nGPR[CMIPS::A0].nV0));
83 		break;
84 	case 6:
85 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(EnableIntrLine(
86 		    context,
87 		    context.m_State.nGPR[CMIPS::A0].nV0));
88 		break;
89 	case 7:
90 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(DisableIntrLine(
91 		    context,
92 		    context.m_State.nGPR[CMIPS::A0].nV0,
93 		    context.m_State.nGPR[CMIPS::A1].nV0));
94 		break;
95 	case 8:
96 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(DisableInterrupts(
97 		    context));
98 		break;
99 	case 9:
100 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(EnableInterrupts(
101 		    context));
102 		break;
103 	case 17:
104 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(SuspendInterrupts(
105 		    context,
106 		    context.m_State.nGPR[CMIPS::A0].nV0));
107 		break;
108 	case 18:
109 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(ResumeInterrupts(
110 		    context,
111 		    context.m_State.nGPR[CMIPS::A0].nV0));
112 		break;
113 	case 23:
114 		context.m_State.nGPR[CMIPS::V0].nD0 = static_cast<int32>(QueryIntrContext(
115 		    context));
116 		break;
117 	default:
118 		CLog::GetInstance().Warn(LOGNAME, "%08X: Unknown function (%d) called.\r\n", context.m_State.nPC, functionId);
119 		break;
120 	}
121 }
122 
RegisterIntrHandler(uint32 line,uint32 mode,uint32 handler,uint32 arg)123 uint32 CIntrman::RegisterIntrHandler(uint32 line, uint32 mode, uint32 handler, uint32 arg)
124 {
125 #ifdef _DEBUG
126 	CLog::GetInstance().Print(LOGNAME, FUNCTION_REGISTERINTRHANDLER "(line = %d, mode = %d, handler = 0x%08X, arg = 0x%08X);\r\n",
127 	                          line, mode, handler, arg);
128 #endif
129 	return m_bios.RegisterIntrHandler(line, mode, handler, arg);
130 }
131 
ReleaseIntrHandler(uint32 line)132 uint32 CIntrman::ReleaseIntrHandler(uint32 line)
133 {
134 #ifdef _DEBUG
135 	CLog::GetInstance().Print(LOGNAME, FUNCTION_RELEASEINTRHANDLER "(line = %d);\r\n",
136 	                          line);
137 #endif
138 	return m_bios.ReleaseIntrHandler(line);
139 }
140 
EnableIntrLine(CMIPS & context,uint32 line)141 uint32 CIntrman::EnableIntrLine(CMIPS& context, uint32 line)
142 {
143 #ifdef _DEBUG
144 	CLog::GetInstance().Print(LOGNAME, FUNCTION_ENABLEINTRLINE "(line = %d);\r\n",
145 	                          line);
146 #endif
147 	UNION64_32 mask(
148 	    context.m_pMemoryMap->GetWord(CIntc::MASK0),
149 	    context.m_pMemoryMap->GetWord(CIntc::MASK1));
150 	mask.f |= 1LL << line;
151 	context.m_pMemoryMap->SetWord(CIntc::MASK0, mask.h0);
152 	context.m_pMemoryMap->SetWord(CIntc::MASK1, mask.h1);
153 	return 0;
154 }
155 
DisableIntrLine(CMIPS & context,uint32 line,uint32 res)156 uint32 CIntrman::DisableIntrLine(CMIPS& context, uint32 line, uint32 res)
157 {
158 #ifdef _DEBUG
159 	CLog::GetInstance().Print(LOGNAME, FUNCTION_DISABLEINTRLINE "(line = %d, res = %08X);\r\n",
160 	                          line, res);
161 #endif
162 	UNION64_32 mask(
163 	    context.m_pMemoryMap->GetWord(CIntc::MASK0),
164 	    context.m_pMemoryMap->GetWord(CIntc::MASK1));
165 	mask.f &= ~(1LL << line);
166 	context.m_pMemoryMap->SetWord(CIntc::MASK0, mask.h0);
167 	context.m_pMemoryMap->SetWord(CIntc::MASK1, mask.h1);
168 	return 0;
169 }
170 
EnableInterrupts(CMIPS & context)171 uint32 CIntrman::EnableInterrupts(CMIPS& context)
172 {
173 #ifdef _DEBUG
174 	CLog::GetInstance().Print(LOGNAME, FUNCTION_ENABLEINTERRUPTS "();\r\n");
175 #endif
176 
177 	uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
178 	statusRegister |= CMIPS::STATUS_IE;
179 	return 0;
180 }
181 
DisableInterrupts(CMIPS & context)182 uint32 CIntrman::DisableInterrupts(CMIPS& context)
183 {
184 #ifdef _DEBUG
185 	CLog::GetInstance().Print(LOGNAME, FUNCTION_DISABLEINTERRUPTS "();\r\n");
186 #endif
187 
188 	uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
189 	statusRegister &= ~CMIPS::STATUS_IE;
190 	return 0;
191 }
192 
SuspendInterrupts(CMIPS & context,uint32 statePtr)193 uint32 CIntrman::SuspendInterrupts(CMIPS& context, uint32 statePtr)
194 {
195 #ifdef _DEBUG
196 	CLog::GetInstance().Print(LOGNAME, FUNCTION_SUSPENDINTERRUPTS "(statePtr = 0x%08X);\r\n",
197 	                          statePtr);
198 #endif
199 	uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
200 	uint32 result = ((statusRegister & CMIPS::STATUS_IE) != 0) ? 0 : -1;
201 	if(statePtr != 0)
202 	{
203 		uint32* state = reinterpret_cast<uint32*>(m_ram + statePtr);
204 		(*state) = statusRegister & CMIPS::STATUS_IE;
205 	}
206 	statusRegister &= ~CMIPS::STATUS_IE;
207 	return result;
208 }
209 
ResumeInterrupts(CMIPS & context,uint32 state)210 uint32 CIntrman::ResumeInterrupts(CMIPS& context, uint32 state)
211 {
212 #ifdef _DEBUG
213 	CLog::GetInstance().Print(LOGNAME, FUNCTION_RESUMEINTERRUPTS "();\r\n");
214 #endif
215 	uint32& statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
216 	if(state)
217 	{
218 		statusRegister |= CMIPS::STATUS_IE;
219 	}
220 	else
221 	{
222 		statusRegister &= ~CMIPS::STATUS_IE;
223 	}
224 	return 0;
225 }
226 
QueryIntrContext(CMIPS & context)227 uint32 CIntrman::QueryIntrContext(CMIPS& context)
228 {
229 #ifdef _DEBUG
230 	CLog::GetInstance().Print(LOGNAME, FUNCTION_QUERYINTRCONTEXT "();\r\n");
231 #endif
232 	uint32 statusRegister = context.m_State.nCOP0[CCOP_SCU::STATUS];
233 	//If we're inside an exception or if interrupts are disabled, we are inside an interrupt context
234 	return ((statusRegister & CMIPS::STATUS_EXL) != 0) || ((statusRegister & CMIPS::STATUS_IE) == 0);
235 }
236