176 lines
3.9 KiB
C++
176 lines
3.9 KiB
C++
/******************************************************************************/
|
|
/* Mednafen NEC PC-FX Emulation Module */
|
|
/******************************************************************************/
|
|
/* timer.cpp:
|
|
** Copyright (C) 2006-2016 Mednafen Team
|
|
**
|
|
** This program is free software; you can redistribute it and/or
|
|
** modify it under the terms of the GNU General Public License
|
|
** as published by the Free Software Foundation; either version 2
|
|
** of the License, or (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/*
|
|
TODO: Determine if the interrupt request bit can be manually set even if timer enable and/or timer int enable bits are 0.
|
|
*/
|
|
|
|
|
|
#include "pcfx.h"
|
|
#include "interrupt.h"
|
|
#include "timer.h"
|
|
|
|
namespace MDFN_IEN_PCFX
|
|
{
|
|
|
|
static uint16 control;
|
|
static uint16 period;
|
|
static int32 counter;
|
|
|
|
static int32 lastts;
|
|
|
|
static INLINE v810_timestamp_t CalcNextEventTS(const v810_timestamp_t timestamp)
|
|
{
|
|
return((control & 0x2) ? (timestamp + counter) : PCFX_EVENT_NONONO);
|
|
}
|
|
|
|
#define EFF_PERIOD ((period ? period : 0x10000) * 15)
|
|
|
|
v810_timestamp_t FXTIMER_Update(const v810_timestamp_t timestamp)
|
|
{
|
|
if(control & 0x2)
|
|
{
|
|
int32 cycles = timestamp - lastts;
|
|
counter -= cycles;
|
|
while(counter <= 0)
|
|
{
|
|
counter += EFF_PERIOD;
|
|
if(control & 0x1)
|
|
{
|
|
control |= 0x4;
|
|
PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
lastts = timestamp;
|
|
|
|
return(CalcNextEventTS(timestamp));
|
|
}
|
|
|
|
void FXTIMER_ResetTS(int32 ts_base)
|
|
{
|
|
lastts = ts_base;
|
|
}
|
|
|
|
uint16 FXTIMER_Read16(uint32 A, const v810_timestamp_t timestamp)
|
|
{
|
|
FXTIMER_Update(timestamp);
|
|
switch(A & 0xFC0)
|
|
{
|
|
default: return(0);
|
|
|
|
case 0xF00: return(control);
|
|
|
|
case 0xF80: return(period);
|
|
|
|
case 0xFC0: return((counter + 14) / 15);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
uint8 FXTIMER_Read8(uint32 A, const v810_timestamp_t timestamp)
|
|
{
|
|
FXTIMER_Update(timestamp);
|
|
return(FXTIMER_Read16(A&~1, timestamp) >> ((A & 1) * 8));
|
|
}
|
|
|
|
void FXTIMER_Write16(uint32 A, uint16 V, const v810_timestamp_t timestamp)
|
|
{
|
|
FXTIMER_Update(timestamp);
|
|
|
|
switch(A & 0xFC0)
|
|
{
|
|
default: break;
|
|
|
|
case 0xF00: if(!(control & 0x2) && (V & 0x2))
|
|
counter = EFF_PERIOD;
|
|
control = V & 0x7;
|
|
|
|
if(V & 0x4)
|
|
FXDBG("Timer control write with D2 set?");
|
|
|
|
PCFXIRQ_Assert(PCFXIRQ_SOURCE_TIMER, (bool)(control & 0x4));
|
|
PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
|
|
break;
|
|
|
|
case 0xF80: period = V;
|
|
PCFX_SetEvent(PCFX_EVENT_TIMER, CalcNextEventTS(timestamp));
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32 FXTIMER_GetRegister(const unsigned int id, char *special, const uint32 special_len)
|
|
{
|
|
uint32 value = 0xDEADBEEF;
|
|
|
|
switch(id)
|
|
{
|
|
case FXTIMER_GSREG_TCTRL:
|
|
value = control;
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "Counting Enabled: %d, IRQ Enabled: %d, IRQ Asserted: %d", (int)(bool)(control & 2), (int)(bool)(control & 1), (int)(bool)(control & 4));
|
|
}
|
|
break;
|
|
|
|
case FXTIMER_GSREG_TPRD:
|
|
value = period;
|
|
if(special)
|
|
{
|
|
trio_snprintf(special, special_len, "Effective Period: %d; 21477272 / %d = %fHz", EFF_PERIOD, EFF_PERIOD, (double)21477272 / (EFF_PERIOD));
|
|
}
|
|
break;
|
|
|
|
case FXTIMER_GSREG_TCNTR:
|
|
value = counter;
|
|
if(special)
|
|
{
|
|
//trio_snprintf(buf, 256, "Pad: %d, ??: %d, Timer: %d, Reset: %d",
|
|
//*special = std::string(buf);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
void FXTIMER_SetRegister(const unsigned int id, uint32 value)
|
|
{
|
|
|
|
|
|
}
|
|
|
|
void FXTIMER_Reset(void)
|
|
{
|
|
control = 0;
|
|
period = 0;
|
|
counter = 0;
|
|
}
|
|
|
|
void FXTIMER_Init(void)
|
|
{
|
|
lastts = 0;
|
|
FXTIMER_Reset();
|
|
}
|
|
|
|
}
|