From 094d06e5d7792a29966eb3c9c426bc0997fc0384 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Thu, 29 Feb 2024 01:24:45 +0100 Subject: h8_sci: Entirely revise clocking --- src/devices/bus/plg100/vl.cpp | 2 +- src/devices/cpu/h8/h8.cpp | 2 + src/devices/cpu/h8/h8.h | 3 + src/devices/cpu/h8/h8_sci.cpp | 533 +++++++++++++++++++----------------------- src/devices/cpu/h8/h8_sci.h | 23 +- src/mame/namco/namcos23.cpp | 2 +- 6 files changed, 259 insertions(+), 306 deletions(-) diff --git a/src/devices/bus/plg100/vl.cpp b/src/devices/bus/plg100/vl.cpp index ec89fbeab0a..58a150cbaea 100644 --- a/src/devices/bus/plg100/vl.cpp +++ b/src/devices/bus/plg100/vl.cpp @@ -50,7 +50,7 @@ plg100_vl_device::~plg100_vl_device() void plg100_vl_device::midi_rx(int state) { - m_cpu->sci_rx_w<0>(state); + m_cpu->sci_rx_w<1>(state); } void plg100_vl_device::map(address_map &map) diff --git a/src/devices/cpu/h8/h8.cpp b/src/devices/cpu/h8/h8.cpp index 131f9aabf4c..b1b342bedf2 100644 --- a/src/devices/cpu/h8/h8.cpp +++ b/src/devices/cpu/h8/h8.cpp @@ -145,6 +145,7 @@ void h8_device::device_start() state_add(H8_R7, "ER7", m_TMPR).callimport().callexport().formatstr("%9s"); } + save_item(NAME(m_cycles_base)); save_item(NAME(m_PPC)); save_item(NAME(m_NPC)); save_item(NAME(m_PC)); @@ -189,6 +190,7 @@ void h8_device::device_start() void h8_device::device_reset() { + m_cycles_base = machine().time().as_ticks(clock()); m_inst_state = STATE_RESET; m_inst_substate = 0; m_count_before_instruction_step = 0; diff --git a/src/devices/cpu/h8/h8.h b/src/devices/cpu/h8/h8.h index 9cce7631d9d..6a7ac788035 100644 --- a/src/devices/cpu/h8/h8.h +++ b/src/devices/cpu/h8/h8.h @@ -65,6 +65,8 @@ public: void do_sci_tx(int sci, int state) { m_sci_tx[sci](state); } void do_sci_clk(int sci, int state) { m_sci_clk[sci](state); } + u64 now_as_cycles() const { return machine().time().as_ticks(clock()) - m_cycles_base; } + protected: enum { // digital I/O ports @@ -153,6 +155,7 @@ protected: h8_dma_state *m_dma_channel[8]; int m_current_dma; h8_dtc_state *m_current_dtc; + u64 m_cycles_base; u32 m_PPC; // previous program counter u32 m_NPC; // next start-of-instruction program counter diff --git a/src/devices/cpu/h8/h8_sci.cpp b/src/devices/cpu/h8/h8_sci.cpp index d5f826d6f80..8dea1ee4b1d 100644 --- a/src/devices/cpu/h8/h8_sci.cpp +++ b/src/devices/cpu/h8/h8_sci.cpp @@ -13,6 +13,7 @@ #define LOG_DATA (1 << 4U) // Bytes transmitted #define LOG_CLOCK (1 << 5U) // Clock and transmission start/stop #define LOG_STATE (1 << 6U) // State machine states +#define LOG_TICK (1 << 7U) // Clock ticks #define VERBOSE (LOG_DATA) @@ -20,6 +21,46 @@ DEFINE_DEVICE_TYPE(H8_SCI, h8_sci_device, "h8_sci", "H8 Serial Communications Interface") + +// Clocking: +// Async mode: +// The circuit wants 16 events per bit. +// * Internal clocking: the cpu clock is divided by one of (1, 4, 16, 64) from the cks field of smr +// then by (brr+1) then by 2. +// * External clocking: the external clock is supposed to be 16*bitrate. +// Sync mode: +// The circuit wants 2 events per bit, a positive and a negative edge. +// * Internal clocking: the cpu clock is divided by one of (1, 4, 16, 64) from the cks field of smr +// then by (brr+1) then by 2. Events are then interpreted has been alternatively positive and +// negative (e.g. another divide-by-two, sync-wise). +// * External clocking: the external clock is supposed to be at bitrate, both edges are used. +// +// Synchronization: +// Async mode: +// Both modes use a 4-bits counter incremented on every event (16/bit). +// +// * Transmit sets the counter to 0 at transmit start. Output data line changes value +// on counter == 0. If the clock output is required, clk=1 outside of transmit, +// clk=0 on counter==0, clk=1 on counter==8. +// +// * Receive sets the counter to 0 when the data line initially goes down (start bit) +// Output line is read on counter==8. It is unknown whether the counter is reset +// on every data line level change. +// +// Sync mode: +// * Transmit changes the data line on negative edges, the clock line, following positive and +// negative edge definition, is output as long as transmit is active and is otherwise 1. +// +// * Receive reads the data line on positive edges. +// +// Framing: +// Async mode: 1 bit of start at 0, 7 or 8 bits of data, nothing or 1 bit of parity or 1 bit of multiprocessing, 1 or 2 bits of stop at 1. +// Sync mode: 8 bits of data. +// +// Multiprocessing bit is an extra bit which value can be set on transmit in bit zero of ssr. +// On receive when zero the byte is dropped. + + const char *const h8_sci_device::state_names[] = { "idle", "start", "bit", "parity", "stop", "last-tick" }; h8_sci_device::h8_sci_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : @@ -27,8 +68,9 @@ h8_sci_device::h8_sci_device(const machine_config &mconfig, const char *tag, dev m_cpu(*this, finder_base::DUMMY_TAG), m_intc(*this, finder_base::DUMMY_TAG), m_external_to_internal_ratio(0), m_internal_to_external_ratio(0), m_sync_timer(nullptr), m_id(0), m_eri_int(0), m_rxi_int(0), m_txi_int(0), m_tei_int(0), - m_tx_state(0), m_rx_state(0), m_tx_bit(0), m_rx_bit(0), m_clock_state(0), m_tx_parity(0), m_rx_parity(0), m_tx_ext_clock_counter(0), m_rx_ext_clock_counter(0), m_clock_mode(clock_mode_t::INTERNAL_ASYNC), m_tx_clock_value(false), m_rx_clock_value(false), m_ext_clock_value(false), m_rx_value(false), - m_rdr(0), m_tdr(0), m_smr(0), m_scr(0), m_ssr(0), m_brr(0), m_rsr(0), m_tsr(0), m_tx_clock_base(0), m_rx_clock_base(0), m_divider(0) + m_tx_state(0), m_rx_state(0), m_tx_bit(0), m_rx_bit(0), m_clock_state(0), m_tx_parity(0), m_rx_parity(0), m_tx_clock_counter(0), m_rx_clock_counter(0), + m_clock_mode(INTERNAL_ASYNC), m_ext_clock_value(false), m_rx_value(true), + m_rdr(0), m_tdr(0), m_smr(0), m_scr(0), m_ssr(0), m_brr(0), m_rsr(0), m_tsr(0), m_clock_event(0), m_divider(0) { m_external_clock_period = attotime::never; } @@ -184,53 +226,50 @@ u8 h8_sci_device::scmr_r() void h8_sci_device::clock_update() { - // Sync: Divider must be the time of a half-period (both edges are used, datarate*2) - // Async: Divider must be the time of one period (only rising edge used, datarate*16) - m_divider = 2 << (2*(m_smr & SMR_CKS)); m_divider *= m_brr+1; if(m_smr & SMR_CA) { if(m_scr & SCR_CKE1) - m_clock_mode = clock_mode_t::EXTERNAL_SYNC; + m_clock_mode = EXTERNAL_SYNC; else - m_clock_mode = clock_mode_t::INTERNAL_SYNC_OUT; + m_clock_mode = INTERNAL_SYNC_OUT; } else { if(m_scr & SCR_CKE1) - m_clock_mode = clock_mode_t::EXTERNAL_ASYNC; + m_clock_mode = EXTERNAL_ASYNC; else if(m_scr & SCR_CKE0) - m_clock_mode = clock_mode_t::INTERNAL_ASYNC_OUT; + m_clock_mode = INTERNAL_ASYNC_OUT; else - m_clock_mode = clock_mode_t::INTERNAL_ASYNC; + m_clock_mode = INTERNAL_ASYNC; } - if(m_clock_mode == clock_mode_t::EXTERNAL_ASYNC && !m_external_clock_period.is_never()) - m_clock_mode = clock_mode_t::EXTERNAL_RATE_ASYNC; - if(m_clock_mode == clock_mode_t::EXTERNAL_SYNC && !m_external_clock_period.is_never()) - m_clock_mode = clock_mode_t::EXTERNAL_RATE_SYNC; + if(m_clock_mode == EXTERNAL_ASYNC && !m_external_clock_period.is_never()) + m_clock_mode = EXTERNAL_RATE_ASYNC; + if(m_clock_mode == EXTERNAL_SYNC && !m_external_clock_period.is_never()) + m_clock_mode = EXTERNAL_RATE_SYNC; if(VERBOSE & LOG_RATE) { std::string new_message; switch(m_clock_mode) { - case clock_mode_t::INTERNAL_ASYNC: + case INTERNAL_ASYNC: new_message = util::string_format("clock internal at %d Hz, async, bitrate %d bps\n", int(m_cpu->clock() / m_divider), int(m_cpu->clock() / (m_divider*16))); break; - case clock_mode_t::INTERNAL_ASYNC_OUT: + case INTERNAL_ASYNC_OUT: new_message = util::string_format("clock internal at %d Hz, async, bitrate %d bps, output\n", int(m_cpu->clock() / m_divider), int(m_cpu->clock() / (m_divider*16))); break; - case clock_mode_t::EXTERNAL_ASYNC: + case EXTERNAL_ASYNC: new_message = "clock external, async\n"; break; - case clock_mode_t::EXTERNAL_RATE_ASYNC: + case EXTERNAL_RATE_ASYNC: new_message = util::string_format("clock external at %d Hz, async, bitrate %d bps\n", int(m_cpu->clock()*m_internal_to_external_ratio), int(m_cpu->clock()*m_internal_to_external_ratio/16)); break; - case clock_mode_t::INTERNAL_SYNC_OUT: + case INTERNAL_SYNC_OUT: new_message = util::string_format("clock internal at %d Hz, sync, output\n", int(m_cpu->clock() / (m_divider*2))); break; - case clock_mode_t::EXTERNAL_SYNC: + case EXTERNAL_SYNC: new_message = "clock external, sync\n"; break; - case clock_mode_t::EXTERNAL_RATE_SYNC: + case EXTERNAL_RATE_SYNC: new_message = util::string_format("clock external at %d Hz, sync\n", int(m_cpu->clock()*m_internal_to_external_ratio)); break; } @@ -267,15 +306,15 @@ void h8_sci_device::device_start() save_item(NAME(m_rx_state)); save_item(NAME(m_tx_state)); save_item(NAME(m_tx_parity)); + save_item(NAME(m_clock_mode)); save_item(NAME(m_clock_state)); - save_item(NAME(m_tx_clock_value)); - save_item(NAME(m_rx_clock_value)); - save_item(NAME(m_tx_clock_base)); - save_item(NAME(m_rx_clock_base)); + save_item(NAME(m_clock_event)); + save_item(NAME(m_clock_step)); save_item(NAME(m_divider)); + save_item(NAME(m_rx_value)); save_item(NAME(m_ext_clock_value)); - save_item(NAME(m_tx_ext_clock_counter)); - save_item(NAME(m_rx_ext_clock_counter)); + save_item(NAME(m_tx_clock_counter)); + save_item(NAME(m_rx_clock_counter)); save_item(NAME(m_cur_sync_time)); } @@ -294,25 +333,14 @@ void h8_sci_device::device_reset() m_tx_state = ST_IDLE; m_rx_state = ST_IDLE; m_clock_state = 0; - m_clock_mode = clock_mode_t::INTERNAL_ASYNC; - m_tx_clock_base = 0; - m_rx_clock_base = 0; + m_clock_mode = INTERNAL_ASYNC; + m_clock_event = 0; clock_update(); - m_tx_clock_value = true; - m_rx_clock_value = true; m_ext_clock_value = true; - m_tx_ext_clock_counter = 0; - m_rx_ext_clock_counter = 0; - m_rx_value = true; - m_cpu->do_sci_clk(m_id, m_tx_clock_value); + m_tx_clock_counter = 0; + m_rx_clock_counter = 0; + m_cpu->do_sci_clk(m_id, 1); m_cpu->do_sci_tx(m_id, 1); - m_cur_sync_time = attotime::never; -} - -void h8_sci_device::device_post_load() -{ - // Set clock_mode correctly as it's not saved - clock_update(); } TIMER_CALLBACK_MEMBER(h8_sci_device::sync_tick) @@ -322,6 +350,10 @@ TIMER_CALLBACK_MEMBER(h8_sci_device::sync_tick) void h8_sci_device::do_rx_w(int state) { + if(state != m_rx_value && (m_clock_state & CLK_RX)) + if(m_rx_clock_counter == 1 || m_rx_clock_counter == 15) + m_rx_clock_counter = 0; + m_rx_value = state; if(!m_rx_value && !(m_clock_state & CLK_RX) && m_rx_state != ST_IDLE && !m_cpu->standby()) clock_start(CLK_RX); @@ -329,231 +361,63 @@ void h8_sci_device::do_rx_w(int state) void h8_sci_device::do_clk_w(int state) { - if(m_ext_clock_value != state) { - m_ext_clock_value = state; - if(m_clock_state && !m_cpu->standby()) { - switch(m_clock_mode) { - case clock_mode_t::EXTERNAL_ASYNC: - if(m_ext_clock_value) { - m_tx_ext_clock_counter = (m_tx_ext_clock_counter+1) & 15; - m_rx_ext_clock_counter = (m_rx_ext_clock_counter+1) & 15; - - if((m_clock_state & CLK_TX) && m_tx_ext_clock_counter == 0) - tx_dropped_edge(); - if((m_clock_state & CLK_RX) && m_rx_ext_clock_counter == 8) - rx_raised_edge(); - } - break; - - case clock_mode_t::EXTERNAL_SYNC: - if((!m_ext_clock_value) && (m_clock_state & CLK_TX)) - tx_dropped_edge(); - - else if(m_ext_clock_value && (m_clock_state & CLK_RX)) - rx_raised_edge(); - break; - default: - // Do nothing - break; - } - } + if(m_ext_clock_value == state) + return; + + m_ext_clock_value = state; + if(!m_clock_state || m_cpu->standby()) + return; + + if(m_clock_mode == EXTERNAL_ASYNC) { + if(m_clock_state & CLK_TX) + tx_async_tick(); + if(m_clock_state & CLK_RX) + rx_async_tick(); + } else if(m_clock_mode == EXTERNAL_SYNC) { + if(m_clock_state & CLK_TX) + tx_sync_tick(); + if(m_clock_state & CLK_RX) + rx_sync_tick(); } } u64 h8_sci_device::internal_update(u64 current_time) { - u64 tx_event = 0, rx_event = 0; - switch(m_clock_mode) { - case clock_mode_t::INTERNAL_SYNC_OUT: - if(m_clock_state & CLK_TX) { - u64 fp = m_divider*2; - if(current_time >= m_tx_clock_base) { - u64 delta = current_time - m_tx_clock_base; - if(delta >= fp) { - delta -= fp; - m_tx_clock_base += fp; - } - assert(delta < fp); - - bool new_clock = delta >= m_divider; - if(new_clock != m_tx_clock_value) { - machine().scheduler().synchronize(); - if(!new_clock) - tx_dropped_edge(); - - m_tx_clock_value = new_clock; - if(m_clock_state || m_tx_clock_value) - m_cpu->do_sci_clk(m_id, m_tx_clock_value); - } - } - tx_event = m_tx_clock_base + (m_tx_clock_value ? fp : m_divider); - } - if(m_clock_state & CLK_RX) { - u64 fp = m_divider*2; - if(current_time >= m_rx_clock_base) { - u64 delta = current_time - m_rx_clock_base; - if(delta >= fp) { - delta -= fp; - m_rx_clock_base += fp; - } - assert(delta < fp); - - bool new_clock = delta >= m_divider; - if(new_clock != m_rx_clock_value) { - machine().scheduler().synchronize(); - if(new_clock) - rx_raised_edge(); - - m_rx_clock_value = new_clock; - } - } - rx_event = m_rx_clock_base + (m_rx_clock_value ? fp : m_divider); - } - break; - - case clock_mode_t::INTERNAL_ASYNC: - case clock_mode_t::INTERNAL_ASYNC_OUT: - if(m_clock_state & CLK_TX) { - u64 fp = m_divider*16; - if(current_time >= m_tx_clock_base) { - u64 delta = current_time - m_tx_clock_base; - if(delta >= fp) { - delta -= fp; - m_tx_clock_base += fp; - } - assert(delta < fp); - bool new_clock = delta >= m_divider*8; - if(new_clock != m_tx_clock_value) { - machine().scheduler().synchronize(); - if(!new_clock) - tx_dropped_edge(); - - m_tx_clock_value = new_clock; - if(m_clock_mode == clock_mode_t::INTERNAL_ASYNC_OUT && (m_clock_state || !m_tx_clock_value)) - m_cpu->do_sci_clk(m_id, m_tx_clock_value); - } - } - tx_event = m_tx_clock_base + (m_tx_clock_value ? fp : m_divider*8); - } - - if(m_clock_state & CLK_RX) { - u64 fp = m_divider*16; - if(current_time >= m_rx_clock_base) { - u64 delta = current_time - m_rx_clock_base; - if(delta >= fp) { - delta -= fp; - m_rx_clock_base += fp; - } - assert(delta < fp); - bool new_clock = delta >= m_divider*8; - if(new_clock != m_rx_clock_value) { - machine().scheduler().synchronize(); - if(new_clock) - rx_raised_edge(); - - m_rx_clock_value = new_clock; - if(m_clock_mode == clock_mode_t::INTERNAL_ASYNC_OUT && (m_clock_state || !m_rx_clock_value)) - m_cpu->do_sci_clk(m_id, m_rx_clock_value); - } - } - rx_event = m_rx_clock_base + (m_rx_clock_value ? fp : m_divider*8); - } - break; - - case clock_mode_t::EXTERNAL_RATE_SYNC: - if(m_clock_state & CLK_TX) { - u64 ctime = u64(current_time*m_internal_to_external_ratio*2); - if(ctime >= m_tx_clock_base) { - u64 delta = ctime - m_tx_clock_base; - m_tx_clock_base += delta & ~1; - delta &= 1; - bool new_clock = delta >= 1; - if(new_clock != m_tx_clock_value) { - machine().scheduler().synchronize(); - if(!new_clock) - tx_dropped_edge(); - - m_tx_clock_value = new_clock; - } - } - - tx_event = u64((m_tx_clock_base + (m_tx_clock_value ? 2 : 1))*m_external_to_internal_ratio)+1; - } - - if(m_clock_state & CLK_RX) { - u64 ctime = u64(current_time*m_internal_to_external_ratio*2); - if(ctime >= m_rx_clock_base) { - u64 delta = ctime - m_rx_clock_base; - m_rx_clock_base += delta & ~1; - delta &= 1; - bool new_clock = delta >= 1; - if(new_clock != m_rx_clock_value) { - machine().scheduler().synchronize(); - if(new_clock) - rx_raised_edge(); - - m_rx_clock_value = new_clock; - } - } - - rx_event = u64((m_rx_clock_base + (m_rx_clock_value ? 2 : 1))*m_external_to_internal_ratio)+1; - } - break; - - case clock_mode_t::EXTERNAL_RATE_ASYNC: - if(m_clock_state & CLK_TX) { - u64 ctime = u64(current_time*m_internal_to_external_ratio); - if(ctime >= m_tx_clock_base) { - u64 delta = ctime - m_tx_clock_base; - m_tx_clock_base += delta & ~15; - delta &= 15; - bool new_clock = delta >= 8; - if(new_clock != m_tx_clock_value) { - machine().scheduler().synchronize(); - if(!new_clock) - tx_dropped_edge(); - m_tx_clock_value = new_clock; - } - } + if(!m_clock_event || current_time < m_clock_event) + return m_clock_event; + + if(m_clock_mode == INTERNAL_ASYNC || m_clock_mode == INTERNAL_ASYNC_OUT || m_clock_mode == EXTERNAL_RATE_ASYNC) { + if(m_clock_state & CLK_TX) + tx_async_tick(); + if(m_clock_state & CLK_RX) + rx_async_tick(); + } else if(m_clock_mode == INTERNAL_SYNC_OUT || m_clock_mode == EXTERNAL_RATE_SYNC) { + if(m_clock_state & CLK_TX) + tx_sync_tick(); + if(m_clock_state & CLK_RX) + rx_sync_tick(); + } - tx_event = u64((m_tx_clock_base + (m_tx_clock_value ? 16 : 8))*m_external_to_internal_ratio)+1; - } - if(m_clock_state & CLK_RX) { - u64 ctime = u64(current_time*m_internal_to_external_ratio); - if(ctime >= m_rx_clock_base) { - u64 delta = ctime - m_rx_clock_base; - m_rx_clock_base += delta & ~15; - delta &= 15; - bool new_clock = delta >= 8; - if(new_clock != m_rx_clock_value) { - machine().scheduler().synchronize(); - if(new_clock) - rx_raised_edge(); - - m_rx_clock_value = new_clock; - } - } + if(m_clock_state) { + if(m_clock_step) + m_clock_event += m_clock_step; + else if(m_clock_mode == EXTERNAL_RATE_ASYNC || m_clock_mode == EXTERNAL_RATE_SYNC) + m_clock_event = u64(u64(m_clock_event * m_internal_to_external_ratio + 1) * m_external_to_internal_ratio + 1); + else + m_clock_event = 0; - rx_event = u64((m_rx_clock_base + (m_rx_clock_value ? 16 : 8))*m_external_to_internal_ratio)+1; + if(m_clock_event) { + m_sync_timer->adjust(attotime::from_ticks(m_clock_event - m_cpu->now_as_cycles(), m_cpu->clock())); + m_cpu->internal_update(); } - break; - case clock_mode_t::EXTERNAL_ASYNC: - case clock_mode_t::EXTERNAL_SYNC: - break; - } - u64 event = rx_event; - if(!event || (tx_event && tx_event < event)) - event = tx_event; - if(event) { - attotime ctime = machine().time(); - attotime sync_time = attotime::from_ticks(event-10, m_cpu->clock()); - if(m_cur_sync_time != sync_time && sync_time > ctime) { - m_sync_timer->adjust(sync_time - ctime); - m_cur_sync_time = sync_time; - } + } else if(!m_clock_state) { + m_clock_event = 0; + if(m_clock_mode == INTERNAL_ASYNC_OUT || m_clock_mode == INTERNAL_SYNC_OUT) + m_cpu->do_sci_clk(m_id, 1); } - return event; + + return m_clock_event; } void h8_sci_device::clock_start(int mode) @@ -562,48 +426,43 @@ void h8_sci_device::clock_start(int mode) if(m_clock_state & mode) return; - machine().scheduler().synchronize(); + if(mode == CLK_TX) + m_tx_clock_counter = 15; + else + m_rx_clock_counter = 15; + m_clock_state |= mode; + if(m_clock_state != mode) + return; + + m_clock_step = 0; + switch(m_clock_mode) { - case clock_mode_t::INTERNAL_ASYNC: - case clock_mode_t::INTERNAL_ASYNC_OUT: - case clock_mode_t::INTERNAL_SYNC_OUT: + case INTERNAL_ASYNC: + case INTERNAL_ASYNC_OUT: + case INTERNAL_SYNC_OUT: { LOGMASKED(LOG_CLOCK, "Starting internal clock\n"); - if(mode == CLK_TX) - m_tx_clock_base = machine().time().as_ticks(m_cpu->clock()); - else - m_rx_clock_base = machine().time().as_ticks(m_cpu->clock()); - m_cpu->internal_update(); - break; - - case clock_mode_t::EXTERNAL_RATE_ASYNC: - LOGMASKED(LOG_CLOCK, "Simulating external clock async\n"); - if(mode == CLK_TX) - m_tx_clock_base = u64(m_cpu->total_cycles()*m_internal_to_external_ratio); - else - m_rx_clock_base = u64(m_cpu->total_cycles()*m_internal_to_external_ratio); + m_clock_step = m_divider; + u64 now = mode == CLK_TX ? m_cpu->total_cycles() : m_cpu->now_as_cycles(); + m_clock_event = (now / m_clock_step + 1) * m_clock_step; + m_sync_timer->adjust(attotime::from_ticks(m_clock_event - now, m_cpu->clock())); m_cpu->internal_update(); break; + } - case clock_mode_t::EXTERNAL_RATE_SYNC: - LOGMASKED(LOG_CLOCK, "Simulating external clock sync\n"); - if(mode == CLK_TX) - m_tx_clock_base = u64(m_cpu->total_cycles()*2*m_internal_to_external_ratio); - else - m_rx_clock_base = u64(m_cpu->total_cycles()*2*m_internal_to_external_ratio); + case EXTERNAL_RATE_ASYNC: + case EXTERNAL_RATE_SYNC: { + LOGMASKED(LOG_CLOCK, "Simulating external clock\n", m_clock_mode == EXTERNAL_RATE_ASYNC ? "async" : "sync"); + u64 now = mode == CLK_TX ? m_cpu->total_cycles() : m_cpu->now_as_cycles(); + m_clock_event = u64(u64(now * m_internal_to_external_ratio + 1) * m_external_to_internal_ratio + 1); + m_sync_timer->adjust(attotime::from_ticks(m_clock_event - now, m_cpu->clock())); m_cpu->internal_update(); break; + } - case clock_mode_t::EXTERNAL_ASYNC: - LOGMASKED(LOG_CLOCK, "Waiting for external clock async\n"); - if(mode == CLK_TX) - m_tx_ext_clock_counter = 15; - else - m_rx_ext_clock_counter = 15; - break; - - case clock_mode_t::EXTERNAL_SYNC: - LOGMASKED(LOG_CLOCK, "Waiting for external clock sync\n"); + case EXTERNAL_ASYNC: + case EXTERNAL_SYNC: + LOGMASKED(LOG_CLOCK, "Waiting for external clock\n"); break; } } @@ -611,6 +470,11 @@ void h8_sci_device::clock_start(int mode) void h8_sci_device::clock_stop(int mode) { m_clock_state &= ~mode; + if(!m_clock_state) { + m_clock_event = 0; + m_clock_step = 0; + LOGMASKED(LOG_CLOCK, "Stopping clocks\n"); + } m_cpu->internal_update(); } @@ -634,9 +498,23 @@ void h8_sci_device::tx_start() rx_start(); } -void h8_sci_device::tx_dropped_edge() +void h8_sci_device::tx_async_tick() { - LOGMASKED(LOG_STATE, "tx_dropped_edge state=%s bit=%d\n", state_names[m_tx_state], m_tx_bit); + m_tx_clock_counter = (m_tx_clock_counter + 1) & 15; + LOGMASKED(LOG_TICK, "tx_async_tick %x\n", m_tx_clock_counter); + if(m_tx_clock_counter == 0) { + tx_async_step(); + + if(m_clock_mode == INTERNAL_ASYNC_OUT) + m_cpu->do_sci_clk(m_id, 0); + + } else if(m_tx_clock_counter == 8 && m_clock_mode == INTERNAL_ASYNC_OUT) + m_cpu->do_sci_clk(m_id, 1); +} + +void h8_sci_device::tx_async_step() +{ + LOGMASKED(LOG_STATE, "tx_async_step state=%s bit=%d\n", state_names[m_tx_state], m_tx_bit); switch(m_tx_state) { case ST_START: m_cpu->do_sci_tx(m_id, false); @@ -680,7 +558,7 @@ void h8_sci_device::tx_dropped_edge() m_tx_bit--; if(!m_tx_bit) { if(!(m_ssr & SSR_TDRE)) - tx_start(); + tx_start(); else { m_tx_state = ST_LAST_TICK; m_tx_bit = 0; @@ -708,6 +586,41 @@ void h8_sci_device::tx_dropped_edge() LOGMASKED(LOG_STATE, " -> state=%s bit=%d\n", state_names[m_tx_state], m_tx_bit); } +void h8_sci_device::tx_sync_tick() +{ + m_tx_clock_counter = (m_tx_clock_counter + 1) & 1; + LOGMASKED(LOG_TICK, "%s tx_sync_tick %x\n", machine().time().to_string(), m_tx_clock_counter); + if(m_tx_clock_counter == 0) { + tx_sync_step(); + + if(m_clock_mode == INTERNAL_SYNC_OUT) + m_cpu->do_sci_clk(m_id, 0); + + } else if(m_tx_clock_counter == 1 && m_clock_mode == INTERNAL_SYNC_OUT) + m_cpu->do_sci_clk(m_id, 1); +} + +void h8_sci_device::tx_sync_step() +{ + LOGMASKED(LOG_STATE, "tx_sync_step bit=%d\n", m_tx_bit); + m_cpu->do_sci_tx(m_id, m_tsr & 1); + m_tsr >>= 1; + m_tx_bit--; + if(!m_tx_bit) { + m_tx_state = ST_IDLE; + m_tx_bit = 0; + clock_stop(CLK_TX); + m_cpu->do_sci_tx(m_id, 1); + m_ssr |= SSR_TEND; + if(m_scr & SCR_TEIE) + m_intc->internal_interrupt(m_tei_int); + + // if there's more to send, start the transmitter + if((m_scr & SCR_TE) && !(m_ssr & SSR_TDRE)) + tx_start(); + } +} + void h8_sci_device::rx_start() { m_rx_parity = m_smr & SMR_OE ? 0 : 1; @@ -754,9 +667,17 @@ void h8_sci_device::rx_done() } } -void h8_sci_device::rx_raised_edge() +void h8_sci_device::rx_async_tick() { - LOGMASKED(LOG_STATE, "rx_raised_edge state=%s bit=%d\n", state_names[m_rx_state], m_rx_bit); + m_rx_clock_counter = (m_rx_clock_counter + 1) & 15; + LOGMASKED(LOG_TICK, "rx_async_tick %x\n", m_rx_clock_counter); + if(m_rx_clock_counter == 8) + rx_async_step(); +} + +void h8_sci_device::rx_async_step() +{ + LOGMASKED(LOG_STATE, "rx_async_step state=%s bit=%d\n", state_names[m_rx_state], m_rx_bit); switch(m_rx_state) { case ST_START: if(m_rx_value) { @@ -809,3 +730,23 @@ void h8_sci_device::rx_raised_edge() } LOGMASKED(LOG_STATE, " -> state=%s, bit=%d\n", state_names[m_rx_state], m_rx_bit); } + +void h8_sci_device::rx_sync_tick() +{ + m_rx_clock_counter = (m_rx_clock_counter + 1) & 1; + LOGMASKED(LOG_TICK, "rx_sync_tick %x\n", m_rx_clock_counter); + if(m_rx_clock_counter == 1) + rx_sync_step(); +} + +void h8_sci_device::rx_sync_step() +{ + LOGMASKED(LOG_STATE, "rx_sync_step bit=%d\n", m_rx_value); + m_rsr >>= 1; + if(m_rx_value) + m_rsr |= 0x80; + m_rx_bit--; + + if(!m_rx_bit) + rx_done(); +} diff --git a/src/devices/cpu/h8/h8_sci.h b/src/devices/cpu/h8/h8_sci.h index 170745fa668..5e5cda3db33 100644 --- a/src/devices/cpu/h8/h8_sci.h +++ b/src/devices/cpu/h8/h8_sci.h @@ -65,7 +65,7 @@ protected: CLK_RX = 2 }; - enum class clock_mode_t { + enum { INTERNAL_ASYNC, INTERNAL_ASYNC_OUT, EXTERNAL_ASYNC, @@ -112,29 +112,36 @@ protected: int m_id, m_eri_int, m_rxi_int, m_txi_int, m_tei_int; - int m_tx_state, m_rx_state, m_tx_bit, m_rx_bit, m_clock_state, m_tx_parity, m_rx_parity, m_tx_ext_clock_counter, m_rx_ext_clock_counter; - clock_mode_t m_clock_mode; - bool m_tx_clock_value, m_rx_clock_value, m_ext_clock_value, m_rx_value; + int m_tx_state, m_rx_state, m_tx_bit, m_rx_bit, m_clock_state, m_tx_parity, m_rx_parity, m_tx_clock_counter, m_rx_clock_counter; + u32 m_clock_mode; + bool m_ext_clock_value, m_rx_value; u8 m_rdr, m_tdr, m_smr, m_scr, m_ssr, m_brr, m_rsr, m_tsr; - u64 m_tx_clock_base, m_rx_clock_base, m_divider; + u64 m_clock_event, m_clock_step, m_divider; std::string m_last_clock_message; void device_start() override; void device_reset() override; - void device_post_load() override; TIMER_CALLBACK_MEMBER(sync_tick); void clock_start(int mode); void clock_stop(int mode); void clock_update(); + void tx_start(); - void tx_dropped_edge(); + void tx_async_tick(); + void tx_async_step(); + void tx_sync_tick(); + void tx_sync_step(); + void rx_start(); void rx_done(); - void rx_raised_edge(); + void rx_async_tick(); + void rx_async_step(); + void rx_sync_tick(); + void rx_sync_step(); bool is_sync_start() const; bool has_recv_error() const; diff --git a/src/mame/namco/namcos23.cpp b/src/mame/namco/namcos23.cpp index bfc88453a04..07884d40f1e 100644 --- a/src/mame/namco/namcos23.cpp +++ b/src/mame/namco/namcos23.cpp @@ -3365,7 +3365,7 @@ void namcos23_state::s23iobrdmap(address_map &map) { map(0x0000, 0x1fff).rom().region("iocpu", 0); map(0x6000, 0x6001).portr("IN01"); - map(0x6002, 0x6003).portr("IN23"); + map(0x6002, 0x6003).portr("IN23").nopw(); map(0x6004, 0x6005).nopw(); map(0x6006, 0x6007).noprw(); map(0xc000, 0xfb7f).ram(); -- cgit v1.2.3