mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
h8_sci: Entirely revise clocking
This commit is contained in:
parent
5466b7f0c9
commit
094d06e5d7
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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_ext_clock_value == state)
|
||||
return;
|
||||
|
||||
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;
|
||||
m_ext_clock_value = state;
|
||||
if(!m_clock_state || m_cpu->standby())
|
||||
return;
|
||||
|
||||
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_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);
|
||||
if(!m_clock_event || current_time < m_clock_event)
|
||||
return m_clock_event;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
rx_event = u64((m_rx_clock_base + (m_rx_clock_value ? 16 : 8))*m_external_to_internal_ratio)+1;
|
||||
}
|
||||
break;
|
||||
|
||||
case clock_mode_t::EXTERNAL_ASYNC:
|
||||
case clock_mode_t::EXTERNAL_SYNC:
|
||||
break;
|
||||
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();
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
} 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_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_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);
|
||||
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_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);
|
||||
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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user