mirror of
https://github.com/holub/mame
synced 2025-04-26 10:13:37 +03:00
commit
eab8fe41c3
@ -53,7 +53,7 @@ DONE (x) (p=partly) NMOS CMOS ESCC EMSCC
|
||||
DPLL clock recov Y Y Y Y
|
||||
-- Additional features CMOS versions -----------------------------------
|
||||
x Status FIFO N Y Y Y
|
||||
SWI ack feat N Y Y Y
|
||||
x SWI ack feat N Y Y Y
|
||||
higher bps w ext DPLL N 32Mbps 32Mbps 32Mbps
|
||||
-- Additional features 85C30 -------------------------------------------
|
||||
New WR7 feat N 85C30 Y Y
|
||||
@ -80,10 +80,11 @@ DONE (x) (p=partly) NMOS CMOS ESCC EMSCC
|
||||
|
||||
#define VERBOSE 0
|
||||
#define LOGPRINT(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
#define LOG(x) LOGPRINT(x)
|
||||
#define LOGR(x)
|
||||
#define LOG(x) {}
|
||||
#define LOGR(x) {}
|
||||
#define LOGSETUP(x) LOGPRINT(x)
|
||||
#define LOGRCV(x) LOGPRINT(x)
|
||||
#define LOGINT(x) {}
|
||||
#define LOGRCV(x){}
|
||||
#if VERBOSE == 2
|
||||
#define logerror printf
|
||||
#endif
|
||||
@ -250,6 +251,7 @@ void z80scc_device::device_start()
|
||||
|
||||
// state saving
|
||||
save_item(NAME(m_int_state));
|
||||
save_item(NAME(m_wr9));
|
||||
save_item(NAME(m_wr0_ptrbits));
|
||||
LOG((" - SCC variant %02x\n", m_variant));
|
||||
}
|
||||
@ -263,19 +265,35 @@ void z80scc_device::device_reset()
|
||||
{
|
||||
LOG(("%s %s \n",tag(), FUNCNAME));
|
||||
|
||||
// Do channel reset on both channels
|
||||
m_chanA->reset();
|
||||
m_chanB->reset();
|
||||
|
||||
// Fix hardware reset values for registers where it differs from channel reset values
|
||||
m_wr9 &= 0x3c;
|
||||
m_wr9 |= 0xc0;
|
||||
m_chanA->m_wr10 = 0x00;
|
||||
m_chanB->m_wr10 = 0x00;
|
||||
m_chanA->m_wr11 = 0x08;
|
||||
m_chanB->m_wr11 = 0x08;
|
||||
m_chanA->m_wr14 &= 0xf0;
|
||||
m_chanA->m_wr14 |= 0x30;
|
||||
m_chanB->m_wr14 &= 0xf0;
|
||||
m_chanB->m_wr14 |= 0x30;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupts
|
||||
Each of the SCC's two channels contain three sources of interrupts, making a total of six interrupt
|
||||
sources. These three sources of interrupts are: 1) Receiver, 2) Transmitter, and 3) External/Status
|
||||
conditions. In addition, there are several conditions that may cause these interrupts.*/
|
||||
conditions. In addition, there are several conditions that may cause these interrupts.
|
||||
|
||||
To allow for control over the daisy chain, the SCC has a Disable Lower Chain (DLC) software command (WR9 bit 2)
|
||||
that pulls IEO Low. This selectively deactivates parts of the daisy chain regardless of the interrupt status.
|
||||
*/
|
||||
//-------------------------------------------------
|
||||
// z80daisy_irq_state - get interrupt status
|
||||
//-------------------------------------------------
|
||||
|
||||
int z80scc_device::z80daisy_irq_state()
|
||||
{
|
||||
int state = 0;
|
||||
@ -297,6 +315,9 @@ int z80scc_device::z80daisy_irq_state()
|
||||
state |= m_int_state[i];
|
||||
}
|
||||
|
||||
// Last chance to keep the control of the interrupt line
|
||||
state |= (m_wr9 & z80scc_channel::WR9_BIT_DLC) ? Z80_DAISY_IEO : 0;
|
||||
|
||||
LOG(("Interrupt State %u\n", state));
|
||||
|
||||
return state;
|
||||
@ -339,6 +360,15 @@ int z80scc_device::z80daisy_irq_ack()
|
||||
//-------------------------------------------------
|
||||
// z80daisy_irq_reti - return from interrupt
|
||||
//-------------------------------------------------
|
||||
/*
|
||||
SCC Interrupt Daisy-Chain Operation
|
||||
In the SCC, the IUS bit normally controls the state of the IEO line. The IP bit affects the daisy
|
||||
chain only during an Interrupt Acknowledge cycle. Since the IP bit is normally not part of the SCC
|
||||
interrupt daisy chain, there is no need to decode the RETI instruction. To allow for control over the
|
||||
daisy chain, the SCC has a Disable Lower Chain (DLC) software command (WR9 bit 2) that pulls IEO Low.
|
||||
|
||||
TODO: investigate removal of z80daisy_irq_reti() and rely entirely on rom software to activate IEO as SCC does
|
||||
*/
|
||||
|
||||
void z80scc_device::z80daisy_irq_reti()
|
||||
{
|
||||
@ -411,7 +441,7 @@ UINT8 z80scc_device::modify_vector(UINT8 vec, int i, UINT8 src)
|
||||
src |= (i == CHANNEL_A ? 0x04 : 0x00 );
|
||||
|
||||
// Modify vector according to Hi/lo bit of WR9
|
||||
if (m_chanA->m_wr9 & z80scc_channel::WR9_BIT_SHSL) // Affect V4-V6
|
||||
if (m_wr9 & z80scc_channel::WR9_BIT_SHSL) // Affect V4-V6
|
||||
{
|
||||
vec |= src << 4;
|
||||
}
|
||||
@ -428,7 +458,7 @@ UINT8 z80scc_device::modify_vector(UINT8 vec, int i, UINT8 src)
|
||||
//-------------------------------------------------
|
||||
void z80scc_device::trigger_interrupt(int index, int state)
|
||||
{
|
||||
UINT8 vector = m_chanB->m_wr2;
|
||||
UINT8 vector = m_chanA->m_rr2;
|
||||
UINT8 source = 0;
|
||||
int priority;
|
||||
|
||||
@ -437,7 +467,7 @@ void z80scc_device::trigger_interrupt(int index, int state)
|
||||
LOG(("%s %s:%c %02x \n",FUNCNAME, tag(), 'A' + index, state));
|
||||
|
||||
/* The Master Interrupt Enable (MIE) bit, WR9 D3, must be set to enable the SCC to generate interrupts.*/
|
||||
if (!(m_chanA->m_wr9 & z80scc_channel::WR9_BIT_MIE))
|
||||
if (!(m_wr9 & z80scc_channel::WR9_BIT_MIE))
|
||||
{
|
||||
LOG(("Master Interrupt Enable is not set, blocking attempt to interrupt\n"));
|
||||
return;
|
||||
@ -452,6 +482,12 @@ void z80scc_device::trigger_interrupt(int index, int state)
|
||||
source = 2;
|
||||
prio_level = 2;
|
||||
break;
|
||||
case z80scc_channel::INT_EXTERNAL:
|
||||
/* The External/status interrupts have several sources which may be individually enabled in WR15.
|
||||
The sources are zero count, /DCD, Sync/Hunt, /CTS, transmitter under-run/EOM and Break/Abort.*/
|
||||
source = 1;
|
||||
prio_level = 0;
|
||||
break;
|
||||
case z80scc_channel::INT_TRANSMIT:
|
||||
/*The NMOS/CMOS version of the SCC only has a one byte deep transmit buffer. The status of the
|
||||
transmit buffer can be determined through TBE bit in RR0, bit D2, which shows whether the
|
||||
@ -483,15 +519,15 @@ void z80scc_device::trigger_interrupt(int index, int state)
|
||||
}
|
||||
|
||||
// Vector modification requested?
|
||||
if (m_chanA->m_wr9 & z80scc_channel::WR9_BIT_VIS)
|
||||
if (m_wr9 & z80scc_channel::WR9_BIT_VIS)
|
||||
{
|
||||
vector = modify_vector(vector, index, source);
|
||||
}
|
||||
|
||||
LOG((" Interrupt Request fired of type %u and vector %02x\n", state, vector));
|
||||
|
||||
// update vector register // TODO: What if interrupts are nested? May we loose the modified vector or even get the wrong one?
|
||||
m_chanB->m_wr2 = vector;
|
||||
// update vector register
|
||||
m_chanB->m_rr2 = vector;
|
||||
|
||||
/* Check the interrupt source and build the vector modification */
|
||||
/*Interrupt Source Priority order
|
||||
@ -508,8 +544,9 @@ void z80scc_device::trigger_interrupt(int index, int state)
|
||||
// trigger interrupt
|
||||
m_int_state[priority] |= Z80_DAISY_INT;
|
||||
|
||||
// Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this... TODO: field needs blanking?
|
||||
m_chanA->m_rr3 |= (prio_level << (index == CHANNEL_A ? 3 : 0 ));
|
||||
// Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this...
|
||||
m_chanA->m_rr3 &= ~( 0x07 << (index == CHANNEL_A ? 3 : 0 ));
|
||||
m_chanA->m_rr3 |= (prio_level << (index == CHANNEL_A ? 3 : 0 ));
|
||||
|
||||
// check for interrupt
|
||||
check_interrupts();
|
||||
@ -526,6 +563,72 @@ int z80scc_device::m1_r()
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// zbus_r - Z-Bus read
|
||||
//-------------------------------------------------
|
||||
READ8_MEMBER( z80scc_device::zbus_r )
|
||||
{
|
||||
int ba = 0;
|
||||
int reg = 0x20; // Default point to a non register number
|
||||
UINT8 data = 0;
|
||||
|
||||
/* Expell non- Z-Bus variants */
|
||||
if ( !(m_variant & SET_Z80X30))
|
||||
{
|
||||
logerror(" zbus_r not supported by this device variant, you should probably use the universal bus variants c*_r/w and d*_r/w (see z80scc.h)\n");
|
||||
return data;
|
||||
}
|
||||
|
||||
switch ((m_chanB->m_wr0) & 7)
|
||||
{
|
||||
case z80scc_channel::WR0_Z_SEL_SHFT_LEFT: ba = offset & 0x01; reg = (offset >> 1) & 0x0f; break; /* Shift Left mode */
|
||||
case z80scc_channel::WR0_Z_SEL_SHFT_RIGHT: ba = offset & 0x10; reg = (offset >> 1) & 0x0f; break; /* Shift Right mode */
|
||||
default:
|
||||
logerror("Malformed Z-bus SCC read: offset %02x WR0 bits %02x\n", offset, m_chanB->m_wr0);
|
||||
LOG(("Malformed Z-bus SCC read: offset %02x WR0 bits %02x\n", offset, m_chanB->m_wr0));
|
||||
return data;
|
||||
}
|
||||
|
||||
if (ba == 0)
|
||||
data = m_chanB->scc_register_read(reg);
|
||||
else
|
||||
data = m_chanA->scc_register_read(reg);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// zbus_w - Z-Bus write
|
||||
//-------------------------------------------------
|
||||
WRITE8_MEMBER( z80scc_device::zbus_w )
|
||||
{
|
||||
int ba = 0;
|
||||
int reg = 0x20; // Default point to a non register number
|
||||
|
||||
/* Expell non- Z-Bus variants */
|
||||
if ( !(m_variant & SET_Z80X30))
|
||||
{
|
||||
logerror(" zbus_w not supported by this device variant, you should probably use the universal bus variants c*_r/w and d*_r/w (see z80scc.h)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch ((m_chanB->m_wr0) & 7)
|
||||
{
|
||||
case z80scc_channel::WR0_Z_SEL_SHFT_LEFT: ba = offset & 0x01; reg = (offset >> 1) & 0x0f; break; /* Shift Left mode */
|
||||
case z80scc_channel::WR0_Z_SEL_SHFT_RIGHT: ba = offset & 0x10; reg = (offset >> 1) & 0x0f; break; /* Shift Right mode */
|
||||
default:
|
||||
logerror("Malformed Z-bus SCC write: offset %02x WR0 bits %02x\n", offset, m_chanB->m_wr0);
|
||||
LOG(("Malformed Z-bus SCC write: offset %02x WR0 bits %02x\n", offset, m_chanB->m_wr0));
|
||||
}
|
||||
|
||||
if (ba == 0)
|
||||
m_chanB->scc_register_write(reg, data);
|
||||
else
|
||||
m_chanA->scc_register_write(reg, data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// cd_ba_r - Universal Bus read
|
||||
//-------------------------------------------------
|
||||
@ -593,7 +696,7 @@ READ8_MEMBER( z80scc_device::ba_cd_r )
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ba_cd_w -
|
||||
// ba_cd_w - Universal Bus write
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( z80scc_device::ba_cd_w )
|
||||
@ -618,7 +721,7 @@ WRITE8_MEMBER( z80scc_device::ba_cd_w )
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// ba_cd_r - Universal Bus read
|
||||
// ba_cd_inv_r - Universal Bus read
|
||||
//-------------------------------------------------
|
||||
|
||||
READ8_MEMBER( z80scc_device::ba_cd_inv_r )
|
||||
@ -640,7 +743,7 @@ READ8_MEMBER( z80scc_device::ba_cd_inv_r )
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ba_cd_w -
|
||||
// ba_cd_inv_w - Universal Bus read
|
||||
//-------------------------------------------------
|
||||
|
||||
WRITE8_MEMBER( z80scc_device::ba_cd_inv_w )
|
||||
@ -702,10 +805,10 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d
|
||||
LOG(("%s\n",FUNCNAME));
|
||||
|
||||
// Reset all registers
|
||||
m_rr0 = m_rr1 = m_rr2 = m_rr3 = m_rr4 = m_rr5 = m_rr6 = m_rr7 = m_rr8
|
||||
m_rr0 = m_rr1 = m_rr2 = m_rr3 = m_rr4 = m_rr5 = m_rr6 = m_rr7 = m_rr7p = m_rr8
|
||||
= m_rr9 = m_rr10 = m_rr11 = m_rr12 = m_rr13 = m_rr14 = m_rr15 = 0;
|
||||
m_wr0 = m_wr1 = m_wr2 = m_wr3 = m_wr4 = m_wr5 = m_wr6 = m_wr7 = m_wr8
|
||||
= m_wr9 = m_wr10 = m_wr11 = m_wr12 = m_wr13 = m_wr14 = m_wr15 = 0;
|
||||
m_wr0 = m_wr1 = m_wr2 = m_wr3 = m_wr4 = m_wr5 = m_wr6 = m_wr7 = m_wr7p = m_wr8
|
||||
= m_wr10 = m_wr11 = m_wr12 = m_wr13 = m_wr14 = m_wr15 = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++) // TODO adapt to SCC fifos
|
||||
{
|
||||
@ -744,6 +847,7 @@ void z80scc_channel::device_start()
|
||||
save_item(NAME(m_rr5));
|
||||
save_item(NAME(m_rr6));
|
||||
save_item(NAME(m_rr7));
|
||||
save_item(NAME(m_rr7p));
|
||||
save_item(NAME(m_rr8));
|
||||
save_item(NAME(m_rr9));
|
||||
save_item(NAME(m_rr10));
|
||||
@ -760,8 +864,8 @@ void z80scc_channel::device_start()
|
||||
save_item(NAME(m_wr5));
|
||||
save_item(NAME(m_wr6));
|
||||
save_item(NAME(m_wr7));
|
||||
save_item(NAME(m_wr7p));
|
||||
save_item(NAME(m_wr8));
|
||||
save_item(NAME(m_wr9));
|
||||
save_item(NAME(m_wr10));
|
||||
save_item(NAME(m_wr11));
|
||||
save_item(NAME(m_wr12));
|
||||
@ -810,10 +914,11 @@ void z80scc_channel::device_reset()
|
||||
m_wr5 &= 0x61;
|
||||
if (m_uart->m_variant & (z80scc_device::TYPE_SCC85C30 | SET_ESCC))
|
||||
m_wr7 = 0x20;
|
||||
m_wr9 &= 0xdf; // WR9 has a different hard reset value
|
||||
m_wr10 &= 0x60; // WR10 has a different hard reset value
|
||||
m_wr11 &= 0xff; // WR11 has a different hard reset value
|
||||
m_wr14 &= 0xc3; // WR14 has a different hard reset value
|
||||
// WR9,WR10,WR11 and WR14 has a different hard reset (see z80scc_device::device_reset()) values
|
||||
m_uart->m_wr9 &= 0xdf;
|
||||
m_wr10 &= 0x60;
|
||||
m_wr11 &= 0xff;
|
||||
m_wr14 &= 0xc3;
|
||||
m_wr14 |= 0x20;
|
||||
m_wr15 = 0xf8;
|
||||
m_rr0 &= 0xfc;
|
||||
@ -1304,6 +1409,7 @@ UINT8 z80scc_channel::do_sccreg_rr11()
|
||||
RR12 returns the value stored in WR12, the lower byte of the time constant, for the BRG.*/
|
||||
UINT8 z80scc_channel::do_sccreg_rr12()
|
||||
{
|
||||
LOGR(("%s\n", FUNCNAME));
|
||||
return m_wr12;
|
||||
}
|
||||
|
||||
@ -1311,6 +1417,7 @@ UINT8 z80scc_channel::do_sccreg_rr12()
|
||||
RR13 returns the value stored in WR13, the upper byte of the time constant for the BRG. */
|
||||
UINT8 z80scc_channel::do_sccreg_rr13()
|
||||
{
|
||||
LOGR(("%s\n", FUNCNAME));
|
||||
return m_wr13;
|
||||
}
|
||||
|
||||
@ -1337,6 +1444,67 @@ UINT8 z80scc_channel::do_sccreg_rr15()
|
||||
return m_wr15 & 0xf5; // Mask out the used bits
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// scc_register_read - read a SCC register
|
||||
//-------------------------------------------------
|
||||
UINT8 z80scc_channel::scc_register_read( UINT8 reg)
|
||||
{
|
||||
if (reg > 1)
|
||||
LOG(("%s %02x\n", FUNCNAME, reg));
|
||||
UINT8 data = 0;
|
||||
UINT8 wreg = 0;
|
||||
|
||||
/* Sort out 80X30 limitations in register access */
|
||||
// if ((BIT(m_wr15, 2) == 0) || m_uart->m_variant == z80scc_device::TYPE_SCC8030)
|
||||
if (BIT(m_wr15, 2) == 0 || m_uart->m_variant & SET_NMOS)
|
||||
{
|
||||
if (reg > 3 && reg < 8) reg &= 0x03;
|
||||
else if (reg == 9) reg = 13;
|
||||
else if (reg == 11) reg = 15;
|
||||
}
|
||||
else if (BIT(m_wr15, 2) != 0)
|
||||
{
|
||||
// if (m_uart->variant == z80scc_device::TYPE_SCC80230 && BIT(m_wr7p, 6) != 0)
|
||||
if (m_uart->m_variant & SET_ESCC && BIT(m_wr7p, 6) != 0)
|
||||
{
|
||||
if (reg > 3 && reg < 6) wreg = 1;
|
||||
else if (reg == 9) { reg = 3; wreg = 1; }
|
||||
else if (reg == 11) { reg = 10; wreg = 1; }
|
||||
else if (reg == 14) { reg = 7; wreg = 1; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (reg > 3 && reg < 6) reg &= 3;
|
||||
else if (reg == 9) { reg = 13; }
|
||||
else if (reg == 11) { reg = 15; }
|
||||
}
|
||||
}
|
||||
switch (reg)
|
||||
{
|
||||
case REG_RR0_STATUS: data = do_sccreg_rr0(); break; // TODO: verify handling of SCC specific bits: D6 and D1
|
||||
case REG_RR1_SPEC_RCV_COND: data = do_sccreg_rr1(); break;
|
||||
case REG_RR2_INTERRUPT_VECT: data = do_sccreg_rr2(); break; // Channel dependent and SCC specific handling compared to SIO
|
||||
/* registers 3-7 are specific to SCC. TODO: Check variant and log/stop misuse */
|
||||
case REG_RR3_INTERUPPT_PEND: data = wreg ? m_wr3 : do_sccreg_rr3(); break;
|
||||
case REG_RR4_WR4_OR_RR0: data = wreg ? m_wr4 : do_sccreg_rr4(); break;
|
||||
case REG_RR5_WR5_OR_RR0: data = wreg ? m_wr5 : do_sccreg_rr5(); break;
|
||||
case REG_RR6_LSB_OR_RR2: data = do_sccreg_rr6(); break;
|
||||
case REG_RR7_MSB_OR_RR3: data = wreg ? m_wr7p : do_sccreg_rr7(); break;
|
||||
/* registers 8-15 are specific to SCC */
|
||||
case REG_RR8_RECEIVE_DATA: data = data_read(); break;
|
||||
case REG_RR9_WR3_OR_RR13: data = do_sccreg_rr9(); break;
|
||||
case REG_RR10_MISC_STATUS: data = wreg ? m_wr10 : do_sccreg_rr10(); break;
|
||||
case REG_RR11_WR10_OR_RR15: data = do_sccreg_rr11(); break;
|
||||
case REG_RR12_LO_TIME_CONST: data = do_sccreg_rr12(); break;
|
||||
case REG_RR13_HI_TIME_CONST: data = do_sccreg_rr13(); break;
|
||||
case REG_RR14_WR7_OR_R10: data = do_sccreg_rr14(); break;
|
||||
case REG_RR15_WR15_EXT_STAT: data = do_sccreg_rr15(); break;
|
||||
default:
|
||||
logerror(" \"%s\" %s: %c : Unsupported RRx register:%02x\n", m_owner->tag(), FUNCNAME, 'A' + m_index, reg);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// control_read - read control register
|
||||
//-------------------------------------------------
|
||||
@ -1357,30 +1525,7 @@ UINT8 z80scc_channel::control_read()
|
||||
m_wr0 &= ~regmask;
|
||||
}
|
||||
|
||||
/* TODO. Sort out 80X30 limitations in register access */
|
||||
switch (reg)
|
||||
{
|
||||
case REG_RR0_STATUS: data = do_sccreg_rr0(); break; // TODO: verify handling of SCC specific bits: D6 and D1
|
||||
case REG_RR1_SPEC_RCV_COND: data = do_sccreg_rr1(); break;
|
||||
case REG_RR2_INTERRUPT_VECT: data = do_sccreg_rr2(); break; // Channel dependent and SCC specific handling compared to SIO
|
||||
/* registers 3-7 are specific to SCC. TODO: Check variant and log/stop misuse */
|
||||
case REG_RR3_INTERUPPT_PEND: data = do_sccreg_rr3(); break;
|
||||
case REG_RR4_WR4_OR_RR0: data = do_sccreg_rr4(); break;
|
||||
case REG_RR5_WR5_OR_RR0: data = do_sccreg_rr5(); break;
|
||||
case REG_RR6_LSB_OR_RR2: data = do_sccreg_rr6(); break;
|
||||
case REG_RR7_MSB_OR_RR3: data = do_sccreg_rr7(); break;
|
||||
/* registers 8-15 are specific to SCC */
|
||||
case REG_RR8_RECEIVE_DATA: data = data_read(); break;
|
||||
case REG_RR9_WR3_OR_RR13: data = do_sccreg_rr9(); break;
|
||||
case REG_RR10_MISC_STATUS: data = do_sccreg_rr10(); break;
|
||||
case REG_RR11_WR10_OR_RR15: data = do_sccreg_rr11(); break;
|
||||
case REG_RR12_LO_TIME_CONST: data = do_sccreg_rr12(); break;
|
||||
case REG_RR13_HI_TIME_CONST: data = do_sccreg_rr13(); break;
|
||||
case REG_RR14_WR7_OR_R10: data = do_sccreg_rr14(); break;
|
||||
case REG_RR15_WR15_EXT_STAT: data = do_sccreg_rr15(); break;
|
||||
default:
|
||||
logerror(" \"%s\" %s: %c : Unsupported RRx register:%02x\n", m_owner->tag(), FUNCNAME, 'A' + m_index, reg);
|
||||
}
|
||||
data = scc_register_read(reg);
|
||||
|
||||
//LOG(("%s \"%s\": %c : Register R%d read '%02x'\n", FUNCNAME, m_owner->tag(), 'A' + m_index, reg, data));
|
||||
return data;
|
||||
@ -1430,7 +1575,6 @@ void z80scc_channel::do_sccreg_wr0(UINT8 data)
|
||||
if (m_uart->m_variant & SET_Z85X3X)
|
||||
{
|
||||
LOG(("%s %s: %c : - Point High command\n", FUNCNAME, m_owner->tag(), 'A' + m_index));
|
||||
//m_ph = 8;
|
||||
m_uart->m_wr0_ptrbits |= 8;
|
||||
}
|
||||
else
|
||||
@ -1459,8 +1603,17 @@ void z80scc_channel::do_sccreg_wr0(UINT8 data)
|
||||
/* This command resets the highest priority Interrupt Under Service (IUS) bit, allowing lower
|
||||
priority conditions to request interrupts. This command allows the use of the internal
|
||||
daisy chain (even in systems without an external daisy chain) and is the last operation in
|
||||
an interrupt service routine.TODO: Implement internal Daisychain */
|
||||
LOG(("\"%s\" %s: %c : Reset Highest IUS\n", m_owner->tag(), FUNCNAME, 'A' + m_index));
|
||||
an interrupt service routine. */
|
||||
if (m_uart->m_variant & (SET_NMOS))
|
||||
{
|
||||
logerror("WR0 SWI ack command not supported on NMOS\n");
|
||||
LOG(("\"%s\" %s: %c : Reset Highest IUS command not available on NMOS!\n", m_owner->tag(), FUNCNAME, 'A' + m_index));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uart->z80daisy_irq_ack();
|
||||
LOG(("\"%s\" %s: %c : Reset Highest IUS\n", m_owner->tag(), FUNCNAME, 'A' + m_index));
|
||||
}
|
||||
break;
|
||||
case WR0_ERROR_RESET:
|
||||
/*Error Reset Command (110). This command resets the error bits in RR1. If interrupt on first Rx
|
||||
@ -1663,13 +1816,7 @@ at the same time as the Reset command, because these bits are only reset by a ha
|
||||
note that the Z80X30 contains only one WR2 and WR9; these registers may be written from either channel.*/
|
||||
void z80scc_channel::do_sccreg_wr9(UINT8 data)
|
||||
{
|
||||
if (m_uart->m_variant & SET_Z80X30)
|
||||
{
|
||||
m_uart->m_chanA->m_wr9 = data;
|
||||
m_uart->m_chanB->m_wr9 = data;
|
||||
}
|
||||
else
|
||||
m_wr9 = data;
|
||||
m_uart->m_wr9 = data; // There is only one WR9 register and is written from both channels A and B (if exists)
|
||||
|
||||
switch (data & WR9_CMD_MASK)
|
||||
{
|
||||
@ -1688,10 +1835,22 @@ void z80scc_channel::do_sccreg_wr9(UINT8 data)
|
||||
LOG(("\"%s\": %c : Master Interrupt Control - Device reset %02x\n", m_owner->tag(), 'A' + m_index, data));
|
||||
/*"The effects of this command are identical to those of a hardware reset, except that the Shift Right/Shift Left bit is
|
||||
not changed and the MIE, Status High/Status Low and DLC bits take the programmed values that accompany this command."
|
||||
The Shift Right/Shift Left bits of the WR0 is only valid on SCC8030 device hence not implemented yet, just the SCC8530 */
|
||||
if (data & (WR9_BIT_MIE | WR9_BIT_IACK | WR9_BIT_SHSL | WR9_BIT_DLC | WR9_BIT_NV))
|
||||
logerror(" SCC Interrupt system not yet implemented, please be patient.\n");
|
||||
m_uart->device_reset();
|
||||
*/
|
||||
if (m_uart->m_variant & SET_Z80X30)
|
||||
{
|
||||
UINT8 tmp_wr0 = m_wr0; // Save the Shift Left/Shift Right bits
|
||||
m_uart->device_reset();
|
||||
// Restore the Shift Left/Shift Right bits
|
||||
m_wr0 &= 0xfc;
|
||||
m_wr0 |= (tmp_wr0 & 0x03);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uart->device_reset();
|
||||
}
|
||||
// Set the MIE, Status High/Status Low and DLC bits as given in this command
|
||||
m_uart->m_wr9 &= ~(WR9_BIT_MIE | WR9_BIT_SHSL | WR9_BIT_DLC );
|
||||
m_uart->m_wr9 |= (data & (WR9_BIT_MIE | WR9_BIT_SHSL | WR9_BIT_DLC ));
|
||||
break;
|
||||
default:
|
||||
logerror("Code is broken in WR9, please report!\n");
|
||||
@ -1908,17 +2067,47 @@ void z80scc_channel::do_sccreg_wr14(UINT8 data)
|
||||
as a group via WR1, bits in this register control which External/Status conditions cause an interrupt.
|
||||
Only the External/Status conditions that occur after the controlling bit is set to 1 cause an
|
||||
interrupt. This is true, even if an External/Status condition is pending at the time the bit is set*/
|
||||
#define WR15EN "enabled"
|
||||
#define WR15NO "not implemented"
|
||||
void z80scc_channel::do_sccreg_wr15(UINT8 data)
|
||||
{
|
||||
LOG(("%s(%02x) \"%s\": %c : External/Status Control Bits - not implemented\n",
|
||||
LOGINT(("%s(%02x) \"%s\": %c : External/Status Control Bits\n",
|
||||
FUNCNAME, data, m_owner->tag(), 'A' + m_index));
|
||||
LOGINT(("WR7 prime ints : %s\n", data & WR15_WR7PRIME ? WR15NO : "disabled"));
|
||||
LOGINT(("Zero count ints : %s\n", data & WR15_ZEROCOUNT ? WR15NO : "disabled"));
|
||||
LOGINT(("14 bit Status FIFO : %s\n", data & WR15_STATUS_FIFO ? WR15NO : "disabled"));
|
||||
LOGINT(("DCD ints : %s\n", data & WR15_DCD ? WR15EN : "disabled"));
|
||||
LOGINT(("SYNC/Hunt ints : %s\n", data & WR15_SYNC ? WR15NO : "disabled"));
|
||||
LOGINT(("CTS ints : %s\n", data & WR15_CTS ? WR15EN : "disabled"));
|
||||
LOGINT(("Tx underr./EOM ints: %s\n", data & WR15_TX_EOM ? WR15NO : "disabled"));
|
||||
LOGINT(("Break/Abort ints : %s\n", data & WR15_BREAK_ABORT ? WR15NO : "disabled"));
|
||||
m_wr15 = data;
|
||||
}
|
||||
|
||||
/*TODO: Z80X30 Register Access
|
||||
----------------------------
|
||||
The Shift Right/Shift Left bit in the Channel B WR0 controls which bits are decoded to form the register
|
||||
address. See do_sccreg_wr0() for details */
|
||||
void z80scc_channel::scc_register_write(UINT8 reg, UINT8 data)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case REG_WR0_COMMAND_REGPT: do_sccreg_wr0(data); break;
|
||||
case REG_WR1_INT_DMA_ENABLE: do_sccreg_wr1(data); m_uart->check_interrupts(); break;
|
||||
case REG_WR2_INT_VECTOR: do_sccreg_wr2(data); break;
|
||||
case REG_WR3_RX_CONTROL: do_sccreg_wr3(data); break;
|
||||
case REG_WR4_RX_TX_MODES: do_sccreg_wr4(data); break;
|
||||
case REG_WR5_TX_CONTROL: do_sccreg_wr5(data); break;
|
||||
case REG_WR6_SYNC_OR_SDLC_A: do_sccreg_wr6(data); break;
|
||||
case REG_WR7_SYNC_OR_SDLC_F: do_sccreg_wr7(data); break;
|
||||
case REG_WR8_TRANSMIT_DATA: do_sccreg_wr8(data); break;
|
||||
case REG_WR9_MASTER_INT_CTRL: do_sccreg_wr9(data); break;
|
||||
case REG_WR10_MSC_RX_TX_CTRL: do_sccreg_wr10(data); break;
|
||||
case REG_WR11_CLOCK_MODES: do_sccreg_wr11(data); break;
|
||||
case REG_WR12_LO_BAUD_GEN: do_sccreg_wr12(data); break;
|
||||
case REG_WR13_HI_BAUD_GEN: do_sccreg_wr13(data); break;
|
||||
case REG_WR14_MISC_CTRL: do_sccreg_wr14(data); break;
|
||||
case REG_WR15_EXT_ST_INT_CTRL: do_sccreg_wr15(data); break;
|
||||
default:
|
||||
logerror("\"%s\": %c : Unsupported WRx register:%02x\n", m_owner->tag(), 'A' + m_index, reg);
|
||||
}
|
||||
}
|
||||
|
||||
/*Z85X30 Register Access
|
||||
-----------------------
|
||||
@ -1959,28 +2148,7 @@ void z80scc_channel::control_write(UINT8 data)
|
||||
//LOG(("\n%s(%02x) reg %02x, regmask %02x\n", FUNCNAME, data, reg, regmask));
|
||||
LOGSETUP((" * %s %c Reg %02x <- %02x \n", m_owner->tag(), 'A' + m_index, reg, data));
|
||||
|
||||
/* TODO. Sort out 80X30 & other SCC variants limitations in register access */
|
||||
switch (reg)
|
||||
{
|
||||
case REG_WR0_COMMAND_REGPT: do_sccreg_wr0(data); break;
|
||||
case REG_WR1_INT_DMA_ENABLE: do_sccreg_wr1(data); m_uart->check_interrupts(); break;
|
||||
case REG_WR2_INT_VECTOR: do_sccreg_wr2(data); break;
|
||||
case REG_WR3_RX_CONTROL: do_sccreg_wr3(data); break;
|
||||
case REG_WR4_RX_TX_MODES: do_sccreg_wr4(data); break;
|
||||
case REG_WR5_TX_CONTROL: do_sccreg_wr5(data); break;
|
||||
case REG_WR6_SYNC_OR_SDLC_A: do_sccreg_wr6(data); break;
|
||||
case REG_WR7_SYNC_OR_SDLC_F: do_sccreg_wr7(data); break;
|
||||
case REG_WR8_TRANSMIT_DATA: do_sccreg_wr8(data); break;
|
||||
case REG_WR9_MASTER_INT_CTRL: do_sccreg_wr9(data); break;
|
||||
case REG_WR10_MSC_RX_TX_CTRL: do_sccreg_wr10(data); break;
|
||||
case REG_WR11_CLOCK_MODES: do_sccreg_wr11(data); break;
|
||||
case REG_WR12_LO_BAUD_GEN: do_sccreg_wr12(data); break;
|
||||
case REG_WR13_HI_BAUD_GEN: do_sccreg_wr13(data); break;
|
||||
case REG_WR14_MISC_CTRL: do_sccreg_wr14(data); break;
|
||||
case REG_WR15_EXT_ST_INT_CTRL: do_sccreg_wr15(data); break;
|
||||
default:
|
||||
logerror("\"%s\": %c : Unsupported WRx register:%02x\n", m_owner->tag(), 'A' + m_index, reg);
|
||||
}
|
||||
scc_register_write(reg, data);
|
||||
}
|
||||
|
||||
|
||||
@ -2191,8 +2359,13 @@ WRITE_LINE_MEMBER( z80scc_channel::cts_w )
|
||||
else
|
||||
m_rr0 &= ~RR0_CTS;
|
||||
|
||||
// trigger interrupt
|
||||
if (m_wr1 & WR1_EXT_INT_ENABLE)
|
||||
/* If the CTS IE bit in WR15 is set, this bit indicates the state of the /CTS pin while no interrupt is
|
||||
pending, latches the state of the /CTS pin and generates an External/Status interrupt. Any odd
|
||||
number of transitions on the /CTS pin causes another External/Status interrupt condition. If the
|
||||
CTS IE bit is reset, it merely reports the current unlatched state of the /CTS pin.
|
||||
|
||||
Check that external interrupts are enabled and this one in particular and generate an interrupt on any change */
|
||||
if ((m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_CTS))
|
||||
{
|
||||
// trigger interrupt
|
||||
m_uart->trigger_interrupt(m_index, INT_EXTERNAL);
|
||||
@ -2235,7 +2408,14 @@ WRITE_LINE_MEMBER( z80scc_channel::dcd_w )
|
||||
else
|
||||
m_rr0 &= ~RR0_DCD;
|
||||
|
||||
if (m_wr1 & WR1_EXT_INT_ENABLE)
|
||||
/* If the DCD IE bit in WR15 is set, this bit indicates the state of the /DCD pin the last time the
|
||||
Enabled External/Status bits changed. Any transition on the /DCD pin, while no interrupt is pending,
|
||||
latches the state of the /DCD pin and generates an External/Status interrupt. Any odd number
|
||||
of transitions on the /DCD pin while another External/Status interrupt condition. If the DCD IE is
|
||||
reset, this bit merely reports the current, unlatched state of the /DCD pin.
|
||||
|
||||
Check that external interrupts are enabled and this one in particular and generate an interrupt on any change */
|
||||
if ((m_wr1 & WR1_EXT_INT_ENABLE) && (m_wr15 & WR15_DCD))
|
||||
{
|
||||
// trigger interrupt
|
||||
m_uart->trigger_interrupt(m_index, INT_EXTERNAL);
|
||||
@ -2333,7 +2513,9 @@ WRITE_LINE_MEMBER( z80scc_channel::rxc_w )
|
||||
|
||||
m_rx_clock++;
|
||||
if (m_rx_clock == clocks)
|
||||
{
|
||||
m_rx_clock = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2462,8 +2644,6 @@ void z80scc_channel::set_dtr(int state)
|
||||
m_uart->m_out_dtrb_cb(m_dtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// write_rx - called by terminal through rs232/diserial
|
||||
// when character is sent to board
|
||||
|
@ -169,6 +169,7 @@ public:
|
||||
UINT8 do_sccreg_rr5();
|
||||
UINT8 do_sccreg_rr6();
|
||||
UINT8 do_sccreg_rr7();
|
||||
UINT8 do_sccreg_rr7p(){ return 0; } // Needs to be implemented for Synchronous mode
|
||||
// UINT8 do_sccreg_rr8(); Short cutted due to frequent use
|
||||
UINT8 do_sccreg_rr9();
|
||||
UINT8 do_sccreg_rr10();
|
||||
@ -188,6 +189,7 @@ public:
|
||||
void do_sccreg_wr5(UINT8 data);
|
||||
void do_sccreg_wr6(UINT8 data);
|
||||
void do_sccreg_wr7(UINT8 data);
|
||||
void do_sccreg_wr7p(UINT8 data){}; // Needs to be implemented for Synchronous mode
|
||||
void do_sccreg_wr8(UINT8 data);
|
||||
void do_sccreg_wr9(UINT8 data);
|
||||
void do_sccreg_wr10(UINT8 data);
|
||||
@ -228,6 +230,7 @@ public:
|
||||
UINT8 m_rr5; // REG_RR5_WR5_OR_RR0
|
||||
UINT8 m_rr6; // REG_RR6_LSB_OR_RR2
|
||||
UINT8 m_rr7; // REG_RR7_MSB_OR_RR3
|
||||
UINT8 m_rr7p;
|
||||
UINT8 m_rr8; // REG_RR8_RECEIVE_DATA
|
||||
UINT8 m_rr9; // REG_RR9_WR3_OR_RR13
|
||||
UINT8 m_rr10; // REG_RR10_MISC_STATUS
|
||||
@ -246,8 +249,9 @@ public:
|
||||
UINT8 m_wr5; // REG_WR5_TX_CONTROL
|
||||
UINT8 m_wr6; // REG_WR6_SYNC_OR_SDLC_A
|
||||
UINT8 m_wr7; // REG_WR7_SYNC_OR_SDLC_F
|
||||
UINT8 m_wr7p; //
|
||||
UINT8 m_wr8; // REG_WR8_TRANSMIT_DATA
|
||||
UINT8 m_wr9; // REG_WR9_MASTER_INT_CTRL
|
||||
// UINT8 m_wr9; // REG_WR9_MASTER_INT_CTRL
|
||||
UINT8 m_wr10; // REG_WR10_MSC_RX_TX_CTRL
|
||||
UINT8 m_wr11; // REG_WR11_CLOCK_MODES
|
||||
UINT8 m_wr12; // REG_WR12_LO_BAUD_GEN
|
||||
@ -506,7 +510,19 @@ protected:
|
||||
WR14_BRG_SOURCE = 0x02,
|
||||
WR14_DTR_REQ_FUNC = 0x04,
|
||||
WR14_AUTO_ECHO = 0x08,
|
||||
WR14_LOCAL_LOOPBACK = 0x010
|
||||
WR14_LOCAL_LOOPBACK = 0x10
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR15_WR7PRIME = 0x01,
|
||||
WR15_ZEROCOUNT = 0x02,
|
||||
WR15_STATUS_FIFO = 0x04,
|
||||
WR15_DCD = 0x08,
|
||||
WR15_SYNC = 0x10,
|
||||
WR15_CTS = 0x20,
|
||||
WR15_TX_EOM = 0x40,
|
||||
WR15_BREAK_ABORT = 0x80
|
||||
};
|
||||
|
||||
enum
|
||||
@ -526,6 +542,8 @@ protected:
|
||||
unsigned int m_delayed_tx_brg_change;
|
||||
unsigned int m_brg_const;
|
||||
|
||||
void scc_register_write(UINT8 reg, UINT8 data);
|
||||
UINT8 scc_register_read(UINT8 reg);
|
||||
void update_serial();
|
||||
void set_dtr(int state);
|
||||
void set_rts(int state);
|
||||
@ -631,9 +649,15 @@ public:
|
||||
DECLARE_READ8_MEMBER( cb_r ) { return m_chanB->control_read(); }
|
||||
DECLARE_WRITE8_MEMBER( cb_w ) { m_chanB->control_write(data); }
|
||||
|
||||
DECLARE_READ8_MEMBER( zbus_r );
|
||||
DECLARE_WRITE8_MEMBER( zbus_w );
|
||||
|
||||
// interrupt acknowledge
|
||||
int m1_r();
|
||||
|
||||
// Single registers instances accessed from both channels
|
||||
UINT8 m_wr9; // REG_WR9_MASTER_INT_CTRL
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( rxa_w ) { m_chanA->write_rx(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( rxb_w ) { m_chanB->write_rx(state); }
|
||||
DECLARE_WRITE_LINE_MEMBER( ctsa_w ) { m_chanA->cts_w(state); }
|
||||
|
Loading…
Reference in New Issue
Block a user