diff options
author | 2017-01-16 23:49:55 +0100 | |
---|---|---|
committer | 2017-01-16 23:49:55 +0100 | |
commit | a2f105b8e44283a6f3d467d98095903e6fd23abb (patch) | |
tree | 2c4fbe9d351b6a05fc0d95317769d0bbb8ddc1c6 /src | |
parent | b7f222a94a19d4269df8ded8efd29db50c223964 (diff) |
- WIP: Refactored device: MPCC 68561 (nw)
- 68230 PIT: Added support for the PSR register, H1-H4 sense and direct pin levels
- WIP: fccpu20: added mpcc device and serial interface (nw)
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/machine/68230pit.cpp | 85 | ||||
-rw-r--r-- | src/devices/machine/68230pit.h | 19 | ||||
-rw-r--r-- | src/devices/machine/68561mpcc.cpp | 902 | ||||
-rw-r--r-- | src/devices/machine/68561mpcc.h | 365 | ||||
-rw-r--r-- | src/mame/drivers/fccpu20.cpp | 50 |
5 files changed, 931 insertions, 490 deletions
diff --git a/src/devices/machine/68230pit.cpp b/src/devices/machine/68230pit.cpp index 2e03051727a..9f7f71e6028 100644 --- a/src/devices/machine/68230pit.cpp +++ b/src/devices/machine/68230pit.cpp @@ -31,7 +31,7 @@ #define LOG_DR 0x20 #define LOG_INT 0x40 -#define VERBOSE 0 // (LOG_PRINTF | LOG_SETUP | LOG_GENERAL | LOG_INT | LOG_BIT | LOG_DR) +#define VERBOSE 0 //(LOG_PRINTF | LOG_SETUP | LOG_GENERAL | LOG_INT | LOG_BIT | LOG_DR) #define LOGMASK(mask, ...) do { if (VERBOSE & mask) logerror(__VA_ARGS__); } while (0) #define LOGLEVEL(mask, level, ...) do { if ((VERBOSE & mask) >= level) logerror(__VA_ARGS__); } while (0) @@ -142,19 +142,30 @@ pit68230_device::pit68230_device(const machine_config &mconfig, const char *tag, //------------------------------------------------- void pit68230_device::device_start () { - LOG("%s\n", FUNCNAME); + LOGSETUP("%s\n", FUNCNAME); - // resolve callbacks + // NOTE: + // Not using resolve_safe for the m_px_in_cb's is a temporary way to be able to check + // if a handler is installed with isnull(). The safe function installs a dummy default + // handler which disable the isnull() test. TODO: Need a better fix? + + // resolve callbacks Port A m_pa_out_cb.resolve_safe(); m_pa_in_cb.resolve(); + + // resolve callbacks Port B m_pb_out_cb.resolve_safe(); m_pb_in_cb.resolve(); + + // resolve callbacks Port C m_pc_out_cb.resolve_safe(); - m_pc_in_cb.resolve(); // A temporary way to check if handler is installed with isnull(). TODO: Need better fix. + m_pc_in_cb.resolve(); + m_h1_out_cb.resolve_safe(); m_h2_out_cb.resolve_safe(); m_h3_out_cb.resolve_safe(); m_h4_out_cb.resolve_safe(); + m_tirq_out_cb.resolve_safe(); m_pirq_out_cb.resolve_safe(); @@ -186,7 +197,7 @@ void pit68230_device::device_start () //------------------------------------------------- void pit68230_device::device_reset () { - LOG("%s %s \n",tag(), FUNCNAME); + LOGSETUP("%s %s \n",tag(), FUNCNAME); m_pgcr = 0; m_psrr = 0; @@ -203,6 +214,7 @@ void pit68230_device::device_reset () m_tcr = 0; m_tivr = 0x0f; m_tirq_out_cb(CLEAR_LINE); m_tsr = 0; + LOGSETUP("%s %s DONE!\n",tag(), FUNCNAME); } /* @@ -280,9 +292,60 @@ void pit68230_device::device_timer (emu_timer &timer, device_timer_id id, int32_ } } -void pit68230_device::h1_set (uint8_t state) +WRITE_LINE_MEMBER( pit68230_device::h1_w ) +{ + LOGBIT("%s %s H1 set to %d\n", tag(), FUNCNAME, state); + + // Set the direct level in PSR + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H1L) : (m_psr | REG_PSR_H1L)); + + // Set the programmed assert level in PSR + if (m_pgcr & REG_PGCR_H1_SENSE) + m_psr = ((state != 0) ? (m_psr & ~REG_PSR_H1S) : (m_psr | REG_PSR_H1S)); + else + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H1S) : (m_psr | REG_PSR_H1S)); +} + +WRITE_LINE_MEMBER( pit68230_device::h2_w ) { - if (state) m_psr |= 1; else m_psr &= ~1; + LOGBIT("%s %s H2 set to %d\n", tag(), FUNCNAME, state); + + // Set the direct level in PSR + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H2L) : (m_psr | REG_PSR_H2L)); + + // Set the programmed assert level in PSR + if (m_pgcr & REG_PGCR_H2_SENSE) + m_psr = ((state != 0) ? (m_psr & ~REG_PSR_H2S) : (m_psr | REG_PSR_H2S)); + else + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H2S) : (m_psr | REG_PSR_H2S)); +} + +WRITE_LINE_MEMBER( pit68230_device::h3_w ) +{ + LOGBIT("%s %s H3 set to %d\n", tag(), FUNCNAME, state); + + // Set the direct level in PSR + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H3L) : (m_psr | REG_PSR_H3L)); + + // Set the programmed assert level in PSR + if (m_pgcr & REG_PGCR_H3_SENSE) + m_psr = ((state != 0) ? (m_psr & ~REG_PSR_H3S) : (m_psr | REG_PSR_H3S)); + else + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H3S) : (m_psr | REG_PSR_H3S)); +} + +WRITE_LINE_MEMBER( pit68230_device::h4_w ) +{ + LOGBIT("%s %s H4 set to %d\n", tag(), FUNCNAME, state); + + // Set the direct level in PSR + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H4L) : (m_psr | REG_PSR_H4L)); + + // Set the programmed assert level in PSR + if (m_pgcr & REG_PGCR_H4_SENSE) + m_psr = ((state != 0) ? (m_psr & ~REG_PSR_H4S) : (m_psr | REG_PSR_H4S)); + else + m_psr = ((state == 0) ? (m_psr & ~REG_PSR_H4S) : (m_psr | REG_PSR_H4S)); } // TODO: remove this method and replace it with a call to pb_update_bit() in force68k.cpp @@ -293,7 +356,7 @@ void pit68230_device::portb_setbit(uint8_t bit, uint8_t state) void pit68230_device::pa_update_bit(uint8_t bit, uint8_t state) { - LOGBIT("%s %s bit %d to %d\n",tag(), FUNCNAME, bit, state); + LOGBIT("%s %s bit %d to %d\n", tag(), FUNCNAME, bit, state); // Check if requested bit is an output bit and can't be affected if (m_paddr & (1 << bit)) { @@ -860,9 +923,8 @@ the instantaneous pin level is read and no input latching is performed except at data bus interface. Writes to this address are answered with DTACK, but the data is ignored.*/ uint8_t pit68230_device::rr_pitreg_paar() { - // NOTE: no side effect emulated so using ..padr uint8_t ret; - ret = m_pa_in_cb(); + ret = m_pa_in_cb.isnull() ? 0 : m_pa_in_cb(); LOGR("%s %s <- %02x\n",tag(), FUNCNAME, ret); return ret; } @@ -873,9 +935,8 @@ the instantaneous pin level is read and no input latching is performed except at data bus interface.Writes to this address are answered with DTACK, but the data is ignored.*/ uint8_t pit68230_device::rr_pitreg_pbar() { - // NOTE: no side effect emulated so using ..pbdr uint8_t ret; - ret = m_pb_in_cb(); + ret = m_pb_in_cb.isnull() ? 0 : m_pb_in_cb(); LOGR("%s %s <- %02x\n",tag(), FUNCNAME, ret); return ret; } diff --git a/src/devices/machine/68230pit.h b/src/devices/machine/68230pit.h index 79c30aa0b2a..396ba854891 100644 --- a/src/devices/machine/68230pit.h +++ b/src/devices/machine/68230pit.h @@ -131,7 +131,8 @@ class pit68230_device : public device_t//, public device_execute_interface DECLARE_WRITE8_MEMBER (write); DECLARE_READ8_MEMBER (read); - void h1_set (uint8_t state); + // TODO: remove these methods and replace it with a call to methods below in force68k.cpp + void h1_set (uint8_t state){ if (state) m_psr |= 1; else m_psr &= ~1; } void portb_setbit (uint8_t bit, uint8_t state); // Bit updaters @@ -140,6 +141,11 @@ class pit68230_device : public device_t//, public device_execute_interface void pc_update_bit(uint8_t bit, uint8_t state); void update_tin(uint8_t); + DECLARE_WRITE_LINE_MEMBER( h1_w ); + DECLARE_WRITE_LINE_MEMBER( h2_w ); + DECLARE_WRITE_LINE_MEMBER( h3_w ); + DECLARE_WRITE_LINE_MEMBER( h4_w ); + DECLARE_WRITE_LINE_MEMBER( pa0_w ){ pa_update_bit(0, state); } DECLARE_WRITE_LINE_MEMBER( pa1_w ){ pa_update_bit(1, state); } DECLARE_WRITE_LINE_MEMBER( pa2_w ){ pa_update_bit(2, state); } @@ -270,6 +276,17 @@ protected: }; enum { + REG_PSR_H1S = 0x01, + REG_PSR_H2S = 0x02, + REG_PSR_H3S = 0x04, + REG_PSR_H4S = 0x08, + REG_PSR_H1L = 0x10, + REG_PSR_H2L = 0x20, + REG_PSR_H3L = 0x40, + REG_PSR_H4L = 0x80, + }; + + enum { REG_TCR_TIMER_ENABLE = 0x01 }; diff --git a/src/devices/machine/68561mpcc.cpp b/src/devices/machine/68561mpcc.cpp index 7ee3880877c..0535d36fb5e 100644 --- a/src/devices/machine/68561mpcc.cpp +++ b/src/devices/machine/68561mpcc.cpp @@ -1,481 +1,585 @@ -// license:BSD-3-Clause -// copyright-holders:Sergey Svishchev -/********************************************************************* - - 68561mpcc.c - - Rockwell 68561 MPCC (Multi Protocol Communications Controller) - - skeleton driver, just enough for besta.c console to work - -*********************************************************************/ +// license:BSD-3-Clause copyright-holders: Joakim Larsson Edstrom +/*************************************************************************** + MPCC Multi-Protocol Communications Controller emulation + + The MPCC was introduced in the late 80:ies by Rockwell + + The variants in the MPCC family are as follows: + + - 68560 with an 8 bit data bus + - 68560A with an 8 bit data bus and some enhancements + - 68561 with a 16 bit data bus + - 68561A with a 16 bit data bus and some enhancements + +FEATURES +------------------------------------------------------------------ + * Full duplex synchronous/asynchronous receiver and transmitter + * Implements IBM Binary Synchronous Communications (BSC) in two coding formats: ASCII and EBCDIC + * Supports other synchronous character -oriented protocols (COP), such as six -bit BSC, X3.28k. ISO IS1745, ECMA-16, etc. + * Supports synchronous bit oriented protocols (BOP), such as SDLC, HDLC, X.25, etc. + * Asynchronous and isochronous modes + * Modem handshake interface + * High speed serial data rate (DC to 4 MHz) + * Internal oscillator and baud rate generator with programmable data rate + * Crystal or TTL level clock input and buffered clock output (8 MHz) + * Direct interface to 68008/68000 asynchronous bus + * Eight -character receiver and transmitter buffer registers + * 22 directly addressable registers for flexible option selection, complete status reporting, and data transfer + * Three separate programmable interrupt vector numbers for receiver, transmitter and serial interface + * Maskable interrupt conditions for receiver, transmitter and serial interface + * Programmable microprocessor bus data transfer; polled, interrupt and two -channel DMA transfer compatible with MC68440/MC68450 + * Clock control register for receiver clock divisor and receiver and transmitter clock routing + * Selectable full/half duplex, autoecho and local loop -back modes + * Selectable parity (enable, odd, even) and CRC (control field enable, CRC -16, CCITT V.41, VRC/LRC) + *------------------------------------------------------------------------------------------- + * x = Features that has been implemented p = partly n = features that will not + *------------------------------------------------------------------------------------------- +*/ #include "emu.h" #include "68561mpcc.h" -const device_type MPCC68561 = &device_creator<mpcc68561_t>; - - -/*************************************************************************** - PARAMETERS -***************************************************************************/ - -#define LOG_MPCC (1) +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** +#define LOG_GENERAL 0x001 +#define LOG_SETUP 0x002 +#define LOG_PRINTF 0x004 +#define LOG_READ 0x008 +#define LOG_INT 0x010 +#define LOG_CMD 0x020 +#define LOG_TX 0x040 +#define LOG_RCV 0x080 +#define LOG_CTS 0x100 +#define LOG_DCD 0x200 +#define LOG_SYNC 0x400 +#define LOG_CHAR 0x800 + +#define VERBOSE 0 // (LOG_PRINTF | LOG_SETUP | LOG_GENERAL) + +#define LOGMASK(mask, ...) do { if (VERBOSE & mask) logerror(__VA_ARGS__); } while (0) +#define LOGLEVEL(mask, level, ...) do { if ((VERBOSE & mask) >= level) logerror(__VA_ARGS__); } while (0) + +#define LOG(...) LOGMASK(LOG_GENERAL, __VA_ARGS__) +#define LOGSETUP(...) LOGMASK(LOG_SETUP, __VA_ARGS__) +#define LOGR(...) LOGMASK(LOG_READ, __VA_ARGS__) +#define LOGINT(...) LOGMASK(LOG_INT, __VA_ARGS__) +#define LOGCMD(...) LOGMASK(LOG_CMD, __VA_ARGS__) +#define LOGTX(...) LOGMASK(LOG_TX, __VA_ARGS__) +#define LOGRCV(...) LOGMASK(LOG_RCV, __VA_ARGS__) +#define LOGCTS(...) LOGMASK(LOG_CTS, __VA_ARGS__) +#define LOGDCD(...) LOGMASK(LOG_DCD, __VA_ARGS__) +#define LOGSYNC(...) LOGMASK(LOG_SYNC, __VA_ARGS__) +#define LOGCHAR(...) LOGMASK(LOG_CHAR, __VA_ARGS__) + +#if VERBOSE & LOG_PRINTF +#define logerror printf +#endif -/*************************************************************************** - IMPLEMENTATION -***************************************************************************/ +#ifdef _MSC_VER +#define FUNCNAME __func__ +#define LLFORMAT "%I64d" +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#define LLFORMAT "%lld" +#endif -mpcc68561_t::mpcc68561_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, MPCC68561, "Rockwell 68561 MPCC", tag, owner, clock, "mpcc68561", __FILE__), mode(0), reg(0), status(0), IRQV(0), MasterIRQEnable(0), lastIRQStat(0), IRQType(), - intrq_cb(*this) +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** +// device type definition +const device_type MPCC = &device_creator<mpcc_device>; +const device_type MPCC68560 = &device_creator<mpcc68560_device>; +const device_type MPCC68560A = &device_creator<mpcc68560A_device>; +const device_type MPCC68561 = &device_creator<mpcc68561_device>; +const device_type MPCC68561A = &device_creator<mpcc68561A_device>; + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +mpcc_device::mpcc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, uint32_t variant, const char *shortname, const char *source) + : device_t(mconfig, type, name, tag, owner, clock, shortname, source), + device_serial_interface(mconfig, *this), + m_variant(variant), + m_rxc(0), + m_txc(0), + m_brg_rate(0), + m_rcv(0), + m_rxd(0), + m_tra(0), + m_out_txd_cb(*this), + m_out_dtr_cb(*this), + m_out_rts_cb(*this), + m_out_rtxc_cb(*this), + m_out_trxc_cb(*this), + m_out_int_cb(*this), + m_rsr(0), + m_rcr(0), + m_rdr(0), + m_rivnr(0), + m_rier(0), + m_tsr(0), + m_tcr(0), + m_tdr(0), + m_tivnr(0), + m_tier(0), + m_sisr(0), + m_sicr(0), + m_sivnr(0), + m_sier(0), + m_psr1(0), + m_psr2(0), + m_ar1(0), + m_ar2(0), + m_brdr1(0), + m_brdr2(0), + m_ccr(0), + m_ecr(0) { + for (auto & elem : m_int_state) + elem = 0; } -/*------------------------------------------------- - mpcc_updateirqs --------------------------------------------------*/ - -void mpcc68561_t::updateirqs() +mpcc_device::mpcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, MPCC, "Rockwell MPCC", tag, owner, clock, "mpcc", __FILE__), + device_serial_interface(mconfig, *this), + m_variant(TYPE_MPCC), + m_rxc(0), + m_txc(0), + m_brg_rate(0), + m_rcv(0), + m_rxd(0), + m_tra(0), + m_out_txd_cb(*this), + m_out_dtr_cb(*this), + m_out_rts_cb(*this), + m_out_rtxc_cb(*this), + m_out_trxc_cb(*this), + m_out_int_cb(*this), + m_rsr(0), + m_rcr(0), + m_rdr(0), + m_rivnr(0), + m_rier(0), + m_tsr(0), + m_tcr(0), + m_tdr(0), + m_tivnr(0), + m_tier(0), + m_sisr(0), + m_sicr(0), + m_sivnr(0), + m_sier(0), + m_psr1(0), + m_psr2(0), + m_ar1(0), + m_ar2(0), + m_brdr1(0), + m_brdr2(0), + m_ccr(0), + m_ecr(0) { - int irqstat; + for (auto & elem : m_int_state) + elem = 0; +} - irqstat = 0; - if (MasterIRQEnable) - { - if ((channel[0].txIRQEnable) && (channel[0].txIRQPending)) - { - IRQType = IRQ_B_TX; - irqstat = 1; - } - else if ((channel[1].txIRQEnable) && (channel[1].txIRQPending)) - { - IRQType = IRQ_A_TX; - irqstat = 1; - } - else if ((channel[0].extIRQEnable) && (channel[0].extIRQPending)) - { - IRQType = IRQ_B_EXT; - irqstat = 1; - } - else if ((channel[1].extIRQEnable) && (channel[1].extIRQPending)) - { - IRQType = IRQ_A_EXT; - irqstat = 1; - } - } - else - { - IRQType = IRQ_NONE; - } +mpcc68560_device::mpcc68560_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mpcc_device(mconfig, MPCC68560, "MPCC 68560", tag, owner, clock, TYPE_MPCC68560, "mpcc68560", __FILE__){ } -// printf("mpcc: irqstat %d, last %d\n", irqstat, lastIRQStat); -// printf("ch0: en %d pd %d ch1: en %d pd %d\n", channel[0].txIRQEnable, channel[0].txIRQPending, channel[1].txIRQEnable, channel[1].txIRQPending); +mpcc68560A_device::mpcc68560A_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mpcc_device(mconfig, MPCC68560A, "MPCC 68560A", tag, owner, clock, TYPE_MPCC68560A, "mpcc68560A", __FILE__){ } - // don't spam the driver with unnecessary transitions - if (irqstat != lastIRQStat) - { - lastIRQStat = irqstat; +mpcc68561_device::mpcc68561_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mpcc_device(mconfig, MPCC68561, "MPCC 68561", tag, owner, clock, TYPE_MPCC68561, "mpcc68561", __FILE__){ } - // tell the driver the new IRQ line status if possible -#if LOG_MPCC - printf("mpcc68561 IRQ status => %d\n", irqstat); -#endif - if(!intrq_cb.isnull()) - intrq_cb(irqstat); - } -} +mpcc68561A_device::mpcc68561A_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : mpcc_device(mconfig, MPCC68561A, "MPCC 68561A", tag, owner, clock, TYPE_MPCC68561A, "mpcc68561A", __FILE__){ } -/*------------------------------------------------- - mpcc_initchannel --------------------------------------------------*/ -void mpcc68561_t::initchannel(int ch) +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- +void mpcc_device::device_start() { - channel[ch].syncHunt = 1; + LOGSETUP("%s\n", FUNCNAME); + + // resolve callbacks + m_out_txd_cb.resolve_safe(); + m_out_dtr_cb.resolve_safe(); + m_out_rts_cb.resolve_safe(); + m_out_rtxc_cb.resolve_safe(); + m_out_trxc_cb.resolve_safe(); + m_out_int_cb.resolve_safe(); + + // state saving + save_item(NAME(m_int_state)); + save_item(NAME(m_rsr)); + save_item(NAME(m_rcr)); + save_item(NAME(m_rdr)); + save_item(NAME(m_rivnr)); + save_item(NAME(m_rier)); + save_item(NAME(m_tsr)); + save_item(NAME(m_tcr)); + save_item(NAME(m_tdr)); + save_item(NAME(m_tivnr)); + save_item(NAME(m_tier)); + save_item(NAME(m_sisr)); + save_item(NAME(m_sicr)); + save_item(NAME(m_sivnr)); + save_item(NAME(m_sier)); + save_item(NAME(m_psr1)); + save_item(NAME(m_psr2)); + save_item(NAME(m_ar1)); + save_item(NAME(m_ar2)); + save_item(NAME(m_brdr1)); + save_item(NAME(m_brdr2)); + save_item(NAME(m_ccr)); + save_item(NAME(m_ecr)); + LOG(" - MPCC variant %02x\n", m_variant); } -/*------------------------------------------------- - mpcc_resetchannel --------------------------------------------------*/ -void mpcc68561_t::resetchannel(int ch) +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- +void mpcc_device::device_reset() { - emu_timer *timersave = channel[ch].baudtimer; - - memset(&channel[ch], 0, sizeof(Chan)); - - channel[ch].txUnderrun = 1; - channel[ch].baudtimer = timersave; - - channel[ch].baudtimer->adjust(attotime::never, ch); + LOGSETUP("%s %s \n",tag(), FUNCNAME); + + m_rsr = 0x00; + m_rcr = 0x01; + m_rivnr = 0x0f; + m_rier = 0x00; + m_tsr = 0x80; + m_tcr = 0x01; + m_tivnr = 0x0f; + m_tier = 0x00; + m_sisr = 0x00; + m_sicr = 0x00; + m_sivnr = 0x0f; + m_sier = 0x00; + m_psr1 = 0x00; + m_psr2 = 0x00; + m_ar1 = 0x00; + m_ar2 = 0x00; + m_brdr1 = 0x01; + m_brdr2 = 0x00; + m_ccr = 0x00; + m_ecr = 0x04; + + // Init out callbacks to known inactive state + m_out_txd_cb(1); + m_out_dtr_cb(1); + m_out_rts_cb(1); + m_out_rtxc_cb(1); + m_out_trxc_cb(1); + m_out_int_cb(1); } -/*------------------------------------------------- - mpcc68561_baud_expire - baud rate timer expiry --------------------------------------------------*/ - -void mpcc68561_t::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +/* + * Serial device implementation + */ +//------------------------------------------------- +// tra_callback - is called for each bit that needs to be transmitted +//------------------------------------------------- +void mpcc_device::tra_callback() { - Chan *pChan = &channel[id]; - int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; - int rate; - - if (brconst) + // Check if transmitter is idle as in disabled + if (!(m_tcr & REG_TCR_TEN)) { - rate = clock() / brconst; + // transmit idle TODO: Support TCR TICS bit + m_out_txd_cb(1); } - else +#if 0 + // Check if we are transmitting break TODO: Figure out Break support + else if (...) { - rate = 0; + // transmit break + m_out_txd_cb(0); } +#endif + // Check if there is more bits to send + else if (!is_transmit_register_empty()) + { + // Get the next bit + int db = transmit_register_get_data_bit(); - // is baud counter IRQ enabled on this channel? - // always flag pending in case it's enabled after this - pChan->baudIRQPending = 1; - if (pChan->baudIRQEnable) + // transmit data + m_out_txd_cb(db); + } + // Otherwise we don't know why we are called... + else { - if (pChan->extIRQEnable) + logerror("%s %s Failed to transmit\n", FUNCNAME, m_owner->tag()); + } +} + +//------------------------------------------------- +// tra_complete - is called when the transmitter shift register has sent the last bit +//------------------------------------------------- +void mpcc_device::tra_complete() +{ + // check if transmitter is enabled and we are not sending BREAK level + if ((m_tcr & REG_TCR_TEN) && !(m_tcr & REG_TCR_TICS)) + { // check if there are more data in the fifo + if (!m_tx_data_fifo.empty()) { - pChan->extIRQPending = 1; - pChan->baudIRQPending = 0; - updateirqs(); + transmit_register_setup(m_tx_data_fifo.dequeue()); // Reload the shift register + m_tsr |= REG_TSR_TDRA; // Mark fifo as having room for more data + } + else + { + m_out_rts_cb(CLEAR_LINE); // TODO: respect the RTSLV bit } - } - // reset timer according to current register values - if (rate) + // Check if Tx interrupts are enabled + if (m_tier & REG_TIER_TDRA) + { + // TODO: Check circumstances, eg int on first or every character etc + trigger_interrupt(INT_TX_TDRA); + } + } // Check if sending BREAK + else if (m_tcr & REG_TCR_TICS) { - timer.adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); + // TODO: Should transmit content of AR2, needs investigation + m_out_txd_cb(0); } else { - timer.adjust(attotime::never, 0, attotime::never); + // transmit mark + m_out_txd_cb(1); } } -/*------------------------------------------------- - device_start - device-specific startup --------------------------------------------------*/ - -void mpcc68561_t::device_start() +//------------------------------------------------- +// rcv_callback - called when it is time to sample incomming data bit +//------------------------------------------------- +void mpcc_device::rcv_callback() { - intrq_cb.resolve_safe(); - - memset(channel, 0, sizeof(channel)); - - mode = 0; - reg = 0; - status = 0; - IRQV = 0; - MasterIRQEnable = 0; - lastIRQStat = 0; - IRQType = IRQ_NONE; - - channel[0].baudtimer = timer_alloc(0); + // Check if the Receiver is enabled + if (!(m_rcr & REG_RCR_RRES)) + { + receive_register_update_bit(m_rxd); + } } -/*------------------------------------------------- - device_reset - device-specific reset --------------------------------------------------*/ -void mpcc68561_t::device_reset() -{ - IRQType = IRQ_NONE; - MasterIRQEnable = 0; - IRQV = 0; +//------------------------------------------------- +// rcv_complete - +//------------------------------------------------- - initchannel(0); - resetchannel(0); -} +void mpcc_device::rcv_complete() +{ + uint8_t data; -/*------------------------------------------------- - mpcc_set_status --------------------------------------------------*/ + receive_register_extract(); + data = get_received_char(); -void mpcc68561_t::set_status(int _status) -{ - status = _status; + // receive_data(data); + if (m_rx_data_fifo.full()) + { + // receive overrun error detected, new data is lost + m_rsr |= REG_RSR_ROVRN; + // interrupt if rx overrun interrupt is enabled + if (m_rier & REG_RIER_ROVRN) + { + trigger_interrupt(INT_RX_ROVRN); + } + } + else + { + m_rx_data_fifo.enqueue(data); + m_rsr |= REG_RSR_RDA; + // interrupt if rx data availble is enabled + if (m_rier & REG_RIER_RDA) + { + trigger_interrupt(INT_RX_RDA); + } + } } -/*------------------------------------------------- - mpcc_acknowledge --------------------------------------------------*/ - -void mpcc68561_t::acknowledge() +//------------------------------------------------- +// write_rx - called by terminal through rs232/diserial +// when character is sent to board +//------------------------------------------------- +WRITE_LINE_MEMBER(mpcc_device::write_rx) { - if(!intrq_cb.isnull()) - intrq_cb(0); + LOGRCV("%s(%d)\n", FUNCNAME, state); + m_rxd = state; + + //only use rx_w when self-clocked + if(m_rxc != 0 || m_brg_rate != 0) + device_serial_interface::rx_w(state); } -/*------------------------------------------------- - mpcc_getreg --------------------------------------------------*/ -uint8_t mpcc68561_t::getreg() +/* + * Interrupts + */ +//------------------------------------------------- +// check_interrupts - +//------------------------------------------------- +void mpcc_device::check_interrupts() { - /* Not yet implemented */ - #if LOG_MPCC - printf("mpcc: port A reg %d read 0x%02x\n", reg, channel[0].reg_val[reg]); - #endif + int state = 0; + LOGINT("%s %s \n",tag(), FUNCNAME); - if (reg == 0) + // loop over all interrupt sources + for (auto & elem : m_int_state) { - uint8_t rv = 0; - - Chan *ourCh = &channel[0]; - - rv |= (ourCh->txUnderrun) ? 0x40 : 0; - rv |= (ourCh->syncHunt) ? 0x10 : 0; - rv |= channel[0].reg_val[0] & 0x05; // pick up TXBE and RXBF bits - - return rv; + state |= elem; } - else if (reg == 10) + + // update IRQ line + // If we are not serving any interrupt the IRQ is asserted already and we need to do nothing + if ((state & INT_ACK) == 0) { - return 0; + // If there is a new interrupt not yet acknowledged IRQ needs to be asserted + if (state & INT_REQ) + { + m_out_int_cb(ASSERT_LINE); + } + // Otherwise we just clear the IRQ line allowing other devices to interrupt + else + { + m_out_int_cb(CLEAR_LINE); + } } - return channel[0].reg_val[reg]; } -/*------------------------------------------------- - mpcc_putreg --------------------------------------------------*/ +//------------------------------------------------- +// reset_interrupts - +//------------------------------------------------- -void mpcc68561_t::putreg(int ch, uint8_t data) +void mpcc_device::reset_interrupts() { - Chan *pChan = &channel[ch]; - - channel[ch].reg_val[reg] = data; - #if LOG_MPCC - printf("mpcc: port %c reg %d write 0x%02x\n", 'A'+ch, reg, data); - #endif - - switch (reg) + LOGINT("%s %s \n",tag(), FUNCNAME); + // reset internal interrupt sources + for (auto & elem : m_int_state) { - case 0: // command register - switch ((data >> 3) & 7) - { - case 1: // select high registers (handled elsewhere) - break; - - case 2: // reset external and status IRQs - pChan->syncHunt = 0; - break; - - case 5: // ack Tx IRQ - pChan->txIRQPending = 0; - updateirqs(); - break; - - case 0: // nothing - case 3: // send SDLC abort - case 4: // enable IRQ on next Rx byte - case 6: // reset errors - case 7: // reset highest IUS - // we don't handle these yet - break; - - } - break; - - case 1: // Tx/Rx IRQ and data transfer mode defintion - pChan->extIRQEnable = (data & 1); - pChan->txIRQEnable = (data & 2) ? 1 : 0; - pChan->rxIRQEnable = (data >> 3) & 3; - updateirqs(); - break; - - case 2: // IRQ vector - IRQV = data; - break; - - case 3: // Rx parameters and controls - pChan->rxEnable = (data & 1); - pChan->syncHunt = (data & 0x10) ? 1 : 0; - break; - - case 5: // Tx parameters and controls -// printf("ch %d TxEnable = %d [%02x]\n", ch, data & 8, data); - pChan->txEnable = data & 8; - - if (pChan->txEnable) - { - pChan->reg_val[0] |= 0x04; // Tx empty - } - break; - - case 4: // Tx/Rx misc parameters and modes - case 6: // sync chars/SDLC address field - case 7: // sync char/SDLC flag - break; - - case 9: // master IRQ control - MasterIRQEnable = (data & 8) ? 1 : 0; - updateirqs(); - - // channel reset command - switch ((data>>6) & 3) - { - case 0: // do nothing - break; - - case 1: // reset channel B - resetchannel(0); - break; - - case 3: // force h/w reset (entire chip) - IRQType = IRQ_NONE; - MasterIRQEnable = 0; - IRQV = 0; - - initchannel(0); - resetchannel(0); - - // make sure we stop yanking the IRQ line if we were - updateirqs(); - break; - - } - break; - - case 10: // misc transmitter/receiver control bits - case 11: // clock mode control - case 12: // lower byte of baud rate gen - case 13: // upper byte of baud rate gen - break; - - case 14: // misc control bits - if (data & 0x01) // baud rate generator enable? - { - int brconst = pChan->reg_val[13]<<8 | pChan->reg_val[14]; - int rate = clock() / brconst; - - pChan->baudtimer->adjust(attotime::from_hz(rate), 0, attotime::from_hz(rate)); - } - break; - - case 15: // external/status interrupt control - pChan->baudIRQEnable = (data & 2) ? 1 : 0; - pChan->DCDEnable = (data & 8) ? 1 : 0; - pChan->CTSEnable = (data & 0x20) ? 1 : 0; - pChan->txUnderrunEnable = (data & 0x40) ? 1 : 0; - break; + elem = 0; } -} - -/*------------------------------------------------- - mpcc68561_get_reg_a --------------------------------------------------*/ -uint8_t mpcc68561_t::get_reg_a(int reg) -{ - return channel[0].reg_val[reg]; + // check external interrupt sources + check_interrupts(); } - - -/*------------------------------------------------- - mpcc68561_set_reg_a --------------------------------------------------*/ - -void mpcc68561_t::set_reg_a(int reg, uint8_t data) +//----------------------------------------------------------------------- +// trigger_interrupt - called when a potential interrupt condition occurs +//------------------------------------------------- +void mpcc_device::trigger_interrupt(int source) { - channel[0].reg_val[reg] = data; + LOGINT("%s %s: %02x\n",FUNCNAME, tag(), source); + switch(source) + { + case INT_TX_TDRA: + case INT_TX_TFC: + case INT_TX_TUNRN: + case INT_TX_TFERR: + m_int_state[TX_INT_PRIO] = INT_REQ; + break; + case INT_RX_RDA: + case INT_RX_EOF: + case INT_RX_CPERR: + case INT_RX_FRERR: + case INT_RX_ROVRN: + case INT_RX_RAB: + m_int_state[RX_INT_PRIO] = INT_REQ; + break; + case INT_SR_CTS: + case INT_SR_DSR: + case INT_SR_DCD: + m_int_state[SR_INT_PRIO] = INT_REQ; + break; + } + check_interrupts(); } - - -/*------------------------------------------------- - mpcc68561_r --------------------------------------------------*/ - -READ8_MEMBER( mpcc68561_t::reg_r) +//------------------------------------------------- +// Read register +//------------------------------------------------- +READ8_MEMBER( mpcc_device::read ) { - uint8_t result = 0; - - offset %= 4; + uint8_t data = 0; switch(offset) { - case 1: - /* Channel A (Modem Port) Control */ - if (mode == 1) - mode = 0; - else - reg = 0; - - result = getreg(); - break; - - case 3: - /* Channel A (Modem Port) Data */ - return channel[0].rxData; - break; + case 0x00: data = m_rsr; logerror("MPCC: Reg RSR not implemented\n"); break; + case 0x01: data = m_rcr; logerror("MPCC: Reg RCR not implemented\n"); break; + case 0x02: data = m_rdr; logerror("MPCC: Reg RDR not implemented\n"); break; + case 0x04: data = m_rivnr; logerror("MPCC: Reg RIVNR not implemented\n"); break; + case 0x05: data = m_rier; logerror("MPCC: Reg RIER not implemented\n"); break; + case 0x08: data = m_tsr; break; logerror("MPCC: Reg TSR not implemented\n"); break; + case 0x09: data = m_tcr; logerror("MPCC: Reg TCR not implemented\n"); break; + //case 0x0a: data = m_tdr; break; + case 0x0c: data = m_tivnr; logerror("MPCC: Reg TIVNR not implemented\n"); break; + case 0x0d: data = m_tier; logerror("MPCC: Reg TIER not implemented\n"); break; + case 0x10: data = m_sisr; logerror("MPCC: Reg SISR not implemented\n"); break; + case 0x11: data = m_sicr; logerror("MPCC: Reg SICR not implemented\n"); break; + case 0x14: data = m_sivnr; logerror("MPCC: Reg SIVNR not implemented\n"); break; + case 0x15: data = m_sier; logerror("MPCC: Reg SIER not implemented\n"); break; + case 0x18: data = m_psr1; logerror("MPCC: Reg PSR1 not implemented\n"); break; + case 0x19: data = m_psr2; logerror("MPCC: Reg PSR2 not implemented\n"); break; + case 0x1a: data = m_ar1; logerror("MPCC: Reg AR1 not implemented\n"); break; + case 0x1b: data = m_ar2; logerror("MPCC: Reg AR2 not implemented\n"); break; + case 0x1c: data = m_brdr1; logerror("MPCC: Reg BRDR1 not implemented\n"); break; + case 0x1d: data = m_brdr2; logerror("MPCC: Reg BRDR2 not implemented\n"); break; + case 0x1e: data = m_ccr; logerror("MPCC: Reg CCR not implemented\n"); break; + case 0x1f: data = m_ecr; logerror("MPCC: Reg ECR not implemented\n"); break; + default: logerror("%s invalid register accessed: %02x\n", m_owner->tag(), offset); } - return result; + LOGSETUP(" * %s Reg %02x -> %02x \n", m_owner->tag(), offset, data); + return data; } - - -/*------------------------------------------------- - mpcc68561_w --------------------------------------------------*/ - -WRITE8_MEMBER( mpcc68561_t::reg_w ) +//------------------------------------------------- +// Write register +//------------------------------------------------- +WRITE8_MEMBER( mpcc_device::write ) { - Chan *pChan; - - offset &= 3; - -// printf(" mode %d data %x offset %d \n", mode, data, offset); - + LOGSETUP(" * %s Reg %02x <- %02x \n", m_owner->tag(), offset, data); switch(offset) { - case 1: - /* Channel A (Modem Port) Control */ - if (mode == 0) - { - if((data & 0xf0) == 0) // not a reset command - { - mode = 1; - reg = data & 0x0f; -// putareg(data & 0xf0); - } - else if (data == 0x10) - { - pChan = &channel[0]; - // clear ext. interrupts - pChan->extIRQPending = 0; - pChan->baudIRQPending = 0; - updateirqs(); - } - } - else - { - mode = 0; - putreg(0, data); - } - break; - - case 3: - /* Channel A (Modem Port) Data */ - pChan = &channel[0]; - - if (pChan->txEnable) - { - pChan->txData = data; - // local loopback? - if (pChan->reg_val[14] & 0x10) - { - pChan->rxData = data; - pChan->reg_val[0] |= 0x01; // Rx character available - } - pChan->reg_val[1] |= 0x01; // All sent - pChan->reg_val[0] |= 0x04; // Tx empty - pChan->txUnderrun = 1; - pChan->txIRQPending = 1; - updateirqs(); - } - break; + case 0x00: m_rsr = data; logerror("MPCC: Reg RSR not implemented\n"); break; + case 0x01: m_rcr = data; logerror("MPCC: Reg RCR not implemented\n"); break; + //case 0x02: m_rdr = data; break; + case 0x04: m_rivnr = data; logerror("MPCC: Reg RIVNR not implemented\n"); break; + case 0x05: m_rier = data; logerror("MPCC: Reg RIER not implemented\n"); break; + case 0x08: m_tsr = data; logerror("MPCC: Reg TSR not implemented\n"); break; + case 0x09: m_tcr = data; logerror("MPCC: Reg TCR not implemented\n"); break; + case 0x0a: m_tdr = data; LOGCHAR("*%c", data); do_tdr_w(data); break; + case 0x0c: m_tivnr = data; logerror("MPCC: Reg TIVNR not implemented\n"); break; + case 0x0d: m_tier = data; logerror("MPCC: Reg TIER not implemented\n"); break; + case 0x10: m_sisr = data; logerror("MPCC: Reg SISR not implemented\n"); break; + case 0x11: m_sicr = data; logerror("MPCC: Reg SICR not implemented\n"); break; + case 0x14: m_sivnr = data; logerror("MPCC: Reg SIVNR not implemented\n"); break; + case 0x15: m_sier = data; logerror("MPCC: Reg SIER not implemented\n"); break; + case 0x18: m_psr1 = data; logerror("MPCC: Reg PSR1 not implemented\n"); break; + case 0x19: m_psr2 = data; logerror("MPCC: Reg PSR2 not implemented\n"); break; + case 0x1a: m_ar1 = data; logerror("MPCC: Reg AR1 not implemented\n"); break; + case 0x1b: m_ar2 = data; logerror("MPCC: Reg AR2 not implemented\n"); break; + case 0x1c: m_brdr1 = data; logerror("MPCC: Reg BRDR1 not implemented\n"); break; + case 0x1d: m_brdr2 = data; logerror("MPCC: Reg BRDR2 not implemented\n"); break; + case 0x1e: m_ccr = data; logerror("MPCC: Reg CCR not implemented\n"); break; + case 0x1f: m_ecr = data; logerror("MPCC: Reg ECR not implemented\n"); break; + default: logerror("%s invalid register accessed: %02x\n", m_owner->tag(), offset); + } +} + +void mpcc_device::do_tdr_w(uint8_t data) +{ + // Check of Tx fifo has room + if (m_tx_data_fifo.full()) + { + logerror("- TX FIFO is full, discarding data\n"); + LOGTX("- TX FIFO is full, discarding data\n"); + } + else // ..there is still room + { + m_tx_data_fifo.enqueue(data); + if (m_tx_data_fifo.full()) + { + m_tsr &= ~REG_TSR_TDRA; // Mark fifo as full + } } } diff --git a/src/devices/machine/68561mpcc.h b/src/devices/machine/68561mpcc.h index ed38b7bdb01..da9ef87fca7 100644 --- a/src/devices/machine/68561mpcc.h +++ b/src/devices/machine/68561mpcc.h @@ -1,102 +1,319 @@ // license:BSD-3-Clause -// copyright-holders:Sergey Svishchev -/********************************************************************* +// copyright-holders:Joakim Larsson Edstrom +/*************************************************************************** + + MPCC Multi-Protocol Communications Controller emulation + +**************************************************************************** + _____ _____ + 1|* \_/ |48 + 2| |47 + 3| |46 + 4| |45 _____ _____ + 5| |44 1|* \_/ |40 + 6| |43 2| |39 + 7| |42 3| |38 + 8| |41 4| |37 + 9| |40 5| |36 + 10| |39 6| |35 + 11| |38 7| |34 + 12| |37 8| |33 + 13| SCN26562 |36 9| |32 + 14| SCN26C562 |35 10| |31 + 15| |34 11| Z8530 |30 + 16| |33 12| Z85C30 |29 + 17| |32 13| Z85230 |28 + 18| |31 14| |27 + 19| |30 15| |26 + 20| |29 16| |25 + 21| |28 17| |24 + 22| |27 18| |23 + 23| |26 19| |22 + 24|_____________|25 20|_____________|21 + +***************************************************************************/ + +#ifndef MPCC68561_H +#define MPCC68561_H + +#include "emu.h" + +/* Variant ADD macros - use the right one to enable the right feature set! */ +#define MCFG_MPCC68560_ADD(_tag, _clock, _rx, _tx) \ + MCFG_DEVICE_ADD(_tag, MPCC68560, _clock) \ + MCFG_MPCC_CLOCK(_rx, _tx) + +#define MCFG_MPCC68560A_ADD(_tag, _clock, _rx, _tx) \ + MCFG_DEVICE_ADD(_tag, MPCC68560A, _clock) \ + MCFG_MPCC_CLOCK(_rx, _tx) + +#define MCFG_MPCC68561_ADD(_tag, _clock, _rx, _tx) \ + MCFG_DEVICE_ADD(_tag, MPCC68561, _clock) \ + MCFG_MPCC_CLOCK(_rx, _tx) + +#define MCFG_MPCC68561A_ADD(_tag, _clock, _rx, _tx) \ + MCFG_DEVICE_ADD(_tag, MPCC68561A, _clock) \ + MCFG_MPCC_CLOCK(_rx, _tx) + +/* Generic ADD macro - Avoid using it directly, see above for correct variant instead */ +#define MCFG_MPCC_ADD(_tag, _clock, _rxa, _txa, _rxb, _txb) \ + MCFG_DEVICE_ADD(_tag, MPCC, _clock) \ + MCFG_MPCC_CLOCK(_rx, _tx) - 68561mpcc.h +/* Generic macros */ +#define MCFG_MPCC_CLOCK(_rx, _tx) \ + mpcc_device::configure_clocks(*device, _rx, _tx); - Rockwell 68561 MPCC (Multi Protocol Communications Controller) +/* Callbacks to be called by us for signals driven by the MPCC */ +#define MCFG_MPCC_OUT_TXD_CB(_devcb) \ + devcb = &mpcc_device::set_out_txd_callback(*device, DEVCB_##_devcb); - skeleton driver +#define MCFG_MPCC_OUT_DTR_CB(_devcb) \ + devcb = &mpcc_device::set_out_dtr_callback(*device, DEVCB_##_devcb); -*********************************************************************/ +#define MCFG_MPCC_OUT_RTS_CB(_devcb) \ + devcb = &mpcc_device::set_out_rts_callback(*device, DEVCB_##_devcb); -#ifndef __68561MPCC_H__ -#define __68561MPCC_H__ +#define MCFG_MPCC_OUT_TRXC_CB(_devcb) \ + devcb = &mpcc_device::set_out_trxc_callback(*device, DEVCB_##_devcb); -#define MCFG_MPCC68561_INTRQ_CALLBACK(_write) \ - devcb = &mpcc68561_t::set_intrq_wr_callback(*device, DEVCB_##_write); +#define MCFG_MPCC_OUT_RTXC_CB(_devcb) \ + devcb = &mpcc_device::set_out_rtxc_callback(*device, DEVCB_##_devcb); -class mpcc68561_t : public device_t +#define MCFG_MPCC_OUT_INT_CB(_devcb) \ + devcb = &mpcc_device::set_out_int_callback(*device, DEVCB_##_devcb); + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** +class mpcc_device : public device_t, + public device_serial_interface { public: - enum IRQType_t { - IRQ_NONE, - IRQ_A_RX, - IRQ_A_RX_SPECIAL, - IRQ_B_RX, - IRQ_B_RX_SPECIAL, - IRQ_A_TX, - IRQ_B_TX, - IRQ_A_EXT, - IRQ_B_EXT - }; + // construction/destruction + mpcc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, uint32_t variant, const char *shortname, const char *source); + mpcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template<class _Object> static devcb_base &set_out_txd_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_txd_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_dtr_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_dtr_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_rts_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_rts_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_rtxc_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_rtxc_cb.set_callback(object); } + template<class _Object> static devcb_base &set_out_trxc_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_trxc_cb.set_callback(object); } - mpcc68561_t(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + template<class _Object> static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast<mpcc_device &>(device).m_out_int_cb.set_callback(object); } - template<class _Object> static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast<mpcc68561_t &>(device).intrq_cb.set_callback(object); } + static void configure_clocks(device_t &device, int rxc, int txc) + { + mpcc_device &dev = downcast<mpcc_device &>(device); + dev.m_rxc = rxc; + dev.m_txc = txc; + } - uint8_t get_reg_a(int reg); - void set_reg_a(int reg, uint8_t data); + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); - void set_status(int status); + // interrupt acknowledge + DECLARE_READ8_MEMBER( iack ); - DECLARE_READ8_MEMBER(reg_r); - DECLARE_WRITE8_MEMBER(reg_w); + /* Callbacks to be called by others for signals driven by connected devices */ + DECLARE_WRITE_LINE_MEMBER( write_rx ); // bit transitions from serial device + DECLARE_WRITE_LINE_MEMBER( cts_w ) {} // { m_chanA->cts_w(state); } + DECLARE_WRITE_LINE_MEMBER( dcd_w ) {} // { m_chanA->dcd_w(state); } + DECLARE_WRITE_LINE_MEMBER( rxc_w ) {} // { m_chanA->rxc_w(state); } + DECLARE_WRITE_LINE_MEMBER( txc_w ) {} // { m_chanA->txc_w(state); } protected: + // 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; - -private: - struct Chan { - bool txIRQEnable; - bool rxIRQEnable; - bool extIRQEnable; - bool baudIRQEnable; - bool txIRQPending; - bool rxIRQPending; - bool extIRQPending; - bool baudIRQPending; - bool txEnable; - bool rxEnable; - bool txUnderrun; - bool txUnderrunEnable; - bool syncHunt; - bool DCDEnable; - bool CTSEnable; - uint8_t rxData; - uint8_t txData; - - emu_timer *baudtimer; - - uint8_t reg_val[22]; + + // device_serial_interface overrides + virtual void tra_callback() override; + virtual void tra_complete() override; + virtual void rcv_callback() override; + virtual void rcv_complete() override; + + /* + * Interrupts + */ + void check_interrupts(); + void reset_interrupts(); + void trigger_interrupt(int source); + enum + { + INT_TX_TDRA, // Tx char available + INT_TX_TFC, // Tx frame complete + INT_TX_TUNRN, // Tx underrun detected + INT_TX_TFERR, // Tx frame error detected + INT_RX_RDA, // Rx interrupt on Receiver Data Available + INT_RX_EOF, // Rx interrupt on End of frame + INT_RX_CPERR, // Rx interrupt on CRC or Parity error + INT_RX_FRERR, // Rx interrupt on Frame error + INT_RX_ROVRN, // Rx interrupt on Receiver overrun + INT_RX_RAB, // Rx interrupt on Abort/Break + INT_SR_CTS, // Serial interface interrupt on CTS asserted + INT_SR_DSR, // Serial interface interrupt on DSR asserted + INT_SR_DCD, // Serial interface interrupt on DCD asserted }; - int mode; - int reg; - int status; - int IRQV; - int MasterIRQEnable; - int lastIRQStat; - IRQType_t IRQType; + enum + { + RX_INT_PRIO = 0x00, // Highest interrupt priority + TX_INT_PRIO = 0x01, + SR_INT_PRIO = 0x02 // Lowest interrupt priority + }; - Chan channel[2]; + enum + { + INT_REQ = 0x01, // Interrupt requested + INT_ACK = 0x02 // Interrupt acknowledged + }; - devcb_write_line intrq_cb; + // Variants in the MPCC family + enum + { + TYPE_MPCC = 0x001, + TYPE_MPCC68560 = 0x002, + TYPE_MPCC68560A = 0x004, + TYPE_MPCC68561 = 0x008, + TYPE_MPCC68561A = 0x010, + }; - void updateirqs(); - void initchannel(int ch); - void resetchannel(int ch); - void acknowledge(); - uint8_t getreg(); - void putreg(int ch, uint8_t data); -}; +#define SET_TYPE_A ( mpcc_device::TYPE_MPCC68560A | mpcc_device::TYPE_MPCC68561A ) -/*************************************************************************** - MACROS -***************************************************************************/ + // State variables + int m_variant; + int m_rxc; + int m_txc; + int m_brg_rate; + int m_rcv; + int m_rxd; + int m_tra; + int m_int_state[3]; // Three priority levels Rx, Tx and Serial interface + + // Callbacks + devcb_write_line m_out_txd_cb; + devcb_write_line m_out_dtr_cb; + devcb_write_line m_out_rts_cb; + devcb_write_line m_out_rtxc_cb; + devcb_write_line m_out_trxc_cb; + + devcb_write_line m_out_int_cb; + + /* + * Register handling + */ + // RSR register + uint8_t m_rsr; + enum + { + REG_RSR_RDA = 0x80, // Rx Data available + REG_RSR_EOF = 0x40, // End of frame detected (BOP and BSC modes) + REG_RSR_RHW = 0x20, // Odd number of frame data bytes reeived in 16 bit mode. + REG_RSR_CPERR = 0x10, // CRC or parity error detected + REG_RSR_FRERR = 0x08, // Frame error detected + REG_RSR_ROVRN = 0x04, // Rx overrun detected + REG_RSR_RAB = 0x02, // Rx Abort break detected + REG_RSR_RIDLE = 0x01, // Rx idle detcted (15+ high consecutive bits accounted for) + }; + + // RCR register + uint8_t m_rcr; + enum + { + REG_RCR_RDSREN = 0x40, // Rx Data Service Request Enable (DMA) + REG_RCR_DONEEN = 0x20, // DONE output enable + REG_RCR_RSYNEN = 0x10, // RSYNEN output enable + REG_RCR_STRSYN = 0x08, // STRIP SYN character (COP mode) + REG_RCR_RABTEN = 0x02, // Receiver Abort Enable (BOP mode) + REG_RCR_RRES = 0x01, // Receiver Reset command/Enable + }; + + uint8_t m_rdr; + // TODO: investigate if 4 x 16 bit wide FIFO is needed for 16 bit mode + util::fifo<uint8_t, 8> m_rx_data_fifo; + + uint8_t m_rivnr; + + // RIER register + uint8_t m_rier; + enum { + REG_RIER_RDA = 0x80, // Rx interrupt on Receiver Data Available + REG_RIER_EOF = 0x40, // Rx interrupt on End of frame + REG_RIER_CPERR = 0x10, // Rx interrupt on CRC or Parity error + REG_RIER_FRERR = 0x08, // Rx interrupt on Frame error + REG_RIER_ROVRN = 0x04, // Rx interrupt on Receiver overrun + REG_RIER_RAB = 0x02, // Rx interrupt on Abort/Break + }; + // TSR register + uint8_t m_tsr; + enum + { + REG_TSR_TDRA = 0x80, + REG_TSR_TFC = 0x40, + REG_TSR_TUNRN = 0x04, + REG_TSR_TFERR = 0x02, + }; + + // TCR register + uint8_t m_tcr; + enum + { + REG_TCR_TEN = 0x80, // Tx enabled + REG_TCR_TDSREN = 0x40, + REG_TCR_TICS = 0x20, // Tx Idle Char Select, 'A' variant differs + REG_TCR_THW = 0x10, + REG_TCR_TLAST = 0x08, + REG_TCR_TSYN = 0x04, + REG_TCR_TABT = 0x02, + REG_TCR_TRES = 0x01, + }; + + // TDR register + uint8_t m_tdr; + void do_tdr_w(uint8_t data); + // TODO: investigate if 4 x 16 bit wide FIFO is needed for 16 bit mode + util::fifo<uint8_t, 8> m_tx_data_fifo; + + uint8_t m_tivnr; + + // TIER register + uint8_t m_tier; + enum + { + REG_TIER_TDRA = 0x80, // TX Character available interrupt + REG_TIER_TFC = 0x40, // TX Frame complete interrupt + REG_TIER_TUNRN = 0x04, // TX Underrun interrupt + REG_TIER_TFERR = 0x02, // TX Frame error interrupt + }; + + uint8_t m_sisr; + uint8_t m_sicr; + uint8_t m_sivnr; + uint8_t m_sier; + uint8_t m_psr1; + uint8_t m_psr2; + uint8_t m_ar1; + uint8_t m_ar2; + uint8_t m_brdr1; + uint8_t m_brdr2; + uint8_t m_ccr; + uint8_t m_ecr; +}; + +// device type definition +extern const device_type MPCC; +extern const device_type MPCC68560; +extern const device_type MPCC68560A; extern const device_type MPCC68561; +extern const device_type MPCC68561A; + +class mpcc68560_device : public mpcc_device { public : mpcc68560_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class mpcc68560A_device : public mpcc_device { public : mpcc68560A_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class mpcc68561_device : public mpcc_device { public : mpcc68561_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; +class mpcc68561A_device : public mpcc_device { public : mpcc68561A_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); }; -#endif /* __68561MPCC_H__ */ +#endif // MPCC68561_H diff --git a/src/mame/drivers/fccpu20.cpp b/src/mame/drivers/fccpu20.cpp index 5d951b25216..24a16bc6458 100644 --- a/src/mame/drivers/fccpu20.cpp +++ b/src/mame/drivers/fccpu20.cpp @@ -142,9 +142,9 @@ Basadressen av I / O-enheter: *--------------------------------------------------------------------------- * TODO: * - Find accurate documentation and adjust memory map - * - Add layout - * - Write & add 68561 UART - * - Add 68230 PIT + * - Add PCB layout + * - Improve 68561 UART + * - Improve hookup of 68230 PIT * - Add variants of boards in the CPU-20 and CPU-21 family * - Add FGA, DUSCC devices and CPU-22 variants * @@ -158,6 +158,7 @@ Basadressen av I / O-enheter: #include "bus/rs232/rs232.h" #include "machine/68230pit.h" #include "machine/68153bim.h" +#include "machine/68561mpcc.h" #include "machine/clock.h" #define LOG_GENERAL 0x01 @@ -192,6 +193,7 @@ cpu20_state(const machine_config &mconfig, device_type type, const char *tag) , m_maincpu (*this, "maincpu") , m_pit (*this, "pit") , m_bim (*this, "bim") + , m_mpcc (*this, "mpcc") { } DECLARE_READ32_MEMBER (bootvect_r); @@ -208,6 +210,7 @@ private: required_device<m68000_base_device> m_maincpu; required_device<pit68230_device> m_pit; required_device<bim68153_device> m_bim; + required_device<mpcc68561_device> m_mpcc; // Pointer to System ROMs needed by bootvect_r and masking RAM buffer for post reset accesses uint32_t *m_sysrom; @@ -224,7 +227,7 @@ static ADDRESS_MAP_START (cpu20_mem, AS_PROGRAM, 32, cpu20_state) AM_RANGE (0x00000008, 0x003fffff) AM_RAM /* RAM installed in machine start */ AM_RANGE (0xff040000, 0xff04ffff) AM_RAM /* RAM installed in machine start */ AM_RANGE (0xff000000, 0xff00ffff) AM_ROM AM_REGION("roms", 0x0000) -// AM_RANGE (0xff800000, 0xff80000f) AM_DEVREADWRITE8("mpcc", mpcc68561_device, read, write, 0x00ff00ff) + AM_RANGE (0xff800000, 0xff80001f) AM_DEVREADWRITE8("mpcc", mpcc68561_device, read, write, 0xffffffff) // AM_RANGE (0xff800200, 0xff80020f) AM_DEVREADWRITE8("pit2", pit68230_device, read, write, 0xff00ff00) AM_RANGE (0xff800800, 0xff80080f) AM_DEVREADWRITE8("bim", bim68153_device, read, write, 0xff00ff00) // AM_RANGE (0xff800a00, 0xff800a0f) AM_DEVREADWRITE8("rtc", rtc_device, read, write, 0x00ff00ff) @@ -254,6 +257,8 @@ void cpu20_state::machine_reset () /* Reset pointer to bootvector in ROM for bootvector handler bootvect_r */ if (m_sysrom == &m_sysram[0]) /* Condition needed because memory map is not setup first time */ m_sysrom = (uint32_t*)(memregion ("roms")->base()); + + m_pit->h1_w(1); // signal no ACFAIL or SYSFAIL } #if 0 @@ -339,6 +344,19 @@ static MACHINE_CONFIG_START (cpu20, cpu20_state) /*INT1 - MPCC@8.064 MHz aswell */ /*INT2 - PI/T timer */ /*INT3 - SYSFAIL/IRQVMX/ACFAIL/MPCC2/3 */ + + /* MPCC */ +#define RS232P1_TAG "rs232p1" + MCFG_MPCC68561_ADD ("mpcc", XTAL_8_664MHz, 0, 0) + MCFG_MPCC_OUT_TXD_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_txd)) + MCFG_MPCC_OUT_DTR_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_dtr)) + MCFG_MPCC_OUT_RTS_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_rts)) + // RS232 + MCFG_RS232_PORT_ADD (RS232P1_TAG, default_rs232_devices, nullptr) + MCFG_RS232_RXD_HANDLER (DEVWRITELINE ("mpcc", mpcc68561_device, rx_w)) + MCFG_RS232_CTS_HANDLER (DEVWRITELINE ("mpcc", mpcc68561_device, cts_w)) + +// MCFG_MPCC_OUT_INT_CB(DEVWRITELINE("bim", bim68153_device, int1_w)) MACHINE_CONFIG_END /* ROM definitions */ @@ -384,6 +402,30 @@ ROM_END - PC2 used as I/O pin,CLK and x32 prescaler are used - Timer reload the preload values when reaching 0 (zero) - Timer is enabled + * MPCC setup + * : Reg 19 <- 1e - PSR2: Byte mode, 1 Stop bit, 8 bit data, ASYNC mode + * : Reg 1c <- 8a - BRDR1: Baud Rate Divider 1 + * : Reg 1d <- 00 - BRDR1: Baud Rate Divider 2 + * : Reg 1e <- 1c - CCR: x3 Mode, TxC is output, internal RxC, ISOC + * : Reg 1f <- 00 - ECR: No parity + * : Reg 0d <- 00 - TIER: interrupts disabled + * : Reg 15 <- 00 - SIER: interrupts disabled + * : Reg 05 <- 80 - RIER: enable RDA interrupts + * : Reg 01 <- 01 - RCR: Reset receiver command + * : Reg 01 <- 00 - RCR: Reciver in normal operation + * : Reg 09 <- 01 - TCR: Reset transmitter command + * : Reg 09 <- 80 - TCR: Transmitter in normal operation + * : Reg 11 <- c0 - SICR: Assert RTS, Assert DTR + * : Reg 08 -> 80 - TSR: Tx FIFO has room + * : Reg 0a <- 0a - TDR: send 0x0a to Tx FIFO... etc + * + * TDR outputs: + * "Disk Controller installed + * Disk #0: Header sector error = 145 + * Disk #1: Header sector error = 145 + * Out of PDOS boot disk table entries. + * I'LL Retry them all." + * */ /* Driver */ |