Add preliminary MK68564 device (nw)

This commit is contained in:
AJR 2019-10-29 13:43:49 -04:00
parent 3151dbd31b
commit 7d862e69f9
3 changed files with 489 additions and 13 deletions

View File

@ -45,6 +45,15 @@
* Transmitter FIFO 1
-------------------------------------------------------------------------
* = Features that has been implemented n/a = features that will not
Mostek not only second-sourced the Z80 SIO but redesigned it for
68000 compatibility as the MK68564 SIO. This 48-pin device has a
revamped register interface with five address inputs to make every
register separately selectable, and most control registers may be read
back as written. The RxRDY and TxRDY pins are separate here, and many
control bits have been shifted around. The MK68564 also features a
built-in baud rate generator (not compatible with the Z8530 SCC's).
***************************************************************************/
#include "emu.h"
@ -237,11 +246,13 @@ constexpr uint16_t SDLC_RESIDUAL = 0x1d0f;
//**************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(Z80SIO_CHANNEL, z80sio_channel, "z80sio_channel", "Z80 SIO channel")
DEFINE_DEVICE_TYPE(I8274_CHANNEL, i8274_channel, "i8274_channel", "Intel 8274 MPSC channel")
DEFINE_DEVICE_TYPE(Z80SIO, z80sio_device, "z80sio", "Z80 SIO")
DEFINE_DEVICE_TYPE(I8274_NEW, i8274_new_device, "i8274_new", "Intel 8274 MPSC (new)") // Remove trailing N when z80dart.cpp's 8274 implementation is fully replaced
DEFINE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device, "upd7201_new", "NEC uPD7201 MPSC (new)") // Remove trailing N when z80dart.cpp's 7201 implementation is fully replaced
DEFINE_DEVICE_TYPE(Z80SIO_CHANNEL, z80sio_channel, "z80sio_channel", "Z80 SIO channel")
DEFINE_DEVICE_TYPE(I8274_CHANNEL, i8274_channel, "i8274_channel", "Intel 8274 MPSC channel")
DEFINE_DEVICE_TYPE(MK68564_CHANNEL, mk68564_channel, "mk68564_channel", "Mostek MK68564 SIO channel")
DEFINE_DEVICE_TYPE(Z80SIO, z80sio_device, "z80sio", "Z80 SIO")
DEFINE_DEVICE_TYPE(I8274_NEW, i8274_new_device, "i8274_new", "Intel 8274 MPSC (new)") // Remove trailing N when z80dart.cpp's 8274 implementation is fully replaced
DEFINE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device, "upd7201_new", "NEC uPD7201 MPSC (new)") // Remove trailing N when z80dart.cpp's 7201 implementation is fully replaced
DEFINE_DEVICE_TYPE(MK68564, mk68564_device, "mk68564", "Mostek MK68564 SIO")
//-------------------------------------------------
// device_add_mconfig - add device configuration
@ -258,6 +269,12 @@ void i8274_new_device::device_add_mconfig(machine_config &config)
I8274_CHANNEL(config, CHANB_TAG, 0);
}
void mk68564_device::device_add_mconfig(machine_config &config)
{
MK68564_CHANNEL(config, CHANA_TAG, 0);
MK68564_CHANNEL(config, CHANB_TAG, 0);
}
//**************************************************************************
// LIVE DEVICE
@ -290,11 +307,16 @@ inline bool z80sio_channel::receive_allowed() const
return (m_wr3 & WR3_RX_ENABLE) && (!(m_wr3 & WR3_AUTO_ENABLES) || !m_dcd);
}
inline bool z80sio_channel::transmit_allowed() const
bool z80sio_channel::transmit_allowed() const
{
return (m_wr5 & WR5_TX_ENABLE) && (!(m_wr3 & WR3_AUTO_ENABLES) || !m_cts);
}
bool mk68564_channel::transmit_allowed() const
{
return (m_wr5 & WR5_TX_ENABLE) && (!m_tx_auto_enable || !m_cts);
}
inline void z80sio_channel::set_rts(int state)
{
if (bool(m_rts) != bool(state))
@ -393,6 +415,11 @@ upd7201_new_device::upd7201_new_device(const machine_config &mconfig, const char
{
}
mk68564_device::mk68564_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
i8274_new_device(mconfig, MK68564, tag, owner, clock)
{
}
//-------------------------------------------------
// device_validity_check - device-specific validation
//-------------------------------------------------
@ -947,6 +974,14 @@ i8274_channel::i8274_channel(const machine_config &mconfig, const char *tag, dev
{
}
mk68564_channel::mk68564_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: z80sio_channel(mconfig, MK68564_CHANNEL, tag, owner, clock, RR1_END_OF_FRAME | RR1_CRC_FRAMING_ERROR | RR1_RESIDUE_CODE_MASK)
, m_tx_auto_enable(false)
, m_brg_tc(0)
, m_brg_control(0)
{
}
//-------------------------------------------------
// resove_objects - channel setup
@ -1016,6 +1051,15 @@ void z80sio_channel::device_start()
save_item(NAME(m_cts));
}
void mk68564_channel::device_start()
{
z80sio_channel::device_start();
save_item(NAME(m_tx_auto_enable));
save_item(NAME(m_brg_tc));
save_item(NAME(m_brg_control));
}
//-------------------------------------------------
// reset - reset channel status
@ -1066,6 +1110,15 @@ void z80sio_channel::device_reset()
m_uart->reset_interrupts();
}
void mk68564_channel::device_reset()
{
z80sio_channel::device_reset();
m_tx_auto_enable = false;
m_brg_tc = 0;
m_brg_control = 0;
}
bool z80sio_channel::is_tx_idle() const
{
return (m_tx_sr & TX_SR_MASK) == TX_SR_MASK;
@ -1337,7 +1390,7 @@ void z80sio_channel::trigger_ext_int()
//-------------------------------------------------
// get_clock_mode - get clock divisor
//-------------------------------------------------
int z80sio_channel::get_clock_mode()
int z80sio_channel::get_clock_mode() const
{
//LOG("%s %s\n",FUNCNAME, tag());
int clocks = 1;
@ -1385,7 +1438,7 @@ void z80sio_channel::update_dtr_rts_break()
//-------------------------------------------------
// get_rx_word_length - get receive word length
//-------------------------------------------------
int z80sio_channel::get_rx_word_length()
int z80sio_channel::get_rx_word_length() const
{
LOG("%s %s\n",FUNCNAME, tag());
int bits = 5;
@ -2524,3 +2577,339 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w )
}
m_tx_clock = state;
}
//**************************************************************************
// MK68564 REGISTER INTERFACE
//**************************************************************************
//-------------------------------------------------
// cmdreg_r - read from command register
//-------------------------------------------------
uint8_t mk68564_channel::cmdreg_r()
{
return m_wr0;
}
//-------------------------------------------------
// cmdreg_w - write to command register
//-------------------------------------------------
void mk68564_channel::cmdreg_w(uint8_t data)
{
// TODO: bit 0 sets loop mode (no register select)
// FIXME: no return from interrupt command
do_sioreg_wr0(data);
}
//-------------------------------------------------
// modectl_r - read from mode control register
//-------------------------------------------------
uint8_t mk68564_channel::modectl_r()
{
return m_wr4;
}
//-------------------------------------------------
// modectl_w - write to mode control register
//-------------------------------------------------
void mk68564_channel::modectl_w(uint8_t data)
{
do_sioreg_wr4(data);
}
//-------------------------------------------------
// intctl_r - read from interrupt control register
//-------------------------------------------------
uint8_t mk68564_channel::intctl_r()
{
return m_wr1 | (m_wr5 & WR5_CRC16 ? 0x80 : 0);
}
//-------------------------------------------------
// intctl_w - write to interrupt control register
//-------------------------------------------------
void mk68564_channel::intctl_w(uint8_t data)
{
if (BIT(data, 7))
m_wr5 |= WR5_CRC16;
else
m_wr5 &= ~WR5_CRC16;
// TODO: bits 5 and 6 are independent RxRDY and WxRDY enables
do_sioreg_wr1(data & 0x7f);
}
//-------------------------------------------------
// sync1_r - read from sync word register 1
//-------------------------------------------------
uint8_t mk68564_channel::sync1_r()
{
return m_wr6;
}
//-------------------------------------------------
// sync1_w - write to sync word register 1
//-------------------------------------------------
void mk68564_channel::sync1_w(uint8_t data)
{
do_sioreg_wr6(data);
}
//-------------------------------------------------
// sync2_r - read from sync word register 2
//-------------------------------------------------
uint8_t mk68564_channel::sync2_r()
{
return m_wr7;
}
//-------------------------------------------------
// sync2_w - write to sync word register 2
//-------------------------------------------------
void mk68564_channel::sync2_w(uint8_t data)
{
do_sioreg_wr7(data);
}
//-------------------------------------------------
// rcvctl_r - read from receiver control register
//-------------------------------------------------
uint8_t mk68564_channel::rcvctl_r()
{
return bitswap<8>(m_wr3, 6, 7, 5, 4, 3, 2, 1, 0) & ~WR3_ENTER_HUNT_PHASE;
}
//-------------------------------------------------
// rcvctl_w - write to receiver control register
//-------------------------------------------------
void mk68564_channel::rcvctl_w(uint8_t data)
{
do_sioreg_wr3(bitswap<8>(data, 6, 7, 5, 4, 3, 2, 1, 0));
}
//-------------------------------------------------
// xmtctl_r - read from transmitter control
// register
//-------------------------------------------------
uint8_t mk68564_channel::xmtctl_r()
{
uint8_t xmtctl = 0;
if (m_wr5 & WR5_TX_ENABLE)
xmtctl |= 0x01;
if (m_wr5 & WR5_RTS)
xmtctl |= 0x02;
if (m_wr5 & WR5_DTR)
xmtctl |= 0x04;
if (m_wr5 & WR5_TX_CRC_ENABLE)
xmtctl |= 0x08;
if (m_wr5 & WR5_SEND_BREAK)
xmtctl |= 0x10;
if (m_tx_auto_enable)
xmtctl |= 0x20;
xmtctl |= (m_wr5 & 0x40) << 1;
xmtctl |= (m_wr5 & 0x80) >> 1;
return xmtctl;
}
//-------------------------------------------------
// xmtctl_w - write to transmitter control
// register
//-------------------------------------------------
void mk68564_channel::xmtctl_w(uint8_t data)
{
uint8_t control =
(BIT(data, 0) ? WR5_TX_ENABLE : 0) |
(BIT(data, 1) ? WR5_RTS : 0) |
(BIT(data, 2) ? WR5_DTR : 0) |
(BIT(data, 3) ? WR5_TX_CRC_ENABLE : 0) |
(BIT(data, 4) ? WR5_SEND_BREAK : 0) |
(data & 0x40) << 1 |
(data & 0x80) >> 1 |
(m_wr5 & WR5_CRC16);
do_sioreg_wr5(control);
m_tx_auto_enable = BIT(data, 5);
}
//-------------------------------------------------
// tcreg_r - read from time constant register
//-------------------------------------------------
uint8_t mk68564_channel::tcreg_r()
{
return m_brg_tc;
}
//-------------------------------------------------
// tcreg_w - write to time constant register
//-------------------------------------------------
void mk68564_channel::tcreg_w(uint8_t data)
{
logerror("Time constant = %d\n", data);
m_brg_tc = data;
}
//-------------------------------------------------
// brgctl_r - read from baud rate generator
// control register
//-------------------------------------------------
uint8_t mk68564_channel::brgctl_r()
{
return m_brg_control;
}
//-------------------------------------------------
// brgctl_w - write to baud rate generator
// control register
//-------------------------------------------------
void mk68564_channel::brgctl_w(uint8_t data)
{
// TODO: actually emulate this
logerror("BRG %sabled, divide by %d, RxC %sternal, TxC %sternal\n",
BIT(data, 0) ? "en" : "dis",
BIT(data, 1) ? 64 : 4,
BIT(data, 2) ? "in" : "ex",
BIT(data, 3) ? "in" : "ex");
// unused bits are always zero
m_brg_control = data & 0x0f;
}
//-------------------------------------------------
// vectrg_w - write to the interrupt vector
// register (only one exists)
//-------------------------------------------------
void mk68564_device::vectrg_w(uint8_t data)
{
m_chanB->do_sioreg_wr2(data);
}
//-------------------------------------------------
// read - 68000 compatible bus read
//-------------------------------------------------
uint8_t mk68564_device::read(offs_t offset)
{
mk68564_channel &channel = downcast<mk68564_channel &>(BIT(offset, 4) ? *m_chanB : *m_chanA);
switch (offset & 0x0f)
{
case 0x00:
return channel.cmdreg_r();
case 0x01:
return channel.modectl_r();
case 0x02:
return channel.intctl_r();
case 0x03:
return channel.sync1_r();
case 0x04:
return channel.sync2_r();
case 0x05:
return channel.rcvctl_r();
case 0x06:
return channel.xmtctl_r();
case 0x07:
return channel.do_sioreg_rr0();
case 0x08:
return channel.do_sioreg_rr1();
case 0x09:
return channel.data_read();
case 0x0a:
return channel.tcreg_r();
case 0x0b:
return channel.brgctl_r();
case 0x0c: // vector register is addressable through either channel
return read_vector();
default: // unused registers read as FF
return 0xff;
}
}
//-------------------------------------------------
// write - 68000 compatible bus write
//-------------------------------------------------
void mk68564_device::write(offs_t offset, uint8_t data)
{
mk68564_channel &channel = downcast<mk68564_channel &>(BIT(offset, 4) ? *m_chanB : *m_chanA);
switch (offset & 0x0f)
{
case 0x00:
channel.cmdreg_w(data);
break;
case 0x01:
channel.modectl_w(data);
break;
case 0x02:
channel.intctl_w(data);
break;
case 0x03:
channel.sync1_w(data);
break;
case 0x04:
channel.sync2_w(data);
break;
case 0x05:
channel.rcvctl_w(data);
break;
case 0x06:
channel.xmtctl_w(data);
break;
case 0x09:
channel.data_write(data);
break;
case 0x0a:
channel.tcreg_w(data);
break;
case 0x0b:
channel.brgctl_w(data);
break;
case 0x0c: // vector register is addressable through either channel
vectrg_w(data);
break;
default:
LOG("Write %02X to unused/read-only register %02X\n", data, offset & 0x1f);
break;
}
}

View File

@ -49,6 +49,31 @@
R S S D K S D S S R D R S S D K S D S S R C
A A A A E B B B B B A A A A E B B B B
T T
_____ _____
D1 1|* \_/ |48 D0
D3 2| |47 D2
D5 3| |46 D4
D7 4| |45 D6
_INTR 5| |44 R/_W
IEO 6| |43 _IACK
IEI 7| |42 _DTACK
_M1 8| |41 _CS
_RESET 9| |40 _RxRDYB
_RxRDYA 10| |39 _TxRDYB
_TxRDYA 11| DIP48 |38 GND
Vcc 12| MK68564 |37 _IEI
_IEO 13| SIO |36 _SYNCB
_SYNCA 14| |35 _TxCB
_TxCA 15| |34 _RxCB
_RxCA 16| |29 RxDB
RxDA 17| |28 TxDB
TxDA 18| |27 _DTRB
_DTRA 19| |26 _RTSB
_RTSA 20| |25 _CTSB
_CTSA 21| |24 _DCDB
_DCDA 22| |23 A1
A2 23| |22 A3
A4 24|_____________|21 A5
***************************************************************************/
@ -80,6 +105,7 @@ class z80sio_channel : public device_t
friend class z80sio_device;
friend class i8274_new_device;
friend class upd7201_new_device;
friend class mk68564_device;
public:
z80sio_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@ -199,8 +225,8 @@ protected:
void set_dtr(int state);
void set_rts(int state);
int get_clock_mode();
int get_rx_word_length();
int get_clock_mode() const;
int get_rx_word_length() const;
int get_tx_word_length() const;
// receiver state
@ -258,14 +284,14 @@ protected:
int m_index;
z80sio_device *m_uart;
private:
protected:
// helpers
void out_txd_cb(int state);
void out_rts_cb(int state);
void out_dtr_cb(int state);
void set_ready(bool ready);
bool receive_allowed() const;
bool transmit_allowed() const;
virtual bool transmit_allowed() const;
void receive_enabled();
void enter_hunt_mode();
@ -304,6 +330,47 @@ public:
};
// ======================> mk68564_channel
class mk68564_channel : public z80sio_channel
{
friend class mk68564_device;
public:
mk68564_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual bool transmit_allowed() const override;
private:
uint8_t cmdreg_r();
void cmdreg_w(uint8_t data);
uint8_t modectl_r();
void modectl_w(uint8_t data);
uint8_t intctl_r();
void intctl_w(uint8_t data);
uint8_t sync1_r();
void sync1_w(uint8_t data);
uint8_t sync2_r();
void sync2_w(uint8_t data);
uint8_t rcvctl_r();
void rcvctl_w(uint8_t data);
uint8_t xmtctl_r();
void xmtctl_w(uint8_t data);
uint8_t tcreg_r();
void tcreg_w(uint8_t data);
uint8_t brgctl_r();
void brgctl_w(uint8_t data);
bool m_tx_auto_enable;
uint8_t m_brg_tc;
uint8_t m_brg_control;
};
// ======================> z80sio_device
class z80sio_device : public device_t,
@ -443,9 +510,26 @@ public:
upd7201_new_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
class mk68564_device : public i8274_new_device
{
public:
mk68564_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
protected:
// device_t overrides
virtual void device_add_mconfig(machine_config &config) override;
private:
void vectrg_w(uint8_t data);
};
// device type declaration
DECLARE_DEVICE_TYPE(Z80SIO, z80sio_device)
DECLARE_DEVICE_TYPE(I8274_NEW, i8274_new_device)
DECLARE_DEVICE_TYPE(UPD7201_NEW, upd7201_new_device)
DECLARE_DEVICE_TYPE(MK68564, mk68564_device)
#endif // MAME_MACHINE_Z80SIO_H

View File

@ -12,6 +12,7 @@
#include "emu.h"
#include "cpu/m68000/m68000.h"
#include "machine/hd63450.h"
#include "machine/z80sio.h"
#include "video/am8052.h"
@ -62,7 +63,7 @@ void e9161_state::mem_map(address_map &map)
map(0xffe000, 0xffe03f).rw(m_dmac, FUNC(hd63450_device::read), FUNC(hd63450_device::write));
map(0xffe802, 0xffe803).w("crtc", FUNC(am8052_device::pointer_w));
map(0xffe804, 0xffe805).w("crtc", FUNC(am8052_device::data_w));
//map(0xfff600, 0xfff63f).rw("sio", FUNC(mk68564_device::read), FUNC(mk68564_device::write)).umask16(0x00ff);
map(0xfff600, 0xfff63f).rw("sio", FUNC(mk68564_device::read), FUNC(mk68564_device::write)).umask16(0x00ff);
}
@ -78,6 +79,8 @@ void e9161_state::e9161(machine_config &config)
HD63450(config, m_dmac, 8'000'000, m_maincpu);
AM8052(config, "crtc", 8'000'000);
MK68564(config, "sio", 4'000'000);
}