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