rtc: add leap year support (nw)

msm53821:

- add standard register support
- use std::array
- fix several counter to behave like a real MSM53821
This commit is contained in:
Sven Schnelle 2018-10-10 14:17:48 +02:00
parent 4c36a851f0
commit 7b48d52e94
3 changed files with 82 additions and 48 deletions

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause // license:BSD-3-Clause
// copyright-holders:Curt Coder // copyright-holders:Curt Coder,Sven Schnelle
/********************************************************************** /**********************************************************************
OKI MSM58321RS Real Time Clock/Calendar emulation OKI MSM58321RS Real Time Clock/Calendar emulation
@ -10,9 +10,7 @@
TODO: TODO:
- leap year - non gregorian leap year
- test
- reference registers
*/ */
@ -105,21 +103,13 @@ inline int msm58321_device::read_counter(int counter)
{ {
data += (h10 & 3) * 10; data += (h10 & 3) * 10;
} }
else if (h10 & H10_PM)
{
data += 12 + (h10 & 1) * 10;
}
else else
{ {
data += (h10 & 1) * 10; data += (h10 & 1) * 10;
if (h10 & H10_PM)
{
if (data != 12)
{
data += 12;
}
}
else if (data == 12)
{
data = 0;
}
} }
} }
else else
@ -139,8 +129,7 @@ inline void msm58321_device::write_counter(int address, int data)
{ {
int flag = 0; int flag = 0;
switch (address) switch (address) {
{
case REGISTER_H1: case REGISTER_H1:
flag = m_reg[REGISTER_H10] & H10_24; flag = m_reg[REGISTER_H10] & H10_24;
if (!flag) if (!flag)
@ -151,11 +140,9 @@ inline void msm58321_device::write_counter(int address, int data)
flag = H10_PM; flag = H10_PM;
} }
if (data == 0) if ((m_reg[REGISTER_H10] & H10_PM) && data == 0)
{
data = 12; data = 12;
} }
}
break; break;
case REGISTER_D1: case REGISTER_D1:
@ -200,9 +187,9 @@ msm58321_device::msm58321_device(const machine_config &mconfig, const char *tag,
m_stop(0), m_stop(0),
m_test(0), m_test(0),
m_cs1(0), m_cs1(0),
m_address(0xf) m_address(0xf),
m_reg{}
{ {
memset(m_reg, 0x00, sizeof(m_reg));
} }
@ -221,12 +208,16 @@ void msm58321_device::device_start()
// allocate timers // allocate timers
m_clock_timer = timer_alloc(TIMER_CLOCK); m_clock_timer = timer_alloc(TIMER_CLOCK);
m_clock_timer->adjust(clocks_to_attotime(32768), 0, clocks_to_attotime(32768)); m_clock_timer->adjust(clocks_to_attotime(32768/1024), 0, clocks_to_attotime(32768/1024));
// busy signal active period is approximately 427 µs // busy signal active period is approximately 427 µs
m_busy_timer = timer_alloc(TIMER_BUSY); m_busy_timer = timer_alloc(TIMER_BUSY);
m_busy_timer->adjust(clocks_to_attotime(32768 - 14), 0, clocks_to_attotime(32768)); m_busy_timer->adjust(clocks_to_attotime(32768 - 14), 0, clocks_to_attotime(32768));
// standard signal active period is approximately 122 µs
m_standard_timer = timer_alloc(TIMER_STANDARD);
m_standard_timer->adjust(clocks_to_attotime(32768-4), 0, clocks_to_attotime(32768));
// state saving // state saving
save_item(NAME(m_cs2)); save_item(NAME(m_cs2));
save_item(NAME(m_write)); save_item(NAME(m_write));
@ -258,13 +249,30 @@ void msm58321_device::device_timer(emu_timer &timer, device_timer_id id, int par
switch (id) switch (id)
{ {
case TIMER_CLOCK: case TIMER_CLOCK:
if (m_khz_ctr & 1)
{
m_reg[REGISTER_REF0] |= 1;
m_reg[REGISTER_REF1] |= 1;
} else {
m_reg[REGISTER_REF0] &= ~1;
m_reg[REGISTER_REF1] &= ~1;
}
if (++m_khz_ctr >= 1024)
{
m_khz_ctr = 0;
if (!m_stop) if (!m_stop)
{
advance_seconds(); advance_seconds();
}
if (!m_busy) if (!m_busy)
{ {
m_busy = 1; m_busy = 1;
m_busy_handler(m_busy); m_busy_handler(m_busy);
} }
}
break; break;
case TIMER_BUSY: case TIMER_BUSY:
@ -274,9 +282,29 @@ void msm58321_device::device_timer(emu_timer &timer, device_timer_id id, int par
m_busy_handler(m_busy); m_busy_handler(m_busy);
} }
break; break;
case TIMER_STANDARD:
m_reg[REGISTER_REF0] = 0x0e;
m_reg[REGISTER_REF1] = 0x0e;
break;
} }
} }
void msm58321_device::update_standard()
{
uint8_t reg = 0;
if (m_reg[REGISTER_S1] == 0)
reg |= 1 << 1;
if (m_reg[REGISTER_MI1] == 0)
reg |= 1 << 2;
if (m_reg[REGISTER_H1] == 0)
reg |= 1 << 3;
m_reg[REGISTER_REF0] = (reg ^ 0x0e) | (m_khz_ctr & 1);
m_reg[REGISTER_REF1] = m_reg[REGISTER_REF0];
}
//------------------------------------------------- //-------------------------------------------------
// rtc_clock_updated - // rtc_clock_updated -
@ -291,7 +319,7 @@ void msm58321_device::rtc_clock_updated(int year, int month, int day, int day_of
write_counter(REGISTER_H1, hour); write_counter(REGISTER_H1, hour);
write_counter(REGISTER_MI1, minute); write_counter(REGISTER_MI1, minute);
write_counter(REGISTER_S1, second); write_counter(REGISTER_S1, second);
update_standard();
update_output(); update_output();
} }
@ -319,7 +347,7 @@ void msm58321_device::nvram_default()
void msm58321_device::nvram_read(emu_file &file) void msm58321_device::nvram_read(emu_file &file)
{ {
file.read(m_reg, sizeof(m_reg)); file.read(m_reg.data(), m_reg.size());
clock_updated(); clock_updated();
} }
@ -332,7 +360,7 @@ void msm58321_device::nvram_read(emu_file &file)
void msm58321_device::nvram_write(emu_file &file) void msm58321_device::nvram_write(emu_file &file)
{ {
file.write(m_reg, sizeof(m_reg)); file.write(m_reg.data(), m_reg.size());
} }
//------------------------------------------------- //-------------------------------------------------
@ -350,13 +378,9 @@ void msm58321_device::update_output()
case REGISTER_RESET: case REGISTER_RESET:
data = 0; data = 0;
break; break;
case REGISTER_W:
case REGISTER_REF0: data = m_reg[m_address] - 1;
case REGISTER_REF1:
// TODO: output reference values
data = 0;
break; break;
default: default:
data = m_reg[m_address]; data = m_reg[m_address];
break; break;
@ -434,15 +458,17 @@ void msm58321_device::update_input()
default: default:
LOG("MSM58321 Register Write %s (%01x): %01x\n", reg_name(m_address), m_address, data); LOG("MSM58321 Register Write %s (%01x): %01x\n", reg_name(m_address), m_address, data);
m_khz_ctr = 0;
switch (m_address) switch (m_address)
{ {
case REGISTER_S10: case REGISTER_S10:
case REGISTER_MI10: case REGISTER_MI10:
case REGISTER_W:
m_reg[m_address] = data & 7; m_reg[m_address] = data & 7;
break; break;
case REGISTER_W:
m_reg[m_address] = (data & 7) + 1;
break;
case REGISTER_H10: case REGISTER_H10:
if (data & H10_24) if (data & H10_24)
{ {

View File

@ -114,14 +114,16 @@ protected:
virtual void nvram_default() override; virtual void nvram_default() override;
virtual void nvram_read(emu_file &file) override; virtual void nvram_read(emu_file &file) override;
virtual void nvram_write(emu_file &file) override; virtual void nvram_write(emu_file &file) override;
virtual bool rtc_feature_leap_year() const override { return true; }
private: private:
static const device_timer_id TIMER_CLOCK = 0; static constexpr device_timer_id TIMER_CLOCK = 0;
static const device_timer_id TIMER_BUSY = 1; static constexpr device_timer_id TIMER_BUSY = 1;
static constexpr device_timer_id TIMER_STANDARD = 2;
void update_input(); void update_input();
void update_output(); void update_output();
void update_standard();
inline int read_counter(int counter); inline int read_counter(int counter);
inline void write_counter(int counter, int value); inline void write_counter(int counter, int value);
@ -151,11 +153,14 @@ private:
int m_cs1; // chip select 1 int m_cs1; // chip select 1
uint8_t m_address; // address latch uint8_t m_address; // address latch
uint8_t m_reg[13]; // registers std::array<uint8_t, 16> m_reg; // registers
// timers // timers
emu_timer *m_clock_timer; emu_timer *m_clock_timer;
emu_timer *m_busy_timer; emu_timer *m_busy_timer;
emu_timer *m_standard_timer;
int m_khz_ctr;
}; };

View File

@ -195,11 +195,14 @@ void device_rtc_interface::advance_days()
m_register[RTC_DAY_OF_WEEK] = 1; m_register[RTC_DAY_OF_WEEK] = 1;
} }
if (m_register[RTC_DAY] > DAYS_PER_MONTH[m_register[RTC_MONTH] - 1]) if (m_register[RTC_MONTH] > 0 && m_register[RTC_DAY] > DAYS_PER_MONTH[m_register[RTC_MONTH] - 1])
{ {
if (m_register[RTC_MONTH] != 2 || m_register[RTC_DAY] != 29 || !rtc_feature_leap_year() ||
(m_register[RTC_YEAR] % 4) != 0) {
m_register[RTC_DAY] = 1; m_register[RTC_DAY] = 1;
m_register[RTC_MONTH]++; m_register[RTC_MONTH]++;
} }
}
if (m_register[RTC_MONTH] == 13) if (m_register[RTC_MONTH] == 13)
{ {