mc68681: Preliminary support for SC28C94 QUART. [R. Belmont]

This commit is contained in:
arbee 2016-12-31 23:41:15 -05:00
parent 67bded8842
commit a9f9729c07
2 changed files with 131 additions and 46 deletions

View File

@ -1,7 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Mariusz Wojcieszek, R. Belmont
/*
2681 DUART
68681 DUART
28C94 QUART
Written by Mariusz Wojcieszek
Updated by Jonathan Gevaryahu AKA Lord Nightmare
@ -50,9 +52,12 @@ static const int baud_rate_ACR_1[] = { 75, 110, 134, 150, 300, 600, 1200, 2000,
#define CHANA_TAG "cha"
#define CHANB_TAG "chb"
#define CHANC_TAG "chc"
#define CHAND_TAG "chd"
// device type definition
const device_type MC68681 = &device_creator<mc68681_device>;
const device_type SC28C94 = &device_creator<sc28c94_device>;
const device_type MC68681_CHANNEL = &device_creator<mc68681_channel>;
MACHINE_CONFIG_FRAGMENT( duart68681 )
@ -60,17 +65,28 @@ MACHINE_CONFIG_FRAGMENT( duart68681 )
MCFG_DEVICE_ADD(CHANB_TAG, MC68681_CHANNEL, 0)
MACHINE_CONFIG_END
MACHINE_CONFIG_FRAGMENT( quart28c94 )
MCFG_DEVICE_ADD(CHANA_TAG, MC68681_CHANNEL, 0)
MCFG_DEVICE_ADD(CHANB_TAG, MC68681_CHANNEL, 0)
MCFG_DEVICE_ADD(CHANC_TAG, MC68681_CHANNEL, 0)
MCFG_DEVICE_ADD(CHAND_TAG, MC68681_CHANNEL, 0)
MACHINE_CONFIG_END
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
mc68681_device::mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, MC68681, "MC68681 DUART", tag, owner, clock, "mc68681", __FILE__),
mc68681_base_device::mc68681_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source)
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
m_chanA(*this, CHANA_TAG),
m_chanB(*this, CHANB_TAG),
m_chanC(*this, CHANC_TAG),
m_chanD(*this, CHAND_TAG),
write_irq(*this),
write_a_tx(*this),
write_b_tx(*this),
write_c_tx(*this),
write_d_tx(*this),
read_inport(*this),
write_outport(*this),
ip3clk(0),
@ -83,14 +99,24 @@ mc68681_device::mc68681_device(const machine_config &mconfig, const char *tag, d
{
}
mc68681_device::mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc68681_base_device(mconfig, MC68681, "MC68681 DUART", tag, owner, clock, "mc68681", __FILE__)
{
}
sc28c94_device::sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mc68681_base_device(mconfig, SC28C94, "SC28C94 QUART", tag, owner, clock, "sc28c94", __FILE__)
{
}
//-------------------------------------------------
// static_set_clocks - configuration helper to set
// the external clocks
//-------------------------------------------------
void mc68681_device::static_set_clocks(device_t &device, int clk3, int clk4, int clk5, int clk6)
void mc68681_base_device::static_set_clocks(device_t &device, int clk3, int clk4, int clk5, int clk6)
{
mc68681_device &duart = downcast<mc68681_device &>(device);
mc68681_base_device &duart = downcast<mc68681_base_device &>(device);
duart.ip3clk = clk3;
duart.ip4clk = clk4;
duart.ip5clk = clk5;
@ -101,7 +127,7 @@ void mc68681_device::static_set_clocks(device_t &device, int clk3, int clk4, int
device start callback
-------------------------------------------------*/
void mc68681_device::device_start()
void mc68681_base_device::device_start()
{
write_irq.resolve_safe();
write_a_tx.resolve_safe();
@ -109,7 +135,7 @@ void mc68681_device::device_start()
read_inport.resolve();
write_outport.resolve_safe();
duart_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68681_device::duart_timer_callback),this), nullptr);
duart_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68681_base_device::duart_timer_callback),this), nullptr);
save_item(NAME(ACR));
save_item(NAME(IMR));
@ -125,7 +151,7 @@ void mc68681_device::device_start()
device reset callback
-------------------------------------------------*/
void mc68681_device::device_reset()
void mc68681_base_device::device_reset()
{
ACR = 0; /* Interrupt Vector Register */
IVR = 0x0f; /* Interrupt Vector Register */
@ -141,12 +167,17 @@ void mc68681_device::device_reset()
write_outport(OPR ^ 0xff);
}
machine_config_constructor mc68681_device::device_mconfig_additions() const
machine_config_constructor mc68681_base_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( duart68681 );
}
void mc68681_device::update_interrupts()
machine_config_constructor sc28c94_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( quart28c94 );
}
void mc68681_base_device::update_interrupts()
{
/* update SR state and update interrupt ISR state for the following bits:
SRn: bits 7-4: handled elsewhere.
@ -208,7 +239,7 @@ void mc68681_device::update_interrupts()
}
}
double mc68681_device::duart68681_get_ct_rate()
double mc68681_base_device::duart68681_get_ct_rate()
{
double rate = 0.0f;
@ -250,19 +281,19 @@ double mc68681_device::duart68681_get_ct_rate()
return rate;
}
uint16_t mc68681_device::duart68681_get_ct_count()
uint16_t mc68681_base_device::duart68681_get_ct_count()
{
double clock = duart68681_get_ct_rate();
return (duart_timer->remaining() * clock).as_double();
}
void mc68681_device::duart68681_start_ct(int count)
void mc68681_base_device::duart68681_start_ct(int count)
{
double clock = duart68681_get_ct_rate();
duart_timer->adjust(attotime::from_hz(clock) * count, 0);
}
TIMER_CALLBACK_MEMBER( mc68681_device::duart_timer_callback )
TIMER_CALLBACK_MEMBER( mc68681_base_device::duart_timer_callback )
{
if (ACR & 0x40)
{
@ -320,13 +351,13 @@ TIMER_CALLBACK_MEMBER( mc68681_device::duart_timer_callback )
}
READ8_MEMBER( mc68681_device::read )
READ8_MEMBER( mc68681_base_device::read )
{
uint8_t r = 0xff;
offset &= 0xf;
LOG(( "Reading 68681 (%s) reg %x (%s) ", tag(), offset, duart68681_reg_read_names[offset] ));
LOG(( "Reading 68681 (%s) reg %x (%s)\n", tag(), offset, duart68681_reg_read_names[offset] ));
switch (offset)
{
@ -424,7 +455,7 @@ READ8_MEMBER( mc68681_device::read )
return r;
}
WRITE8_MEMBER( mc68681_device::write )
WRITE8_MEMBER( mc68681_base_device::write )
{
offset &= 0x0f;
LOG(( "Writing 68681 (%s) reg %x (%s) with %04x\n", tag(), offset, duart68681_reg_write_names[offset], data ));
@ -516,7 +547,7 @@ WRITE8_MEMBER( mc68681_device::write )
}
}
WRITE_LINE_MEMBER( mc68681_device::ip0_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip0_w )
{
uint8_t newIP = (IP_last_state & ~0x01) | ((state == ASSERT_LINE) ? 1 : 0);
@ -536,7 +567,7 @@ WRITE_LINE_MEMBER( mc68681_device::ip0_w )
IP_last_state = newIP;
}
WRITE_LINE_MEMBER( mc68681_device::ip1_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip1_w )
{
uint8_t newIP = (IP_last_state & ~0x02) | ((state == ASSERT_LINE) ? 2 : 0);
@ -556,7 +587,7 @@ WRITE_LINE_MEMBER( mc68681_device::ip1_w )
IP_last_state = newIP;
}
WRITE_LINE_MEMBER( mc68681_device::ip2_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip2_w )
{
uint8_t newIP = (IP_last_state & ~0x04) | ((state == ASSERT_LINE) ? 4 : 0);
@ -576,7 +607,7 @@ WRITE_LINE_MEMBER( mc68681_device::ip2_w )
IP_last_state = newIP;
}
WRITE_LINE_MEMBER( mc68681_device::ip3_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip3_w )
{
uint8_t newIP = (IP_last_state & ~0x08) | ((state == ASSERT_LINE) ? 8 : 0);
@ -596,21 +627,21 @@ WRITE_LINE_MEMBER( mc68681_device::ip3_w )
IP_last_state = newIP;
}
WRITE_LINE_MEMBER( mc68681_device::ip4_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip4_w )
{
uint8_t newIP = (IP_last_state & ~0x10) | ((state == ASSERT_LINE) ? 0x10 : 0);
// TODO: special mode for ip4 (Ch. A Rx clock)
IP_last_state = newIP;
}
WRITE_LINE_MEMBER( mc68681_device::ip5_w )
WRITE_LINE_MEMBER( mc68681_base_device::ip5_w )
{
uint8_t newIP = (IP_last_state & ~0x20) | ((state == ASSERT_LINE) ? 0x20 : 0);
// TODO: special mode for ip5 (Ch. B Tx clock)
IP_last_state = newIP;
}
mc68681_channel *mc68681_device::get_channel(int chan)
mc68681_channel *mc68681_base_device::get_channel(int chan)
{
if (chan == 0)
{
@ -620,7 +651,7 @@ mc68681_channel *mc68681_device::get_channel(int chan)
return m_chanB;
}
int mc68681_device::calc_baud(int ch, uint8_t data)
int mc68681_base_device::calc_baud(int ch, uint8_t data)
{
int baud_rate;
@ -661,15 +692,16 @@ int mc68681_device::calc_baud(int ch, uint8_t data)
LOG(( "Unsupported transmitter clock: channel %d, clock select = %02x\n", ch, data ));
}
// printf("%s ch %d setting baud to %d\n", tag(), ch, baud_rate);
return baud_rate;
}
void mc68681_device::clear_ISR_bits(int mask)
void mc68681_base_device::clear_ISR_bits(int mask)
{
ISR &= ~mask;
}
void mc68681_device::set_ISR_bits(int mask)
void mc68681_base_device::set_ISR_bits(int mask)
{
ISR |= mask;
}
@ -690,7 +722,7 @@ mc68681_channel::mc68681_channel(const machine_config &mconfig, const char *tag,
void mc68681_channel::device_start()
{
m_uart = downcast<mc68681_device *>(owner());
m_uart = downcast<mc68681_base_device *>(owner());
m_ch = m_uart->get_ch(this); // get our channel number
save_item(NAME(CR));
@ -793,7 +825,7 @@ void mc68681_channel::tra_callback()
if ((MR2&0xC0) != 0x80)
{
int bit = transmit_register_get_data_bit();
// printf("%s ch %d transmit %d\n", tag(), m_ch, bit);
//printf("%s ch %d transmit %d\n", tag(), m_ch, bit);
if (m_ch == 0)
{
m_uart->write_a_tx(bit);
@ -1157,7 +1189,7 @@ void mc68681_channel::write_TX(uint8_t data)
printf("Write %02x to TX when TX not ready!\n", data);
}*/
// printf("%s ch %d Tx %02x\n", tag(), m_ch, data);
//printf("%s ch %d Tx %02x\n", tag(), m_ch, data);
tx_ready = 0;
SR &= ~STATUS_TRANSMITTER_READY;

View File

@ -11,28 +11,38 @@
MCFG_DEVICE_REPLACE(_tag, MC68681, _clock)
#define MCFG_MC68681_IRQ_CALLBACK(_cb) \
devcb = &mc68681_device::set_irq_cb(*device, DEVCB_##_cb);
devcb = &mc68681_base_device::set_irq_cb(*device, DEVCB_##_cb);
#define MCFG_MC68681_A_TX_CALLBACK(_cb) \
devcb = &mc68681_device::set_a_tx_cb(*device, DEVCB_##_cb);
devcb = &mc68681_base_device::set_a_tx_cb(*device, DEVCB_##_cb);
#define MCFG_MC68681_B_TX_CALLBACK(_cb) \
devcb = &mc68681_device::set_b_tx_cb(*device, DEVCB_##_cb);
devcb = &mc68681_base_device::set_b_tx_cb(*device, DEVCB_##_cb);
// deprecated: use ipX_w() instead
#define MCFG_MC68681_INPORT_CALLBACK(_cb) \
devcb = &mc68681_device::set_inport_cb(*device, DEVCB_##_cb);
devcb = &mc68681_base_device::set_inport_cb(*device, DEVCB_##_cb);
#define MCFG_MC68681_OUTPORT_CALLBACK(_cb) \
devcb = &mc68681_device::set_outport_cb(*device, DEVCB_##_cb);
devcb = &mc68681_base_device::set_outport_cb(*device, DEVCB_##_cb);
#define MCFG_MC68681_SET_EXTERNAL_CLOCKS(_a, _b, _c, _d) \
mc68681_device::static_set_clocks(*device, _a, _b, _c, _d);
mc68681_base_device::static_set_clocks(*device, _a, _b, _c, _d);
// SC28C94 specific callbacks
#define MCFG_SC28C94_ADD(_tag, _clock) \
MCFG_DEVICE_ADD(_tag, SC28C94, _clock)
#define MCFG_SC28C94_C_TX_CALLBACK(_cb) \
devcb = &sc28c94_device::set_c_tx_cb(*device, DEVCB_##_cb);
#define MCFG_SC28C94_D_TX_CALLBACK(_cb) \
devcb = &sc28c94_device::set_d_tx_cb(*device, DEVCB_##_cb);
#define MC68681_RX_FIFO_SIZE 3
// forward declaration
class mc68681_device;
class mc68681_base_device;
// mc68681_channel class
class mc68681_channel : public device_t, public device_serial_interface
@ -86,7 +96,7 @@ private:
uint8_t tx_data;
uint8_t tx_ready;
mc68681_device *m_uart;
mc68681_base_device *m_uart;
void write_MR(uint8_t data);
void write_CR(uint8_t data);
@ -94,15 +104,17 @@ private:
void recalc_framing();
};
class mc68681_device : public device_t
class mc68681_base_device : public device_t
{
friend class mc68681_channel;
public:
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
mc68681_base_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, uint32_t clock, const char *shortname, const char *source);
required_device<mc68681_channel> m_chanA;
required_device<mc68681_channel> m_chanB;
optional_device<mc68681_channel> m_chanC;
optional_device<mc68681_channel> m_chanD;
// inline configuration helpers
static void static_set_clocks(device_t &device, int clk3, int clk4, int clk5, int clk6);
@ -115,13 +127,13 @@ public:
DECLARE_WRITE_LINE_MEMBER( rx_a_w ) { m_chanA->device_serial_interface::rx_w((uint8_t)state); }
DECLARE_WRITE_LINE_MEMBER( rx_b_w ) { m_chanB->device_serial_interface::rx_w((uint8_t)state); }
template<class _Object> static devcb_base &set_irq_cb(device_t &device, _Object object) { return downcast<mc68681_device &>(device).write_irq.set_callback(object); }
template<class _Object> static devcb_base &set_a_tx_cb(device_t &device, _Object object) { return downcast<mc68681_device &>(device).write_a_tx.set_callback(object); }
template<class _Object> static devcb_base &set_b_tx_cb(device_t &device, _Object object) { return downcast<mc68681_device &>(device).write_b_tx.set_callback(object); }
template<class _Object> static devcb_base &set_inport_cb(device_t &device, _Object object) { return downcast<mc68681_device &>(device).read_inport.set_callback(object); }
template<class _Object> static devcb_base &set_outport_cb(device_t &device, _Object object) { return downcast<mc68681_device &>(device).write_outport.set_callback(object); }
template<class _Object> static devcb_base &set_irq_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_irq.set_callback(object); }
template<class _Object> static devcb_base &set_a_tx_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_a_tx.set_callback(object); }
template<class _Object> static devcb_base &set_b_tx_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_b_tx.set_callback(object); }
template<class _Object> static devcb_base &set_inport_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).read_inport.set_callback(object); }
template<class _Object> static devcb_base &set_outport_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_outport.set_callback(object); }
devcb_write_line write_irq, write_a_tx, write_b_tx;
devcb_write_line write_irq, write_a_tx, write_b_tx, write_c_tx, write_d_tx;
devcb_read8 read_inport;
devcb_write8 write_outport;
int32_t ip3clk, ip4clk, ip5clk, ip6clk;
@ -166,15 +178,56 @@ private:
uint16_t duart68681_get_ct_count();
void duart68681_start_ct(int count);
int calc_baud(int ch, uint8_t data);
int get_ch(mc68681_channel *ch) { return (ch == m_chanA) ? 0 : 1; }
void clear_ISR_bits(int mask);
void set_ISR_bits(int mask);
void update_interrupts();
int get_ch(mc68681_channel *ch)
{
if (ch == m_chanA)
{
return 0;
}
else if (ch == m_chanB)
{
return 1;
}
else if (ch == m_chanC)
{
return 2;
}
return 3;
}
mc68681_channel *get_channel(int chan);
};
class mc68681_device : public mc68681_base_device
{
public:
mc68681_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class sc28c94_device : public mc68681_base_device
{
public:
sc28c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
template<class _Object> static devcb_base &set_c_tx_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_c_tx.set_callback(object); }
template<class _Object> static devcb_base &set_d_tx_cb(device_t &device, _Object object) { return downcast<mc68681_base_device &>(device).write_d_tx.set_callback(object); }
DECLARE_WRITE_LINE_MEMBER( rx_c_w ) { m_chanC->device_serial_interface::rx_w((uint8_t)state); }
DECLARE_WRITE_LINE_MEMBER( rx_d_w ) { m_chanD->device_serial_interface::rx_w((uint8_t)state); }
protected:
virtual machine_config_constructor device_mconfig_additions() const override;
private:
};
extern const device_type MC68681;
extern const device_type SC28C94;
extern const device_type MC68681_CHANNEL;
#endif //_N68681_H