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
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define FUNCTION_ALLOCHARDTIMER "AllocHardTimer"
|
|
|
|
#define FUNCTION_REFERHARDTIMER "ReferHardTimer"
|
|
|
|
#define FUNCTION_SETTIMERMODE "SetTimerMode"
|
|
|
|
#define FUNCTION_GETTIMERSTATUS "GetTimerStatus"
|
|
|
|
#define FUNCTION_GETTIMERCOUNTER "GetTimerCounter"
|
|
|
|
#define FUNCTION_SETTIMERCOMPARE "SetTimerCompare"
|
|
|
|
#define FUNCTION_GETHARDTIMERINTRCODE "GetHardTimerIntrCode"
|
|
|
|
#define FUNCTION_SETTIMERCALLBACK "SetTimerCallback"
|
|
|
|
#define FUNCTION_SETUPHARDTIMER "SetupHardTimer"
|
|
|
|
#define FUNCTION_STARTHARDTIMER "StartHardTimer"
|
|
|
|
#define FUNCTION_STOPHARDTIMER "StopHardTimer"
|
2008-11-28 23:46:52 +00:00
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
using namespace Iop;
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
CTimrman::CTimrman(CIopBios& bios)
|
|
|
|
: m_bios(bios)
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CTimrman::~CTimrman()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-11-06 21:37:50 +00:00
|
|
|
std::string CTimrman::GetId() const
|
2008-01-15 20:27:44 +00:00
|
|
|
{
|
2012-04-26 06:29:34 +00:00
|
|
|
return "timrman";
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
|
|
|
|
2011-11-06 21:37:50 +00:00
|
|
|
std::string CTimrman::GetFunctionName(unsigned int functionId) const
|
2008-11-28 23:46:52 +00:00
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
return FUNCTION_ALLOCHARDTIMER;
|
|
|
|
break;
|
2012-05-29 01:01:02 +00:00
|
|
|
case 5:
|
|
|
|
return FUNCTION_REFERHARDTIMER;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
return FUNCTION_SETTIMERMODE;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
return FUNCTION_GETTIMERSTATUS;
|
|
|
|
break;
|
2015-05-22 01:28:51 -04:00
|
|
|
case 10:
|
|
|
|
return FUNCTION_GETTIMERCOUNTER;
|
|
|
|
break;
|
2012-05-29 01:01:02 +00:00
|
|
|
case 11:
|
|
|
|
return FUNCTION_SETTIMERCOMPARE;
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
return FUNCTION_GETHARDTIMERINTRCODE;
|
|
|
|
break;
|
2008-11-28 23:46:52 +00:00
|
|
|
case 20:
|
|
|
|
return FUNCTION_SETTIMERCALLBACK;
|
|
|
|
break;
|
2011-11-06 21:37:50 +00:00
|
|
|
case 22:
|
2014-11-24 16:48:19 +00:00
|
|
|
return FUNCTION_SETUPHARDTIMER;
|
2011-11-06 21:37:50 +00:00
|
|
|
break;
|
|
|
|
case 23:
|
2014-11-24 16:48:19 +00:00
|
|
|
return FUNCTION_STARTHARDTIMER;
|
2011-11-06 21:37:50 +00:00
|
|
|
break;
|
2016-05-14 20:52:46 -04:00
|
|
|
case 24:
|
|
|
|
return FUNCTION_STOPHARDTIMER;
|
|
|
|
break;
|
2008-11-28 23:46:52 +00:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-15 20:27:44 +00:00
|
|
|
void CTimrman::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
2012-04-26 06:29:34 +00:00
|
|
|
switch(functionId)
|
|
|
|
{
|
|
|
|
case 4:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = AllocHardTimer(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A2].nV0);
|
2012-04-26 06:29:34 +00:00
|
|
|
break;
|
2012-05-29 01:01:02 +00:00
|
|
|
case 5:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = ReferHardTimer(
|
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-05-29 01:01:02 +00:00
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
SetTimerMode(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0);
|
2012-05-29 01:01:02 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = GetTimerStatus(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2012-05-29 01:01:02 +00:00
|
|
|
break;
|
2015-05-22 01:28:51 -04:00
|
|
|
case 10:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = GetTimerCounter(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2015-05-22 01:28:51 -04:00
|
|
|
break;
|
2012-05-29 01:01:02 +00:00
|
|
|
case 11:
|
|
|
|
SetTimerCompare(
|
2018-04-30 21:01:23 +01:00
|
|
|
context,
|
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0,
|
|
|
|
context.m_State.nGPR[CMIPS::A1].nV0);
|
2012-05-29 01:01:02 +00:00
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = GetHardTimerIntrCode(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2012-05-29 01:01:02 +00:00
|
|
|
break;
|
2012-04-26 06:29:34 +00:00
|
|
|
case 20:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = SetTimerCallback(
|
2018-04-30 21:01:23 +01:00
|
|
|
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);
|
2012-04-26 06:29:34 +00:00
|
|
|
break;
|
2011-11-06 21:37:50 +00:00
|
|
|
case 22:
|
2014-11-24 16:48:19 +00:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = SetupHardTimer(
|
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);
|
2011-11-06 21:37:50 +00:00
|
|
|
break;
|
|
|
|
case 23:
|
2014-11-24 16:48:19 +00:00
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = StartHardTimer(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2011-11-06 21:37:50 +00:00
|
|
|
break;
|
2016-05-14 20:52:46 -04:00
|
|
|
case 24:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nD0 = StopHardTimer(
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_State.nGPR[CMIPS::A0].nV0);
|
2016-05-14 20:52:46 -04:00
|
|
|
break;
|
2012-04-26 06:29:34 +00:00
|
|
|
default:
|
2018-05-24 12:59:15 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "(%08X): Unknown function (%d) called.\r\n",
|
2018-05-25 12:26:07 -04:00
|
|
|
context.m_State.nPC, functionId);
|
2012-04-26 06:29:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-01-15 20:27:44 +00:00
|
|
|
}
|
2008-10-29 01:42:35 +00:00
|
|
|
|
2015-03-08 00:34:32 -05:00
|
|
|
int CTimrman::AllocHardTimer(CMIPS& context, uint32 source, uint32 size, uint32 prescale)
|
2008-10-29 01:42:35 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2015-02-01 18:50:04 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_ALLOCHARDTIMER "(source = %d, size = %d, prescale = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
source, size, prescale);
|
2008-10-29 01:42:35 +00:00
|
|
|
#endif
|
2015-03-08 00:34:32 -05:00
|
|
|
assert(
|
2018-04-30 21:01:23 +01:00
|
|
|
(source == CRootCounters::COUNTER_SOURCE_SYSCLOCK) ||
|
|
|
|
(source == CRootCounters::COUNTER_SOURCE_PIXEL) ||
|
|
|
|
(source == CRootCounters::COUNTER_SOURCE_HLINE));
|
2012-05-29 01:01:02 +00:00
|
|
|
for(unsigned int i = 0; i < CRootCounters::MAX_COUNTERS; i++)
|
|
|
|
{
|
|
|
|
if(
|
2018-04-30 21:01:23 +01:00
|
|
|
(CRootCounters::g_counterSizes[i] == size) &&
|
|
|
|
((CRootCounters::g_counterSources[i] & source) != 0) &&
|
|
|
|
(CRootCounters::g_counterMaxScales[i] >= prescale))
|
2012-05-29 01:01:02 +00:00
|
|
|
{
|
2015-03-08 00:34:32 -05:00
|
|
|
//Set proper clock divider
|
|
|
|
auto modeAddr = CRootCounters::g_counterBaseAddresses[i] + CRootCounters::CNT_MODE;
|
|
|
|
auto mode = make_convertible<CRootCounters::MODE>(context.m_pMemoryMap->GetWord(modeAddr));
|
|
|
|
mode.clc = (source != CRootCounters::COUNTER_SOURCE_SYSCLOCK) ? 1 : 0;
|
2015-07-21 01:22:26 -04:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
if(prescale == 1)
|
|
|
|
mode.div = CRootCounters::COUNTER_SCALE_1;
|
|
|
|
else if(prescale == 8)
|
|
|
|
mode.div = CRootCounters::COUNTER_SCALE_8;
|
|
|
|
else if(prescale == 16)
|
|
|
|
mode.div = CRootCounters::COUNTER_SCALE_16;
|
|
|
|
else if(prescale == 256)
|
|
|
|
mode.div = CRootCounters::COUNTER_SCALE_256;
|
|
|
|
else
|
|
|
|
assert(false);
|
2015-07-21 01:22:26 -04:00
|
|
|
|
2015-03-08 00:34:32 -05:00
|
|
|
context.m_pMemoryMap->SetWord(modeAddr, mode);
|
|
|
|
|
2012-05-29 01:01:02 +00:00
|
|
|
return (i + 1);
|
|
|
|
}
|
|
|
|
}
|
2020-09-18 13:15:02 -04:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "Couldn't allocate a timer.\r\n");
|
|
|
|
return CIopBios::KERNEL_RESULT_ERROR_NO_TIMER;
|
2008-10-30 22:22:10 +00:00
|
|
|
}
|
|
|
|
|
2012-05-29 01:01:02 +00:00
|
|
|
int CTimrman::ReferHardTimer(uint32 source, uint32 size, uint32 mode, uint32 modeMask)
|
2008-10-30 22:22:10 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_REFERHARDTIMER "(source = %d, size = %d, mode = 0x%08X, mask = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
source, size, mode, modeMask);
|
2008-10-30 22:22:10 +00:00
|
|
|
#endif
|
2012-05-29 01:01:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CTimrman::SetTimerMode(CMIPS& context, uint32 timerId, uint32 mode)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERMODE "(timerId = %d, mode = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId, mode);
|
2012-05-29 01:01:02 +00:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return;
|
|
|
|
timerId--;
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_MODE, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CTimrman::GetTimerStatus(CMIPS& context, uint32 timerId)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_GETTIMERSTATUS "(timerId = %d).\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId);
|
2012-05-29 01:01:02 +00:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return 0;
|
|
|
|
timerId--;
|
|
|
|
return context.m_pMemoryMap->GetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_MODE) | 0x800;
|
|
|
|
}
|
|
|
|
|
2015-05-22 01:28:51 -04:00
|
|
|
int CTimrman::GetTimerCounter(CMIPS& context, uint32 timerId)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_GETTIMERCOUNTER "(timerId = %d).\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId);
|
2015-05-22 01:28:51 -04:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return 0;
|
|
|
|
timerId--;
|
|
|
|
return context.m_pMemoryMap->GetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_COUNT);
|
|
|
|
}
|
|
|
|
|
2012-05-29 01:01:02 +00:00
|
|
|
void CTimrman::SetTimerCompare(CMIPS& context, uint32 timerId, uint32 compare)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERCOMPARE "(timerId = %d, compare = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId, compare);
|
2012-05-29 01:01:02 +00:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return;
|
|
|
|
timerId--;
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_COUNT, 0);
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_TARGET, compare);
|
|
|
|
}
|
|
|
|
|
|
|
|
int CTimrman::GetHardTimerIntrCode(uint32 timerId)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_GETHARDTIMERINTRCODE "(timerId = %d).\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId);
|
2012-05-29 01:01:02 +00:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return CIntc::LINE_RTC0;
|
|
|
|
timerId--;
|
|
|
|
return CRootCounters::g_counterInterruptLines[timerId];
|
|
|
|
}
|
|
|
|
|
|
|
|
int CTimrman::SetTimerCallback(CMIPS& context, int timerId, uint32 target, uint32 handler, uint32 arg)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERCALLBACK "(timerId = %d, target = %d, handler = 0x%08X, arg = 0x%08X);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId, target, handler, arg);
|
2012-05-29 01:01:02 +00:00
|
|
|
#endif
|
|
|
|
if(timerId == 0) return 0;
|
|
|
|
timerId--;
|
|
|
|
|
|
|
|
uint32 timerInterruptLine = CRootCounters::g_counterInterruptLines[timerId];
|
|
|
|
m_bios.RegisterIntrHandler(timerInterruptLine, 0, handler, arg);
|
2018-04-30 21:01:23 +01:00
|
|
|
|
2015-03-08 00:34:32 -05:00
|
|
|
auto modeAddr = CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_MODE;
|
|
|
|
auto mode = make_convertible<CRootCounters::MODE>(context.m_pMemoryMap->GetWord(modeAddr));
|
|
|
|
|
|
|
|
mode.tar = 1;
|
|
|
|
mode.iq1 = 1;
|
|
|
|
mode.iq2 = 1;
|
|
|
|
|
2008-10-30 22:22:10 +00:00
|
|
|
//Enable timer
|
2018-04-30 21:01:23 +01:00
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_COUNT, 0x0000);
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_MODE, mode);
|
|
|
|
context.m_pMemoryMap->SetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_TARGET, target);
|
2008-10-30 22:22:10 +00:00
|
|
|
|
|
|
|
uint32 mask = context.m_pMemoryMap->GetWord(CIntc::MASK0);
|
2012-05-29 01:01:02 +00:00
|
|
|
mask |= (1 << timerInterruptLine);
|
2008-10-30 22:22:10 +00:00
|
|
|
context.m_pMemoryMap->SetWord(CIntc::MASK0, mask);
|
|
|
|
return 0;
|
2008-10-29 01:42:35 +00:00
|
|
|
}
|
2011-11-06 21:37:50 +00:00
|
|
|
|
2014-11-24 16:48:19 +00:00
|
|
|
int CTimrman::SetupHardTimer(uint32 timerId, uint32 source, uint32 mode, uint32 prescale)
|
2011-11-06 21:37:50 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2015-02-01 18:50:04 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETUPHARDTIMER "(timerId = %d, source = %d, mode = %d, prescale = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId, source, mode, prescale);
|
2011-11-06 21:37:50 +00:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-24 16:48:19 +00:00
|
|
|
int CTimrman::StartHardTimer(uint32 timerId)
|
2011-11-06 21:37:50 +00:00
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
2015-02-01 18:50:04 -05:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_STARTHARDTIMER "(timerId = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId);
|
2011-11-06 21:37:50 +00:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
2016-05-14 20:52:46 -04:00
|
|
|
|
|
|
|
int32 CTimrman::StopHardTimer(uint32 timerId)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, FUNCTION_STOPHARDTIMER "(timerId = %d);\r\n",
|
2018-04-30 21:01:23 +01:00
|
|
|
timerId);
|
2016-05-14 20:52:46 -04:00
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|