Made Epson R4543 RTC a proper RTC device, eliminates duplicated code in Namco Systems 12 and 23 [R. Belmont]

This commit is contained in:
R. Belmont 2012-09-23 03:37:54 +00:00
parent ba5468b246
commit 449d8c260a
6 changed files with 298 additions and 92 deletions

2
.gitattributes vendored
View File

@ -1178,6 +1178,8 @@ src/emu/machine/rp5c15.c svneol=native#text/plain
src/emu/machine/rp5c15.h svneol=native#text/plain
src/emu/machine/rp5h01.c svneol=native#text/plain
src/emu/machine/rp5h01.h svneol=native#text/plain
src/emu/machine/rtc4543.c svneol=native#text/plain
src/emu/machine/rtc4543.h svneol=native#text/plain
src/emu/machine/rtc65271.c svneol=native#text/plain
src/emu/machine/rtc65271.h svneol=native#text/plain
src/emu/machine/rtc9701.c svneol=native#text/plain

View File

@ -239,6 +239,7 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/rp5c01.o \
$(EMUMACHINE)/rp5c15.o \
$(EMUMACHINE)/rp5h01.o \
$(EMUMACHINE)/rtc4543.o \
$(EMUMACHINE)/rtc65271.o \
$(EMUMACHINE)/rtc9701.o \
$(EMUMACHINE)/s3c2400.o \

191
src/emu/machine/rtc4543.c Normal file
View File

@ -0,0 +1,191 @@
/**********************************************************************
rtc4543.c - Epson R4543 real-time clock chip emulation
by R. Belmont
TODO: writing (not done by System 12 or 23 so no test case)
**********************************************************************/
#include "rtc4543.h"
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
#define VERBOSE 0
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
// device type definition
const device_type RTC4543 = &device_creator<rtc4543_device>;
//-------------------------------------------------
// rtc4543_device - constructor
//-------------------------------------------------
rtc4543_device::rtc4543_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, RTC4543, "Epson R4543", tag, owner, clock),
device_rtc_interface(mconfig, *this)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void rtc4543_device::device_start()
{
// allocate timers
m_clock_timer = timer_alloc();
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
// state saving
save_item(NAME(m_ce));
save_item(NAME(m_clk));
save_item(NAME(m_wr));
save_item(NAME(m_data));
save_item(NAME(m_regs));
save_item(NAME(m_curreg));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void rtc4543_device::device_reset()
{
set_current_time(machine());
m_ce = 0;
m_wr = 0;
m_clk = 0;
m_data = 0;
m_curreg = 0;
}
//-------------------------------------------------
// device_timer - handler timer events
//-------------------------------------------------
void rtc4543_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
advance_seconds();
}
INLINE UINT8 make_bcd(UINT8 data)
{
return ((data / 10) << 4) | (data % 10);
}
//-------------------------------------------------
// rtc_clock_updated -
//-------------------------------------------------
void rtc4543_device::rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second)
{
static const int weekday[7] = { 7, 1, 2, 3, 4, 5, 6 };
m_regs[0] = make_bcd(second); // seconds (BCD, 0-59) in bits 0-6, bit 7 = battery low
m_regs[1] = make_bcd(minute); // minutes (BCD, 0-59)
m_regs[2] = make_bcd(hour); // hour (BCD, 0-23)
m_regs[3] = make_bcd(weekday[day_of_week]); // low nibble = day of the week
m_regs[3] |= (make_bcd(day) & 0x0f)<<4; // high nibble = low digit of day
m_regs[4] = (make_bcd(day) >> 4); // low nibble = high digit of day
m_regs[4] |= (make_bcd(month & 0x0f)<<4); // high nibble = low digit of month
m_regs[5] = make_bcd(month & 0x0f) >> 4; // low nibble = high digit of month
m_regs[5] |= (make_bcd(year % 10) << 4); // high nibble = low digit of year
m_regs[6] = make_bcd(year % 100) >> 4; // low nibble = tens digit of year (BCD, 0-9)
}
//-------------------------------------------------
// ce_w - chip enable write
//-------------------------------------------------
WRITE_LINE_MEMBER( rtc4543_device::ce_w )
{
if (VERBOSE) printf("RTC4543 '%s' CE: %u\n", tag(), state);
if (!state && m_ce) // complete transfer
{
}
else if (state && !m_ce) // start new data transfer
{
m_curreg = 0;
m_bit = 8; // force immediate reload of output data
}
m_ce = state;
}
//-------------------------------------------------
// wr_w - data direction line write
//-------------------------------------------------
WRITE_LINE_MEMBER( rtc4543_device::wr_w )
{
if (VERBOSE) logerror("RTC4543 '%s' WR: %u\n", tag(), state);
m_wr = state;
}
//-------------------------------------------------
// clk_w - serial clock write
//-------------------------------------------------
WRITE_LINE_MEMBER( rtc4543_device::clk_w )
{
if (VERBOSE) logerror("RTC4543 '%s' CLK: %u\n", tag(), state);
if (!m_ce) return;
if (!m_clk && state) // rising edge - read data becomes valid here
{
if (m_bit > 7) // reload data?
{
m_bit = 0;
m_data = m_regs[m_curreg++];
}
else // no reload, just continue with the current byte
{
m_data <<= 1;
}
m_bit++;
}
else if (m_clk && !state) // falling edge - write data becomes valid here
{
}
m_clk = state;
}
//-------------------------------------------------
// data_w - I/O write
//-------------------------------------------------
WRITE_LINE_MEMBER( rtc4543_device::data_w )
{
if (VERBOSE) logerror("RTC4543 '%s' I/O: %u\n", tag(), state);
m_data |= (state & 1);
}
//-------------------------------------------------
// data_r - I/O read
//-------------------------------------------------
READ_LINE_MEMBER( rtc4543_device::data_r )
{
return (m_data & 0x80) ? 1 : 0;
}

72
src/emu/machine/rtc4543.h Normal file
View File

@ -0,0 +1,72 @@
/**********************************************************************
rtc4543.h - Epson R4543 real-time clock emulation
by R. Belmont
**********************************************************************/
#pragma once
#ifndef __RTC4543_H__
#define __RTC4543_H__
#include "emu.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_RTC4543_ADD(_tag, _clock) \
MCFG_DEVICE_ADD(_tag, RTC4543, _clock)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> rtc4543_device
class rtc4543_device : public device_t,
public device_rtc_interface
{
public:
// construction/destruction
rtc4543_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
DECLARE_WRITE_LINE_MEMBER( ce_w );
DECLARE_WRITE_LINE_MEMBER( wr_w );
DECLARE_WRITE_LINE_MEMBER( clk_w );
DECLARE_READ_LINE_MEMBER( data_r );
DECLARE_WRITE_LINE_MEMBER( data_w );
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
// device_rtc_interface overrides
virtual void rtc_clock_updated(int year, int month, int day, int day_of_week, int hour, int minute, int second);
virtual bool rtc_feature_leap_year() { return true; }
private:
int m_ce;
int m_clk;
int m_wr;
int m_data;
int m_regs[7];
int m_curreg;
int m_bit;
// timers
emu_timer *m_clock_timer;
};
// device type definition
extern const device_type RTC4543;
#endif

View File

@ -1039,6 +1039,7 @@ Notes:
#include "includes/psx.h"
#include "machine/at28c16.h"
#include "sound/c352.h"
#include "machine/rtc4543.h"
#define VERBOSE_LEVEL ( 0 )
@ -1047,8 +1048,10 @@ class namcos12_state : public psx_state
public:
namcos12_state(const machine_config &mconfig, device_type type, const char *tag)
: psx_state(mconfig, type, tag),
m_rtc(*this, "rtc"),
m_sharedram(*this, "sharedram") { }
required_device<rtc4543_device> m_rtc;
required_shared_ptr<UINT32> m_sharedram;
UINT32 m_n_bankoffset;
@ -1467,59 +1470,21 @@ READ8_MEMBER(namcos12_state::s12_mcu_pa_r)
WRITE8_MEMBER(namcos12_state::s12_mcu_pa_w)
{
// bit 0 = chip enable for the RTC
// reset the state on the rising edge of the bit
if ((!(m_s12_porta & 1)) && (data & 1))
{
m_s12_rtcstate = 0;
}
m_rtc->ce_w(data & 1);
m_s12_porta = data;
}
INLINE UINT8 make_bcd(UINT8 data)
{
return ((data / 10) << 4) | (data % 10);
}
READ8_MEMBER(namcos12_state::s12_mcu_rtc_r)
{
UINT8 ret = 0;
system_time systime;
static const int weekday[7] = { 7, 1, 2, 3, 4, 5, 6 };
UINT8 ret = 0;
machine().current_datetime(systime);
switch (m_s12_rtcstate)
{
case 0:
ret = make_bcd(systime.local_time.second); // seconds (BCD, 0-59) in bits 0-6, bit 7 = battery low
break;
case 1:
ret = make_bcd(systime.local_time.minute); // minutes (BCD, 0-59)
break;
case 2:
ret = make_bcd(systime.local_time.hour); // hour (BCD, 0-23)
break;
case 3:
ret = make_bcd(weekday[systime.local_time.weekday]); // low nibble = day of the week
ret |= (make_bcd(systime.local_time.mday) & 0x0f)<<4; // high nibble = low digit of day
break;
case 4:
ret = (make_bcd(systime.local_time.mday) >> 4); // low nibble = high digit of day
ret |= (make_bcd(systime.local_time.month + 1) & 0x0f)<<4; // high nibble = low digit of month
break;
case 5:
ret = make_bcd(systime.local_time.month + 1) >> 4; // low nibble = high digit of month
ret |= (make_bcd(systime.local_time.year % 10) << 4); // high nibble = low digit of year
break;
case 6:
ret = make_bcd(systime.local_time.year % 100) >> 4; // low nibble = tens digit of year (BCD, 0-9)
break;
}
m_s12_rtcstate++;
for (int i = 0; i < 8; i++)
{
m_rtc->clk_w(0);
m_rtc->clk_w(1);
ret <<= 1;
ret |= m_rtc->data_r();
}
return ret;
}
@ -1682,6 +1647,8 @@ static MACHINE_CONFIG_START( coh700, namcos12_state )
MCFG_MACHINE_RESET_OVERRIDE(namcos12_state, namcos12 )
MCFG_RTC4543_ADD("rtc", XTAL_32_768kHz)
/* video hardware */
MCFG_PSXGPU_ADD( "maincpu", "gpu", CXD8654Q, 0x200000, XTAL_53_693175MHz )
MCFG_PSXGPU_VBLANK_CALLBACK( vblank_state_delegate( FUNC( namcos12_sub_irq ), (namcos12_state *) owner ) )

View File

@ -1228,6 +1228,7 @@ Notes:
#include "cpu/sh2/sh2.h"
#include "sound/c352.h"
#include "machine/nvram.h"
#include "machine/rtc4543.h"
#define S23_BUSCLOCK (66664460/2) /* 33MHz CPU bus clock / input, somehow derived from 14.31721 MHz crystal */
#define S23_H8CLOCK (14745600)
@ -1320,6 +1321,7 @@ class namcos23_state : public driver_device
public:
namcos23_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag) ,
m_rtc(*this, "rtc"),
m_shared_ram(*this, "shared_ram"),
m_charram(*this, "charram"),
m_textram(*this, "textram"),
@ -1333,6 +1335,7 @@ public:
render_t m_render;
tilemap_t *m_bgtilemap;
required_device<rtc4543_device> m_rtc;
required_shared_ptr<UINT32> m_shared_ram;
required_shared_ptr<UINT32> m_charram;
required_shared_ptr<UINT32> m_textram;
@ -2610,57 +2613,21 @@ READ8_MEMBER(namcos23_state::s23_mcu_pa_r)
WRITE8_MEMBER(namcos23_state::s23_mcu_pa_w)
{
// bit 0 = chip enable for the RTC
// reset the state on the rising edge of the bit
if ((!(m_s23_porta & 1)) && (data & 1))
{
m_s23_rtcstate = 0;
}
m_rtc->ce_w(data & 1);
m_s23_porta = data;
}
INLINE UINT8 make_bcd(UINT8 data)
{
return ((data / 10) << 4) | (data % 10);
}
READ8_MEMBER(namcos23_state::s23_mcu_rtc_r)
{
UINT8 ret = 0;
system_time systime;
static const int weekday[7] = { 7, 1, 2, 3, 4, 5, 6 };
UINT8 ret = 0;
machine().current_datetime(systime);
switch (m_s23_rtcstate)
{
case 0:
ret = make_bcd(systime.local_time.second); // seconds (BCD, 0-59) in bits 0-6, bit 7 = battery low
break;
case 1:
ret = make_bcd(systime.local_time.minute); // minutes (BCD, 0-59)
break;
case 2:
ret = make_bcd(systime.local_time.hour); // hour (BCD, 0-23)
break;
case 3:
ret = make_bcd(weekday[systime.local_time.weekday]); // low nibble = day of the week
ret |= (make_bcd(systime.local_time.mday) & 0x0f)<<4; // high nibble = low digit of day
break;
case 4:
ret = (make_bcd(systime.local_time.mday) >> 4); // low nibble = high digit of day
ret |= (make_bcd(systime.local_time.month + 1) & 0x0f)<<4; // high nibble = low digit of month
break;
case 5:
ret = make_bcd(systime.local_time.month + 1) >> 4; // low nibble = high digit of month
ret |= (make_bcd(systime.local_time.year % 10) << 4); // high nibble = low digit of year
break;
case 6:
ret = make_bcd(systime.local_time.year % 100) >> 4; // low nibble = tens digit of year (BCD, 0-9)
break;
}
m_s23_rtcstate++;
for (int i = 0; i < 8; i++)
{
m_rtc->clk_w(0);
m_rtc->clk_w(1);
ret <<= 1;
ret |= m_rtc->data_r();
}
return ret;
}
@ -3161,6 +3128,8 @@ static MACHINE_CONFIG_START( gorgon, namcos23_state )
MCFG_QUANTUM_TIME(attotime::from_hz(60000))
MCFG_RTC4543_ADD("rtc", XTAL_32_768kHz)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(S23_VSYNC1)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // Not in any way accurate
@ -3206,6 +3175,8 @@ static MACHINE_CONFIG_START( s23, namcos23_state )
MCFG_QUANTUM_TIME(attotime::from_hz(60000))
MCFG_RTC4543_ADD("rtc", XTAL_32_768kHz)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(S23_VSYNC1)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // Not in any way accurate
@ -3247,6 +3218,8 @@ static MACHINE_CONFIG_START( ss23, namcos23_state )
MCFG_QUANTUM_TIME(attotime::from_hz(60000))
MCFG_RTC4543_ADD("rtc", XTAL_32_768kHz)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(S23_VSYNC1)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) // Not in any way accurate