diff options
author | Joakim Larsson Edstrom <joakimlarsson42@gmail.com> | 2016-06-10 10:29:13 +0200 |
---|---|---|
committer | Joakim Larsson Edstrom <joakimlarsson42@gmail.com> | 2016-06-10 10:29:13 +0200 |
commit | f812a76116c92b3bdd04eb5ff8ca6262e89ae062 (patch) | |
tree | dbf458de7528abece6436f2e8f0f11f32221d764 /src | |
parent | 37d8de37fa1c4aec64ba5553cae530067476bb2c (diff) |
DUSCC driver for 68562,26562,68C562 and 26C562 added, WIP but works for Force CPU-30 in polled mode
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/machine/scnxx562.cpp | 1793 | ||||
-rw-r--r-- | src/devices/machine/scnxx562.h | 698 |
2 files changed, 2491 insertions, 0 deletions
diff --git a/src/devices/machine/scnxx562.cpp b/src/devices/machine/scnxx562.cpp new file mode 100644 index 00000000000..b7ec3b80109 --- /dev/null +++ b/src/devices/machine/scnxx562.cpp @@ -0,0 +1,1793 @@ +// license:BSD-3-Clause copyright-holders: Joakim Larsson Edstrom +/*************************************************************************** + + DUSCC Dual Serial Communications Controller emulation + + The DUSCC was introduced in the mid 80:ies by Signetics, a part of Philips + Semiconductor that later became NXP, and apparantly trying to dig into + the huge success of the Zilog SCC with a very similar feature set but not + software compatible at all. + + The variants in the DUSCC family are as follows: + + Bus type + Intel Motorola +---------------------------------- + NMOS 26562 68562 + CMOS 26C562 68C562 +---------------------------------- + For more info see: + page 511: http://bitsavers.informatik.uni-stuttgart.de/pdf/signetics/_dataBooks/1986_Signetics_Microprocessor.pdf + page 514: http://bitsavers.informatik.uni-stuttgart.de/pdf/signetics/_dataBooks/1994_Signetics_Data_Communications.pdf + +Designs known of including one or more DUSCCs +------------------------------------------------ + Force Computers + CPU VME boards: CPU-22, CPU-26, CPU-30, CPU-33, CPU-386, CPU-40, CPU-41 + Graphics VME boards: AGC-1 + Serial VME boards: ISIO-1, ISIO-2 + Digital Equipment + DEC MicroServer DEMSA, DECrouter-150, DECrouter-250 +------------------------------------------------ + +TODO/ "NDUSCC" "CDUSCC" +DONE (x) (p=partly) NMOS CMOS +------------------------------------------------ + Channels 2 FD 2 FD + Synch data rates 4Mbps 10Mbps + ----- asynchrounous features ------------------ + p 5-8 bit per char Y Y + y 1,1.5,2 stop bits Y Y in 1/16 bit increments + p odd/even parity Y Y + x1,x16 Y Y + break det/gen Y Y + parity, framing & Y Y + overrun error det + -- byte oriented synchrounous features -- + Int/ext char sync Y Y + 1/2 synch chars ? ? + Aut CRC gen/det Y Y + -- SDLC/HDLC capabilities --------------- + Abort seq gen/chk Y Y + Aut zero ins/det Y Y + Aut flag insert Y Y + Addr field rec Y Y + I-fld resid hand Y Y + CRC gen/det Y Y + SDLC loop w EOP Y Y + -- + Receiver FIFO 4 16 + Transmitter FIFO 4 16 + NRZ, NRZI, FM1 or Y Y + FM2 enc/dec + Manchester dec Y Y + Baud gen per chan Y Y + DPLL clock recov Y Y + -- Additional features CMOS versions ----- + Status FIFO N Y + Watchdog timer N Y + Fifo Fill status N Y + DMA frame status N Y + Rx/TxRDY on FIFO lvl N Y + TxFifo Empty status N Y + Interrupt enable bits N Y + X.21 pattern recogn N Y + Improved BiSync support N Y + ------------------------------------------------------------------------- + x/p = Features that has been implemented n/a = features that will not +***************************************************************************/ + +#include "scnxx562.h" + +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** +/* Useful temporary debug printout format */ +// printf("TAG %lld %s%s Data:%d\n", machine().firstcpu->total_cycles(), __PRETTY_FUNCTION__, m_owner->tag(), data); + +#define VERBOSE 2 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define LOGR(x) +#if VERBOSE == 0 +#define logerror printf +#endif + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#define LLFORMAT "%I64%" +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#define LLFORMAT "%lld" +#endif + +#define CHANA_TAG "cha" +#define CHANB_TAG "chb" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** +// device type definition +const device_type DUSCC = &device_creator<duscc_device>; +const device_type DUSCC_CHANNEL = &device_creator<duscc_channel>; +const device_type DUSCC26562 = &device_creator<duscc26562_device>; +const device_type DUSCC26C562 = &device_creator<duscc26C562_device>; +const device_type DUSCC68562 = &device_creator<duscc68562_device>; +const device_type DUSCC68C562 = &device_creator<duscc68C562_device>; + +//------------------------------------------------- +// device_mconfig_additions - +//------------------------------------------------- +MACHINE_CONFIG_FRAGMENT( duscc ) + MCFG_DEVICE_ADD(CHANA_TAG, DUSCC_CHANNEL, 0) + MCFG_DEVICE_ADD(CHANB_TAG, DUSCC_CHANNEL, 0) +MACHINE_CONFIG_END + +machine_config_constructor duscc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( duscc ); +} + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// duscc_device - constructor +//------------------------------------------------- +duscc_device::duscc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + // device_z80daisy_interface(mconfig, *this), + m_chanA(*this, CHANA_TAG), + m_chanB(*this, CHANB_TAG), +#if 0 + m_rxca(0), + m_txca(0), + m_rxcb(0), + m_txcb(0), +#endif + m_out_txda_cb(*this), + m_out_dtra_cb(*this), + m_out_rtsa_cb(*this), + m_out_synca_cb(*this), + m_out_txdb_cb(*this), + m_out_dtrb_cb(*this), + m_out_rtsb_cb(*this), + m_out_syncb_cb(*this), + m_variant(variant) +{ + for (auto & elem : m_int_state) + elem = 0; +} + +duscc_device::duscc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DUSCC, "DUSCC", tag, owner, clock, "duscc", __FILE__), + m_chanA(*this, CHANA_TAG), + m_chanB(*this, CHANB_TAG), + m_out_txda_cb(*this), + m_out_dtra_cb(*this), + m_out_rtsa_cb(*this), + m_out_synca_cb(*this), + m_out_txdb_cb(*this), + m_out_dtrb_cb(*this), + m_out_rtsb_cb(*this), + m_out_syncb_cb(*this), + m_variant(TYPE_DUSCC) +{ + for (auto & elem : m_int_state) + elem = 0; +} + +duscc26562_device::duscc26562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : duscc_device(mconfig, DUSCC26562, "DUSCC 26562", tag, owner, clock, TYPE_DUSCC26562, "duscc26562", __FILE__){ } + +duscc26C562_device::duscc26C562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : duscc_device(mconfig, DUSCC26C562, "DUSCC 26C562", tag, owner, clock, TYPE_DUSCC26C562, "duscc26C562", __FILE__){ } + +duscc68562_device::duscc68562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : duscc_device(mconfig, DUSCC68562, "DUSCC 68562", tag, owner, clock, TYPE_DUSCC68562, "duscc68562", __FILE__){ } + +duscc68C562_device::duscc68C562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : duscc_device(mconfig, DUSCC68C562, "DUSCC 68C562", tag, owner, clock, TYPE_DUSCC68C562, "duscc68C562", __FILE__){ } + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void duscc_device::device_start() +{ + LOG(("%s\n", FUNCNAME)); + // resolve callbacks + m_out_txda_cb.resolve_safe(); + m_out_dtra_cb.resolve_safe(); + m_out_rtsa_cb.resolve_safe(); + m_out_synca_cb.resolve_safe(); + m_out_txdb_cb.resolve_safe(); + m_out_dtrb_cb.resolve_safe(); + m_out_rtsb_cb.resolve_safe(); + m_out_syncb_cb.resolve_safe(); + + // state saving + //save_item(NAME(m_int_state)); + + LOG((" - DUSCC variant %02x\n", m_variant)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void duscc_device::device_reset() +{ + LOG(("%s %s \n",tag(), FUNCNAME)); + + m_chanA->reset(); + m_chanB->reset(); +} + +//------------------------------------------------- +// check_interrupts - +//------------------------------------------------- + +void duscc_device::check_interrupts() +{ + LOG(("%s %s - not implemented\n",tag(), FUNCNAME)); + // m_out_int_cb(state); +} + + +//------------------------------------------------- +// reset_interrupts - +//------------------------------------------------- + +void duscc_device::reset_interrupts() +{ + LOG(("%s %s - not implemented \n",tag(), FUNCNAME)); +#if 0 + // reset internal interrupt sources + for (auto & elem : m_int_state) + { + elem = 0; + } + + // check external interrupt sources + check_interrupts(); +#endif +} + +UINT8 duscc_device::modify_vector(UINT8 vec, int i, UINT8 src) +{ + LOG(("%s %s - not implemented\n",tag(), FUNCNAME)); + return vec; +} + + +//------------------------------------------------- +// trigger_interrupt - +//------------------------------------------------- +void duscc_device::trigger_interrupt(int index, int state) +{ + LOG(("%s %s - not implemented\n",tag(), FUNCNAME)); +} + +READ8_MEMBER( duscc_device::read ) +{ + if ( offset & 0x20 ) + return m_chanB->read(offset); + else + return m_chanA->read(offset); +} + +WRITE8_MEMBER( duscc_device::write ) +{ + if ( offset & 0x20 ) + m_chanB->write(data, offset); + else + m_chanA->write(data, offset); + return; +} + +//************************************************************************** +// DUSCC CHANNEL +//************************************************************************** +duscc_channel::duscc_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, DUSCC_CHANNEL, "DUSCC channel", tag, owner, clock, "duscc_channel", __FILE__), + device_serial_interface(mconfig, *this), + m_brg_rx_rate(0), + m_brg_tx_rate(0), + m_brg_const(1), + m_rx_error(0), + m_rx_clock(0), + m_rx_first(0), + m_rx_break(0), + m_rxd(0), + m_cts(0), + m_dcd(0), + m_tx_data(0), + m_tx_clock(0), + m_dtr(0), + m_rts(0), + m_sync(0) +{ + LOG(("%s\n",FUNCNAME)); + + // Reset all registers + m_cmr1 = m_cmr2 = m_s1r = m_s2r = m_tpr = m_ttr = m_rpr = m_rtr + = m_ctprh = m_ctprl = m_ctcr = m_omr = m_cth = m_ctl = m_pcr + = m_ccr = m_rsr = m_trsr = m_ictsr = m_gsr = m_ier /* = m_rea */ + = m_cid = m_ivr = m_icr = /*m_sea =*/ m_ivrm = m_mrr = m_ier1 + = m_ier2 = m_ier3 = m_trcr = m_rflr = m_ftlr = m_trmsr = m_telr = 0; + + for (int i = 0; i < sizeof(m_rx_data_fifo); i++) + { + m_rx_data_fifo[i] = 0; + m_rx_error_fifo[i] = 0; + } + for (int i = 0; i < sizeof(m_tx_data_fifo); i++) + { + m_tx_data_fifo[i] = 0; + m_tx_error_fifo[i] = 0; + } +} + +//------------------------------------------------- +// start - channel startup +//------------------------------------------------- + +void duscc_channel::device_start() +{ + LOG(("%s\n", FUNCNAME)); + m_uart = downcast<duscc_device *>(owner()); + m_index = m_uart->get_channel_index(this); + + m_rx_fifo_sz = (m_uart->m_variant & SET_CMOS) ? 16 : 4; + m_rx_fifo_wp = m_rx_fifo_rp = 0; + + m_tx_fifo_sz = (m_uart->m_variant & SET_CMOS) ? 16 : 4; + m_tx_fifo_wp = m_tx_fifo_rp = 0; + + m_cid = (m_uart->m_variant & SET_CMOS) ? 0x7f : 0xff; // TODO: support CMOS rev A = 0xbf + + // state saving + save_item(NAME(m_cmr1)); + save_item(NAME(m_cmr2)); + save_item(NAME(m_s1r)); + save_item(NAME(m_s2r)); + save_item(NAME(m_tpr)); + save_item(NAME(m_ttr)); + save_item(NAME(m_rpr)); + save_item(NAME(m_rtr)); + save_item(NAME(m_ctprh)); + save_item(NAME(m_ctprl)); + save_item(NAME(m_ctcr)); + save_item(NAME(m_omr)); + save_item(NAME(m_cth)); + save_item(NAME(m_ctl)); + save_item(NAME(m_pcr)); + save_item(NAME(m_ccr)); + save_item(NAME(m_txfifo[4])); + save_item(NAME(m_rxfifo[4])); + save_item(NAME(m_rsr)); + save_item(NAME(m_trsr)); + save_item(NAME(m_ictsr)); + save_item(NAME(m_gsr)); // TODO: Move this to the device instead, it is a global register + save_item(NAME(m_ier)); + // save_item(NAME(m_rea)); + save_item(NAME(m_cid)); + save_item(NAME(m_ivr)); + save_item(NAME(m_icr)); + // save_item(NAME(m_sea)); + save_item(NAME(m_ivrm)); + save_item(NAME(m_mrr)); + save_item(NAME(m_ier1)); + save_item(NAME(m_ier2)); + save_item(NAME(m_ier3)); + save_item(NAME(m_trcr)); + save_item(NAME(m_rflr)); + save_item(NAME(m_ftlr)); + save_item(NAME(m_trmsr)); + save_item(NAME(m_telr)); + save_item(NAME(m_rx_data_fifo)); + save_item(NAME(m_rx_error_fifo)); + save_item(NAME(m_rx_fifo_rp)); + save_item(NAME(m_rx_fifo_wp)); + save_item(NAME(m_rx_fifo_sz)); + save_item(NAME(m_rx_clock)); + save_item(NAME(m_rx_first)); + save_item(NAME(m_rx_break)); + save_item(NAME(m_ri)); + save_item(NAME(m_cts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_tx_data)); + save_item(NAME(m_tx_clock)); + save_item(NAME(m_dtr)); + save_item(NAME(m_rts)); + save_item(NAME(m_sync)); + + device_serial_interface::register_save_state(machine().save(), this); +} + + +//------------------------------------------------- +// reset - reset channel status +//------------------------------------------------- + +void duscc_channel::device_reset() +{ + LOG(("%s\n", FUNCNAME)); + + // Reset RS232 emulation + receive_register_reset(); + transmit_register_reset(); + + // Soft/Channel Reset values according to DUSCC users guide + m_cmr1 =0x00; + m_cmr2 =0x00; + m_s1r =0x00; + m_s2r =0x00; + m_tpr =0x00; + m_ttr =0x00; + m_rpr =0x00; + m_rtr =0x00; + m_ctcr =0x00; + m_omr =0x00; + m_pcr =0x00; + m_ccr =0x00; + m_rsr =0x00; + m_trsr =0x00; + m_ictsr =0x00; + m_gsr =0x00; + m_ier =0x00; + // m_rea =0x00; + m_ivr =0x0f; + m_icr =0x00; + // m_sea =0x00; + m_ivrm =0x00; + m_mrr =0x00; // TODO: Need a read after reset to enable CMOS features + m_ier1 =0x00; + m_ier2 =0x00; + m_ier3 =0x00; + m_trcr =0x00; + m_rflr =0x00; + m_ftlr =0x33; + m_trmsr =0x00; + m_telr =0x10; + + // reset external lines TODO: check relation to control bits and reset + set_rts(1); + set_dtr(1); + + // reset interrupts + if (m_index == duscc_device::CHANNEL_A) + { + m_uart->reset_interrupts(); + } + + m_a7 = 0; +} + +void duscc_channel::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // LOG(("%s %d\n", FUNCNAME, id)); + device_serial_interface::device_timer(timer, id, param, ptr); +} + + +//------------------------------------------------- +// tra_callback - +//------------------------------------------------- + +void duscc_channel::tra_callback() +{ + if (!is_transmit_register_empty()) + { + int db = transmit_register_get_data_bit(); + + LOGR((LLFORMAT " %s() \"%s \"Channel %c transmit data bit %d\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, db)); + + // transmit data + if (m_index == duscc_device::CHANNEL_A) + m_uart->m_out_txda_cb(db); + else + m_uart->m_out_txdb_cb(db); + } + else + { + LOG((LLFORMAT " %s() \"%s \"Channel %c Failed to transmit \n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index)); + logerror("%s \"%s \"Channel %c Failed to transmit\n", FUNCNAME, m_owner->tag(), 'A' + m_index); + } +} + + +//------------------------------------------ +// tra_complete - +// TODO: +// - Fix mark and space tx support +//------------------------------------------ + +void duscc_channel::tra_complete() +{ + if (m_tra == 1) // transmitter enabled? + { + if (m_tx_fifo_rp != m_tx_fifo_wp) // there are more characters to send? + { + transmit_register_setup(m_tx_data_fifo[m_tx_fifo_rp]); // Reload the shift register + m_tx_fifo_rp_step(); + } + if (m_omr & REG_OMR_TXRDY_ACTIVATED)// Wait until FIFO empty before ready for more data? + { + if (m_tx_fifo_wp == m_tx_fifo_rp) // So is Tx FIFO empty? + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + } + else // Always ready for more! + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + } +} + + +//------------------------------------------------- +// rcv_callback - +//------------------------------------------------- + +void duscc_channel::rcv_callback() +{ + if (m_rcv == 1) + { + LOG((LLFORMAT " %s() \"%s \"Channel %c received data bit %d\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_rxd)); + receive_register_update_bit(m_rxd); + } +} + + +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- + +void duscc_channel::rcv_complete() +{ + UINT8 data; + + receive_register_extract(); + data = get_received_char(); + LOG((LLFORMAT " %s() \"%s \"Channel %c Received Data %c\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, data)); + receive_data(data); +} + + +//------------------------------------------------- +// get_xx_clock_mode - get clock divisor +// TODO +// - support all the other clock divisors +// - actually use the divisors when calculating baud +//------------------------------------------------- + +int duscc_channel::get_rx_clock_mode() +{ + int clocks = 1; + + if ( (m_rtr & REG_RTR_RXCLK_MASK) == REG_RTR_RXCLK_BRG ) + clocks = 32; + + return clocks; +} + +int duscc_channel::get_tx_clock_mode() +{ + int clocks = 1; + + if ( (m_ttr & REG_TTR_TXCLK_MASK) == REG_TTR_TXCLK_BRG ) + clocks = 32; + + return clocks; +} + +void duscc_channel::set_rts(int state) +{ + LOG(("%s(%d) \"%s\": %c \n", FUNCNAME, state, m_owner->tag(), 'A' + m_index)); + if (m_index == duscc_device::CHANNEL_A) + m_uart->m_out_rtsa_cb(state); + else + m_uart->m_out_rtsb_cb(state); +} + +/* -------------------------------------------------------------------------- + * get_stop_bits - get number of stop bits + * The DUSCC supports from 1/2 stop bit to 2 stop bits in 1/16th bit increments + * This is not yet supported by diserial so we need to translate into 1, 1.5 + * or 2 stop bits. It is also dependent on the data bit length + * TODO: Support finer granularity of stop bits in diserial if/when nessesarry + * --------------------------------------------------------------------------- + * TPR[4:7] TPR[0:1] + * 5 bits 6-8 bits + * 00 01,10,11 + * --------------------------- + * 0 0 0 0 1.063 0.563 + * 0 0 0 1 1.125 0.625 + * 0 0 1 0 1.188 0.688 + * 0 0 1 1 1.250 0.750 + * 0 1 0 0 1.313 0.813 + * 0 1 0 1 1.375 0.875 + * 0 1 1 0 1.438 0.938 + * 0 1 1 1 1.500 1.000 + * 1 0 0 0 1.563 1.563 + * 1 0 0 1 1.625 1.625 + * 1 0 1 0 1.688 1.688 + * 1 0 1 1 1.750 1.750 + * 1 1 0 0 1.813 1.813 + * 1 1 0 1 1.875 1.875 + * 1 1 1 0 1.938 1.938 + * 1 1 1 1 2.000 2.000 + * -------------------------------------------------------------------------- + */ +device_serial_interface::stop_bits_t duscc_channel::get_stop_bits() +{ + const stop_bits_t bits5[] = + { STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1_5, STOP_BITS_1_5, STOP_BITS_1_5, STOP_BITS_1_5, + STOP_BITS_1_5, STOP_BITS_1_5, STOP_BITS_1_5, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2 }; + const stop_bits_t bits6to8[] = + { STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, STOP_BITS_1, + STOP_BITS_1, STOP_BITS_1_5, STOP_BITS_1_5, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2, STOP_BITS_2 }; + + /* 5 data bits */ + if (get_tx_word_length() == 5) + { + return bits5[((m_tpr & REG_TPR_STOP_BITS_MASK) >> 4) & 0x0f]; + } + else /* 6-8 data bits */ + { + return bits6to8[((m_tpr & REG_TPR_STOP_BITS_MASK) >> 4) & 0x0f]; + } + + return STOP_BITS_0; +} + +//------------------------------------------------- +// get_rx_word_length - get receive word length +//------------------------------------------------- + +int duscc_channel::get_rx_word_length() +{ + int bits = 5; + + switch (m_rpr & REG_RPR_DATA_BITS_MASK) + { + case REG_RPR_DATA_BITS_5BIT: bits = 5; break; + case REG_RPR_DATA_BITS_6BIT: bits = 6; break; + case REG_RPR_DATA_BITS_7BIT: bits = 7; break; + case REG_RPR_DATA_BITS_8BIT: bits = 8; break; + } + + return bits; +} + + +//------------------------------------------------- +// get_tx_word_length - get transmit word length +//------------------------------------------------- + +int duscc_channel::get_tx_word_length() +{ + int bits = 5; + + switch (m_tpr & REG_TPR_DATA_BITS_MASK) + { + case REG_TPR_DATA_BITS_5BIT: bits = 5; break; + case REG_TPR_DATA_BITS_6BIT: bits = 6; break; + case REG_TPR_DATA_BITS_7BIT: bits = 7; break; + case REG_TPR_DATA_BITS_8BIT: bits = 8; break; + } + + return bits; +} + +UINT8 duscc_channel::do_dusccreg_cmr1_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_cmr2_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_s1r_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_s2r_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_tpr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ttr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_rpr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_rtr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ctprh_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ctprl_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ctcr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_omr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_cth_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ctl_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_pcr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } + +/* Commands to the DUSCC are entered through the channel command register.A read of this + register returns the last invoked command (with bits 4 and 5 set to 1). */ +UINT8 duscc_channel::do_dusccreg_ccr_r() +{ + LOG(("%s\n", FUNCNAME)); + return (UINT8) m_ccr | 1 << 4 | 1 << 5; +} + +UINT8 duscc_channel::do_dusccreg_rxfifo_r() +{ + UINT8 data = 0; + + LOG(("%s\n", FUNCNAME)); + LOG((" - RX rp:%d wp:%d sz:%d\n", m_rx_fifo_rp, m_rx_fifo_wp, m_rx_fifo_sz)); + + /* So is there a character in the FIFO? */ + if (m_rx_fifo_rp != m_rx_fifo_wp) + { + data = m_rx_data_fifo[m_rx_fifo_rp]; + m_rx_fifo_rp_step(); + LOG((" - RX reading out data:%02x '%c'\n", data, isalnum(data) ? data : ' ')); + } + else + { + logerror("- RX FIFO empty despite RxREADY\n"); + LOG(("- RX FIFO empty despite RxREADY\n")); + } + + return (UINT8) data; +} + +UINT8 duscc_channel::do_dusccreg_rsr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_trsr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ictsr_r() +{ + logerror("register access method %s is not implemented yet\n", FUNCNAME); + return (UINT8) m_ictsr; +} + +/* General Status Register (GSR) + This register provides a 'quick look' at the overall status of both channels of the DUSCC. A write to this register with ls at the + corresponding bit pOSitions causes TxRDY (bits 5 and 1) and/or RxRDY (bits 4 and 0) to be reset. The other status bits can be reset + only by resetting the individual status bits that they point to. + [7] Channel B External or Counter/timer Status - This bit indicates that one of the following status bits is asserted: ICTSRB[6:4] + [6] Channel B Receiver or Transmitter Status - This bit indicates that one of the following status bits is asserted: TRSRB[7:1], TRSRB[7:3]. + [5] Channel B Transmitter Ready - The assertion of this bit indicates that one or more characters may be loaded into the Channel B transmitter + FIFO to be serialized by the transmit shift register. See description of OMR[4j. This bit can be asserted only when the transmitter is enabled. + Resetting the transmitter negates TxRDY. + [4] Channel B Receiver Ready - The assertion of this bit indicates that one or more characters are available in the Channel B receiver + FIFO to be read by the CPU. See deSCription of OMR[3]. RxRDY is initially reset (negated) by a chip reset or when a 'reset Channel B + receiver' command is invoked. + [3] Channel A External or Countermmer Status - This bit indicates that one of the following status bits is asserted: ICTSRA[6:4]. + [2] Channel A Receiver or Transmitter Status - This bit indicates that one of the following status bits is asserted: TRSRA[7:0], TRSRA[7:3]. + [1] Channel A Transmitter Ready - The assertion of this bit indicates that one or more characters may be loaded into the Channel A + transmitter FIFO to be serialized by the transmit shift register. See description of OMR[4]. This bit can be asserted only + when the transmitter is enabled. Resetting the transmitter negates TxRDY. + [0] Channel A Receiver Ready - The assertion of this bit indicates that one or more characters are available in the Channel A receiver + FIFO to be read by the CPU. See description of OMR[3]. RxRDY is initially reset (negated) by a chip reset or when a 'reset Channel A + receiver' command is invoked. +*/ +UINT8 duscc_channel::do_dusccreg_gsr_r() +{ + LOGR(("%s <- %02x\n", FUNCNAME, m_gsr)); + return (UINT8) m_gsr; +} + +UINT8 duscc_channel::do_dusccreg_ier_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } + +UINT8 duscc_channel::do_dusccreg_cid_r() +{ + LOG(("%s\n", FUNCNAME)); + if ( m_uart->m_variant != SET_CMOS ) + { + logerror("Attempt read out CDUSCC register CID on an NDUSCC\n"); + return 0; + } + if ( m_index != duscc_device::CHANNEL_B ) + { + logerror("Attempt read out CID on channel B not allowed\n"); + return 0; + } + else + return m_cid; +} + +UINT8 duscc_channel::do_dusccreg_ivr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_icr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ivrm_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_mrr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ier1_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ier2_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ier3_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_trcr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_rflr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_ftlr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_trmsr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } +UINT8 duscc_channel::do_dusccreg_telr_r(){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return (UINT8) 0; } + + // write register handlers +/* CMR1 register + [7:6] Data Encoding - These bits select the data encoding for the received and transmitted data: + 00 If the DPLL is set to NRZI mode (see DPLL commands), it selects positive logic (1 = high, 0 = low). + If the DPLL is set to FM mode (see DPLL commands), Manchester (bi-phase level) encoding is selected. + 01 NRZI. Non-return-to-zero inverted. + 10 FMO. Bi-phase space. + 11 FM 1. Bi-phase mark. + [5] Extended Control (BOP) - + 0 No. A one-octet control field follows the address field. + 1 Yes. A two-octet control field follows the address field. + [5] Parity (COP/ ASYNC), Code Select (BISYNC) + 0 Even parity if with parity is selected by [4:3] or a 0 in the parity bit position if force parity is + selected by [4:3]. In BISYNC protocol mode, internal character comparisons are made using EBCDIC coding. + 1 Odd parity if with parity is selected by [4:3] or a 1 in the parity bit position if force parity is selected by [4:3]. + In BISYNC protocol mode, internal character comparisons are made using Bbit ASCII coding. + [4:3] Address Mode (BOP) - + This field controls whether a single octet or multiple octets follow the opening FLAG(s) for both the receiver and the transmitter. + This field is activated by selection of BOP secondary mode through the channel protocol mode bits CMR1_[2:0] (see Detailed Operation). + 00 Single octet address. + 01 Extended address. + 10 Dual octet address. + 11 Dual octet address with group. + [4:3] Parity Mode (COP/ASYNC) - + This field selects the parity mode for both the receiver and the transmitter. A parity bit is added to the programmed character length if + with parity or force parity is selected: + 00 No parity. Required when BISYNC protocol mode is programmed. + 01 Reserved. + 10 With parity. Odd or even parity is selected by [5]. + 11 Force parity. The parity bit is forced to the state selected by [5]. + [2:0] Channel Protocol Mode - + This field selects the operational protocol and submode for both the receiver and transmitter: + 000 - BOP Primary. No address comparison is performed. For receive, all characters received after the opening FLAG(s) are transferred to the FIFO. + 001 - BOP Secondary. This mode activates the address modes selected by [4:3]. Except in the case of extended address ([4:3]=01), an address comparison + is performed to determine if a frame should be received. Refer to Detailed Operation for details of the various addressing modes. If a valid comparison + occurs, the receiver is activated and the address octets and all subsequent received characters of the frame are transferred to the receive FIFO. + 010 - BOP Loop. The DUSCC acts as a secondary station in a loop. The GO-ON-LOOP and GO-OFF-LOOP commands are used to cause the DUSCC to go on and off the + loop. Normally, the TXD output echoes the RXD input with a three bit time delay. If the transmitter is enabled and the 'go active on poll' command has been + asserted, the transmitter will begin sending when an EOP sequence consisting of a zero followed by seven ones is detected. The DUSCC changes the last one of + the EOP to zero, making it another FLAG, and then operates as described in the detailed operation section. The loop sending status bit (TRSR[6]) is asserted + concurrent with the beginning of transmission. The frame should normally be terminated with an EOM followed by an echo of the marking RXD line so that secondary + stations further down the loop can append their messages to the messages from up-loop stations by the same process. If the 'go active on poll'command is not + asserted, the transmitter remains inactive (other than echOing the received data) even when the EOP sequence is received. + 011 - BOP Loop without address comparison. Same as normal loop mode except that address field comparisons are disabled. All received frames aretransmitted to the CPU. + 100 - COP Dual SYN. Character sync is achieved upon receipt of a bit sequence matching the contents of the appropriate bits of SIR and S2R (SYNI-SYN2), including + parity bits if any. + 101 - COP Dual SYN (BISYNC). Character sync is achieved upon receipt of a bit sequence matching the contents of the appropriate bits of SI Rand S2R + (SYN1·SYN2). In this mode, special transmitter and receive logic is activated. Transmitter and receiver character length must be programmed to 8 bits and no parity + 110 - COP Single SYN. Character sync is achieved upon receipt of a bit sequence matching the contents of the appropriate bits of Sl R (SYN1), including parity bit if any. + This mode is required when the external sync mode is selected. + 111 Asynchronous. Start/stop format. +*/ +void duscc_channel::do_dusccreg_cmr1_w(UINT8 data) +{ + LOG(("%s(%02x)\n", FUNCNAME, data)); + m_cmr1 = data; + LOG(("- Setting up %s mode\n", (m_cmr1 & REG_CMR1_CPMODE_MASK) == REG_CMR1_CPMODE_ASYNC ? "ASYNC" : "SYNC")); + LOG(("- Parity: %s\n", ((m_cmr1 & REG_CMR1_PMMODE_MASK) == REG_CMR1_PMMODE_PARITY ? (m_cmr1 & REG_CMR1_PARITY ? "odd" : "even") : "none"))); + return; +} + +/* CMR2 register + [7:6] Channel Connection - This field selects the mode of operation of the channel. The user must exercise care when switching into and out of the various modes. The + selected mode will be activated immediately upon mode selection, even if this occurs in the middle of a received or transmitted character. + + 00 - Normal mode. The 1ransmitter and receiver operate independently in either half or full-duplex, controlled by the respective enable commands. + + 01 - Automatic echo mode. Automatically retransmits the received data with a half-bit time delay (ASYNC, 16X clock mode) or a one-bit time delay (allother modes). + The following conditions are true while in automatic echo mode: + 1. Received data is reclocked and retransmitted on the TXD output. + 2. The receiver clock is used for the transmitter. + 3. The receiver must be enabled, but the transmitter need not be enabled. + 4. The TXRDY and underrun status bits are inactive. + 5. The received parity and/or FCS are checked if required, but are not regenerated for transmission, + i.e., transmitted parity and/ or FCS are as received. + 6. In ASYNC mode, character framing is checked, but the stop bits are retransmitted as received. + A received break is echoed as received. + 7. CPU to receiver communication continues normally, but the CPU to transmitter link is disabled. + + 10 - Local loopback mode. In this mode: + 1. The transmitter output is internally connected to the receiver input. + 2. The transmit clock is used for the receiver if NRZI or NRZ encoding is used. For FM or Manchester encoding because the receiver clock is derived from the DPLL, + the DPLL source clock must be maintained. + 3. The TXD output is held high. + 4. The RXD input is ignored. + 5. The receiver and transmitter must be enabled. + 6. CPU to transmitter and receiver communications continue normally. + + 11 - Reserved. + + [5:3] Data Transfer Interface - This field specifies the type of data transfer between the DUSCC's RX and TX FIFOs and the CPU. + All interrupt and status functions operate normally regardless of the data transfer interface programmed. + 000 - Half duplex single address DMA. + 001 - Half duplex dual address DMA. + 010 - Full duplex single address DMA. + 011 - Full duplex dual address DMA. + 100 - Wait on receive only. In this mode a read of a non-empty receive FIFO results in a normal bus cycle. However, if the receive FIFO of the channel + is empty when a read RX FIFO cycle is initiated, the DTACKN output remains negated until a character is received and loaded into the FIFO. + DT ACKN is then asserted and the cycle is completed normally. + 101 - Wait on transmit only. In this mode a write to a non-full transmit FI Fa results in a normal bus cycle. However, if the transmit FIFO of the channel is + full when a write TX FIFO cycle is initiated, the DTACKN output remains negated until a FI Fa position becomes available for the new character. DT ACKN + is then asserted and the cycle is completed normally. + 110 - Wait on transmit and receive. As above for both wait on receive and transmit operations. + 111 - Polled or interrupt. DMA and wait functions of the channel are not activated. Data transfers to the RX and TX FIFOs are via normal bus read and + write cycles in response to polling of the status registers and/or interrupts. + + [2:0] Frame Check Sequence Select - This field selects the optional frame check sequence (FCS) to be appended at the end of a transmitted frame. + When CRC is selected in COP, then no parity and 8-bit character length must be used. The selected FCS is transmitted as follows: + 1. Following the transmission of a FIFO'ed character tagged with the 'send EOM' command. + 2. If underrun control (TPR[7:6]) is programmed for TEOM, upon occurrence of an underrun. + 3. If TEOM on zero count or done (TPR[4]) is asserted and the counter/timer is counting transmitted characters, after transmission of the character which + causes the counter to reach zero count. + 4. In DMA mode with TEOM on zero count or done (TPR[4]) set, after transmission of a character if DONEN is asserted when that character was loaded into the + TX FIFO by the DMA controller. + + 000 - No frame check sequence. + 001 - Reserved + 010 - LRC8: Divisor ~ x8+ 1, dividend preset to zeros. The TX sends the calculated LRC non-inverted. The RX indicates an error if the computed LRC is + not equal to O. Valid for COP modes only. + 011 - LRC8: Divisor ~ x8+ 1, dividend preset to ones. The TX sends the calculated LRC non-inverted. The RX indicates + an error if the computed LRC is not equal to O. Valid for COP modes only. + 100 - CRCI6: Divisor ~ x16+x15+x2+1, dividend preset to zeros. The TX sends the calculated CRC non-inverted. The RX indicates an error if the + computed CRC is not equal to O. Not valid for ASYNC mode. + 101 - CRCI6: Divisor ~ x16+x15+x2+1, dividend preset to ones. The TX sends the calculated CRC non-inverted. The RX indicates an error if the + computed CRC is not equal to O. Not valid for ASYNC mode. + 110 - CRC-CCITT: Divisor ~ x16+x12+x5+1, dividend preset to zeros. The TX sends the calculated CRC non-inverted. The RX indicates an error if the + computed CRC is not equal to O. Not valid for ASYNC mode. + 111 CRC-CCITT: Divisor ~ x16+x12+x5+1, dividend preset to ones. The TX sends the calculated CRC inverted. The RX indicates an error if the computed + CRC is not equal to H' FOB8'. Not valid for ASYNC mode. +*/ +void duscc_channel::do_dusccreg_cmr2_w(UINT8 data) +{ + LOG(("%s(%02x)\n", FUNCNAME, data)); + m_cmr2 = data; + LOG(("- Preparing for %s driven transfers\n", (m_cmr2 & REG_CMR2_DTI_MASK) == REG_CMR2_DTI_NODMA ? "polled or interrupt" : "dma")); + return; +} + +void duscc_channel::do_dusccreg_s1r_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_s2r_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } + +/* Transmitter Parameter Register (TPRA, TPRB) + SYNC mode + [7:6] Underrun Control - In BOP and COP modes, this field selects the transmitter response in the event of an underrun (i.e., the TX FIFO is empty). + 00 - Normal end of message termination. In BOP, the transmitter sends the FCS (if selected by CMR2[2:011 followed by a FLAG and then either MARKs or + FLAGs, as specified by [5]. In COP, the transmitter sends the FCS (if selected by CMR2[2:0]) and then either MARKs or SYNs, as specified by [5]. + 01 - Reserved. + l0 - in BOP, the transmitter sends an ABORT (11111111) and then places the TXD output in a marking condition until receipt of further instructions. + In COP, the transmitter places the TXD output in a marking condition until receipt of further instructions. + 11 - In BOP, the transmitter sends an ABORT (11111111) and then sends FLAGs until receipt of further instructions. In COP, the transmitter sends + SYNs until receipt of further instructions. + [5] Idle - In BOP and COP modes, this bit selects the transmitter output during idle. Idle is defined as the state following a normal end of message until + receipt of the next transmitter command. + 0 - Idle in marking condition. + 1 - Idle sending SYNs (COP) or FLAGs (BOP). + [4] Transmit EOM on Zero Count or Done - In BOP and COP modes, the assertion of this bit causes the end of message (FCS in COP, FCS-FLAG in BOP) to be transmitted + upon the following events: + 1. If the counterltimer is counting transmitted characters, after transmission of the character which causes the counter to reach zero count. (DONEN is also asserted + as an output if the channel is in a DMA operation.) + 2. If the channel is operating in DMA mode, after transmission of a character if DONEN was asserted when that character was loaded into the TX FIFO by the DMA controller. + + ASYNC mode + [7:4] Stop Bits per Character - In ASYNC mode, this field programs the length of the stop bit appended to the transmitted character + Stop bit lengths of 9/16 to 1 and 1-9/16 to 2 bits, in increments of 1/16 bit, can be programmed for character lengths of 6, 7, and 8 bits. + For a character length of 5 bits, 1-1/16 to 2 stop bits can be programmed in increments of 1/16 bit. The receiver only checks for a 'mark' + condition at the center of the first stop bit position (one bit time after the last data bit, or after the parity bit if parity is enabled) in all cases. + If an external 1 X clock is used for the transmitter, [7) = 0 selects one stop bit and [7) = 1 selects two stop bits to be transmitted. + If Manchester, NRZI, or FM data encoding is selected, only integral stop bit lengths should be used. + [3] Transmitter Request-to-Send Control - This bit controls the deactivation of the RTS_N output by the transmitter + 0 - RTS_N is not affected by status of transmitter. + 1 - RTS_N changes state as a function of transmitter status. + [2] Clear-ta-Send Enable Transmitter - The state of this bit determines if the CTS N input controls the operation of the channels transmitter + The duration of CTS level change is described in the discussion of ICTSR[4). + 0 - CTS_N has no affect on the transmitter. + 1 - CTS_N affects the state of the transmitter. + [1:0] Transmitted Bits per Character - This field selects the number of data bits per character to be transmitted. The character length does not + include the start, parity, and stop bits in ASYNC or the parity bit in COP. In BOP modes the character length for the address and control + fields is always 8 bits, and the value of this field only applies to the information (I) field, except for the last character of the I field, + whose length is specified by OMR[7:5). +*/ +void duscc_channel::do_dusccreg_tpr_w(UINT8 data) +{ + LOG(("%s(%02x) Setting up Transmit Parameters\n", FUNCNAME, data)); + m_tpr = data; + LOG(("- RTS %u\n", (m_tpr & REG_TPR_RTS) ? 1 : 0)); + LOG(("- CTS %u\n", (m_tpr & REG_TPR_CTS) ? 1 : 0)); + LOG(("- Stop Bits %s\n", stop_bits_tostring(get_stop_bits()))); + LOG(("- Data Tx bits %u\n", get_tx_word_length())); + + update_serial(); + return; +} + +/* Transmitter Timing Register (TTRA, TTRB) + [7] External Source - This bit selects the RTxC pin or the TRxC pin of the channel as the transmitter clock input when [6:4] specifies + external. When used for input, the selected pin must be programmed as an input in the PCR [4:3] or [2:0]. + 0 External input form RTxC pin. + 1 External input from TRxC pin. + [6:4] Transmitter Clock Select - This field selects the clock for the transmitter. + 000 External clock from TRxC or RTXC at 1 X the shift (baud) rate. + 001 External clock from TRXC or RTxC at 16X the shift rate. + 010 Internal clock from the phase-locked loop at IX the bit rate. It should be used only in half-duplex operation since the + DPLL will periodically resync itself to the received data if in full-duplex operation. + 0ll Internal clock from the bit rate generator at 32X the shift rate. The clock signal is divided by two before use in the + transmitter which operates at 16X the baud rate. Rate selected by [3:0]. + 100 Internal clock from counter/timer of other channel. The C/T should be programmed to produce a clock at 2X the shift rate. + 101 Internal clock from counter/timer of other channel. The C/T should be programmed to produce a clock at 32X the shift rate. + 110 Internal clock from the counter/timer of own channel. The C/T should be programmed to produce a clock at 2X the shift rate. + 111 Internal clock from the counter/timer of own channel. The C/T should be programmed to produce a clock at 32X the shift rate. + [3:0] Bit Rate Select - This field selects an output from the bit rate generator to be used by the transmitter circuits. The actual + frequency output from the BRG is 32X the bit rate shown in Table 5. With a crystal or external clock of 14.7456MHz the bit rates are as + given in Table 5 (this input is divided by two before being applied to the oscillator circuit). + + Table 5. Receiver/Transmitter Baud Rates + [3:0] BIT RATE [3:0] BIT RATE + 0000 50 1000 1050 + 0001 75 1001 1200 + 0010 110 1010 2000 + 0011 134.5 1011 2400 + 0100 150 1100 4800 + 0101 200 1101 9600 + 0110 300 1110 19.2K + 0111 600 1111 38.4K +*/ +void duscc_channel::do_dusccreg_ttr_w(UINT8 data) +{ + LOG(("%s(%02x) Setting up Transmit Timing\n", FUNCNAME, data)); + m_ttr = data; + LOG(("- External source: %s\n", (m_ttr & REG_TTR_EXT) ? "TRxC" : "RTxC")); + LOG(("- Transmit Clock: ")); +#if VERBOSE > 0 + switch(m_ttr & REG_TTR_TXCLK_MASK) + { + case REG_TTR_TXCLK_1XEXT: LOG(("1x External - not implemented\n")); break; + case REG_TTR_TXCLK_16XEXT: LOG(("16x External - not implemented\n")); break; + case REG_TTR_TXCLK_DPLL: LOG(("DPLL - not implemented\n")); break; + case REG_TTR_TXCLK_BRG: + LOG(("BRG\n")); + m_brg_tx_rate = get_baudrate(m_ttr & REG_TTR_BRG_RATE_MASK); + break; + case REG_TTR_TXCLK_2X_OTHER: LOG(("2x other channel C/T - not implemented\n")); break; + case REG_TTR_TXCLK_32X_OTHER: LOG(("32x other channel C/T - not implemented\n")); break; + case REG_TTR_TXCLK_2X_OWN: LOG(("2x own channel C/T - not implemented\n")); break; + case REG_TTR_TXCLK_32X_OWN: LOG(("32x own channel C/T - not implemented\n")); break; + default: LOG(("Wrong programming\n")); break; // Should never happen + } +#endif + + LOG(("- BRG Tx rate %u assuming a 14.7456MHz CLK crystal\n", get_baudrate(m_ttr & REG_TTR_BRG_RATE_MASK))); + update_serial(); + + return; +} + +/* Receiver Parameter Resgister (RPRA, RPRB) + [7] SYN Stripping - This bit controls the DUSCC processing in COP modes of SYN 'character patterns' that occur after the initial + character synchronization. Refer to Detailed Operation of the receiver for details and definition of SYN 'patterns', and their + accumulation of FCS. + 0 Strip only leading SYN 'patterns' (i.e. before a message). + 1 Strip all SYN 'patterns' (including all odd DLE's in BISYNC transparent mode). + + [6] Transfer Received FCS to FIFO - In BISYNC and BOP modes, the assertion of this bit causes the received FCS to be loaded into the + RxFIFO. When this bit is set, BOP mode operates correctly only if a minimum of two extra FLAGs (without shared zeros) are appended + to the frame. If the FCS is specified to be transferred to the FI FO, the EOM status bit will be tagged onto the last byte of the + FCS instead of to the last character of the message. + 0 Do not transfer FCS to RxFIFO. + 1 Transfer FCS to RxFIFO. + + [5] Auto-Hunt and Pad Check (BISYNC) -In BISYNC rnode, the assertion of this bit causes the receiver to go into hunt for character + sync mode after detecting certain End-Ol-Message (EOM) characters. These are defined in the Detailed Operations section for + COP receiver operation. After the EOT and NAK sequences, the receiver also does a check for a closing PAD of four 1 s. + 0 Disable auto-hunt and PAD check. + 1 Enable auto-hunt and PAD check. + [5] Overrun Mode (BOP) - The state of this control bit deterrnines the operation of the receiver in the event of a data overrun, i.e., + when a character is received while the RxFIFO and the Rx shift register are both full. + 0 The receiver terrninates receiving the current frame and goes into hunt phase, looking for a FLAG to be received. + 1 The receiver continues receiving the current frame. The overrunning character is lost. (The five characters already + assembled in the RxFIFO and Rx shift register are protected). + + [4] Receiver Request-to-Send Control (ASYNC) + 0 Receiver does not control RTSN output. + 1 Receiver can negate RTSN output. + [4] External Sync (COP) - In COP single SYN mode, the assertion of this bit enables external character synchronization and + receipt of SYN patterns is not required. In order to use this feature, the DUSCC must be programmed to COP single SYN mode, + CMR1[2:0] = 110, which is used to set up the internal data paths. In all other respects, however, the external sync mode operation is + protocol transparent. A negative signal on the DCDN/SYNIN pin will cause the receiver to establish synchronization on the next rising + edge of the receiver clock. Character assembly will start at this edge with the RxD input pin considered to have the second bit of + data. The sync signal can then be negated. Receipt of the Active-High external sync input causes the SYN detect status bit + (RSR[2]) to be set and the SYNBOUTN pin to be asserted for one bit time. When this mode is enable, the internal SYN (COP mode) + detection and special character recognition (e.g., IDLE, STX, ETX, etc.) circuits are disabled. Character assembly begins as ~ in the + I-field with character length as programmed in RPR[I :)]. Incoming COP frames with parity specified optionally can have it stripped by + programming RPR[3J. The user must wait at least eight bit times after Rx is enabled before applying the SYNIN signal. This time is + required to flush the internal data paths. The receiver remains in this mode and further external sync pulses are ignored until the + receiver is disabled and then reenabled to resynchronize or to return to normal mode. + 0 External sync not enabled. + 1 External sync enabled. + Note that EXT SYNC and DCD ENABLE Rx cannot be asserted simultaneously since they use the same pin. + + [3] Strip Parity - In COP and ASYNC modes with parity enabled, this bit controls whether the received parity bit is stripped from the + data placed in the receiver FIFO. It is valid ony for programmed character lengths of 5, 6, and 7 bits. If the bit is stripped, the + corresponding bit in the received data is set to zero. + 0 Transfer parity bit as received. + 1 Stop parity bit from data. + [3] All Parties Address - In BOP secondary modes, the assertion of this bit causes the receiver to 'wake-up' upon receipt of the + address H'FF' or H'FF, FF', for single- and dual-octet address modes, respectively, in addition to its normal station address. This + feature allows all stations to receive a message. + 0 Don't recognize all parties address. + 1 Recognize all parties address. + + [2] DCD Enable Receiver - If this bit is asserted, the DCDN/SYNIN input must be Low in order for the receiver to operate. + If the input is negated (goes High) while a character is being received, the receiver terminates receipt of the current message + (this action in effect disables the receiver). If DCD is subsequently asserted, the receiver will search for the start bit, SYN pattern, or + FLAG, depending on the channel protocol. (Note that the change of input can be programmed to generate an interrupt; the duration of + the DCD level change is described in the discussion of the input and counter/timer status register (CTSR[5]). + 0 DCD not used to enabled receiver. + 1 DCD used to enabled receiver. + NOTE that EXT SYNC and DCD ENABLE Rx cannot be asserted simultaneously since they use the same pin. + + [1:0] Received Bits per Character - This field selects the number of data bits per character to be assembled by the receiver. The + character length does not include the start, parity, and stop bits in the ASYNC or the parity bit in COP. In BOP modes, the character + length for the address and control field is always 8 bits, and the value of this field only applies to the information field. lithe number + of bits assembled for the last character of the l-field is less than the value programmed in this field, RCL not zero (RSR[O]) is asserted + and the actual number of bits received is given in TRSR[2:0]. +*/ +void duscc_channel::do_dusccreg_rpr_w(UINT8 data) +{ + LOG(("%s(%02x) Setting up Receiver Parameters\n", FUNCNAME, data)); + m_rpr = data; + LOG(("- RTS output %u\n", (m_rpr & REG_RPR_RTS) ? 1 : 0)); + LOG(("- Strip Parity %u\n", (m_rpr & REG_RPR_STRIP_PARITY && get_rx_word_length() < 8) ? 1 : 0)); + LOG(("- DCD/SYNIN input %u\n", (m_rpr & REG_RPR_DCD) ? 1 : 0)); + LOG(("- Data Rx bits %u\n", get_rx_word_length())); + + update_serial(); + return; +} + +/* Receiver Timing Register (RTRA, RTRB) + [7] External Source - This M selects the RTxC pin or the TRxC pin of the channel as the receiver or DPLL clock input, when [6:4J + specifies external. When used for input, the selected pin must be programmed as an input in the PCR [4:3] or [2:0]. + 0 External input form RTxC pin. + 1 External input form TRxC pin. + [6:4] Receiver Clock Select- This field selects the clock for the receiver. + 000 External clock from TRxC or RTxC at 1 X the shift (baud) rate. + 001 External clock fromTRxC or RTxC at 16X the shift rate. Used for ASYNC mode only. + 010 Internal clock from the bit rate generator at 32X the shift rate. Clock is divided by two before used by the receiver + logic, which operates at 16X the baud rate. Rate selected + by [3:0J. Used for ASYNC mode only. + 011 Internal clock from counter/timer of own channel. The CIT should be programmed to produce a clock at 32X the shift + rate. Clock is divided by two before use in the receiver logic. Used for ASYNC mode only. + 100 Internal clock from the digital phase- locked loop. The clock for the DPLL is a 64X clock from the crystal oscillator or + system clock input. (The input to the oscillator is divided by two). + 101 Internal clock from the digital phase- locked loop. The clock for the DPLL is an external 32X clock from the RTxC or + TRxC pin, as selected by [7J. + 110 Internal clock from the digital phase- locked loop. The clock for the DPLL is a 32X clock from the BRG. The frequency + is programmed by [3:0]. + 111 Internal clock from the digital phase- locked loop. The clock for the DPLL is a 32X clock from the counter/timer of the + channel. + [3:0] Bit Rate Select- This field selects an output from the bit rate generator to be used by the receiver circuits. The actual frequency + output from the BRG is 32X the bit rate shown in Table 5.*/ + +void duscc_channel::do_dusccreg_rtr_w(UINT8 data) +{ + LOG(("%s(%02x) Setting up Receiver Timing\n", FUNCNAME, data)); + m_rtr = data; + LOG(("- External source: %s\n", (m_rtr & REG_RTR_EXT) ? "TRxC" : "RTxC")); + LOG(("- Receiver Clock: ")); + +#if VERBOSE > 0 + switch(m_rtr & REG_RTR_RXCLK_MASK) + { + case REG_RTR_RXCLK_1XEXT: LOG(("1x External - not implemented\n")); break; + case REG_RTR_RXCLK_16XEXT: LOG(("16x External - not implemented\n")); break; + case REG_RTR_RXCLK_BRG: + LOG(("BRG\n")); + m_brg_rx_rate = get_baudrate(m_rtr & REG_RTR_BRG_RATE_MASK); + break; + case REG_RTR_RXCLK_CT: LOG(("C/T of channel - not implemented\n")); break; + case REG_RTR_RXCLK_DPLL_64X_X1: LOG(("DPLL, source = 64X X1/CLK - not implemented\n")); break; + case REG_RTR_RXCLK_DPLL_32X_EXT:LOG(("DPLL, source = 32X External - not implemented\n")); break; + case REG_RTR_RXCLK_DPLL_32X_BRG:LOG(("DPLL, source = 32X BRG - not implemented\n")); break; + case REG_RTR_RXCLK_DPLL_32X_CT: LOG(("DPLL, source = 32X C/T - not implemented\n")); break; + default: LOG(("Wrong programming\n")); break; // Should never happen + } +#endif + + LOG(("- BRG Rx rate %u assuming a 14.7456MHz CLK crystal\n", get_baudrate(m_rtr & REG_RTR_BRG_RATE_MASK))); + update_serial(); + + return; +} + +void duscc_channel::do_dusccreg_ctprh_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ctprl_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ctcr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } + +/* Output and Miscellaneous Register (OMRA, OMRB) + [7:5] Transmitted Residual Character Length - In BOP modes, this field determines the number of bits transmitted for the last + character in the information field. This length applies to: + - The character in the transmit FIFO accompanied by the FIFOed TEOM command. + - The character loaded into the FIFO by the DMA controller if DONEN is simultaneously asserted and TPR(4) is asserted. + - The character loaded into the FIFO which causes the counter to reach zero count when TPR[4J is asserted. + The length of all other characters in the frame's information field is selected by TPR[I :OJ. If this field is 111, + the number of bits in the last character is the same as programmed in TPR[1:0]. + [4] TxRDY Activate Mode - + 0 FIFO not full. The channel's TxRDY status bit is asserted each time a character is transferred from the transmit FIFO + to the transmit shift register. If not reset by the CPU, TxRDY remains asserted until the FIFO is full, at which time + it is automatically negated. + 1 FIFO empty. The channel's TxRDY status bit is asserted when a character transfer from the transmit FIFO to the + transmit shift register causes the FI FO to become empty. If not reset by the CPU, TxRDY remains asserted until the + FIFO is full, at which time it is negated. + If the TxRDY status bit is reset by the CPU, it will remain negated regardless of the current state of the transmit + FIFO, until it is asserted again due to the occurrence of one of the above conditions. + [3] RxRDY Activate Mode - + 0 FIFO not empty. The channel's RxRDY status bit is asserted each time a character is transferred from the + receive shift register to the receive FIFO. If not reset by the CPU, RxRDY remains asserted until the receive FIFO is + empty, at which time it is automatically negated. + 1 FIFO full. The channel's RxRDY status bit is asserted when a character transfer from the receive shift register to the + receive FIFO causes the FIFO to become full. If not reset by the CPU, RxRDY reamins asserted until the FIFO is empty, + at which time it is negated. + The RxRDY status bit will also be asserted, regardless of the receiver FIFO full condition, when an end-of-message + character is loaded in the RxFIFO (BOP/BISYNC), when a BREAK condition (ASYNC mode) is detected in RSR[2), or + when the counterltimer is programmed to count received characters and the character which causes it to reach zero + is loaded in the FIFO (all modes). If reset by the CPU, the RxRDY status bit will remain negated, regardless of the + current state of the receiver FIFO, until it is asserted again due to one of the above conditions. + [2] General Purpose Output 2 - + This general purpose bit is used to control the TxDRQN/GP02lRTSN pin, when it is used as an output. The output is + High when the bit is a 0 and is Low when the bit is a 1. + [1] General Purpose Output 1 - This bit is used to control the RTxDRQN/GPOl N output, which is a general purpose output + when the channel is not in DMA mode. The output is High when the bit is a 0 and is Low when the bit is a 1. + [0] Request-to-Send Output - This bit controls the TxDRQN/GP02N/RTSN and SYNOUTN/RTSN pin, when either is + used as a RTS output. The output is High when the bit is a 0 and is Low when the bit is a 1. +*/ +void duscc_channel::do_dusccreg_omr_w(UINT8 data) +{ + LOG(("%s(%02x) Output and Miscellaneous Register\n", FUNCNAME, data)); + m_omr = data; + LOG(("- Tx Residual Character Length is ")); + if ((m_omr & REG_OMR_TXRCL_MASK) == REG_OMR_TXRCL_8BIT) + LOG(("determined by TPR[1:0], the Transmitter Parameter Register\n")); + else + LOG(("%u bits\n", (((m_omr & REG_OMR_TXRCL_MASK) >> 5) & 0x07) + 1)); + LOG(("- TxRDY activated by %s\n", m_omr & REG_OMR_TXRDY_ACTIVATED ? "FIFO empty" : "FIFO not full")); + LOG(("- RxRDY activated by %s\n", m_omr & REG_OMR_RXRDY_ACTIVATED ? "FIFO full" : "FIFO not empty")); + LOG(("- GP02, if configured as output, is: %u\n", m_omr & REG_OMR_GP02 ? 0 : 1)); + LOG(("- GP01, if configured as output, is: %u\n", m_omr & REG_OMR_GP01 ? 0 : 1)); + LOG(("- RTS, either pin if configured as output, is: %u\n", m_omr & REG_OMR_RTS ? 0 : 1)); + return; +} + +/* Pin Configuration Register (PCRA, PCRB) + This register selects the functions for multipurpose 1/0 pins. + [7] X2IIDC - This bit is defined only for PCRA. It is not used in PCRB. + 0 The X2/IDCN pin is used as a crystal connection. + 1 The X2/IDCN pin is the interrupt daisy chain output. + [6] GP02/RTS - The function of this pin is programmable only when not operating in full-duplex DMA mode. + 0 The TxDRQN/GP02N/RTSN pin is a general purpose output. It is Low when OMR[2] is a 1 and High when OMR[2] is a O. + 1 The pin is a request-to-send output The logical stale of the pin is controlled by OMR[O]. When OMR[O] is set, the output is Low. + [5] SYNOUT/RTS - + 0 The SYNOUTN/RTSN pin is an active-Low output which is asserted one bit time after a SYN pattern (COP modes) in HSRH/HSRL or FLAG + (BOP modes) is detected in CCSR.The output remains asserted for one receiver clock period. + 1 The pin is a request-to-send output The,logical state of the pin Is controlled by OMR[O] when OMR[O] is set, the output is Low. + [4:3] RTxC- + 00 The pin is an input. It must be programmed for input when used as the input for the receiver or transmitter clock, the DPLL, or the CIT. + 01 The pin is an output for the counterltimer. + 10 The pin is an output for the transmitter shift register clock. + 11 The pin is an output for the receiver shift register clock. + [2:0]TRxC- + 000 The pin is an input. It must be programmed for input when used as the input for the receiver or transmitter clock, the DPLL, or the CIT. + 001 The pin is an output from the crystal oscillator divided by two. + 010 The pin is an outputfor the DPLL output clock. + 011 The pin is an output for the counterltimer. Refer to CTCRAIB description. + 100 The pin is an output for the transmitter BRG at 16X the rate selected by TTR [3:0]. + 101 The pin is an output for the receiver BRG at 16X the rate selected by RTR [3:0]. + 110 The pin is an output for the transmitter shift register clock. + 111 The pin is an output for the receiver shift register clock. +*/ +void duscc_channel::do_dusccreg_pcr_w(UINT8 data) +{ + LOG(("%s(%02x) Pin Configuration Register\n", FUNCNAME, data)); + m_pcr = data; + LOG(("- The X2/IDCN pin is %s\n", m_index == duscc_device::CHANNEL_B ? "ignored for channel B" : + ((m_pcr & REG_PCR_X2_IDC) ? "crystal input" : "daisy chain interrupt output"))); + LOG(("- The GP02/RTS pin is %s\n", m_pcr & REG_PCR_GP02_RTS ? "RTS" : "GP02")); + LOG(("- The SYNOUT/RTS pin is %s\n", m_pcr & REG_PCR_SYNOUT_RTS ? "RTS" : "SYNOUT")); + +#if VERBOSE > 0 + LOG(("- The RTxC pin is ")); + switch ( m_pcr & REG_PCR_RTXC_MASK ) + { + case REG_PCR_RTXC_INPUT: LOG(("- an input\n")); break; + case REG_PCR_RTXC_CNTR_OUT: LOG(("- a counter/timer output\n")); break; + case REG_PCR_RTXC_TXCLK_OUT:LOG(("- a Tx clock output\n")); break; + case REG_PCR_RTXC_RXCLK_OUT:LOG(("- a Rx clock output\n")); break; + default: LOG(("Wrong programming\n")); break; // Should never happen + } + LOG(("- The TRxC pin is ")); + switch( m_pcr & REG_PCR_TRXC_MASK ) + { + case REG_PCR_TRXC_INPUT: LOG(("- an input\n")); break; + case REG_PCR_TRXC_CRYST_OUT:LOG(("- a crystal/2 output\n")); break; + case REG_PCR_TRXC_DPLL_OUT: LOG(("- a DPLL output\n")); break; + case REG_PCR_TRXC_CNTR_OUT: LOG(("- a counter/timer output\n")); break; + case REG_PCR_TRXC_TXBRG_OUT:LOG(("- a Tx BRG output\n")); break; + case REG_PCR_TRXC_RXBRG_OUT:LOG(("- a Rx BRG output\n")); break; + case REG_PCR_TRXC_TXCLK_OUT:LOG(("- a Tx CLK output\n")); break; + case REG_PCR_TRXC_RXCLK_OUT:LOG(("- a Rx CLK output\n")); break; + default: LOG(("Wrong programming\n")); break; // Should never happen + } + +#endif + + return; +} + +/* + * Commands to the DUSCC are entered through the CCR channel command register. + * + * TODO: + * - support enable/disable of Tx/Rx using m_tra/m_rcv respectivelly + */ +void duscc_channel::do_dusccreg_ccr_w(UINT8 data) +{ + m_ccr = data; + LOG(("%s\n", FUNCNAME)); + switch(m_ccr) + { + + // TRANSMITTER COMMANDS + + /* Reset transmitter. Causes the transmitter to cease operation immediately. + The transmit FIFO is cleared and the TxD output goes into the marking state. + Also clears the transmitter status bits (TRSR[7:4]) and resets the TxRDY + status bit (GSR[I] or GSR[5] for Channels A and B, respectively). + The counter/timer and other registers are not affected*/ + case REG_CCR_RESET_TX: LOG(("- Reset Tx\n")); + set_tra_rate(0); + m_tx_fifo_wp = m_tx_fifo_rp = 0; + m_trsr &= 0x0f; + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + break; + + /* Enable transmitter. Enables transmitter operation, conditioned by the state of + the CTS ENABLE Tx bit, TPR[2]. Has no effect if invoked when the transmitter has + previously been enabled.*/ + case REG_CCR_ENABLE_TX: LOG(("- Enable Tx\n")); + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + m_tra = 1; + set_tra_rate(m_brg_tx_rate); + break; + + /* Disable transmitter. Terminates transmitter operation and places the TXD output in the + marking state at the next occurrence of a transmit FIFO empty condition. All characters + currently in the FIFO, or any loaded subsequently prior to attaining an empty condition, + will be transmitted. + TODO: let all the chararcters be transmitted before shutting down shifter */ + case REG_CCR_DISABLE_TX: LOG(("- Disable Tx\n")); + set_tra_rate(0); + m_tra = 0; + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + break; + + // RECEIVER COMMANDS + + /* Reset Receiver. Causes the receiver to cease operation, clears the receiver FIFO, + clears the data path, and clears the receiver status (RSR[7:0], TRSR[3:0], and either + GSR[O] or GSR[4] for Channels A and B, respectively). The counter/timer and other + registers are not affected.*/ + case REG_CCR_RESET_RX: LOG(("- Reset Rx\n")); + set_rcv_rate(0); + m_rx_fifo_wp = m_rx_fifo_rp = 0; + m_trsr &= 0xf0; + m_rsr = 0; + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + break; + + /* Enable receiver. Causes receiver operation to begin, conditioned by the state of the DCD + ENABLED Rx bit, RPR[2]. Receiver goes into START, SYN, or FLAG search mode depending on + channel protocol mode. Has no effect if invoked when the receiver has previously been enabled.*/ + case REG_CCR_ENABLE_RX: LOG(("- Enable Rx\n")); + m_rcv = 1; + set_rcv_rate(m_brg_rx_rate); + //m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + break; + + /* Disable receiver. Terminates operation of the receiver. Any character currently being assembled + will be lost. Does not affect FIFO or any status.*/ + case REG_CCR_DISABLE_RX: LOG(("- Disable Rx\n")); + m_rcv = 0; + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + break; + default: LOG((" - command %02x not implemented yet\n", data)); + } + return; +} + +void duscc_channel::do_dusccreg_txfifo_w(UINT8 data) +{ + LOG(("%s(%02x)'%c'\n", FUNCNAME,data, isalnum(data) ? data : ' ')); + LOG((" - TX wp:%d rp:%d sz:%d\n", m_tx_fifo_wp, m_tx_fifo_rp, m_tx_fifo_sz)); + + /* Tx FIFO is full or...? */ + if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )) + { + logerror("- TX FIFO is full, discarding data\n"); + LOG(("- TX FIFO is full, discarding data\n")); + } + else // ..there is still room + { + m_tx_data_fifo[m_tx_fifo_wp++] = data; + //m_rsr &= ~REG_RSR_OVERRUN_ERROR; + //m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + if (m_tx_fifo_wp >= m_tx_fifo_sz) + { + m_tx_fifo_wp = 0; + } + } + + /* Transmitter enabled? */ + if ( m_tra == 1 ) + { + if ( is_transmit_register_empty()) // Is the shift register loaded? + { + LOG(("- Setting up transmitter\n")); + transmit_register_setup(m_tx_data_fifo[m_tx_fifo_rp]); // Load the shift register, reload is done in tra_complete() + m_tx_fifo_rp_step(); + } + } + // check if Tx FIFO is FULL and set TxREADY accordingly + if (m_tx_fifo_wp + 1 == m_tx_fifo_rp || ( (m_tx_fifo_wp + 1 == m_tx_fifo_sz) && (m_tx_fifo_rp == 0) )) + { + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + } + else + { + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + } + + return; +} + +void duscc_channel::do_dusccreg_rsr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_trsr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ictsr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_gsr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ier_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ivr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_icr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } + +/* Short cutted non complex features */ +//void duscc_channel::do_dusccreg_rea_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +//void duscc_channel::do_dusccreg_sea_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } + +void duscc_channel::do_dusccreg_mrr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ier1_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ier2_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ier3_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_trcr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_ftlr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } +void duscc_channel::do_dusccreg_trmsr_w(UINT8 data){ logerror("register access method %s is not implemented yet\n", FUNCNAME); return; } + +//------------------------------------------------- +// control_read - read register +//------------------------------------------------- +UINT8 duscc_channel::read(offs_t &offset) +{ + UINT8 data = 0; + int reg = offset | m_a7; + + switch (reg) + { + case REG_CID: data = do_dusccreg_cid_r(); break; + case REG_CCR: data = do_dusccreg_ccr_r(); break; + case REG_RXFIFO_0: data = do_dusccreg_rxfifo_r(); break; + case REG_RXFIFO_1: data = do_dusccreg_rxfifo_r(); break; + case REG_RXFIFO_2: data = do_dusccreg_rxfifo_r(); break; + case REG_RXFIFO_3: data = do_dusccreg_rxfifo_r(); break; + case REG_GSR: data = do_dusccreg_gsr_r(); break; + default: + logerror(" \"%s\" %s: %c : Unsupported RRx register:%02x\n", m_owner->tag(), FUNCNAME, 'A' + m_index, reg); + } + + //LOG(("%s \"%s\": %c : Register R%d read '%02x'\n", FUNCNAME, m_owner->tag(), 'A' + m_index, reg, data)); + return data; +} + +//------------------------------------------------- +// write - write register +//------------------------------------------------- + +void duscc_channel::write(UINT8 data, offs_t &offset) +//WRITE8_MEMBER( duscc_channel::write) +{ + int reg = offset | m_a7; + + LOG(("\"%s\" %s: %c : Register write '%02x' -> [%02x]", m_owner->tag(), FUNCNAME, 'A' + m_index, data, reg )); + switch (reg) + { + case REG_SEA: /*Also REG_REA depending on which channel is written to */ + if ( m_uart->m_variant != SET_CMOS ) + { + logerror("Attempt set/clear the CDUSCC A7 bit on an NDUSCC\n"); + m_a7 = 0; + } + else + m_a7 = (m_index == duscc_device::CHANNEL_A ? 0x40 : 0); + break; + case REG_CMR1: do_dusccreg_cmr1_w(data); break; + case REG_CMR2: do_dusccreg_cmr2_w(data); break; + case REG_S1R: LOG(("REG_S1R \n")); break; + case REG_S2R: LOG(("REG_S2R \n")); break; + case REG_TPR: do_dusccreg_tpr_w(data); break; + case REG_TTR: do_dusccreg_ttr_w(data); break; + case REG_RPR: do_dusccreg_rpr_w(data); break; + case REG_RTR: do_dusccreg_rtr_w(data); break; + case REG_CTPRH: LOG(("REG_CTPRH\n")); break; + case REG_CTPRL: LOG(("REG_CTPRL\n")); break; + case REG_CTCR: LOG(("REG_CTCR\n")); break; + case REG_OMR: do_dusccreg_omr_w(data); break; + case REG_CTH: LOG(("REG_CTH \n")); break; + case REG_CTL: LOG(("REG_CTL \n")); break; + case REG_PCR: do_dusccreg_pcr_w(data); break; + case REG_CCR: do_dusccreg_ccr_w(data); break; + case REG_TXFIFO_0: do_dusccreg_txfifo_w(data); break; + case REG_TXFIFO_1: do_dusccreg_txfifo_w(data); break; + case REG_TXFIFO_2: do_dusccreg_txfifo_w(data); break; + case REG_TXFIFO_3: do_dusccreg_txfifo_w(data); break; + case REG_RSR: LOG(("REG_RSR \n")); break; + case REG_TRSR: LOG(("REG_TRSR\n")); break; + case REG_ICTSR: LOG(("REG_ICTSR\n")); break; + case REG_GSR: LOG(("REG_GSR \n")); break; + case REG_IER: LOG(("REG_IER \n")); break; +// case REG_CID: LOG(("REG_CID \n")); break; + case REG_IVR: LOG(("REG_IVR \n")); break; + case REG_ICR: LOG(("REG_ICR \n")); break; +// case REG_SEA: LOG(("REG_SEA \n")); break; +// case REG_IVRM: LOG(("REG_IVRM\n")); break; +// case REG_MRR: LOG(("REG_MRR \n")); break; + case REG_IER1: LOG(("REG_IER1\n")); break; + case REG_IER2: LOG(("REG_IER2\n")); break; + case REG_IER3: LOG(("REG_IER3\n")); break; + case REG_TRCR: LOG(("REG_TRCR\n")); break; + case REG_RFLR: LOG(("REG_RFLR\n")); break; + case REG_FTLR: LOG(("REG_FTLR\n")); break; + case REG_TRMSR: LOG(("REG_TRMSR\n")); break; + case REG_TELR: LOG(("REG_TELR\n")); break; + + default: + logerror(" \"%s\" %s: %c : Unsupported WRx register:%02x(%02x)\n", m_owner->tag(), FUNCNAME, 'A' + m_index, reg, data); + } +} + +/* Get data from top of fifo data but restore read pointer in case of exit latch lock */ +UINT8 duscc_channel::m_rx_fifo_rp_data() +{ + UINT8 data; + UINT8 old_rp = m_rx_fifo_rp; + m_rx_fifo_rp_step(); + data = m_rx_data_fifo[m_rx_fifo_rp]; + m_rx_fifo_rp = old_rp; + + return data; +} + +/* Step read pointer */ +void duscc_channel::m_rx_fifo_rp_step() +{ + m_rx_fifo_rp++; + if (m_rx_fifo_rp >= m_rx_fifo_sz) + { + m_rx_fifo_rp = 0; + } + + // check if FIFO is empty + if (m_rx_fifo_rp == m_rx_fifo_wp) + { + // no more characters available in the FIFO + // m_rr0 &= ~ RR0_RX_CHAR_AVAILABLE; + m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + } +} + +/* Step TX read pointer */ +void duscc_channel::m_tx_fifo_rp_step() +{ + m_tx_fifo_rp++; + if (m_tx_fifo_rp >= m_tx_fifo_sz) + { + m_tx_fifo_rp = 0; + } +} + +//------------------------------------------------- +// receive_data - receive data word into fifo +//------------------------------------------------- + +void duscc_channel::receive_data(UINT8 data) +{ + LOG(("\"%s\": %c : Receive Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, data)); +# + if (m_rx_fifo_wp + 1 == m_rx_fifo_rp || ( (m_rx_fifo_wp + 1 == m_rx_fifo_sz) && (m_rx_fifo_rp == 0) )) + { + // receive overrun error detected + m_rsr |= REG_RSR_OVERRUN_ERROR; + logerror("Receive_data() Error %02x\n", m_rsr); + } + else + { + m_rx_data_fifo[m_rx_fifo_wp] = data; + m_rx_error_fifo[m_rx_fifo_wp] &= ~REG_RSR_OVERRUN_ERROR; + m_rsr &= ~REG_RSR_OVERRUN_ERROR; + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY); + + m_rx_fifo_wp++; + if (m_rx_fifo_wp >= m_rx_fifo_sz) + { + m_rx_fifo_wp = 0; + } + } +} + + +//------------------------------------------------- +// cts_w - clear to send handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( duscc_channel::cts_w ) +{ + LOG(("\"%s\" %s: %c : CTS %u\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); + + if (m_cts != state) + { + // enable transmitter if in auto enables mode + if (!state) + { + m_ictsr |= REG_ICTSR_DELTA_CTS; + } + else + { + m_ictsr &= ~REG_ICTSR_DELTA_CTS; + } + + if (m_tpr & REG_TPR_CTS && m_tra) + { + m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY); + } + + // set clear to send + m_cts = state; + } +} + + +//------------------------------------------------- +// dcd_w - data carrier detected handler +//------------------------------------------------- +WRITE_LINE_MEMBER( duscc_channel::dcd_w ) +{ + LOG(("\"%s\" %s: %c : DCD %u - not implemented\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); +#if 0 + + if (m_dcd != state) + { + // enable receiver if in auto enables mode + if (!state) + if (reg & REG_AUTO_ENABLES) + { + reg |= REG_RX_ENABLE; + } + + // set data carrier detect + m_dcd = state; + } +#endif +} + +//------------------------------------------------- +// ri_w - ring indicator handler +//------------------------------------------------- + +WRITE_LINE_MEMBER( duscc_channel::ri_w ) +{ + LOG(("\"%s\" %s: %c : RI %u - not implemented\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); +#if 0 + if (m_ri != state) + { + // set ring indicator state + m_ri = state; + } +#endif +} + +//------------------------------------------------- +// sync_w - sync handler +//------------------------------------------------- +WRITE_LINE_MEMBER( duscc_channel::sync_w ) +{ + LOG(("\"%s\" %s: %c : SYNC %u - not implemented\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); +} + +//------------------------------------------------- +// rxc_w - receive clock +//------------------------------------------------- +WRITE_LINE_MEMBER( duscc_channel::rxc_w ) +{ + LOG(("\"%s\" %s: %c : RXC %u - not implemented\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); +} + +//------------------------------------------------- +// txc_w - transmit clock +//------------------------------------------------- +WRITE_LINE_MEMBER( duscc_channel::txc_w ) +{ + LOG(("\"%s\" %s: %c : TXC %u - not implemented\n", m_owner->tag(), FUNCNAME, 'A' + m_index, state)); +} + +//------------------------------------------------- +// update_serial - +//------------------------------------------------- +void duscc_channel::update_serial() +{ + int data_bit_count = get_rx_word_length(); + stop_bits_t stop_bits = get_stop_bits(); + parity_t parity; + + if ((m_cmr1 & REG_CMR1_PMMODE_MASK) == REG_CMR1_PMMODE_PARITY) + { + if ( (m_cmr1 & REG_CMR1_PARITY) == 0) + parity = PARITY_EVEN; + else + parity = PARITY_ODD; + } + else + parity = PARITY_NONE; + + LOG((LLFORMAT " %s() \"%s \"Channel %c setting data frame %d+%d%c%d\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, 1, + data_bit_count, parity == PARITY_NONE ? 'N' : parity == PARITY_EVEN ? 'E' : 'O', (stop_bits + 1) / 2)); + + set_data_frame(1, data_bit_count, parity, stop_bits); + + int clocks = get_rx_clock_mode(); + + if (m_rxc > 0) + { + set_rcv_rate(m_rxc / clocks); + LOG((" - Receiver clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks)); + } + + clocks = get_tx_clock_mode(); + if (m_txc > 0) + { + set_tra_rate(m_txc / clocks); + LOG((" - Transmit clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks)); + } + + if (m_brg_rx_rate != 0) + { + if (m_brg_rx_rate == 1) m_brg_rx_rate = 0; // BRG beeing disabled + set_rcv_rate(m_brg_rx_rate); + LOG((" - Baud Rate Generator: %d mode: RX:%dx\n", m_brg_rx_rate, get_rx_clock_mode())); + } + if (m_brg_tx_rate != 0) + { + if (m_brg_tx_rate == 1) m_brg_tx_rate = 0; // BRG beeing disabled + set_tra_rate(m_brg_tx_rate); + LOG((" - Baud Rate Generator: %d mode: TX:%dx\n", m_brg_tx_rate, get_tx_clock_mode())); + } +} + +//------------------------------------------------- +// set_dtr - +//------------------------------------------------- +void duscc_channel::set_dtr(int state) +{ + LOG(("%s(%d)\n", FUNCNAME, state)); + m_dtr = state; + + if (m_index == duscc_device::CHANNEL_A) + m_uart->m_out_dtra_cb(m_dtr); + else + m_uart->m_out_dtrb_cb(m_dtr); +} + + + +//------------------------------------------------- +// write_rx - called by terminal through rs232/diserial +// when character is sent to board +//------------------------------------------------- +WRITE_LINE_MEMBER(duscc_channel::write_rx) +{ + m_rxd = state; + //only use rx_w when self-clocked + if(m_rxc != 0 || m_brg_rx_rate != 0) + device_serial_interface::rx_w(state); +} diff --git a/src/devices/machine/scnxx562.h b/src/devices/machine/scnxx562.h new file mode 100644 index 00000000000..917f816228a --- /dev/null +++ b/src/devices/machine/scnxx562.h @@ -0,0 +1,698 @@ +// license:BSD-3-Clause +// copyright-holders:Joakim Larsson Edstrom +/*************************************************************************** + + Philips DUSCC - Dual Serial Communications Controller emulation + +**************************************************************************** + + Chan B Chan A Chan B Chan A + ======= _____ _____ ======== ======= _____ _____ ======== + IACKN 1|* \_/ |48 VCC IACKN 1|* \_/ |48 VDD + A3 2| |47 A4 A3 2| |47 A4 + A2 3| |46 A5 A2 3| |46 A5 + A1 4| |45 A6 A1 4| |45 A6 + RTxDAK/GPI1 5| |44 RTxDAK/GPI1 5| |44 RTxDAK/GP1 + IRQN 6| |43 X1/CLK IRQN 6| |43 X1/CLK + RDYN 7| |42 X2 RESETN 7| |42 X2 + RTS/SYNOUT 8| |41 RTS/SYNOUT 8| |41 RTS/SYNOUT + TRxC 9| |40 TRxC TRxC 9| |40 TRxC + RTxC 10| |39 RTxC RTxC 10| |39 RTxC + DCD/SYNI 11| |38 DCD/SYNI 11| |38 DCD/SYNI + RxD 12| |37 RxD RxD 12| |37 RxD + TxD 13| SCN26562 |36 TxD TxD 13| SCN68562 |36 TxD + TxDAK/GPI2 14| SCN26C562 |35 TxDAK/GPI2 14| SCN68C562 |35 TxDAK/GPI2 + RTxDRQ/GPO1 15| |34 RTxDRQ/GPO1 15| |34 RTxDRQ/GPO1 + TxDRQ/RTS/GPO2 16| |33 TxDRQ/RTS/GPO2 16| |33 TxDRQ/RTS/GPO2 + CTS/LC 17| |32 CTS/LC CTS/LC 17| |32 CTS/LC + D7 18| |31 D0 D7 18| |31 D0 + D6 19| |30 D1 D6 19| |30 D1 + D5 20| |29 D2 D5 20| |29 D2 + D4 21| |28 D3 D4 21| |28 D3 + RDN 22| |27 EOPN DTACKN 22| |27 DONEN + RESETN 23| |26 WRN DTCN 23| |26 R/WN + GND 24|_____________|25 CEN CND 24|_____________|25 CSN + Intel Bus Motorola Bus + +***************************************************************************/ + +#ifndef __SCNXX562_H__ +#define __SCNXX562_H__ + +#include "emu.h" + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define LOCAL_BRG 0 + +/* Variant ADD macros - use the right one to enable the right feature set! */ +#define MCFG_DUSCC26562_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, DUSCC26562, _clock) \ + MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_DUSCC26C562_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, DUSCC26C562, _clock) \ + MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_DUSCC68562_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, DUSCC68562, _clock) \ + MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) + +#define MCFG_DUSCC68C562_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, DUSCC68C562, _clock) \ + MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) + +/* generic ADD macro - Avoid using it directly, see above for correct variant instead */ +#define MCFG_DUSCC_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, DUSCC, _clock) \ + MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) + +/* Generic macros */ +#define MCFG_DUSCC_OFFSETS(_rxa, _txa, _rxb, _txb) \ + duscc_device::configure_channels(*device, _rxa, _txa, _rxb, _txb); + +// Port A callbacks +#define MCFG_DUSCC_OUT_TXDA_CB(_devcb) \ + devcb = &duscc_device::set_out_txda_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_DTRA_CB(_devcb) \ + devcb = &duscc_device::set_out_dtra_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_RTSA_CB(_devcb) \ + devcb = &duscc_device::set_out_rtsa_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_SYNCA_CB(_devcb) \ + devcb = &duscc_device::set_out_synca_callback(*device, DEVCB_##_devcb); + +// Port B callbacks +#define MCFG_DUSCC_OUT_TXDB_CB(_devcb) \ + devcb = &duscc_device::set_out_txdb_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_DTRB_CB(_devcb) \ + devcb = &duscc_device::set_out_dtrb_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_RTSB_CB(_devcb) \ + devcb = &duscc_device::set_out_rtsb_callback(*device, DEVCB_##_devcb); + +#define MCFG_DUSCC_OUT_SYNCB_CB(_devcb) \ + devcb = &duscc_device::set_out_syncb_callback(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> duscc_channel + +class duscc_device; + +class duscc_channel : public device_t, + public device_serial_interface +{ + friend class duscc_device; + +public: + duscc_channel(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + + // device_serial_interface overrides + virtual void tra_callback() override; + virtual void tra_complete() override; + virtual void rcv_callback() override; + virtual void rcv_complete() override; + + // read register handlers + UINT8 do_dusccreg_cmr1_r(); + UINT8 do_dusccreg_cmr2_r(); + UINT8 do_dusccreg_s1r_r(); + UINT8 do_dusccreg_s2r_r(); + UINT8 do_dusccreg_tpr_r(); + UINT8 do_dusccreg_ttr_r(); + UINT8 do_dusccreg_rpr_r(); + UINT8 do_dusccreg_rtr_r(); + UINT8 do_dusccreg_ctprh_r(); + UINT8 do_dusccreg_ctprl_r(); + UINT8 do_dusccreg_ctcr_r(); + UINT8 do_dusccreg_omr_r(); + UINT8 do_dusccreg_cth_r(); + UINT8 do_dusccreg_ctl_r(); + UINT8 do_dusccreg_pcr_r(); + UINT8 do_dusccreg_ccr_r(); + UINT8 do_dusccreg_rxfifo_r(); + UINT8 do_dusccreg_rsr_r(); + UINT8 do_dusccreg_trsr_r(); + UINT8 do_dusccreg_ictsr_r(); + UINT8 do_dusccreg_gsr_r(); + UINT8 do_dusccreg_ier_r(); + UINT8 do_dusccreg_cid_r(); + UINT8 do_dusccreg_ivr_r(); + UINT8 do_dusccreg_icr_r(); + UINT8 do_dusccreg_ivrm_r(); + UINT8 do_dusccreg_mrr_r(); + UINT8 do_dusccreg_ier1_r(); + UINT8 do_dusccreg_ier2_r(); + UINT8 do_dusccreg_ier3_r(); + UINT8 do_dusccreg_trcr_r(); + UINT8 do_dusccreg_rflr_r(); + UINT8 do_dusccreg_ftlr_r(); + UINT8 do_dusccreg_trmsr_r(); + UINT8 do_dusccreg_telr_r(); + + // write register handlers + void do_dusccreg_cmr1_w(UINT8 data); + void do_dusccreg_cmr2_w(UINT8 data); + void do_dusccreg_s1r_w(UINT8 data); + void do_dusccreg_s2r_w(UINT8 data); + void do_dusccreg_tpr_w(UINT8 data); + void do_dusccreg_ttr_w(UINT8 data); + void do_dusccreg_rpr_w(UINT8 data); + void do_dusccreg_rtr_w(UINT8 data); + void do_dusccreg_ctprh_w(UINT8 data); + void do_dusccreg_ctprl_w(UINT8 data); + void do_dusccreg_ctcr_w(UINT8 data); + void do_dusccreg_omr_w(UINT8 data); + void do_dusccreg_pcr_w(UINT8 data); + void do_dusccreg_ccr_w(UINT8 data); + void do_dusccreg_txfifo_w(UINT8 data); + void do_dusccreg_rsr_w(UINT8 data); + void do_dusccreg_trsr_w(UINT8 data); + void do_dusccreg_ictsr_w(UINT8 data); + void do_dusccreg_gsr_w(UINT8 data); + void do_dusccreg_ier_w(UINT8 data); + // void do_dusccreg_rea_w(UINT8 data); // Short cutted non complex feature + void do_dusccreg_ivr_w(UINT8 data); + void do_dusccreg_icr_w(UINT8 data); + // void do_dusccreg_sea_w(UINT8 data); // Short cutted non complex feature + void do_dusccreg_mrr_w(UINT8 data); + void do_dusccreg_ier1_w(UINT8 data); + void do_dusccreg_ier2_w(UINT8 data); + void do_dusccreg_ier3_w(UINT8 data); + void do_dusccreg_trcr_w(UINT8 data); + void do_dusccreg_ftlr_w(UINT8 data); + void do_dusccreg_trmsr_w(UINT8 data); + + UINT8 read(offs_t &offset); + void write(UINT8 data, offs_t &offset); + + // UINT8 data_read(); + // void data_write(UINT8 data); + + void receive_data(UINT8 data); + void m_tx_fifo_rp_step(); + void m_rx_fifo_rp_step(); + UINT8 m_rx_fifo_rp_data(); + + DECLARE_WRITE_LINE_MEMBER( write_rx ); + DECLARE_WRITE_LINE_MEMBER( cts_w ); + DECLARE_WRITE_LINE_MEMBER( dcd_w ); + DECLARE_WRITE_LINE_MEMBER( ri_w ); + DECLARE_WRITE_LINE_MEMBER( rxc_w ); + DECLARE_WRITE_LINE_MEMBER( txc_w ); + DECLARE_WRITE_LINE_MEMBER( sync_w ); + + int m_rxc; + int m_txc; + int m_tra; + int m_rcv; + + // Register state + UINT8 m_cmr1; + UINT8 m_cmr2; + UINT8 m_s1r; + UINT8 m_s2r; + UINT8 m_tpr; + UINT8 m_ttr; + UINT8 m_rpr; + UINT8 m_rtr; + UINT8 m_ctprh; + UINT8 m_ctprl; + UINT8 m_ctcr; + UINT8 m_omr; + UINT8 m_cth; + UINT8 m_ctl; + UINT8 m_pcr; + UINT8 m_ccr; + UINT8 m_txfifo[4]; + UINT8 m_rxfifo[4]; + UINT8 m_rsr; + UINT8 m_trsr; + UINT8 m_ictsr; + UINT8 m_gsr; + UINT8 m_ier; + // UINT8 m_rea; + UINT8 m_cid; + UINT8 m_ivr; + UINT8 m_icr; + // UINT8 m_sea; + UINT8 m_ivrm; + UINT8 m_mrr; + UINT8 m_ier1; + UINT8 m_ier2; + UINT8 m_ier3; + UINT8 m_trcr; + UINT8 m_rflr; + UINT8 m_ftlr; + UINT8 m_trmsr; + UINT8 m_telr; + +protected: + enum + { + INT_TRANSMIT = 0, + INT_EXTERNAL = 1, + INT_RECEIVE = 2, + INT_SPECIAL = 3 + }; + + enum + { + REG_CCR_RESET_TX = 0x00, + REG_CCR_ENABLE_TX = 0x02, + REG_CCR_DISABLE_TX = 0x03, + REG_CCR_RESET_RX = 0x40, + REG_CCR_ENABLE_RX = 0x42, + REG_CCR_DISABLE_RX = 0x43 + }; + + enum + { + REG_CMR1_PARITY = 0x20, + REG_CMR1_PMMODE_MASK = 0x18, + REG_CMR1_PMMODE_NONE = 0x00, + REG_CMR1_PMMODE_RES = 0x01, + REG_CMR1_PMMODE_PARITY = 0x10, + REG_CMR1_PMMODE_FORCED = 0x11, + REG_CMR1_CPMODE_MASK = 0x07, + REG_CMR1_CPMODE_ASYNC = 0x07 + }; + + enum + { + REG_CMR2_DTI_MASK = 0x38, + REG_CMR2_DTI_NODMA = 0x38 + }; + + enum + { + REG_RPR_DATA_BITS_MASK = 0x03, + REG_RPR_DATA_BITS_5BIT = 0x00, + REG_RPR_DATA_BITS_6BIT = 0x01, + REG_RPR_DATA_BITS_7BIT = 0x02, + REG_RPR_DATA_BITS_8BIT = 0x03, + REG_RPR_DCD = 0x04, + REG_RPR_STRIP_PARITY = 0x08, + REG_RPR_RTS = 0x10 + }; + + enum + { + REG_TPR_DATA_BITS_MASK = 0x03, + REG_TPR_DATA_BITS_5BIT = 0x00, + REG_TPR_DATA_BITS_6BIT = 0x01, + REG_TPR_DATA_BITS_7BIT = 0x02, + REG_TPR_DATA_BITS_8BIT = 0x03, + REG_TPR_CTS = 0x04, + REG_TPR_RTS = 0x08, + REG_TPR_STOP_BITS_MASK = 0xf0 + }; + + enum + { + REG_TTR_EXT = 0x80, + REG_TTR_TXCLK_MASK = 0x70, + REG_TTR_TXCLK_1XEXT = 0x00, + REG_TTR_TXCLK_16XEXT = 0x10, + REG_TTR_TXCLK_DPLL = 0x20, + REG_TTR_TXCLK_BRG = 0x30, + REG_TTR_TXCLK_2X_OTHER = 0x40, + REG_TTR_TXCLK_32X_OTHER = 0x50, + REG_TTR_TXCLK_2X_OWN = 0x60, + REG_TTR_TXCLK_32X_OWN = 0x70, + REG_TTR_BRG_RATE_MASK = 0x0f, + }; + + enum + { + REG_RTR_EXT = 0x80, + REG_RTR_RXCLK_MASK = 0x70, + REG_RTR_RXCLK_1XEXT = 0x00, + REG_RTR_RXCLK_16XEXT = 0x10, + REG_RTR_RXCLK_BRG = 0x20, + REG_RTR_RXCLK_CT = 0x30, + REG_RTR_RXCLK_DPLL_64X_X1 = 0x40, + REG_RTR_RXCLK_DPLL_32X_EXT = 0x50, + REG_RTR_RXCLK_DPLL_32X_BRG = 0x60, + REG_RTR_RXCLK_DPLL_32X_CT = 0x70, + REG_RTR_BRG_RATE_MASK = 0x0f, + }; + + enum + { + REG_PCR_X2_IDC = 0x80, + REG_PCR_GP02_RTS = 0x40, + REG_PCR_SYNOUT_RTS = 0x20, + REG_PCR_RTXC_MASK = 0x18, + REG_PCR_RTXC_INPUT = 0x00, + REG_PCR_RTXC_CNTR_OUT = 0x08, + REG_PCR_RTXC_TXCLK_OUT = 0x10, + REG_PCR_RTXC_RXCLK_OUT = 0x18, + REG_PCR_TRXC_MASK = 0x07, + REG_PCR_TRXC_INPUT = 0x00, + REG_PCR_TRXC_CRYST_OUT = 0x01, + REG_PCR_TRXC_DPLL_OUT = 0x02, + REG_PCR_TRXC_CNTR_OUT = 0x03, + REG_PCR_TRXC_TXBRG_OUT = 0x04, + REG_PCR_TRXC_RXBRG_OUT = 0x05, + REG_PCR_TRXC_TXCLK_OUT = 0x06, + REG_PCR_TRXC_RXCLK_OUT = 0x07, + }; + + enum + { + REG_OMR_TXRCL_MASK = 0xe0, + REG_OMR_TXRCL_8BIT = 0xe0, + REG_OMR_TXRDY_ACTIVATED = 0x10, + REG_OMR_RXRDY_ACTIVATED = 0x08, + REG_OMR_GP02 = 0x04, + REG_OMR_GP01 = 0x02, + REG_OMR_RTS = 0x01, + }; + + enum + { + REG_RSR_OVERRUN_ERROR = 0x20, + }; + + enum + { + REG_ICTSR_DELTA_CTS = 0x10, + REG_ICTSR_DCD = 0x08, + REG_ICTSR_CTS = 0x04, + }; + + enum + { + REG_GSR_CHAN_A_RXREADY = 0x01, + REG_GSR_CHAN_B_RXREADY = 0x10, + REG_GSR_CHAN_A_TXREADY = 0x02, + REG_GSR_CHAN_B_TXREADY = 0x20, + }; + + // Register offsets, stripped from channel bit 0x20 but including A7 bit + enum + { + REG_CMR1 = 0x00, + REG_CMR2 = 0x01, + REG_S1R = 0x02, + REG_S2R = 0x03, + REG_TPR = 0x04, + REG_TTR = 0x05, + REG_RPR = 0x06, + REG_RTR = 0x07, + REG_CTPRH = 0x08, + REG_CTPRL = 0x09, + REG_CTCR = 0x0a, + REG_OMR = 0x0b, + REG_CTH = 0x0c, + REG_CTL = 0x0d, + REG_PCR = 0x0e, + REG_CCR = 0x0f, + REG_TXFIFO_0= 0x10, + REG_TXFIFO_1= 0x11, + REG_TXFIFO_2= 0x12, + REG_TXFIFO_3= 0x13, + REG_RXFIFO_0= 0x14, + REG_RXFIFO_1= 0x15, + REG_RXFIFO_2= 0x16, + REG_RXFIFO_3= 0x17, + REG_RSR = 0x18, + REG_TRSR = 0x19, + REG_ICTSR = 0x1a, + REG_GSR = 0x1b, + REG_IER = 0x1c, + REG_REA = 0x1d, + REG_CID = 0x1d, + REG_IVR = 0x1e, + REG_ICR = 0x1f, + REG_SEA = 0x1d, + REG_IVRM = 0x1e, + REG_MRR = 0x1f, + REG_IER1 = 0x42, + REG_IER2 = 0x43, + REG_IER3 = 0x45, + REG_TRCR = 0x47, + REG_RFLR = 0x4e, + REG_FTLR = 0x5c, + REG_TRMSR = 0x5e, + REG_TELR = 0x5f, + }; + + enum + { + TIMER_ID_BAUD, + TIMER_ID_XTAL, + TIMER_ID_RTXC, + TIMER_ID_TRXC + }; + + UINT16 m_brg_rx_rate; + UINT16 m_brg_tx_rate; + UINT16 m_brg_const; + + // TODO: Implement the 14.4K, 56K and 64K bauds available on the CDUSCC + static unsigned int get_baudrate(unsigned int br) + { + switch (br) + { + case 0x00: return 50; break; + case 0x01: return 75; break; + case 0x02: return 110; break; + case 0x03: return 134; break; + case 0x04: return 150; break; + case 0x05: return 200; break; + case 0x06: return 300; break; + case 0x07: return 600; break; + case 0x08: return 1050; break; + case 0x09: return 1200; break; + case 0x0a: return 2000; break; + case 0x0b: return 2400; break; + case 0x0c: return 4800; break; + case 0x0d: return 9600; break; + case 0x0e: return 19200; break; + case 0x0f: return 38400; break; + }; + return 0; + } + + void update_serial(); + void set_dtr(int state); + void set_rts(int state); + + int get_tx_clock_mode(); + int get_rx_clock_mode(); + stop_bits_t get_stop_bits(); + int get_rx_word_length(); + int get_tx_word_length(); + + /* FIFOs and rx/tx status */ + /* Receiver */ + UINT8 m_rx_data_fifo[16]; // data FIFO + UINT8 m_rx_error_fifo[16]; // error FIFO + int m_rx_fifo_rp; // FIFO read pointer + int m_rx_fifo_wp; // FIFO write pointer + int m_rx_fifo_sz; // FIFO size + UINT8 m_rx_error; // current error + + /* Transmitter */ + UINT8 m_tx_data_fifo[16]; // data FIFO + UINT8 m_tx_error_fifo[16]; // error FIFO + int m_tx_fifo_rp; // FIFO read pointer + int m_tx_fifo_wp; // FIFO write pointer + int m_tx_fifo_sz; // FIFO size + UINT8 m_tx_error; // current error + + int m_rx_clock; // receive clock pulse count + int m_rx_first; // first character received + int m_rx_break; // receive break condition + // UINT8 m_rx_rr0_latch; // read register 0 latched + + int m_rxd; + int m_ri; // ring indicator latch + int m_cts; // clear to send latch + int m_dcd; // data carrier detect latch + + // transmitter state + UINT8 m_tx_data; // transmit data register + int m_tx_clock; // transmit clock pulse count + + int m_dtr; // data terminal ready + int m_rts; // request to send + + // synchronous state + UINT16 m_sync; // sync character + + int m_rcv_mode; + int m_index; + duscc_device *m_uart; + + // CDUSCC specifics + int m_a7; // Access additional registers +}; + + +// ======================> duscc_device + + +class duscc_device : public device_t +// ,public device_z80daisy_interface +{ + friend class duscc_channel; + +public: + // construction/destruction + duscc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, UINT32 variant, const char *shortname, const char *source); + duscc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + template<class _Object> static devcb_base &set_out_txda_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_txda_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_dtra_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_dtra_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_rtsa_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_rtsa_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_synca_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_synca_cb.set_callback(object); } + + template<class _Object> static devcb_base &set_out_txdb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_txdb_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_dtrb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_dtrb_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_rtsb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_rtsb_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_syncb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_syncb_cb.set_callback(object); } + + static void configure_channels(device_t &device, int rxa, int txa, int rxb, int txb) + { +#if 0 // TODO: Fix this, need a way to set external rx/tx clocks for the channels + duscc_device &dev = downcast<duscc_device &>(device); + dev.m_chanA->m_rxc = rxa; + dev.m_chanA->m_txc = txa; + dev.m_chanB->m_rxc = rxb; + dev.m_chanB->m_txc = txb; +#endif + } + + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + + // interrupt acknowledge + // 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); } + DECLARE_WRITE_LINE_MEMBER( ctsa_w ) { m_chanA->cts_w(state); } + DECLARE_WRITE_LINE_MEMBER( ctsb_w ) { m_chanB->cts_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcda_w ) { m_chanA->dcd_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcdb_w ) { m_chanB->dcd_w(state); } + DECLARE_WRITE_LINE_MEMBER( ria_w ) { m_chanA->ri_w(state); } + DECLARE_WRITE_LINE_MEMBER( rib_w ) { m_chanB->ri_w(state); } +#if 0 + DECLARE_WRITE_LINE_MEMBER( rxca_w ) { m_chanA->rxc_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxcb_w ) { m_chanB->rxc_w(state); } + DECLARE_WRITE_LINE_MEMBER( txca_w ) { m_chanA->txc_w(state); } + DECLARE_WRITE_LINE_MEMBER( txcb_w ) { m_chanB->txc_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxtxcb_w ) { m_chanB->rxc_w(state); m_chanB->txc_w(state); } +#endif + DECLARE_WRITE_LINE_MEMBER( synca_w ) { m_chanA->sync_w(state); } + DECLARE_WRITE_LINE_MEMBER( syncb_w ) { m_chanB->sync_w(state); } + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual machine_config_constructor device_mconfig_additions() const override; + + // internal interrupt management + void check_interrupts(); + void reset_interrupts(); + UINT8 modify_vector(UINT8 vect, int i, UINT8 src); + void trigger_interrupt(int index, int state); + int get_channel_index(duscc_channel *ch) { return (ch == m_chanA) ? 0 : 1; } + + // Variants in the DUSCC family + enum + { + TYPE_DUSCC = 0x001, + TYPE_DUSCC26562 = 0x002, + TYPE_DUSCC26C562 = 0x004, + TYPE_DUSCC68562 = 0x008, + TYPE_DUSCC68C562 = 0x010, + }; + +#define SET_NMOS ( duscc_device::TYPE_DUSCC26562 | duscc_device::TYPE_DUSCC68562 ) +#define SET_CMOS ( duscc_device::TYPE_DUSCC26C562 | duscc_device::TYPE_DUSCC68C562 ) + + enum + { + CHANNEL_A = 0, + CHANNEL_B + }; + + required_device<duscc_channel> m_chanA; + required_device<duscc_channel> m_chanB; + + // internal state +#if 0 + int m_rxca; + int m_txca; + int m_rxcb; + int m_txcb; +#endif + + devcb_write_line m_out_txda_cb; + devcb_write_line m_out_dtra_cb; + devcb_write_line m_out_rtsa_cb; + devcb_write_line m_out_synca_cb; + + devcb_write_line m_out_txdb_cb; + devcb_write_line m_out_dtrb_cb; + devcb_write_line m_out_rtsb_cb; + devcb_write_line m_out_syncb_cb; + + int m_int_state[6]; // interrupt state + + int m_variant; +}; + +// device type definition +extern const device_type DUSCC; +extern const device_type DUSCC_CHANNEL; +extern const device_type DUSCC26562; +extern const device_type DUSCC26C562; +extern const device_type DUSCC68562; +extern const device_type DUSCC68C562; + +class duscc26562_device : public duscc_device +{ +public : + duscc26562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class duscc26C562_device : public duscc_device +{ +public : + duscc26C562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class duscc68562_device : public duscc_device +{ +public : + duscc68562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class duscc68C562_device : public duscc_device +{ +public : + duscc68C562_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +#endif // __SCNXX562_H__ |