Changed the way INTC handlers are managed in PS2OS.

This commit is contained in:
Jean-Philip Desjardins 2015-07-25 20:13:59 -04:00
parent 3d46888ea2
commit 33abecc37c
6 changed files with 164 additions and 84 deletions

View File

@ -11,7 +11,7 @@ public:
, m_idBase(idBase)
, m_structMax(structMax)
{
assert(m_idBase != 0);
}
StructType* GetBase() const

84
Source/OsStructQueue.h Normal file
View File

@ -0,0 +1,84 @@
#pragma once
template <typename StructType>
struct COsStructQueue
{
public:
typedef COsStructManager<StructType> StructManager;
COsStructQueue(StructManager& items, uint32* headIdPtr)
: m_items(items)
, m_headIdPtr(headIdPtr)
{
}
void PushFront(uint32 id)
{
uint32 nextId = (*m_headIdPtr);
(*m_headIdPtr) = id;
auto item = m_items[id];
item->nextId = nextId;
}
void PushBack(uint32 id)
{
auto nextId = m_headIdPtr;
while(1)
{
if(*nextId == 0) break;
auto nextItem = m_items[*nextId];
nextId = &nextItem->nextId;
}
*nextId = id;
}
void AddBefore(uint32 beforeId, uint32 id)
{
auto newItem = m_items[id];
auto nextId = m_headIdPtr;
while(1)
{
if(*nextId == 0)
{
//Id not found
assert(false);
break;
}
auto nextItem = m_items[*nextId];
if((*nextId) == beforeId)
{
(*nextId) = id;
newItem->nextId = beforeId;
break;
}
nextId = &nextItem->nextId;
}
}
void Unlink(uint32 id)
{
auto nextId = m_headIdPtr;
while(1)
{
if(*nextId == 0)
{
//Id not found
assert(false);
break;
}
auto nextItem = m_items[*nextId];
if((*nextId) == id)
{
(*nextId) = nextItem->nextId;
nextItem->nextId = 0;
break;
}
nextId = &nextItem->nextId;
}
}
private:
uint32* m_headIdPtr = nullptr;
StructManager& m_items;
};

View File

@ -49,6 +49,8 @@
#define BIOS_ADDRESS_CURRENT_THREAD_ID 0x00000010
#define BIOS_ADDRESS_VSYNCFLAG_VALUE1PTR 0x00000014
#define BIOS_ADDRESS_VSYNCFLAG_VALUE2PTR 0x00000018
#define BIOS_ADDRESS_INTCHANDLERQUEUE_BASE 0x0000001C
#define BIOS_ADDRESS_INTCHANDLER_BASE 0x0000A000
#define BIOS_ADDRESS_DMACHANDLER_BASE 0x0000C000
#define BIOS_ADDRESS_SEMAPHORE_BASE 0x0000E000
#define BIOS_ADDRESS_ALARM_BASE 0x00010800
@ -56,6 +58,7 @@
#define BIOS_ADDRESS_BASE 0x1FC00000
#define BIOS_ADDRESS_INTERRUPTHANDLER 0x1FC00200
#define BIOS_ADDRESS_DMACHANDLER 0x1FC01000
#define BIOS_ADDRESS_INTCHANDLER 0x1FC02000
#define BIOS_ADDRESS_THREADEPILOG 0x1FC03000
#define BIOS_ADDRESS_WAITTHREADPROC 0x1FC03100
#define BIOS_ADDRESS_ALARMHANDLER 0x1FC03200
@ -194,8 +197,10 @@ CPS2OS::CPS2OS(CMIPS& ee, uint8* ram, uint8* bios, uint8* spr, CGSHandler*& gs,
, m_sif(sif)
, m_iopBios(iopBios)
, m_semaphores(reinterpret_cast<SEMAPHORE*>(m_ram + BIOS_ADDRESS_SEMAPHORE_BASE), BIOS_ID_BASE, MAX_SEMAPHORE)
, m_intcHandlers(reinterpret_cast<INTCHANDLER*>(m_ram + BIOS_ADDRESS_INTCHANDLER_BASE), BIOS_ID_BASE, MAX_INTCHANDLER)
, m_dmacHandlers(reinterpret_cast<DMACHANDLER*>(m_ram + BIOS_ADDRESS_DMACHANDLER_BASE), BIOS_ID_BASE, MAX_DMACHANDLER)
, m_alarms(reinterpret_cast<ALARM*>(m_ram + BIOS_ADDRESS_ALARM_BASE), BIOS_ID_BASE, MAX_ALARM)
, m_intcHandlerQueue(m_intcHandlers, reinterpret_cast<uint32*>(m_ram + BIOS_ADDRESS_INTCHANDLERQUEUE_BASE))
{
Initialize();
}
@ -250,8 +255,8 @@ void CPS2OS::DumpIntcHandlers()
for(unsigned int i = 0; i < MAX_INTCHANDLER; i++)
{
INTCHANDLER* handler = GetIntcHandler(i + 1);
if(handler->valid == 0) continue;
auto handler = m_intcHandlers[i + 1];
if(handler == nullptr) continue;
printf("ID: %0.2i, Line: %i, Address: 0x%0.8X.\r\n", \
i + 1,
@ -680,10 +685,8 @@ void CPS2OS::AssembleInterruptHandler()
assembler.NOP();
//Process handlers
assembler.LUI(CMIPS::T0, 0x1FC0);
assembler.ORI(CMIPS::T0, CMIPS::T0, 0x2000);
assembler.ADDIU(CMIPS::A0, CMIPS::R0, line);
assembler.JALR(CMIPS::T0);
assembler.JAL(BIOS_ADDRESS_INTCHANDLER);
assembler.NOP();
assembler.MarkLabel(skipIntHandlerLabel);
@ -856,67 +859,68 @@ void CPS2OS::AssembleDmacHandler()
void CPS2OS::AssembleIntcHandler()
{
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_bios[0x2000]));
CMIPSAssembler assembler(reinterpret_cast<uint32*>(&m_bios[BIOS_ADDRESS_INTCHANDLER - BIOS_ADDRESS_BASE]));
CMIPSAssembler::LABEL checkHandlerLabel = assembler.CreateLabel();
CMIPSAssembler::LABEL moveToNextHandler = assembler.CreateLabel();
auto checkHandlerLabel = assembler.CreateLabel();
auto finishLoop = assembler.CreateLabel();
auto nextIdPtrRegister = CMIPS::S0;
auto causeRegister = CMIPS::S1;
auto nextIdRegister = CMIPS::T2;
//Prologue
//S0 -> Handler Counter
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFE0);
assembler.SD(CMIPS::RA, 0x0000, CMIPS::SP);
assembler.SD(CMIPS::S0, 0x0008, CMIPS::SP);
assembler.SD(CMIPS::S1, 0x0010, CMIPS::SP);
//Clear INTC cause
assembler.LUI(CMIPS::T1, 0x1000);
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xF000);
assembler.LI(CMIPS::T1, CINTC::INTC_STAT);
assembler.ADDIU(CMIPS::T0, CMIPS::R0, 0x0001);
assembler.SLLV(CMIPS::T0, CMIPS::T0, CMIPS::A0);
assembler.SW(CMIPS::T0, 0x0000, CMIPS::T1);
//Initialize INTC handler loop
assembler.ADDU(CMIPS::S0, CMIPS::R0, CMIPS::R0);
assembler.ADDU(CMIPS::S1, CMIPS::A0, CMIPS::R0);
assembler.LI(nextIdPtrRegister, BIOS_ADDRESS_INTCHANDLERQUEUE_BASE);
assembler.ADDU(causeRegister, CMIPS::A0, CMIPS::R0);
assembler.MarkLabel(checkHandlerLabel);
//Check
assembler.LW(nextIdRegister, 0, nextIdPtrRegister);
assembler.BEQ(nextIdRegister, CMIPS::R0, finishLoop);
assembler.ADDIU(nextIdRegister, nextIdRegister, static_cast<uint16>(-1));
//Get the address to the current INTCHANDLER structure
assembler.ADDIU(CMIPS::T0, CMIPS::R0, sizeof(INTCHANDLER));
assembler.MULTU(CMIPS::T0, CMIPS::S0, CMIPS::T0);
assembler.LUI(CMIPS::T1, 0x8000);
assembler.ORI(CMIPS::T1, CMIPS::T1, 0xA000);
assembler.MULTU(CMIPS::T0, nextIdRegister, CMIPS::T0);
assembler.LI(CMIPS::T1, BIOS_ADDRESS_INTCHANDLER_BASE);
assembler.ADDU(CMIPS::T0, CMIPS::T0, CMIPS::T1);
//Check validity
assembler.LW(CMIPS::T1, 0x0000, CMIPS::T0);
assembler.BEQ(CMIPS::T1, CMIPS::R0, moveToNextHandler);
assembler.NOP();
//Adjust nextIdPtr
assembler.ADDIU(nextIdPtrRegister, CMIPS::T0, offsetof(INTCHANDLER, nextId));
//Check if the cause is good one
assembler.LW(CMIPS::T1, 0x0004, CMIPS::T0);
assembler.BNE(CMIPS::S1, CMIPS::T1, moveToNextHandler);
assembler.LW(CMIPS::T1, offsetof(INTCHANDLER, cause), CMIPS::T0);
assembler.BNE(causeRegister, CMIPS::T1, checkHandlerLabel);
assembler.NOP();
//Load the necessary stuff
assembler.LW(CMIPS::T1, 0x0008, CMIPS::T0);
assembler.ADDU(CMIPS::A0, CMIPS::S1, CMIPS::R0);
assembler.LW(CMIPS::A1, 0x000C, CMIPS::T0);
assembler.LW(CMIPS::GP, 0x0010, CMIPS::T0);
assembler.LW(CMIPS::T1, offsetof(INTCHANDLER, address), CMIPS::T0);
assembler.ADDU(CMIPS::A0, causeRegister, CMIPS::R0);
assembler.LW(CMIPS::A1, offsetof(INTCHANDLER, arg), CMIPS::T0);
assembler.LW(CMIPS::GP, offsetof(INTCHANDLER, gp), CMIPS::T0);
//Jump
assembler.JALR(CMIPS::T1);
assembler.NOP();
assembler.MarkLabel(moveToNextHandler);
//Increment handler counter and test
assembler.ADDIU(CMIPS::S0, CMIPS::S0, 0x0001);
assembler.ADDIU(CMIPS::T0, CMIPS::R0, MAX_INTCHANDLER - 1);
assembler.BNE(CMIPS::S0, CMIPS::T0, checkHandlerLabel);
assembler.BGEZ(CMIPS::V0, checkHandlerLabel);
assembler.NOP();
assembler.MarkLabel(finishLoop);
//Epilogue
assembler.LD(CMIPS::RA, 0x0000, CMIPS::SP);
assembler.LD(CMIPS::S0, 0x0008, CMIPS::SP);
@ -1248,26 +1252,6 @@ uint8* CPS2OS::GetStructPtr(uint32 address) const
return memory + address;
}
uint32 CPS2OS::GetNextAvailableIntcHandlerId()
{
for(uint32 i = 1; i < MAX_INTCHANDLER; i++)
{
INTCHANDLER* handler = GetIntcHandler(i);
if(handler->valid != 1)
{
return i;
}
}
return 0xFFFFFFFF;
}
CPS2OS::INTCHANDLER* CPS2OS::GetIntcHandler(uint32 id)
{
id--;
return &((INTCHANDLER*)&m_ram[0x0000A000])[id];
}
uint32 CPS2OS::GetNextAvailableDeci2HandlerId()
{
for(uint32 i = 1; i < MAX_DECI2HANDLER; i++)
@ -1407,30 +1391,33 @@ void CPS2OS::sc_AddIntcHandler()
uint32 next = m_ee.m_State.nGPR[SC_PARAM2].nV[0];
uint32 arg = m_ee.m_State.nGPR[SC_PARAM3].nV[0];
/*
if(next != 0)
uint32 id = m_intcHandlers.Allocate();
if(static_cast<int32>(id) == -1)
{
assert(0);
}
*/
uint32 id = GetNextAvailableIntcHandlerId();
if(id == 0xFFFFFFFF)
{
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(-1);
return;
}
INTCHANDLER* handler = GetIntcHandler(id);
handler->valid = 1;
auto handler = m_intcHandlers[id];
handler->address = address;
handler->cause = cause;
handler->arg = arg;
handler->gp = m_ee.m_State.nGPR[CMIPS::GP].nV[0];
m_ee.m_State.nGPR[SC_RETURN].nV[0] = id;
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
if(next == 0)
{
m_intcHandlerQueue.PushFront(id);
}
else if(static_cast<int32>(next) == -1)
{
m_intcHandlerQueue.PushBack(id);
}
else
{
m_intcHandlerQueue.AddBefore(next, id);
}
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(id);
}
//11
@ -1439,18 +1426,17 @@ void CPS2OS::sc_RemoveIntcHandler()
uint32 cause = m_ee.m_State.nGPR[SC_PARAM0].nV[0];
uint32 id = m_ee.m_State.nGPR[SC_PARAM1].nV[0];
INTCHANDLER* handler = GetIntcHandler(id);
if(handler->valid != 1)
auto handler = m_intcHandlers[id];
if(!handler)
{
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0xFFFFFFFF;
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0xFFFFFFFF;
m_ee.m_State.nGPR[SC_RETURN].nD0 = static_cast<int32>(-1);
return;
}
handler->valid = 0;
m_intcHandlerQueue.Unlink(id);
m_intcHandlers.Free(id);
m_ee.m_State.nGPR[SC_RETURN].nV[0] = 0;
m_ee.m_State.nGPR[SC_RETURN].nV[1] = 0;
m_ee.m_State.nGPR[SC_RETURN].nD0 = 0;
}
//12
@ -2422,15 +2408,14 @@ void CPS2OS::sc_SetSyscall()
unsigned int line = 12;
uint32 handlerId = GetNextAvailableIntcHandlerId();
if(handlerId == 0xFFFFFFFF)
uint32 handlerId = m_intcHandlers.Allocate();
if(static_cast<int32>(handlerId) == -1)
{
CLog::GetInstance().Print(LOG_NAME, "Couldn't set INTC handler through SetSyscall");
return;
}
INTCHANDLER* handler = GetIntcHandler(handlerId);
handler->valid = 1;
auto handler = m_intcHandlers[handlerId];
handler->address = address & 0x1FFFFFFF;
handler->cause = line;
handler->arg = 0;
@ -2440,6 +2425,8 @@ void CPS2OS::sc_SetSyscall()
{
m_ee.m_pMemoryMap->SetWord(CINTC::INTC_MASK, (1 << line));
}
m_intcHandlerQueue.PushFront(handlerId);
}
else
{

View File

@ -6,6 +6,7 @@
#include "../MIPS.h"
#include "../BiosDebugInfoProvider.h"
#include "../OsStructManager.h"
#include "../OsStructQueue.h"
#include "../gs/GSHandler.h"
#include "SIF.h"
@ -182,7 +183,8 @@ private:
struct INTCHANDLER
{
uint32 valid;
uint32 isValid;
uint32 nextId;
uint32 cause;
uint32 address;
uint32 arg;
@ -255,9 +257,12 @@ private:
};
typedef COsStructManager<SEMAPHORE> SemaphoreList;
typedef COsStructManager<INTCHANDLER> IntcHandlerList;
typedef COsStructManager<DMACHANDLER> DmacHandlerList;
typedef COsStructManager<ALARM> AlarmList;
typedef COsStructQueue<INTCHANDLER> IntcHandlerQueue;
typedef void (CPS2OS::*SystemCallHandler)();
void LoadELF(Framework::CStream&, const char*, const ArgumentList&);
@ -296,9 +301,6 @@ private:
uint8* GetStructPtr(uint32) const;
uint32 GetNextAvailableIntcHandlerId();
INTCHANDLER* GetIntcHandler(uint32);
uint32 GetNextAvailableDeci2HandlerId();
DECI2HANDLER* GetDeci2Handler(uint32);
@ -364,9 +366,12 @@ private:
CMIPS& m_ee;
CRoundRibbon* m_threadSchedule;
SemaphoreList m_semaphores;
IntcHandlerList m_intcHandlers;
DmacHandlerList m_dmacHandlers;
AlarmList m_alarms;
IntcHandlerQueue m_intcHandlerQueue;
std::string m_executableName;
ArgumentList m_currentArguments;

View File

@ -291,6 +291,7 @@
<ClInclude Include="..\Source\MIPSReflection.h" />
<ClInclude Include="..\Source\MIPSTags.h" />
<ClInclude Include="..\Source\OsStructManager.h" />
<ClInclude Include="..\Source\OsStructQueue.h" />
<ClInclude Include="..\Source\PadHandler.h" />
<ClInclude Include="..\Source\PadListener.h" />
<ClInclude Include="..\Source\Profiler.h" />

View File

@ -861,5 +861,8 @@
<ClInclude Include="..\Source\DiskUtils.h">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="..\Source\OsStructQueue.h">
<Filter>Source Files</Filter>
</ClInclude>
</ItemGroup>
</Project>