diff options
Diffstat (limited to 'trunk/src/emu/machine/timekpr.c')
-rw-r--r-- | trunk/src/emu/machine/timekpr.c | 446 |
1 files changed, 446 insertions, 0 deletions
diff --git a/trunk/src/emu/machine/timekpr.c b/trunk/src/emu/machine/timekpr.c new file mode 100644 index 00000000000..eb7c9737d62 --- /dev/null +++ b/trunk/src/emu/machine/timekpr.c @@ -0,0 +1,446 @@ +/*************************************************************************** + + timekpr.h + + Various ST Microelectronics timekeeper SRAM implementations: + - M48T02 + - M48T35 + - M48T37 + - M48T58 + - MK48T08 + +***************************************************************************/ + +#include "emu.h" +#include "machine/timekpr.h" + + +// device type definition +const device_type M48T02 = &device_creator<m48t02_device>; +const device_type M48T35 = &device_creator<m48t35_device>; +const device_type M48T37 = &device_creator<m48t37_device>; +const device_type M48T58 = &device_creator<m48t58_device>; +const device_type MK48T08 = &device_creator<mk48t08_device>; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define MASK_SECONDS ( 0x7f ) +#define MASK_MINUTES ( 0x7f ) +#define MASK_HOURS ( 0x3f ) +#define MASK_DAY ( 0x07 ) +#define MASK_DATE ( 0x3f ) +#define MASK_MONTH ( 0x1f ) +#define MASK_YEAR ( 0xff ) +#define MASK_CENTURY ( 0xff ) + +#define CONTROL_W ( 0x80 ) +#define CONTROL_R ( 0x40 ) +#define CONTROL_S ( 0x20 ) /* not emulated */ +#define CONTROL_CALIBRATION ( 0x1f ) /* not emulated */ + +#define SECONDS_ST ( 0x80 ) + +#define DAY_FT ( 0x40 ) /* M48T37 - not emulated */ +#define DAY_CEB ( 0x20 ) /* M48T35/M48T58 */ +#define DAY_CB ( 0x10 ) /* M48T35/M48T58 */ + +#define DATE_BLE ( 0x80 ) /* M48T58: not emulated */ +#define DATE_BL ( 0x40 ) /* M48T58: not emulated */ + +#define FLAGS_BL ( 0x10 ) /* MK48T08/M48T37: not emulated */ +#define FLAGS_AF ( 0x40 ) /* M48T37: not emulated */ +#define FLAGS_WDF ( 0x80 ) /* M48T37: not emulated */ + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +INLINE UINT8 make_bcd(UINT8 data) +{ + return ( ( ( data / 10 ) % 10 ) << 4 ) + ( data % 10 ); +} + +INLINE UINT8 from_bcd( UINT8 data ) +{ + return ( ( ( data >> 4 ) & 15 ) * 10 ) + ( data & 15 ); +} + +static int inc_bcd( UINT8 *data, int mask, int min, int max ) +{ + int bcd; + int carry; + + bcd = ( *( data ) + 1 ) & mask; + carry = 0; + + if( ( bcd & 0x0f ) > 9 ) + { + bcd &= 0xf0; + bcd += 0x10; + if( bcd > max ) + { + bcd = min; + carry = 1; + } + } + + *( data ) = ( *( data ) & ~mask ) | ( bcd & mask ); + return carry; +} + +static void counter_to_ram( UINT8 *data, int offset, int counter ) +{ + if( offset >= 0 ) + { + data[ offset ] = counter; + } +} + +static int counter_from_ram( UINT8 *data, int offset ) +{ + if( offset >= 0 ) + { + return data[ offset ]; + } + return 0; +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// timekeeper_device_config - constructor +//------------------------------------------------- + +timekeeper_device::timekeeper_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, name, tag, owner, clock), + device_nvram_interface(mconfig, *this) +{ + +} + +m48t02_device::m48t02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T02, "M48T02", tag, owner, clock) +{ + m_offset_control = 0x7f8; + m_offset_seconds = 0x7f9; + m_offset_minutes = 0x7fa; + m_offset_hours = 0x7fb; + m_offset_day = 0x7fc; + m_offset_date = 0x7fd; + m_offset_month = 0x7fe; + m_offset_year = 0x7ff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x800; +} + +m48t35_device::m48t35_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T35, "M48T35", tag, owner, clock) +{ + m_offset_control = 0x7ff8; + m_offset_seconds = 0x7ff9; + m_offset_minutes = 0x7ffa; + m_offset_hours = 0x7ffb; + m_offset_day = 0x7ffc; + m_offset_date = 0x7ffd; + m_offset_month = 0x7ffe; + m_offset_year = 0x7fff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x8000; +} + +m48t37_device::m48t37_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T37, "M48T37", tag, owner, clock) +{ + m_offset_control = 0x7ff8; + m_offset_seconds = 0x7ff9; + m_offset_minutes = 0x7ffa; + m_offset_hours = 0x7ffb; + m_offset_day = 0x7ffc; + m_offset_date = 0x7ffd; + m_offset_month = 0x7ffe; + m_offset_year = 0x7fff; + m_offset_century = 0x7ff1; + m_offset_flags = 0x7ff0; + m_size = 0x8000; +} + +m48t58_device::m48t58_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, M48T58, "M48T58", tag, owner, clock) +{ + m_offset_control = 0x1ff8; + m_offset_seconds = 0x1ff9; + m_offset_minutes = 0x1ffa; + m_offset_hours = 0x1ffb; + m_offset_day = 0x1ffc; + m_offset_date = 0x1ffd; + m_offset_month = 0x1ffe; + m_offset_year = 0x1fff; + m_offset_century = -1; + m_offset_flags = -1; + m_size = 0x2000; +} + +mk48t08_device::mk48t08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : timekeeper_device(mconfig, MK48T08, "MK48T08", tag, owner, clock) +{ + m_offset_control = 0x1ff8; + m_offset_seconds = 0x1ff9; + m_offset_minutes = 0x1ffa; + m_offset_hours = 0x1ffb; + m_offset_day = 0x1ffc; + m_offset_date = 0x1ffd; + m_offset_month = 0x1ffe; + m_offset_year = 0x1fff; + m_offset_century = 0x1ff1; + m_offset_flags = 0x1ff0; + m_size = 0x2000; +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void timekeeper_device::device_start() +{ + system_time systime; + + /* validate some basic stuff */ + assert(this != NULL); + + machine().base_datetime(systime); + + m_control = 0; + m_seconds = make_bcd( systime.local_time.second ); + m_minutes = make_bcd( systime.local_time.minute ); + m_hours = make_bcd( systime.local_time.hour ); + m_day = make_bcd( systime.local_time.weekday + 1 ); + m_date = make_bcd( systime.local_time.mday ); + m_month = make_bcd( systime.local_time.month + 1 ); + m_year = make_bcd( systime.local_time.year % 100 ); + m_century = make_bcd( systime.local_time.year / 100 ); + m_data = auto_alloc_array( machine(), UINT8, m_size ); + + m_default_data = *region(); + if (m_default_data) + { + assert( region()->bytes() == m_size ); + } + + save_item( NAME(m_control) ); + save_item( NAME(m_seconds) ); + save_item( NAME(m_minutes) ); + save_item( NAME(m_hours) ); + save_item( NAME(m_day) ); + save_item( NAME(m_date) ); + save_item( NAME(m_month) ); + save_item( NAME(m_year) ); + save_item( NAME(m_century) ); + save_pointer( NAME(m_data), m_size ); + + emu_timer *timer = timer_alloc(); + timer->adjust(attotime::from_seconds(1), 0, attotime::from_seconds(1)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void timekeeper_device::device_reset() { } + +void timekeeper_device::counters_to_ram() +{ + counter_to_ram( m_data, m_offset_control, m_control ); + counter_to_ram( m_data, m_offset_seconds, m_seconds ); + counter_to_ram( m_data, m_offset_minutes, m_minutes ); + counter_to_ram( m_data, m_offset_hours, m_hours ); + counter_to_ram( m_data, m_offset_day, m_day ); + counter_to_ram( m_data, m_offset_date, m_date ); + counter_to_ram( m_data, m_offset_month, m_month ); + counter_to_ram( m_data, m_offset_year, m_year ); + counter_to_ram( m_data, m_offset_century, m_century ); +} + +void timekeeper_device::counters_from_ram() +{ + m_control = counter_from_ram( m_data, m_offset_control ); + m_seconds = counter_from_ram( m_data, m_offset_seconds ); + m_minutes = counter_from_ram( m_data, m_offset_minutes ); + m_hours = counter_from_ram( m_data, m_offset_hours ); + m_day = counter_from_ram( m_data, m_offset_day ); + m_date = counter_from_ram( m_data, m_offset_date ); + m_month = counter_from_ram( m_data, m_offset_month ); + m_year = counter_from_ram( m_data, m_offset_year ); + m_century = counter_from_ram( m_data, m_offset_century ); +} + +void timekeeper_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if( ( m_seconds & SECONDS_ST ) != 0 || + ( m_control & CONTROL_W ) != 0 ) + { + return; + } + + int carry = inc_bcd( &m_seconds, MASK_SECONDS, 0x00, 0x59 ); + if( carry ) + { + carry = inc_bcd( &m_minutes, MASK_MINUTES, 0x00, 0x59 ); + } + if( carry ) + { + carry = inc_bcd( &m_hours, MASK_HOURS, 0x00, 0x23 ); + } + + if( carry ) + { + UINT8 maxdays; + static const UINT8 daysinmonth[] = { 0x31, 0x28, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31 }; + + inc_bcd( &m_day, MASK_DAY, 0x01, 0x07 ); + + UINT8 month = from_bcd( m_month ); + UINT8 year = from_bcd( m_year ); + + if( month == 2 && ( year % 4 ) == 0 ) + { + maxdays = 0x29; + } + else if( month >= 1 && month <= 12 ) + { + maxdays = daysinmonth[ month - 1 ]; + } + else + { + maxdays = 0x31; + } + + carry = inc_bcd( &m_date, MASK_DATE, 0x01, maxdays ); + } + if( carry ) + { + carry = inc_bcd( &m_month, MASK_MONTH, 0x01, 0x12 ); + } + if( carry ) + { + carry = inc_bcd( &m_year, MASK_YEAR, 0x00, 0x99 ); + } + if( carry ) + { + carry = inc_bcd( &m_century, MASK_CENTURY, 0x00, 0x99 ); + + if( type() == M48T35 || + type() == M48T58 ) + { + if( ( m_day & DAY_CEB ) != 0 ) + { + m_day ^= DAY_CB; + } + } + } + + if( ( m_control & CONTROL_R ) == 0 ) + { + counters_to_ram(); + } +} + +void timekeeper_device::write(UINT16 offset, UINT8 data) +{ + if( offset == m_offset_control ) + { + if( ( m_control & CONTROL_W ) != 0 && + ( data & CONTROL_W ) == 0 ) + { + counters_from_ram(); + } + m_control = data; + } + else if( offset == m_offset_day ) + { + if( type() == M48T35 || + type() == M48T58 ) + { + m_day = ( m_day & ~DAY_CEB ) | ( data & DAY_CEB ); + } + } + + m_data[ offset ] = data; +} + +UINT8 timekeeper_device::read(UINT16 offset) +{ + UINT8 result = m_data[ offset ]; + if( offset == m_offset_date && type() == M48T58 ) + { + result &= ~DATE_BL; + } + else if( offset == m_offset_flags && (type() == MK48T08 || type() == M48T37) ) + { + result = 0; + } + return result; +} + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void timekeeper_device::nvram_default() +{ + if( m_default_data != NULL ) + { + memcpy( m_data, m_default_data, m_size ); + } + else + { + memset( m_data, 0xff, m_size ); + } + + if ( m_offset_flags >= 0 ) + m_data[ m_offset_flags ] = 0; + counters_to_ram(); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void timekeeper_device::nvram_read(emu_file &file) +{ + file.read( m_data, m_size ); + + counters_to_ram(); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void timekeeper_device::nvram_write(emu_file &file) +{ + file.write( m_data, m_size ); +} + + + +/*************************************************************************** + TRAMPOLINES +***************************************************************************/ + +WRITE8_DEVICE_HANDLER( timekeeper_w ) { downcast<timekeeper_device *>(device)->write(offset, data); } +READ8_DEVICE_HANDLER( timekeeper_r ) { return downcast<timekeeper_device*>(device)->read(offset); } + |