diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua index 1d061199208..e6d7dbe7818 100644 --- a/scripts/src/machine.lua +++ b/scripts/src/machine.lua @@ -2032,6 +2032,18 @@ if (MACHINES["S3C2440"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/machine/scnxx562.h,MACHINES["DUSCC"] = true +--------------------------------------------------- + +if (MACHINES["DUSCC"]~=null) then + files { + MAME_DIR .. "src/devices/machine/scnxx562.cpp", + MAME_DIR .. "src/devices/machine/scnxx562.h", + } +end + --------------------------------------------------- -- --@src/devices/machine/serflash.h,MACHINES["SERFLASH"] = true diff --git a/src/devices/machine/68230pit.cpp b/src/devices/machine/68230pit.cpp index 927ece2cb75..fe84888ffbf 100644 --- a/src/devices/machine/68230pit.cpp +++ b/src/devices/machine/68230pit.cpp @@ -9,13 +9,31 @@ * * Todo * - Add clock and timers +* - Add double buffering for each submode * - Add all missing registers * - Add configuration **********************************************************************/ #include "68230pit.h" -#define LOG(x) /* x */ +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#define LOGR(x) LOG(x) +#if VERBOSE == 2 +#define logerror printf +#endif + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#define LLFORMAT "%I64%" +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#define LLFORMAT "%lld" +#endif + +//#define LOG(x) x +//#define logerror printf //************************************************************************** // DEVICE TYPE DEFINITIONS @@ -27,22 +45,70 @@ const device_type PIT68230 = &device_creator; // pit68230_device - constructors //------------------------------------------------- pit68230_device::pit68230_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_execute_interface (mconfig, *this) - , m_icount (0) - , m_write_pa (*this) - , m_write_h2 (*this), m_pgcr(0), m_psrr(0), m_paddr(0), m_pbddr(0), m_pcddr(0), m_pacr(0), m_pbcr(0), m_padr(0), m_pbdr(0), m_psr(0) - { + : device_t (mconfig, type, name, tag, owner, clock, shortname, source), + device_execute_interface (mconfig, *this) + , m_icount (0) + , m_pa_out_cb(*this) + , m_pa_in_cb(*this) + , m_pb_out_cb(*this) + , m_pb_in_cb(*this) + , m_pc_out_cb(*this) + , m_pc_in_cb(*this) + , m_h1_out_cb (*this) + , m_h2_out_cb (*this) + , m_h3_out_cb (*this) + , m_h4_out_cb (*this) + , m_pgcr(0) + , m_psrr(0) + , m_paddr(0) + , m_pbddr(0) + , m_pcddr(0) + , m_pacr(0) + , m_pbcr(0) + , m_padr(0) + , m_pbdr(0) + , m_psr(0) + , m_tcr(0) + , m_cpr(0) + // , m_cprh(0) + // , m_cprm(0) + // , m_cprl(0) + , m_cntr(0) +{ } pit68230_device::pit68230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t (mconfig, PIT68230, "PIT68230", tag, owner, clock, "pit68230", __FILE__), - device_execute_interface (mconfig, *this) - , m_icount (0) - , m_write_pa (*this) - , m_write_h2 (*this), m_pgcr(0), m_psrr(0), m_paddr(0), m_pbddr(0), m_pcddr(0), m_pacr(0), m_pbcr(0), m_padr(0), m_pbdr(0), m_psr(0) - { + : device_t (mconfig, PIT68230, "PIT68230", tag, owner, clock, "pit68230", __FILE__), + device_execute_interface (mconfig, *this) + , m_icount (0) + , m_pa_out_cb (*this) + , m_pa_in_cb(*this) + , m_pb_out_cb(*this) + , m_pb_in_cb(*this) + , m_pc_out_cb(*this) + , m_pc_in_cb(*this) + , m_h1_out_cb(*this) + , m_h2_out_cb(*this) + , m_h3_out_cb(*this) + , m_h4_out_cb(*this) + , m_pgcr(0) + , m_psrr(0) + , m_paddr(0) + , m_pbddr(0) + , m_pcddr(0) + , m_pacr(0) + , m_pbcr(0) + , m_padr(0) + , m_pbdr(0) + , m_psr(0) + , m_tcr(0) + , m_cpr(0) + // , m_cprh(0) + // , m_cprm(0) + // , m_cprl(0) + , m_cntr(0) +{ } //------------------------------------------------- @@ -50,12 +116,18 @@ pit68230_device::pit68230_device(const machine_config &mconfig, const char *tag, //------------------------------------------------- void pit68230_device::device_start () { - LOG (logerror ("PIT68230 device started\n")); - m_icountptr = &m_icount; + LOG(("%s\n", FUNCNAME)); + m_icountptr = &m_icount; - // resolve callbacks - m_write_pa.resolve_safe (); - m_write_h2.resolve_safe (); + // resolve callbacks + m_pa_out_cb.resolve_safe(); + m_pa_in_cb.resolve_safe(0); + m_pb_out_cb.resolve_safe(); + m_pb_in_cb.resolve_safe(0); + m_h1_out_cb.resolve_safe(); + m_h2_out_cb.resolve_safe(); + m_h3_out_cb.resolve_safe(); + m_h4_out_cb.resolve_safe(); } //------------------------------------------------- @@ -63,17 +135,18 @@ void pit68230_device::device_start () //------------------------------------------------- void pit68230_device::device_reset () { - LOG (logerror ("PIT68230 device reseted\n")); - m_pgcr = 0; - m_psrr = 0; - m_paddr = 0; - m_pbddr = 0; - m_pcddr = 0; - m_pacr = 0; m_write_h2 (m_pacr); - m_pbcr = 0; - m_padr = 0; m_write_pa ((offs_t)0, m_padr); // TODO: check PADDR - m_pbdr = 0; - m_psr = 0; + LOG(("%s %s \n",tag(), FUNCNAME)); + + m_pgcr = 0; + m_psrr = 0; + m_paddr = 0; + m_pbddr = 0; + m_pcddr = 0; + m_pacr = 0; m_h2_out_cb(m_pacr); + m_pbcr = 0; + m_padr = 0; m_pa_out_cb((offs_t)0, m_padr); // TODO: check PADDR + m_pbdr = 0; + m_psr = 0; } //------------------------------------------------- @@ -85,16 +158,16 @@ void pit68230_device::device_timer (emu_timer &timer, device_timer_id id, INT32 void pit68230_device::h1_set (UINT8 state) { - LOG (logerror ("h1_set %d @ m_psr %2x => ", state, m_psr)); - if (state) m_psr |= 1; else m_psr &= ~1; - LOG (logerror ("%02x %lld\n", m_psr, machine ().firstcpu->total_cycles ())); + LOG(("%s %s %d @ m_psr %2x => ",tag(), FUNCNAME, state, m_psr)); + if (state) m_psr |= 1; else m_psr &= ~1; + LOG(("%02x %lld\n", m_psr, machine ().firstcpu->total_cycles ())); } void pit68230_device::portb_setbit (UINT8 bit, UINT8 state) { - LOG (logerror ("portb_setbit %d/%d @ m_pbdr %2x => ", bit, state, m_pbdr)); - if (state) m_pbdr |= (1 << bit); else m_pbdr &= ~(1 << bit); - LOG (logerror ("%02x %lld\n", m_pbdr, machine ().firstcpu->total_cycles ())); + LOG(("%s %s %d/%d @ m_pbdr %2x => ", tag(), FUNCNAME, bit, state, m_pbdr)); + if (state) m_pbdr |= (1 << bit); else m_pbdr &= ~(1 << bit); + LOG(("%02x %lld\n", m_pbdr, machine ().firstcpu->total_cycles ())); } //------------------------------------------------- @@ -109,157 +182,373 @@ void pit68230_device::execute_run () } while (m_icount > 0); } -LOG (static INT32 ow_cnt = 0) -LOG (static INT32 ow_data = 0) -LOG (static INT32 ow_ofs = 0) +#if VERBOSE > 2 +static INT32 ow_cnt = 0; +static INT32 ow_data = 0; +static INT32 ow_ofs = 0; +#endif -WRITE8_MEMBER (pit68230_device::write){ - switch (offset) { - case PIT_68230_PGCR: - m_pgcr = data; - break; - - case PIT_68230_PSRR: - m_psrr = data; - break; - - case PIT_68230_PADDR: - m_paddr = data; - break; - - case PIT_68230_PBDDR: - m_pbddr = data; - break; - - case PIT_68230_PCDDR: - m_pcddr = data; - break; - - case PIT_68230_PACR: - m_pacr = data; - // callbacks - /*PACR in Mode 0 - * 5 43 H2 Control in Submode 00 && 01 - * ------------------------------------ - * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. - * 1 00 Output pin - negated, H2S is always clear. - * 1 01 Output pin - asserted, H2S is always clear. - * 1 10 Output pin - interlocked input handshake protocol, H2S is always clear. - * 1 11 Output pin - pulsed input handshake protocol, H2S is always clear. - * - * 5 43 H2 Control in Submode 1x - * ------------------------------------ - * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. - * 1 X0 Output pin - negated, H2S is always cleared. - * 1 X1 Output pin - asserted, H2S is always cleared. - */ - m_write_h2 (m_pacr & 0x08 ? 1 : 0); // TODO: Check mode and submodes - break; - - case PIT_68230_PBCR: - m_pbcr = data; - break; - - case PIT_68230_PADR: - m_padr = data; - // callbacks - m_write_pa ((offs_t)0, m_padr); // TODO: check PADDR - break; - - case PIT_68230_PSR: - m_psr = data; - break; - - default: - LOG (logerror ("unhandled register %02x", offset)); - } - - LOG (if (offset != ow_ofs || data != ow_data || ow_cnt >= 1000) { - logerror ("\npit68230_device::write: previous identical operation performed %02x times\n", ow_cnt); - ow_cnt = 0; - ow_data = data; - ow_ofs = offset; - logerror ("pit68230_device::write: offset=%02x data=%02x %lld\n", ow_ofs, ow_data, machine ().firstcpu->total_cycles ()); - } - else - ow_cnt++; ) +void pit68230_device::wr_pitreg_pgcr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_pgcr = data; } -LOG (static INT32 or_cnt = 0) -LOG (static INT32 or_data = 0) -LOG (static INT32 or_ofs = 0) +void pit68230_device::wr_pitreg_psrr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_psrr = data; +} + +void pit68230_device::wr_pitreg_paddr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_paddr = data; +} + +void pit68230_device::wr_pitreg_pbddr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_pbddr = data; +} + +void pit68230_device::wr_pitreg_pcddr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_pcddr = data; +} + +void pit68230_device::wr_pitreg_pacr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_pacr = data; + // callbacks + /*PACR in Mode 0 + * 5 43 H2 Control in Submode 00 && 01 + * ------------------------------------ + * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. + * 1 00 Output pin - negated, H2S is always clear. + * 1 01 Output pin - asserted, H2S is always clear. + * 1 10 Output pin - interlocked input handshake protocol, H2S is always clear. + * 1 11 Output pin - pulsed input handshake protocol, H2S is always clear. + * + * 5 43 H2 Control in Submode 1x + * ------------------------------------ + * 0 XX Input pin - edge-sensitive status input, H2S is set on an asserted edge. + * 1 X0 Output pin - negated, H2S is always cleared. + * 1 X1 Output pin - asserted, H2S is always cleared. + */ + m_h2_out_cb (m_pacr & 0x08 ? 1 : 0); // TODO: Check mode and submodes +} + +void pit68230_device::wr_pitreg_pbcr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_pbcr = data; +} + +void pit68230_device::wr_pitreg_padr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_padr = data; + // callbacks + m_pa_out_cb ((offs_t)0, m_padr); // TODO: check PADDR +} + +void pit68230_device::wr_pitreg_psr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_psr = data; +} + +/* The timer control register (TCR) determines all operations of the timer. Bits 7-5 configure the PC3/TOUT +and PC7/TIACKpins for port C, square wave, vectored interrupt, or autovectored interrupt operation bit +4 specifies whether the counter receives data from the counter preload register or continues counting when +zero detect is reached ; bit 3 is unused and is read as zero bits 2 and 1 configure the path from the CLK +and TINpins to the counter controller ; and bit 0 ena-bles the timer. This register is readable and writable +at all times. All bits are cleared to zero when the RESET pin is asserted. + +TCR bits + 7 6 5 TOUT/TIACK Control +---------------------------- + 0 0 X The dual-function pins PC3/TOUT and PC7/TIACK carry the port C function. + 0 1 X The dual-function pinPC3/TOUT carries the TOUT function. In the run state it is used as a squarewave + output and is toggled on zero detect. The TOUT pin is high while in the halt state. The dualfunction + pin PC7/TIACK carries the PC7 function. + 1 0 0 The dual-function pin PC3/TOUT carries the TOUT function. In the run or halt state it is used as + a timer interrupt request output. The timer interrupt is disabled, thus, the pin is always three stated. + The dual-function pin PC7/TIACK carries the TIACK function ; however, since interrupt request is + negated, the PI/T produces no response (i.e., no data or DTACK) to an asserted TIACK. Refer to + 5.1.3. Timer Interrupt Acknowledge Cycles for details. + 1 0 1 The dual-function pin PC3/TOUT carries the TOUTfunction and is used as a timer interrupt request + output. The timer interrupt is enabled ; thus, the pin is low when the timer ZDS status bit is one. + The dual-function pin PC7/TIACK carries the TIACK function and is used as a timer interrupt acknowledge + input. Refer to the5.1.3. Timer InterruptAcknowledge Cycles fordetails. Thiscombination + supports vectored timer interrupts. + 1 1 0 The dual-function pin PC3/TOUT function. In the run or halt state it is used as a timer interrupt + request output. The timer interrupt is disabled ; thus, the pin is always three-stated. The dual-function + pin PC7/TIACK carries the PC7 function. + 1 1 1 The dual-function pin PC3/TOUT carries the TOUTfunction and is used as a timer interrupt request + output. The timer interrupt is enabled ; thus, the pin is low when the timer ZDS status bit is one. + The dual-function pin PC7/TIACK carries the PC7 function and autovectored interrupts are supported. + +TCR bit 4 - Zero Detect Control + 0 The counter is loaded fromthe counter preload register on the first clock to the 24-bit counter after + zero detect, then resumes counting. + 1 The counter rolls over on zero detect, then continues counting. + +TCR bit 3 - Unused and is always read as zero. + +TCR bits + 2 1 Clock Control + 0 0 The PC2/TIN input pin carries the port C function, and the CLK pin and prescaler are used. The + prescaler is decremented on the falling transition of the CLKpin ; the 24-bit counter is decremented, + rolls over, or is loaded from the counter preload registers when the prescaler rolls over from $OO + to $1F. The timer enable bit determines whether the timer is in the run or halt state. + 0 1 The PC2/TIN pin serves as a timer input, and the CLK pin and prescaler are used. The prescaler + is decremented on the falling transition of the CLK pin ; the 24-bit counter is decremented, rolls + over, or is loaded from the counter preload registers when the prescaler rolls over from $00 to $1F. + The timer is in the run state when the timer enable bit is one and the TIN pin is high ; otherwise, + the timer is in the halt state. + 1 0 The PC2/TIN pin serves as a timer input and the prescaler is used. The prescaler is decremented + following the rising transition of the TIN pin after being synchronized with the internal clock. The + 24-bit counter is decremented, rolls over, or is loaded from the counter preload registers when the + prescaler rolls over from $00 to $1F. The timer enable bit determines whether the timer is in the + run or halt state. + 1 1 The PC2/TIN pin serves as a timer input and the prescaler is not used. The 24-bit counter is decremented, + rolls over, or is loaded from the counter preload registers following the rising edge of + the TIN pin after being synchronized with the internal clock. The timer enable bit determines whether + the timer is in the run or halt state. +TCR bit 0 - Timer Enable + 0 Disabled + 1 Enabled +*/ +void pit68230_device::wr_pitreg_tcr(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x Timer %s\n", + FUNCNAME, data, m_owner->tag(), FUNCNAME, data, data & REG_TCR_ENABLE ? "enabled" : "disabled")); + m_tcr = data; +} + +void pit68230_device::wr_pitreg_cprh(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_cpr &= ~0xff0000; + m_cpr |= ((data << 16) & 0xff0000); + // m_cprh = data; +} + +void pit68230_device::wr_pitreg_cprm(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_cpr &= ~0x00ff00; + m_cpr |= ((data << 8) & 0x00ff00); + // m_cprm = data; +} + +void pit68230_device::wr_pitreg_cprl(UINT8 data) +{ + LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data)); + m_cpr &= ~0x0000ff; + m_cpr |= ((data << 0) & 0x0000ff); + // m_cprl = data; +} + +WRITE8_MEMBER (pit68230_device::write) +{ + LOG(("%s %s \n",tag(), FUNCNAME)); + switch (offset) { + case PIT_68230_PGCR: wr_pitreg_pgcr(data); break; + case PIT_68230_PSRR: wr_pitreg_psrr(data); break; + case PIT_68230_PADDR: wr_pitreg_paddr(data); break; + case PIT_68230_PBDDR: wr_pitreg_pbddr(data); break; + case PIT_68230_PCDDR: wr_pitreg_pcddr(data); break; + case PIT_68230_PACR: wr_pitreg_pacr(data); break; + case PIT_68230_PBCR: wr_pitreg_pbcr(data); break; + case PIT_68230_PADR: wr_pitreg_padr(data); break; + case PIT_68230_PAAR: break; // RO register so ignored + case PIT_68230_PBAR: break; // RO register so ignored + case PIT_68230_PSR: wr_pitreg_psr(data); break; + case PIT_68230_TCR: wr_pitreg_tcr(data); break; + case PIT_68230_CPRH: wr_pitreg_cprh(data); break; + case PIT_68230_CPRM: wr_pitreg_cprm(data); break; + case PIT_68230_CPRL: wr_pitreg_cprl(data); break; + default: + LOG (("Unhandled Write of %02x to register %02x", data, offset)); + } + +#if VERBOSE > 2 + if (offset != ow_ofs || data != ow_data || ow_cnt >= 1000) { + logerror ("\npit68230_device::write: previous identical operation performed %02x times\n", ow_cnt); + ow_cnt = 0; + ow_data = data; + ow_ofs = offset; + logerror ("pit68230_device::write: offset=%02x data=%02x %lld\n", ow_ofs, ow_data, machine ().firstcpu->total_cycles ()); + } + else + ow_cnt++; +#endif + +} + +#if VERBOSE > 2 +static INT32 or_cnt = 0; +static INT32 or_data = 0; +static INT32 or_ofs = 0; +#endif + +UINT8 pit68230_device::rr_pitreg_pgcr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pgcr)); + return m_pgcr; +} + +UINT8 pit68230_device::rr_pitreg_psrr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_psrr)); + return m_psrr; +} + +UINT8 pit68230_device::rr_pitreg_paddr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_paddr)); + return m_paddr; +} + +UINT8 pit68230_device::rr_pitreg_pbddr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pbddr)); + return m_pbddr; +} + +UINT8 pit68230_device::rr_pitreg_pcddr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pcddr)); + return m_pcddr; +} + +UINT8 pit68230_device::rr_pitreg_pacr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pacr)); + return m_pacr; +} + +UINT8 pit68230_device::rr_pitreg_pbcr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pbcr)); + return m_pbcr; +} + +UINT8 pit68230_device::rr_pitreg_padr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_padr)); + return m_padr; +} + +/* 4.6.2. PORT B DATA REGISTER (PBDR). The port B data register is a holding + * register for moving data to and from port B pins. The port B data direction + * register determines whether each pin is an input (zero) or an output (one). + * This register is readable and writable at all times. Depending on the chosen + * mode/submode, reading or writing may affect the double-buffered handshake + * mechanism. The port B data register is not affected by the assertion of the + * RESET pin. PB0-PB7 sits on pins 17-24 on a 48 pin DIP package */ +UINT8 pit68230_device::rr_pitreg_pbdr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_pbdr)); + return m_pbdr; +} + +/* The port A alternate register is an alternate register for reading the port A pins. +It is a read-only address and no other PI/T condition is affected. In all modes, +the instantaneous pin level is read and no input latching is performed except at the +data bus interface. Writes to this address are answered with DTACK, but the data is ignored.*/ +UINT8 pit68230_device::rr_pitreg_paar() +{ + // NOTE: no side effect emulated so using ..padr + UINT8 ret; + ret = m_pa_in_cb(); + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, ret)); + return ret; +} + +/* The port B alternate register is an alternate register for reading the port B pins. +It is a read-only address and no other PI/T condition is affected. In all modes, +the instantaneous pin level is read and no input latching is performed except at the +data bus interface.Writes to this address are answered with DTACK, but the data is ignored.*/ +UINT8 pit68230_device::rr_pitreg_pbar() +{ + // NOTE: no side effect emulated so using ..pbdr + UINT8 ret; + ret = m_pb_in_cb(); + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, ret)); + return ret; +} + +/* 4.8. PORT STATUS REGISTER (PSR) The port status register contains information about + * handshake pin activity. Bits 7-4 show the instantaneous level of the respective handshake + * pin, and are independent of the handshake pin sense bits in the port general control + * register. Bits 3-0 are the respective status bits referred to throughout this document. + * Their interpretation depends on the programmed mode/submode of the PI/T. For bits + * 3-0 a one is the active or asserted state. */ +UINT8 pit68230_device::rr_pitreg_psr() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, m_psr)); + return m_psr; +} + +UINT8 pit68230_device::rr_pitreg_cntrh() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 16) & 0xff)); + return (m_cntr >> 16) & 0xff; +} + +UINT8 pit68230_device::rr_pitreg_cntrm() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 8) & 0xff)); + return (m_cntr >> 8) & 0xff; +} + +UINT8 pit68230_device::rr_pitreg_cntrl() +{ + LOGR(("%s %s <- %02x\n",tag(), FUNCNAME, (m_cntr >> 0) & 0xff)); + return (m_cntr >> 0) & 0xff; +} READ8_MEMBER (pit68230_device::read){ - UINT8 data; + UINT8 data; - switch (offset) { - case PIT_68230_PGCR: - data = m_pgcr; - break; + switch (offset) { + case PIT_68230_PGCR: data = rr_pitreg_pgcr(); break; + case PIT_68230_PSRR: data = rr_pitreg_psrr(); break; + case PIT_68230_PADDR: data = rr_pitreg_paddr(); break; + case PIT_68230_PBDDR: data = rr_pitreg_pbddr(); break; + case PIT_68230_PCDDR: data = rr_pitreg_pcddr(); break; + case PIT_68230_PACR: data = rr_pitreg_pacr(); break; + case PIT_68230_PBCR: data = rr_pitreg_pbcr(); break; + case PIT_68230_PADR: data = rr_pitreg_padr(); break; + case PIT_68230_PBDR: data = rr_pitreg_pbdr(); break; + case PIT_68230_PAAR: data = rr_pitreg_paar(); break; + case PIT_68230_PBAR: data = rr_pitreg_pbar(); break; + case PIT_68230_PSR: data = rr_pitreg_psr(); break; + case PIT_68230_CNTRH: data = rr_pitreg_cntrh(); break; + case PIT_68230_CNTRM: data = rr_pitreg_cntrm(); break; + case PIT_68230_CNTRL: data = rr_pitreg_cntrl(); break; + default: + LOG (("Unhandled read register %02x\n", offset)); + data = 0; + } - case PIT_68230_PSRR: - data = m_psrr; - break; +#if VERBOSE > 2 + if (offset != or_ofs || data != or_data || or_cnt >= 1000) { + logerror ("\npit68230_device::read: previous identical operation performed %02x times\n", or_cnt); + or_cnt = 0; + or_data = data; + or_ofs = offset; + logerror ("pit68230_device::read: offset=%02x data=%02x %lld\n", or_ofs, or_data, machine ().firstcpu->total_cycles ()); + } + else + or_cnt++; +#endif - case PIT_68230_PADDR: - data = m_paddr; - break; - - case PIT_68230_PBDDR: - data = m_pbddr; - break; - - case PIT_68230_PCDDR: - data = m_pcddr; - break; - - case PIT_68230_PACR: - data = m_pacr; - break; - - case PIT_68230_PBCR: - data = m_pbcr; - break; - - case PIT_68230_PADR: - data = m_padr; - break; - - case PIT_68230_PBDR: - /* 4.6.2. PORT B DATA REGISTER (PBDR). The port B data register is a holding - * register for moving data to and from port B pins. The port B data direction - * register determines whether each pin is an input (zero) or an output (one). - * This register is readable and writable at all times. Depending on the chosen - * mode/submode, reading or writing may affect the double-buffered handshake - * mechanism. The port B data register is not affected by the assertion of the - * RESET pin. PB0-PB7 sits on pins 17-24 on a 48 pin DIP package */ - data = m_pbdr; - break; - - case PIT_68230_PSR: - /* 4.8. PORT STATUS REGISTER (PSR) The port status register contains information about - * handshake pin activity. Bits 7-4 show the instantaneous level of the respective handshake - * pin, and are independent of the handshake pin sense bits in the port general control - * register. Bits 3-0 are the respective status bits referred to throughout this document. - * Their interpretation depends on the programmed mode/submode of the PI/T. For bits - * 3-0 a one is the active or asserted state. */ - data = m_psr; - break; - - default: - LOG (logerror ("unhandled register %02x", offset)); - data = 0; - } - - LOG (if (offset != or_ofs || data != or_data || or_cnt >= 1000) { - logerror ("\npit68230_device::read: previous identical operation performed %02x times\n", or_cnt); - or_cnt = 0; - or_data = data; - or_ofs = offset; - logerror ("pit68230_device::read: offset=%02x data=%02x %lld\n", or_ofs, or_data, machine ().firstcpu->total_cycles ()); - } - else - or_cnt++; ) - - return data; + return data; } diff --git a/src/devices/machine/68230pit.h b/src/devices/machine/68230pit.h index 2a2f2c6824c..7712419f7fc 100644 --- a/src/devices/machine/68230pit.h +++ b/src/devices/machine/68230pit.h @@ -43,14 +43,35 @@ // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define MCFG_PIT68230_PA_OUTPUT_CALLBACK(_write) \ - devcb = &pit68230_device::set_pa_wr_callback (*device, DEVCB_ ## _write); +#define MCFG_PIT68230_PA_INPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pa_in_callback (*device, DEVCB_##_devcb); -#define MCFG_PIT68230_PB_OUTPUT_CALLBACK(_write) \ - devcb = &pit68230_device::set_pb_wr_callback (*device, DEVCB_ ## _write); +#define MCFG_PIT68230_PA_OUTPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pa_out_callback (*device, DEVCB_##_devcb); -#define MCFG_PIT68230_H2_CALLBACK(_write) \ - devcb = &pit68230_device::set_h2_wr_callback (*device, DEVCB_ ## _write); +#define MCFG_PIT68230_PB_INPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pb_in_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_PB_OUTPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pb_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_PC_INPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pc_in_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_PC_OUTPUT_CB(_devcb) \ + devcb = &pit68230_device::set_pc_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_H1_CB(_devcb) \ + devcb = &pit68230_device::set_h1_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_H2_CB(_devcb) \ + devcb = &pit68230_device::set_h2_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_H3_CB(_devcb) \ + devcb = &pit68230_device::set_h3_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_PIT68230_H4_CB(_devcb) \ + devcb = &pit68230_device::set_h4_out_callback (*device, DEVCB_##_devcb); /*----------------------------------------------------------------------- * Registers RS1-RS5 R/W Description @@ -84,46 +105,100 @@ //************************************************************************** class pit68230_device : public device_t, public device_execute_interface { -public: -// construction/destruction -pit68230_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); -pit68230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -template static devcb_base &set_pa_wr_callback (device_t &device, _Object object) -{ - return downcast(device).m_write_pa.set_callback (object); -} -template static devcb_base &set_h2_wr_callback (device_t &device, _Object object) -{ - return downcast(device).m_write_h2.set_callback (object); -} + public: + // construction/destruction + pit68230_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); + pit68230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + template static devcb_base &set_pa_in_callback (device_t &device, _Object object){ return downcast(device).m_pa_in_cb.set_callback (object); } + template static devcb_base &set_pa_out_callback (device_t &device, _Object object){ return downcast(device).m_pa_out_cb.set_callback (object); } + template static devcb_base &set_pb_in_callback (device_t &device, _Object object){ return downcast(device).m_pb_in_cb.set_callback (object); } + template static devcb_base &set_pb_out_callback (device_t &device, _Object object){ return downcast(device).m_pb_out_cb.set_callback (object); } + template static devcb_base &set_pc_in_callback (device_t &device, _Object object){ return downcast(device).m_pc_in_cb.set_callback (object); } + template static devcb_base &set_pc_out_callback (device_t &device, _Object object){ return downcast(device).m_pc_out_cb.set_callback (object); } + template static devcb_base &set_h1_out_callback (device_t &device, _Object object){ return downcast(device).m_h1_out_cb.set_callback (object); } + template static devcb_base &set_h2_out_callback (device_t &device, _Object object){ return downcast(device).m_h2_out_cb.set_callback (object); } + template static devcb_base &set_h3_out_callback (device_t &device, _Object object){ return downcast(device).m_h3_out_cb.set_callback (object); } + template static devcb_base &set_h4_out_callback (device_t &device, _Object object){ return downcast(device).m_h4_out_cb.set_callback (object); } -DECLARE_WRITE8_MEMBER (write); -DECLARE_READ8_MEMBER (read); + DECLARE_WRITE8_MEMBER (write); + DECLARE_READ8_MEMBER (read); -void h1_set (UINT8 state); -void portb_setbit (UINT8 bit, UINT8 state); + void h1_set (UINT8 state); + void portb_setbit (UINT8 bit, UINT8 state); + + void wr_pitreg_pgcr(UINT8 data); + void wr_pitreg_psrr(UINT8 data); + void wr_pitreg_paddr(UINT8 data); + void wr_pitreg_pbddr(UINT8 data); + void wr_pitreg_pcddr(UINT8 data); + void wr_pitreg_pacr(UINT8 data); + void wr_pitreg_pbcr(UINT8 data); + void wr_pitreg_padr(UINT8 data); + void wr_pitreg_paar(UINT8 data); + void wr_pitreg_pbar(UINT8 data); + void wr_pitreg_psr(UINT8 data); + void wr_pitreg_tcr(UINT8 data); + void wr_pitreg_cprh(UINT8 data); + void wr_pitreg_cprm(UINT8 data); + void wr_pitreg_cprl(UINT8 data); + + UINT8 rr_pitreg_pgcr(); + UINT8 rr_pitreg_psrr(); + UINT8 rr_pitreg_paddr(); + UINT8 rr_pitreg_pbddr(); + UINT8 rr_pitreg_pcddr(); + UINT8 rr_pitreg_pacr(); + UINT8 rr_pitreg_pbcr(); + UINT8 rr_pitreg_padr(); + UINT8 rr_pitreg_pbdr(); + UINT8 rr_pitreg_paar(); + UINT8 rr_pitreg_pbar(); + UINT8 rr_pitreg_psr(); + UINT8 rr_pitreg_cntrh(); + UINT8 rr_pitreg_cntrm(); + UINT8 rr_pitreg_cntrl(); 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; -virtual void execute_run () override; -int m_icount; -devcb_write8 m_write_pa; -devcb_write_line m_write_h2; -// peripheral ports -UINT8 m_pgcr; // Port General Control register -UINT8 m_psrr; // Port Service Request register -UINT8 m_paddr; // Port A Data Direction register -UINT8 m_pbddr; // Port B Data Direction register -UINT8 m_pcddr; // Port C Data Direction register -UINT8 m_pacr; // Port A Control register -UINT8 m_pbcr; // Port B Control register -UINT8 m_padr; // Port A Data register -UINT8 m_pbdr; // Port B Data register -UINT8 m_psr; // Port Status Register + enum { + REG_TCR_ENABLE = 0x01 + }; + + // 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; + virtual void execute_run () override; + int m_icount; + + devcb_write8 m_pa_out_cb; + devcb_read8 m_pa_in_cb; + devcb_write8 m_pb_out_cb; + devcb_read8 m_pb_in_cb; + devcb_write8 m_pc_out_cb; + devcb_read8 m_pc_in_cb; + devcb_write_line m_h1_out_cb; + devcb_write_line m_h2_out_cb; + devcb_write_line m_h3_out_cb; + devcb_write_line m_h4_out_cb; + + // peripheral ports + UINT8 m_pgcr; // Port General Control register + UINT8 m_psrr; // Port Service Request register + UINT8 m_paddr; // Port A Data Direction register + UINT8 m_pbddr; // Port B Data Direction register + UINT8 m_pcddr; // Port C Data Direction register + UINT8 m_pacr; // Port A Control register + UINT8 m_pbcr; // Port B Control register + UINT8 m_padr; // Port A Data register + UINT8 m_pbdr; // Port B Data register + UINT8 m_psr; // Port Status Register + UINT8 m_tcr; // Timer Control Register + int m_cpr; // Counter Preload Registers (3 x 8 = 24 bits) + // UINT8 m_cprh; // Counter Preload Register High + // UINT8 m_cprm; // Counter Preload Register Mid + // UINT8 m_cprl; // Counter Preload Register Low + int m_cntr; // - The 24 bit Counter }; // device type definition 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; +const device_type DUSCC_CHANNEL = &device_creator; +const device_type DUSCC26562 = &device_creator; +const device_type DUSCC26C562 = &device_creator; +const device_type DUSCC68562 = &device_creator; +const device_type DUSCC68C562 = &device_creator; + +//------------------------------------------------- +// 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(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 static devcb_base &set_out_txda_callback(device_t &device, _Object object) { return downcast(device).m_out_txda_cb.set_callback(object); } + template static devcb_base &set_out_dtra_callback(device_t &device, _Object object) { return downcast(device).m_out_dtra_cb.set_callback(object); } + template static devcb_base &set_out_rtsa_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsa_cb.set_callback(object); } + template static devcb_base &set_out_synca_callback(device_t &device, _Object object) { return downcast(device).m_out_synca_cb.set_callback(object); } + + template static devcb_base &set_out_txdb_callback(device_t &device, _Object object) { return downcast(device).m_out_txdb_cb.set_callback(object); } + template static devcb_base &set_out_dtrb_callback(device_t &device, _Object object) { return downcast(device).m_out_dtrb_cb.set_callback(object); } + template static devcb_base &set_out_rtsb_callback(device_t &device, _Object object) { return downcast(device).m_out_rtsb_cb.set_callback(object); } + template static devcb_base &set_out_syncb_callback(device_t &device, _Object object) { return downcast(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(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 m_chanA; + required_device 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__ diff --git a/src/mame/drivers/fccpu30.cpp b/src/mame/drivers/fccpu30.cpp new file mode 100644 index 00000000000..2be0284abe7 --- /dev/null +++ b/src/mame/drivers/fccpu30.cpp @@ -0,0 +1,802 @@ +// license:BSD-3-Clause +// copyright-holders:Joakim Larsson Edstrom +/*************************************************************************** + * + * Force SYS68K CPU-30 VME SBC drivers + * + * 21/05/2016 + * + * Thanks to Al Kossow his site http://www.bitsavers.org/ I got the information + * required to start the work with this driver. + * + * The driver is currently starting up and the Boot ROM asks for input do start FGA-002 + * diagnostics and do SRAM setup, which it does. After that it jumps to zeroed memory + * and crashes so needs some more work to be useful + * + * + * || + * || || CPU-30 + * ||||--||_____________________________________________________________ + * ||||--|| | + * || || _ |__ + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | |VME| + * || | | | + * || | |P1 | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || |_| | + * || |___| + * || | + * || | + * || | + * || | + * || | + * || | + * || | + * || | + * || |___ + * || _| | + * || | | | + * || | | | + * || | | | + * || | | | + * || | |VME| + * || | | | + * || | |P2 | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || | | | + * || |_| | + * || |___| + * || || + + * ||||--|| | + * ||||--||--------------------------------------------------------------+ + * || + * + * History of Force Computers + *--------------------------- + * + * Misc links about Force Computes and this board: + *------------------------------------------------ + * http://bitsavers.trailing-edge.com/pdf/forceComputers/CPU30/204030_CPU-30_R4_Technical_Reference_Oct96.pdf + * http://www.artisantg.com/info/P_wUovN.pdf + * + * Description(s) + * ------------- + * CPU-30 has the following feature set + * - 16.7 or 25 MHz MC68030 enhanced 32-bit microprocessor + * - 16.7 or 25 MHz MC68882 floating-point coprocessor + * - 32-512 Kb of SRAM with battery backup + * - 4, 8, 16, or 32MB of shared DRAM, with byte parity + * - Up to 8Mb Flash memory + * - 128,256 or 512 Mb boot flash or upto 1Mb of boot OTP PROM + * - Double High (6U) VMEmodule + * - A32/D32 VMEbus master/slave interface with system controller function (VMEchip ASIC) + * - Ethernet transceiver interface (AM79C90) + * - SCSI bus interface with independent data bus on P2 connector (MB87033/34) + * - Flopyy disk interface on P2 connector (FCD37C65C) + * - Four serial ports (DUSCC SCN68562 x 2) + * - 20 bit digital i/o for user applications( 2 x 68230 PI/T ) + * - Real-Time Clock with interrupt (72423) + * - 4-level requester, 7-level interrupter, and 7-level interrupt handler for VMEbus (VMEchip ASIC) + * + * NOTE: This driver currently mimics the CPU-30xyz configuration: 16MHz, 4Mb RAM, no parity, no ethernet (See TODO) + * + * Address Map + * -------------------------------------------------------------------------- + * Range Decscription + * -------------------------------------------------------------------------- + * 00000000-0xxFFFFF Shared DRAM D8-D32 xx=0x1F-0x03 for 32Mb-4Mb + * 0yy00000-FAFFFFFF VME A32 D8-D32 yy=xx+1 + * FB000000-FBFEFFFF VME A24 D8-D32 + * FBFF0000-FBFFFFFF VME A16 D8-D32 + * FC000000-FCFEFFFF VME A24 D8-D16 + * FCFF0000-FCFFFFFF VME A16 D8-D16 + * FD000000-FEEFFFFF Reserved + * FEF00000-FEF7FFFF LAN RAM D8-D32 + * FEF80000-FEFFFFFF LAN Controller D16 (AM79C90) + * FF000000-FF7FFFFF System PROM D8-D32 (read) D32 (flash write) + * FF800000-FF800BFF Reserved + * FF800C00-FF800DFF PIT1 D8 (68230) + * FF800E00-FF800FFF PIT2 D8 (68230) + * FF801000-FF801FFF Reserved + * FF802000-FF8021FF DUSCC1 D8 (SCN68562) + * FF802200-FF8023FF DUSCC2 D8 (SCN68562) + * FF802400-FF802FFF Reserved + * FF803000-FF8031FF RTC (72423) D8 + * FF803200-FF8033FF Reserved + * FF803400-FF8035FF SCSI controller (MB87033/34) D8 + * FF803600-FF8037FF Reserved + * FF803800-FF80397F Floppy controller (FDC37C65C) D8 + * FF803980-FF8039FF Slot 1 status register (read) D8 + * FFC00000-FFCFFFFF Local SRAM D8-D32 + * FFD00000-FFDFFFFF FGA-002 Gate Array D8-D32 + * FFE00000-FFEFFFFF Boot PROM D8-D32 + * FFF00000-FFFFFFFF Reserved + * -------------------------------------------------------------------------- + * + * Interrupt sources MVME + * ---------------------------------------------------------- + * Description Device Lvl IRQ VME board + * /Board Vector Address + * ---------------------------------------------------------- + * On board Sources + * + * Off board Sources (other VME boards) + * + * ---------------------------------------------------------- + * + * DMAC Channel Assignments + * ---------------------------------------------------------- + * Channel MVME147 + * ---------------------------------------------------------- + * + * + * TODO: + * - Investigate and fix crash + * - Add VxWorks proms + * - Add more devices + * - Write VME device + * - Add variants of boards + * + ****************************************************************************/ + +#include "emu.h" +#include "cpu/m68000/m68000.h" +#include "machine/scnxx562.h" +#include "machine/68230pit.h" +#include "machine/nvram.h" +#include "bus/rs232/rs232.h" +#include "machine/clock.h" +//#include "machine/timekpr.h" + +#define VERBOSE 0 + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) +#if VERBOSE >= 2 +#define logerror printf +#endif + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + +#define DUSCC_CLOCK XTAL_14_7456MHz /* Verified */ + +class fccpu30_state : public driver_device +{ +public: +fccpu30_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device (mconfig, type, tag), + m_maincpu (*this, "maincpu") + ,m_dusccterm(*this, "duscc") + ,m_pit1 (*this, "pit1") + ,m_pit2 (*this, "pit2") + { + } + + DECLARE_READ32_MEMBER (bootvect_r); + DECLARE_WRITE32_MEMBER (bootvect_w); + /* FGA-002 - Force Gate Array */ + DECLARE_READ8_MEMBER (fga8_r); + DECLARE_WRITE8_MEMBER (fga8_w); + + /* Rotary switch PIT input */ + DECLARE_READ8_MEMBER (rotary_rd); + DECLARE_READ8_MEMBER (board_mem_id_rd); + + /* VME bus accesses */ + //DECLARE_READ16_MEMBER (vme_a24_r); + //DECLARE_WRITE16_MEMBER (vme_a24_w); + //DECLARE_READ16_MEMBER (vme_a16_r); + //DECLARE_WRITE16_MEMBER (vme_a16_w); + virtual void machine_start () override; + virtual void machine_reset () override; +protected: + +private: + required_device m_maincpu; + required_device m_dusccterm; + + required_device m_pit1; + required_device m_pit2; + + // Pointer to System ROMs needed by bootvect_r and masking RAM buffer for post reset accesses + UINT32 *m_sysrom; + UINT32 m_sysram[2]; + + // FGA-002 + UINT8 m_fga002[0x500]; +}; + +static ADDRESS_MAP_START (fccpu30_mem, AS_PROGRAM, 32, fccpu30_state) + ADDRESS_MAP_UNMAP_HIGH + AM_RANGE (0x00000000, 0x00000007) AM_ROM AM_READ (bootvect_r) /* ROM mirror just during reset */ + AM_RANGE (0x00000000, 0x00000007) AM_RAM AM_WRITE (bootvect_w) /* After first write we act as RAM */ + AM_RANGE (0x00000008, 0x003fffff) AM_RAM /* 4 Mb RAM */ + AM_RANGE (0xff000000, 0xff7fffff) AM_ROM AM_REGION("maincpu", 0xff000000) + AM_RANGE (0xff802000, 0xff8021ff) AM_DEVREADWRITE8("duscc", duscc68562_device, read, write, 0xffffffff) /* Port 1&2 - Dual serial port DUSCC */ + AM_RANGE (0xff800c00, 0xff800dff) AM_DEVREADWRITE8("pit1", pit68230_device, read, write, 0xffffffff) + AM_RANGE (0xff800e00, 0xff800fff) AM_DEVREADWRITE8("pit2", pit68230_device, read, write, 0xffffffff) + AM_RANGE (0xffc00000, 0xffcfffff) AM_RAM AM_SHARE ("nvram") /* On-board SRAM with battery backup (nvram) */ + AM_RANGE (0xffd00000, 0xffd004ff) AM_READWRITE8(fga8_r, fga8_w, 0xffffffff) /* FGA-002 Force Gate Array */ + AM_RANGE (0xffe00000, 0xffefffff) AM_ROM AM_REGION("maincpu", 0xffe00000) + + //AM_RANGE(0x100000, 0xfeffff) AM_READWRITE(vme_a24_r, vme_a24_w) /* VMEbus Rev B addresses (24 bits) - not verified */ + //AM_RANGE(0xff0000, 0xffffff) AM_READWRITE(vme_a16_r, vme_a16_w) /* VMEbus Rev B addresses (16 bits) - not verified */ +ADDRESS_MAP_END + +/* Input ports */ +static INPUT_PORTS_START (fccpu30) +INPUT_PORTS_END + +#define FGA_ICRMBOX0 0x0000 +#define FGA_ICRMBOX1 0x0004 +#define FGA_ICRMBOX2 0x0008 +#define FGA_ICRMBOX3 0x000c +#define FGA_ICRMBOX4 0x0010 +#define FGA_ICRMBOX5 0x0014 +#define FGA_ICRMBOX6 0x0018 +#define FGA_ICRMBOX7 0x001C +#define FGA_VMEPAGE 0x0200 +#define FGA_ICRVME1 0x0204 +#define FGA_ICRVME2 0x0208 +#define FGA_ICRVME3 0x020c +#define FGA_ICRVME4 0x0210 +#define FGA_ICRVME5 0x0214 +#define FGA_ICRVME6 0x0218 +#define FGA_ICRVME7 0x021c +#define FGA_ICRTIM0 0x0220 +#define FGA_ICRDMANORM 0x0230 +#define FGA_ICRDMAERR 0x0234 +#define FGA_CTL1 0x0238 +#define FGA_CTL2 0x023c +#define FGA_ICRFMB0REF 0x0240 +#define FGA_ICRFMB1REF 0x0244 +#define FGA_ICRFMB0MES 0x0248 +#define FGA_ICRFMB1MES 0x024c +#define FGA_CTL3 0x0250 +#define FGA_CTL4 0x0254 +#define FGA_ICRPARITY 0x0258 +#define FGA_AUXPINCTL 0x0260 +#define FGA_CTL5 0x0264 +#define FGA_AUXFIFWEX 0x0268 +#define FGA_AUXFIFREX 0x026c +#define FGA_CTL6 0x0270 +#define FGA_CTL7 0x0274 +#define FGA_CTL8 0x0278 +#define FGA_CTL9 0x027c +#define FGA_ICRABORT 0x0280 +#define FGA_ICRACFAIL 0x0284 +#define FGA_ICRSYSFAIL 0x0288 +#define FGA_ICRLOCAL0 0x028c +#define FGA_ICRLOCAL1 0x0290 +#define FGA_ICRLOCAL2 0x0294 +#define FGA_ICRLOCAL3 0x0298 +#define FGA_ICRLOCAL4 0x029c +#define FGA_ICRLOCAL5 0x02a0 +#define FGA_ICRLOCAL6 0x02a4 +#define FGA_ICRLOCAL7 0x02a8 +#define FGA_ENAMCODE 0x02b4 +#define FGA_CTL10 0x02c0 +#define FGA_CTL11 0x02c4 +#define FGA_MAINUM 0x02c8 +#define FGA_MAINUU 0x02cc +#define FGA_BOTTOMPAGEU 0x02d0 +#define FGA_BOTTOMPAGEL 0x02d4 +#define FGA_TOPPAGEU 0x02d8 +#define FGA_TOPPAGEL 0x02dc +#define FGA_MYVMEPAGE 0x02fc +#define FGA_TIM0PRELOAD 0x0300 +#define FGA_TIM0CTL 0x0310 +#define FGA_DMASRCATT 0x0320 +#define FGA_DMADSTATT 0x0324 +#define FGA_DMA_GENERAL 0x0328 +#define FGA_CTL12 0x032c +#define FGA_LIOTIMING 0x0330 +#define FGA_LOCALIACK 0x0334 +#define FGA_FMBCTL 0x0338 +#define FGA_FMBAREA 0x033c +#define FGA_AUXSRCSTART 0x0340 +#define FGA_AUXDSTSTART 0x0344 +#define FGA_AUXSRCTERM 0x0348 +#define FGA_AUXDSTTERM 0x034c +#define FGA_CTL13 0x0350 +#define FGA_CTL14 0x0354 +#define FGA_CTL15 0x0358 +#define FGA_CTL16 0x035c +#define FGA_SPECIALENA 0x0424 +#define FGA_ISTIM0 0x04a0 +#define FGA_ISDMANORM 0x04b0 +#define FGA_ISDMAERR 0x04b4 +#define FGA_ISFMB0REF 0x04b8 +#define FGA_ISFMB1REF 0x04bc +#define FGA_ISPARITY 0x04c0 +#define FGA_DMARUNCTL 0x04c4 +#define FGA_ISABORT 0x04c8 +#define FGA_ISACFAIL 0x04cc +#define FGA_ISFMB0MES 0x04e0 +#define FGA_ISFMB1MES 0x04e4 +#define FGA_ISSYSFAIL 0x04d0 +#define FGA_ABORTPIN 0x04d4 +#define FGA_RSVMECALL 0x04f0 +#define FGA_RSKEYRES 0x04f4 +#define FGA_RSCPUCALL 0x04f8 +#define FGA_RSLOCSW 0x04fc + +/* Start it up */ +void fccpu30_state::machine_start () +{ + LOG(("--->%s\n", FUNCNAME)); + + save_pointer (NAME (m_sysrom), sizeof(m_sysrom)); + save_pointer (NAME (m_sysram), sizeof(m_sysram)); + save_pointer (NAME (m_fga002), sizeof(m_fga002)); + + /* Setup pointer to bootvector in ROM for bootvector handler bootvect_r */ + m_sysrom = (UINT32*)(memregion ("maincpu")->base () + 0xffe00000); +} + +void fccpu30_state::machine_reset () +{ + LOG(("--->%s\n", FUNCNAME)); + + /* 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*)(memregion ("maincpu")->base () + 0xffe00000); + + /* Reset values for the FGA-002 */ + memset(&m_fga002[0], 0, sizeof(m_fga002)); + m_fga002[FGA_RSVMECALL] = 0x80; + m_fga002[FGA_RSKEYRES] = 0x80; + m_fga002[FGA_RSCPUCALL] = 0x80; + m_fga002[FGA_RSLOCSW] = 0x80; + m_fga002[FGA_ISTIM0] = 0x80; + m_fga002[FGA_ISDMANORM] = 0x80; + m_fga002[FGA_ISDMAERR] = 0x80; + m_fga002[FGA_ISFMB0REF] = 0x80; + m_fga002[FGA_ISFMB1REF] = 0x80; + m_fga002[FGA_ISPARITY] = 0x80; + m_fga002[FGA_ISABORT] = 0x80; + m_fga002[FGA_ISACFAIL] = 0x80; + m_fga002[FGA_ISSYSFAIL] = 0x80; + m_fga002[FGA_ISFMB0MES] = 0x80; + m_fga002[FGA_ISFMB1MES] = 0x80; +} + +/* Boot vector handler, the PCB hardwires the first 8 bytes from 0xff800000 to 0x0 at reset*/ +READ32_MEMBER (fccpu30_state::bootvect_r){ + return m_sysrom[offset]; +} + +WRITE32_MEMBER (fccpu30_state::bootvect_w){ + m_sysram[offset % sizeof(m_sysram)] &= ~mem_mask; + m_sysram[offset % sizeof(m_sysram)] |= (data & mem_mask); + m_sysrom = &m_sysram[0]; // redirect all upcomming accesses to masking RAM until reset. +} + +/* + * FGA-002 driver, might deserve its own driver but will rest here until another board wants it + * +The FGA-002 gate array is a high speed CMOS device manufactured in 1.2 micron technology and +containing 24,000 gates in a 281 pin PGA package. It provides interfaces to the 68020/30 microprocessor +as well as a VMEbus compatible interface. The auxilary interface of the gate array is a high speed data +channel used by the internal 32 bit DMA controller. The interface allows data transfer rates of up to +6 MByte/second. The timing of the local I/O interface is programmable and provides easy interfacing of +local I/O devices. All control, address and data lines of the CPU and the VMEbus are either directly +connected or connected via buffers to the gate array allowing easy implementation and usage. +The gate array registers are programmed by the local CPU. + +FEATURES: +- Programmable decoding for CPU and VME access to the local main memory +- Interrupt management for internal and external interrupt sources +- 32 bit multi-port DMA Controller +- FORCE Message Broadcast slave interface with 2 message channels +- 8 interrupt capable MAILBOXES +- 8 bit TIMER with 16 selectable internal source clocks +*/ +WRITE8_MEMBER (fccpu30_state::fga8_w){ + LOG(("%s[%04x] <- %02x - ", FUNCNAME, offset, data)); + switch(offset) + { + case FGA_SPECIALENA : LOG(("FGA_SPECIALENA - not implemented\n")); m_fga002[FGA_SPECIALENA] = data; break; + case FGA_RSVMECALL : LOG(("FGA_RSVMECALL - not implemented\n")); m_fga002[FGA_RSVMECALL] = data; break; + case FGA_RSKEYRES : LOG(("FGA_RSKEYRES - not implemented\n")); m_fga002[FGA_RSKEYRES] = data; break; + case FGA_RSCPUCALL : LOG(("FGA_RSCPUCALL - not implemented\n")); m_fga002[FGA_RSCPUCALL] = data; break; + case FGA_RSLOCSW : LOG(("FGA_RSLOCSW - not implemented\n")); m_fga002[FGA_RSLOCSW] = data; break; + case FGA_ICRMBOX0 : LOG(("FGA_ICRMBOX0 - not implemented\n")); m_fga002[FGA_ICRMBOX0] = data; break; + case FGA_ICRMBOX1 : LOG(("FGA_ICRMBOX1 - not implemented\n")); m_fga002[FGA_ICRMBOX1] = data; break; + case FGA_ICRMBOX2 : LOG(("FGA_ICRMBOX2 - not implemented\n")); m_fga002[FGA_ICRMBOX2] = data; break; + case FGA_ICRMBOX3 : LOG(("FGA_ICRMBOX3 - not implemented\n")); m_fga002[FGA_ICRMBOX3] = data; break; + case FGA_ICRMBOX4 : LOG(("FGA_ICRMBOX4 - not implemented\n")); m_fga002[FGA_ICRMBOX4] = data; break; + case FGA_ICRMBOX5 : LOG(("FGA_ICRMBOX5 - not implemented\n")); m_fga002[FGA_ICRMBOX5] = data; break; + case FGA_ICRMBOX6 : LOG(("FGA_ICRMBOX6 - not implemented\n")); m_fga002[FGA_ICRMBOX6] = data; break; + case FGA_ICRMBOX7 : LOG(("FGA_ICRMBOX7 - not implemented\n")); m_fga002[FGA_ICRMBOX7] = data; break; + case FGA_VMEPAGE : LOG(("FGA_VMEPAGE - not implemented\n")); m_fga002[FGA_VMEPAGE ] = data; break; + case FGA_ICRVME1 : LOG(("FGA_ICRVME1 - not implemented\n")); m_fga002[FGA_ICRVME1] = data; break; + case FGA_ICRVME2 : LOG(("FGA_ICRVME2 - not implemented\n")); m_fga002[FGA_ICRVME2] = data; break; + case FGA_ICRVME3 : LOG(("FGA_ICRVME3 - not implemented\n")); m_fga002[FGA_ICRVME3] = data; break; + case FGA_ICRVME4 : LOG(("FGA_ICRVME4 - not implemented\n")); m_fga002[FGA_ICRVME4] = data; break; + case FGA_ICRVME5 : LOG(("FGA_ICRVME5 - not implemented\n")); m_fga002[FGA_ICRVME5] = data; break; + case FGA_ICRVME6 : LOG(("FGA_ICRVME6 - not implemented\n")); m_fga002[FGA_ICRVME6] = data; break; + case FGA_ICRVME7 : LOG(("FGA_ICRVME7 - not implemented\n")); m_fga002[FGA_ICRVME7] = data; break; + case FGA_ICRTIM0 : LOG(("FGA_ICRTIM0 - not implemented\n")); m_fga002[FGA_ICRTIM0] = data; break; + case FGA_ICRDMANORM : LOG(("FGA_ICRDMANORM - not implemented\n")); m_fga002[FGA_ICRDMANORM] = data; break; + case FGA_ICRDMAERR : LOG(("FGA_ICRDMAERR - not implemented\n")); m_fga002[FGA_ICRDMAERR] = data; break; + case FGA_CTL1 : LOG(("FGA_CTL1 - not implemented\n")); m_fga002[FGA_CTL1] = data; break; + case FGA_CTL2 : LOG(("FGA_CTL2 - not implemented\n")); m_fga002[FGA_CTL2] = data; break; + case FGA_ICRFMB0REF : LOG(("FGA_ICRFMB0REF - not implemented\n")); m_fga002[FGA_ICRFMB0REF] = data; break; + case FGA_ICRFMB1REF : LOG(("FGA_ICRFMB1REF - not implemented\n")); m_fga002[FGA_ICRFMB1REF] = data; break; + case FGA_ICRFMB0MES : LOG(("FGA_ICRFMB0MES - not implemented\n")); m_fga002[FGA_ICRFMB0MES] = data; break; + case FGA_ICRFMB1MES : LOG(("FGA_ICRFMB1MES - not implemented\n")); m_fga002[FGA_ICRFMB1MES] = data; break; + case FGA_CTL3 : LOG(("FGA_CTL3 - not implemented\n")); m_fga002[FGA_CTL3] = data; break; + case FGA_CTL4 : LOG(("FGA_CTL4 - not implemented\n")); m_fga002[FGA_CTL4] = data; break; + case FGA_ICRPARITY : LOG(("FGA_ICRPARITY - not implemented\n")); m_fga002[FGA_ICRPARITY] = data; break; + case FGA_AUXPINCTL : LOG(("FGA_AUXPINCTL - not implemented\n")); m_fga002[FGA_AUXPINCTL] = data; break; + case FGA_CTL5 : LOG(("FGA_CTL5 - not implemented\n")); m_fga002[FGA_CTL5] = data; break; + case FGA_AUXFIFWEX : LOG(("FGA_AUXFIFWEX - not implemented\n")); m_fga002[FGA_AUXFIFWEX] = data; break; + case FGA_AUXFIFREX : LOG(("FGA_AUXFIFREX - not implemented\n")); m_fga002[FGA_AUXFIFREX] = data; break; + case FGA_CTL6 : LOG(("FGA_CTL6 - not implemented\n")); m_fga002[FGA_CTL6] = data; break; + case FGA_CTL7 : LOG(("FGA_CTL7 - not implemented\n")); m_fga002[FGA_CTL7] = data; break; + case FGA_CTL8 : LOG(("FGA_CTL8 - not implemented\n")); m_fga002[FGA_CTL8] = data; break; + case FGA_CTL9 : LOG(("FGA_CTL9 - not implemented\n")); m_fga002[FGA_CTL9] = data; break; + case FGA_ICRABORT : LOG(("FGA_ICRABORT - not implemented\n")); m_fga002[FGA_ICRABORT] = data; break; + case FGA_ICRACFAIL : LOG(("FGA_ICRACFAIL - not implemented\n")); m_fga002[FGA_ICRACFAIL] = data; break; + case FGA_ICRSYSFAIL : LOG(("FGA_ICRSYSFAIL - not implemented\n")); m_fga002[FGA_ICRSYSFAIL] = data; break; + case FGA_ICRLOCAL0 : LOG(("FGA_ICRLOCAL0 - not implemented\n")); m_fga002[FGA_ICRLOCAL0] = data; break; + case FGA_ICRLOCAL1 : LOG(("FGA_ICRLOCAL1 - not implemented\n")); m_fga002[FGA_ICRLOCAL1] = data; break; + case FGA_ICRLOCAL2 : LOG(("FGA_ICRLOCAL2 - not implemented\n")); m_fga002[FGA_ICRLOCAL2] = data; break; + case FGA_ICRLOCAL3 : LOG(("FGA_ICRLOCAL3 - not implemented\n")); m_fga002[FGA_ICRLOCAL3] = data; break; + case FGA_ICRLOCAL4 : LOG(("FGA_ICRLOCAL4 - not implemented\n")); m_fga002[FGA_ICRLOCAL4] = data; break; + case FGA_ICRLOCAL5 : LOG(("FGA_ICRLOCAL5 - not implemented\n")); m_fga002[FGA_ICRLOCAL5] = data; break; + case FGA_ICRLOCAL6 : LOG(("FGA_ICRLOCAL6 - not implemented\n")); m_fga002[FGA_ICRLOCAL6] = data; break; + case FGA_ICRLOCAL7 : LOG(("FGA_ICRLOCAL7 - not implemented\n")); m_fga002[FGA_ICRLOCAL7] = data; break; + case FGA_ENAMCODE : LOG(("FGA_ENAMCODE - not implemented\n")); m_fga002[FGA_ENAMCODE] = data; break; + case FGA_CTL10 : LOG(("FGA_CTL10 - not implemented\n")); m_fga002[FGA_CTL10] = data; break; + case FGA_CTL11 : LOG(("FGA_CTL11 - not implemented\n")); m_fga002[FGA_CTL11] = data; break; + case FGA_MAINUM : LOG(("FGA_MAINUM - not implemented\n")); m_fga002[FGA_MAINUM] = data; break; + case FGA_MAINUU : LOG(("FGA_MAINUU - not implemented\n")); m_fga002[FGA_MAINUU] = data; break; + case FGA_BOTTOMPAGEU : LOG(("FGA_BOTTOMPAGEU - not implemented\n")); m_fga002[FGA_BOTTOMPAGEU] = data; break; + case FGA_BOTTOMPAGEL : LOG(("FGA_BOTTOMPAGEL - not implemented\n")); m_fga002[FGA_BOTTOMPAGEL] = data; break; + case FGA_TOPPAGEU : LOG(("FGA_TOPPAGEU - not implemented\n")); m_fga002[FGA_TOPPAGEU] = data; break; + case FGA_TOPPAGEL : LOG(("FGA_TOPPAGEL - not implemented\n")); m_fga002[FGA_TOPPAGEL] = data; break; + case FGA_MYVMEPAGE : LOG(("FGA_MYVMEPAGE - not implemented\n")); m_fga002[FGA_MYVMEPAGE] = data; break; + case FGA_TIM0PRELOAD : LOG(("FGA_TIM0PRELOAD - not implemented\n")); m_fga002[FGA_TIM0PRELOAD] = data; break; + case FGA_TIM0CTL : LOG(("FGA_TIM0CTL - not implemented\n")); m_fga002[FGA_TIM0CTL] = data; break; + case FGA_DMASRCATT : LOG(("FGA_DMASRCATT - not implemented\n")); m_fga002[FGA_DMASRCATT] = data; break; + case FGA_DMADSTATT : LOG(("FGA_DMADSTATT - not implemented\n")); m_fga002[FGA_DMADSTATT] = data; break; + case FGA_DMA_GENERAL : LOG(("FGA_DMA_GENERAL - not implemented\n")); m_fga002[FGA_DMA_GENERAL] = data; break; + case FGA_CTL12 : LOG(("FGA_CTL12 - not implemented\n")); m_fga002[FGA_CTL12] = data; break; + case FGA_LIOTIMING : LOG(("FGA_LIOTIMING - not implemented\n")); m_fga002[FGA_LIOTIMING] = data; break; + case FGA_LOCALIACK : LOG(("FGA_LOCALIACK - not implemented\n")); m_fga002[FGA_LOCALIACK] = data; break; + case FGA_FMBCTL : LOG(("FGA_FMBCTL - not implemented\n")); m_fga002[FGA_FMBCTL] = data; break; + case FGA_FMBAREA : LOG(("FGA_FMBAREA - not implemented\n")); m_fga002[FGA_FMBAREA] = data; break; + case FGA_AUXSRCSTART : LOG(("FGA_AUXSRCSTART - not implemented\n")); m_fga002[FGA_AUXSRCSTART] = data; break; + case FGA_AUXDSTSTART : LOG(("FGA_AUXDSTSTART - not implemented\n")); m_fga002[FGA_AUXDSTSTART] = data; break; + case FGA_AUXSRCTERM : LOG(("FGA_AUXSRCTERM - not implemented\n")); m_fga002[FGA_AUXSRCTERM] = data; break; + case FGA_AUXDSTTERM : LOG(("FGA_AUXDSTTERM - not implemented\n")); m_fga002[FGA_AUXDSTTERM] = data; break; + case FGA_CTL13 : LOG(("FGA_CTL13 - not implemented\n")); m_fga002[FGA_CTL13] = data; break; + case FGA_CTL14 : LOG(("FGA_CTL14 - not implemented\n")); m_fga002[FGA_CTL14] = data; break; + case FGA_CTL15 : LOG(("FGA_CTL15 - not implemented\n")); m_fga002[FGA_CTL15] = data; break; + case FGA_CTL16 : LOG(("FGA_CTL16 - not implemented\n")); m_fga002[FGA_CTL16] = data; break; + case FGA_ISTIM0 : LOG(("FGA_ISTIM0 - not implemented\n")); m_fga002[FGA_ISTIM0] = data; break; + case FGA_ISDMANORM : LOG(("FGA_ISDMANORM - not implemented\n")); m_fga002[FGA_ISDMANORM] = data; break; + case FGA_ISDMAERR : LOG(("FGA_ISDMAERR - not implemented\n")); m_fga002[FGA_ISDMAERR] = data; break; + case FGA_ISFMB0REF : LOG(("FGA_ISFMB0REF - not implemented\n")); m_fga002[FGA_ISFMB0REF] = data; break; + case FGA_ISFMB1REF : LOG(("FGA_ISFMB1REF - not implemented\n")); m_fga002[FGA_ISFMB1REF] = data; break; + case FGA_ISPARITY : LOG(("FGA_ISPARITY - not implemented\n")); m_fga002[FGA_ISPARITY] = data; break; + case FGA_DMARUNCTL : LOG(("FGA_DMARUNCTL - not implemented\n")); m_fga002[FGA_DMARUNCTL] = data; break; + case FGA_ISABORT : LOG(("FGA_ISABORT - not implemented\n")); m_fga002[FGA_ISABORT] = data; break; + case FGA_ISFMB0MES : LOG(("FGA_ISFMB0MES - not implemented\n")); m_fga002[FGA_ISFMB0MES] = data; break; + case FGA_ISFMB1MES : LOG(("FGA_ISFMB1MES - not implemented\n")); m_fga002[FGA_ISFMB1MES] = data; break; + case FGA_ABORTPIN : LOG(("FGA_ABORTPIN - not implemented\n")); m_fga002[FGA_ABORTPIN] = data; break; + default: + LOG(("Unsupported register %04x\n", offset)); + } +} + +READ8_MEMBER (fccpu30_state::fga8_r){ + + UINT8 ret = 0; + + LOG(("%s[%04x] ", FUNCNAME, offset)); + switch(offset) + { + case FGA_SPECIALENA : ret = m_fga002[FGA_SPECIALENA]; LOG(("FGA_SPECIALENA returns %02x - not implemented\n", ret)); break; + case FGA_RSVMECALL : ret = m_fga002[FGA_RSVMECALL]; LOG(("FGA_RSVMECALL returns %02x - not implemented\n", ret)); break; + case FGA_RSKEYRES : ret = m_fga002[FGA_RSKEYRES]; LOG(("FGA_RSKEYRES returns %02x - not implemented\n", ret)); break; + case FGA_RSCPUCALL : ret = m_fga002[FGA_RSCPUCALL]; LOG(("FGA_RSCPUCALL returns %02x - not implemented\n", ret)); break; + case FGA_RSLOCSW : ret = m_fga002[FGA_RSLOCSW]; LOG(("FGA_RSLOCSW returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX0 : ret = m_fga002[FGA_ICRMBOX0]; LOG(("FGA_ICRMBOX0 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX1 : ret = m_fga002[FGA_ICRMBOX1]; LOG(("FGA_ICRMBOX1 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX2 : ret = m_fga002[FGA_ICRMBOX2]; LOG(("FGA_ICRMBOX2 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX3 : ret = m_fga002[FGA_ICRMBOX3]; LOG(("FGA_ICRMBOX3 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX4 : ret = m_fga002[FGA_ICRMBOX4]; LOG(("FGA_ICRMBOX4 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX5 : ret = m_fga002[FGA_ICRMBOX5]; LOG(("FGA_ICRMBOX5 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX6 : ret = m_fga002[FGA_ICRMBOX6]; LOG(("FGA_ICRMBOX6 returns %02x - not implemented\n", ret)); break; + case FGA_ICRMBOX7 : ret = m_fga002[FGA_ICRMBOX7]; LOG(("FGA_ICRMBOX7 returns %02x - not implemented\n", ret)); break; + case FGA_VMEPAGE : ret = m_fga002[FGA_VMEPAGE]; LOG(("FGA_VMEPAGE returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME1 : ret = m_fga002[FGA_ICRVME1]; LOG(("FGA_ICRVME1 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME2 : ret = m_fga002[FGA_ICRVME2]; LOG(("FGA_ICRVME2 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME3 : ret = m_fga002[FGA_ICRVME3]; LOG(("FGA_ICRVME3 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME4 : ret = m_fga002[FGA_ICRVME4]; LOG(("FGA_ICRVME4 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME5 : ret = m_fga002[FGA_ICRVME5]; LOG(("FGA_ICRVME5 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME6 : ret = m_fga002[FGA_ICRVME6]; LOG(("FGA_ICRVME6 returns %02x - not implemented\n", ret)); break; + case FGA_ICRVME7 : ret = m_fga002[FGA_ICRVME7]; LOG(("FGA_ICRVME7 returns %02x - not implemented\n", ret)); break; + case FGA_ICRTIM0 : ret = m_fga002[FGA_ICRTIM0]; LOG(("FGA_ICRTIM0 returns %02x - not implemented\n", ret)); break; + case FGA_ICRDMANORM : ret = m_fga002[FGA_ICRDMANORM]; LOG(("FGA_ICRDMANORM returns %02x - not implemented\n", ret)); break; + case FGA_ICRDMAERR : ret = m_fga002[FGA_ICRDMAERR]; LOG(("FGA_ICRDMAERR returns %02x - not implemented\n", ret)); break; + case FGA_CTL1 : ret = m_fga002[FGA_CTL1]; LOG(("FGA_CTL1 returns %02x - not implemented\n", ret)); break; + case FGA_CTL2 : ret = m_fga002[FGA_CTL2]; LOG(("FGA_CTL2 returns %02x - not implemented\n", ret)); break; + case FGA_ICRFMB0REF : ret = m_fga002[FGA_ICRFMB0REF]; LOG(("FGA_ICRFMB0REF returns %02x - not implemented\n", ret)); break; + case FGA_ICRFMB1REF : ret = m_fga002[FGA_ICRFMB1REF]; LOG(("FGA_ICRFMB1REF returns %02x - not implemented\n", ret)); break; + case FGA_ICRFMB0MES : ret = m_fga002[FGA_ICRFMB0MES]; LOG(("FGA_ICRFMB0MES returns %02x - not implemented\n", ret)); break; + case FGA_ICRFMB1MES : ret = m_fga002[FGA_ICRFMB1MES]; LOG(("FGA_ICRFMB1MES returns %02x - not implemented\n", ret)); break; + case FGA_CTL3 : ret = m_fga002[FGA_CTL3]; LOG(("FGA_CTL3 returns %02x - not implemented\n", ret)); break; + case FGA_CTL4 : ret = m_fga002[FGA_CTL4]; LOG(("FGA_CTL4 returns %02x - not implemented\n", ret)); break; + case FGA_ICRPARITY : ret = m_fga002[FGA_ICRPARITY]; LOG(("FGA_ICRPARITY returns %02x - not implemented\n", ret)); break; + case FGA_AUXPINCTL : ret = m_fga002[FGA_AUXPINCTL]; LOG(("FGA_AUXPINCTL returns %02x - not implemented\n", ret)); break; + case FGA_CTL5 : ret = m_fga002[FGA_CTL5]; LOG(("FGA_CTL5 returns %02x - not implemented\n", ret)); break; + case FGA_AUXFIFWEX : ret = m_fga002[FGA_AUXFIFWEX]; LOG(("FGA_AUXFIFWEX returns %02x - not implemented\n", ret)); break; + case FGA_AUXFIFREX : ret = m_fga002[FGA_AUXFIFREX]; LOG(("FGA_AUXFIFREX returns %02x - not implemented\n", ret)); break; + case FGA_CTL6 : ret = m_fga002[FGA_CTL6]; LOG(("FGA_CTL6 returns %02x - not implemented\n", ret)); break; + case FGA_CTL7 : ret = m_fga002[FGA_CTL7]; LOG(("FGA_CTL7 returns %02x - not implemented\n", ret)); break; + case FGA_CTL8 : ret = m_fga002[FGA_CTL8]; LOG(("FGA_CTL8 returns %02x - not implemented\n", ret)); break; + case FGA_CTL9 : ret = m_fga002[FGA_CTL9]; LOG(("FGA_CTL9 returns %02x - not implemented\n", ret)); break; + case FGA_ICRABORT : ret = m_fga002[FGA_ICRABORT]; LOG(("FGA_ICRABORT returns %02x - not implemented\n", ret)); break; + case FGA_ICRACFAIL : ret = m_fga002[FGA_ICRACFAIL]; LOG(("FGA_ICRACFAIL returns %02x - not implemented\n", ret)); break; + case FGA_ICRSYSFAIL : ret = m_fga002[FGA_ICRSYSFAIL]; LOG(("FGA_ICRSYSFAIL returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL0 : ret = m_fga002[FGA_ICRLOCAL0]; LOG(("FGA_ICRLOCAL0 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL1 : ret = m_fga002[FGA_ICRLOCAL1]; LOG(("FGA_ICRLOCAL1 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL2 : ret = m_fga002[FGA_ICRLOCAL2]; LOG(("FGA_ICRLOCAL2 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL3 : ret = m_fga002[FGA_ICRLOCAL3]; LOG(("FGA_ICRLOCAL3 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL4 : ret = m_fga002[FGA_ICRLOCAL4]; LOG(("FGA_ICRLOCAL4 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL5 : ret = m_fga002[FGA_ICRLOCAL5]; LOG(("FGA_ICRLOCAL5 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL6 : ret = m_fga002[FGA_ICRLOCAL6]; LOG(("FGA_ICRLOCAL6 returns %02x - not implemented\n", ret)); break; + case FGA_ICRLOCAL7 : ret = m_fga002[FGA_ICRLOCAL7]; LOG(("FGA_ICRLOCAL7 returns %02x - not implemented\n", ret)); break; + case FGA_ENAMCODE : ret = m_fga002[FGA_ENAMCODE]; LOG(("FGA_ENAMCODE returns %02x - not implemented\n", ret)); break; + case FGA_CTL10 : ret = m_fga002[FGA_CTL10]; LOG(("FGA_CTL10 returns %02x - not implemented\n", ret)); break; + case FGA_CTL11 : ret = m_fga002[FGA_CTL11]; LOG(("FGA_CTL11 returns %02x - not implemented\n", ret)); break; + case FGA_MAINUM : ret = m_fga002[FGA_MAINUM]; LOG(("FGA_MAINUM returns %02x - not implemented\n", ret)); break; + case FGA_MAINUU : ret = m_fga002[FGA_MAINUU]; LOG(("FGA_MAINUU returns %02x - not implemented\n", ret)); break; + case FGA_BOTTOMPAGEU : ret = m_fga002[FGA_BOTTOMPAGEU]; LOG(("FGA_BOTTOMPAGEU returns %02x - not implemented\n", ret)); break; + case FGA_BOTTOMPAGEL : ret = m_fga002[FGA_BOTTOMPAGEL]; LOG(("FGA_BOTTOMPAGEL returns %02x - not implemented\n", ret)); break; + case FGA_TOPPAGEU : ret = m_fga002[FGA_TOPPAGEU]; LOG(("FGA_TOPPAGEU returns %02x - not implemented\n", ret)); break; + case FGA_TOPPAGEL : ret = m_fga002[FGA_TOPPAGEL]; LOG(("FGA_TOPPAGEL returns %02x - not implemented\n", ret)); break; + case FGA_MYVMEPAGE : ret = m_fga002[FGA_MYVMEPAGE]; LOG(("FGA_MYVMEPAGE returns %02x - not implemented\n", ret)); break; + case FGA_TIM0PRELOAD : ret = m_fga002[FGA_TIM0PRELOAD]; LOG(("FGA_TIM0PRELOAD returns %02x - not implemented\n", ret)); break; + case FGA_TIM0CTL : ret = m_fga002[FGA_TIM0CTL]; LOG(("FGA_TIM0CTL returns %02x - not implemented\n", ret)); break; + case FGA_DMASRCATT : ret = m_fga002[FGA_DMASRCATT]; LOG(("FGA_DMASRCATT returns %02x - not implemented\n", ret)); break; + case FGA_DMADSTATT : ret = m_fga002[FGA_DMADSTATT]; LOG(("FGA_DMADSTATT returns %02x - not implemented\n", ret)); break; + case FGA_DMA_GENERAL : ret = m_fga002[FGA_DMA_GENERAL]; LOG(("FGA_DMA_GENERAL returns %02x - not implemented\n", ret)); break; + case FGA_CTL12 : ret = m_fga002[FGA_CTL12]; LOG(("FGA_CTL12 returns %02x - not implemented\n", ret)); break; + case FGA_LIOTIMING : ret = m_fga002[FGA_LIOTIMING]; LOG(("FGA_LIOTIMING returns %02x - not implemented\n", ret)); break; + case FGA_LOCALIACK : ret = m_fga002[FGA_LOCALIACK]; LOG(("FGA_LOCALIACK returns %02x - not implemented\n", ret)); break; + case FGA_FMBCTL : ret = m_fga002[FGA_FMBCTL]; LOG(("FGA_FMBCTL returns %02x - not implemented\n", ret)); break; + case FGA_FMBAREA : ret = m_fga002[FGA_FMBAREA]; LOG(("FGA_FMBAREA returns %02x - not implemented\n", ret)); break; + case FGA_AUXSRCSTART : ret = m_fga002[FGA_AUXSRCSTART]; LOG(("FGA_AUXSRCSTART returns %02x - not implemented\n", ret)); break; + case FGA_AUXDSTSTART : ret = m_fga002[FGA_AUXDSTSTART]; LOG(("FGA_AUXDSTSTART returns %02x - not implemented\n", ret)); break; + case FGA_AUXSRCTERM : ret = m_fga002[FGA_AUXSRCTERM]; LOG(("FGA_AUXSRCTERM returns %02x - not implemented\n", ret)); break; + case FGA_AUXDSTTERM : ret = m_fga002[FGA_AUXDSTTERM]; LOG(("FGA_AUXDSTTERM returns %02x - not implemented\n", ret)); break; + case FGA_CTL13 : ret = m_fga002[FGA_CTL13]; LOG(("FGA_CTL13 returns %02x - not implemented\n", ret)); break; + case FGA_CTL14 : ret = m_fga002[FGA_CTL14]; LOG(("FGA_CTL14 returns %02x - not implemented\n", ret)); break; + case FGA_CTL15 : ret = m_fga002[FGA_CTL15]; LOG(("FGA_CTL15 returns %02x - not implemented\n", ret)); break; + case FGA_CTL16 : ret = m_fga002[FGA_CTL16]; LOG(("FGA_CTL16 returns %02x - not implemented\n", ret)); break; + case FGA_ISTIM0 : ret = m_fga002[FGA_ISTIM0]; LOG(("FGA_ISTIM0 returns %02x - not implemented\n", ret)); break; + case FGA_ISDMANORM : ret = m_fga002[FGA_ISDMANORM]; LOG(("FGA_ISDMANORM returns %02x - not implemented\n", ret)); break; + case FGA_ISDMAERR : ret = m_fga002[FGA_ISDMAERR]; LOG(("FGA_ISDMAERR returns %02x - not implemented\n", ret)); break; + case FGA_ISFMB0REF : ret = m_fga002[FGA_ISFMB0REF]; LOG(("FGA_ISFMB0REF returns %02x - not implemented\n", ret)); break; + case FGA_ISFMB1REF : ret = m_fga002[FGA_ISFMB1REF]; LOG(("FGA_ISFMB1REF returns %02x - not implemented\n", ret)); break; + case FGA_ISPARITY : ret = m_fga002[FGA_ISPARITY]; LOG(("FGA_ISPARITY returns %02x - not implemented\n", ret)); break; + case FGA_DMARUNCTL : ret = m_fga002[FGA_DMARUNCTL]; LOG(("FGA_DMARUNCTL returns %02x - not implemented\n", ret)); break; + case FGA_ISABORT : ret = m_fga002[FGA_ISABORT]; LOG(("FGA_ISABORT returns %02x - not implemented\n", ret)); break; + case FGA_ISFMB0MES : ret = m_fga002[FGA_ISFMB0MES]; LOG(("FGA_ISFMB0MES returns %02x - not implemented\n", ret)); break; + case FGA_ISFMB1MES : ret = m_fga002[FGA_ISFMB1MES]; LOG(("FGA_ISFMB1MES returns %02x - not implemented\n", ret)); break; + case FGA_ABORTPIN : ret = m_fga002[FGA_ABORTPIN]; LOG(("FGA_ABORTPIN returns %02x - not implemented\n", ret)); break; + default: + LOG(("Unsupported register %04x\n", offset)); + } + return ret; +} + +/* + * Rotary Switches - to configure the board + * + * Table 25: PI/T #1 Interface Signals + * Pin Function In/Out + * PA0-PA3 SW1 In + * PA4 PA7 SW2 In + * + * Table 38: Upper Rotary Switch (SW2) + * Bit 3: This bit indicates whether the RAM disk should be initialized after reset. If this bit is set to "0" (settings 0-7), + * the RAM disk is initialized as defined by bit 0 and 1. When the disk is initialized, all data on the disk is lost. + * Bit 2: This bit defines the default data size on the VMEbus. If the bit is set to "0", 16 bits are selected, if it is set + * to "1", 32 bits are selected. + * Bit 1 and Bit 0: These two bits define the default RAM disk. See Table 40, "RAM Disk Usage," a detailed description. + * If AUTOBOOT is set by bit 2 and 3 of SW1, bit 1 and 0 of SW2 define which operating system will be booted. See Table 42, + * "Boot an Operating System (if AUTOBOOT is selected)," on page 129 for detailed description. + * + * Table 39: Lower Rotary Switch (SW1) + * Bit 3 and Bit 2: These two bits define which program is to be invoked after reset. Please refer + * to Table 41, "Program After Reset," on page 129 for a detailed description. + * Bit 1: If this switch is "0" (settings 0,1,4,5,8,9,C,D), VMEPROM tries to execute a start-up file after reset. The default + * filename is SY$STRT. If the bit is "1", VMEPROM comes up with the default banner. + * Bit 0: If this switch is set to "0" (settings 0,2,4,6,8,A,C,E), VMEPROM checks the VMEbus for available hardware after reset. + * In addition VMEPROM waits for SYSFAIL to disappear from the VMEbus. The following hardware can be detected: + * - Contiguous memory + * - ASCU-1/2 + * - ISIO-1/2 + * - SIO-1/2 + * - ISCSI-1 + * - WFC-1 + * + * Table 40: RAM Disk Usage + * Bit 1 Bit 0 Upper Switch (SW 2) selected on + * 1 1 RAM DISK AT TOP OF MEMORY (32 Kbytes) 3,7,B,F + * 1 0 RAM DISK AT 0xFC80 0000 (512 Kbytes) 2,6,A,E + * 0 1 RAM DISK AT 0x4070 0000 (512 Kbytes) 1,5,9,D + * 0 0 RAM DISK AT 0x4080 0000 (512 Kbytes) 0,4,8,C + * + * Table 41: Program After Reset + * Bit 3 Bit 2 Lower Switch (SW 1) selected on + * 1 1 VMEPROM C,D,E,F + * 1 0 USER PROGRAM AT 0x4070 0000 8,9,A,B + * 0 1 AUTOBOOT SYSTEM 4,5,6,7 + * 0 0 USER PROGRAM AT 4080.000016 0,1,2,3 + * + * Table 42: Boot an Operating System (if AUTOBOOT is selected) + * Bit 1 Bit 0 Upper Switch (SW 2) selected on + * 1 1 reserved 3,7,B,F + * 1 0 Boot UNIX/PDOS 4.x 2,6,A,E + * 0 1 Boot another operating system 1,5,9,D + * 0 0 Setup for UNIX mailbox driver 0,4,8,C + * + * "To start VMEPROM, the rotary switches must both be set to 'F':" Hmm... + */ +READ8_MEMBER (fccpu30_state::rotary_rd){ + LOG(("%s\n", FUNCNAME)); + return 0xff; // TODO: make this configurable from commandline or artwork +} + +/* + * PI/T #2 Factory settings + * B0-B2 Shared Memory Size - From these lines, the on-board Shared RAM capacity can be read in by software. + * 0 0 0 32 Mb + * 0 0 1 16 Mb + * 0 1 0 8 Mb + * 0 1 1 4 Mb + * 1 x x Reserved + * B3-B7 Board ID(s) - From these lines, the CPU board identification number can be read in by + * 0 1 0 1 0 CPU-30 R4 software. Every CPU board has a unique number. Different versions of + * (fill in more) one CPU board (i.e. different speeds, capacity of memory, or modules) + * contain the same identification number. In the case of the CPU-30 R4, the + * number is ten ("10" decimal or 0A16 hexadecimal "01010" binary). + */ +READ8_MEMBER (fccpu30_state::board_mem_id_rd){ + LOG(("%s\n", FUNCNAME)); + return 0x6A; // CPU-30 R4 with 4Mb of shared RAM. TODO: make this configurable from commandline or artwork +} + +#if 0 +/* Dummy VME access methods until the VME bus device is ready for use */ +READ16_MEMBER (fccpu30_state::vme_a24_r){ + LOG (logerror ("vme_a24_r\n")); + return (UINT16) 0; +} + +WRITE16_MEMBER (fccpu30_state::vme_a24_w){ + LOG (logerror ("vme_a24_w\n")); +} + +READ16_MEMBER (fccpu30_state::vme_a16_r){ + LOG (logerror ("vme_16_r\n")); + return (UINT16) 0; +} + +WRITE16_MEMBER (fccpu30_state::vme_a16_w){ + LOG (logerror ("vme_a16_w\n")); +} +#endif + +/* + * Machine configuration + */ +static MACHINE_CONFIG_START (fccpu30, fccpu30_state) + /* basic machine hardware */ + MCFG_CPU_ADD ("maincpu", M68030, XTAL_16MHz) + MCFG_CPU_PROGRAM_MAP (fccpu30_mem) + MCFG_NVRAM_ADD_0FILL("nvram") + + /* Terminal Port config */ + MCFG_DUSCC68562_ADD("duscc", DUSCC_CLOCK, 0, 0, 0, 0 ) + MCFG_DUSCC_OUT_TXDA_CB(DEVWRITELINE("rs232trm", rs232_port_device, write_txd)) + MCFG_DUSCC_OUT_DTRA_CB(DEVWRITELINE("rs232trm", rs232_port_device, write_dtr)) + MCFG_DUSCC_OUT_RTSA_CB(DEVWRITELINE("rs232trm", rs232_port_device, write_rts)) + + MCFG_RS232_PORT_ADD ("rs232trm", default_rs232_devices, "terminal") + MCFG_RS232_RXD_HANDLER (DEVWRITELINE ("duscc", duscc68562_device, rxa_w)) + MCFG_RS232_CTS_HANDLER (DEVWRITELINE ("duscc", duscc68562_device, ctsa_w)) + +// MCFG_DUSCC68562_ADD("duscc2", DUSCC_CLOCK, 0, 0, 0, 0 ) + + /* PIT Parallel Interface and Timer device, assuming strapped for on board clock */ + MCFG_DEVICE_ADD ("pit1", PIT68230, XTAL_16MHz / 2) + MCFG_PIT68230_PA_INPUT_CB(READ8(fccpu30_state, rotary_rd)) + MCFG_DEVICE_ADD ("pit2", PIT68230, XTAL_16MHz / 2) + MCFG_PIT68230_PB_INPUT_CB(READ8(fccpu30_state, board_mem_id_rd)) +MACHINE_CONFIG_END + +/* ROM definitions */ +ROM_START (fccpu30) +ROM_REGION32_BE(0xfff00000, "maincpu", 0) + +ROM_LOAD16_BYTE("CPU30LO.BIN", 0xff000000, 0x20000, CRC (fefa88ed) SHA1 (71a9ad807c0c2da5c6f6a6dc68c73ad8b52f3ea9)) +ROM_LOAD16_BYTE("CPU30UP.BIN", 0xff000001, 0x20000, CRC (dfed1f68) SHA1 (71478a77d5ab5da0fabcd78e69537919b560e3b8)) +ROM_LOAD("PGA-002.BIN", 0xffe00000, 0x10000, CRC (faa38972) SHA1 (651dfc2f9a865fc6adf49dad90f9e705f2889919)) + +/* + * System ROM information + * + * FGA-002 Bootprom version 3.1 is released May 28, 1990, coprighted by FORCE Computers Gmbh + * + * Bootprom PIT setup sequence + * 0a 00 <- read port A without side effects + * 0b 00 <- read port B without side effects + * 10 00 -> TCR - Timer Control register: Disable timer + * 13 ff -> CPRH - Counter Preload Regsiter High + * 14 ff -> CPRM - Counter Preload Regsiter Mid + * 15 ff -> CPRL - Counter Preload Regsiter Low + * 10 01 -> TCR - Timer Control register: Enable timer + * ------ init ends -------- clock: 4217 + * + * To start VMEPROM, the rotary switches must both be set to 'F' (PI/T #1 port A) + * + * ------ next config -------- clock: 1964222 + * 10 00 -> TCR - Timer Control register: Disable timer + * 17 00 -> CRH - Counter Register High + * 18 00 -> CRM - Counter Register Medium + * 19 00 -> CRL - Counter Register Low + * + * DUSCC #1 channel A setup sequence + * 0f 00 -> REG_CCR - reset Tx Command + * 0f 40 -> REG_CCR - reset Rx Command + * 00 07 -> REG_CMR1 - Async mode + * 01 38 -> REG_CMR2 - Normal polled or interrupt mode, no DMA + * 04 7f -> REG_TPR - Tx 8 bits, CTS and RTS, 1 STOP bit + * 06 1b -> REG_RPR - Rx RTS, 8 bits, no DCD, no parity + * 05 3d -> REG_TTR - Tx BRG 9600 (assuming a 14.7456 crystal) + * 07 2d -> REG_RTR - Rx BRG 9600 (assuming a 14.7456 crystal) + * 0e 27 -> REG_PCR - TRxC = RxCLK 1x, RTxC is input, RTS, GPO2, crystal oscillator connected to X2 + * 0b f1 -> REG_OMR - RTS low, OUT1 = OUT2 = high, RxRdy asserted for each character, + * TxRdy asserted on threshold, Same Tx Residual Character Length as for REG_TPR + * 0f 00 -> REG_CCR - reset Tx Command + * 0f 40 -> REG_CCR - reset Rx Command + * 0f 02 -> REG_CCR - enable Tx Command + * 0f 42 -> REG_CCR - enable Rx Command + *--- end of setup sequence --- + * loop: + * read <- REG_GSR + * until something needs attention + */ +ROM_END + +/* Driver */ +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP (1990, fccpu30, 0, 0, fccpu30, fccpu30, driver_device, 0, "Force Computers Gmbh", "SYS68K/CPU-30", MACHINE_NOT_WORKING | MACHINE_NO_SOUND_HW | MACHINE_TYPE_COMPUTER ) diff --git a/src/mame/drivers/force68k.cpp b/src/mame/drivers/force68k.cpp index a4ba796836e..6a7cc1a172a 100644 --- a/src/mame/drivers/force68k.cpp +++ b/src/mame/drivers/force68k.cpp @@ -470,8 +470,8 @@ MCFG_DEVICE_ADD ("rtc", MM58167, XTAL_32_768kHz) /* PIT Parallel Interface and Timer device, assuming strapped for on board clock */ MCFG_DEVICE_ADD ("pit", PIT68230, XTAL_16MHz / 2) -MCFG_PIT68230_PA_OUTPUT_CALLBACK (DEVWRITE8 ("cent_data_out", output_latch_device, write)) -MCFG_PIT68230_H2_CALLBACK (DEVWRITELINE ("centronics", centronics_device, write_strobe)) +MCFG_PIT68230_PA_OUTPUT_CB (DEVWRITE8 ("cent_data_out", output_latch_device, write)) +MCFG_PIT68230_H2_CB (DEVWRITELINE ("centronics", centronics_device, write_strobe)) // centronics MCFG_CENTRONICS_ADD ("centronics", centronics_devices, "printer") diff --git a/src/mame/mame.lst b/src/mame/mame.lst index ab30da025a6..f6c35358e1d 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -12069,6 +12069,9 @@ fb01 // 1986 FB-01 @source:fc100.cpp fc100 // +@source:fccpu30.cpp +fccpu30 // + @source:fcscsi.cpp fcscsi1 //