mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +03:00
z80sio updates:
* Don't use device_serial_interface for transmit - it can't support sync modes, on-the-fly register updates, and other weirdness. * Better modelling of 1-deep transmit queue. * Better RTS/CTS behaviour. * Completely overhauled interrupt logic - vectors should be correct for most async modes. * Implemented different auto-reset receive errors in MPSC vs SIO. * Implemented SDLC transmission including bit stuffing, transmit CRC, abort, and underrun/end-of-message behaviour. Added an SDLC consumer device that logs SNA frame headers and data.
This commit is contained in:
parent
4c9bac79ff
commit
46c4dfb5f9
@ -29,6 +29,8 @@ files {
|
||||
MAME_DIR .. "src/devices/machine/ram.h",
|
||||
MAME_DIR .. "src/devices/machine/legscsi.cpp",
|
||||
MAME_DIR .. "src/devices/machine/legscsi.h",
|
||||
MAME_DIR .. "src/devices/machine/sdlc.cpp",
|
||||
MAME_DIR .. "src/devices/machine/sdlc.h",
|
||||
MAME_DIR .. "src/devices/machine/terminal.cpp",
|
||||
MAME_DIR .. "src/devices/machine/terminal.h",
|
||||
MAME_DIR .. "src/devices/machine/timer.cpp",
|
||||
|
298
src/devices/machine/sdlc.cpp
Normal file
298
src/devices/machine/sdlc.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
|
||||
#include "emu.h"
|
||||
#include "sdlc.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_RXBIT (1U << 1)
|
||||
#define LOG_RXFLAG (1U << 2)
|
||||
#define LOG_LINESTATE (1U << 3)
|
||||
#define LOG_FRAMING (1U << 4)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL | LOG_RXBIT | LOG_RXFLAG | LOG_LINESTATE | LOG_FRAMING)
|
||||
#include "logmacro.h"
|
||||
|
||||
#define LOGRXBIT(...) LOGMASKED(LOG_RXBIT, __VA_ARGS__)
|
||||
#define LOGRXFLAG(...) LOGMASKED(LOG_RXFLAG, __VA_ARGS__)
|
||||
#define LOGLINESTATE(...) LOGMASKED(LOG_LINESTATE, __VA_ARGS__)
|
||||
#define LOGFRAMING(...) LOGMASKED(LOG_FRAMING, __VA_ARGS__)
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(SDLC_LOGGER, sdlc_logger_device, "sdlc_logger", "SDLC/HDLC logger")
|
||||
|
||||
|
||||
constexpr std::uint16_t device_sdlc_consumer_interface::POLY_SDLC;
|
||||
|
||||
|
||||
device_sdlc_consumer_interface::device_sdlc_consumer_interface(machine_config const &mconfig, device_t &device) :
|
||||
device_interface(device, "sdlc_consumer"),
|
||||
m_line_active(0U),
|
||||
m_discard_bits(0U),
|
||||
m_in_frame(0U),
|
||||
m_shift_register(0xffffU),
|
||||
m_frame_check(0xffffU)
|
||||
{
|
||||
}
|
||||
|
||||
void device_sdlc_consumer_interface::interface_post_start()
|
||||
{
|
||||
device().save_item(NAME(m_line_active));
|
||||
device().save_item(NAME(m_discard_bits));
|
||||
device().save_item(NAME(m_in_frame));
|
||||
device().save_item(NAME(m_shift_register));
|
||||
device().save_item(NAME(m_frame_check));
|
||||
}
|
||||
|
||||
void device_sdlc_consumer_interface::rx_bit(bool state)
|
||||
{
|
||||
LOGRXBIT("Received bit %u\n", state ? 1U : 0U);
|
||||
|
||||
m_shift_register = (m_shift_register >> 1) | (state ? 0x8000U : 0x0000U);
|
||||
if (!state && !m_line_active)
|
||||
{
|
||||
// any zero bit means the line has become active
|
||||
LOGLINESTATE("Line became active\n");
|
||||
m_line_active = 1U;
|
||||
line_active();
|
||||
}
|
||||
|
||||
if ((m_shift_register & 0xff00U) == 0x7e00U)
|
||||
{
|
||||
// a flag opens and closes frames
|
||||
LOGRXFLAG("Received flag\n");
|
||||
if (m_in_frame)
|
||||
{
|
||||
LOGFRAMING("End of frame\n");
|
||||
m_in_frame = 0U;
|
||||
frame_end();
|
||||
}
|
||||
m_discard_bits = 8U;
|
||||
m_frame_check = 0xffffU;
|
||||
}
|
||||
else if ((m_shift_register & 0xfffeU) == 0xfffeU)
|
||||
{
|
||||
// fifteen consecutive ones is an inactive line condition
|
||||
if (m_line_active)
|
||||
{
|
||||
LOGLINESTATE("Line became inactive\n");
|
||||
m_line_active = 0U;
|
||||
line_inactive();
|
||||
}
|
||||
}
|
||||
else if ((m_shift_register & 0xfe00U) == 0xfe00U)
|
||||
{
|
||||
// seven consecutive ones is a frame abort
|
||||
if (m_in_frame || m_discard_bits)
|
||||
{
|
||||
LOGFRAMING("Received frame abort\n");
|
||||
m_in_frame = 0U;
|
||||
m_discard_bits = 0U;
|
||||
frame_abort();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// discard the flag as it shifts off
|
||||
if (m_discard_bits && !--m_discard_bits)
|
||||
{
|
||||
LOGFRAMING("Start of frame\n");
|
||||
m_in_frame = 1U;
|
||||
frame_start();
|
||||
}
|
||||
|
||||
// discard a zero after five consecutive ones
|
||||
if (m_in_frame && ((m_shift_register & 0x01f8U) != 0x00f8U))
|
||||
{
|
||||
bool const bit(BIT(m_shift_register, 8));
|
||||
m_frame_check = update_frame_check(POLY_SDLC, m_frame_check, bit);
|
||||
data_bit(bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void device_sdlc_consumer_interface::rx_reset()
|
||||
{
|
||||
LOG("Receive reset\n");
|
||||
|
||||
m_line_active = 0U;
|
||||
m_in_frame = 0U;
|
||||
m_discard_bits = 0U;
|
||||
m_shift_register = 0xffffU;
|
||||
m_frame_check = 0xffffU;
|
||||
}
|
||||
|
||||
|
||||
sdlc_logger_device::sdlc_logger_device(machine_config const &mconfig, char const *tag, device_t *owner, std::uint32_t clock) :
|
||||
device_t(mconfig, SDLC_LOGGER, tag, owner, clock),
|
||||
device_sdlc_consumer_interface(mconfig, *this),
|
||||
m_data_nrzi(0U),
|
||||
m_clock_active(1U),
|
||||
m_current_data(1U),
|
||||
m_last_data(1U),
|
||||
m_current_clock(1U),
|
||||
m_frame_bits(0U),
|
||||
m_buffer()
|
||||
{
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(sdlc_logger_device::clock_w)
|
||||
{
|
||||
if (bool(state) != bool(m_current_clock))
|
||||
{
|
||||
m_current_clock = state ? 1U : 0U;
|
||||
if (m_current_clock == m_clock_active)
|
||||
{
|
||||
bool const bit(m_data_nrzi ? (m_current_data == m_last_data) : m_current_data);
|
||||
LOGRXBIT("Received bit: %u (%u -> %u)\n", bit ? 1U : 0U, m_last_data, m_current_data);
|
||||
m_last_data = m_current_data;
|
||||
rx_bit(bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sdlc_logger_device::device_start()
|
||||
{
|
||||
m_buffer.reset(new std::uint8_t[BUFFER_BYTES]);
|
||||
|
||||
save_item(NAME(m_data_nrzi));
|
||||
save_item(NAME(m_clock_active));
|
||||
save_item(NAME(m_current_data));
|
||||
save_item(NAME(m_last_data));
|
||||
save_item(NAME(m_current_clock));
|
||||
save_item(NAME(m_frame_bits));
|
||||
save_pointer(NAME(m_buffer.get()), BUFFER_BYTES);
|
||||
}
|
||||
|
||||
void sdlc_logger_device::device_reset()
|
||||
{
|
||||
}
|
||||
|
||||
void sdlc_logger_device::frame_start()
|
||||
{
|
||||
m_frame_bits = 0U;
|
||||
m_expected_fcs = 0xffffU;
|
||||
}
|
||||
|
||||
void sdlc_logger_device::frame_end()
|
||||
{
|
||||
shift_residual_bits();
|
||||
log_frame(false);
|
||||
}
|
||||
|
||||
void sdlc_logger_device::frame_abort()
|
||||
{
|
||||
logerror("Frame aborted!\n");
|
||||
shift_residual_bits();
|
||||
log_frame(true);
|
||||
}
|
||||
|
||||
void sdlc_logger_device::data_bit(bool value)
|
||||
{
|
||||
if (BUFFER_BITS > m_frame_bits)
|
||||
{
|
||||
m_buffer[m_frame_bits >> 3] >>= 1;
|
||||
m_buffer[m_frame_bits >> 3] |= value ? 0x80U : 0x00U;
|
||||
}
|
||||
else if (BUFFER_BITS == m_frame_bits)
|
||||
{
|
||||
logerror("Frame buffer overrun!\n");
|
||||
}
|
||||
|
||||
if ((16U <= m_frame_bits) && ((BUFFER_BITS + 16U) > m_frame_bits))
|
||||
m_expected_fcs = update_frame_check(POLY_SDLC, m_expected_fcs, BIT(m_buffer[(m_frame_bits - 16U) >> 3], m_frame_bits & 0x0007U));
|
||||
|
||||
++m_frame_bits;
|
||||
}
|
||||
|
||||
void sdlc_logger_device::shift_residual_bits()
|
||||
{
|
||||
if (BUFFER_BITS > m_frame_bits)
|
||||
{
|
||||
uint32_t const residual_bits(m_frame_bits & 0x0007U);
|
||||
if (residual_bits)
|
||||
m_buffer[m_frame_bits >> 3] >>= 8 - residual_bits;
|
||||
}
|
||||
}
|
||||
|
||||
void sdlc_logger_device::log_frame(bool partial) const
|
||||
{
|
||||
if (m_frame_bits)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
std::uint32_t const frame_bytes(m_frame_bits >> 3);
|
||||
std::uint32_t const residual_bits(m_frame_bits & 0x0007U);
|
||||
util::stream_format(msg, "Received %u-bit %sframe (%u bytes + %u bits)", m_frame_bits, partial ? "partial " : "", frame_bytes, residual_bits);
|
||||
|
||||
if (8U <= m_frame_bits)
|
||||
{
|
||||
std::uint8_t const addr(m_buffer[0]);
|
||||
util::stream_format(msg, " A=%02X%s", addr, (0xffU == addr) ? " (broadcast)" : !addr ? " (no station)" : "");
|
||||
}
|
||||
|
||||
if (16U <= m_frame_bits)
|
||||
{
|
||||
std::uint8_t const ctrl(m_buffer[1]);
|
||||
if (!BIT(ctrl, 0))
|
||||
{
|
||||
msg << " I";
|
||||
}
|
||||
else if (!BIT(ctrl, 1))
|
||||
{
|
||||
msg << " S";
|
||||
switch (ctrl & 0x0cU)
|
||||
{
|
||||
case 0x00U: msg << " RR"; break;
|
||||
case 0x04U: msg << " RNR"; break;
|
||||
case 0x08U: msg << " REJ"; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg << " U";
|
||||
switch (ctrl & 0xecU)
|
||||
{
|
||||
case 0x00U: msg << " UI"; break;
|
||||
case 0x04U: msg << " RIM/SIM"; break;
|
||||
case 0x0cU: msg << " DM"; break;
|
||||
case 0x20U: msg << " UP"; break;
|
||||
case 0x40U: msg << " DISC/RD"; break;
|
||||
case 0x60U: msg << " UA"; break;
|
||||
case 0x80U: msg << " SNRM"; break;
|
||||
case 0x84U: msg << " FRMR"; break;
|
||||
case 0x9cU: msg << " XID"; break;
|
||||
case 0xc4U: msg << " CFGR"; break;
|
||||
case 0xccU: msg << " SNRME"; break;
|
||||
case 0xe0U: msg << " TEST"; break;
|
||||
case 0xecU: msg << " BCN"; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!partial && (BUFFER_BITS >= m_frame_bits))
|
||||
{
|
||||
std::uint16_t fcs;
|
||||
fcs = std::uint16_t(m_buffer[frame_bytes - 2]) >> residual_bits;
|
||||
fcs |= std::uint16_t(m_buffer[frame_bytes - 1]) << (8 - residual_bits);
|
||||
if (residual_bits)
|
||||
fcs |= (std::uint16_t(m_buffer[frame_bytes]) & ((1U << residual_bits) - 1U)) << (16 - residual_bits);
|
||||
fcs = ~BITSWAP16(fcs, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
|
||||
util::stream_format(msg, " FCS=%04X", fcs);
|
||||
if (!is_frame_check_good())
|
||||
util::stream_format(msg, " (expected %04X)", m_expected_fcs);
|
||||
}
|
||||
}
|
||||
|
||||
if (!partial)
|
||||
msg << (is_frame_check_good() ? " (good)" : " (bad)");
|
||||
|
||||
for (std::uint32_t i = 0U; (frame_bytes > i) && (BUFFER_BYTES > i); ++i)
|
||||
util::stream_format(msg, (i & 0x000fU) ? " %02X" : "\n %02X", m_buffer[i]);
|
||||
if (residual_bits && (BUFFER_BITS >= m_frame_bits))
|
||||
util::stream_format(msg, (residual_bits > 4) ? "%s %02X&%02X" : "%s %01X&%01X", (frame_bytes & 0x000fU) ? "" : "\n ", m_buffer[frame_bytes], (1U << residual_bits) - 1);
|
||||
|
||||
logerror("%s\n", msg.str());
|
||||
}
|
||||
}
|
116
src/devices/machine/sdlc.h
Normal file
116
src/devices/machine/sdlc.h
Normal file
@ -0,0 +1,116 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
#ifndef MAME_MACHINE_SDLC_H
|
||||
#define MAME_MACHINE_SDLC_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
|
||||
#define MCFG_SDLC_LOGGER_DATA_NRZL \
|
||||
downcast<sdlc_logger_device &>(*device).clock_active(0);
|
||||
|
||||
#define MCFG_SDLC_LOGGER_DATA_NRZI \
|
||||
downcast<sdlc_logger_device &>(*device).clock_active(1);
|
||||
|
||||
#define MCFG_SDLC_LOGGER_CLOCK_ACTIVE_RISING \
|
||||
downcast<sdlc_logger_device &>(*device).clock_active(1);
|
||||
|
||||
#define MCFG_SDLC_LOGGER_CLOCK_ACTIVE_FALLING \
|
||||
downcast<sdlc_logger_device &>(*device).clock_active(0);
|
||||
|
||||
|
||||
class device_sdlc_consumer_interface : public device_interface
|
||||
{
|
||||
public:
|
||||
static constexpr std::uint16_t POLY_SDLC = 0x1021U;
|
||||
|
||||
template <typename T>
|
||||
static constexpr u16 update_frame_check(u16 poly, u16 current, T bit)
|
||||
{
|
||||
return (current << 1) ^ ((bool(bit) != bool(BIT(current, 15))) ? poly : 0U);
|
||||
}
|
||||
|
||||
protected:
|
||||
device_sdlc_consumer_interface(machine_config const &mconfig, device_t &device);
|
||||
|
||||
virtual void interface_post_start() override;
|
||||
|
||||
void rx_bit(bool state);
|
||||
void rx_reset();
|
||||
|
||||
bool is_line_active() const { return bool(m_line_active); }
|
||||
uint16_t get_frame_check() const { return m_frame_check; }
|
||||
bool is_frame_check_good() const { return 0x1d0fU == m_frame_check; }
|
||||
|
||||
private:
|
||||
template <typename... Params> void logerror(Params &&... args) { device().logerror(std::forward<Params>(args)...); }
|
||||
|
||||
virtual void frame_start() { }
|
||||
virtual void frame_end() { }
|
||||
virtual void frame_abort() { }
|
||||
virtual void line_active() { }
|
||||
virtual void line_inactive() { }
|
||||
virtual void data_bit(bool value) { }
|
||||
|
||||
std::uint8_t m_line_active;
|
||||
std::uint8_t m_discard_bits;
|
||||
std::uint8_t m_in_frame;
|
||||
std::uint16_t m_shift_register;
|
||||
std::uint16_t m_frame_check;
|
||||
};
|
||||
|
||||
|
||||
class sdlc_logger_device : public device_t, public device_sdlc_consumer_interface
|
||||
{
|
||||
public:
|
||||
sdlc_logger_device(machine_config const &mconfig, char const *tag, device_t *owner, std::uint32_t clock);
|
||||
|
||||
// input signals
|
||||
DECLARE_WRITE_LINE_MEMBER(data_w) { m_current_data = state ? 1U : 0U; }
|
||||
DECLARE_WRITE_LINE_MEMBER(clock_w);
|
||||
|
||||
// input format configuration
|
||||
DECLARE_WRITE_LINE_MEMBER(data_nrzi) { m_data_nrzi = state ? 1U : 0U; }
|
||||
DECLARE_WRITE_LINE_MEMBER(clock_active) { m_clock_active = state ? 1U : 0U; }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
using device_t::logerror;
|
||||
|
||||
private:
|
||||
enum : std::size_t
|
||||
{
|
||||
BUFFER_BYTES = 1024U,
|
||||
BUFFER_BITS = BUFFER_BYTES << 3
|
||||
};
|
||||
|
||||
virtual void frame_start() override;
|
||||
virtual void frame_end() override;
|
||||
virtual void frame_abort() override;
|
||||
virtual void data_bit(bool value) override;
|
||||
|
||||
void shift_residual_bits();
|
||||
void log_frame(bool partial) const;
|
||||
|
||||
std::uint8_t m_data_nrzi;
|
||||
std::uint8_t m_clock_active;
|
||||
|
||||
std::uint8_t m_current_data;
|
||||
std::uint8_t m_last_data;
|
||||
std::uint8_t m_current_clock;
|
||||
|
||||
std::uint32_t m_frame_bits;
|
||||
std::uint16_t m_expected_fcs;
|
||||
std::unique_ptr<std::uint8_t []> m_buffer;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SDLC_LOGGER, sdlc_logger_device)
|
||||
|
||||
#endif // MAME_MACHINE_SDLC_H
|
File diff suppressed because it is too large
Load Diff
@ -126,17 +126,15 @@
|
||||
|
||||
class z80sio_device;
|
||||
|
||||
class z80sio_channel : public device_t, public device_serial_interface
|
||||
class z80sio_channel : public device_t
|
||||
{
|
||||
friend class z80sio_device;
|
||||
friend class i8274_new_device;
|
||||
friend class upd7201_new_device;
|
||||
|
||||
public:
|
||||
z80sio_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device_serial_interface overrides
|
||||
virtual void tra_callback() override;
|
||||
virtual void tra_complete() override;
|
||||
|
||||
// read register handlers
|
||||
uint8_t do_sioreg_rr0();
|
||||
uint8_t do_sioreg_rr1();
|
||||
@ -160,8 +158,6 @@ public:
|
||||
void data_write(uint8_t data);
|
||||
|
||||
void receive_reset();
|
||||
void receive_data();
|
||||
void advance_rx_fifo();
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( write_rx ) { m_rxd = state; }
|
||||
DECLARE_WRITE_LINE_MEMBER( cts_w );
|
||||
@ -174,7 +170,6 @@ public:
|
||||
// read registers enum
|
||||
uint8_t m_rr0; // REG_RR0_STATUS
|
||||
uint8_t m_rr1; // REG_RR1_SPEC_RCV_COND
|
||||
uint8_t m_rr2; // REG_RR2_INTERRUPT_VECT
|
||||
// write registers enum
|
||||
uint8_t m_wr0; // REG_WR0_COMMAND_REGPT
|
||||
uint8_t m_wr1; // REG_WR1_INT_DMA_ENABLE
|
||||
@ -185,15 +180,12 @@ public:
|
||||
uint8_t m_wr6; // REG_WR6_SYNC_OR_SDLC_A
|
||||
uint8_t m_wr7; // REG_WR7_SYNC_OR_SDLC_F
|
||||
|
||||
int m_variant; // Set in device
|
||||
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
INT_TRANSMIT = 0,
|
||||
INT_EXTERNAL,
|
||||
INT_RECEIVE,
|
||||
INT_SPECIAL
|
||||
INT_RECEIVE
|
||||
};
|
||||
|
||||
enum
|
||||
@ -224,136 +216,13 @@ protected:
|
||||
REG_WR7_SYNC_OR_SDLC_F = 7
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RR0_RX_CHAR_AVAILABLE = 0x01,
|
||||
RR0_INTERRUPT_PENDING = 0x02,
|
||||
RR0_TX_BUFFER_EMPTY = 0x04,
|
||||
RR0_DCD = 0x08,
|
||||
RR0_SYNC_HUNT = 0x10,
|
||||
RR0_CTS = 0x20,
|
||||
RR0_TX_UNDERRUN = 0x40,
|
||||
RR0_BREAK_ABORT = 0x80
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RR1_ALL_SENT = 0x01,
|
||||
RR1_RESIDUE_CODE_MASK = 0x0e,
|
||||
RR1_PARITY_ERROR = 0x10,
|
||||
RR1_RX_OVERRUN_ERROR = 0x20,
|
||||
RR1_CRC_FRAMING_ERROR = 0x40,
|
||||
RR1_END_OF_FRAME = 0x80
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
RR2_INT_VECTOR_MASK = 0xff,
|
||||
RR2_INT_VECTOR_V1 = 0x02,
|
||||
RR2_INT_VECTOR_V2 = 0x04,
|
||||
RR2_INT_VECTOR_V3 = 0x08
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR0_REGISTER_MASK = 0x07,
|
||||
WR0_COMMAND_MASK = 0x38,
|
||||
WR0_NULL = 0x00,
|
||||
WR0_SEND_ABORT = 0x08,
|
||||
WR0_RESET_EXT_STATUS = 0x10,
|
||||
WR0_CHANNEL_RESET = 0x18,
|
||||
WR0_ENABLE_INT_NEXT_RX = 0x20,
|
||||
WR0_RESET_TX_INT = 0x28,
|
||||
WR0_ERROR_RESET = 0x30,
|
||||
WR0_RETURN_FROM_INT = 0x38,
|
||||
WR0_CRC_RESET_CODE_MASK = 0xc0,
|
||||
WR0_CRC_RESET_NULL = 0x00,
|
||||
WR0_CRC_RESET_RX = 0x40,
|
||||
WR0_CRC_RESET_TX = 0x80,
|
||||
WR0_CRC_RESET_TX_UNDERRUN = 0xc0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR1_EXT_INT_ENABLE = 0x01,
|
||||
WR1_TX_INT_ENABLE = 0x02,
|
||||
WR1_STATUS_VECTOR = 0x04,
|
||||
WR1_RX_INT_MODE_MASK = 0x18,
|
||||
WR1_RX_INT_DISABLE = 0x00,
|
||||
WR1_RX_INT_FIRST = 0x08,
|
||||
WR1_RX_INT_ALL_PARITY = 0x10,
|
||||
WR1_RX_INT_ALL = 0x18,
|
||||
WR1_WRDY_ON_RX_TX = 0x20,
|
||||
WR1_WRDY_FUNCTION = 0x40, // WAIT not supported
|
||||
WR1_WRDY_ENABLE = 0x80
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR2_DATA_XFER_INT = 0x00, // not supported
|
||||
WR2_DATA_XFER_DMA_INT = 0x01, // not supported
|
||||
WR2_DATA_XFER_DMA = 0x02, // not supported
|
||||
WR2_DATA_XFER_ILLEGAL = 0x03, // not supported
|
||||
WR2_DATA_XFER_MASK = 0x03, // not supported
|
||||
WR2_PRIORITY = 0x04, // not supported
|
||||
WR2_MODE_8085_1 = 0x00, // not supported
|
||||
WR2_MODE_8085_2 = 0x08, // not supported
|
||||
WR2_MODE_8086_8088 = 0x10, // not supported
|
||||
WR2_MODE_ILLEGAL = 0x18, // not supported
|
||||
WR2_MODE_MASK = 0x18, // not supported
|
||||
WR2_VECTORED_INT = 0x20, // not supported
|
||||
WR2_PIN10_SYNDETB_RTSB = 0x80 // not supported
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR3_RX_ENABLE = 0x01,
|
||||
WR3_SYNC_CHAR_LOAD_INHIBIT= 0x02, // not supported
|
||||
WR3_ADDRESS_SEARCH_MODE = 0x04, // not supported
|
||||
WR3_RX_CRC_ENABLE = 0x08, // not supported
|
||||
WR3_ENTER_HUNT_PHASE = 0x10, // not supported
|
||||
WR3_AUTO_ENABLES = 0x20,
|
||||
WR3_RX_WORD_LENGTH_MASK = 0xc0,
|
||||
WR3_RX_WORD_LENGTH_5 = 0x00,
|
||||
WR3_RX_WORD_LENGTH_7 = 0x40,
|
||||
WR3_RX_WORD_LENGTH_6 = 0x80,
|
||||
WR3_RX_WORD_LENGTH_8 = 0xc0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR4_PARITY_ENABLE = 0x01,
|
||||
WR4_PARITY_EVEN = 0x02,
|
||||
WR4_STOP_BITS_MASK = 0x0c,
|
||||
WR4_STOP_BITS_1 = 0x04,
|
||||
WR4_STOP_BITS_1_5 = 0x08, // not supported
|
||||
WR4_STOP_BITS_2 = 0x0c,
|
||||
WR4_SYNC_MODE_MASK = 0x30, // not supported
|
||||
WR4_SYNC_MODE_8_BIT = 0x00, // not supported
|
||||
WR4_SYNC_MODE_16_BIT = 0x10, // not supported
|
||||
WR4_SYNC_MODE_SDLC = 0x20, // not supported
|
||||
WR4_SYNC_MODE_EXT = 0x30, // not supported
|
||||
WR4_CLOCK_RATE_MASK = 0xc0,
|
||||
WR4_CLOCK_RATE_X1 = 0x00,
|
||||
WR4_CLOCK_RATE_X16 = 0x40,
|
||||
WR4_CLOCK_RATE_X32 = 0x80,
|
||||
WR4_CLOCK_RATE_X64 = 0xc0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR5_TX_CRC_ENABLE = 0x01, // not supported
|
||||
WR5_RTS = 0x02,
|
||||
WR5_CRC16 = 0x04, // not supported
|
||||
WR5_TX_ENABLE = 0x08,
|
||||
WR5_SEND_BREAK = 0x10,
|
||||
WR5_TX_WORD_LENGTH_MASK = 0x60,
|
||||
WR5_TX_WORD_LENGTH_5 = 0x00,
|
||||
WR5_TX_WORD_LENGTH_6 = 0x40,
|
||||
WR5_TX_WORD_LENGTH_7 = 0x20,
|
||||
WR5_TX_WORD_LENGTH_8 = 0x60,
|
||||
WR5_DTR = 0x80
|
||||
};
|
||||
z80sio_channel(
|
||||
const machine_config &mconfig,
|
||||
device_type type,
|
||||
const char *tag,
|
||||
device_t *owner,
|
||||
uint32_t clock,
|
||||
uint8_t rr1_auto_reset);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_resolve_objects() override;
|
||||
@ -361,15 +230,14 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
|
||||
void update_serial();
|
||||
void update_rts();
|
||||
void update_dtr_rts_break();
|
||||
void set_dtr(int state);
|
||||
void set_rts(int state);
|
||||
void set_ready(bool ready);
|
||||
|
||||
int get_clock_mode();
|
||||
stop_bits_t get_stop_bits();
|
||||
int get_rx_word_length();
|
||||
int get_tx_word_length();
|
||||
int get_tx_word_length() const;
|
||||
int get_tx_word_length(uint8_t data) const;
|
||||
|
||||
// receiver state
|
||||
int m_rx_fifo_depth;
|
||||
@ -387,21 +255,66 @@ protected:
|
||||
|
||||
int m_rxd;
|
||||
int m_sh; // sync hunt
|
||||
int m_cts; // clear to send latch
|
||||
int m_dcd; // data carrier detect latch
|
||||
|
||||
// transmitter state
|
||||
uint8_t m_tx_data; // transmit data register
|
||||
int m_tx_clock; // transmit clock pulse count
|
||||
uint8_t m_tx_data;
|
||||
|
||||
int m_tx_clock; // transmit clock line state
|
||||
int m_tx_count; // clocks until next bit transition
|
||||
int m_tx_bits; // remaining bits in shift register
|
||||
int m_tx_parity; // parity enable/disable
|
||||
int m_tx_framing; // currnetly transmitting framing bits
|
||||
int m_tx_special; // special conditions (SDLC FCS/abort)
|
||||
uint16_t m_tx_sr; // transmit shift register
|
||||
uint16_t m_tx_crc; // calculated transmit checksum
|
||||
uint8_t m_tx_hist; // transmit history (for bitstuffing)
|
||||
|
||||
int m_txd;
|
||||
int m_dtr; // data terminal ready
|
||||
int m_rts; // request to send
|
||||
|
||||
// external/status monitoring
|
||||
int m_ext_latched; // changed data lines
|
||||
int m_cts; // clear to send line state
|
||||
int m_dcd; // data carrier detect line state
|
||||
int m_sync; // sync line state
|
||||
|
||||
// synchronous state
|
||||
uint16_t m_sync; // sync character
|
||||
|
||||
int m_index;
|
||||
z80sio_device *m_uart;
|
||||
|
||||
private:
|
||||
// helpers
|
||||
void out_txd_cb(int state);
|
||||
void out_rts_cb(int state);
|
||||
void out_dtr_cb(int state);
|
||||
bool transmit_allowed() const;
|
||||
|
||||
void receive_data();
|
||||
void advance_rx_fifo();
|
||||
|
||||
void transmit_enable();
|
||||
void transmit_complete();
|
||||
void async_tx_setup();
|
||||
void sdlc_tx_sr_empty();
|
||||
void tx_setup(uint16_t data, int bits, int parity, int framing);
|
||||
void tx_setup_flag();
|
||||
|
||||
void reset_ext_status();
|
||||
void read_ext();
|
||||
void trigger_ext_int();
|
||||
|
||||
uint8_t const m_rr1_auto_reset;
|
||||
};
|
||||
|
||||
|
||||
// ======================> i8274_channel
|
||||
|
||||
class i8274_channel : public z80sio_channel
|
||||
{
|
||||
public:
|
||||
i8274_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
|
||||
@ -454,7 +367,7 @@ public:
|
||||
DECLARE_WRITE8_MEMBER( cb_w ) { m_chanB->control_write(data); }
|
||||
|
||||
// interrupt acknowledge
|
||||
int m1_r();
|
||||
virtual int m1_r();
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_chanA->write_rx(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_chanB->write_rx(state); }
|
||||
@ -471,7 +384,7 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_chanB->sync_w(state); }
|
||||
|
||||
protected:
|
||||
z80sio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant);
|
||||
z80sio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_resolve_objects() override;
|
||||
@ -487,18 +400,13 @@ protected:
|
||||
// internal interrupt management
|
||||
void check_interrupts();
|
||||
void reset_interrupts();
|
||||
int get_interrupt_prio(int index, int type);
|
||||
uint8_t modify_vector(int index, int type);
|
||||
void trigger_interrupt(int index, int state);
|
||||
int get_channel_index(z80sio_channel *ch) { return (ch == m_chanA) ? 0 : 1; }
|
||||
void trigger_interrupt(int index, int type);
|
||||
void clear_interrupt(int index, int type);
|
||||
void return_from_interrupt();
|
||||
virtual uint8_t read_vector();
|
||||
virtual int const *interrupt_priorities() const;
|
||||
|
||||
// CPU types that has slightly different behaviour
|
||||
enum
|
||||
{
|
||||
TYPE_Z80SIO = 0x001,
|
||||
TYPE_UPD7201 = 0x002,
|
||||
TYPE_I8274 = 0x004
|
||||
};
|
||||
int get_channel_index(z80sio_channel const *ch) const { return (ch == m_chanA) ? 0 : 1; }
|
||||
|
||||
enum
|
||||
{
|
||||
@ -530,26 +438,39 @@ protected:
|
||||
|
||||
int m_int_state[8]; // interrupt state
|
||||
int m_int_source[8]; // interrupt source
|
||||
int m_variant;
|
||||
const char *m_cputag;
|
||||
};
|
||||
|
||||
class upd7201_new_device : public z80sio_device
|
||||
{
|
||||
public:
|
||||
upd7201_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
class i8274_new_device : public z80sio_device
|
||||
{
|
||||
public:
|
||||
i8274_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
virtual int m1_r() override;
|
||||
|
||||
protected:
|
||||
i8274_new_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device_t overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
// device_z80daisy_interface overrides
|
||||
virtual int z80daisy_irq_ack() override;
|
||||
virtual void z80daisy_irq_reti() override;
|
||||
|
||||
virtual uint8_t read_vector() override;
|
||||
virtual int const *interrupt_priorities() const override;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
class upd7201_new_device : public i8274_new_device
|
||||
{
|
||||
public:
|
||||
upd7201_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
// device type declaration
|
||||
DECLARE_DEVICE_TYPE(Z80SIO, z80sio_device)
|
||||
DECLARE_DEVICE_TYPE(Z80SIO_CHANNEL, z80sio_channel)
|
||||
DECLARE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device)
|
||||
DECLARE_DEVICE_TYPE(I8274_NEW, i8274_new_device)
|
||||
DECLARE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device)
|
||||
|
||||
#endif // MAME_MACHINE_Z80SIO_H
|
||||
|
Loading…
Reference in New Issue
Block a user