Merge pull request #1373 from JoakimLarsson/fccpu30_10

Added interrupt support in DUSCC device, Force CPU30 board driver and…
This commit is contained in:
R. Belmont 2016-09-08 16:30:03 -04:00 committed by GitHub
commit aff04e4c60
6 changed files with 1059 additions and 212 deletions

View File

@ -27,8 +27,11 @@
#define VERBOSE 0
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define LOGR(x) LOG(x)
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
#define LOG(x)
#define LOGR(x)
#define LOGINT(x) LOGPRINT(x)
#define LOGSETUP(x) LOGPRINT(x)
#if VERBOSE == 2
#define logerror printf
#endif
@ -231,42 +234,42 @@ static INT32 ow_ofs = 0;
void pit68230_device::wr_pitreg_pgcr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_pgcr = data;
}
void pit68230_device::wr_pitreg_psrr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, 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));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, 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));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, 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));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_pcddr = data;
}
void pit68230_device::wr_pitreg_pivr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": Not implemented yet\n", FUNCNAME, data, m_owner->tag()));
LOG(("%s(%02x) \"%s\": Not implemented yet\n", FUNCNAME, data, tag()));
}
void pit68230_device::wr_pitreg_pacr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_pacr = data;
// callbacks
/*PACR in Mode 0
@ -289,13 +292,13 @@ void pit68230_device::wr_pitreg_pacr(UINT8 data)
void pit68230_device::wr_pitreg_pbcr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, 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));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_padr |= (data & m_paddr);
// callbacks
m_pa_out_cb ((offs_t)0, m_padr);
@ -303,7 +306,7 @@ void pit68230_device::wr_pitreg_padr(UINT8 data)
void pit68230_device::wr_pitreg_pbdr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_pbdr |= (data & m_pbddr);
// callbacks
m_pb_out_cb ((offs_t)0, m_pbdr & m_pbddr);
@ -311,7 +314,7 @@ void pit68230_device::wr_pitreg_pbdr(UINT8 data)
void pit68230_device::wr_pitreg_pcdr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_pcdr |= (data & m_pcddr);
// callbacks
m_pc_out_cb ((offs_t)0, m_pcdr);
@ -319,7 +322,7 @@ void pit68230_device::wr_pitreg_pcdr(UINT8 data)
void pit68230_device::wr_pitreg_psr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_psr = data;
}
@ -395,7 +398,7 @@ void pit68230_device::wr_pitreg_tcr(UINT8 data)
int pen = 0;
int sqr = 0;
LOG(("%s(%02x) %s\n", FUNCNAME, data, m_owner->tag()));
LOG(("%s(%02x) %s\n", FUNCNAME, data, tag()));
m_tcr = data;
switch (m_tcr & REG_TCR_TOUT_TIACK_MASK)
{
@ -440,40 +443,41 @@ void pit68230_device::wr_pitreg_tcr(UINT8 data)
void pit68230_device::wr_pitreg_tivr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": \n", FUNCNAME, data, m_owner->tag()));
LOG(("%s(%02x) \"%s\": \n", FUNCNAME, data, tag()));
m_tivr = data;
}
void pit68230_device::wr_pitreg_cprh(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_cpr &= ~0xff0000;
m_cpr |= ((data << 16) & 0xff0000);
}
void pit68230_device::wr_pitreg_cprm(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_cpr &= ~0x00ff00;
m_cpr |= ((data << 8) & 0x00ff00);
}
void pit68230_device::wr_pitreg_cprl(UINT8 data)
{
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, m_owner->tag(), FUNCNAME, data));
LOG(("%s(%02x) \"%s\": %s - %02x\n", FUNCNAME, data, tag(), FUNCNAME, data));
m_cpr &= ~0x0000ff;
m_cpr |= ((data << 0) & 0x0000ff);
}
void pit68230_device::wr_pitreg_tsr(UINT8 data)
{
LOG(("%s(%02x) \"%s\": \n", FUNCNAME, data, m_owner->tag()));
LOG(("%s(%02x) \"%s\": \n", FUNCNAME, data, tag()));
m_tsr = data;
}
WRITE8_MEMBER (pit68230_device::write)
{
LOG(("%s %s \n",tag(), FUNCNAME));
LOG(("\"%s\" %s: Register write '%02x' -> [%02x]\n", tag(), FUNCNAME, data, offset ));
LOGSETUP((" * %s Reg %02x <- %02x \n", tag(), offset, data));
switch (offset) {
case PIT_68230_PGCR: wr_pitreg_pgcr(data); break;
case PIT_68230_PSRR: wr_pitreg_psrr(data); break;

View File

@ -31,12 +31,16 @@
* external hardware. It is expressly forbidden to change register bits, except those defined for the user.
*
*/
#include "fga002.h"
#define VERBOSE 0
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
#define LOG(x)
#define LOGR(x)
#define LOGSETUP(x)
#define LOGINT(x) LOGPRINT(x)
#define LOGVEC(x)
#define LOGLVL(x)
#define LOGIACK(x) LOGPRINT(x)
#if VERBOSE == 2
#define logerror printf
#endif
@ -49,6 +53,8 @@
#define LLFORMAT "%lld"
#endif
#include "fga002.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
@ -65,22 +71,48 @@ const device_type FGA002 = &device_creator<fga002_device>;
fga002_device::fga002_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)
, m_out_int_cb(*this)
, m_liack4_cb(*this)
, m_liack5_cb(*this)
, m_liack6_cb(*this)
, m_liack7_cb(*this)
, m_irq_level((UINT8)0)
{
for (auto & elem : m_int_state)
elem = 0;
}
fga002_device::fga002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, FGA002, "FGA-002", tag, owner, clock, "fga002", __FILE__)
, m_out_int_cb(*this)
, m_liack4_cb(*this)
, m_liack5_cb(*this)
, m_liack6_cb(*this)
, m_liack7_cb(*this)
, m_irq_level((UINT8)0)
{
for (auto & elem : m_int_state)
elem = 0;
}
void fga002_device::device_start()
{
LOG(("%s\n", FUNCNAME));
// resolve callbacks
m_out_int_cb.resolve_safe();
m_liack4_cb.resolve_safe(0);
m_liack5_cb.resolve_safe(0);
m_liack6_cb.resolve_safe(0);
m_liack7_cb.resolve_safe(0);
// Timers
fga_timer = timer_alloc(TIMER_ID_FGA);
save_pointer (NAME (m_fga002), sizeof(m_fga002));
// Interrupts
save_item(NAME(m_int_state));
}
void fga002_device::device_reset()
@ -103,6 +135,14 @@ void fga002_device::device_reset()
m_fga002[FGA_ISSYSFAIL] = 0x80;
m_fga002[FGA_ISFMB0MES] = 0x80;
m_fga002[FGA_ISFMB1MES] = 0x80;
m_fga002[FGA_ISLOCAL0] = 0x80;
m_fga002[FGA_ISLOCAL1] = 0x80;
m_fga002[FGA_ISLOCAL2] = 0x80;
m_fga002[FGA_ISLOCAL3] = 0x80;
m_fga002[FGA_ISLOCAL4] = 0x80;
m_fga002[FGA_ISLOCAL5] = 0x80;
m_fga002[FGA_ISLOCAL6] = 0x80;
m_fga002[FGA_ISLOCAL7] = 0x80;
}
//-------------------------------------------------
@ -134,7 +174,163 @@ void fga002_device::device_timer (emu_timer &timer, device_timer_id id, INT32 pa
}
}
/* The FGA002 Interrupts
The FGA-002 Gate Array provides high end support for interrupt functionality. It manages interrupt sources
within the gate array as well as external sources connected to the gate array. The FGA-002 Gate Array is an
efficient interface for various interrupt sources to the local CPU, and supports up to 18 external interrupters.
Interrupt inputs provided for external interrupt sources (exclusive of the VMEbus interrupt inputs) offer
maximum flexibility as they may be configured to be level/edge sensitive or low/high active. The control of
these features is performed by two bits contained in the extended interrupt control registers. The Interrupt
Auto Clear bit in the extended interrupt control register determines, whether the interrupt of an edge sensitive
input is cleared automatically during the interrupt acknowledge cycle or has to be cleared by the interrupt
service routine. Each interrupt source is bound to an individual interrupt channel which has its own assigned
vector number. The interrupt channels are configured by the Interrupt Control Registers where a 3 bit code for
the level and a bit for enable/disable control are stored. Each interrupt channel may be programmed to interrupt
the processor at any level.
The vector table of the gate array is a group of 64 vectors. The two most significant bits of the 8 bit vector
are programmable via register bits. The rest of the bits are assigned by gate array hardware. Not all of the
64 vectors are used in the present gate array, and those not used are reserved for future extensions.
The following groups of interrupt sources are supported:
1. Internal Interrupt Sources
- DMA CONTROLLER
- TIMER
- FORCE MESSAGE BROADCAST -FMB-
- PARITY ERROR
- 8 MAILBOXES
2. External Interrupt Sources
Onboard interrupts:
- LOCAL 0-7 inputs
- ABORT Key input
- ACFAIL input
- SYSFAIL input
VMEbus interrupts:
- 7 VMEbus interrupt inputs
*/
// TODO: Add more intrrupts sources in priority order, 18 in total.
const fga_irq_t fga002_device::m_irq_sources[] = {
{INT_LOCAL0, FGA_ISLOCAL0, FGA_ICRLOCAL0 },
{INT_LOCAL1, FGA_ISLOCAL1, FGA_ICRLOCAL1 },
{INT_LOCAL2, FGA_ISLOCAL2, FGA_ICRLOCAL2 },
{INT_LOCAL3, FGA_ISLOCAL3, FGA_ICRLOCAL3 },
{INT_LOCAL4, FGA_ISLOCAL4, FGA_ICRLOCAL4 },
{INT_LOCAL5, FGA_ISLOCAL5, FGA_ICRLOCAL5 },
{INT_LOCAL6, FGA_ISLOCAL6, FGA_ICRLOCAL6 },
{INT_LOCAL7, FGA_ISLOCAL7, FGA_ICRLOCAL7 }
};
void fga002_device::trigger_interrupt(UINT8 data)
{
UINT8 icr = 0;
LOGINT(("%s(%02x)\n", FUNCNAME, data));
/* The Interrupt Control Register (ICR*) bit, must be set for the correspondning channel */
// TODO: Support programmable assert level for interrupt source
switch(data)
{
case INT_LOCAL0: icr = m_fga002[FGA_ICRLOCAL0]; m_fga002[FGA_ISLOCAL0] = 0x00; break;
case INT_LOCAL1: icr = m_fga002[FGA_ICRLOCAL1]; m_fga002[FGA_ISLOCAL1] = 0x00; break;
case INT_LOCAL2: icr = m_fga002[FGA_ICRLOCAL2]; m_fga002[FGA_ISLOCAL2] = 0x00; break;
case INT_LOCAL3: icr = m_fga002[FGA_ICRLOCAL3]; m_fga002[FGA_ISLOCAL3] = 0x00; break;
case INT_LOCAL4: icr = m_fga002[FGA_ICRLOCAL4]; m_fga002[FGA_ISLOCAL4] = 0x00; break;
case INT_LOCAL5: icr = m_fga002[FGA_ICRLOCAL5]; m_fga002[FGA_ISLOCAL5] = 0x00; break;
case INT_LOCAL6: icr = m_fga002[FGA_ICRLOCAL6]; m_fga002[FGA_ISLOCAL6] = 0x00; break;
case INT_LOCAL7: icr = m_fga002[FGA_ICRLOCAL7]; m_fga002[FGA_ISLOCAL7] = 0x00; break;
default: LOGINT((" - interrupt source %d - not supported", data)); return;
}
if ((icr & REG_ICR_ENABLE) == 0 || (icr & REG_ICR_LVL_MSK) == 0)
{
LOGINT((" - The Interrupt Control Register bit for channel %02x is not set or level is 0, blocking attempt to interrupt\n", data));
return;
}
m_irq_level = icr & REG_ICR_LVL_MSK;
LOGINT((" - Interrupt Level %d, caused by ICR %02x with vector %02x\n", m_irq_level, icr, data ));
// trigger intrrupt to CPU through board driver callback.
m_out_int_cb(ASSERT_LINE);
}
IRQ_CALLBACK_MEMBER(fga002_device::iack)
{
int vec = M68K_INT_ACK_AUTOVECTOR;
int vec_found = 0;
int level;
LOGIACK(("%s %s()\n", tag(), FUNCNAME));
for (level = 7; level > 0; level--)
{
LOGLVL(("\n LEVEL %d\n", level));
// Find first interrupt on this level to acknowledge
LOGLVL(("Vec Status[val] Control[val]\n"));
for (auto & elem : m_irq_sources)
{
LOGLVL((" %02x %02x[%02x] %02x[%02x]\n",
elem.vector,
elem.status, m_fga002[elem.status],
elem.control, m_fga002[elem.control]));
// Right level?
LOGLVL(("Level %02x == ICR %02x is %s\n", level, m_fga002[elem.control] & REG_ICR_LVL_MSK, ((m_fga002[elem.control] & REG_ICR_LVL_MSK) == level) ? "true!" : "false.."));
if ((m_fga002[elem.control] & REG_ICR_LVL_MSK) == level)
{
// Pending interrupt?
LOGLVL(("ISx %02x interrupt is %s\n", m_fga002[elem.status], (m_fga002[elem.status] & REG_ISLOCAL_IRQ) ? "cleared though.." : "pending!"));
if ((m_fga002[elem.status] & REG_ISLOCAL_IRQ) == 0)
{
if (vec_found == 0)
{
vec = elem.vector; // Assume internal vector
LOGVEC((" - org vec:%02x ", vec));
switch (vec)
{
// Assuming that the attached device is returning -1 (INT_ACK_AUTOVECTOR) if no vector is provided, then we keep internal vector
// TODO: Add device specific parameter that maps devices no-vector response to INT_ACK_AUTOVECTOR (and preferably INT_ACK_NOVECTOR)
case INT_LOCAL4: if (( (m_fga002[FGA_LOCALIACK] & REG_LIACK_LOCAL4_MSK) >> 0) != REG_LIACK_INT_IACK ) vec = m_liack4_cb(); break;
case INT_LOCAL5: if (( (m_fga002[FGA_LOCALIACK] & REG_LIACK_LOCAL5_MSK) >> 2) != REG_LIACK_INT_IACK ) vec = m_liack5_cb(); break;
case INT_LOCAL6: if (( (m_fga002[FGA_LOCALIACK] & REG_LIACK_LOCAL6_MSK) >> 4) != REG_LIACK_INT_IACK ) vec = m_liack6_cb(); break;
case INT_LOCAL7: if (( (m_fga002[FGA_LOCALIACK] & REG_LIACK_LOCAL7_MSK) >> 6) != REG_LIACK_INT_IACK ) vec = m_liack7_cb(); break;
// All other devices uses the vector provided by the FGA.
default: break; /* Since we need the vector for the switch statement the default job is already done */
}
LOGVEC(("dev:%02x ", vec));
if (vec == INT_ACK_AUTOVECTOR) vec = INT_EMPTY;
LOGVEC(("avec:%02x ", vec));
// Add vector page bits and return vector
vec = (vec & 0x3f) | ((m_fga002[FGA_CTL3] & REG_CTL3_VECTORBITS7_6) << 4);
LOGVEC(("pvec:%02x\n", vec));
LOGVEC((" - Interrupt Acknowledge Vector %02x\n", vec));
/* TODO:
- Support auto clear of interrupt source and level triggered
*/
vec_found = 1;
}
else{
m_irq_level = level;
LOGIACK((" - Interrupt Acknowledge Vector %02x, next interrupt has level %02x\n", vec, m_irq_level));
m_out_int_cb(CLEAR_LINE);
return vec;
}
}
}
}
}
LOGIACK((" - Interrupt Acknowledge Vector %02x, next interrupt is off %02x\n", vec, m_irq_level));
m_out_int_cb(CLEAR_LINE);
return vec;
}
int fga002_device::get_irq_level()
{
LOGINT(("%s %s() - %02x\n", tag(), FUNCNAME, m_irq_level));
return m_irq_level;
}
/* The FGA002 Timer
@ -277,13 +473,13 @@ UINT8 fga002_device::do_fga002reg_tim0count_r()
*/
void fga002_device::do_fga002reg_icrtim0_w(UINT8 data)
{
LOG(("%s(%02x)\n", FUNCNAME, data));
LOGINT(("%s(%02x)\n", FUNCNAME, data));
m_fga002[FGA_ICRTIM0] = data;
}
UINT8 fga002_device::do_fga002reg_icrtim0_r()
{
LOG(("%s() %02x\n", FUNCNAME, m_fga002[FGA_ICRTIM0]));
LOGINT(("%s() %02x\n", FUNCNAME, m_fga002[FGA_ICRTIM0]));
return m_fga002[FGA_ICRTIM0];
}
@ -295,19 +491,129 @@ UINT8 fga002_device::do_fga002reg_icrtim0_r()
*/
void fga002_device::do_fga002reg_istim0_w(UINT8 data)
{
LOG(("%s(%02x)\n", FUNCNAME, data));
LOGINT(("%s(%02x)\n", FUNCNAME, data));
m_fga002[FGA_ISTIM0] &= ~REG_ISTIM0_TIM_INT; // Clear timer interrupt status
}
UINT8 fga002_device::do_fga002reg_istim0_r()
{
LOG(("%s() %02x\n", FUNCNAME, m_fga002[FGA_ISTIM0]));
LOGINT(("%s() %02x\n", FUNCNAME, m_fga002[FGA_ISTIM0]));
return m_fga002[FGA_ISTIM0];
}
/*
* FGA-002 interrupt support
*/
void fga002_device::do_fga002reg_localiack_w(UINT8 data)
{
m_fga002[FGA_LOCALIACK] = data;
#if VERBOSE
const char *liack[] = {"internal", "no", "external 1us", "external 500ns"};
LOGINT(("%s(%02x)\n", FUNCNAME, data));
LOGINT(("- LOCAL7: %s vector\n", liack[(data >> 6) & 0x03]));
LOGINT(("- LOCAL6: %s vector\n", liack[(data >> 4) & 0x03]));
LOGINT(("- LOCAL5: %s vector\n", liack[(data >> 2) & 0x03]));
LOGINT(("- LOCAL4: %s vector\n", liack[(data >> 0) & 0x03]));
#endif
}
UINT8 fga002_device::do_fga002reg_localiack_r()
{
UINT8 ret = m_fga002[FGA_LOCALIACK];
LOGINT(("%s() <- %02x\n", FUNCNAME, ret));
return ret;
}
UINT8 fga002_device::do_fga002reg_ctl3_r()
{
UINT8 ret = m_fga002[FGA_CTL3];
LOGINT(("%s() <- %02x\n", FUNCNAME, ret));
return ret;
}
void fga002_device::do_fga002reg_ctl3_w(UINT8 data)
{
m_fga002[FGA_CTL3] = data;
LOGINT(("%s(%02x)\n", FUNCNAME, data));
}
// Local Interrupt control register methods
UINT8 fga002_device::do_fga002reg_icrlocal0_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL0]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal1_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL1]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal2_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL2]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal3_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL3]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal4_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL4]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal5_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL5]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal6_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL6]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_icrlocal7_r(){ UINT8 ret = m_fga002[FGA_ICRLOCAL7]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
void fga002_device::do_fga002reg_icrlocal0_w(UINT8 data){ m_fga002[FGA_ICRLOCAL0] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal1_w(UINT8 data){ m_fga002[FGA_ICRLOCAL1] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal2_w(UINT8 data){ m_fga002[FGA_ICRLOCAL2] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal3_w(UINT8 data){ m_fga002[FGA_ICRLOCAL3] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal4_w(UINT8 data){ m_fga002[FGA_ICRLOCAL4] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal5_w(UINT8 data){ m_fga002[FGA_ICRLOCAL5] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal6_w(UINT8 data){ m_fga002[FGA_ICRLOCAL6] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
void fga002_device::do_fga002reg_icrlocal7_w(UINT8 data){ m_fga002[FGA_ICRLOCAL7] = data; LOGINT(("%s(%02x)\n", FUNCNAME, data)); }
// Local Interrupt Status Register methods
UINT8 fga002_device::do_fga002reg_islocal0_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL0]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal1_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL1]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal2_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL2]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal3_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL3]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal4_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL4]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal5_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL5]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal6_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL6]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
UINT8 fga002_device::do_fga002reg_islocal7_r(){ UINT8 ret = m_fga002[FGA_ISLOCAL7]; LOGINT(("%s() <- %02x\n", FUNCNAME, ret)); return ret; }
void fga002_device::islocal_w(int status, int vector, int control, int data)
{
m_fga002[status] = m_fga002[control] & REG_ICR_EDGE ? 0x80 : 0x00;
LOGINT(("%s(%02x)\n", FUNCNAME, m_fga002[status]));
}
// TODO: support level triggered interrupts, only edge triggered interrupts are supported atm
void fga002_device::do_fga002reg_islocal0_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL0, INT_LOCAL0, FGA_ICRLOCAL0, data ); }
void fga002_device::do_fga002reg_islocal1_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL1, INT_LOCAL1, FGA_ICRLOCAL1, data ); }
void fga002_device::do_fga002reg_islocal2_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL2, INT_LOCAL2, FGA_ICRLOCAL2, data ); }
void fga002_device::do_fga002reg_islocal3_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL3, INT_LOCAL3, FGA_ICRLOCAL3, data ); }
void fga002_device::do_fga002reg_islocal4_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL4, INT_LOCAL4, FGA_ICRLOCAL4, data ); m_liack4_cb(); } /* terminate device IRQ */
void fga002_device::do_fga002reg_islocal5_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL5, INT_LOCAL5, FGA_ICRLOCAL5, data ); m_liack5_cb(); }
void fga002_device::do_fga002reg_islocal6_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL6, INT_LOCAL6, FGA_ICRLOCAL6, data ); m_liack6_cb(); }
void fga002_device::do_fga002reg_islocal7_w(UINT8 data){ LOGINT(("%s\n", FUNCNAME)); islocal_w( FGA_ISLOCAL6, INT_LOCAL7, FGA_ICRLOCAL7, data ); m_liack7_cb(); }
// Local IRQ callbacks
// TODO: support level triggered interrupts, ICR bit 6, only edge triggered interrupts are supported atm
// TODO: support programmable assertion levels ICR bit 5, a call to this function assumes assertion atm
void fga002_device::lirq_w(int status, int vector, int control, int state)
{
LOGINT((" - %s\n", state == ASSERT_LINE ? "Asserted" : "Cleared"));
if (state == ASSERT_LINE)
{
m_fga002[status] &= ~REG_ISLOCAL_IRQ;
trigger_interrupt(vector);
}
else
{
m_fga002[status] |= REG_ISLOCAL_IRQ;
}
}
WRITE_LINE_MEMBER (fga002_device::lirq0_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL0, INT_LOCAL0, FGA_ICRLOCAL0, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq1_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL1, INT_LOCAL1, FGA_ICRLOCAL1, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq2_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL2, INT_LOCAL2, FGA_ICRLOCAL2, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq3_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL3, INT_LOCAL3, FGA_ICRLOCAL3, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq4_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL4, INT_LOCAL4, FGA_ICRLOCAL4, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq5_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL5, INT_LOCAL5, FGA_ICRLOCAL5, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq6_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL6, INT_LOCAL6, FGA_ICRLOCAL6, state ); }
WRITE_LINE_MEMBER (fga002_device::lirq7_w) { LOGINT(("%s\n", FUNCNAME)); lirq_w( FGA_ISLOCAL7, INT_LOCAL7, FGA_ICRLOCAL7, state ); }
WRITE8_MEMBER (fga002_device::write){
LOG(("%s[%04x] <- %02x - ", FUNCNAME, offset, data));
LOGSETUP((" * %s Reg %04x <- %02x\n", tag(), offset, data));
switch(offset)
{
case FGA_SPECIALENA : LOG(("FGA_SPECIALENA - not implemented\n")); m_fga002[FGA_SPECIALENA] = data; break;
@ -340,7 +646,7 @@ WRITE8_MEMBER (fga002_device::write){
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_CTL3 : do_fga002reg_ctl3_w(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;
@ -354,14 +660,14 @@ WRITE8_MEMBER (fga002_device::write){
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_ICRLOCAL0 : do_fga002reg_icrlocal0_w(data); break;
case FGA_ICRLOCAL1 : do_fga002reg_icrlocal1_w(data); break;
case FGA_ICRLOCAL2 : do_fga002reg_icrlocal2_w(data); break;
case FGA_ICRLOCAL3 : do_fga002reg_icrlocal3_w(data); break;
case FGA_ICRLOCAL4 : do_fga002reg_icrlocal4_w(data); break;
case FGA_ICRLOCAL5 : do_fga002reg_icrlocal5_w(data); break;
case FGA_ICRLOCAL6 : do_fga002reg_icrlocal6_w(data); break;
case FGA_ICRLOCAL7 : do_fga002reg_icrlocal7_w(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;
@ -379,7 +685,7 @@ WRITE8_MEMBER (fga002_device::write){
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_LOCALIACK : do_fga002reg_localiack_w(data);
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;
@ -390,7 +696,15 @@ WRITE8_MEMBER (fga002_device::write){
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 : do_fga002reg_istim0_w(data); break;
case FGA_ISTIM0 : do_fga002reg_istim0_w(data); break;
case FGA_ISLOCAL0 : do_fga002reg_islocal0_w(data); break;
case FGA_ISLOCAL1 : do_fga002reg_islocal1_w(data); break;
case FGA_ISLOCAL2 : do_fga002reg_islocal2_w(data); break;
case FGA_ISLOCAL3 : do_fga002reg_islocal3_w(data); break;
case FGA_ISLOCAL4 : do_fga002reg_islocal4_w(data); break;
case FGA_ISLOCAL5 : do_fga002reg_islocal5_w(data); break;
case FGA_ISLOCAL6 : do_fga002reg_islocal6_w(data); break;
case FGA_ISLOCAL7 : do_fga002reg_islocal7_w(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;
@ -443,7 +757,7 @@ READ8_MEMBER (fga002_device::read){
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_CTL3 : ret = do_fga002reg_ctl3_r(); 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;
@ -457,14 +771,14 @@ READ8_MEMBER (fga002_device::read){
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_ICRLOCAL0 : ret = do_fga002reg_icrlocal0_r(); break;
case FGA_ICRLOCAL1 : ret = do_fga002reg_icrlocal1_r(); break;
case FGA_ICRLOCAL2 : ret = do_fga002reg_icrlocal2_r(); break;
case FGA_ICRLOCAL3 : ret = do_fga002reg_icrlocal3_r(); break;
case FGA_ICRLOCAL4 : ret = do_fga002reg_icrlocal4_r(); break;
case FGA_ICRLOCAL5 : ret = do_fga002reg_icrlocal5_r(); break;
case FGA_ICRLOCAL6 : ret = do_fga002reg_icrlocal6_r(); break;
case FGA_ICRLOCAL7 : ret = do_fga002reg_icrlocal7_r(); 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;
@ -482,7 +796,7 @@ READ8_MEMBER (fga002_device::read){
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_LOCALIACK : ret = do_fga002reg_localiack_r(); 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;
@ -493,7 +807,15 @@ READ8_MEMBER (fga002_device::read){
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 = do_fga002reg_istim0_r(); break;
case FGA_ISTIM0 : ret = do_fga002reg_istim0_r(); break;
case FGA_ISLOCAL0 : ret = do_fga002reg_islocal0_r(); break;
case FGA_ISLOCAL1 : ret = do_fga002reg_islocal1_r(); break;
case FGA_ISLOCAL2 : ret = do_fga002reg_islocal2_r(); break;
case FGA_ISLOCAL3 : ret = do_fga002reg_islocal3_r(); break;
case FGA_ISLOCAL4 : ret = do_fga002reg_islocal4_r(); break;
case FGA_ISLOCAL5 : ret = do_fga002reg_islocal5_r(); break;
case FGA_ISLOCAL6 : ret = do_fga002reg_islocal6_r(); break;
case FGA_ISLOCAL7 : ret = do_fga002reg_islocal7_r(); 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;

View File

@ -4,8 +4,36 @@
#define __FGA002_H__
#include "emu.h"
#include "cpu/m68000/m68000.h" // The FGA002 is designed for the 68K interrupt PL0-PL2 signalling, however used on Sparc and x86 boards too
#define MCFG_FGA002_ADD(_tag, _clock) MCFG_DEVICE_ADD(_tag, FGA002, _clock)
#ifndef VERBOSE
#define LOG(x)
#endif
#define MCFG_FGA002_ADD(_tag, _clock) MCFG_DEVICE_ADD(_tag, FGA002, _clock)
// LOCAL IRQ callbacks
#define MCFG_FGA002_OUT_INT_CB(_devcb) \
devcb = &fga002_device::set_out_int_callback(*device, DEVCB_##_devcb);
#define MCFG_FGA002_OUT_LIACK4_CB(_devcb) \
devcb = &fga002_device::set_liack4_callback(*device, DEVCB_##_devcb);
#define MCFG_FGA002_OUT_LIACK5_CB(_devcb) \
devcb = &fga002_device::set_liack5_callback(*device, DEVCB_##_devcb);
#define MCFG_FGA002_OUT_LIACK6_CB(_devcb) \
devcb = &fga002_device::set_liack6_callback(*device, DEVCB_##_devcb);
#define MCFG_FGA002_OUT_LIACK7_CB(_devcb) \
devcb = &fga002_device::set_liack7_callback(*device, DEVCB_##_devcb);
// type for array of mapping of FGA registers that assembles an IRQ source
typedef struct {
int vector;
int status;
int control;
} fga_irq_t;
//**************************************************************************
// TYPE DEFINITIONS
@ -14,6 +42,7 @@
// ======================> fga002_device
class fga002_device : public device_t
// ,public device_z80daisy_interface
{
public:
// construction/destruction
@ -22,15 +51,57 @@ class fga002_device : public device_t
DECLARE_WRITE8_MEMBER (write);
DECLARE_READ8_MEMBER (read);
protected:
void lirq_w(int status, int vector, int control, int state);
DECLARE_WRITE_LINE_MEMBER( lirq0_w );
DECLARE_WRITE_LINE_MEMBER( lirq1_w );
DECLARE_WRITE_LINE_MEMBER( lirq2_w );
DECLARE_WRITE_LINE_MEMBER( lirq3_w );
DECLARE_WRITE_LINE_MEMBER( lirq4_w );
DECLARE_WRITE_LINE_MEMBER( lirq5_w );
DECLARE_WRITE_LINE_MEMBER( lirq6_w );
DECLARE_WRITE_LINE_MEMBER( lirq7_w );
IRQ_CALLBACK_MEMBER(iack);
int acknowledge();
int get_irq_level();
template<class _Object> static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast<fga002_device &>(device).m_out_int_cb.set_callback(object); }
template<class _Object> static devcb_base &set_liack4_callback(device_t &device, _Object object) { return downcast<fga002_device &>(device).m_liack4_cb.set_callback(object); }
template<class _Object> static devcb_base &set_liack5_callback(device_t &device, _Object object) { return downcast<fga002_device &>(device).m_liack5_cb.set_callback(object); }
template<class _Object> static devcb_base &set_liack6_callback(device_t &device, _Object object) { return downcast<fga002_device &>(device).m_liack6_cb.set_callback(object); }
template<class _Object> static devcb_base &set_liack7_callback(device_t &device, _Object object) { return downcast<fga002_device &>(device).m_liack7_cb.set_callback(object); }
// interrupt sources in prio order if on same interrupt level. TODO: Add all sources
const static fga_irq_t m_irq_sources[];
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
#if 0
// device_z80daisy_interface overrides
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
#endif
virtual void device_timer (emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
devcb_write_line m_out_int_cb;
devcb_read8 m_liack4_cb;
devcb_read8 m_liack5_cb;
devcb_read8 m_liack6_cb;
devcb_read8 m_liack7_cb;
int m_int_state[0x08]; // interrupt state
private:
UINT8 m_tim0count;
UINT8 m_fga002[0x500];
UINT8 do_fga002reg_ctl3_r();
void do_fga002reg_ctl3_w(UINT8 data);
/* Timer functions */
UINT8 do_fga002reg_tim0preload_r();
void do_fga002reg_tim0preload_w(UINT8 data);
@ -74,6 +145,90 @@ class fga002_device : public device_t
REG_ISTIM0_TIM_INT = 0x80,
};
/* Interrupt support */
UINT8 m_irq_level;
UINT8 do_fga002reg_localiack_r();
void do_fga002reg_localiack_w(UINT8 data);
UINT8 do_fga002reg_islocal0_r();
UINT8 do_fga002reg_islocal1_r();
UINT8 do_fga002reg_islocal2_r();
UINT8 do_fga002reg_islocal3_r();
UINT8 do_fga002reg_islocal4_r();
UINT8 do_fga002reg_islocal5_r();
UINT8 do_fga002reg_islocal6_r();
UINT8 do_fga002reg_islocal7_r();
void islocal_w(int status, int vector, int control, int data);
void do_fga002reg_islocal0_w(UINT8 data);
void do_fga002reg_islocal1_w(UINT8 data);
void do_fga002reg_islocal2_w(UINT8 data);
void do_fga002reg_islocal3_w(UINT8 data);
void do_fga002reg_islocal4_w(UINT8 data);
void do_fga002reg_islocal5_w(UINT8 data);
void do_fga002reg_islocal6_w(UINT8 data);
void do_fga002reg_islocal7_w(UINT8 data);
UINT8 do_fga002reg_icrlocal0_r();
UINT8 do_fga002reg_icrlocal1_r();
UINT8 do_fga002reg_icrlocal2_r();
UINT8 do_fga002reg_icrlocal3_r();
UINT8 do_fga002reg_icrlocal4_r();
UINT8 do_fga002reg_icrlocal5_r();
UINT8 do_fga002reg_icrlocal6_r();
UINT8 do_fga002reg_icrlocal7_r();
void do_fga002reg_icrlocal0_w(UINT8 data);
void do_fga002reg_icrlocal1_w(UINT8 data);
void do_fga002reg_icrlocal2_w(UINT8 data);
void do_fga002reg_icrlocal3_w(UINT8 data);
void do_fga002reg_icrlocal4_w(UINT8 data);
void do_fga002reg_icrlocal5_w(UINT8 data);
void do_fga002reg_icrlocal6_w(UINT8 data);
void do_fga002reg_icrlocal7_w(UINT8 data);
void trigger_interrupt(UINT8 data);
void check_interrupts();
enum {
REG_ISLOCAL_IRQ = 0x80
};
enum {
REG_CTL3_VECTORBITS7_6 = 0x0c
};
enum{
REG_LIACK_LOCAL4_MSK = 0x03,
REG_LIACK_LOCAL5_MSK = 0x0c, // >> 2 to use patterns below
REG_LIACK_LOCAL6_MSK = 0x30, // >> 4 to use patterns below
REG_LIACK_LOCAL7_MSK = 0xc0, // >> 6 to use patterns below
REG_LIACK_INT_IACK = 0x00, // Assumes bits to be right adjusted
REG_LIACK_EXT_IACK1 = 0x01,
REG_LIACK_EXT_IACK2 = 0x02,
REG_LIACK_EXT_IACK3 = 0x03,
};
enum{
INT_LOCAL0 = 0x30,
INT_LOCAL1 = 0x31,
INT_LOCAL2 = 0x32,
INT_LOCAL3 = 0x33,
INT_LOCAL4 = 0x34,
INT_LOCAL5 = 0x35,
INT_LOCAL6 = 0x36,
INT_LOCAL7 = 0x37,
INT_EMPTY = 0x3F,
INT_ACK_AUTOVECTOR = -1,
};
enum{
REG_ICR_LVL_MSK = 0x07,
REG_ICR_ENABLE = 0x08,
REG_ICR_AUTOCLR = 0x10,
REG_ICR_ACTIVITY = 0x20,
REG_ICR_EDGE = 0x40,
};
/* Register offsets */
enum {
FGA_ICRMBOX0 = 0x0000,
@ -145,33 +300,40 @@ class fga002_device : public device_t
FGA_FMBAREA = 0x033c,
FGA_AUXSRCSTART = 0x0340,
FGA_AUXDSTSTART = 0x0344,
FGA_AUXSRCTERM = 0x0348,
FGA_AUXDSTTERM = 0x034c,
FGA_CTL13 = 0x0350,
FGA_CTL14 = 0x0354,
FGA_CTL15 = 0x0358,
FGA_CTL16 = 0x035c,
FGA_SPECIALENA = 0x0424,
FGA_ISTIM0 = 0x04a0,
FGA_ISDMANORM = 0x04b0,
FGA_ISDMAERR = 0x04b4,
FGA_ISFMB0REF = 0x04b8,
FGA_ISFMB1REF = 0x04bc,
FGA_ISPARITY = 0x04c0,
FGA_DMARUNCTL = 0x04c4,
FGA_ISABORT = 0x04c8,
FGA_ISACFAIL = 0x04cc,
FGA_ISFMB0MES = 0x04e0,
FGA_ISFMB1MES = 0x04e4,
FGA_ISSYSFAIL = 0x04d0,
FGA_ABORTPIN = 0x04d4,
FGA_RSVMECALL = 0x04f0,
FGA_RSKEYRES = 0x04f4,
FGA_RSCPUCALL = 0x04f8,
FGA_RSLOCSW = 0x04fc,
FGA_TIM0COUNT = 0x0c00,
FGA_AUXSRCTERM = 0x0348,
FGA_AUXDSTTERM = 0x034c,
FGA_CTL13 = 0x0350,
FGA_CTL14 = 0x0354,
FGA_CTL15 = 0x0358,
FGA_CTL16 = 0x035c,
FGA_SPECIALENA = 0x0424,
FGA_ISLOCAL0 = 0x0480,
FGA_ISLOCAL1 = 0x0484,
FGA_ISLOCAL2 = 0x0488,
FGA_ISLOCAL3 = 0x048C,
FGA_ISLOCAL4 = 0x0490,
FGA_ISLOCAL5 = 0x0494,
FGA_ISLOCAL6 = 0x0498,
FGA_ISLOCAL7 = 0x049C,
FGA_ISTIM0 = 0x04a0,
FGA_ISDMANORM = 0x04b0,
FGA_ISDMAERR = 0x04b4,
FGA_ISFMB0REF = 0x04b8,
FGA_ISFMB1REF = 0x04bc,
FGA_ISPARITY = 0x04c0,
FGA_DMARUNCTL = 0x04c4,
FGA_ISABORT = 0x04c8,
FGA_ISACFAIL = 0x04cc,
FGA_ISFMB0MES = 0x04e0,
FGA_ISFMB1MES = 0x04e4,
FGA_ISSYSFAIL = 0x04d0,
FGA_ABORTPIN = 0x04d4,
FGA_RSVMECALL = 0x04f0,
FGA_RSKEYRES = 0x04f4,
FGA_RSCPUCALL = 0x04f8,
FGA_RSLOCSW = 0x04fc,
FGA_TIM0COUNT = 0x0c00,
};
};

View File

@ -87,8 +87,14 @@ DONE (x) (p=partly) NMOS CMOS
#define VERBOSE 0
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
#define LOG(x)
#define LOGR(x)
#define LOGTX(x)
#define LOGRX(x)
#define LOGSETUP(x)
#define LOGINT(x) LOGPRINT(x)
#if VERBOSE > 1
#define logerror printf
#endif
@ -264,7 +270,8 @@ void duscc_device::device_reset()
/*
* Interrupt Control
A single interrupt output (IRON) is provided which is activated upon the occurrence of any of the following conditions:
A single interrupt output (IRQN) is provided which is activated upon the occurrence of any of the following conditions:
- Channel A external or CIT special condition
- Channel B external or CIT special condition
- Channel A RxlTx error or special condition
@ -273,6 +280,7 @@ void duscc_device::device_reset()
- Channel B TxRDY
- Channel A RxRDY
- Channel B RxRDY
Each of the above conditions occupies a bit in the General Status Register (GSR). If ICR[2] is set, the eight conditions are encoded
into three bits which are inserted into bits [2:0] or [4:2] of the interrupt vector register. This forms the content of the IVRM during
an interrupt acknowledge cycle. Unmodified and modified vectors can read directly through specified registers. Two of the conditions
@ -288,26 +296,26 @@ void duscc_device::device_reset()
IER, CTCR[?] could be programmed to enable or disable an interrupt upon the CfT zero count condition. The interrupt priorities
within a channel are fixed. Priority between channels is controlled by ICR[7:6]. Reier to Table 8 and ICR[7:6].
The ICR contains the master interrupt enables for each channel (ICR[I] andICR[OJ) which must be set if the corresponding channel
The ICR contains the master interrupt enables for each channel (ICR[1] and ICR[O]) which must be set if the corresponding channel
is to cause an interrupt. The CPU vector mode is specified by ICR[5:4] which selects either vectored or non-vectored operation. If
vectored mode is selected, the content of the IVR or IVRM is placed on the data bus when lACK is activated. If ICR[2] is set, the content
of IVRM is output which contains the content of IVR and the encoded status of the interrupting condition.
Upon receiving an interrupt acknowledge, the DUSCC locks its current interrupt status until the end of the acknowledge cycle.
If it has an active interrupt pending, it responds with the appropriate vector and then asserts DTACKN. If it does not have an interrupt, it
propagates the acknowledge through its X2/1DCN output if this function is programmed in PCRA[7]; otherwise, the IACKN is
propagates the acknowledge through its X2/IDCN output if this function is programmed in PCRA[7]; otherwise, the IACKN is
ignored. Locking the interrupt status at the leading edge of IACKN prevents a device at a High position in the interrupt daisy chain from
responding to an lACK issued for a lower priority device while the acknowledge is being propagated to that device.*/
//-------------------------------------------------
// z80daisy_irq_state - get interrupt status
//-------------------------------------------------
int duscc_device::z80daisy_irq_state()
{
int state = 0;
LOG(("%s %s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ",tag(), FUNCNAME,
m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3],
m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]));
LOGINT(("%s %s A:[%02x][%02x][%02x][%02x] B:[%02x][%02x][%02x][%02x] ",tag(), FUNCNAME,
m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3],
m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]));
// loop over all interrupt sources
for (auto & elem : m_int_state)
@ -321,7 +329,7 @@ int duscc_device::z80daisy_irq_state()
state |= elem;
}
LOG(("Interrupt State %02x\n", state));
LOGINT((" - Interrupt State %02x\n", state));
return state;
}
@ -333,7 +341,7 @@ int duscc_device::z80daisy_irq_state()
int duscc_device::z80daisy_irq_ack()
{
LOG(("%s %s()\n",tag(), FUNCNAME));
LOGINT(("%s %s()\n",tag(), FUNCNAME));
// loop over all interrupt sources
for (auto & elem : m_int_state)
@ -344,12 +352,21 @@ int duscc_device::z80daisy_irq_ack()
// clear interrupt, switch to the IEO state, and update the IRQs
elem = Z80_DAISY_IEO;
check_interrupts();
return m_ivrm;
LOGINT((" - Found an INT request, "));
if ((m_icr & REG_ICR_VEC_MODE_MASK) == REG_ICR_VEC_MODE_NONE)
{
LOGINT(("but ICR set to use autovector, returning -1\n"));
return -1;
}
else
{
LOGINT(("returning IVRM: %02x\n", m_ivrm ));
return m_ivrm;
}
}
}
return m_ivrm;
LOGINT((" - Found NO INT request, returning -1\n"));
return -1; // Signal no-vector, same as autovector but caller should know the difference
}
@ -359,7 +376,7 @@ int duscc_device::z80daisy_irq_ack()
void duscc_device::z80daisy_irq_reti()
{
LOG(("%s %s \n",tag(), FUNCNAME));
LOGINT(("%s %s \n",tag(), FUNCNAME));
// loop over all interrupt sources
for (auto & elem : m_int_state)
@ -376,15 +393,25 @@ void duscc_device::z80daisy_irq_reti()
}
}
READ8_MEMBER( duscc_device::iack )
{
LOGINT(("%s %s - returning vector:%02x\n",tag(), FUNCNAME, m_ivrm));
int vec = z80daisy_irq_ack();
z80daisy_irq_reti();
return vec;
}
void duscc_device::check_interrupts()
{
LOG(("%s %s()\n",tag(), FUNCNAME));
LOGINT(("%s %s()\n",tag(), FUNCNAME));
int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE;
// "If no interrupt is pending, an H'FF' is output when reading the IVRM."
if (state == 0)
if (state == CLEAR_LINE)
m_ivrm = 0xff;
// Provide the IRQN interrupt request signal level to the connected device (ie a CPU or an interrupt controller)
// The CPU can issue an IACK cycle but is not required to do so, it may read the status and vectors by software
m_out_int_cb(state);
}
@ -395,7 +422,7 @@ void duscc_device::check_interrupts()
void duscc_device::reset_interrupts()
{
LOG(("%s %s - not implemented \n",tag(), FUNCNAME));
LOGINT(("%s %s\n",tag(), FUNCNAME));
// reset internal interrupt sources
for (auto & elem : m_int_state)
@ -407,7 +434,7 @@ void duscc_device::reset_interrupts()
check_interrupts();
}
UINT8 duscc_device::modify_vector(UINT8 vec, int i, UINT8 src)
UINT8 duscc_device::modify_vector(UINT8 vec, int index, UINT8 src)
{
/*
Interrupt Vector Modification
@ -424,22 +451,26 @@ UINT8 duscc_device::modify_vector(UINT8 vec, int i, UINT8 src)
1 1 1 Ch B external or C/T status
--------------------------------------------------
*/
LOG(("%s %s - not implemented\n",tag(), FUNCNAME));
//TODO: Prevent modification if no vector has been programmed, even if it is the default vector.
LOGINT(("%s %c %s, vec:%02x src=%02x\n",tag(), 'A' + index, FUNCNAME, vec, src));
// TODO: Prevent modification if no vector has been programmed, even if it is the default vector.
if ((m_icr & REG_ICR_VEC_MOD) != 0) // Affect vector?
{
// Modify vector according to "Vector Include Status" bit (REG_ICR_V2V4_MOD)
if ((m_icr & REG_ICR_V2V4_MOD) != 0)
{ // Affect V2-V4
{ // Affect V2-V4
LOGINT((" - Affect V2-V4 with status"));
vec &= 0x07 << 3;
vec |= src << 3;
}
else // Affect V0-V2
{
LOGINT((" - Affect V0-V2 with status"));
vec &= 0x07 << 0;
vec |= src << 0;
}
}
LOGINT((" - Returning vector %02x\n", vec));
return vec;
}
@ -448,10 +479,10 @@ UINT8 duscc_device::modify_vector(UINT8 vec, int i, UINT8 src)
This group of registers define mechanisms for communications between the DUSCC and the processor and contain the device status
information. Four registers, available for each channel, and four common device registers comprise this group which consists of
the following:
1. Interrupt Enable Register (IERA/B).
1. Interrupt Enable Register (IERA/B). - checked by trigger_interrupt
2. Receiver Status Register (RSRA/B).
3. Transmitter and Receiver Status Register (TRSRA/B).
4. Input and Coutnermmer Status Register (ICTSRA/B).
4. Input and Counter/timer Status Register (ICTSRA/B).
5. interrupt Vector Register (IVR) and Modified Interrupt Vector Register (IVRM).
6. Interrupt control register (lCR).
7. General status register (GSR)
@ -467,12 +498,13 @@ void duscc_device::trigger_interrupt(int index, int state)
UINT8 source = 0;
int priority_level = 0;
LOG(("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state));
LOGINT(("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state));
/* The Interrup Controll Register (ICR) bits, must be set for the correspondning channel */
// ICR Check is probably by the caller but we check again to be sure
if ((m_icr & (index == CHANNEL_A ? REG_ICR_CHA : REG_ICR_CHB)) == 0)
{
LOG(("The Interrupt Control Register [%02x] bit for this channel is not set, blocking attempt to interrupt\n", m_icr));
LOGINT(("The Interrupt Control Register [%02x] bit for this channel is not set, blocking attempt to interrupt\n", m_icr));
return;
}
@ -483,7 +515,7 @@ void duscc_device::trigger_interrupt(int index, int state)
case REG_ICR_PRIO_BHI: priority_level = state + (index == CHANNEL_A ? 4 : 0); break;
case REG_ICR_PRIO_AINT: priority_level = state * 2 + (index == CHANNEL_A ? 0 : 1); break;
case REG_ICR_PRIO_BINT: priority_level = state * 2 + (index == CHANNEL_A ? 1 : 0); break;
default: logerror("Programming error, please report/fix\n"); // Will not happen
default: logerror("DUSCC Programming error, please report/fix\n"); // Will not happen
}
// Vector modification requested?
@ -492,6 +524,10 @@ void duscc_device::trigger_interrupt(int index, int state)
// trigger interrupt
m_int_state[priority_level] |= Z80_DAISY_INT;
LOGINT((" - Interrupt Priority Level %d, caused by Source %02x with vector %02x\n",priority_level, source, m_ivrm ));
// check for interupts
check_interrupts();
}
READ8_MEMBER( duscc_device::read )
@ -639,8 +675,6 @@ void duscc_channel::device_start()
save_item(NAME(m_dtr));
save_item(NAME(m_rts));
save_item(NAME(m_sync));
// device_serial_interface::register_save_state(machine().save(), this);
}
@ -718,7 +752,8 @@ void duscc_channel::device_timer(emu_timer &timer, device_timer_id id, int param
if ( ( (m_ctcr & REG_CTCR_ZERO_DET_INT) == 1 ) &&
( (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB) ) != 0) )
{
//trigger_interrupt();
LOG(("Zero Detect Interrupt pending\n"));
m_uart->trigger_interrupt(m_index, INT_EXTCTSTAT);
}
// Preload or rollover?
@ -943,7 +978,7 @@ void duscc_channel::tra_callback()
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);
logerror("%s Channel %c Failed to transmit\n", FUNCNAME, 'A' + m_index);
}
}
@ -998,7 +1033,7 @@ void duscc_channel::rcv_complete()
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));
LOGINT((LLFORMAT " %s() \"%s \"Channel %c Received Data %c\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, data));
receive_data(data);
}
@ -1203,8 +1238,8 @@ 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));
LOGINT(("%s\n", FUNCNAME));
LOGRX((" - 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)
@ -1213,12 +1248,12 @@ UINT8 duscc_channel::do_dusccreg_rxfifo_r()
m_rx_error_fifo[m_rx_fifo_rp] = 0; // Loose the old errors
m_rx_fifo_rp_step();
m_rsr |= (m_rx_error_fifo[m_rx_fifo_rp] & (REG_RSR_CHAR_COMPARE | REG_RSR_FRAMING_ERROR | REG_RSR_PARITY_ERROR)); // Get new errors
LOG((" - RX reading out data:%02x '%c'\n", data, isalnum(data) ? data : ' '));
LOGINT((" - 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"));
LOGINT(("- RX FIFO empty despite RxREADY\n"));
}
return (UINT8) data;
@ -1265,14 +1300,16 @@ UINT8 duscc_channel::do_dusccreg_ictsr_r()
*/
UINT8 duscc_channel::do_dusccreg_gsr_r()
{
LOGR(("%s <- %02x\n", FUNCNAME, m_uart->m_gsr));
return (UINT8) m_uart->m_gsr;
static UINT8 old_gsr = 0;
if (m_uart->m_gsr != old_gsr) LOG(("%s <- %02x\n", FUNCNAME, m_uart->m_gsr));
old_gsr = m_uart->m_gsr;
return m_uart->m_gsr;
}
UINT8 duscc_channel::do_dusccreg_ier_r()
{
LOGR(("%s <- %02x\n", FUNCNAME, m_uart->m_ier));
return (UINT8) 0;
LOGINT(("%s <- %02x\n", FUNCNAME, m_ier));
return (UINT8) m_ier;
}
UINT8 duscc_channel::do_dusccreg_cid_r()
@ -1647,7 +1684,7 @@ void duscc_channel::do_dusccreg_ttr_w(UINT8 data)
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
default: LOG(("DUSCC: Wrong programming\n")); break; // Should never happen
}
LOG(("- BRG Tx rate %u assuming a 14.7456MHz CLK crystal\n", get_baudrate(m_ttr & REG_TTR_BRG_RATE_MASK)));
@ -1656,7 +1693,7 @@ void duscc_channel::do_dusccreg_ttr_w(UINT8 data)
return;
}
/* Receiver Parameter Resgister (RPRA, RPRB)
/* Receiver Parameter Register (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.
@ -1783,7 +1820,7 @@ void duscc_channel::do_dusccreg_rtr_w(UINT8 data)
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
default: LOG(("DUSCC: Wrong programming\n")); break; // Should never happen
}
LOG(("- BRG Rx rate %u assuming a 14.7456MHz CLK crystal\n", get_baudrate(m_rtr & REG_RTR_BRG_RATE_MASK)));
@ -1875,7 +1912,7 @@ void duscc_channel::do_dusccreg_omr_w(UINT8 data)
*/
void duscc_channel::do_dusccreg_pcr_w(UINT8 data)
{
LOG(("%s(%02x) Pin Configuration Register\n", FUNCNAME, data));
LOG(("%c %s(%02x)\n", 'A' + m_index, 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")));
@ -1889,7 +1926,7 @@ void duscc_channel::do_dusccreg_pcr_w(UINT8 data)
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
default: LOG(("DUSCC: Wrong programming\n")); break; // Should never happen
}
LOG(("- The TRxC pin is "));
switch( m_pcr & REG_PCR_TRXC_MASK )
@ -1919,7 +1956,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
int rate;
m_ccr = data;
LOG(("%s\n", FUNCNAME));
LOG(("%c %s(%02x)\n", 'A' + m_index, FUNCNAME, data));
switch(m_ccr)
{
// TRANSMITTER COMMANDS
@ -1929,7 +1966,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
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"));
case REG_CCR_RESET_TX: LOGINT(("- Reset Tx\n"));
set_tra_rate(0);
m_tx_fifo_wp = m_tx_fifo_rp = 0;
m_trsr &= 0x0f;
@ -1939,7 +1976,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
/* 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"));
case REG_CCR_ENABLE_TX: LOGINT(("- Enable Tx\n"));
m_uart->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);
@ -1950,7 +1987,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
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"));
case REG_CCR_DISABLE_TX: LOGINT(("- Disable Tx\n"));
set_tra_rate(0);
m_tra = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
@ -1962,7 +1999,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
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"));
case REG_CCR_RESET_RX: LOGINT(("- Reset Rx\n"));
set_rcv_rate(0);
m_rx_fifo_wp = m_rx_fifo_rp = 0;
m_trsr &= 0xf0;
@ -1973,14 +2010,14 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
/* 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"));
case REG_CCR_ENABLE_RX: LOGINT(("- Enable Rx\n"));
m_rcv = 1;
set_rcv_rate(m_brg_rx_rate);
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"));
case REG_CCR_DISABLE_RX: LOGINT(("- Disable Rx\n"));
m_rcv = 0;
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
break;
@ -2018,8 +2055,7 @@ void duscc_channel::do_dusccreg_ccr_w(UINT8 data)
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));
LOGTX((" - TX %s(%02x)'%c'\n", FUNCNAME,data, isalnum(data) ? data : ' '));
/* 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) ))
@ -2053,7 +2089,13 @@ void duscc_channel::do_dusccreg_txfifo_w(UINT8 data)
}
else
{
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
if (m_omr & REG_OMR_TXRDY_ACTIVATED) // TXRDY on FIFO empty?
{
if (m_tx_fifo_wp == m_tx_fifo_rp) // TXFIFO empty?
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
}
else // TXRDY on FIFO not full
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_TXREADY : REG_GSR_CHAN_B_TXREADY);
}
return;
@ -2072,7 +2114,7 @@ void duscc_channel::do_dusccreg_txfifo_w(UINT8 data)
message is received. Asserted status bits can be programmed to generate an interrupt (see Interrupt Enable Register).*/
void duscc_channel::do_dusccreg_rsr_w(UINT8 data)
{
LOG(("%s: %02x\n", FUNCNAME, data));
LOG(("%c %s(%02x)\n", 'A' + m_index, FUNCNAME, data));
m_rsr &= ~data; // Clear only bits which are 1:s
return;
}
@ -2091,7 +2133,7 @@ void duscc_channel::do_dusccreg_ictsr_w(UINT8 data)
return;
}
/* 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
/* The GSR 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 8 External or Coutnerrrimer Status - This bit indicates that one of the following status bits is asserted: ICTSRB[6:4].
@ -2112,7 +2154,7 @@ void duscc_channel::do_dusccreg_ictsr_w(UINT8 data)
receiver' command is invoked.*/
void duscc_channel::do_dusccreg_gsr_w(UINT8 data)
{
LOG(("%s(%02x)\n", FUNCNAME, data));
LOG(("%c %s(%02x)\n", 'A' + m_index, FUNCNAME, data));
m_uart->m_gsr &= (data & REG_GSR_XXREADY_MASK); // Reset only XXREADY bits, the rest needs to be reset by the source
return; // TODO: Check of the XXREADY source bits should be reset too
}
@ -2122,8 +2164,16 @@ void duscc_channel::do_dusccreg_gsr_w(UINT8 data)
condition for an interrupt to be generated is that the channel's master interrupt enabled bit, ICR[O] or ICR[1], be asserted.*/
void duscc_channel::do_dusccreg_ier_w(UINT8 data)
{
LOGINT(("%c %s(%02x)\n", 'A' + m_index, FUNCNAME, data));
if (REG_IER_DCD_CTS & (data ^ m_ier)) LOGINT(("- DCD/CTS interrups %s\n", (data & REG_IER_DCD_CTS) ? "enabled" : "disabled" ));
if (REG_IER_TXRDY & (data ^ m_ier)) LOGINT(("- TXRDY interrupts %s\n", (data & REG_IER_TXRDY) ? "enabled" : "disabled" ));
if (REG_IER_TRSR73 & (data ^ m_ier)) LOGINT(("- TRSR73 interrupts %s\n", (data & REG_IER_TRSR73) ? "enabled" : "disabled" ));
if (REG_IER_RXRDY & (data ^ m_ier)) LOGINT(("- RXRDY interrupts %s\n", (data & REG_IER_RXRDY) ? "enabled" : "disabled" ));
if (REG_IER_RSR76 & (data ^ m_ier)) LOGINT(("- RSR76 interrupts %s\n", (data & REG_IER_RSR76) ? "enabled" : "disabled" ));
if (REG_IER_RSR54 & (data ^ m_ier)) LOGINT(("- RSR54 interrupts %s\n", (data & REG_IER_RSR54) ? "enabled" : "disabled" ));
if (REG_IER_RSR32 & (data ^ m_ier)) LOGINT(("- RSR32 interrupts %s\n", (data & REG_IER_RSR32) ? "enabled" : "disabled" ));
if (REG_IER_RSR10 & (data ^ m_ier)) LOGINT(("- RSR10 interrupts %s\n", (data & REG_IER_RSR10) ? "enabled" : "disabled" ));
m_ier = data;
LOG(("%s(%02x)\n", FUNCNAME, data));
m_uart->check_interrupts();
return;
}
@ -2139,6 +2189,12 @@ void duscc_channel::do_dusccreg_icr_w(UINT8 data)
{
m_uart->m_icr = data;
LOG(("%s(%02x)\n", FUNCNAME, data));
if (duscc_device::REG_ICR_CHB & (data ^ m_uart->m_icr)) LOG(("- Channel B interrupts %s\n", (data & duscc_device::REG_ICR_CHB) ? "enabled" : "disabled" ));
if (duscc_device::REG_ICR_CHA & (data ^ m_uart->m_icr)) LOG(("- Channel A interrupts %s\n", (data & duscc_device::REG_ICR_CHA) ? "enabled" : "disabled" ));
if (duscc_device::REG_ICR_VEC_MOD & (data ^ m_uart->m_icr)) LOG(("- Vector is %s\n", (data & duscc_device::REG_ICR_VEC_MOD) ? "modified" : "unmodified" ));
if (duscc_device::REG_ICR_V2V4_MOD & (data ^ m_uart->m_icr)) LOG(("- Vector bits %s modified\n", (data & duscc_device::REG_ICR_V2V4_MOD) ? "4:2" : "2:0" ));
// TODO: LOG the other bits as well
m_uart->m_icr = data;
return;
}
@ -2173,7 +2229,8 @@ UINT8 duscc_channel::read(offs_t &offset)
{
UINT8 data = 0;
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
LOG(("\"%s\" %s: %c : Register read '%02x' <- [%02x]", m_owner->tag(), FUNCNAME, 'A' + m_index, data, reg ));
LOGR((" * %c Reg %02x -> %02x \n", 'A' + m_index, reg, data));
switch (reg)
{
case REG_CMR1: data = do_dusccreg_cmr1_r(); break;
@ -2207,10 +2264,10 @@ UINT8 duscc_channel::read(offs_t &offset)
// CDUSCC Extended registers - requires A7 to be set through REG_SEA
case REG_CID: data = do_dusccreg_cid_r(); break;
default:
logerror(" \"%s\" %s: %c : Unsupported RRx register:%02x\n", m_owner->tag(), FUNCNAME, 'A' + m_index, reg);
logerror("%s: %c : Unsupported RRx register:%02x\n", FUNCNAME, 'A' + m_index, reg);
}
//LOG(("%s \"%s\": %c : Register R%d read '%02x'\n", FUNCNAME, m_owner->tag(), 'A' + m_index, reg, data));
LOGR(("%s \"%s\": %c : Register R%d read '%02x'\n", FUNCNAME, m_owner->tag(), 'A' + m_index, reg, data));
return data;
}
@ -2222,7 +2279,7 @@ void duscc_channel::write(UINT8 data, offs_t &offset)
{
int reg = (offset | m_a7) & ~0x20; // Add extended rgisters and remove the channel B bit from offset
LOG((" * %c Reg %02x <- %02x \n", 'A' + m_index, reg, data));
LOGSETUP((" * %c Reg %02x <- %02x \n", 'A' + m_index, reg, data));
LOG(("\"%s\" %s: %c : Register write '%02x' -> [%02x]", m_owner->tag(), FUNCNAME, 'A' + m_index, data, reg ));
switch (reg)
{
@ -2266,7 +2323,7 @@ void duscc_channel::write(UINT8 data, offs_t &offset)
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);
logerror("%s: %c : Unsupported WRx register:%02x(%02x)\n", FUNCNAME, 'A' + m_index, reg, data);
}
}
@ -2278,7 +2335,6 @@ UINT8 duscc_channel::m_rx_fifo_rp_data()
m_rx_fifo_rp_step();
data = m_rx_data_fifo[m_rx_fifo_rp];
m_rx_fifo_rp = old_rp;
return data;
}
@ -2294,7 +2350,8 @@ void duscc_channel::m_rx_fifo_rp_step()
// check if FIFO is empty
if (m_rx_fifo_rp == m_rx_fifo_wp)
{
// no more characters available in the FIFO
// no more characters available in the FIFO
LOGINT(("Clear RXRDY in GSR because FIFO is emptied\n"));
m_uart->m_gsr &= ~(m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
}
}
@ -2316,7 +2373,7 @@ void duscc_channel::m_tx_fifo_rp_step()
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
@ -2328,6 +2385,7 @@ void duscc_channel::receive_data(UINT8 data)
{
m_rx_data_fifo[m_rx_fifo_wp] = data;
m_rsr &= ~REG_RSR_OVERRUN_ERROR;
LOGINT((" - Setting RXRDY in GSR for channel %c\n", 'A' + m_index));
m_uart->m_gsr |= (m_index == duscc_device::CHANNEL_A ? REG_GSR_CHAN_A_RXREADY : REG_GSR_CHAN_B_RXREADY);
m_rx_fifo_wp++;
@ -2336,8 +2394,19 @@ void duscc_channel::receive_data(UINT8 data)
m_rx_fifo_wp = 0;
}
// if (m_eir & REG_IER_)
if (m_uart->m_icr & (m_index == duscc_device::CHANNEL_A ? duscc_device::REG_ICR_CHA : duscc_device::REG_ICR_CHB))
{
if (m_ier & REG_IER_RXRDY)
{
if (m_omr & REG_OMR_RXRDY_ACTIVATED) // interrupt on FIFO full and...
{
if (m_rx_fifo_rp == m_rx_fifo_wp) // FIFO full?
m_uart->trigger_interrupt(m_index, INT_RXREADY);
}
else
m_uart->trigger_interrupt(m_index, INT_RXREADY);
}
}
}
}

View File

@ -112,6 +112,9 @@
#define MCFG_DUSCC_OUT_RTXCB_CB(_devcb) \
devcb = &duscc_device::set_out_rtxcb_callback(*device, DEVCB_##_devcb);
#define MCFG_DUSCC_OUT_INT_CB(_devcb) \
devcb = &duscc_device::set_out_int_callback(*device, DEVCB_##_devcb);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@ -620,6 +623,7 @@ public:
template<class _Object> static devcb_base &set_out_syncb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_syncb_cb.set_callback(object); }
template<class _Object> static devcb_base &set_out_rtxcb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_rtxcb_cb.set_callback(object); }
template<class _Object> static devcb_base &set_out_trxcb_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_trxcb_cb.set_callback(object); }
template<class _Object> static devcb_base &set_out_int_callback(device_t &device, _Object object) { return downcast<duscc_device &>(device).m_out_int_cb.set_callback(object); }
static void configure_channels(device_t &device, int rxa, int txa, int rxb, int txb)
{
@ -636,7 +640,12 @@ public:
DECLARE_WRITE8_MEMBER( write );
// interrupt acknowledge
// int m1_r();
DECLARE_READ8_MEMBER( iack );
// device_z80daisy_interface overrides
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_chanA->write_rx(state); }
DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_chanB->write_rx(state); }
@ -662,11 +671,6 @@ protected:
virtual void device_reset() override;
virtual machine_config_constructor device_mconfig_additions() const override;
// device_z80daisy_interface overrides
virtual int z80daisy_irq_state() override;
virtual int z80daisy_irq_ack() override;
virtual void z80daisy_irq_reti() override;
// internal interrupt management
void check_interrupts();
void reset_interrupts();
@ -720,7 +724,6 @@ protected:
devcb_write_line m_out_int_cb;
int m_int_state[8]; // interrupt state
int m_variant;
@ -731,15 +734,17 @@ protected:
enum
{
REG_ICR_CHB = 0x01,
REG_ICR_CHA = 0x02,
REG_ICR_VEC_MOD = 0x04,
REG_ICR_V2V4_MOD = 0x08,
REG_ICR_PRIO_MASK = 0xC0,
REG_ICR_PRIO_AHI = 0x00,
REG_ICR_PRIO_BHI = 0x40,
REG_ICR_PRIO_AINT = 0x80,
REG_ICR_PRIO_BINT = 0xC0,
REG_ICR_CHB = 0x01,
REG_ICR_CHA = 0x02,
REG_ICR_VEC_MOD = 0x04,
REG_ICR_V2V4_MOD = 0x08,
REG_ICR_VEC_MODE_MASK = 0x30,
REG_ICR_VEC_MODE_NONE = 0x30,
REG_ICR_PRIO_MASK = 0xC0,
REG_ICR_PRIO_AHI = 0x00,
REG_ICR_PRIO_BHI = 0x40,
REG_ICR_PRIO_AINT = 0x80,
REG_ICR_PRIO_BINT = 0xC0,
};
};

View File

@ -130,7 +130,7 @@
* FFF00000-FFFFFFFF Reserved
* --------------------------------------------------------------------------
*
* Interrupt sources MVME
* Interrupt sources CPU30
* ----------------------------------------------------------
* Description Device Lvl IRQ VME board
* /Board Vector Address
@ -141,9 +141,39 @@
*
* ----------------------------------------------------------
*
* PIT #1 hardware wiring
* ----------------------------------------------------------
* PA0-PA3 Rotary Switch 1 input
* PA4-PA7 Rotary Switch 2 input
* H1-H4 User I/O via optional B5 or optional 5-row VME P2 connector
* PB0-PB2 Floppy Disk Drive Control output
* PB3-PB4 Floppy Disk Drive Control input
* PB5 Floppy Disk Drive Control output
* PB6-PB7 DMAC control
* PC0,PC1 User I/O via optional B5 or optional 5-row VME P2 connector
* PC4,PC7 User I/O via optional B5 or optional 5-row VME P2 connector
* PC2 Reserved
* PC3 Timer interrupt request
* PC5 Port Interrupt Request
* PC6 68882 FPCP Sense
*
* PIT #2 hardware setup wiring
* ----------------------------------------------------------
* PA0-PA7 User I/O via optional B5 or optional 5-row VME P2 connector
* H1-H4 User I/O via optional B5 or optional 5-row VME P2 connector
* PB0-PB2 Memory Size
* PB3-PB7 Board ID
* PC0-PC1 Hardware ID
* PC2 Status of write protection for (default and optional) Boot PROMs
* PC3 Timer Interrupt request
* PC4 Status of write protection for SYSTEM-Flash Memory
* PC5 DMA control
* PC6 Flash programming voltage control
* PC7 Reserved
*
* DMAC Channel Assignments
* ----------------------------------------------------------
* Channel MVME147
* Channel SYS68K/CPU30
* ----------------------------------------------------------
*
*
@ -168,7 +198,11 @@
#define VERBOSE 0
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
#define LOG(x)
#define LOGR(x)
#define LOGSETUP(x)
#define LOGINT(x) LOGPRINT(x)
#if VERBOSE >= 2
#define logerror printf
#endif
@ -197,9 +231,24 @@ fccpu30_state(const machine_config &mconfig, device_type type, const char *tag)
DECLARE_READ32_MEMBER (bootvect_r);
DECLARE_WRITE32_MEMBER (bootvect_w);
/* Interrupt support */
// IRQ_CALLBACK_MEMBER(maincpu_iack_callback);
DECLARE_WRITE_LINE_MEMBER(fga_irq_callback);
UINT8 fga_irq_state;
// int fga_irq_vector;
int fga_irq_level;
/* Rotary switch PIT input */
DECLARE_READ8_MEMBER (rotary_rd);
DECLARE_READ8_MEMBER (flop_dmac_r);
DECLARE_WRITE8_MEMBER (flop_dmac_w);
DECLARE_READ8_MEMBER (pit1c_r);
DECLARE_WRITE8_MEMBER (pit1c_w);
DECLARE_READ8_MEMBER (pit2a_r);
DECLARE_WRITE8_MEMBER (pit2a_w);
DECLARE_READ8_MEMBER (board_mem_id_rd);
DECLARE_READ8_MEMBER (pit2c_r);
DECLARE_WRITE8_MEMBER (pit2c_w);
/* VME bus accesses */
//DECLARE_READ16_MEMBER (vme_a24_r);
@ -219,6 +268,9 @@ private:
required_device<fga002_device> m_fga002;
// Helper functions
void update_irq_to_maincpu();
// Pointer to System ROMs needed by bootvect_r and masking RAM buffer for post reset accesses
UINT32 *m_sysrom;
UINT32 m_sysram[2];
@ -231,6 +283,7 @@ static ADDRESS_MAP_START (fccpu30_mem, AS_PROGRAM, 32, fccpu30_state)
AM_RANGE (0x00000008, 0x003fffff) AM_RAM /* 4 Mb RAM */
AM_RANGE (0xff000000, 0xff7fffff) AM_ROM AM_REGION("roms", 0x000000)
AM_RANGE (0xff802000, 0xff8021ff) AM_DEVREADWRITE8("duscc", duscc68562_device, read, write, 0xffffffff) /* Port 1&2 - Dual serial port DUSCC */
AM_RANGE (0xff802200, 0xff8023ff) AM_DEVREADWRITE8("duscc2", duscc68562_device, read, write, 0xffffffff) /* Port 3&4 - 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) */
@ -336,6 +389,39 @@ READ8_MEMBER (fccpu30_state::rotary_rd){
return 0xff; // TODO: make this configurable from commandline or artwork
}
// PIT#1 Port B TODO: implement floppy and dma control
READ8_MEMBER (fccpu30_state::flop_dmac_r){
LOG(("%s\n", FUNCNAME));
return 0xff;
}
WRITE8_MEMBER (fccpu30_state::flop_dmac_w){
LOG(("%s(%02x)\n", FUNCNAME, data));
}
// PIT#1 Port C TODO: implement timer+port interrupts and 68882 sense
// TODO: Connect PC0, PC1, PC4 and PC7 to B5 and/or P2 connector
READ8_MEMBER (fccpu30_state::pit1c_r){
LOG(("%s\n", FUNCNAME));
return 0xff;
}
WRITE8_MEMBER (fccpu30_state::pit1c_w){
LOG(("%s(%02x)\n", FUNCNAME, data));
}
// PIT#2 Port A TODO: Connect to B5 and /or P2 connector
READ8_MEMBER (fccpu30_state::pit2a_r){
LOG(("%s\n", FUNCNAME));
logerror("Unsupported user i/o on PIT2 port A detected\n");
return 0xff;
}
WRITE8_MEMBER (fccpu30_state::pit2a_w){
LOG(("%s(%02x)\n", FUNCNAME, data));
logerror("Unsupported user i/o on PIT2 port A detected\n");
}
/*
* 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.
@ -359,6 +445,16 @@ READ8_MEMBER (fccpu30_state::board_mem_id_rd){
return 0x36; // CPU-26 1Mb 36 MHz
}
// PIT#2 Port C TODO: implement timer interrupt, DMA i/o, memory control and Hardware ID
READ8_MEMBER (fccpu30_state::pit2c_r){
LOG(("%s\n", FUNCNAME));
return 0xff;
}
WRITE8_MEMBER (fccpu30_state::pit2c_w){
LOG(("%s(%02x)\n", FUNCNAME, data));
}
#if 0
/* Dummy VME access methods until the VME bus device is ready for use */
READ16_MEMBER (fccpu30_state::vme_a24_r){
@ -380,6 +476,34 @@ WRITE16_MEMBER (fccpu30_state::vme_a16_w){
}
#endif
WRITE_LINE_MEMBER(fccpu30_state::fga_irq_callback)
{
LOGINT(("%s(%02x)\n", FUNCNAME, state));
fga_irq_state = state;
fga_irq_level = m_fga002->get_irq_level();
LOGINT((" - FGA irq level %02x\n", fga_irq_level));
update_irq_to_maincpu();
}
void fccpu30_state::update_irq_to_maincpu()
{
LOGINT(("%s()\n", FUNCNAME));
LOGINT((" - fga_irq_level: %02x\n", fga_irq_level));
LOGINT((" - fga_irq_state: %02x\n", fga_irq_state));
switch (fga_irq_level & 0x07)
{
case 1: m_maincpu->set_input_line(M68K_IRQ_1, fga_irq_state); break;
case 2: m_maincpu->set_input_line(M68K_IRQ_2, fga_irq_state); break;
case 3: m_maincpu->set_input_line(M68K_IRQ_3, fga_irq_state); break;
case 4: m_maincpu->set_input_line(M68K_IRQ_4, fga_irq_state); break;
case 5: m_maincpu->set_input_line(M68K_IRQ_5, fga_irq_state); break;
case 6: m_maincpu->set_input_line(M68K_IRQ_6, fga_irq_state); break;
case 7: m_maincpu->set_input_line(M68K_IRQ_7, fga_irq_state); break;
default: logerror("Programmatic error in %s, please report\n", FUNCNAME);
}
}
/*
* Machine configuration
*/
@ -387,40 +511,106 @@ static MACHINE_CONFIG_START (fccpu30, fccpu30_state)
/* basic machine hardware */
MCFG_CPU_ADD ("maincpu", M68030, XTAL_25MHz)
MCFG_CPU_PROGRAM_MAP (fccpu30_mem)
MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("fga002", fga002_device, iack)
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))
/* Force CPU30 series of boards has up to four serial ports, p1-p4, the FGA boot uses p4 as console and subsequent
firmware uses p1 as console and in an operating system environment there may be user login shells on the other.
MCFG_RS232_PORT_ADD ("rs232trm", default_rs232_devices, "terminal")
In order to use more than just one terminal MAME supports serial socket servers to which it is possible to
connect a telnet terminal to. The general syntax to open a socket server from the command prompts is:
mame fccpu30 -window -rs232p4 null_modem -bitbngr socket.127.0.0.1:1001
At the opening screen, before the board starts to execute code, start up the telnet client and give 127.0.0.1:1001 as host
It is also possible to enumerate more than one terminal server in order to have several terminal session attached.
mame fccpu30 -window -rs232p4 null_modem -bitbngr1 socket.127.0.0.1:1001 -rs232p1 null_modem -bitbngr2 socket.127.0.0.1:1002
Now just start up the telnet clients with 127.0.0.1:1001 and 127.0.0.1:1002 as hosts and you have control of input for each port.
*/
#define RS232P1_TAG "rs232p1"
#define RS232P2_TAG "rs232p2"
#define RS232P3_TAG "rs232p3"
#define RS232P4_TAG "rs232p4"
MCFG_DUSCC68562_ADD("duscc", DUSCC_CLOCK, 0, 0, 0, 0 )
/* Port 1 on Port B */
MCFG_DUSCC_OUT_TXDB_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_txd))
MCFG_DUSCC_OUT_DTRB_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_dtr))
MCFG_DUSCC_OUT_RTSB_CB(DEVWRITELINE(RS232P1_TAG, rs232_port_device, write_rts))
/* Port 4 on Port A */
MCFG_DUSCC_OUT_TXDA_CB(DEVWRITELINE(RS232P4_TAG, rs232_port_device, write_txd))
MCFG_DUSCC_OUT_DTRA_CB(DEVWRITELINE(RS232P4_TAG, rs232_port_device, write_dtr))
MCFG_DUSCC_OUT_RTSA_CB(DEVWRITELINE(RS232P4_TAG, rs232_port_device, write_rts))
/* DUSCC1 interrupt signal REQN is connected to LOCAL IRQ4 of the FGA-002 and level is programmable */
MCFG_DUSCC_OUT_INT_CB(DEVWRITELINE("fga002", fga002_device, lirq4_w))
MCFG_DUSCC68562_ADD("duscc2", DUSCC_CLOCK, 0, 0, 0, 0 )
/* Port 2 on Port A */
MCFG_DUSCC_OUT_TXDA_CB(DEVWRITELINE(RS232P2_TAG, rs232_port_device, write_txd))
MCFG_DUSCC_OUT_DTRA_CB(DEVWRITELINE(RS232P2_TAG, rs232_port_device, write_dtr))
MCFG_DUSCC_OUT_RTSA_CB(DEVWRITELINE(RS232P2_TAG, rs232_port_device, write_rts))
/* Port 3 on Port B */
MCFG_DUSCC_OUT_TXDB_CB(DEVWRITELINE(RS232P3_TAG, rs232_port_device, write_txd))
MCFG_DUSCC_OUT_DTRB_CB(DEVWRITELINE(RS232P3_TAG, rs232_port_device, write_dtr))
MCFG_DUSCC_OUT_RTSB_CB(DEVWRITELINE(RS232P3_TAG, rs232_port_device, write_rts))
/* DUSCC2 interrupt signal REQN is connected to LOCAL IRQ5 of the FGA-002 and level is programmable */
MCFG_DUSCC_OUT_INT_CB(DEVWRITELINE("fga002", fga002_device, lirq5_w))
MCFG_RS232_PORT_ADD (RS232P1_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER (DEVWRITELINE ("duscc", duscc68562_device, rxb_w))
MCFG_RS232_CTS_HANDLER (DEVWRITELINE ("duscc", duscc68562_device, ctsb_w))
MCFG_RS232_PORT_ADD (RS232P2_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER (DEVWRITELINE ("duscc2", duscc68562_device, rxa_w))
MCFG_RS232_CTS_HANDLER (DEVWRITELINE ("duscc2", duscc68562_device, ctsa_w))
MCFG_RS232_PORT_ADD (RS232P3_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER (DEVWRITELINE ("duscc2", duscc68562_device, rxb_w))
MCFG_RS232_CTS_HANDLER (DEVWRITELINE ("duscc2", duscc68562_device, ctsb_w))
MCFG_RS232_PORT_ADD (RS232P4_TAG, default_rs232_devices, nullptr)
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 */
/* PIT Parallel Interface and Timer device, assumed strapped for on board clock */
MCFG_DEVICE_ADD ("pit1", PIT68230, XTAL_16MHz / 2) // The PIT clock is not verified on schema but reversed from behaviour
MCFG_PIT68230_PA_INPUT_CB(READ8(fccpu30_state, rotary_rd))
MCFG_PIT68230_PB_INPUT_CB(READ8(fccpu30_state, flop_dmac_r))
MCFG_PIT68230_PB_OUTPUT_CB(WRITE8(fccpu30_state, flop_dmac_w))
MCFG_PIT68230_PC_INPUT_CB(READ8(fccpu30_state, pit1c_r))
MCFG_PIT68230_PC_OUTPUT_CB(WRITE8(fccpu30_state, pit1c_w))
// MCFG_PIT68230_OUT_INT_CB(DEVWRITELINE("fga002", fga002_device, lirq2_w)) // Interrupts not yet supported by 68230
MCFG_DEVICE_ADD ("pit2", PIT68230, XTAL_16MHz / 2) // Th PIT clock is not verified on schema but reversed from behaviour
MCFG_PIT68230_PB_INPUT_CB(READ8(fccpu30_state, board_mem_id_rd))
MCFG_PIT68230_PA_INPUT_CB(READ8(fccpu30_state, pit2a_r))
MCFG_PIT68230_PA_OUTPUT_CB(WRITE8(fccpu30_state, pit2a_w))
MCFG_PIT68230_PC_INPUT_CB(READ8(fccpu30_state, pit2c_r))
MCFG_PIT68230_PC_OUTPUT_CB(WRITE8(fccpu30_state, pit2c_w))
// MCFG_PIT68230_OUT_INT_CB(DEVWRITELINE("fga002", fga002_device, lirq3_w)) // Interrupts not yet supported by 68230
/* FGA-002, Force Gate Array */
MCFG_FGA002_ADD("fga002", 0)
MCFG_FGA002_OUT_INT_CB(WRITELINE(fccpu30_state, fga_irq_callback))
MCFG_FGA002_OUT_LIACK4_CB(DEVREAD8("duscc", duscc_device, iack))
MCFG_FGA002_OUT_LIACK5_CB(DEVREAD8("duscc2", duscc_device, iack))
MACHINE_CONFIG_END
/* ROM definitions */
ROM_START (fccpu30)
ROM_REGION32_BE(0x900000, "roms", 0)
// Boots with Board ID set to: 0x36
#if 1
// Boots with Board ID set to: 0x36 (FGA002 BOOT and VMEPROM on terminal P4)
ROM_LOAD16_BYTE("CPU33LO.BIN", 0x000001, 0x40000, CRC (49895fdf) SHA1 (733abd144c95225a2faf920490e31df2a27f8e03))
ROM_LOAD16_BYTE("CPU33UP.BIN", 0x000000, 0x40000, CRC (cfe75e94) SHA1 (d40e0635a48607be25f7c58c74b53b7e58fe735d))
// Boots with Board ID set to: 0x36 (no display yet)
#if 0
// Boots with Board ID set to: 0x36 (FGA002 BOOT on terminal P4, "Wait until harddisk is up to speed " on terminal P1)
#else
ROM_LOAD32_BYTE("CPU30LL.BIN", 0x000003, 0x20000, CRC (a03ebf46) SHA1 (48fa0268cb10e20679c093e02574dbd9925f95d1))
ROM_LOAD32_BYTE("CPU30LO.BIN", 0x000002, 0x20000, CRC (fefa88ed) SHA1 (71a9ad807c0c2da5c6f6a6dc68c73ad8b52f3ea9))
ROM_LOAD32_BYTE("CPU30UP.BIN", 0x000001, 0x20000, CRC (dfed1f68) SHA1 (71478a77d5ab5da0fabcd78e69537919b560e3b8))
@ -436,44 +626,139 @@ ROM_END
*
* 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
* Bootprom PIT setup sequence - To start VMEPROM, the rotary switches must both be set to 'F' (PI/T #1 port A)
* --------------------------------------------------------------------------------------------------------------
* :pit1 Reg 10 -> ff PAAR - read port A of PIT1 without side effects
* :pit2 Reg 10 -> 36 PBAR - read port B of PIT2 without side effects
* :pit2 Reg 10 <- 00 TCR - PC3/PC7 is I/O, PC2 is I/O, CLK and x32 prescaler, Preload timer on 0 (zero), Timer disabled
* :pit2 Reg 13 <- ff CPRH - Counter Preload Regsiter High
* :pit2 Reg 14 <- ff CPRM - Counter Preload Regsiter Mid
* :pit2 Reg 15 <- ff CPRL - Counter Preload Regsiter Low
* :pit2 Reg 10 <- 01 TCR - PC3/PC7 is I/O, PC2 is I/O, CLK and x32 prescaler, Preload timer on 0 (zero), Timer enabled
* :pit2 Reg 10 <- 00 TCR - PC3/PC7 is I/O, PC2 is I/O, CLK and x32 prescaler, Preload timer on 0 (zero), Timer disabled
* :pit2 Reg -> ff CNTRH - Current value of timer high byte
* :pit2 Reg -> b3 CNTRM - Current value of timer mid byte
* :pit2 Reg -> 70 CNTRL - Current value of timer low byte
* :pit1 Reg 10 <- e0 TCR - PC3 is TOUT, PC7 is I/O, Interrupts enabled, PC2 is I/O, CLK and x32 prescaler, Preload timer on 0 (zero), Timer disabled
* :pit1 Reg 00 <- 20 PGCR -
* :pit1 Reg 01 <- 08 PSRR -
* :pit1 Reg 06 <- c0 PACR -
* :pit1 Reg 02 <- 00 PADDR -
* :pit1 Reg 07 <- c0 PBCR -
* :pit1 Reg 09 <- 00 PBDR -
* :pit1 Reg 03 <- 00 PBDDR -
* :pit1 Reg 0c <- 17 PCDR -
* :pit1 Reg 04 <- 17 PCDDR -
* :pit1 Reg 15 <- e2 CPRL -
* :pit1 Reg 14 <- 04 CPRM -
* :pit1 Reg 13 <- 00 CPRH -
* :pit1 Reg 11 <- f2 TIVR -
* :pit1 Reg 10 <- 41 TCR - PC3 is SQW at TOUT, PC7 is I/O, PC2 is I/O, CLK and x32 prescaler, Preload timer on 0 (zero), Timer enabled
* :pit2 Reg 10 <- e2 PC3 is TOUT, PC7 is I/O, Interrupts enabled, PC2 is timer enable/disable, CLK and prescaler, Preload timer on 0 (zero), Timer disabled
* :pit2 Reg 00 <- 1e PGCR
* :pit2 Reg 01 <- 08 PSRR
* :pit2 Reg 06 <- c0 PACR
* :pit2 Reg 02 <- 00 PADDR
* :pit2 Reg 07 <- c0 PBCR
* :pit2 Reg 03 <- 00 PBDDR
* :pit2 Reg 04 <- 00 PCDDR
* :pit2 Reg 15 <- 08 CPRL
* :pit2 Reg 14 <- 00 CPRM
* :pit2 Reg 13 <- 00 CPRH
* :pit2 Reg 11 <- f3 TIVR
* :pit2 Reg 10 <- e3 PC3 is TOUT, PC7 is I/O, Interrupts enabled, PC2 is timer enable/disable, CLK and prescaler, Preload timer on 0 (zero), Timer enabled
* DUSCC #1 channel A setup 1 sequence FGA-002 firmware (polled i/o)
* A Reg 0f <- 00 - reset Tx Command
* A Reg 0f <- 40 - reset Rx Command
* A Reg 00 <- 07 - Async mode
* A Reg 01 <- 38 - Normal polled or interrupt mode, no DMA
* A Reg 04 <- 7f - Tx 8 bits, CTS and RTS, 1 STOP bit
* A Reg 06 <- 1b - Rx RTS, 8 bits, no DCD, no parity
* A Reg 05 <- 3d - Tx BRG 9600 (assuming a 14.7456 crystal)
* A Reg 07 <- 2d - Rx BRG 9600 (assuming a 14.7456 crystal)
* A Reg 0e <- 27 - TRxC = RxCLK 1x, RTxC is input, RTS, GPO2, crystal oscillator connected to X2
* A Reg 0b <- f1 - RTS low, OUT1 = OUT2 = high, RxRdy asserted on FIFO not empty
* TxRdy asserted on FIFO not empty, Same Tx Residual Character Length as for REG_TPR
* A Reg 0f <- 00 - reset Tx Command
* A Reg 0f <- 40 - reset Rx Command
* A Reg 0f <- 02 - enable Tx Command
* A Reg 0f <- 42 - enable Rx Command
*--- end of setup sequence ---
* loop:
* read <- REG_GSR
* until something needs attention
*
* DUSCC #1 channel A & B setup 2 sequence CPU-33 VMEPROM with PDOS (interrupt driven i/o)
* A Reg 0f <- 00 - reset Tx Command
* A Reg 0f <- 40 - reset Rx Command
* A Reg 00 <- 07 - Async mode
* A Reg 01 <- 38 - Normal polled or interrupt mode, no DMA
* A Reg 04 <- 7f - Tx 8 bits, CTS and RTS, 1 STOP bit
* A Reg 06 <- 1b - Rx RTS, 8 bits, no DCD, no parity
* A Reg 0b <- e1 - RTS low, OUT1 = OUT2 = high, RxRdy asserted on FIFO not empty
* TxRdy asserted on FIFO not full, Same Tx Residual Character Length as for REG_TPR
* A Reg 0e <- 27 - TRxC = RxCLK 1x, RTxC is input, RTS, GPO2, crystal oscillator connected to X2
* A Reg 07 <- 2d - Rx BRG 9600 (assuming a 14.7456 crystal)
* A Reg 05 <- 3d - Tx BRG 9600 (assuming a 14.7456 crystal)
* A Reg 1c <- 10 - RXRDY interrupts enabled
* A Reg 1e <- 1c - Interrupt vector
* A Reg 1f <- 83 - Interleaved prio with A high, no status in vector, enable interrupts for A & B channel
* A Reg 0f <- 00 - reset Tx Command
* A Reg 0f <- 02 - enable Tx Command
* A Reg 0f <- 40 - reset Rx Command
* A Reg 0f <- 42 - enable Rx Command
* Repeated setup for channel B
*
* FGA setup
void fga002_device::do_fga002reg_icrtim0_w(UINT8)(00)
void fga002_device::do_fga002reg_ctl3_w(UINT8)(0c)
void fga002_device::do_fga002reg_icrlocal0_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal1_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal2_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal3_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal4_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal5_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal6_w(UINT8)(00)
void fga002_device::do_fga002reg_icrlocal7_w(UINT8)(00)
* A Reg 10 <- 20
UINT8 duscc_channel::do_dusccreg_rxfifo_r()
- RX rp:0 wp:1 sz:4
- RX reading out data:6e 'n'
UINT8 duscc_channel::do_dusccreg_rxfifo_r()
- RX rp:1 wp:2 sz:4
- RX reading out data:6e 'n'
* A Reg 10 <- 6e
* A Reg 10 <- 0d
* A Reg 10 <- 0a
void fga002_device::do_fga002reg_icrlocal2_w(UINT8)(4d)
void fga002_device::do_fga002reg_icrlocal4_w(UINT8)(1c)
* A Reg 0f <- 00
* A Reg 0f <- 40
* A Reg 00 <- 07
* A Reg 01 <- 38
* A Reg 04 <- 7f
* A Reg 06 <- 1b
* A Reg 0b <- e1
* A Reg 0e <- 27
* A Reg 07 <- 2d
* A Reg 05 <- 3d
* A Reg 1c <- 10
void duscc_channel::do_dusccreg_ier_w(UINT8)(10)
- RXRDY interrupts enabled
:duscc void duscc_device::check_interrupts()()
:duscc virtual int duscc_device::z80daisy_irq_state() A:[00][00][00][00] B:[00][00][00][00] Interrupt State 00
void fga002_device::trigger_interrupt(UINT8)(34)
Interrupt Level 4, caused by ICR 1c with vector 34
void fga002_device::check_interrupts()()
:fga002 virtual int fga002_device::z80daisy_irq_state() Level 0-7:[00][00] [00][00] [01][00] [00][00]
void fccpu30_state::fga_irq_callback(int)(01)
void fga002_device::check_interrupts()()
*/
/* Driver */