2008-10-30 22:22:10 +00:00
|
|
|
#include <assert.h>
|
2008-01-15 20:27:44 +00:00
|
|
|
#include "Iop_Timrman.h"
|
2008-10-30 22:22:10 +00:00
|
|
|
#include "Iop_Intc.h"
|
2008-11-10 01:46:02 +00:00
|
|
|
#include "../Log.h"
|
2008-10-30 22:22:10 +00:00
|
|
|
#include "IopBios.h"
|
2008-11-03 00:36:40 +00:00
|
|
|
#include "Iop_RootCounters.h"
|
2008-10-29 01:42:35 +00:00
|
|
|
|
|
|
|
#define LOG_NAME ("iop_timrman")
|
2008-01-15 20:27:44 +00:00
|
|
|
|
2008-11-28 23:46:52 +00:00
|
|
|
#define FUNCTION_ALLOCHARDTIMER "AllocHardTimer"
|
|
|
|
#define FUNCTION_SETTIMERCALLBACK "SetTimerCallback"
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
using namespace Iop;
|
|
|
|
using namespace std;
|
|
|
|
|
2008-10-30 22:22:10 +00:00
|
|
|
CTimrman::CTimrman(CIopBios& bios) :
|
|
|
|
m_bios(bios)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
CTimrman::~CTimrman()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
string CTimrman::GetId() const
|
|
|
|
{
|
|
|
|
return "timrman";
|
|
|
|
}
|
|
|
|
|
2008-11-28 23:46:52 +00:00
|
|
|
string CTimrman::GetFunctionName(unsigned int functionId) const
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return FUNCTION_ALLOCHARDTIMER;
|
|
|
|
break;
|
|
|
|
case 20:
|
|
|
|
return FUNCTION_SETTIMERCALLBACK;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
void CTimrman::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
2008-10-29 01:42:35 +00:00
|
|
|
case 4:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = AllocHardTimer(
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0
|
|
|
|
);
|
|
|
|
break;
|
2008-01-15 20:27:44 +00:00
|
|
|
case 20:
|
2008-10-30 22:22:10 +00:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = SetTimerCallback(
|
|
|
|
context,
|
|
|
|
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);
|
2008-01-15 20:27:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
2008-10-29 01:42:35 +00:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "(%0.8X): Unknown function (%d) called.\r\n",
|
|
|
|
context.m_State.nPC, functionId);
|
2008-01-15 20:27:44 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2008-10-29 01:42:35 +00:00
|
|
|
|
2008-10-30 22:22:10 +00:00
|
|
|
#define TIMER_ID (2)
|
|
|
|
|
2008-10-29 01:42:35 +00:00
|
|
|
int CTimrman::AllocHardTimer(int source, int size, int prescale)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2008-11-28 23:46:52 +00:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_ALLOCHARDTIMER "(source = %d, size = %d, prescale = %d).\r\n",
|
2008-10-29 01:42:35 +00:00
|
|
|
source, size, prescale);
|
|
|
|
#endif
|
2008-10-30 22:22:10 +00:00
|
|
|
return TIMER_ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CTimrman::SetTimerCallback(CMIPS& context, int timerId, uint32 unknown, uint32 handler, uint32 arg)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2009-02-10 01:44:48 +00:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERCALLBACK "(timerId = %d, unknown = %d, handler = 0x%0.8X, arg = 0x%0.8X).\r\n",
|
2008-10-30 22:22:10 +00:00
|
|
|
timerId, unknown, handler, arg);
|
|
|
|
#endif
|
|
|
|
assert(timerId == TIMER_ID);
|
|
|
|
m_bios.RegisterIntrHandler(CIntc::LINE_RTC2, 0, handler, arg);
|
|
|
|
|
|
|
|
//Enable timer
|
2008-11-03 00:36:40 +00:00
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::CNT2_BASE + CRootCounters::CNT_COUNT, 0x0000);
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::CNT2_BASE + CRootCounters::CNT_MODE, 0x0258);
|
2008-11-05 21:37:07 +00:00
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::CNT2_BASE + CRootCounters::CNT_TARGET, 0x4400);
|
2008-10-30 22:22:10 +00:00
|
|
|
|
|
|
|
uint32 mask = context.m_pMemoryMap->GetWord(CIntc::MASK0);
|
|
|
|
mask |= (1 << CIntc::LINE_RTC2);
|
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK0, mask);
|
|
|
|
return 0;
|
2008-10-29 01:42:35 +00:00
|
|
|
}
|