Imported uPD1990A RTC from MESS. (no whatsnew)

This commit is contained in:
Curt Coder 2011-03-30 18:36:47 +00:00
parent 9809123a38
commit 9ce28237de
4 changed files with 687 additions and 0 deletions

2
.gitattributes vendored
View File

@ -877,6 +877,8 @@ src/emu/machine/tmp68301.c svneol=native#text/plain
src/emu/machine/tmp68301.h svneol=native#text/plain src/emu/machine/tmp68301.h svneol=native#text/plain
src/emu/machine/tms6100.c svneol=native#text/plain src/emu/machine/tms6100.c svneol=native#text/plain
src/emu/machine/tms6100.h svneol=native#text/plain src/emu/machine/tms6100.h svneol=native#text/plain
src/emu/machine/upd1990a.c svneol=native#text/plain
src/emu/machine/upd1990a.h svneol=native#text/plain
src/emu/machine/upd4701.c svneol=native#text/plain src/emu/machine/upd4701.c svneol=native#text/plain
src/emu/machine/upd4701.h svneol=native#text/plain src/emu/machine/upd4701.h svneol=native#text/plain
src/emu/machine/wd33c93.c svneol=native#text/plain src/emu/machine/wd33c93.c svneol=native#text/plain

View File

@ -213,6 +213,7 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/timekpr.o \ $(EMUMACHINE)/timekpr.o \
$(EMUMACHINE)/tmp68301.o \ $(EMUMACHINE)/tmp68301.o \
$(EMUMACHINE)/tms6100.o \ $(EMUMACHINE)/tms6100.o \
$(EMUMACHINE)/upd1990a.o \
$(EMUMACHINE)/upd4701.o \ $(EMUMACHINE)/upd4701.o \
$(EMUMACHINE)/wd33c93.o \ $(EMUMACHINE)/wd33c93.o \
$(EMUMACHINE)/x2212.o \ $(EMUMACHINE)/x2212.o \

534
src/emu/machine/upd1990a.c Normal file
View File

@ -0,0 +1,534 @@
/**********************************************************************
NEC uPD1990AC Serial I/O Calendar & Clock emulation
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
/*
TODO:
- test mode
*/
#include "emu.h"
#include "upd1990a.h"
#include "machine/devhelpr.h"
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
#define LOG 0
// operating modes
enum
{
MODE_REGISTER_HOLD = 0,
MODE_SHIFT,
MODE_TIME_SET,
MODE_TIME_READ,
MODE_TP_64HZ_SET,
MODE_TP_256HZ_SET,
MODE_TP_2048HZ_SET,
MODE_TEST,
};
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// devices
const device_type UPD1990A = upd1990a_device_config::static_alloc_device_config;
//**************************************************************************
// DEVICE CONFIGURATION
//**************************************************************************
GENERIC_DEVICE_CONFIG_SETUP(upd1990a, "uPD1990A")
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void upd1990a_device_config::device_config_complete()
{
// inherit a copy of the static data
const upd1990a_interface *intf = reinterpret_cast<const upd1990a_interface *>(static_config());
if (intf != NULL)
*static_cast<upd1990a_interface *>(this) = *intf;
// or initialize to defaults if none provided
else
{
// memset(&in_pa_func, 0, sizeof(in_pa_func));
}
}
//**************************************************************************
// INLINE HELPERS
//**************************************************************************
//-------------------------------------------------
// convert_to_bcd -
//-------------------------------------------------
inline UINT8 upd1990a_device::convert_to_bcd(int val)
{
return ((val / 10) << 4) | (val % 10);
}
//-------------------------------------------------
// bcd_to_integer -
//-------------------------------------------------
inline int upd1990a_device::bcd_to_integer(UINT8 val)
{
return (((val & 0xf0) >> 4) * 10) + (val & 0x0f);
}
//-------------------------------------------------
// advance_seconds -
//-------------------------------------------------
inline void upd1990a_device::advance_seconds()
{
static const int days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int seconds = bcd_to_integer(m_time_counter[0]);
int minutes = bcd_to_integer(m_time_counter[1]);
int hours = bcd_to_integer(m_time_counter[2]);
int days = bcd_to_integer(m_time_counter[3]);
int day_of_week = m_time_counter[4] & 0x0f;
int month = (m_time_counter[4] & 0xf0) >> 4;
seconds++;
if (seconds > 59)
{
seconds = 0;
minutes++;
}
if (minutes > 59)
{
minutes = 0;
hours++;
}
if (hours > 23)
{
hours = 0;
days++;
day_of_week++;
}
if (day_of_week > 6)
{
day_of_week++;
}
if (days > days_per_month[month - 1])
{
days = 1;
month++;
}
if (month > 12)
{
month = 1;
}
m_time_counter[0] = convert_to_bcd(seconds);
m_time_counter[1] = convert_to_bcd(minutes);
m_time_counter[2] = convert_to_bcd(hours);
m_time_counter[3] = convert_to_bcd(days);
m_time_counter[4] = (month << 4) | day_of_week;
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// upd1990a_device - constructor
//-------------------------------------------------
upd1990a_device::upd1990a_device(running_machine &_machine, const upd1990a_device_config &config)
: device_t(_machine, config),
m_config(config)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void upd1990a_device::device_start()
{
// resolve callbacks
devcb_resolve_write_line(&m_out_data_func, &m_config.m_out_data_func, this);
devcb_resolve_write_line(&m_out_tp_func, &m_config.m_out_tp_func, this);
// allocate timers
m_timer_clock = timer_alloc(TIMER_CLOCK);
m_timer_clock->adjust(attotime::zero, 0, attotime::from_hz(1));
m_timer_tp = timer_alloc(TIMER_TP);
m_timer_data_out = timer_alloc(TIMER_DATA_OUT);
// state saving
save_item(NAME(m_time_counter));
save_item(NAME(m_shift_reg));
save_item(NAME(m_oe));
save_item(NAME(m_cs));
save_item(NAME(m_stb));
save_item(NAME(m_data_in));
save_item(NAME(m_data_out));
save_item(NAME(m_c));
save_item(NAME(m_clk));
save_item(NAME(m_tp));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void upd1990a_device::device_reset()
{
system_time curtime, *systime = &curtime;
machine().current_datetime(curtime);
// HACK: load time counter from system time
m_time_counter[0] = convert_to_bcd(systime->local_time.second);
m_time_counter[1] = convert_to_bcd(systime->local_time.minute);
m_time_counter[2] = convert_to_bcd(systime->local_time.hour);
m_time_counter[3] = convert_to_bcd(systime->local_time.mday);
m_time_counter[4] = systime->local_time.weekday;
m_time_counter[4] |= (systime->local_time.month + 1) << 4;
}
//-------------------------------------------------
// device_timer - handler timer events
//-------------------------------------------------
void upd1990a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_CLOCK:
advance_seconds();
break;
case TIMER_TP:
m_tp = !m_tp;
if (LOG) logerror("UPD1990A TP %u\n", m_tp);
devcb_call_write_line(&m_out_tp_func, m_tp);
break;
case TIMER_DATA_OUT:
m_data_out = !m_data_out;
if (LOG) logerror("UPD1990A DATA OUT TICK %u\n", m_data_out);
devcb_call_write_line(&m_out_data_func, m_data_out);
break;
}
}
//-------------------------------------------------
// oe_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::oe_w )
{
if (LOG) logerror("UPD1990A OE %u\n", state);
m_oe = state;
}
//-------------------------------------------------
// cs_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::cs_w )
{
if (LOG) logerror("UPD1990A CS %u\n", state);
m_cs = state;
}
//-------------------------------------------------
// stb_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::stb_w )
{
if (LOG) logerror("UPD1990A STB %u\n", state);
m_stb = state;
if (m_cs && m_stb && !m_clk)
{
switch (m_c)
{
case MODE_REGISTER_HOLD:
if (LOG) logerror("UPD1990A Register Hold Mode\n");
/* enable time counter */
m_timer_clock->enable(1);
/* 1 Hz data out pulse */
m_data_out = 1;
m_timer_data_out->adjust(attotime::zero, 0, attotime::from_hz(1*2));
/* 64 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(64*2));
break;
case MODE_SHIFT:
if (LOG) logerror("UPD1990A Shift Mode\n");
/* enable time counter */
m_timer_clock->enable(1);
/* disable data out pulse */
m_timer_data_out->enable(0);
/* output LSB of shift register */
m_data_out = BIT(m_shift_reg[0], 0);
devcb_call_write_line(&m_out_data_func, m_data_out);
/* 32 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(32*2));
break;
case MODE_TIME_SET:
{
int i;
if (LOG) logerror("UPD1990A Time Set Mode\n");
if (LOG) logerror("UPD1990A Shift Register %02x%02x%02x%02x%02x\n", m_shift_reg[4], m_shift_reg[3], m_shift_reg[2], m_shift_reg[1], m_shift_reg[0]);
/* disable time counter */
m_timer_clock->enable(0);
/* disable data out pulse */
m_timer_data_out->enable(0);
/* output LSB of shift register */
m_data_out = BIT(m_shift_reg[0], 0);
devcb_call_write_line(&m_out_data_func, m_data_out);
/* load shift register data into time counter */
for (i = 0; i < 5; i++)
{
m_time_counter[i] = m_shift_reg[i];
}
/* 32 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(32*2));
}
break;
case MODE_TIME_READ:
{
int i;
if (LOG) logerror("UPD1990A Time Read Mode\n");
/* enable time counter */
m_timer_clock->enable(1);
/* load time counter data into shift register */
for (i = 0; i < 5; i++)
{
m_shift_reg[i] = m_time_counter[i];
}
if (LOG) logerror("UPD1990A Shift Register %02x%02x%02x%02x%02x\n", m_shift_reg[4], m_shift_reg[3], m_shift_reg[2], m_shift_reg[1], m_shift_reg[0]);
/* 512 Hz data out pulse */
m_data_out = 1;
m_timer_data_out->adjust(attotime::zero, 0, attotime::from_hz(512*2));
/* 32 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(32*2));
}
break;
case MODE_TP_64HZ_SET:
if (LOG) logerror("UPD1990A TP = 64 Hz Set Mode\n");
/* 64 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(64*2));
break;
case MODE_TP_256HZ_SET:
if (LOG) logerror("UPD1990A TP = 256 Hz Set Mode\n");
/* 256 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(256*2));
break;
case MODE_TP_2048HZ_SET:
if (LOG) logerror("UPD1990A TP = 2048 Hz Set Mode\n");
/* 2048 Hz time pulse */
m_timer_tp->adjust(attotime::zero, 0, attotime::from_hz(2048*2));
break;
case MODE_TEST:
if (LOG) logerror("UPD1990A Test Mode not supported!\n");
if (m_oe)
{
/* time counter is advanced at 1024 Hz from "Second" counter input */
}
else
{
/* each counter is advanced at 1024 Hz in parallel, overflow carry does not affect next counter */
}
break;
}
}
}
//-------------------------------------------------
// clk_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::clk_w )
{
if (LOG) logerror("UPD1990A CLK %u\n", state);
if (!m_clk && state) // rising edge
{
if (m_c == MODE_SHIFT)
{
m_shift_reg[0] >>= 1;
m_shift_reg[0] |= (BIT(m_shift_reg[1], 0) << 7);
m_shift_reg[1] >>= 1;
m_shift_reg[1] |= (BIT(m_shift_reg[2], 0) << 7);
m_shift_reg[2] >>= 1;
m_shift_reg[2] |= (BIT(m_shift_reg[3], 0) << 7);
m_shift_reg[3] >>= 1;
m_shift_reg[3] |= (BIT(m_shift_reg[4], 0) << 7);
m_shift_reg[4] >>= 1;
m_shift_reg[4] |= (m_data_in << 7);
if (m_oe)
{
m_data_out = BIT(m_shift_reg[0], 0);
if (LOG) logerror("UPD1990A DATA OUT %u\n", m_data_out);
devcb_call_write_line(&m_out_data_func, m_data_out);
}
}
}
m_clk = state;
}
//-------------------------------------------------
// c0_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::c0_w )
{
if (LOG) logerror("UPD1990A C0 %u\n", state);
m_c = (m_c & 0x06) | state;
}
//-------------------------------------------------
// c1_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::c1_w )
{
if (LOG) logerror("UPD1990A C1 %u\n", state);
m_c = (m_c & 0x05) | (state << 1);
}
//-------------------------------------------------
// c2_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::c2_w )
{
if (LOG) logerror("UPD1990A C2 %u\n", state);
m_c = (m_c & 0x03) | (state << 2);
}
//-------------------------------------------------
// data_in_w -
//-------------------------------------------------
WRITE_LINE_MEMBER( upd1990a_device::data_in_w )
{
if (LOG) logerror("UPD1990A DATA IN %u\n", state);
m_data_in = state;
}
//-------------------------------------------------
// data_out_r -
//-------------------------------------------------
READ_LINE_MEMBER( upd1990a_device::data_out_r )
{
return m_data_out;
}
//-------------------------------------------------
// tp_r -
//-------------------------------------------------
READ_LINE_MEMBER( upd1990a_device::tp_r )
{
return m_tp;
}

150
src/emu/machine/upd1990a.h Normal file
View File

@ -0,0 +1,150 @@
/**********************************************************************
NEC uPD1990AC Serial I/O Calendar & Clock emulation
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************
_____ _____
C2 1 |* \_/ | 14 Vdd
C1 2 | | 13 XTAL
C0 3 | | 12 _XTAL
STB 4 | uPD1990AC | 11 OUT ENBL
CS 5 | | 10 TP
DATA IN 6 | | 9 DATA OUT
GND 7 |_____________| 8 CLK
**********************************************************************/
#pragma once
#ifndef __UPD1990A__
#define __UPD1990A__
#include "emu.h"
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_UPD1990A_ADD(_tag, _clock, _config) \
MCFG_DEVICE_ADD((_tag), UPD1990A, _clock) \
MCFG_DEVICE_CONFIG(_config)
#define UPD1990A_INTERFACE(name) \
const upd1990a_interface (name) =
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> upd1990a_interface
struct upd1990a_interface
{
devcb_write_line m_out_data_func;
devcb_write_line m_out_tp_func;
};
// ======================> upd1990a_device_config
class upd1990a_device_config : public device_config,
public upd1990a_interface
{
friend class upd1990a_device;
// construction/destruction
upd1990a_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
public:
// allocators
static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock);
virtual device_t *alloc_device(running_machine &machine) const;
protected:
// device_config overrides
virtual void device_config_complete();
};
// ======================> upd1990a_device
class upd1990a_device : public device_t
{
friend class upd1990a_device_config;
// construction/destruction
upd1990a_device(running_machine &_machine, const upd1990a_device_config &_config);
public:
DECLARE_WRITE_LINE_MEMBER( oe_w );
DECLARE_WRITE_LINE_MEMBER( cs_w );
DECLARE_WRITE_LINE_MEMBER( stb_w );
DECLARE_WRITE_LINE_MEMBER( clk_w );
DECLARE_WRITE_LINE_MEMBER( c0_w );
DECLARE_WRITE_LINE_MEMBER( c1_w );
DECLARE_WRITE_LINE_MEMBER( c2_w );
DECLARE_WRITE_LINE_MEMBER( data_in_w );
DECLARE_READ_LINE_MEMBER( data_out_r );
DECLARE_READ_LINE_MEMBER( tp_r );
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);
private:
inline UINT8 convert_to_bcd(int val);
inline int bcd_to_integer(UINT8 val);
inline void advance_seconds();
static const device_timer_id TIMER_CLOCK = 0;
static const device_timer_id TIMER_TP = 1;
static const device_timer_id TIMER_DATA_OUT = 2;
devcb_resolved_write_line m_out_data_func;
devcb_resolved_write_line m_out_tp_func;
UINT8 m_time_counter[5]; // time counter
UINT8 m_shift_reg[5]; // shift register
int m_oe; // output enable
int m_cs; // chip select
int m_stb; // strobe
int m_data_in; // data in
int m_data_out; // data out
int m_c; // command
int m_clk; // shift clock
int m_tp; // time pulse
// timers
emu_timer *m_timer_clock;
emu_timer *m_timer_tp;
emu_timer *m_timer_data_out;
const upd1990a_device_config &m_config;
};
// device type definition
extern const device_type UPD1990A;
#endif