mirror of
https://github.com/holub/mame
synced 2025-04-21 16:01:56 +03:00
- Added correct reset values
- Added correct read FIFO depths for the different SCC variants - Started work on interrupt system, not verified/debugged due to lack of software - Added conditonal compile for MVC and GCC LOG messages to sort out differences - Cleaned up LOG messages
This commit is contained in:
parent
e96f45034d
commit
e421e79c01
@ -84,6 +84,14 @@ TODO:
|
||||
#define logerror printf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define LLFORMAT "%I64%"
|
||||
#define FUNCNAME __func__
|
||||
#else
|
||||
#define LLFORMAT "%lld"
|
||||
#define FUNCNAME __PRETTY_FUNCTION__
|
||||
#endif
|
||||
|
||||
#define CHANA_TAG "cha"
|
||||
#define CHANB_TAG "chb"
|
||||
|
||||
@ -149,7 +157,7 @@ z80scc_device::z80scc_device(const machine_config &mconfig, device_type type, co
|
||||
m_out_txdrqb_cb(*this),
|
||||
m_variant(variant)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_int_state[i] = 0;
|
||||
}
|
||||
|
||||
@ -179,7 +187,7 @@ z80scc_device::z80scc_device(const machine_config &mconfig, const char *tag, dev
|
||||
m_out_txdrqb_cb(*this),
|
||||
m_variant(TYPE_Z80SCC)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_int_state[i] = 0;
|
||||
}
|
||||
|
||||
@ -213,6 +221,7 @@ scc8523L_device::scc8523L_device(const machine_config &mconfig, const char *tag,
|
||||
|
||||
void z80scc_device::device_start()
|
||||
{
|
||||
LOG(("%s\n", FUNCNAME));
|
||||
// resolve callbacks
|
||||
m_out_txda_cb.resolve_safe();
|
||||
m_out_dtra_cb.resolve_safe();
|
||||
@ -249,12 +258,17 @@ void z80scc_device::device_start()
|
||||
|
||||
void z80scc_device::device_reset()
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Reset\n", tag()));
|
||||
LOG(("%s %s \n",FUNCNAME, tag()));
|
||||
|
||||
m_chanA->reset();
|
||||
m_chanB->reset();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.*/
|
||||
//-------------------------------------------------
|
||||
// z80daisy_irq_state - get interrupt status
|
||||
//-------------------------------------------------
|
||||
@ -269,7 +283,7 @@ int z80scc_device::z80daisy_irq_state()
|
||||
m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]));
|
||||
|
||||
// loop over all interrupt sources
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
// if we're servicing a request, don't indicate more interrupts
|
||||
if (m_int_state[i] & Z80_DAISY_IEO)
|
||||
@ -297,7 +311,7 @@ int z80scc_device::z80daisy_irq_ack()
|
||||
LOG(("Z80SCC \"%s\" Interrupt Acknowledge\n", tag()));
|
||||
|
||||
// loop over all interrupt sources
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
// find the first channel with an interrupt requested
|
||||
if (m_int_state[i] & Z80_DAISY_INT)
|
||||
@ -330,7 +344,7 @@ void z80scc_device::z80daisy_irq_reti()
|
||||
LOG(("Z80SCC \"%s\" Return from Interrupt\n", tag()));
|
||||
|
||||
// loop over all interrupt sources
|
||||
for (i = 0; i < 8; i++)
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
// find the first channel with an IEO pending
|
||||
if (m_int_state[i] & Z80_DAISY_IEO)
|
||||
@ -352,8 +366,8 @@ void z80scc_device::z80daisy_irq_reti()
|
||||
|
||||
void z80scc_device::check_interrupts()
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" : check_interrupts\n", m_owner->tag()));
|
||||
int state = (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE;
|
||||
LOG(("Z80SCC \"%s\" : %s() state = %d\n", m_owner->tag(), __func__, state));
|
||||
m_out_int_cb(state);
|
||||
}
|
||||
|
||||
@ -364,85 +378,135 @@ void z80scc_device::check_interrupts()
|
||||
|
||||
void z80scc_device::reset_interrupts()
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
// reset internal interrupi sources
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_int_state[i] = 0;
|
||||
}
|
||||
|
||||
// check external interrupt sources
|
||||
check_interrupts();
|
||||
}
|
||||
|
||||
UINT8 z80scc_device::modify_vector(UINT8 vec, int i, UINT8 src)
|
||||
{
|
||||
/*
|
||||
Interrupt Vector Modification
|
||||
V3 V2 V1 Status High/Status Low =0
|
||||
V4 V5 V6 Status High/Status Low =1
|
||||
0 0 0 Ch B Transmit Buffer Empty
|
||||
0 0 1 Ch B External/Status Change
|
||||
0 1 0 Ch B Receive Char. Available
|
||||
0 1 1 Ch B Special Receive Condition
|
||||
1 0 0 Ch A Transmit Buffer Empty
|
||||
1 0 1 Ch A External/Status Change
|
||||
1 1 0 Ch A Receive Char. Available
|
||||
1 1 1 Ch A Special Receive Condition
|
||||
*/
|
||||
// Add channel offset according to table above
|
||||
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
|
||||
{
|
||||
vec |= src << 4;
|
||||
}
|
||||
else // Affect V1-V3
|
||||
{
|
||||
vec |= src << 1;
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// trigger_interrupt -
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80scc_device::trigger_interrupt(int index, int state)
|
||||
{
|
||||
#if 0 // TODO: SIO code Needs to be adapted for SCC
|
||||
UINT8 vector = m_chanB->m_wr2;
|
||||
UINT8 source = 0;
|
||||
int priority;
|
||||
|
||||
int prio_level = 0;
|
||||
|
||||
if((m_variant == TYPE_I8274) || (m_variant == TYPE_UPD7201))
|
||||
{
|
||||
int prio_level = 0;
|
||||
switch(state)
|
||||
{
|
||||
case z80scc_channel::INT_TRANSMIT:
|
||||
prio_level = 1;
|
||||
break;
|
||||
case z80scc_channel::INT_RECEIVE:
|
||||
case z80scc_channel::INT_SPECIAL:
|
||||
prio_level = 0;
|
||||
break;
|
||||
case z80scc_channel::INT_EXTERNAL:
|
||||
prio_level = 2;
|
||||
break;
|
||||
}
|
||||
/* 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))
|
||||
{
|
||||
LOG(("Master Interrupt Enable is not set, blocking attempt to interrupt\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_chanA->m_wr2 & z80scc_channel::WR2_PRIORITY)
|
||||
{
|
||||
priority = (prio_level * 2) + index;
|
||||
}
|
||||
else
|
||||
{
|
||||
priority = (prio_level == 2) ? index + 4 : ((index * 2) + prio_level);
|
||||
}
|
||||
if (m_chanB->m_wr1 & z80scc_channel::WR1_STATUS_VECTOR)
|
||||
{
|
||||
vector = (!index << 2) | state;
|
||||
if((m_chanA->m_wr1 & 0x18) == z80scc_channel::WR2_MODE_8086_8088)
|
||||
{
|
||||
vector = (m_chanB->m_wr2 & 0xf8) | vector;
|
||||
}
|
||||
else
|
||||
{
|
||||
vector = (m_chanB->m_wr2 & 0xe3) | (vector << 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
switch(state)
|
||||
{
|
||||
priority = (index << 2) | state;
|
||||
if (m_chanB->m_wr1 & z80scc_channel::WR1_STATUS_VECTOR)
|
||||
{
|
||||
// status affects vector
|
||||
vector = (m_chanB->m_wr2 & 0xf1) | (!index << 3) | (state << 1);
|
||||
}
|
||||
// }
|
||||
case z80scc_channel::INT_RECEIVE:
|
||||
/*The sources of receive interrupts consist of Receive Character Available and Special Receive Condition.
|
||||
The Special Receive Condition can be subdivided into Receive Overrun, Framing Error (Asynchronous) or
|
||||
End of Frame (SDLC). In addition, a parity error can be a special receive condition by programming*/
|
||||
source = 2;
|
||||
prio_level = 2;
|
||||
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
|
||||
transmit buffer is empty or not. After a hardware reset (including a hardware reset by software), or
|
||||
a channel reset, this bit is set to 1.
|
||||
While transmit interrupts are enabled, the NMOS/CMOS version sets the Transmit Interrupt Pending
|
||||
(TxIP) bit whenever the transmit buffer becomes empty. This means that the transmit buffer
|
||||
must be full before the TxIP can be set. Thus, when transmit interrupts are first enabled, the TxIP
|
||||
will not be set until after the first character is written to the NMOS/CMOS.*/
|
||||
source = 0;
|
||||
prio_level = 1;
|
||||
break;
|
||||
case z80scc_channel::INT_SPECIAL:
|
||||
/*This mode allows the receiver to interrupt only on
|
||||
characters with a special receive condition. When an interrupt occurs, the data containing the error
|
||||
is held in the Receive FIFO until an Error Reset command is issued. When using this mode in conjunction
|
||||
with a DMA, the DMA is initialized and enabled before any characters have been
|
||||
received by the ESCC. This eliminates the time-critical section of code required in the Receive
|
||||
Interrupt on First Character or Special Condition mode. Hence, all data can be transferred via the
|
||||
DMA so that the CPU need not handle the first received character as a special case. In SDLC
|
||||
mode, if the SDLC Frame Status FIFO is enabled and an EOF is received, an interrupt with vector
|
||||
for receive data available is generated and the Receive FIFO is not locked.*/
|
||||
source = 3;
|
||||
prio_level = 0;
|
||||
break;
|
||||
default:
|
||||
logerror("Attempt to trigger interrupt of unknown origin blocked: %02x on channel %c\n", state, 'A' + index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Vector modification requested?
|
||||
if (m_chanA->m_wr9 & z80scc_channel::WR9_BIT_VIS)
|
||||
{
|
||||
vector = modify_vector(vector, index, source);
|
||||
}
|
||||
|
||||
LOG(("Z80SCC \"%s\" Channel %c : Interrupt Request %u\n", tag(), 'A' + index, state));
|
||||
|
||||
// update vector register
|
||||
m_chanB->m_rr2 = 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;
|
||||
|
||||
/* Check the interrupt source and build the vector modification */
|
||||
/*Interrupt Source Priority order
|
||||
Channel A Receive
|
||||
Channel A Transmit
|
||||
Channel A External/Status
|
||||
Channel B Receive
|
||||
Channel B Transmit
|
||||
Channel B External/Status
|
||||
*/
|
||||
// Add channel offset to priority according to table above
|
||||
priority = prio_level + (index == CHANNEL_A ? 3 : 0 );
|
||||
|
||||
// trigger interrupt
|
||||
m_int_state[priority] |= Z80_DAISY_INT;
|
||||
m_chanA->m_rr0 |= z80scc_channel::RR0_INTERRUPT_PENDING;
|
||||
|
||||
// Based on the fact that prio levels are aligned with the bitorder of rr3 we can do this...
|
||||
m_chanA->m_rr3 |= (prio_level << (index == CHANNEL_A ? 3 : 0 ));
|
||||
|
||||
// check for interrupt
|
||||
check_interrupts();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -562,7 +626,7 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d
|
||||
m_rr3 = m_rr4 = m_rr5 = m_rr6 = m_rr7 = 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;
|
||||
m_wr8 = m_wr9 = 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
|
||||
{
|
||||
@ -579,11 +643,14 @@ z80scc_channel::z80scc_channel(const machine_config &mconfig, const char *tag, d
|
||||
void z80scc_channel::device_start()
|
||||
{
|
||||
m_uart = downcast<z80scc_device *>(owner());
|
||||
LOG(("Z80SCC device_start m_uart:%p\n", m_uart));
|
||||
LOG(("%s\n", FUNCNAME));
|
||||
m_index = m_uart->get_channel_index(this);
|
||||
m_ph = 0;
|
||||
m_variant = ((z80scc_device *)m_owner)->m_variant;
|
||||
|
||||
m_rx_fifo_sz = (m_variant & SET_ESCC) ? 8 : 3;
|
||||
m_rx_fifo_wp = m_rx_fifo_rp = 0;
|
||||
|
||||
// state saving
|
||||
// m_rr0-m_rr2 is handled by the z80sio_channel driver, our base class
|
||||
save_item(NAME(m_rr0));
|
||||
@ -621,8 +688,9 @@ void z80scc_channel::device_start()
|
||||
save_item(NAME(m_wr15));
|
||||
save_item(NAME(m_rx_data_fifo));
|
||||
save_item(NAME(m_rx_error_fifo));
|
||||
save_item(NAME(m_rx_error));
|
||||
save_item(NAME(m_rx_fifo));
|
||||
save_item(NAME(m_rx_fifo_rp));
|
||||
save_item(NAME(m_rx_fifo_wp));
|
||||
save_item(NAME(m_rx_fifo_sz));
|
||||
save_item(NAME(m_rx_clock));
|
||||
save_item(NAME(m_rx_first));
|
||||
save_item(NAME(m_rx_break));
|
||||
@ -646,21 +714,42 @@ void z80scc_channel::device_start()
|
||||
|
||||
void z80scc_channel::device_reset()
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : %s\n", m_owner->tag(), 'A' + m_index, __func__));
|
||||
LOG(("Z80SCC \"%s\" Channel %c : %s\n", m_owner->tag(), 'A' + m_index, FUNCNAME));
|
||||
|
||||
// Reset RS232 emulation
|
||||
receive_register_reset();
|
||||
transmit_register_reset();
|
||||
|
||||
// TODO SIO code, check SCC compliance
|
||||
// disable receiver
|
||||
m_wr3 &= ~WR3_RX_ENABLE;
|
||||
// Soft/Channel Reset values according to SCC users manual
|
||||
m_wr0 = 0x00;
|
||||
m_wr1 &= 0x24;
|
||||
m_wr3 &= 0x01;
|
||||
m_wr4 |= 0x04;
|
||||
m_wr5 &= 0x61;
|
||||
if (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
|
||||
m_wr14 |= 0x20;
|
||||
m_wr15 = 0xf8;
|
||||
m_rr0 &= 0xfc;
|
||||
m_rr0 |= 0x44;
|
||||
m_rr1 &= 0x07;
|
||||
m_rr1 |= 0x06;
|
||||
m_rr3 = 0x00;
|
||||
m_rr10 &= 0x40;
|
||||
|
||||
#if 0 // old reset code
|
||||
// disable transmitter
|
||||
m_wr5 &= ~WR5_TX_ENABLE;
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY;
|
||||
m_rr1 |= RR1_ALL_SENT;
|
||||
#endif
|
||||
// TODO: check dependencies on RR1_ALL_SENT and (re)move this setting
|
||||
m_rr1 |= RR1_ALL_SENT; // It is a don't care in the SCC user manual
|
||||
|
||||
// reset external lines
|
||||
// reset external lines TODO: check relation to control bits and reset
|
||||
set_rts(1);
|
||||
set_dtr(1);
|
||||
|
||||
@ -685,6 +774,8 @@ void z80scc_channel::tra_callback()
|
||||
{
|
||||
if (!(m_wr5 & WR5_TX_ENABLE))
|
||||
{
|
||||
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c transmit mark 1 m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// transmit mark
|
||||
if (m_index == z80scc_device::CHANNEL_A)
|
||||
m_uart->m_out_txda_cb(1);
|
||||
@ -693,6 +784,7 @@ void z80scc_channel::tra_callback()
|
||||
}
|
||||
else if (m_wr5 & WR5_SEND_BREAK)
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c send break 1 m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// transmit break
|
||||
if (m_index == z80scc_device::CHANNEL_A)
|
||||
m_uart->m_out_txda_cb(0);
|
||||
@ -701,12 +793,20 @@ void z80scc_channel::tra_callback()
|
||||
}
|
||||
else if (!is_transmit_register_empty())
|
||||
{
|
||||
int db = transmit_register_get_data_bit();
|
||||
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c transmit data bit %d m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, db, m_wr5));
|
||||
// transmit data
|
||||
if (m_index == z80scc_device::CHANNEL_A)
|
||||
m_uart->m_out_txda_cb(transmit_register_get_data_bit());
|
||||
m_uart->m_out_txda_cb(db);
|
||||
else
|
||||
m_uart->m_out_txdb_cb(transmit_register_get_data_bit());
|
||||
m_uart->m_out_txdb_cb(db);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Failed to transmit m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
logerror("%s \"%s \"Channel %c Failed to transmit\n", FUNCNAME, m_owner->tag(), 'A' + m_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -718,7 +818,7 @@ void z80scc_channel::tra_complete()
|
||||
{
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && !(m_wr5 & WR5_SEND_BREAK) && !(m_rr0 & RR0_TX_BUFFER_EMPTY))
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : Transmit Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, m_tx_data));
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit Data Byte '%02x' m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_tx_data, m_wr5));
|
||||
|
||||
transmit_register_setup(m_tx_data);
|
||||
|
||||
@ -730,6 +830,7 @@ void z80scc_channel::tra_complete()
|
||||
}
|
||||
else if (m_wr5 & WR5_SEND_BREAK)
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit Break 0 m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// transmit break
|
||||
if (m_index == z80scc_device::CHANNEL_A)
|
||||
m_uart->m_out_txda_cb(0);
|
||||
@ -738,6 +839,7 @@ void z80scc_channel::tra_complete()
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit Mark 1 m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// transmit mark
|
||||
if (m_index == z80scc_device::CHANNEL_A)
|
||||
m_uart->m_out_txda_cb(1);
|
||||
@ -748,6 +850,7 @@ void z80scc_channel::tra_complete()
|
||||
// if transmit buffer is empty
|
||||
if (m_rr0 & RR0_TX_BUFFER_EMPTY)
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Transmit buffer empty m_wr5:%02x\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_wr5));
|
||||
// then all characters have been sent
|
||||
m_rr1 |= RR1_ALL_SENT;
|
||||
|
||||
@ -766,8 +869,14 @@ void z80scc_channel::rcv_callback()
|
||||
{
|
||||
if (m_wr3 & WR3_RX_ENABLE)
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Received Data Bit %d\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, m_rxd));
|
||||
receive_register_update_bit(m_rxd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Received Data Bit but receiver is disabled\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index));
|
||||
logerror("Z80SCC %s() \"%s \"Channel %c Received data dit but receiver is disabled\n", __func__, m_owner->tag(), 'A' + m_index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -777,8 +886,12 @@ void z80scc_channel::rcv_callback()
|
||||
|
||||
void z80scc_channel::rcv_complete()
|
||||
{
|
||||
UINT8 data;
|
||||
|
||||
receive_register_extract();
|
||||
receive_data(get_received_char());
|
||||
data = get_received_char();
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c Received Data %c\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, data));
|
||||
receive_data(data);
|
||||
}
|
||||
|
||||
|
||||
@ -905,7 +1018,25 @@ in WR9."*/
|
||||
UINT8 z80scc_channel::do_sccreg_rr2()
|
||||
{
|
||||
LOG(("Z80SCC %s()\n", __func__));
|
||||
return m_rr2; // TODO Check that the value is maintained according to the section above for respective channel
|
||||
|
||||
// Assume the unmodified in polled mode
|
||||
m_rr2 = m_uart->m_chanA->m_wr2;
|
||||
|
||||
// If we are chan B we have to modify the vector regardless of the VIS bit
|
||||
if (m_index == z80scc_device::CHANNEL_B)
|
||||
{
|
||||
// loop over all interrupt sources
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
// find the first channel with an interrupt requested
|
||||
if (m_uart->m_int_state[i] & Z80_DAISY_INT)
|
||||
{
|
||||
m_rr2 = m_uart->modify_vector(m_rr2, i < 3 ? z80scc_device::CHANNEL_A : z80scc_device::CHANNEL_B, i & 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_rr2;
|
||||
}
|
||||
|
||||
/* From Zilog SCC/ESCC USers manual, UM010902-0609:
|
||||
@ -1104,7 +1235,7 @@ UINT8 z80scc_channel::control_read()
|
||||
case REG_RR14_WR7_OR_R10: data = do_sccreg_rr14(); break;
|
||||
case REG_RR15_WR15_EXT_STAT: data = do_sccreg_rr15(); break;
|
||||
default:
|
||||
logerror("Z80SCC \"%s\" Channel %c : Unsupported RRx register:%02x\n", m_owner->tag(), 'A' + m_index, reg);
|
||||
logerror("Z80SCC \"%s\" %s Channel %c : Unsupported RRx register:%02x\n", m_owner->tag(), __func__, 'A' + m_index, reg);
|
||||
}
|
||||
|
||||
//LOG(("Z80SCC \"%s\" Channel %c : Register R%d read '%02x'\n", m_owner->tag(), 'A' + m_index, reg, data));
|
||||
@ -1130,11 +1261,11 @@ void z80scc_channel::do_sccreg_wr0(UINT8 data)
|
||||
addressing*/
|
||||
if (m_variant & SET_Z85X3X)
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : %s - Point High command\n", m_owner->tag(), 'A' + m_index, __func__));
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : %s - Point High command\n", m_owner->tag(), __func__, 'A' + m_index, __func__));
|
||||
m_ph = 8;
|
||||
}
|
||||
else
|
||||
LOG(("Z80SCC \"%s\" Channel %c : %s - NULL command 2\n", m_owner->tag(), 'A' + m_index, __func__));
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : %s - NULL command 2\n", m_owner->tag(), __func__, 'A' + m_index, __func__));
|
||||
break;
|
||||
case WR0_RESET_EXT_STATUS: // TODO: Take care of the Zero Count flag and the 2 slot fifo
|
||||
/*After an External/Status interrupt (a change on a modem line or a break condition,
|
||||
@ -1149,15 +1280,28 @@ void z80scc_channel::do_sccreg_wr0(UINT8 data)
|
||||
(there are two transitions), another interrupt is not generated. Exceptions to this
|
||||
rule are detailed in the RR0 description.*/
|
||||
do_sioreg_wr0(data);
|
||||
if (!m_zc) m_rr0 |= RR0_ZC;
|
||||
LOG(("Z80SCC \"%s\" Channel %c : %s - Reset External/Status Interrupt\n", m_owner->tag(), 'A' + m_index, __func__));
|
||||
if (!m_zc)
|
||||
{
|
||||
m_rr0 |= RR0_ZC;
|
||||
}
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : %s - Reset External/Status Interrupt\n", m_owner->tag(), __func__, 'A' + m_index, __func__));
|
||||
break;
|
||||
case WR0_RESET_HIGHEST_IUS:
|
||||
/* 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(("Z80SCC \"%s\" Channel %c : Reset Highest IUS\n", m_owner->tag(), 'A' + m_index));
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : Reset Highest IUS\n", m_owner->tag(), __func__, '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
|
||||
Character or Interrupt on Special Condition modes is selected and a special condition exists, the
|
||||
data with the special condition is held in the Receive FIFO until this command is issued. If either
|
||||
of these modes is selected and this command is issued before the data has been read from the
|
||||
Receive FIFO, the data is lost */
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : WR0_ERROR_RESET\n", m_owner->tag(), __func__, 'A' + m_index));
|
||||
do_sioreg_wr0(data); // reset status registers
|
||||
m_rx_fifo_rp_step(); // Reset error state in fifo and unlock it. unlock == step to next slot in fifo.
|
||||
break;
|
||||
case WR0_SEND_ABORT:
|
||||
data &= 0xef; // convert SCC SEND_ABORT command to a SIO SEND_ABORT command and fall through
|
||||
@ -1165,7 +1309,6 @@ void z80scc_channel::do_sccreg_wr0(UINT8 data)
|
||||
case WR0_NULL:
|
||||
case WR0_ENABLE_INT_NEXT_RX:
|
||||
case WR0_RESET_TX_INT:
|
||||
case WR0_ERROR_RESET:
|
||||
default:
|
||||
do_sioreg_wr0(data);
|
||||
}
|
||||
@ -1244,9 +1387,18 @@ void z80scc_channel::do_sccreg_wr8(UINT8 data)
|
||||
|
||||
/*WR9 is the Master Interrupt Control register and contains the Reset command bits. Only one WR9
|
||||
exists in the SCC and is accessed from either channel. The Interrupt control bits are programmed
|
||||
at the same time as the Reset command, because these bits are only reset by a hardware reset */
|
||||
at the same time as the Reset command, because these bits are only reset by a hardware reset
|
||||
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_variant & SET_Z80X30)
|
||||
{
|
||||
m_uart->m_chanA->m_wr9 = data;
|
||||
m_uart->m_chanB->m_wr9 = data;
|
||||
}
|
||||
else
|
||||
m_wr9 = data;
|
||||
|
||||
switch (data & WR9_CMD_MASK)
|
||||
{
|
||||
case WR9_CMD_NORESET:
|
||||
@ -1483,9 +1635,23 @@ void z80scc_channel::control_write(UINT8 data)
|
||||
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_sioreg_wr3(data); update_serial(); break;
|
||||
case REG_WR4_RX_TX_MODES: do_sioreg_wr4(data); update_serial(); break;
|
||||
case REG_WR5_TX_CONTROL: do_sioreg_wr5(data); update_serial(); update_rts(); break;
|
||||
case REG_WR3_RX_CONTROL:
|
||||
do_sioreg_wr3(data);
|
||||
update_serial();
|
||||
receive_register_reset();
|
||||
break;
|
||||
case REG_WR4_RX_TX_MODES:
|
||||
do_sioreg_wr4(data);
|
||||
update_serial();
|
||||
transmit_register_reset();
|
||||
receive_register_reset();
|
||||
break;
|
||||
case REG_WR5_TX_CONTROL:
|
||||
do_sioreg_wr5(data);
|
||||
update_serial();
|
||||
transmit_register_reset();
|
||||
update_rts();
|
||||
break;
|
||||
case REG_WR6_SYNC_OR_SDLC_A: do_sioreg_wr6(data); break;
|
||||
case REG_WR7_SYNC_OR_SDLC_F: do_sioreg_wr7(data); break;
|
||||
case REG_WR8_TRANSMIT_DATA: do_sccreg_wr8(data); break;
|
||||
@ -1505,36 +1671,97 @@ void z80scc_channel::control_write(UINT8 data)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// data_read - read data register
|
||||
// data_read - read data register from fifo
|
||||
//-------------------------------------------------
|
||||
|
||||
UINT8 z80scc_channel::data_read()
|
||||
{
|
||||
UINT8 data = 0;
|
||||
|
||||
if (m_rx_fifo >= 0)
|
||||
if (m_rx_fifo_wp != m_rx_fifo_rp)
|
||||
{
|
||||
/* Special Receive Condition interrupts are generated after the character is read from
|
||||
the FIFO, not when the special condition is first detected. This is done so that when
|
||||
using receive interrupt on first or Special Condition or Special Condition Only, data is
|
||||
directly read out of the data FIFO without checking the status first. If a special condi-
|
||||
tion interrupted the CPU when first detected, it would be necessary to read RR1
|
||||
before each byte in the FIFO to determine which byte had the special condition.
|
||||
Therefore, by not generating the interrupt until after the byte has been read and then
|
||||
locking the FIFO, only one status read is necessary. A DMA can be used to do all data
|
||||
transfers (otherwise, it would be necessary to disable the DMA to allow the CPU to
|
||||
read the status on each byte). Consequently, since the special condition locks the
|
||||
FIFO to preserve the status, it is necessary to issue the Error Reset command to
|
||||
unlock it. Only the exit location of the FIFO is locked allowing more data to be
|
||||
received into the other bytes of the Receive FIFO.*/
|
||||
|
||||
// load data from the FIFO
|
||||
data = m_rx_data_fifo[m_rx_fifo];
|
||||
data = m_rx_fifo_rp_data();
|
||||
|
||||
// load error status from the FIFO
|
||||
m_rr1 = (m_rr1 & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo[m_rx_fifo];
|
||||
// load error status from the FIFO
|
||||
m_rr1 = (m_rr1 & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo[m_rx_fifo_rp];
|
||||
|
||||
// decrease FIFO pointer
|
||||
m_rx_fifo--;
|
||||
// trigger interrup and lock the fifo if an error is present
|
||||
if (m_rr1 & (RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR))
|
||||
{
|
||||
switch (m_wr1 & WR1_RX_INT_MODE_MASK)
|
||||
{
|
||||
case WR1_RX_INT_FIRST:
|
||||
if (!m_rx_first)
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_SPECIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
if (m_rx_fifo < 0)
|
||||
{
|
||||
// no more characters available in the FIFO
|
||||
m_rr0 &= ~ RR0_RX_CHAR_AVAILABLE;
|
||||
}
|
||||
case WR1_RX_INT_ALL_PARITY:
|
||||
case WR1_RX_INT_ALL:
|
||||
m_uart->trigger_interrupt(m_index, INT_SPECIAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// decrease FIFO pointer
|
||||
m_rx_fifo_rp_step();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("data_read: Attempt to read out character from empty FIFO\n");
|
||||
}
|
||||
|
||||
LOG(("Z80SCC \"%s\" Channel %c : Data Register Read '%02x'\n", m_owner->tag(), 'A' + m_index, data));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Get data from top of fifo data but restore read pointer in case of exit latch lock */
|
||||
UINT8 z80scc_channel::m_rx_fifo_rp_data()
|
||||
{
|
||||
UINT8 data;
|
||||
UINT8 old_rp = m_rx_fifo_rp;
|
||||
m_rx_fifo_rp_step();
|
||||
data = m_rx_data_fifo[m_rx_fifo_rp];
|
||||
m_rx_fifo_rp = old_rp;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Step read pointer */
|
||||
void z80scc_channel::m_rx_fifo_rp_step()
|
||||
{
|
||||
m_rx_fifo_rp++;
|
||||
if (m_rx_fifo_rp >= m_rx_fifo_sz)
|
||||
{
|
||||
m_rx_fifo_rp = 0;
|
||||
}
|
||||
|
||||
// check if FIFO is empty
|
||||
if (m_rx_fifo_rp == m_rx_fifo_wp)
|
||||
{
|
||||
// no more characters available in the FIFO
|
||||
m_rr0 &= ~ RR0_RX_CHAR_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// data_write - write data register
|
||||
@ -1544,7 +1771,7 @@ void z80scc_channel::data_write(UINT8 data)
|
||||
{
|
||||
m_tx_data = data;
|
||||
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && is_transmit_register_empty())
|
||||
if ((m_wr5 & WR5_TX_ENABLE) && is_transmit_register_empty())
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : Transmit Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, m_tx_data));
|
||||
|
||||
@ -1554,7 +1781,9 @@ void z80scc_channel::data_write(UINT8 data)
|
||||
m_rr0 |= RR0_TX_BUFFER_EMPTY;
|
||||
|
||||
if (m_wr1 & WR1_TX_INT_ENABLE)
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_TRANSMIT);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1568,44 +1797,35 @@ void z80scc_channel::data_write(UINT8 data)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// receive_data - receive data word
|
||||
// receive_data - receive data word into fifo
|
||||
//-------------------------------------------------
|
||||
|
||||
void z80scc_channel::receive_data(UINT8 data)
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : Receive Data Byte '%02x'\n", m_owner->tag(), 'A' + m_index, data));
|
||||
|
||||
if (m_rx_fifo == 2)
|
||||
if (m_rx_fifo_wp + 1 == m_rx_fifo_rp ||
|
||||
( (m_rx_fifo_wp + 1 == m_rx_fifo_sz) && (m_rx_fifo_rp == 0) ))
|
||||
{
|
||||
// receive overrun error detected
|
||||
m_rx_error |= RR1_RX_OVERRUN_ERROR;
|
||||
m_rx_error_fifo[m_rx_fifo_wp] |= RR1_RX_OVERRUN_ERROR; // = m_rx_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rx_error_fifo[m_rx_fifo_wp] &= ~RR1_RX_OVERRUN_ERROR; // = m_rx_error;
|
||||
m_rx_fifo_wp++;
|
||||
if (m_rx_fifo_wp >= m_rx_fifo_sz)
|
||||
{
|
||||
m_rx_fifo_wp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m_wr1 & WR1_RX_INT_MODE_MASK)
|
||||
{
|
||||
case WR1_RX_INT_FIRST:
|
||||
if (!m_rx_first)
|
||||
{
|
||||
m_uart->trigger_interrupt(m_index, INT_SPECIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case WR1_RX_INT_ALL_PARITY:
|
||||
case WR1_RX_INT_ALL:
|
||||
m_uart->trigger_interrupt(m_index, INT_SPECIAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rx_fifo++;
|
||||
}
|
||||
|
||||
// store received character and error status into FIFO
|
||||
m_rx_data_fifo[m_rx_fifo] = data;
|
||||
m_rx_error_fifo[m_rx_fifo] = m_rx_error;
|
||||
// store received character
|
||||
m_rx_data_fifo[m_rx_fifo_wp] = data;
|
||||
|
||||
m_rr0 |= RR0_RX_CHAR_AVAILABLE;
|
||||
|
||||
#if 0 // interrupt on exit from fifo
|
||||
// receive interrupt
|
||||
switch (m_wr1 & WR1_RX_INT_MODE_MASK)
|
||||
{
|
||||
@ -1623,6 +1843,7 @@ void z80scc_channel::receive_data(UINT8 data)
|
||||
m_uart->trigger_interrupt(m_index, INT_RECEIVE);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1632,7 +1853,7 @@ void z80scc_channel::receive_data(UINT8 data)
|
||||
|
||||
WRITE_LINE_MEMBER( z80scc_channel::cts_w )
|
||||
{
|
||||
LOG(("Z80SCC \"%s\" Channel %c : CTS %u\n", m_owner->tag(), 'A' + m_index, state));
|
||||
LOG(("Z80SCC \"%s\" %s Channel %c : CTS %u\n", m_owner->tag(), __func__, 'A' + m_index, state));
|
||||
|
||||
if (m_cts != state)
|
||||
{
|
||||
@ -1662,6 +1883,7 @@ WRITE_LINE_MEMBER( z80scc_channel::cts_w )
|
||||
}
|
||||
}
|
||||
}
|
||||
// m_rr0 &= ~RR0_CTS; // Remove, just to test
|
||||
}
|
||||
|
||||
|
||||
@ -1792,8 +2014,6 @@ void z80scc_channel::update_serial()
|
||||
stop_bits_t stop_bits = get_stop_bits();
|
||||
parity_t parity;
|
||||
|
||||
LOG(("Z80SCC update serial\n"));
|
||||
|
||||
if (m_wr4 & WR4_PARITY_ENABLE)
|
||||
{
|
||||
if (m_wr4 & WR4_PARITY_EVEN)
|
||||
@ -1804,6 +2024,8 @@ void z80scc_channel::update_serial()
|
||||
else
|
||||
parity = PARITY_NONE;
|
||||
|
||||
LOG((LLFORMAT " %s() \"%s \"Channel %c setting data frame %d+%d%c%d\n", machine().firstcpu->total_cycles(), FUNCNAME, m_owner->tag(), 'A' + m_index, 1,
|
||||
data_bit_count, parity == PARITY_NONE ? 'N' : parity == PARITY_EVEN ? 'E' : 'O', (stop_bits + 1) / 2));
|
||||
set_data_frame(1, data_bit_count, parity, stop_bits);
|
||||
|
||||
int clocks = get_clock_mode();
|
||||
@ -1811,13 +2033,14 @@ void z80scc_channel::update_serial()
|
||||
if (m_rxc > 0)
|
||||
{
|
||||
set_rcv_rate(m_rxc / clocks);
|
||||
LOG((" - Receiver clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks));
|
||||
}
|
||||
|
||||
if (m_txc > 0)
|
||||
{
|
||||
set_tra_rate(m_txc / clocks);
|
||||
LOG((" - Transmit clock: %d mode: %d rate: %d/%xh\n", m_rxc, clocks, m_rxc / clocks, m_rxc / clocks));
|
||||
}
|
||||
receive_register_reset(); // if stop bits is changed from 0, receive register has to be reset
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -169,6 +169,8 @@ public:
|
||||
void data_write(UINT8 data);
|
||||
|
||||
void receive_data(UINT8 data);
|
||||
void m_rx_fifo_rp_step();
|
||||
UINT8 m_rx_fifo_rp_data();
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( write_rx );
|
||||
DECLARE_WRITE_LINE_MEMBER( cts_w );
|
||||
@ -227,9 +229,9 @@ protected:
|
||||
enum
|
||||
{
|
||||
INT_TRANSMIT = 0,
|
||||
INT_EXTERNAL,
|
||||
INT_RECEIVE,
|
||||
INT_SPECIAL
|
||||
INT_EXTERNAL = 1,
|
||||
INT_RECEIVE = 2,
|
||||
INT_SPECIAL = 3
|
||||
};
|
||||
|
||||
// Read registers
|
||||
@ -339,7 +341,7 @@ protected:
|
||||
WR0_Z_COMMAND_MASK = 0x38, // COMMANDS
|
||||
WR0_Z_NULL_1 = 0x00, // 0 0 0
|
||||
WR0_Z_NULL_2 = 0x08, // 0 0 1
|
||||
WR0_Z_RESET_EXT_STATUS = 0x10, // 0 1 0
|
||||
WR0_Z_RESET_EXT_STATUS = 0x10, // 0 1 0
|
||||
WR0_Z_SEND_ABORT = 0x18, // 0 1 1
|
||||
WR0_Z_ENABLE_INT_NEXT_RX = 0x20, // 1 0 0
|
||||
WR0_Z_RESET_TX_INT = 0x28, // 1 0 1
|
||||
@ -354,7 +356,7 @@ protected:
|
||||
{
|
||||
WR1_EXT_INT_ENABLE = 0x01,
|
||||
WR1_TX_INT_ENABLE = 0x02,
|
||||
WR1_STATUS_VECTOR = 0x04,
|
||||
WR1_PARITY_IS_SPEC_COND = 0x04,
|
||||
WR1_RX_INT_MODE_MASK = 0x18,
|
||||
WR1_RX_INT_DISABLE = 0x00,
|
||||
WR1_RX_INT_FIRST = 0x08,
|
||||
@ -365,23 +367,6 @@ protected:
|
||||
WR1_WRDY_ENABLE = 0x80 // not supported
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR2_DATA_XFER_INT = 0x00, // not supported
|
||||
WR2_DATA_XFER_DMA_INT = 0x01, // not supported
|
||||
WR2_DATA_XFER_DMA = 0x02, // not supported
|
||||
WR2_DATA_XFER_ILLEGAL = 0x03, // not supported
|
||||
WR2_DATA_XFER_MASK = 0x03, // not supported
|
||||
WR2_PRIORITY = 0x04, // not supported
|
||||
WR2_MODE_8085_1 = 0x00, // not supported
|
||||
WR2_MODE_8085_2 = 0x08, // not supported
|
||||
WR2_MODE_8086_8088 = 0x10, // not supported
|
||||
WR2_MODE_ILLEGAL = 0x18, // not supported
|
||||
WR2_MODE_MASK = 0x18, // not supported
|
||||
WR2_VECTORED_INT = 0x20, // not supported
|
||||
WR2_PIN10_SYNDETB_RTSB = 0x80 // not supported
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WR3_RX_ENABLE = 0x01,
|
||||
@ -493,10 +478,13 @@ protected:
|
||||
int get_tx_word_length();
|
||||
|
||||
// receiver state
|
||||
UINT8 m_rx_data_fifo[3]; // receive data FIFO
|
||||
UINT8 m_rx_error_fifo[3]; // receive error FIFO
|
||||
UINT8 m_rx_data_fifo[8]; // receive data FIFO
|
||||
UINT8 m_rx_error_fifo[8]; // receive error FIFO
|
||||
UINT8 m_rx_error; // current receive error
|
||||
int m_rx_fifo; // receive FIFO pointer
|
||||
//int m_rx_fifo // receive FIFO pointer
|
||||
int m_rx_fifo_rp; // receive FIFO read pointer
|
||||
int m_rx_fifo_wp; // receive FIFO write pointer
|
||||
int m_rx_fifo_sz; // receive FIFO size
|
||||
|
||||
int m_rx_clock; // receive clock pulse count
|
||||
int m_rx_first; // first character received
|
||||
@ -612,6 +600,7 @@ protected:
|
||||
// internal interrupt management
|
||||
void check_interrupts();
|
||||
void reset_interrupts();
|
||||
UINT8 modify_vector(UINT8 vect, int i, UINT8 src);
|
||||
void trigger_interrupt(int index, int state);
|
||||
int get_channel_index(z80scc_channel *ch) { return (ch == m_chanA) ? 0 : 1; }
|
||||
|
||||
@ -670,7 +659,7 @@ protected:
|
||||
devcb_write_line m_out_rxdrqb_cb;
|
||||
devcb_write_line m_out_txdrqb_cb;
|
||||
|
||||
int m_int_state[8]; // interrupt state
|
||||
int m_int_state[6]; // interrupt state
|
||||
|
||||
int m_variant;
|
||||
};
|
||||
|
@ -60,6 +60,14 @@
|
||||
#define logerror printf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define LLFORMAT "%I64%"
|
||||
#define FUNCNAME __func__
|
||||
#else
|
||||
#define LLFORMAT "%lld"
|
||||
#define FUNCNAME __PRETTY_FUNCTION__
|
||||
#endif
|
||||
|
||||
#define CHANA_TAG "cha"
|
||||
#define CHANB_TAG "chb"
|
||||
|
||||
@ -161,6 +169,7 @@ z80sio_device::z80sio_device(const machine_config &mconfig, const char *tag, dev
|
||||
|
||||
void z80sio_device::device_start()
|
||||
{
|
||||
LOG(("%s\n", FUNCNAME));
|
||||
// resolve callbacks
|
||||
m_out_txda_cb.resolve_safe();
|
||||
m_out_dtra_cb.resolve_safe();
|
||||
@ -197,7 +206,7 @@ void z80sio_device::device_start()
|
||||
|
||||
void z80sio_device::device_reset()
|
||||
{
|
||||
LOG(("Z80SIO \"%s\" Reset\n", tag()));
|
||||
LOG(("%s \"%s\" \n", FUNCNAME, tag()));
|
||||
|
||||
m_chanA->reset();
|
||||
m_chanB->reset();
|
||||
@ -429,7 +438,7 @@ WRITE8_MEMBER( z80sio_device::cd_ba_w )
|
||||
int cd = BIT(offset, 1);
|
||||
z80sio_channel *channel = ba ? m_chanB : m_chanA;
|
||||
|
||||
// LOG(("z80sio_device::cd_ba_w ba:%02x cd:%02x\n", ba, cd));
|
||||
LOG(("z80sio_device::cd_ba_w ba:%02x cd:%02x\n", ba, cd));
|
||||
|
||||
if (cd)
|
||||
channel->control_write(data);
|
||||
@ -517,8 +526,8 @@ z80sio_channel::z80sio_channel(const machine_config &mconfig, const char *tag, d
|
||||
|
||||
void z80sio_channel::device_start()
|
||||
{
|
||||
LOG(("%s\n",FUNCNAME));
|
||||
m_uart = downcast<z80sio_device *>(owner());
|
||||
LOG(("Z80SIO device_start m_uart:%p\n", m_uart));
|
||||
m_index = m_uart->get_channel_index(this);
|
||||
|
||||
// state saving
|
||||
@ -559,6 +568,7 @@ void z80sio_channel::device_start()
|
||||
|
||||
void z80sio_channel::device_reset()
|
||||
{
|
||||
LOG(("%s\n", FUNCNAME));
|
||||
receive_register_reset();
|
||||
transmit_register_reset();
|
||||
|
||||
@ -881,7 +891,7 @@ void z80sio_channel::do_sioreg_wr0_resets(UINT8 data)
|
||||
LOG(("Z80SIO \"%s\" Channel %c : CRC_RESET_TX_UNDERRUN - not implemented\n", m_owner->tag(), 'A' + m_index));
|
||||
break;
|
||||
default: /* Will not happen unless someone messes with the mask */
|
||||
logerror("Z80SIO \"%s\" Channel %c : %s Wrong CRC reset/init command:%02x\n", m_owner->tag(), 'A' + m_index, __func__, data & WR0_CRC_RESET_CODE_MASK);
|
||||
logerror("Z80SIO \"%s\" Channel %c : %s Wrong CRC reset/init command:%02x\n", m_owner->tag(), 'A' + m_index, FUNCNAME, data & WR0_CRC_RESET_CODE_MASK);
|
||||
}
|
||||
}
|
||||
void z80sio_channel::do_sioreg_wr0(UINT8 data)
|
||||
|
@ -45,7 +45,7 @@
|
||||
* \==||| | | | | | | |74| 4 x | 3 PALs |145|
|
||||
* ||| |SCC | | | | | |804 74245 | CS3-00 |___|
|
||||
* FPI || |seria| |U12 | |U23 | | | | CS2-00 | |
|
||||
* paralell |Z8530| |HBUG| |HBUG| | | | CS1-00 | |___
|
||||
* paralell |Z8530A |HBUG| |HBUG| | | | CS1-00 | |___
|
||||
* port || | | | | | | ---_---------------|__________| _| |
|
||||
* || | | | | | | |MTTLDL|MDLDM| 2 x |___________ | | |
|
||||
* ||| | | |____|_|____|_|____40|TTL75|74280| | | | |
|
||||
@ -80,6 +80,11 @@
|
||||
* http://www.nytimes.com/1992/01/07/business/company-news-briefs.html
|
||||
* http://bitsavers.informatik.uni-stuttgart.de/pdf/heurikon/brochures/HK68_V10_Brochure.pdf
|
||||
* http://bitsavers.informatik.uni-stuttgart.de/pdf/heurikon/Heurikon_UNIX_System_V_and_V.2_Reference_Guide_Apr87.pdf
|
||||
* From http://www.iri.tudelft.nl/~sfwww/manuals/OS9/PDF/9OM_30.pdf:
|
||||
* "In most cases, you will only need to change the device base address. Some hardware implementations of the MC68451
|
||||
* (specifically the Heurikon M10/V10 CPU's) use the DMA portion of the Address Space Table (AST) instead of the MPU
|
||||
* section which is normally used. You should change the offsets for the AST registers to match your hardware. The
|
||||
* ssmdefs.a file has conditional directives to accommodate either the standard or Heurikon style implementations."
|
||||
*
|
||||
* Address Map from the UNIX Ref Guide
|
||||
* --------------------------------------------------------------------------
|
||||
@ -156,6 +161,7 @@
|
||||
* - ADD SCSI controller device
|
||||
* - dump PALs and describe descrete logic
|
||||
* - Setup BAUD generation correctly, (eg find that x32 divider)
|
||||
* it is a multilayer PCB so very hard to trace.
|
||||
* - Add LED:s
|
||||
* - Add Jumpers and strap areas
|
||||
* - Find and Boot Heurikon Unix from a SCSI device
|
||||
@ -169,13 +175,27 @@
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "machine/clock.h"
|
||||
|
||||
#define LOG(x) /* x */
|
||||
#define VERBOSE 0
|
||||
|
||||
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
|
||||
|
||||
#if VERBOSE == 2
|
||||
#define logerror printf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define LLFORMAT "%I64%"
|
||||
#define FUNCNAME __func__
|
||||
#else
|
||||
#define LLFORMAT "%lld"
|
||||
#define FUNCNAME __PRETTY_FUNCTION__
|
||||
#endif
|
||||
|
||||
#define BAUDGEN_CLOCK XTAL_19_6608MHz /* Raltron */
|
||||
/*
|
||||
*/
|
||||
#define SCC_CLOCK (BAUDGEN_CLOCK / 128) /* This will give prompt */
|
||||
//#define SCC_CLOCK (BAUDGEN_CLOCK / 4) /* This is correct */
|
||||
#define SCC_CLOCK (BAUDGEN_CLOCK / 128) /* This gives prompt at the RS232 terminal device (9600) */
|
||||
//#define SCC_CLOCK (BAUDGEN_CLOCK / 4) /* This is correct giving 4.9152MHz as documentation says */
|
||||
class hk68v10_state : public driver_device
|
||||
{
|
||||
public:
|
||||
@ -231,7 +251,7 @@ INPUT_PORTS_END
|
||||
/* Start it up */
|
||||
void hk68v10_state::machine_start ()
|
||||
{
|
||||
LOG (logerror ("machine_start\n"));
|
||||
LOG ((LLFORMAT " %s\n", m_maincpu->total_cycles(), FUNCNAME));
|
||||
|
||||
/* Setup pointer to bootvector in ROM for bootvector handler bootvect_r */
|
||||
m_sysrom = (UINT16*)(memregion ("maincpu")->base () + 0x0fc0000);
|
||||
@ -245,7 +265,7 @@ void hk68v10_state::machine_start ()
|
||||
*/
|
||||
void hk68v10_state::machine_reset ()
|
||||
{
|
||||
LOG (logerror ("machine_reset\n"));
|
||||
LOG ((LLFORMAT " %s\n", m_maincpu->total_cycles(), FUNCNAME));
|
||||
|
||||
/* Reset pointer to bootvector in ROM for bootvector handler bootvect_r */
|
||||
if (m_sysrom == &m_sysram[0]) /* Condition needed because memory map is not setup first time */
|
||||
@ -260,12 +280,12 @@ void hk68v10_state::machine_reset ()
|
||||
FC002E: move.l #$0, $4.l # There is for sure some hardware mapping going in here
|
||||
*/
|
||||
READ16_MEMBER (hk68v10_state::bootvect_r){
|
||||
//LOG (logerror ("bootvect_r %s\n", m_sysrom != &m_sysram[0] ? "as reset" : "as swapped"));
|
||||
return m_sysrom [offset];
|
||||
//LOG (("bootvect_r %s\n", m_sysrom != &m_sysram[0] ? "as reset" : "as swapped"));
|
||||
return m_sysrom[offset];
|
||||
}
|
||||
|
||||
WRITE16_MEMBER (hk68v10_state::bootvect_w){
|
||||
LOG (logerror("bootvect_w offset %08x, mask %08x, data %04x\n", offset, mem_mask, data));
|
||||
LOG (("bootvect_w offset %08x, mask %08x, data %04x\n", offset, mem_mask, data));
|
||||
m_sysram[offset % sizeof(m_sysram)] &= ~mem_mask;
|
||||
m_sysram[offset % sizeof(m_sysram)] |= (data & mem_mask);
|
||||
m_sysrom = &m_sysram[0]; // redirect all upcomming accesses to masking RAM until reset.
|
||||
@ -274,21 +294,21 @@ WRITE16_MEMBER (hk68v10_state::bootvect_w){
|
||||
#if 0
|
||||
/* Dummy VME access methods until the VME bus device is ready for use */
|
||||
READ16_MEMBER (hk68v10_state::vme_a24_r){
|
||||
LOG (logerror ("vme_a24_r\n"));
|
||||
LOG (("vme_a24_r\n"));
|
||||
return (UINT16) 0;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER (hk68v10_state::vme_a24_w){
|
||||
LOG (logerror ("vme_a24_w\n"));
|
||||
LOG (("vme_a24_w\n"));
|
||||
}
|
||||
|
||||
READ16_MEMBER (hk68v10_state::vme_a16_r){
|
||||
LOG (logerror ("vme_16_r\n"));
|
||||
LOG (("vme_16_r\n"));
|
||||
return (UINT16) 0;
|
||||
}
|
||||
|
||||
WRITE16_MEMBER (hk68v10_state::vme_a16_w){
|
||||
LOG (logerror ("vme_a16_w\n"));
|
||||
LOG (("vme_a16_w\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user