Play-/Source/iop/Iop_Timrman.cpp

318 lines
9.6 KiB
C++
Raw Normal View History

#include <assert.h>
#include "Iop_Timrman.h"
#include "Iop_Intc.h"
#include "../Log.h"
#include "IopBios.h"
#include "Iop_RootCounters.h"
#define LOG_NAME ("iop_timrman")
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"
using namespace Iop;
2018-04-30 21:01:23 +01:00
CTimrman::CTimrman(CIopBios& bios)
: m_bios(bios)
{
}
CTimrman::~CTimrman()
{
}
std::string CTimrman::GetId() const
{
return "timrman";
}
std::string CTimrman::GetFunctionName(unsigned int functionId) const
{
switch(functionId)
{
case 4:
return FUNCTION_ALLOCHARDTIMER;
break;
case 5:
return FUNCTION_REFERHARDTIMER;
break;
case 7:
return FUNCTION_SETTIMERMODE;
break;
case 8:
return FUNCTION_GETTIMERSTATUS;
break;
case 10:
return FUNCTION_GETTIMERCOUNTER;
break;
case 11:
return FUNCTION_SETTIMERCOMPARE;
break;
case 16:
return FUNCTION_GETHARDTIMERINTRCODE;
break;
case 20:
return FUNCTION_SETTIMERCALLBACK;
break;
case 22:
2014-11-24 16:48:19 +00:00
return FUNCTION_SETUPHARDTIMER;
break;
case 23:
2014-11-24 16:48:19 +00:00
return FUNCTION_STARTHARDTIMER;
break;
2016-05-14 20:52:46 -04:00
case 24:
return FUNCTION_STOPHARDTIMER;
break;
default:
return "unknown";
break;
}
}
void CTimrman::Invoke(CMIPS& context, unsigned int functionId)
{
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);
break;
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);
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);
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);
break;
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);
break;
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);
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);
break;
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);
break;
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);
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);
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;
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);
break;
}
}
int CTimrman::AllocHardTimer(CMIPS& context, uint32 source, uint32 size, uint32 prescale)
{
#ifdef _DEBUG
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);
#endif
assert(
2018-04-30 21:01:23 +01:00
(source == CRootCounters::COUNTER_SOURCE_SYSCLOCK) ||
(source == CRootCounters::COUNTER_SOURCE_PIXEL) ||
(source == CRootCounters::COUNTER_SOURCE_HLINE));
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))
{
//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;
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);
context.m_pMemoryMap->SetWord(modeAddr, mode);
return (i + 1);
}
}
CLog::GetInstance().Warn(LOG_NAME, "Couldn't allocate a timer.\r\n");
return CIopBios::KERNEL_RESULT_ERROR_NO_TIMER;
}
int CTimrman::ReferHardTimer(uint32 source, uint32 size, uint32 mode, uint32 modeMask)
{
#ifdef _DEBUG
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);
#endif
return 0;
}
void CTimrman::SetTimerMode(CMIPS& context, uint32 timerId, uint32 mode)
{
#ifdef _DEBUG
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERMODE "(timerId = %d, mode = 0x%08X);\r\n",
2018-04-30 21:01:23 +01:00
timerId, mode);
#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);
#endif
if(timerId == 0) return 0;
timerId--;
return context.m_pMemoryMap->GetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_MODE) | 0x800;
}
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);
#endif
if(timerId == 0) return 0;
timerId--;
return context.m_pMemoryMap->GetWord(CRootCounters::g_counterBaseAddresses[timerId] + CRootCounters::CNT_COUNT);
}
void CTimrman::SetTimerCompare(CMIPS& context, uint32 timerId, uint32 compare)
{
#ifdef _DEBUG
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SETTIMERCOMPARE "(timerId = %d, compare = 0x%08X);\r\n",
2018-04-30 21:01:23 +01:00
timerId, compare);
#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);
#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
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);
#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
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;
//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);
uint32 mask = context.m_pMemoryMap->GetWord(CIntc::MASK0);
mask |= (1 << timerInterruptLine);
context.m_pMemoryMap->SetWord(CIntc::MASK0, mask);
return 0;
}
2014-11-24 16:48:19 +00:00
int CTimrman::SetupHardTimer(uint32 timerId, uint32 source, uint32 mode, uint32 prescale)
{
#ifdef _DEBUG
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);
#endif
return 0;
}
2014-11-24 16:48:19 +00:00
int CTimrman::StartHardTimer(uint32 timerId)
{
#ifdef _DEBUG
CLog::GetInstance().Print(LOG_NAME, FUNCTION_STARTHARDTIMER "(timerId = %d);\r\n",
2018-04-30 21:01:23 +01:00
timerId);
#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;
}