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