diff --git a/.gitattributes b/.gitattributes index e931f7f626e..7deabafbf78 100644 --- a/.gitattributes +++ b/.gitattributes @@ -837,6 +837,8 @@ src/emu/machine/mc6852.c svneol=native#text/plain src/emu/machine/mc6852.h svneol=native#text/plain src/emu/machine/mc68901.c svneol=native#text/plain src/emu/machine/mc68901.h svneol=native#text/plain +src/emu/machine/mccs1850.c svneol=native#text/plain +src/emu/machine/mccs1850.h svneol=native#text/plain src/emu/machine/microtch.c svneol=native#text/plain src/emu/machine/microtch.h svneol=native#text/plain src/emu/machine/mm74c922.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index c4803e44f75..0637fc69f5e 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -194,6 +194,7 @@ EMUMACHINEOBJS = \ $(EMUMACHINE)/mc146818.o \ $(EMUMACHINE)/mc6852.o \ $(EMUMACHINE)/mc68901.o \ + $(EMUMACHINE)/mccs1850.o \ $(EMUMACHINE)/mm74c922.o \ $(EMUMACHINE)/microtch.o \ $(EMUMACHINE)/mos6529.o \ diff --git a/src/emu/machine/mccs1850.c b/src/emu/machine/mccs1850.c new file mode 100644 index 00000000000..b2848654c68 --- /dev/null +++ b/src/emu/machine/mccs1850.c @@ -0,0 +1,584 @@ +/********************************************************************** + + Motorola MCCS1850 Serial Real-Time Clock emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +*********************************************************************/ + +/* + + TODO: + + - auto restart + - test mode + +*/ + +#include "mccs1850.h" + + + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +#define LOG 0 + + +#define RAM_SIZE 0x80 + + +// serial state +enum +{ + STATE_ADDRESS, + STATE_DATA +}; + + +// registers +enum +{ + REGISTER_COUNTER_LATCH = 0x20, + REGISTER_ALARM_LATCH = 0x24, + REGISTER_STATUS = 0x30, + REGISTER_CONTROL = 0x31, + REGISTER_TEST_1 = 0x3e, + REGISTER_TEST_2 = 0x3f, + REGISTER_TEST_KICK_START_COUNTER = 0x40, + REGISTER_TEST_PRESCALE_COUNTER = 0x43, + REGISTER_TEST_COUNTER_INCREMENT = 0x4f +}; + + +// clock status/interrupt register +#define STATUS_TM 0x20 // test mode +#define STATUS_FTU 0x10 // first time up +#define STATUS_IT 0x08 // interrupt true +#define STATUS_LB 0x04 // low battery +#define STATUS_AI 0x02 // alarm +#define STATUS_RPD 0x01 // request to power down + + +// clock control register +#define CONTROL_STR_STP 0x80 // start/stop +#define CONTROL_PD 0x40 // power down +#define CONTROL_AR 0x20 // auto restart +#define CONTROL_AE 0x10 // alarm enable +#define CONTROL_AC 0x08 // alarm clear +#define CONTROL_FTUC 0x04 // first time up clear +#define CONTROL_LBE 0x02 // low battery enable +#define CONTROL_RPCD 0x01 // request to power down clear + + +// test register 1 +#define TEST1_DIV1 0x80 // divide by 1 +#define TEST1_VOVR 0x40 // Vdd override +#define TEST1_VDDUP 0x20 // Vdd up +#define TEST1_VDDON 0x10 // Vdd on +#define TEST1_VRT 0x08 // valid RAM and time +#define TEST1_LOW_BAT 0x08 // low battery +#define TEST1_PCC 0x04 // programmable capacitor C (10.0 pF) +#define TEST1_PCB 0x02 // programmable capacitor B (5.0 pF) +#define TEST1_PCA 0x01 // programmable capacitor A (2.5 pF) + + +// test register 2 +#define TEST2_OSCBY 0x80 // oscillator bypass +#define TEST2_COMPOVR 0x40 // comparator override +#define TEST2_POR 0x20 // power on reset +#define TEST2_SELTCK 0x10 // select test clock +#define TEST2_FRZ 0x08 // freeze mode +#define TEST2_DV_MASK 0x07 // divider bits select + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +const device_type MCCS1850 = &device_creator; + + + +//************************************************************************** +// INLINE HELPERS +//************************************************************************** + +//------------------------------------------------- +// check_interrupt - +//------------------------------------------------- + +inline void mccs1850_device::check_interrupt() +{ + UINT8 status = m_ram[REGISTER_STATUS]; + UINT8 control = m_ram[REGISTER_CONTROL]; + + bool interrupt = (((status & STATUS_AI) && (control & CONTROL_AE)) // alarm interrupt + || ((status & STATUS_LB) && (control & CONTROL_LBE)) // low battery + || (status & STATUS_FTU) // first time up + || (status & STATUS_RPD)); // request to power down + + if (interrupt) + { + m_ram[REGISTER_STATUS] |= STATUS_IT; + } + else + { + m_ram[REGISTER_STATUS] &= ~STATUS_IT; + } + + devcb_call_write_line(&m_out_int_func, interrupt ? ASSERT_LINE : CLEAR_LINE); +} + + +//------------------------------------------------- +// set_pse_line - +//------------------------------------------------- + +inline void mccs1850_device::set_pse_line(int state) +{ + m_pse = state; + + devcb_call_write_line(&m_out_pse_func, m_pse); +} + + +//------------------------------------------------- +// read_register - +//------------------------------------------------- + +inline UINT8 mccs1850_device::read_register(offs_t offset) +{ + switch (offset) + { + case REGISTER_COUNTER_LATCH: + // load counter value into latch + m_ram[REGISTER_COUNTER_LATCH] = m_counter >> 24; + m_ram[REGISTER_COUNTER_LATCH + 1] = m_counter >> 16; + m_ram[REGISTER_COUNTER_LATCH + 2] = m_counter >> 8; + m_ram[REGISTER_COUNTER_LATCH + 3] = m_counter; + break; + + case REGISTER_TEST_1: + case REGISTER_TEST_2: + case REGISTER_TEST_KICK_START_COUNTER: + case REGISTER_TEST_PRESCALE_COUNTER: + case REGISTER_TEST_COUNTER_INCREMENT: + logerror("MCCS1850 '%s' Unsupported read from test register %02x!\n", tag(), offset); + break; + } + + return m_ram[offset]; +} + + +//------------------------------------------------- +// write_register - +//------------------------------------------------- + +inline void mccs1850_device::write_register(offs_t offset, UINT8 data) +{ + switch (offset) + { + case REGISTER_STATUS: + // read only + break; + + case REGISTER_CONTROL: + if (LOG) logerror("MCCS1850 '%s' Counter %s\n", tag(), (data & CONTROL_STR_STP) ? "Start" : "Stop"); + m_clock_timer->enable(data & CONTROL_STR_STP); + + if (data & CONTROL_PD) + { + if (LOG) logerror("MCCS1850 '%s' Power Down\n", tag()); + set_pse_line(0); + } + + if (data & CONTROL_AR) + { + if (LOG) logerror("MCCS1850 '%s' Auto Restart\n", tag()); + } + + if (data & CONTROL_AC) + { + if (LOG) logerror("MCCS1850 '%s' Alarm Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_AI; + } + + if (data & CONTROL_FTUC) + { + if (LOG) logerror("MCCS1850 '%s' First Time Up Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_FTU; + } + + if (data & CONTROL_RPCD) + { + if (LOG) logerror("MCCS1850 '%s' Request to Power Down Clear\n", tag()); + m_ram[REGISTER_STATUS] &= ~STATUS_RPD; + } + + m_ram[REGISTER_CONTROL] = data & 0xb2; + + check_interrupt(); + break; + + case REGISTER_TEST_1: + case REGISTER_TEST_2: + case REGISTER_TEST_KICK_START_COUNTER: + case REGISTER_TEST_PRESCALE_COUNTER: + case REGISTER_TEST_COUNTER_INCREMENT: + logerror("MCCS1850 '%s' Unsupported write to test register %02x!\n", tag(), offset); + break; + + default: + m_ram[offset] = data; + } +} + + +//------------------------------------------------- +// advance_seconds - +//------------------------------------------------- + +inline void mccs1850_device::advance_seconds() +{ + UINT32 alarm = (m_ram[REGISTER_ALARM_LATCH] << 24) | (m_ram[REGISTER_ALARM_LATCH + 1] << 16) | (m_ram[REGISTER_ALARM_LATCH + 2] << 8) | m_ram[REGISTER_ALARM_LATCH + 3]; + + m_counter++; + + if (m_counter == alarm) + { + if (m_pse) + { + // trigger alarm + m_ram[REGISTER_STATUS] |= STATUS_AI; + + check_interrupt(); + } + else + { + // wake up + set_pse_line(1); + } + } +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// mccs1850_device - constructor +//------------------------------------------------- + +mccs1850_device::mccs1850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, MCCS1850, "MCCS1850", tag, owner, clock), + device_rtc_interface(mconfig, *this), + device_nvram_interface(mconfig, *this), + m_pse(1), + m_ce(0), + m_sck(0), + m_sdo(0), + m_sdi(0), + m_state(STATE_ADDRESS), + m_bits(0) +{ +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void mccs1850_device::device_config_complete() +{ + // inherit a copy of the static data + const mccs1850_interface *intf = reinterpret_cast(static_config()); + if (intf != NULL) + *static_cast(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_out_int_cb, 0, sizeof(m_out_int_cb)); + memset(&m_out_pse_cb, 0, sizeof(m_out_pse_cb)); + memset(&m_out_nuc_cb, 0, sizeof(m_out_nuc_cb)); + } +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void mccs1850_device::device_start() +{ + // resolve callbacks + devcb_resolve_write_line(&m_out_int_func, &m_out_int_cb, this); + devcb_resolve_write_line(&m_out_pse_func, &m_out_pse_cb, this); + devcb_resolve_write_line(&m_out_nuc_func, &m_out_nuc_cb, this); + + // allocate timers + m_clock_timer = timer_alloc(TIMER_CLOCK); + m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); + + // state saving + save_item(NAME(m_pse)); + save_item(NAME(m_counter)); + save_item(NAME(m_ce)); + save_item(NAME(m_sck)); + save_item(NAME(m_sdo)); + save_item(NAME(m_sdi)); + save_item(NAME(m_state)); + save_item(NAME(m_address)); + save_item(NAME(m_bits)); + save_item(NAME(m_shift)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void mccs1850_device::device_reset() +{ + memset(m_ram, 0xff, RAM_SIZE); + + m_ram[REGISTER_STATUS] = 0x80 | STATUS_FTU; + m_ram[REGISTER_CONTROL] = 0x00; +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void mccs1850_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TIMER_CLOCK: + advance_seconds(); + break; + } +} + + +//------------------------------------------------- +// rtc_set_time - called to initialize the RTC to +// a known state +//------------------------------------------------- + +void mccs1850_device::rtc_set_time(int year, int month, int day, int day_of_week, int hour, int minute, int second) +{ +} + + +//------------------------------------------------- +// nvram_default - called to initialize NVRAM to +// its default state +//------------------------------------------------- + +void mccs1850_device::nvram_default() +{ + memset(m_ram, 0xff, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_read - called to read NVRAM from the +// .nv file +//------------------------------------------------- + +void mccs1850_device::nvram_read(emu_file &file) +{ + file.read(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// nvram_write - called to write NVRAM to the +// .nv file +//------------------------------------------------- + +void mccs1850_device::nvram_write(emu_file &file) +{ + file.write(m_ram, RAM_SIZE); +} + + +//------------------------------------------------- +// ce_w - chip enable write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::ce_w ) +{ + m_ce = state; + + if (!m_ce) + { + m_state = STATE_ADDRESS; + m_bits = 0; + } +} + + +//------------------------------------------------- +// sck_w - serial clock write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::sck_w ) +{ + if (!m_ce) return; + + switch (m_state) + { + case STATE_ADDRESS: + if (m_sck && !state) + { + m_address <<= 1; + m_address |= m_sdi; + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("MCCS1850 '%s' %s Address %u\n", tag(), BIT(m_address, 7) ? "Read" : "Write", m_address & 0x7f); + + m_bits = 0; + m_state = STATE_DATA; + + if (BIT(m_address, 7)) + { + m_shift = read_register(m_address & 0x7f); + + if (LOG) logerror("MCCS1850 '%s' Data Out %02x\n", tag(), m_shift); + } + } + } + break; + + case STATE_DATA: + if (!BIT(m_address, 7) && m_sck && !state) + { + // shift data in + m_shift <<= 1; + m_shift |= m_sdi; + m_bits++; + + if (m_bits == 8) + { + if (LOG) logerror("MCCS1850 '%s' Data In %02x\n", tag(), m_shift); + + write_register(m_address & 0x7f, m_shift); + + m_bits = 0; + + // increment address counter + m_address++; + m_address &= 0x7f; + } + } + else if (BIT(m_address, 7) && !m_sck && state) + { + // shift data out + m_sdo = BIT(m_shift, 7); + m_shift <<= 1; + m_bits++; + + if (m_bits == 8) + { + m_bits = 0; + + // increment address counter + m_address++; + m_address &= 0x7f; + m_shift = read_register(m_address & 0x7f); + } + } + break; + } + + m_sck = state; +} + + +//------------------------------------------------- +// sdo_r - serial data out read +//------------------------------------------------- + +READ_LINE_MEMBER( mccs1850_device::sdo_r ) +{ + return m_sdo; +} + + +//------------------------------------------------- +// sdi_w - serial data in write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::sdi_w ) +{ + m_sdi = state; +} + + +//------------------------------------------------- +// pwrsw_w - power switch write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::pwrsw_w ) +{ + if (!state) + { + if (m_pse) + { + // request to power down + m_ram[REGISTER_STATUS] |= STATUS_RPD; + check_interrupt(); + } + + set_pse_line(1); + } +} + + +//------------------------------------------------- +// por_w - power on reset write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::por_w ) +{ + if (!state) + { + device_reset(); + } +} + + +//------------------------------------------------- +// test_w - test mode write +//------------------------------------------------- + +WRITE_LINE_MEMBER( mccs1850_device::test_w ) +{ + if (state) + { + if (LOG) logerror("MCCS1850 '%s' Test Mode\n", tag()); + + m_ram[REGISTER_STATUS] |= STATUS_TM; + } + else + { + if (LOG) logerror("MCCS1850 '%s' Normal Operation\n", tag()); + + m_ram[REGISTER_STATUS] &= ~STATUS_TM; + } +} diff --git a/src/emu/machine/mccs1850.h b/src/emu/machine/mccs1850.h new file mode 100644 index 00000000000..da3e43a72d0 --- /dev/null +++ b/src/emu/machine/mccs1850.h @@ -0,0 +1,135 @@ +/********************************************************************** + + Motorola MCCS1850 Serial Real-Time Clock emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +********************************************************************** + _____ _____ + Vbat 1 |* \_/ | 16 Vdd + _POR 2 | | 15 TEST + _INT 3 | | 14 XTAL1 + SCK 4 | MCCS1850 | 13 XTAL2 + SDI 5 | | 12 _PWRSW + SDO 6 | | 11 NUC + CE 7 | | 10 _PSE + Vss 8 |_____________| 9 PSE + +**********************************************************************/ + +#pragma once + +#ifndef __MCCS1850__ +#define __MCCS1850__ + +#include "emu.h" + + + +//************************************************************************** +// INTERFACE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_MCCS1850_ADD(_tag, _clock, _config) \ + MCFG_DEVICE_ADD(_tag, MCCS1850, _clock) \ + MCFG_DEVICE_CONFIG(_config) + + +#define MCCS1850_INTERFACE(name) \ + const mccs1850_interface (name) = + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> mccs1850_interface + +struct mccs1850_interface +{ + devcb_write_line m_out_int_cb; + devcb_write_line m_out_pse_cb; + devcb_write_line m_out_nuc_cb; +}; + + + +// ======================> mccs1850_device + +class mccs1850_device : public device_t, + public device_rtc_interface, + public device_nvram_interface, + public mccs1850_interface +{ +public: + // construction/destruction + mccs1850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + DECLARE_WRITE_LINE_MEMBER( ce_w ); + DECLARE_WRITE_LINE_MEMBER( sck_w ); + DECLARE_READ_LINE_MEMBER( sdo_r ); + DECLARE_WRITE_LINE_MEMBER( sdi_w ); + DECLARE_WRITE_LINE_MEMBER( pwrsw_w ); + DECLARE_WRITE_LINE_MEMBER( por_w ); + DECLARE_WRITE_LINE_MEMBER( test_w ); + +protected: + // device-level overrides + virtual void device_config_complete(); + 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_set_time(int year, int month, int day, int day_of_week, int hour, int minute, int second); + virtual bool rtc_is_year_2000_compliant() { return false; } + + // device_nvram_interface overrides + virtual void nvram_default(); + virtual void nvram_read(emu_file &file); + virtual void nvram_write(emu_file &file); + +private: + inline void check_interrupt(); + inline void set_pse_line(int state); + inline UINT8 read_register(offs_t offset); + inline void write_register(offs_t offset, UINT8 data); + inline void advance_seconds(); + + static const device_timer_id TIMER_CLOCK = 0; + + devcb_resolved_write_line m_out_int_func; + devcb_resolved_write_line m_out_pse_func; + devcb_resolved_write_line m_out_nuc_func; + + UINT8 m_ram[0x80]; // RAM + + // power supply + int m_pse; // power supply enable + + // counter + UINT32 m_counter; // seconds counter + + // serial interface + int m_ce; // chip enable + int m_sck; // serial clock + int m_sdo; // serial data out + int m_sdi; // serial data in + int m_state; // serial interface state + UINT8 m_address; // address counter + int m_bits; // bit counter + UINT8 m_shift; // shift register + + // timers + emu_timer *m_clock_timer; +}; + + +// device type definition +extern const device_type MCCS1850; + + + +#endif