From 92f5d35614b7b74613f1daa65d84c664edbbc368 Mon Sep 17 00:00:00 2001 From: Curt Coder Date: Sun, 12 Mar 2023 08:36:28 +0200 Subject: abc1600: Fixed RTC and NVRAM communications. [Curt Coder] --- src/devices/machine/e0516.cpp | 251 +++++++++++++++++++++++++++++++++------- src/devices/machine/e0516.h | 32 +++-- src/devices/machine/nmc9306.cpp | 147 +++++++++++++++++++---- src/devices/machine/nmc9306.h | 16 +-- src/mame/luxor/abc1600.cpp | 11 +- 5 files changed, 368 insertions(+), 89 deletions(-) diff --git a/src/devices/machine/e0516.cpp b/src/devices/machine/e0516.cpp index 29fe42e3f17..1ce16408f1b 100644 --- a/src/devices/machine/e0516.cpp +++ b/src/devices/machine/e0516.cpp @@ -15,14 +15,17 @@ // MACROS / CONSTANTS //************************************************************************** -#define LOG 0 +//#define VERBOSE 1 +#include "logmacro.h" // states enum { STATE_ADDRESS = 0, - STATE_DATA + STATE_HI_Z, + STATE_DATA_READ, + STATE_DATA_WRITE }; @@ -38,11 +41,24 @@ DEFINE_DEVICE_TYPE(E0516, e0516_device, "e0516", "E05-16 RTC") // e0516_device - constructor //------------------------------------------------- -e0516_device::e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, E0516, tag, owner, clock) - , device_rtc_interface(mconfig, *this) - , m_cs(0), m_clk(0), m_data_latch(0), m_reg_latch(0), m_read_write(0), m_state(0), m_bits(0), m_dio(0) - , m_timer(nullptr) +e0516_device::e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, E0516, tag, owner, clock), + device_rtc_interface(mconfig, *this), + m_read_outsel(*this), + m_write_sec(*this), + m_write_min(*this), + m_write_hrs(*this), + m_write_day(*this), + m_cs(1), + m_clk(0), + m_cycle(0), + m_data_latch(0), + m_reg_latch(0), + m_state(STATE_ADDRESS), + m_bits_left(0), + m_dio(0), + m_reset(1), + m_timer(nullptr) { } @@ -53,6 +69,13 @@ e0516_device::e0516_device(const machine_config &mconfig, const char *tag, devic void e0516_device::device_start() { + // resolve callbacks + m_read_outsel.resolve_safe(1); + m_write_sec.resolve_safe(); + m_write_min.resolve_safe(); + m_write_hrs.resolve_safe(); + m_write_day.resolve_safe(); + // allocate timers m_timer = timer_alloc(FUNC(e0516_device::timer_tick), this); m_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768)); @@ -60,12 +83,13 @@ void e0516_device::device_start() // state saving save_item(NAME(m_cs)); save_item(NAME(m_clk)); + save_item(NAME(m_cycle)); save_item(NAME(m_data_latch)); save_item(NAME(m_reg_latch)); - save_item(NAME(m_read_write)); save_item(NAME(m_state)); - save_item(NAME(m_bits)); + save_item(NAME(m_bits_left)); save_item(NAME(m_dio)); + save_item(NAME(m_reset)); } @@ -76,7 +100,10 @@ void e0516_device::device_start() TIMER_CALLBACK_MEMBER(e0516_device::timer_tick) { - advance_seconds(); + if (m_reset) + { + advance_seconds(); + } } @@ -86,17 +113,29 @@ TIMER_CALLBACK_MEMBER(e0516_device::timer_tick) WRITE_LINE_MEMBER( e0516_device::cs_w ) { - if (LOG) logerror("E05-16 '%s' CS %u\n", tag(), state); - - m_cs = state; + if (m_cs != state) + { + LOG("E05-16 '%s' CS %u\n", tag(), state); + } - if (m_cs) + if (!m_cs && state) { + if ((m_state == STATE_DATA_WRITE) && (m_bits_left == 0) && (get_address() != 7)) + { + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), get_address(), m_data_latch); + + // write latched data to register + set_clock_register(get_address(), bcd_to_integer(m_data_latch)); + } + + m_cycle = 0; m_data_latch = 0; m_reg_latch = 0; - m_bits = 0; + m_bits_left = 4; m_state = STATE_ADDRESS; } + + m_cs = state; } @@ -106,63 +145,153 @@ WRITE_LINE_MEMBER( e0516_device::cs_w ) WRITE_LINE_MEMBER( e0516_device::clk_w ) { - if (LOG) logerror("E05-16 '%s' CLK %u\n", tag(), state); - + if (m_cs) return; + if (m_clk == state) return; m_clk = state; - if (m_cs || m_clk) return; + if (m_clk) { + m_cycle++; + LOG("E05-16 '%s' CLK %u\n", tag(), m_cycle); + } + + if (!m_bits_left) return; + + if (!m_clk && (m_state == STATE_HI_Z)) + { + m_state = STATE_DATA_READ; + return; + } - m_bits++; + if (!m_clk && (m_state != STATE_DATA_READ)) return; + if (m_clk && (m_state == STATE_DATA_READ)) return; + m_bits_left--; + if ((m_state == STATE_DATA_READ) && (m_bits_left == 56) && !m_read_outsel()) return; + if (m_state == STATE_ADDRESS) { - if (LOG) logerror("E05-16 '%s' Command Bit %u\n", tag(), m_dio); + LOG("E05-16 '%s' Command Bit %u\n", tag(), m_dio); // command - m_reg_latch |= m_dio << 3; - m_reg_latch >>= 1; + m_reg_latch <<= 1; + m_reg_latch |= m_dio; + m_reg_latch & 0x0f; - if (m_bits == 4) + if (m_bits_left == 0) { - m_state = STATE_DATA; - m_bits = 0; - if (BIT(m_reg_latch, 0)) { - // load register value to data latch - m_data_latch = convert_to_bcd(get_clock_register(m_reg_latch >> 1)); + m_state = STATE_DATA_READ; + + if (get_address() == 7) + { + LOG("E05-16 '%s' Continuous Read-Out Mode\n", tag()); + + // continuous read-out mode + m_bits_left = 56; + + // load all register values to data latch + m_data_latch = convert_to_bcd(get_clock_register(RTC_SECOND)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_DAY_OF_WEEK)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_YEAR)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_MONTH)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_DAY)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_MINUTE)); + m_data_latch <<= 8; + m_data_latch = (m_data_latch & ~0xff) | convert_to_bcd(get_clock_register(RTC_HOUR)); + } + else + { + LOG("E05-16 '%s' Read Register %u\n", tag(), get_address()); + + m_bits_left = 8; + + // load register value to data latch + m_data_latch = convert_to_bcd(get_clock_register(get_address())); + } + + if (!m_read_outsel()) + { + m_state = STATE_HI_Z; + } + } + else + { + m_state = STATE_DATA_WRITE; + + if (get_address() == 7) + { + LOG("E05-16 '%s' Continuous Write-In Mode\n", tag()); + + // continuous write-in mode + m_bits_left = 56; + } + else + { + LOG("E05-16 '%s' Write Register %u\n", tag(), get_address()); + + m_bits_left = 8; + } } } } else { // data - if (BIT(m_reg_latch, 0)) + if (m_state == STATE_DATA_READ) { // read - if (LOG) logerror("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio); - m_dio = BIT(m_data_latch, 0); m_data_latch >>= 1; + + LOG("E05-16 '%s' Data Bit OUT %u\n", tag(), m_dio); } else { // write - if (LOG) logerror("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio); + LOG("E05-16 '%s' Data Bit IN %u\n", tag(), m_dio); - m_data_latch |= m_dio << 7; - m_data_latch >>= 1; - } + m_data_latch <<= 1; + m_data_latch |= m_dio; - if (m_bits == 8) - { - m_state = STATE_ADDRESS; - m_bits = 0; - - if (!BIT(m_reg_latch, 0)) + if (get_address() == 7) { - // write latched data to register - set_clock_register(m_reg_latch >> 1, bcd_to_integer(m_data_latch)); + switch (m_bits_left) + { + case 48: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_HOUR, m_data_latch & 0xff); + set_clock_register(RTC_HOUR, bcd_to_integer(m_data_latch & 0xff)); + break; + case 40: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_MINUTE, m_data_latch & 0xff); + set_clock_register(RTC_MINUTE, bcd_to_integer(m_data_latch & 0xff)); + break; + case 32: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_DAY, m_data_latch & 0xff); + set_clock_register(RTC_DAY, bcd_to_integer(m_data_latch & 0xff)); + break; + case 24: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_MONTH, m_data_latch & 0xff); + set_clock_register(RTC_MONTH, bcd_to_integer(m_data_latch & 0xff)); + break; + case 16: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_YEAR, m_data_latch & 0xff); + set_clock_register(RTC_YEAR, bcd_to_integer(m_data_latch & 0xff)); + break; + case 8: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_DAY_OF_WEEK, m_data_latch & 0xff); + set_clock_register(RTC_DAY_OF_WEEK, bcd_to_integer(m_data_latch & 0xff)); + break; + case 0: + LOG("E05-16 '%s' Write Register %u : %02x\n", tag(), RTC_SECOND, m_data_latch & 0xff); + set_clock_register(RTC_SECOND, bcd_to_integer(m_data_latch & 0xff)); + break; + } } } } @@ -175,9 +304,12 @@ WRITE_LINE_MEMBER( e0516_device::clk_w ) WRITE_LINE_MEMBER( e0516_device::dio_w ) { - if (LOG) logerror("E05-16 '%s' DIO %u\n", tag(), state); + LOG("E05-16 '%s' DIO %u\n", tag(), state); - m_dio = state; + if ((m_state != STATE_DATA_READ) && (m_state != STATE_HI_Z)) + { + m_dio = state; + } } @@ -187,10 +319,39 @@ WRITE_LINE_MEMBER( e0516_device::dio_w ) READ_LINE_MEMBER( e0516_device::dio_r ) { + if (m_cs || (m_state == STATE_HI_Z)) + { + // high impedance + return 0; + } + return m_dio; } +//------------------------------------------------- +// reset_w - reset input +//------------------------------------------------- + +WRITE_LINE_MEMBER( e0516_device::reset_w ) +{ + LOG("E05-16 '%s' RESET %u\n", tag(), state); + + if (m_reset && !state) + { + set_clock_register(RTC_SECOND, 0); + set_clock_register(RTC_MINUTE, 0); + set_clock_register(RTC_HOUR, 0); + set_clock_register(RTC_DAY, 1); + set_clock_register(RTC_MONTH, 1); + set_clock_register(RTC_DAY_OF_WEEK, 1); + set_clock_register(RTC_YEAR, 0); + } + + m_reset = state; +} + + //------------------------------------------------- // rtc_clock_updated - //------------------------------------------------- diff --git a/src/devices/machine/e0516.h b/src/devices/machine/e0516.h index d3807ff5968..190d8fa07ca 100644 --- a/src/devices/machine/e0516.h +++ b/src/devices/machine/e0516.h @@ -30,10 +30,17 @@ public: // construction/destruction e0516_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + auto outsel_rd_cb() { return m_read_outsel.bind(); } + auto sec_wr_cb() { return m_write_sec.bind(); } + auto min_wr_cb() { return m_write_min.bind(); } + auto hrs_wr_cb() { return m_write_hrs.bind(); } + auto day_wr_cb() { return m_write_day.bind(); } + DECLARE_WRITE_LINE_MEMBER( cs_w ); DECLARE_WRITE_LINE_MEMBER( clk_w ); DECLARE_WRITE_LINE_MEMBER( dio_w ); DECLARE_READ_LINE_MEMBER( dio_r ); + DECLARE_WRITE_LINE_MEMBER( reset_w ); protected: // device-level overrides @@ -44,15 +51,24 @@ protected: TIMER_CALLBACK_MEMBER(timer_tick); + devcb_read_line m_read_outsel; + devcb_write_line m_write_sec; + devcb_write_line m_write_min; + devcb_write_line m_write_hrs; + devcb_write_line m_write_day; + private: - int m_cs; // chip select - int m_clk; // clock - int m_data_latch; // data latch - int m_reg_latch; // register latch - int m_read_write; // read/write data - int m_state; // state - int m_bits; // number of bits transferred - int m_dio; // data pin + bool m_cs; + bool m_clk; + int m_cycle; + u64 m_data_latch; + int m_reg_latch; + int m_state; + int m_bits_left; + bool m_dio; + bool m_reset; + + offs_t get_address() { return (m_reg_latch >> 1) & 0x07; } // timers emu_timer *m_timer; diff --git a/src/devices/machine/nmc9306.cpp b/src/devices/machine/nmc9306.cpp index b2fd50626f9..2e932d8f94d 100644 --- a/src/devices/machine/nmc9306.cpp +++ b/src/devices/machine/nmc9306.cpp @@ -43,11 +43,14 @@ enum enum { STATE_IDLE = 0, + STATE_START, STATE_COMMAND, STATE_ADDRESS, STATE_DATA_IN, + STATE_DUMMY_OUT, STATE_DATA_OUT, - STATE_ERASE + STATE_ERASE, + STATE_WRITE }; @@ -73,11 +76,11 @@ inline uint16_t nmc9306_device::read(offs_t offset) // nmc9306_device - constructor //------------------------------------------------- -inline void nmc9306_device::write(offs_t offset, uint16_t data) +inline void nmc9306_device::write(offs_t offset, u16 data) { if (m_ewen) { - m_register[offset] &= data; + m_register[offset] = data; } } @@ -104,11 +107,19 @@ inline void nmc9306_device::erase(offs_t offset) // nmc9306_device - constructor //------------------------------------------------- -nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, NMC9306, tag, owner, clock), - device_nvram_interface(mconfig, *this), - m_state(STATE_IDLE), - m_ewen(false) +nmc9306_device::nmc9306_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, NMC9306, tag, owner, clock), + device_nvram_interface(mconfig, *this), + m_bits(0), + m_state(STATE_IDLE), + m_command(0), + m_address(0), + m_data(0), + m_ewen(false), + m_cs(0), + m_sk(0), + m_do(0), + m_di(0) { } @@ -142,6 +153,8 @@ void nmc9306_device::device_start() void nmc9306_device::nvram_default() { + for (auto & elem : m_register) + elem = 0xffff; } @@ -175,6 +188,64 @@ bool nmc9306_device::nvram_write(util::write_stream &file) WRITE_LINE_MEMBER( nmc9306_device::cs_w ) { + if (m_cs != state) + { + LOG("NMC9306 CS %u\n", state); + + if (m_cs && !state) + { + switch ((m_command >> 2) & 0x03) + { + case OTHER: + switch (m_command & 0x03) + { + case WRAL: + if (m_state == STATE_WRITE) + { + LOG("NMC9306 WRAL\n"); + for (int address = 0; address < 16; address++) + { + write(address, m_data); + } + } + break; + + case ERAL: + if (m_state == STATE_ERASE) + { + LOG("NMC9306 ERAL\n"); + for (int address = 0; address < 16; address++) + { + erase(address); + } + } + break; + } + break; + + case WRITE: + if (m_state == STATE_WRITE) + { + LOG("NMC9306 WRITE %u:%04x\n", m_address, m_data); + write(m_address, m_data); + break; + } + + case ERASE: + if (m_state == STATE_ERASE) + { + LOG("NMC9306 ERASE %u\n", m_address); + erase(m_address); + break; + } + } + + m_state = STATE_IDLE; + m_bits = 0; + m_do = 0; + } + } + m_cs = state; } @@ -185,18 +256,33 @@ WRITE_LINE_MEMBER( nmc9306_device::cs_w ) WRITE_LINE_MEMBER( nmc9306_device::sk_w ) { + if (!m_cs) return; + if (m_sk == state) return; + + LOG("NMC9306 SK %u\n", state); + m_sk = state; - if (!m_cs || !m_sk) return; + if (m_sk && ((m_state == STATE_DUMMY_OUT) || (m_state == STATE_DATA_OUT))) return; + if (!m_sk && (m_state != STATE_DUMMY_OUT) && (m_state != STATE_DATA_OUT)) return; switch (m_state) { case STATE_IDLE: LOG("NMC9306 Idle %u\n", m_di); - if (m_di) + if (!m_di) { // start bit received + m_state = STATE_START; + } + break; + + case STATE_START: + LOG("NMC9306 Start %u\n", m_di); + + if (m_di) + { m_state = STATE_COMMAND; m_bits = 0; } @@ -207,6 +293,8 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w ) m_command <<= 1; m_command |= m_di; + m_command &= 0xf; + m_bits++; if (m_bits == 4) @@ -221,6 +309,8 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w ) m_address <<= 1; m_address |= m_di; + m_address &= 0xf; + m_bits++; if (m_bits == 4) @@ -237,11 +327,13 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w ) break; case WRAL: - LOG("NMC9306 WRAL\n"); + LOG("NMC9306 Command WRAL\n"); + m_state = STATE_DATA_IN; break; case ERAL: - LOG("NMC9306 ERAL\n"); + LOG("NMC9306 Command ERAL\n"); + m_state = ERASE; break; case EWEN: @@ -253,20 +345,19 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w ) break; case WRITE: - LOG("NMC9306 WRITE %u\n", m_address & 0x0f); + LOG("NMC9306 Command WRITE %u\n", m_address); m_state = STATE_DATA_IN; break; case READ: - LOG("NMC9306 READ %u\n", m_address & 0x0f); - m_data = read(m_address & 0x0f); - m_state = STATE_DATA_OUT; + m_data = read(m_address); + LOG("NMC9306 READ %u:%04x\n", m_address, m_data); + m_state = STATE_DUMMY_OUT; break; case ERASE: - LOG("NMC9306 ERASE %u\n", m_address & 0x0f); - erase(m_address & 0x0f); - m_state = STATE_ERASE; + LOG("NMC9306 Command ERASE %u\n", m_address); + m_state = ERASE; break; } @@ -279,21 +370,29 @@ WRITE_LINE_MEMBER( nmc9306_device::sk_w ) m_data <<= 1; m_data |= m_di; + m_bits++; if (m_bits == 16) { - write(m_address & 0x0f, m_data); - - m_state = STATE_IDLE; + m_state = STATE_WRITE; } break; - case STATE_DATA_OUT: - LOG("NMC9306 Data Bit OUT %u\n", m_di); + case STATE_DUMMY_OUT: + m_do = 0; + + LOG("NMC9306 Dummy Bit OUT %u\n", m_do); + + m_state = STATE_DATA_OUT; + break; + case STATE_DATA_OUT: m_do = BIT(m_data, 15); m_data <<= 1; + + LOG("NMC9306 Data Bit OUT %u\n", m_do); + m_bits++; if (m_bits == 16) diff --git a/src/devices/machine/nmc9306.h b/src/devices/machine/nmc9306.h index 98566a9ab82..af2ecb17523 100644 --- a/src/devices/machine/nmc9306.h +++ b/src/devices/machine/nmc9306.h @@ -49,21 +49,21 @@ protected: private: inline uint16_t read(offs_t offset); - inline void write(offs_t offset, uint16_t data); + inline void write(offs_t offset, u16 data); inline void erase(offs_t offset); uint16_t m_register[16]; int m_bits; int m_state; - uint8_t m_command; - uint8_t m_address; - uint16_t m_data; + u8 m_command; + u8 m_address; + u16 m_data; bool m_ewen; - int m_cs; - int m_sk; - int m_do; - int m_di; + bool m_cs; + bool m_sk; + bool m_do; + bool m_di; }; diff --git a/src/mame/luxor/abc1600.cpp b/src/mame/luxor/abc1600.cpp index 4caefb8deac..ea623af4247 100644 --- a/src/mame/luxor/abc1600.cpp +++ b/src/mame/luxor/abc1600.cpp @@ -36,13 +36,15 @@ TODO: - - systest1600 - - chip test fails + - systest1600 failures + - CIO timer + - RTC (seconds advance too slowly) + - DMA + - bootpar writes console bauds without high order byte (9600=>128) - loadsys1 core dump (/etc/mkfs -b 1024 -v 69000 /dev/sa40) - crashes after reset - CIO - optimize timers! - - port C, open drain output bit PC1 (RTC/NVRAM data) - connect RS-232 printer port - Z80 SCC/DART interrupt chain - [:2a:chb] - TX FIFO is full, discarding data @@ -1016,7 +1018,8 @@ void abc1600_state::abc1600(machine_config &config) NMC9306(config, m_nvram, 0); - E0516(config, E050_C16PC_TAG, 32.768_kHz_XTAL); + E0516(config, m_rtc, 32.768_kHz_XTAL); + m_rtc->outsel_rd_cb().set_constant(0); FD1797(config, m_fdc, 64_MHz_XTAL / 64); // clocked by 9229B m_fdc->intrq_wr_callback().set(m_cio, FUNC(z8536_device::pb7_w)); -- cgit v1.2.3