From b26c4ed848d1f5b9b2f28a8fee162e086874bdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miodrag=20Milanovi=C4=87?= Date: Mon, 6 Jun 2022 10:48:41 +0200 Subject: [PATCH] Z180 ASCI (#9762) New working machines ----------------------------------- Micromint SB180 [Miodrag Milanovic] -z180: implemented ASCI serial communication [Miodrag Milanovic] -tim011: hookup serial keyboard [Miodrag Milanovic] -20pacgal: Add support for terminal --- scripts/src/cpu.lua | 2 + scripts/target/mame/mess.lua | 1 + src/devices/cpu/z180/z180.cpp | 256 ++--------- src/devices/cpu/z180/z180.h | 26 +- src/devices/cpu/z180/z180asci.cpp | 702 ++++++++++++++++++++++++++++++ src/devices/cpu/z180/z180asci.h | 201 +++++++++ src/mame/drivers/20pacgal.cpp | 24 +- src/mame/drivers/sb180.cpp | 124 ++++++ src/mame/drivers/tim011.cpp | 14 + src/mame/includes/20pacgal.h | 8 +- src/mame/mame.lst | 3 + src/mame/mess.flt | 1 + 12 files changed, 1139 insertions(+), 223 deletions(-) create mode 100644 src/devices/cpu/z180/z180asci.cpp create mode 100644 src/devices/cpu/z180/z180asci.h create mode 100644 src/mame/drivers/sb180.cpp diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index edf7e364896..b03eccaf618 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -2789,6 +2789,8 @@ if CPUS["Z180"] then MAME_DIR .. "src/devices/cpu/z180/z180ops.h", MAME_DIR .. "src/devices/cpu/z180/z180tbl.h", MAME_DIR .. "src/devices/cpu/z180/z180xy.hxx", + MAME_DIR .. "src/devices/cpu/z180/z180asci.cpp", + MAME_DIR .. "src/devices/cpu/z180/z180asci.h", } end diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 690d8755f49..c1101a709fa 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -4763,6 +4763,7 @@ files { MAME_DIR .. "src/mame/drivers/rvoice.cpp", MAME_DIR .. "src/mame/drivers/sacstate.cpp", MAME_DIR .. "src/mame/drivers/sartorius.cpp", + MAME_DIR .. "src/mame/drivers/sb180.cpp", MAME_DIR .. "src/mame/drivers/sb8085.cpp", MAME_DIR .. "src/mame/drivers/sbrain.cpp", MAME_DIR .. "src/mame/drivers/seattlecmp.cpp", diff --git a/src/devices/cpu/z180/z180.cpp b/src/devices/cpu/z180/z180.cpp index 6c68b877bca..db7b4a3026b 100644 --- a/src/devices/cpu/z180/z180.cpp +++ b/src/devices/cpu/z180/z180.cpp @@ -93,16 +93,12 @@ z180_device::z180_device(const machine_config &mconfig, device_type type, const , m_program_config("program", ENDIANNESS_LITTLE, 8, 20, 0, 16, 12, internal_map) , m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0) , m_decrypted_opcodes_config("opcodes", ENDIANNESS_LITTLE, 8, 20, 0, 16, 12, internal_map) + , m_asci(*this, "asci_%u", 0U) , m_extended_io(extended_io) , m_tend0_cb(*this) , m_tend1_cb(*this) { // some arbitrary initial values - m_asci_cntla[0] = m_asci_cntla[1] = 0; - m_asci_cntlb[0] = m_asci_cntlb[1] = 0; - m_asci_stat[0] = 0; - m_asci_tdr[0] = m_asci_tdr[1] = 0; - m_asci_rdr[0] = m_asci_rdr[1] = 0; m_csio_trdr = 0; m_tmdr[0].w = m_tmdr[1].w = 0; m_rldr[0].w = m_rldr[1].w = 0xffff; @@ -133,8 +129,6 @@ hd64180rp_device::hd64180rp_device(const machine_config &mconfig, const char *ta z8s180_device::z8s180_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : z180_device(mconfig, type, tag, owner, clock, false, address_map_constructor()) { - // some arbitrary initial values - m_asci_tc[0].w = m_asci_tc[1].w = 0; } z8s180_device::z8s180_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) @@ -242,60 +236,6 @@ bool z180_device::get_tend1() #define _LY m_IY.b.l -/* 00 ASCI control register A ch 0 */ -#define Z180_CNTLA0_MPE 0x80 -#define Z180_CNTLA0_RE 0x40 -#define Z180_CNTLA0_TE 0x20 -#define Z180_CNTLA0_RTS0 0x10 -#define Z180_CNTLA0_MPBR_EFR 0x08 -#define Z180_CNTLA0_MODE_DATA 0x04 -#define Z180_CNTLA0_MODE_PARITY 0x02 -#define Z180_CNTLA0_MODE_STOPB 0x01 - -/* 01 ASCI control register A ch 1 */ -#define Z180_CNTLA1_MPE 0x80 -#define Z180_CNTLA1_RE 0x40 -#define Z180_CNTLA1_TE 0x20 -#define Z180_CNTLA1_CKA1D 0x10 -#define Z180_CNTLA1_MPBR_EFR 0x08 -#define Z180_CNTLA1_MODE 0x07 - -/* 02 ASCI control register B ch 0 */ -#define Z180_CNTLB0_MPBT 0x80 -#define Z180_CNTLB0_MP 0x40 -#define Z180_CNTLB0_CTS_PS 0x20 -#define Z180_CNTLB0_PEO 0x10 -#define Z180_CNTLB0_DR 0x08 -#define Z180_CNTLB0_SS 0x07 - -/* 03 ASCI control register B ch 1 */ -#define Z180_CNTLB1_MPBT 0x80 -#define Z180_CNTLB1_MP 0x40 -#define Z180_CNTLB1_CTS_PS 0x20 -#define Z180_CNTLB1_PEO 0x10 -#define Z180_CNTLB1_DR 0x08 -#define Z180_CNTLB1_SS 0x07 - -/* 04 ASCI status register 0 (all bits read-only except RIE and TIE) */ -#define Z180_STAT0_RDRF 0x80 -#define Z180_STAT0_OVRN 0x40 -#define Z180_STAT0_PE 0x20 -#define Z180_STAT0_FE 0x10 -#define Z180_STAT0_RIE 0x08 -#define Z180_STAT0_DCD0 0x04 -#define Z180_STAT0_TDRE 0x02 -#define Z180_STAT0_TIE 0x01 - -/* 05 ASCI status register 1 (all bits read-only except RIE, CTS1E and TIE) */ -#define Z180_STAT1_RDRF 0x80 -#define Z180_STAT1_OVRN 0x40 -#define Z180_STAT1_PE 0x20 -#define Z180_STAT1_FE 0x10 -#define Z180_STAT1_RIE 0x08 -#define Z180_STAT1_CTS1E 0x04 -#define Z180_STAT1_TDRE 0x02 -#define Z180_STAT1_TIE 0x01 - /* 0a CSI/O control/status register (EF is read-only) */ #define Z180_CNTR_EF 0x80 #define Z180_CNTR_EIE 0x40 @@ -315,26 +255,6 @@ bool z180_device::get_tend1() #define Z180_TCR_TDE1 0x02 #define Z180_TCR_TDE0 0x01 -/* 12 (Z8S180/Z8L180) ASCI extension control register 0 (break detect is read-only) */ -#define Z180_ASEXT0_DCD0 0x40 -#define Z180_ASEXT0_CTS0 0x20 -#define Z180_ASEXT0_X1_BIT_CLK0 0x10 -#define Z180_ASEXT0_BRG0_MODE 0x08 -#define Z180_ASEXT0_BRK_EN 0x04 -#define Z180_ASEXT0_BRK_DET 0x02 -#define Z180_ASEXT0_BRK_SEND 0x01 - -#define Z180_ASEXT0_MASK 0x7f - -/* 13 (Z8S180/Z8L180) ASCI extension control register 1 (break detect is read-only) */ -#define Z180_ASEXT1_X1_BIT_CLK1 0x10 -#define Z180_ASEXT1_BRG1_MODE 0x08 -#define Z180_ASEXT1_BRK_EN 0x04 -#define Z180_ASEXT1_BRK_DET 0x02 -#define Z180_ASEXT1_BRK_SEND 0x01 - -#define Z180_ASEXT1_MASK 0x1f - /* 1e (Z8S180/Z8L180) clock multiplier */ #define Z180_CMR_X2 0x80 #define Z180_CMR_LOW_NOISE 0x40 @@ -505,54 +425,28 @@ uint8_t z180_device::z180_internal_port_read(uint8_t port) switch (port) { case 0x00: - data = m_asci_cntla[0]; - LOG("Z180 CNTLA0 rd $%02x\n", data); - break; - case 0x01: - data = m_asci_cntla[1]; - LOG("Z180 CNTLA1 rd $%02x\n", data); + data = m_asci[port & 1]->cntla_r(); break; case 0x02: - data = m_asci_cntlb[0]; - LOG("Z180 CNTLB0 rd $%02x\n", data); - break; - case 0x03: - data = m_asci_cntlb[1]; - LOG("Z180 CNTLB1 rd $%02x\n", data); + data = m_asci[port & 1]->cntlb_r(); break; case 0x04: - data = m_asci_stat[0]; - data |= 0x02; // kludge for 20pacgal - LOG("Z180 STAT0 rd $%02x\n", data); - break; - case 0x05: - data = m_asci_stat[1]; - LOG("Z180 STAT1 rd $%02x\n", data); + data = m_asci[port & 1]->stat_r(); break; case 0x06: - data = m_asci_tdr[0]; - LOG("Z180 TDR0 rd $%02x\n", data); - break; - case 0x07: - data = m_asci_tdr[1]; - LOG("Z180 TDR1 rd $%02x\n", data); + data = m_asci[port & 1]->tdr_r(); break; case 0x08: - data = m_asci_rdr[0]; - LOG("Z180 RDR0 rd $%02x\n", data); - break; - case 0x09: - data = m_asci_rdr[1]; - LOG("Z180 RDR1 rd $%02x\n", data); + data = m_asci[port & 1]->rdr_r(); break; case 0x0a: @@ -869,53 +763,28 @@ void z180_device::z180_internal_port_write(uint8_t port, uint8_t data) switch (port) { case 0x00: - LOG("Z180 CNTLA0 wr $%02x\n", data); - m_asci_cntla[0] = data; - break; - case 0x01: - LOG("Z180 CNTLA1 wr $%02x\n", data); - m_asci_cntla[1] = data; + m_asci[port & 1]->cntla_w(data); break; case 0x02: - LOG("Z180 CNTLB0 wr $%02x\n", data); - m_asci_cntlb[0] = data; - break; - case 0x03: - LOG("Z180 CNTLB1 wr $%02x\n", data); - m_asci_cntlb[1] = data; + m_asci[port & 1]->cntlb_w(data); break; case 0x04: - LOG("Z180 STAT0 wr $%02x ($%02x)\n", data, data & (Z180_STAT0_RIE | Z180_STAT0_TIE)); - m_asci_stat[0] = (m_asci_stat[0] & ~(Z180_STAT0_RIE | Z180_STAT0_TIE)) | (data & (Z180_STAT0_RIE | Z180_STAT0_TIE)); - break; - case 0x05: - LOG("Z180 STAT1 wr $%02x ($%02x)\n", data, data & (Z180_STAT1_RIE | Z180_STAT1_CTS1E | Z180_STAT1_TIE)); - m_asci_stat[1] = (m_asci_stat[1] & ~(Z180_STAT1_RIE | Z180_STAT1_CTS1E | Z180_STAT1_TIE)) | (data & (Z180_STAT1_RIE | Z180_STAT1_CTS1E | Z180_STAT1_TIE)); + m_asci[port & 1]->stat_w(data); break; case 0x06: - LOG("Z180 TDR0 wr $%02x\n", data); - m_asci_tdr[0] = data; - break; - case 0x07: - LOG("Z180 TDR1 wr $%02x\n", data); - m_asci_tdr[1] = data; + m_asci[port & 1]->tdr_w(data); break; case 0x08: - LOG("Z180 RDR0 wr $%02x\n", data); - m_asci_rdr[0] = data; - break; - case 0x09: - LOG("Z180 RDR1 wr $%02x\n", data); - m_asci_rdr[1] = data; + m_asci[port & 1]->rdr_w(data); break; case 0x0a: @@ -1152,33 +1021,18 @@ uint8_t z8s180_device::z180_internal_port_read(uint8_t port) switch (port) { case 0x12: - data = m_asci_ext[0]; - LOG("Z180 ASEXT0 rd $%02x ($%02x)\n", data, m_asci_ext[0]); - break; - case 0x13: - data = m_asci_ext[1]; - LOG("Z180 ASEXT1 rd $%02x ($%02x)\n", data, m_asci_ext[1]); + data = m_asci[port & 1]->asext_r(); break; case 0x1a: - LOG("Z180 ASTC0L wr $%02x\n", data); - m_asci_tc[0].b.l = data; - break; - case 0x1b: - LOG("Z180 ASTC0H wr $%02x\n", data); - m_asci_tc[0].b.h = data; + data = m_asci[port & 1]->astcl_r(); break; case 0x1c: - LOG("Z180 ASTC1L wr $%02x\n", data); - m_asci_tc[1].b.l = data; - break; - case 0x1d: - LOG("Z180 ASTC1H wr $%02x\n", data); - m_asci_tc[1].b.h = data; + data = m_asci[port & 1]->astcl_r(); break; case 0x1e: @@ -1204,33 +1058,18 @@ void z8s180_device::z180_internal_port_write(uint8_t port, uint8_t data) switch (port) { case 0x12: - LOG("Z180 ASEXT0 wr $%02x ($%02x)\n", data, data & Z180_ASEXT0_MASK & ~Z180_ASEXT0_BRK_DET); - m_asci_ext[0] = (m_asci_ext[0] & Z180_ASEXT0_BRK_DET) | (data & Z180_ASEXT0_MASK & ~Z180_ASEXT0_BRK_DET); - break; - case 0x13: - LOG("Z180 ASEXT1 wr $%02x ($%02x)\n", data, data & Z180_ASEXT1_MASK & ~Z180_ASEXT1_BRK_DET); - m_asci_ext[1] = (m_asci_ext[1] & Z180_ASEXT1_BRK_DET) | (data & Z180_ASEXT1_MASK & ~Z180_ASEXT1_BRK_DET); + m_asci[port & 1]->asext_w(data); break; case 0x1a: - data = m_asci_tc[0].b.l; - LOG("Z180 ASTC0L rd $%02x ($%04x)\n", data, m_asci_tc[0].w); - break; - case 0x1b: - data = m_asci_tc[0].b.h; - LOG("Z180 ASTC0H rd $%02x ($%04x)\n", data, m_asci_tc[0].w); + m_asci[port & 1]->astcl_w(data); break; case 0x1c: - data = m_asci_tc[1].b.l; - LOG("Z180 ASTC1L rd $%02x ($%04x)\n", data, m_asci_tc[1].w); - break; - case 0x1d: - data = m_asci_tc[1].b.h; - LOG("Z180 ASTC1H rd $%02x ($%04x)\n", data, m_asci_tc[1].w); + m_asci[port & 1]->astch_w(data); break; case 0x1e: @@ -1725,18 +1564,8 @@ void z180_device::device_start() state_add(Z180_IOLINES, "IOLINES", m_ioltemp).mask(0xffffff).callimport(); - state_add(Z180_CNTLA0, "CNTLA0", m_asci_cntla[0]); - state_add(Z180_CNTLB0, "CNTLB0", m_asci_cntlb[0]); - state_add(Z180_STAT0, "STAT0", m_asci_stat[0]); - state_add(Z180_TDR0, "TDR0", m_asci_tdr[0]); - state_add(Z180_RDR0, "RDR0", m_asci_rdr[0]); - - state_add(Z180_CNTLA1, "CNTLA1", m_asci_cntla[1]); - state_add(Z180_CNTLB1, "CNTLB1", m_asci_cntlb[1]); - state_add(Z180_STAT1, "STAT1", m_asci_stat[1]); - state_add(Z180_TDR1, "TDR1", m_asci_tdr[1]); - state_add(Z180_RDR1, "RDR1", m_asci_rdr[1]); - + m_asci[0]->state_add(*this); + m_asci[1]->state_add(*this); state_add(Z180_CNTR, "CNTR", m_csio_cntr).mask(Z180_CNTR_MASK); state_add(Z180_TRDR, "TRDR", m_csio_trdr); @@ -1798,11 +1627,6 @@ void z180_device::device_start() save_item(NAME(m_tmdrh)); save_item(NAME(m_tmdr_latch)); - save_item(NAME(m_asci_cntla)); - save_item(NAME(m_asci_cntlb)); - save_item(NAME(m_asci_stat)); - save_item(NAME(m_asci_tdr)); - save_item(NAME(m_asci_rdr)); save_item(NAME(m_csio_cntr)); save_item(NAME(m_csio_trdr)); save_item(NAME(m_tmdr[0].w)); @@ -1841,18 +1665,9 @@ void z8s180_device::device_start() { z180_device::device_start(); - state_add(Z180_ASEXT0, "ASEXT0", m_asci_ext[0]).mask(Z180_ASEXT0_MASK); - state_add(Z180_ASTC0, "ASTC0", m_asci_tc[0].w); - - state_add(Z180_ASEXT1, "ASEXT1", m_asci_ext[1]).mask(Z180_ASEXT1_MASK); - state_add(Z180_ASTC1, "ASTC1", m_asci_tc[1].w); - state_add(Z180_CMR, "CMR", m_cmr).mask(Z180_CMR_MASK); state_add(Z180_CCR, "CCR", m_ccr); - save_item(NAME(m_asci_ext)); - save_item(NAME(m_asci_tc[0].w)); - save_item(NAME(m_asci_tc[1].w)); save_item(NAME(m_cmr)); save_item(NAME(m_ccr)); } @@ -1912,12 +1727,6 @@ void z180_device::device_reset() m_frc_prescale = 0; /* reset io registers */ - m_asci_cntla[0] = (m_asci_cntla[0] & Z180_CNTLA0_MPBR_EFR) | Z180_CNTLA0_RTS0; - m_asci_cntla[1] = (m_asci_cntla[1] & Z180_CNTLA1_MPBR_EFR) | Z180_CNTLA1_CKA1D; - m_asci_cntlb[0] = (m_asci_cntlb[0] & (Z180_CNTLB0_MPBT | Z180_CNTLB0_CTS_PS)) | 0x07; - m_asci_cntlb[1] = (m_asci_cntlb[1] & Z180_CNTLB1_MPBT) | 0x07; - m_asci_stat[0] = m_asci_stat[0] & (Z180_STAT0_DCD0 | Z180_STAT0_TDRE); - m_asci_stat[1] = Z180_STAT1_TDRE; m_csio_cntr = 0x07; m_tcr = 0x00; m_dma_iar1.b.h2 = 0x00; @@ -1936,17 +1745,35 @@ void z180_device::device_reset() z180_mmu(); } +void z180_device::device_add_mconfig(machine_config &config) +{ + Z180ASCI_CHANNEL_0(config, m_asci[0], DERIVED_CLOCK(1,2)); + + Z180ASCI_CHANNEL_1(config, m_asci[1], DERIVED_CLOCK(1,2)); +} + +void z8s180_device::device_add_mconfig(machine_config &config) +{ + Z180ASCI_EXT_CHANNEL_0(config, m_asci[0], DERIVED_CLOCK(1,2)); + + Z180ASCI_EXT_CHANNEL_1(config, m_asci[1], DERIVED_CLOCK(1,2)); +} + void z8s180_device::device_reset() { z180_device::device_reset(); - m_asci_ext[0] = 0x00; - m_asci_ext[1] = 0x00; m_cmr = 0x00; m_ccr = 0x00; notify_clock_changed(); } +void z8s180_device::device_clock_changed() +{ + m_asci[0]->set_clock((m_cmr & 0x80) ? DERIVED_CLOCK(2,1) : (m_ccr & 0x80) ? DERIVED_CLOCK(1,1) : DERIVED_CLOCK(1,2)); + m_asci[1]->set_clock((m_cmr & 0x80) ? DERIVED_CLOCK(2,1) : (m_ccr & 0x80) ? DERIVED_CLOCK(1,1) : DERIVED_CLOCK(1,2)); +} + /* Handle PRT timers, decreasing them after 20 clocks and returning the new icount base that needs to be used for the next check */ void z180_device::clock_timers() { @@ -2005,6 +1832,9 @@ int z180_device::check_interrupts() if (m_irq_state[2] != CLEAR_LINE && (m_itc & Z180_ITC_ITE2) == Z180_ITC_ITE2) m_int_pending[Z180_INT_IRQ2] = 1; + + m_int_pending[Z180_INT_ASCI0] = m_asci[0]->check_interrupt(); + m_int_pending[Z180_INT_ASCI1] = m_asci[1]->check_interrupt(); } for (i = 0; i <= Z180_INT_MAX; i++) @@ -2012,6 +1842,8 @@ int z180_device::check_interrupts() { cycles += take_interrupt(i); m_int_pending[i] = 0; + if (i == Z180_INT_ASCI0) m_asci[0]->clear_interrupt(); + if (i == Z180_INT_ASCI1) m_asci[1]->clear_interrupt(); break; } diff --git a/src/devices/cpu/z180/z180.h b/src/devices/cpu/z180/z180.h index 94b95d1488e..62213845b05 100644 --- a/src/devices/cpu/z180/z180.h +++ b/src/devices/cpu/z180/z180.h @@ -6,7 +6,7 @@ #pragma once #include "machine/z80daisy.h" - +#include "z180asci.h" enum { @@ -107,10 +107,23 @@ class z180_device : public cpu_device, public z80_daisy_chain_interface public: auto tend0_wr_callback() { return m_tend0_cb.bind(); } auto tend1_wr_callback() { return m_tend1_cb.bind(); } + auto txa0_wr_callback() { return subdevice("asci_0")->txa_handler(); } + auto txa1_wr_callback() { return subdevice("asci_1")->txa_handler(); } + auto rts0_wr_callback() { return subdevice("asci_0")->rts_handler(); } + auto cka0_wr_callback() { return subdevice("asci_0")->cka_handler(); } + auto cka1_wr_callback() { return subdevice("asci_1")->cka_handler(); } bool get_tend0(); bool get_tend1(); + DECLARE_WRITE_LINE_MEMBER( rxa0_w ) { m_asci[0]->rxa_wr(state); } + DECLARE_WRITE_LINE_MEMBER( rxa1_w ) { m_asci[1]->rxa_wr(state); } + DECLARE_WRITE_LINE_MEMBER( cts0_w ) { m_asci[0]->cts_wr(state); } + DECLARE_WRITE_LINE_MEMBER( cts1_w ) { m_asci[1]->cts_wr(state); } + DECLARE_WRITE_LINE_MEMBER( dcd0_w ) { m_asci[0]->dcd_wr(state); } + DECLARE_WRITE_LINE_MEMBER( cka0_w ) { m_asci[0]->cka_wr(state); } + DECLARE_WRITE_LINE_MEMBER( cka1_w ) { m_asci[1]->cka_wr(state); } + protected: // construction/destruction z180_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool extended_io, address_map_constructor internal_map); @@ -119,6 +132,7 @@ protected: virtual void device_start() override; virtual void device_reset() override; virtual void device_resolve_objects() override; + virtual void device_add_mconfig(machine_config &config) override; // device_execute_interface overrides virtual uint32_t execute_min_cycles() const noexcept override { return 1; } @@ -150,6 +164,7 @@ protected: address_space_config m_program_config; address_space_config m_io_config; address_space_config m_decrypted_opcodes_config; + required_device_array m_asci; void set_address_width(int bits); @@ -169,11 +184,6 @@ private: uint8_t m_tmdr_latch; // flag latched TMDR0H, TMDR1H values uint8_t m_read_tcr_tmdr[2]; // flag to indicate that TCR or TMDR was read uint32_t m_iol; // I/O line status bits - uint8_t m_asci_cntla[2]; // ASCI control register A ch 0-1 - uint8_t m_asci_cntlb[2]; // ASCI control register B ch 0-1 - uint8_t m_asci_stat[2]; // ASCI status register 0-1 - uint8_t m_asci_tdr[2]; // ASCI transmit data register 0-1 - uint8_t m_asci_rdr[2]; // ASCI receive data register 0-1 uint8_t m_csio_cntr; // CSI/O control/status register uint8_t m_csio_trdr; // CSI/O transmit/receive register PAIR16 m_tmdr[2]; // PRT data register ch 0-1 @@ -1822,6 +1832,8 @@ protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; + virtual void device_clock_changed() override; + virtual void device_add_mconfig(machine_config &config) override; // device_execute_interface overrides virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override { return BIT(m_cmr, 7) ? (clocks * 2) : BIT(m_ccr, 7) ? clocks : (clocks + 2 - 1) / 2; } @@ -1831,8 +1843,6 @@ protected: virtual void z180_internal_port_write(uint8_t port, uint8_t data) override; private: - uint8_t m_asci_ext[2]; // ASCI extension control register 0-1 - PAIR16 m_asci_tc[2]; // ASCI time constant ch 0-1 uint8_t m_cmr; // clock multiplier uint8_t m_ccr; // chip control register }; diff --git a/src/devices/cpu/z180/z180asci.cpp b/src/devices/cpu/z180/z180asci.cpp new file mode 100644 index 00000000000..69c225accaa --- /dev/null +++ b/src/devices/cpu/z180/z180asci.cpp @@ -0,0 +1,702 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************* + + z180asci.cpp + +*********************************************************************/ + +#include "emu.h" +#include "z180.h" + +//#define VERBOSE 1 + +#include "logmacro.h" + +/* 00 ASCI control register A ch 0 */ +static constexpr u8 Z180_CNTLA_MPE = 0x80; +static constexpr u8 Z180_CNTLA_RE = 0x40; +static constexpr u8 Z180_CNTLA_TE = 0x20; +static constexpr u8 Z180_CNTLA_RTS0 = 0x10; +static constexpr u8 Z180_CNTLA_MPBR_EFR = 0x08; +static constexpr u8 Z180_CNTLA_MODE = 0x07; +static constexpr u8 Z180_CNTLA_MODE_DATA = 0x04; +static constexpr u8 Z180_CNTLA_MODE_PARITY = 0x02; +static constexpr u8 Z180_CNTLA_MODE_STOPB = 0x01; + +/* 01 ASCI control register A ch 1 */ +static constexpr u8 Z180_CNTLA1_CKA1D = 0x10; + +/* 02/03 ASCI control register B ch 0 */ +static constexpr u8 Z180_CNTLB_MPBT = 0x80; +static constexpr u8 Z180_CNTLB_MP = 0x40; +static constexpr u8 Z180_CNTLB_CTS_PS = 0x20; +static constexpr u8 Z180_CNTLB_PEO = 0x10; +static constexpr u8 Z180_CNTLB_DR = 0x08; +static constexpr u8 Z180_CNTLB_SS = 0x07; + +/* 04 ASCI status register 0 (all bits read-only except RIE and TIE) */ +static constexpr u8 Z180_STAT_RDRF = 0x80; +static constexpr u8 Z180_STAT_OVRN = 0x40; +static constexpr u8 Z180_STAT_PE = 0x20; +static constexpr u8 Z180_STAT_FE = 0x10; +static constexpr u8 Z180_STAT_RIE = 0x08; +static constexpr u8 Z180_STAT_DCD0 = 0x04; +static constexpr u8 Z180_STAT_TDRE = 0x02; +static constexpr u8 Z180_STAT_TIE = 0x01; + +/* 05 ASCI status register 1 (all bits read-only except RIE, CTS1E and TIE) */ +static constexpr u8 Z180_STAT1_CTS1E = 0x04; + +/* 12/13 (Z8S180/Z8L180) ASCI extension control register 0 (break detect is read-only) */ +static constexpr u8 Z180_ASEXT_DCD0 = 0x40; +static constexpr u8 Z180_ASEXT_CTS0 = 0x20; +static constexpr u8 Z180_ASEXT_X1_BIT_CLK0 = 0x10; +static constexpr u8 Z180_ASEXT_BRG0_MODE = 0x08; +static constexpr u8 Z180_ASEXT_BRK_EN = 0x04; +static constexpr u8 Z180_ASEXT_BRK_DET = 0x02; +static constexpr u8 Z180_ASEXT_BRK_SEND = 0x01; + +static constexpr u8 Z180_ASEXT0_MASK = 0x7f; +static constexpr u8 Z180_ASEXT1_MASK = 0x1f; + + +//************************************************************************** +// z180asci_channel_base +//************************************************************************** + +z180asci_channel_base::z180asci_channel_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const int id, const bool ext) + : device_t(mconfig, type, tag, owner, clock) + , m_rcv_clock(nullptr) + , m_tra_clock(nullptr) + , m_bit_rate(attotime::never) + , m_sample_rate(attotime::never) + , m_txa_handler(*this) + , m_rts_handler(*this) + , m_cka_handler(*this) + , m_cts(0) + , m_dcd(0) + , m_irq(0) + , m_rts(0) + , m_divisor(0) + , m_id(id) + , m_ext(ext) +{ +} + + +void z180asci_channel_base::device_resolve_objects() +{ + // resolve callbacks + m_txa_handler.resolve_safe(); + m_rts_handler.resolve_safe(); + m_cka_handler.resolve_safe(); +} + +void z180asci_channel_base::device_start() +{ + save_item(NAME(m_asci_cntla)); + save_item(NAME(m_asci_cntlb)); + save_item(NAME(m_asci_stat)); + save_item(NAME(m_asci_tdr)); + save_item(NAME(m_asci_rdr)); + if (m_ext) + { + save_item(NAME(m_asci_ext)); + save_item(NAME(m_asci_tc.w)); + } + save_item(NAME(m_tsr)); + save_item(NAME(m_rsr)); + save_item(NAME(m_data_fifo)); + save_item(NAME(m_error_fifo)); + save_item(NAME(m_fifo_wr)); + save_item(NAME(m_fifo_rd)); + + save_item(NAME(m_cts)); + save_item(NAME(m_dcd)); + save_item(NAME(m_irq)); + save_item(NAME(m_txa)); + save_item(NAME(m_rxa)); + save_item(NAME(m_rts)); + + save_item(NAME(m_divisor)); + + save_item(NAME(m_clock_state)); + + save_item(NAME(m_tx_counter)); + save_item(NAME(m_tx_state)); + + save_item(NAME(m_rx_state)); + save_item(NAME(m_rx_bits)); + save_item(NAME(m_rx_counter)); + save_item(NAME(m_rx_count_to)); + save_item(NAME(m_rx_total_bits)); + save_item(NAME(m_rx_enabled)); + + save_item(NAME(m_bit_rate)); + save_item(NAME(m_sample_rate)); + + + m_rcv_clock = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z180asci_channel_base::rcv_clock), this)); + m_tra_clock = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(z180asci_channel_base::tra_clock), this)); + +} + +void z180asci_channel_base::device_reset() +{ + m_asci_ext = 0; + m_asci_tc.w = 0; + + m_fifo_wr = 0; + m_fifo_rd = 0; + + output_txa(1); + output_rts(1); + + m_tsr = 0; + m_rxa = 1; + m_clock_state = 0; + m_tx_state = STATE_WAIT; + m_rx_state = STATE_START; + m_rx_bits = 0; + m_rx_enabled = true; + + m_tx_counter = 0; + m_rx_counter = 0; + m_rx_count_to = 1; +} + +void z180asci_channel_base::device_clock_changed() +{ + uint32_t brg_divisor; + // Divide ratio + m_divisor = (m_asci_ext & Z180_ASEXT_X1_BIT_CLK0) ? 1 : ((m_asci_cntlb & Z180_CNTLB_DR) ? 64 : 16); + + if ((m_asci_cntlb & Z180_CNTLB_SS) == Z180_CNTLB_SS) + { + // External clock + brg_divisor = 0; + } + else + { + if (m_asci_ext & Z180_ASEXT_BRG0_MODE) + { + // Extended boud rate generator mode + brg_divisor = m_asci_tc.w + 2; + } + else + { + // Regular bitrate generator mode + brg_divisor = 1 << (m_asci_cntlb & Z180_CNTLB_SS); + brg_divisor *= ((m_asci_cntlb & Z180_CNTLB_CTS_PS) ? 30 : 10); // Prescale + } + } + + if (brg_divisor) + { + LOG("Z180 ASCI%d set bitrate %d\n", m_id, uint32_t(clock() / brg_divisor / m_divisor)); + m_bit_rate = attotime::from_hz(clock() / brg_divisor / m_divisor); + m_sample_rate = attotime::from_hz(clock() / brg_divisor); + } + else + { + LOG("Z180 ASCI%d set bitrate 0, using external\n", m_id); + m_bit_rate = attotime::never; + m_sample_rate = attotime::never; + } + + m_tra_clock->adjust(attotime::never); + m_rx_state = STATE_START; + m_rx_count_to = 1; + if(!m_sample_rate.is_never()) + m_rcv_clock->adjust(m_sample_rate, 0, m_sample_rate); +} + +uint8_t z180asci_channel_base::cntla_r() +{ + LOG("Z180 CNTLA%d rd $%02x\n", m_id, m_asci_cntla); + return m_asci_cntla; +} + +uint8_t z180asci_channel_base::cntlb_r() +{ + uint8_t data = (m_asci_cntlb & 0x0d) | (m_cts << 5); + LOG("Z180 CNTLB%d rd $%02x\n", m_id, data); + return data; +} + +uint8_t z180asci_channel_base::stat_r() +{ + LOG("Z180 STAT%d rd $%02x\n", m_id, m_asci_stat); + return m_asci_stat; +} + +uint8_t z180asci_channel_base::tdr_r() +{ + LOG("Z180 TDR%d rd $%02x\n", m_id, m_asci_tdr); + return m_asci_tdr; +} + +uint8_t z180asci_channel_base::rdr_r() +{ + LOG("Z180 RDR%d rd $%02x\n", m_id, m_asci_rdr); + if (!machine().side_effects_disabled()) + { + if (m_fifo_rd != m_fifo_wr) + { + m_asci_rdr = m_data_fifo[m_fifo_rd]; + m_asci_stat &= ~(Z180_STAT_OVRN | Z180_STAT_PE | Z180_STAT_FE); + m_asci_stat |= m_error_fifo[m_fifo_rd]; + if (m_asci_stat & (Z180_STAT_OVRN | Z180_STAT_PE | Z180_STAT_FE)) + m_irq = 1; + m_fifo_rd = (m_fifo_rd + 1) & 3; + if (m_fifo_rd == m_fifo_wr) // empty + m_asci_stat &= ~Z180_STAT_RDRF; + } + } + return m_asci_rdr; +} + +uint8_t z180asci_channel_base::asext_r() +{ + LOG("Z180 ASEXT%d rd $%02x\n", m_id, m_asci_ext); + return m_asci_ext; +} + +uint8_t z180asci_channel_base::astcl_r() +{ + LOG("Z180 ASTC%dL rd $%02x ($%04x)\n", m_id, m_asci_tc.b.l, m_asci_tc.w); + return m_asci_tc.b.l; +} + +uint8_t z180asci_channel_base::astch_r() +{ + LOG("Z180 ASTC%dH rd $%02x ($%04x)\n", m_id, m_asci_tc.b.h, m_asci_tc.w); + return m_asci_tc.b.h; +} + +void z180asci_channel_base::update_total_bits() +{ + m_rx_total_bits = (m_asci_cntla & Z180_CNTLA_MODE_DATA) ? 8 : 7; + m_rx_total_bits += (m_asci_cntla & Z180_CNTLA_MODE_STOPB) ? 2 : 1; + m_rx_total_bits += (m_asci_cntlb & Z180_CNTLB_MP) ? 1 : ((m_asci_cntla & Z180_CNTLA_MODE_PARITY) ? 1 : 0); +} + +void z180asci_channel_base::cntla_w(uint8_t data) +{ + LOG("Z180 CNTLA%d wr $%02x\n", m_id, data); + m_asci_cntla = data & ~(Z180_CNTLA_MPBR_EFR | Z180_CNTLA_RTS0); + output_rts(BIT(data,4)); // Z180_CNTLA_RTS0 + if (data & Z180_CNTLA_MPBR_EFR) // Error Flag Reset + { + m_asci_stat &= ~(Z180_STAT_OVRN | Z180_STAT_PE | Z180_STAT_FE); + m_asci_ext &= ~(Z180_ASEXT_BRK_DET); + } + update_total_bits(); +} + +void z180asci_channel_base::cntlb_w(uint8_t data) +{ + LOG("Z180 CNTLB%d wr $%02x\n", m_id, data); + m_asci_cntlb = data; + device_clock_changed(); + update_total_bits(); +} + +void z180asci_channel_base::tdr_w(uint8_t data) +{ + LOG("Z180 TDR%d wr $%02x\n", m_id, data); + m_asci_tdr = data; + m_asci_stat &= ~Z180_STAT_TDRE; + + if (!m_bit_rate.is_never()) + m_tra_clock->adjust(m_bit_rate, 0, m_bit_rate); +} + +void z180asci_channel_base::rdr_w(uint8_t data) +{ + LOG("Z180 RDR%d wr $%02x\n", m_id, data); + if (!(m_asci_stat & Z180_STAT_RDRF)) + set_fifo_data(data, 0); +} + +void z180asci_channel_base::asext_w(uint8_t data) +{ + if (m_asci_ext & Z180_ASEXT_BRK_EN) + m_tx_state = (m_asci_ext & Z180_ASEXT_BRK_SEND) ? STATE_BREAK : STATE_WAIT; + device_clock_changed(); +} + +void z180asci_channel_base::astcl_w(uint8_t data) +{ + LOG("Z180 ASTC%dL wr $%02x\n", m_id, data); + m_asci_tc.b.l = data; + device_clock_changed(); +} + +void z180asci_channel_base::astch_w(uint8_t data) +{ + LOG("Z180 ASTC%dH wr $%02x\n", m_id, data); + m_asci_tc.b.h = data; + device_clock_changed(); +} + +DECLARE_WRITE_LINE_MEMBER( z180asci_channel_base::cts_wr ) +{ + if (m_id) + { + // For channel 1, CTS can be disabled + if ((m_asci_stat && Z180_STAT1_CTS1E) == 0) return; + } + else + { + // For channel 0, high resets TDRE + if (m_ext && state && (m_asci_ext && Z180_ASEXT_CTS0) == 0) + m_asci_stat |= Z180_STAT_TDRE; + } + m_cts = state; +} + +DECLARE_WRITE_LINE_MEMBER( z180asci_channel_base::dcd_wr ) +{ + if (m_id) + return; + + // In extended mode, DCD autoenables RX if configured + if (m_ext && (m_asci_ext && Z180_ASEXT_DCD0) == 0) + { + m_rx_enabled = state ? false : true; + if (state) + m_asci_ext &= ~(Z180_ASEXT_BRK_DET); + } + + m_dcd = state; + if (m_dcd) + m_irq = 1; +} + +DECLARE_WRITE_LINE_MEMBER( z180asci_channel_base::rxa_wr ) +{ + m_rxa = state; +} + +DECLARE_WRITE_LINE_MEMBER( z180asci_channel_base::cka_wr ) +{ + // For channel 1, CKA can be disabled + if (m_id && (m_asci_cntla && Z180_CNTLA1_CKA1D)) return; + + if(state != m_clock_state) + { + m_clock_state = state; + if(!state) + { + m_tx_counter++; + if (m_tx_counter != m_divisor) return; + m_tx_counter = 0; + if (m_asci_cntla & Z180_CNTLA_TE) + transmit_edge(); + } + else + { + m_rx_counter++; + if (m_rx_counter != m_rx_count_to) return; + m_rx_counter = 0; + if (m_rx_enabled && (m_asci_cntla & Z180_CNTLA_RE)) + receive_edge(); + } + } +} + +void z180asci_channel_base::prepare_tsr() +{ + int bits = (m_asci_cntla & Z180_CNTLA_MODE_DATA) ? 8 : 7; + + m_tsr = (m_asci_cntla & Z180_CNTLA_MODE_STOPB) ? 3 : 1; // stop bit(s) + + if ((m_asci_cntlb & Z180_CNTLB_MP) || (m_asci_cntla & Z180_CNTLA_MODE_PARITY)) + { + m_tsr <<= 1; + if (m_asci_cntlb & Z180_CNTLB_MP) + { + m_tsr |= (m_asci_cntlb & Z180_CNTLB_MPBT) ? 1 : 0; + } + else + { + uint8_t parity = 0; + for (int i = 0; i < bits; i++) + parity ^= BIT(m_asci_tdr, i); + if (m_asci_cntlb & Z180_CNTLB_PEO) parity ^= 1; // odd parity + m_tsr |= parity; + } + } + m_tsr <<= bits; + m_tsr |= m_asci_tdr; + m_tsr <<= 1; // start bit +} + +void z180asci_channel_base::transmit_edge() +{ + if (m_asci_cntla & Z180_CNTLA_TE) + { + switch (m_tx_state) + { + case STATE_DATA: + output_txa(BIT(m_tsr, 0)); + m_tsr >>= 1; + if (m_tsr == 0) + { + m_asci_stat |= Z180_STAT_TDRE; + if (m_asci_stat & Z180_STAT_TIE) + { + m_irq = 1; + } + m_tx_state = STATE_WAIT; + m_tra_clock->adjust(attotime::never); + } + break; + case STATE_WAIT: + if ((m_asci_stat & Z180_STAT_TDRE) == 0) + { + prepare_tsr(); + m_tx_state = STATE_DATA; + } + break; + case STATE_BREAK: + output_txa(0); + break; + } + } +} + +void z180asci_channel_base::update_received() +{ + uint8_t rx_error = 0; + int stop_bits = (m_asci_cntla & Z180_CNTLA_MODE_STOPB) ? 2 : 1; + if (m_rsr == 0) // Break detect + { + m_asci_ext |= Z180_ASEXT_BRK_DET; + } + uint8_t stop_val = (m_asci_cntla & Z180_CNTLA_MODE_STOPB) ? 3: 1; + if ((m_rsr & stop_val) != stop_val) + rx_error |= Z180_STAT_FE; + + if (m_asci_cntlb & Z180_CNTLB_MP) + { + m_asci_cntla |= ((m_rsr >> stop_bits) & 1) ? Z180_CNTLA_MPBR_EFR : 0; + } + else if (m_asci_cntla & Z180_CNTLA_MODE_PARITY) + { + uint8_t parity = 0; + for (int i = 0; i < ((m_asci_cntla & Z180_CNTLA_MODE_DATA) ? 8 : 7); i++) + parity ^= BIT(m_rsr, i); + if (m_asci_cntlb & Z180_CNTLB_PEO) parity ^= 1; // odd parity + if (((m_rsr >> stop_bits) & 1) != parity) + rx_error |= Z180_STAT_PE; + } + // Skip only if MPE mode active and MPB is 0 + if (!((m_asci_cntla & Z180_CNTLA_MPE) && ((m_asci_cntla & Z180_CNTLA_MPBR_EFR) == 0))) + { + set_fifo_data(m_rsr, rx_error); + } +} + +void z180asci_channel_base::receive_edge() +{ + if (!m_rx_enabled) return; + + if (m_asci_cntla & Z180_CNTLA_RE) + { + switch (m_rx_state) + { + case STATE_START: + if(m_rxa == 0) + { + m_rx_state = STATE_DATA; + m_rx_bits = 0; + m_rsr = 0; + if(!(m_bit_rate.is_never())) + m_rcv_clock->adjust((m_divisor == 1) ? m_bit_rate : (m_bit_rate * 3) / 2, 0, m_bit_rate); + else + m_rx_count_to = (m_divisor == 1) ? m_divisor : (m_divisor * 3) / 2; + } + break; + case STATE_DATA: + m_rsr |= m_rxa << m_rx_bits; + m_rx_bits++; + m_rx_count_to = m_divisor; + if (m_rx_bits == m_rx_total_bits) + { + update_received(); + m_rx_state = STATE_START; + if(!m_sample_rate.is_never()) + m_rcv_clock->adjust(m_sample_rate, 0, m_sample_rate); + else + m_rx_count_to = 1; + } + break; + } + } +} + +void z180asci_channel_base::set_fifo_data(uint8_t data, uint8_t error) +{ + m_data_fifo[m_fifo_wr] = data; + m_error_fifo[m_fifo_wr] = error; + if (((m_fifo_wr + 1) & 3) == m_fifo_rd) // overrun + { + m_error_fifo[m_fifo_wr] |= Z180_STAT_OVRN; + } + else + { + m_error_fifo[m_fifo_wr] &= Z180_STAT_OVRN; + m_fifo_wr = (m_fifo_wr + 1) & 3; + } + m_asci_stat |= Z180_STAT_RDRF; + if (m_asci_stat & Z180_STAT_RIE) + { + m_irq = 1; + } +} + +void z180asci_channel_base::output_txa(int txa) +{ + if (m_txa != txa) + { + m_txa = txa; + m_txa_handler(m_txa); + } +} + +void z180asci_channel_base::output_rts(int rts) +{ + if (m_rts != rts) + { + m_rts = rts; + m_rts_handler(m_rts); + } +} + +//************************************************************************** +// z180asci_channel_0 +//************************************************************************** + +z180asci_channel_0::z180asci_channel_0(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const bool ext) + : z180asci_channel_base(mconfig, type, tag, owner, clock, 0, ext) +{ +} + +z180asci_channel_0::z180asci_channel_0(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : z180asci_channel_0(mconfig, Z180ASCI_CHANNEL_0, tag, owner, clock, false) +{ +} + +void z180asci_channel_0::device_reset() +{ + z180asci_channel_base::device_reset(); + cntla_w((m_asci_cntla & Z180_CNTLA_MPBR_EFR) | Z180_CNTLA_RTS0); + cntlb_w((m_asci_cntlb & (Z180_CNTLB_MPBT | Z180_CNTLB_CTS_PS)) | 0x07); + m_asci_stat = (m_asci_stat & Z180_STAT_DCD0) | Z180_STAT_TDRE; +} + +void z180asci_channel_0::state_add(device_state_interface &parent) +{ + parent.state_add(Z180_CNTLA0, "CNTLA0", m_asci_cntla); + parent.state_add(Z180_CNTLB0, "CNTLB0", m_asci_cntlb); + parent.state_add(Z180_STAT0, "STAT0", m_asci_stat); + parent.state_add(Z180_TDR0, "TDR0", m_asci_tdr); + parent.state_add(Z180_RDR0, "RDR0", m_asci_rdr); + if (m_ext) + { + parent.state_add(Z180_ASEXT0, "ASEXT0", m_asci_ext).mask(Z180_ASEXT0_MASK); + parent.state_add(Z180_ASTC0, "ASTC0", m_asci_tc.w); + } +} + +void z180asci_channel_0::stat_w(uint8_t data) +{ + LOG("Z180 STAT0 wr $%02x ($%02x)\n", data, data & (Z180_STAT_RIE | Z180_STAT_TIE)); + m_asci_stat = (m_asci_stat & ~(Z180_STAT_RIE | Z180_STAT_TIE)) | (data & (Z180_STAT_RIE | Z180_STAT_TIE)); +} + +void z180asci_channel_0::asext_w(uint8_t data) +{ + LOG("Z180 ASEXT0 wr $%02x ($%02x)\n", data, data & Z180_ASEXT0_MASK & ~Z180_ASEXT_BRK_DET); + m_asci_ext = (m_asci_ext & Z180_ASEXT_BRK_DET) | (data & Z180_ASEXT0_MASK & ~Z180_ASEXT_BRK_DET); + z180asci_channel_base::asext_w(data); +} + +//************************************************************************** +// z180asci_channel_1 +//************************************************************************** + +z180asci_channel_1::z180asci_channel_1(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const bool ext) + : z180asci_channel_base(mconfig, type, tag, owner, clock, 1, ext) +{ +} + +z180asci_channel_1::z180asci_channel_1(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : z180asci_channel_1(mconfig, Z180ASCI_CHANNEL_1, tag, owner, clock, false) +{ +} +void z180asci_channel_1::device_reset() +{ + z180asci_channel_base::device_reset(); + cntla_w((m_asci_cntla & Z180_CNTLA_MPBR_EFR) | Z180_CNTLA1_CKA1D); + cntlb_w((m_asci_cntlb & Z180_CNTLB_MPBT) | 0x07); + m_asci_stat = Z180_STAT_TDRE; +} + +void z180asci_channel_1::state_add(device_state_interface &parent) +{ + parent.state_add(Z180_CNTLA1, "CNTLA1", m_asci_cntla); + parent.state_add(Z180_CNTLB1, "CNTLB1", m_asci_cntlb); + parent.state_add(Z180_STAT1, "STAT1", m_asci_stat); + parent.state_add(Z180_TDR1, "TDR1", m_asci_tdr); + parent.state_add(Z180_RDR1, "RDR1", m_asci_rdr); + if (m_ext) + { + parent.state_add(Z180_ASEXT1, "ASEXT1", m_asci_ext).mask(Z180_ASEXT1_MASK); + parent.state_add(Z180_ASTC1, "ASTC1", m_asci_tc.w); + } +} + +void z180asci_channel_1::stat_w(uint8_t data) +{ + LOG("Z180 STAT1 wr $%02x ($%02x)\n", data, data & (Z180_STAT_RIE | Z180_STAT1_CTS1E | Z180_STAT_TIE)); + m_asci_stat = (m_asci_stat & ~(Z180_STAT_RIE | Z180_STAT1_CTS1E | Z180_STAT_TIE)) | (data & (Z180_STAT_RIE | Z180_STAT1_CTS1E | Z180_STAT_TIE)); +} + +void z180asci_channel_1::asext_w(uint8_t data) +{ + LOG("Z180 ASEXT1 wr $%02x ($%02x)\n", data, data & Z180_ASEXT1_MASK & ~Z180_ASEXT_BRK_DET); + m_asci_ext = (m_asci_ext & Z180_ASEXT_BRK_DET) | (data & Z180_ASEXT1_MASK & ~Z180_ASEXT_BRK_DET); + z180asci_channel_base::asext_w(data); +} + +//************************************************************************** +// z180asci_ext_channel_0 +//************************************************************************** + +z180asci_ext_channel_0::z180asci_ext_channel_0(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : z180asci_channel_0(mconfig, Z180ASCI_EXT_CHANNEL_0, tag, owner, clock, true) +{ +} + +//************************************************************************** +// z180asci_channel_1 +//************************************************************************** + +z180asci_ext_channel_1::z180asci_ext_channel_1(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : z180asci_channel_1(mconfig, Z180ASCI_EXT_CHANNEL_1, tag, owner, clock, true) +{ +} + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(Z180ASCI_CHANNEL_0, z180asci_channel_0, "z180asci_channel_0", "Z180 ASCI Channel 0") +DEFINE_DEVICE_TYPE(Z180ASCI_CHANNEL_1, z180asci_channel_1, "z180asci_channel_1", "Z180 ASCI Channel 1") + +DEFINE_DEVICE_TYPE(Z180ASCI_EXT_CHANNEL_0, z180asci_ext_channel_0, "z180asci_ext_channel_0", "Z180 ASCI Extended Channel 0") +DEFINE_DEVICE_TYPE(Z180ASCI_EXT_CHANNEL_1, z180asci_ext_channel_1, "z180asci_ext_channel_1", "Z180 ASCI Extended Channel 1") diff --git a/src/devices/cpu/z180/z180asci.h b/src/devices/cpu/z180/z180asci.h new file mode 100644 index 00000000000..3794fe635a8 --- /dev/null +++ b/src/devices/cpu/z180/z180asci.h @@ -0,0 +1,201 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/********************************************************************* + + z180asci.h + +*********************************************************************/ + +#ifndef MAME_CPU_Z180_Z180ASCI_H +#define MAME_CPU_Z180_Z180ASCI_H + +#pragma once + +//************************************************************************** +// z180asci_channel_base +//************************************************************************** + +class z180asci_channel_base : public device_t +{ +public: + // inline configuration + auto txa_handler() { return m_txa_handler.bind(); } + auto rts_handler() { return m_rts_handler.bind(); } + auto cka_handler() { return m_cka_handler.bind(); } + + uint8_t cntla_r(); + uint8_t cntlb_r(); + uint8_t stat_r(); + uint8_t tdr_r(); + uint8_t rdr_r(); + uint8_t asext_r(); + uint8_t astcl_r(); + uint8_t astch_r(); + void cntla_w(uint8_t data); + void cntlb_w(uint8_t data); + virtual void stat_w(uint8_t data) = 0; + void tdr_w(uint8_t data); + void rdr_w(uint8_t data); + virtual void asext_w(uint8_t data); + void astcl_w(uint8_t data); + void astch_w(uint8_t data); + + DECLARE_WRITE_LINE_MEMBER( rxa_wr ); + DECLARE_WRITE_LINE_MEMBER( cts_wr ); + DECLARE_WRITE_LINE_MEMBER( dcd_wr ); + DECLARE_WRITE_LINE_MEMBER( cka_wr ); + + virtual void state_add(device_state_interface &parent) = 0; + + int check_interrupt() { return m_irq; } + void clear_interrupt() { m_irq = 0; } +protected: + z180asci_channel_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const int id, const bool ext); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_resolve_objects() override; + virtual void device_clock_changed() override; + + void transmit_edge(); + void receive_edge(); + void set_fifo_data(uint8_t data, uint8_t error); + void prepare_tsr(); + void update_received(); + void update_total_bits(); + + enum serial_state + { + STATE_START, + STATE_DATA, + STATE_WAIT, + STATE_BREAK + }; + + + void output_txa(int txa); + void output_rts(int rts); + TIMER_CALLBACK_MEMBER(rcv_clock) { receive_edge(); } + TIMER_CALLBACK_MEMBER(tra_clock) { transmit_edge(); } + + emu_timer *m_rcv_clock; + emu_timer *m_tra_clock; + attotime m_bit_rate; + attotime m_sample_rate; + + devcb_write_line m_txa_handler; + devcb_write_line m_rts_handler; + devcb_write_line m_cka_handler; + + uint8_t m_asci_cntla; // ASCI control register A + uint8_t m_asci_cntlb; // ASCI control register B + uint8_t m_asci_stat; // ASCI status register + uint8_t m_asci_tdr; // ASCI transmit data register + uint8_t m_asci_rdr; // ASCI receive data register + uint8_t m_asci_ext; // ASCI extension control register + PAIR16 m_asci_tc; // ASCI time constant + + uint16_t m_tsr; + uint16_t m_rsr; + uint8_t m_data_fifo[4]; + uint8_t m_error_fifo[4]; + uint8_t m_fifo_wr; + uint8_t m_fifo_rd; + + uint8_t m_cts; + uint8_t m_dcd; + uint8_t m_irq; + uint8_t m_txa; + uint8_t m_rxa; + uint8_t m_rts; + + uint32_t m_divisor; + + uint8_t m_clock_state; + uint8_t m_tx_state; + uint8_t m_rx_state; + uint8_t m_rx_bits; + + uint8_t m_tx_counter; + uint8_t m_rx_counter; + uint8_t m_rx_count_to; + uint8_t m_rx_total_bits; + + bool m_rx_enabled; + + const int m_id; + const bool m_ext; +}; + +//************************************************************************** +// z180asci_channel_0 +//************************************************************************** + +class z180asci_channel_0 : public z180asci_channel_base +{ +public: + // construction/destruction + z180asci_channel_0(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void stat_w(uint8_t data) override; + void asext_w(uint8_t data) override; + void state_add(device_state_interface &parent) override; +protected: + z180asci_channel_0(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const bool ext); + // device-level overrides + virtual void device_reset() override; +}; + +//************************************************************************** +// z180asci_channel_1 +//************************************************************************** + +class z180asci_channel_1 : public z180asci_channel_base +{ +public: + // construction/destruction + z180asci_channel_1(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + void stat_w(uint8_t data) override; + void asext_w(uint8_t data) override; + void state_add(device_state_interface &parent) override; +protected: + z180asci_channel_1(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, const bool ext); + // device-level overrides + virtual void device_reset() override; +}; + +//************************************************************************** +// z180asci_ext_channel_0 +//************************************************************************** + +class z180asci_ext_channel_0 : public z180asci_channel_0 +{ +public: + // construction/destruction + z180asci_ext_channel_0(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +//************************************************************************** +// z180asci_ext_channel_1 +//************************************************************************** + +class z180asci_ext_channel_1 : public z180asci_channel_1 +{ +public: + // construction/destruction + z180asci_ext_channel_1(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +//************************************************************************** +// DEVICE TYPE DEFINITIONS +//************************************************************************** + +DECLARE_DEVICE_TYPE(Z180ASCI_CHANNEL_0, z180asci_channel_0) +DECLARE_DEVICE_TYPE(Z180ASCI_CHANNEL_1, z180asci_channel_1) + +DECLARE_DEVICE_TYPE(Z180ASCI_EXT_CHANNEL_0, z180asci_ext_channel_0) +DECLARE_DEVICE_TYPE(Z180ASCI_EXT_CHANNEL_1, z180asci_ext_channel_1) + +#endif // MAME_CPU_Z180_Z180ASCI_H diff --git a/src/mame/drivers/20pacgal.cpp b/src/mame/drivers/20pacgal.cpp index 94ab22a608a..762873f99f1 100644 --- a/src/mame/drivers/20pacgal.cpp +++ b/src/mame/drivers/20pacgal.cpp @@ -86,7 +86,6 @@ Graphics: CY37256P160-83AC x 2 (Ultra37000 CPLD family - 160 pin TQFP, 256 Macro #include "emu.h" #include "includes/20pacgal.h" -#include "cpu/z180/z180.h" #include "machine/eepromser.h" #include "machine/watchdog.h" #include "speaker.h" @@ -396,12 +395,25 @@ WRITE_LINE_MEMBER(_20pacgal_state::vblank_irq) m_maincpu->set_input_line(0, HOLD_LINE); // TODO: assert breaks the inputs in 25pacman test mode } +static DEVICE_INPUT_DEFAULTS_START( null_modem ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_115200 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_115200 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + void _20pacgal_state::_20pacgal(machine_config &config) { /* basic machine hardware */ Z8S180(config, m_maincpu, MAIN_CPU_CLOCK); // 18.432MHz verified on PCB m_maincpu->set_addrmap(AS_PROGRAM, &_20pacgal_state::_20pacgal_map); m_maincpu->set_addrmap(AS_IO, &_20pacgal_state::_20pacgal_io_map); + m_maincpu->txa0_wr_callback().set("rs232", FUNC(rs232_port_device::write_txd)); + + RS232_PORT(config, m_rs232, default_rs232_devices, nullptr); + m_rs232->set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(null_modem)); + m_rs232->rxd_handler().set(m_maincpu, FUNC(z180_device::rxa0_w)); EEPROM_93C46_8BIT(config, m_eeprom); @@ -420,6 +432,14 @@ void _20pacgal_state::_20pacgal(machine_config &config) DAC_8BIT_R2R(config, "dac", 0).add_route(ALL_OUTPUTS, "speaker", 1.0); // unknown DAC } +static DEVICE_INPUT_DEFAULTS_START( null_modem_57600 ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_57600 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_57600 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + void _25pacman_state::_25pacman(machine_config &config) { _20pacgal(config); @@ -428,6 +448,8 @@ void _25pacman_state::_25pacman(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &_25pacman_state::_25pacman_map); m_maincpu->set_addrmap(AS_IO, &_25pacman_state::_25pacman_io_map); + m_rs232->set_option_device_input_defaults("null_modem", DEVICE_INPUT_DEFAULTS_NAME(null_modem_57600)); + AMD_29LV200T(config, "flash"); } diff --git a/src/mame/drivers/sb180.cpp b/src/mame/drivers/sb180.cpp new file mode 100644 index 00000000000..80d3f2a180b --- /dev/null +++ b/src/mame/drivers/sb180.cpp @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Miodrag Milanovic +/*************************************************************************** + + Micromint SB180 + +****************************************************************************/ + +#include "emu.h" +#include "cpu/z180/z180.h" +#include "imagedev/floppy.h" +#include "formats/imd_dsk.h" +#include "machine/upd765.h" +#include "bus/rs232/rs232.h" + +#define FDC9266_TAG "u24" + +class sb180_state : public driver_device +{ +public: + sb180_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_fdc(*this, FDC9266_TAG) + , m_floppy(*this, FDC9266_TAG ":%u", 0) + { } + + void sb180(machine_config &config); + +private: + virtual void machine_reset() override; + + void sb180_io(address_map &map); + void sb180_mem(address_map &map); + + required_device m_maincpu; + required_device m_fdc; + required_device_array m_floppy; +}; + +void sb180_state::sb180_mem(address_map &map) +{ + map.unmap_value_high(); + map(0x00000, 0x01fff).rom().mirror(0x3e000); + map(0x40000, 0x7ffff).ram(); // 256KB RAM 8 * 41256 DRAM +} + +void sb180_state::sb180_io(address_map &map) +{ + map.global_mask(0xff); + map.unmap_value_high(); + map(0x00, 0x7f).ram(); /* Z180 internal registers */ + map(0x80, 0x81).m(m_fdc, FUNC(upd765a_device::map)); + map(0xa0, 0xa0).rw(m_fdc, FUNC(upd765a_device::dma_r), FUNC(upd765a_device::dma_w)); +} + +/* Input ports */ +static INPUT_PORTS_START( sb180 ) +INPUT_PORTS_END + +void sb180_state::machine_reset() +{ + // motor is actually connected on TXS pin of CPU + for (auto &drive : m_floppy) + { + if (drive->get_device()) + drive->get_device()->mon_w(0); + } +} + +static void sb180_floppies(device_slot_interface &device) +{ + device.option_add("35dd", FLOPPY_35_DD); +} + +static void sb180_floppy_formats(format_registration &fr) +{ + fr.add_mfm_containers(); + fr.add(FLOPPY_IMD_FORMAT); +} + +static DEVICE_INPUT_DEFAULTS_START( terminal ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_NONE ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + +void sb180_state::sb180(machine_config &config) +{ + /* basic machine hardware */ + HD64180RP(config, m_maincpu, XTAL(12'288'000)); // location U17 HD64180 + m_maincpu->set_addrmap(AS_PROGRAM, &sb180_state::sb180_mem); + m_maincpu->set_addrmap(AS_IO, &sb180_state::sb180_io); + m_maincpu->tend1_wr_callback().set(m_fdc, FUNC(upd765a_device::tc_line_w)); + m_maincpu->txa1_wr_callback().set("rs232", FUNC(rs232_port_device::write_txd)); + + // FDC9266 location U24 + UPD765A(config, m_fdc, XTAL(8'000'000)); + m_fdc->intrq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ2); + m_fdc->drq_wr_callback().set_inputline(m_maincpu, Z180_INPUT_LINE_DREQ1); + + /* floppy drives */ + FLOPPY_CONNECTOR(config, m_floppy[0], sb180_floppies, "35dd", sb180_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppy[1], sb180_floppies, "35dd", sb180_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppy[2], sb180_floppies, "35dd", sb180_floppy_formats); + FLOPPY_CONNECTOR(config, m_floppy[3], sb180_floppies, "35dd", sb180_floppy_formats); + + rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal")); + rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); // must be below the DEVICE_INPUT_DEFAULTS_START block + rs232.rxd_handler().set(m_maincpu, FUNC(z180_device::rxa1_w)); +} + +/* ROM definition */ +ROM_START( sb180 ) + ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASEFF ) + ROM_LOAD( "monitor.bin", 0x0000, 0x2000, CRC(49640012) SHA1(ea571dc7476430e31b74bd1ab7a577e9013ad0bd)) +ROM_END + +/* Driver */ + +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1985, sb180, 0, 0, sb180, sb180, sb180_state, empty_init, "Micromint", "SB180", MACHINE_NO_SOUND) diff --git a/src/mame/drivers/tim011.cpp b/src/mame/drivers/tim011.cpp index 66234dbea39..bef566f56b3 100644 --- a/src/mame/drivers/tim011.cpp +++ b/src/mame/drivers/tim011.cpp @@ -14,6 +14,7 @@ #include "formats/imd_dsk.h" #include "formats/tim011_dsk.h" #include "machine/upd765.h" +#include "bus/rs232/rs232.h" #include "emupal.h" #include "screen.h" @@ -136,6 +137,14 @@ static void tim011_floppy_formats(format_registration &fr) fr.add(FLOPPY_TIM011_FORMAT); } +static DEVICE_INPUT_DEFAULTS_START( keyboard ) + DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 ) + DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_8 ) + DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_ODD ) + DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 ) +DEVICE_INPUT_DEFAULTS_END + void tim011_state::tim011_palette(palette_device &palette) const { static constexpr rgb_t tim011_pens[4] = { @@ -155,6 +164,7 @@ void tim011_state::tim011(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &tim011_state::tim011_mem); m_maincpu->set_addrmap(AS_IO, &tim011_state::tim011_io); m_maincpu->tend1_wr_callback().set(m_fdc, FUNC(upd765a_device::tc_line_w)); + m_maincpu->txa1_wr_callback().set("rs232", FUNC(rs232_port_device::write_txd)); // CDP1802(config, "keyboard", XTAL(1'750'000)); // CDP1802, unknown clock @@ -179,6 +189,10 @@ void tim011_state::tim011(machine_config &config) screen.set_visarea(0, 512-1, 0, 256-1); screen.set_screen_update(FUNC(tim011_state::screen_update_tim011)); screen.set_palette(m_palette); + + rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "keyboard")); + rs232.set_option_device_input_defaults("keyboard", DEVICE_INPUT_DEFAULTS_NAME(keyboard)); + rs232.rxd_handler().set(m_maincpu, FUNC(z180_device::rxa1_w)); } /* ROM definition */ diff --git a/src/mame/includes/20pacgal.h b/src/mame/includes/20pacgal.h index 8d03e964985..77c74f6948f 100644 --- a/src/mame/includes/20pacgal.h +++ b/src/mame/includes/20pacgal.h @@ -12,10 +12,12 @@ #pragma once +#include "cpu/z180/z180.h" #include "machine/eepromser.h" #include "machine/intelfsh.h" #include "sound/dac.h" #include "sound/namco.h" +#include "bus/rs232/rs232.h" #include "emupal.h" class _20pacgal_state : public driver_device @@ -33,7 +35,8 @@ public: m_maincpu(*this, "maincpu"), m_eeprom(*this, "eeprom"), m_palette(*this, "palette"), - m_dac(*this, "dac") + m_dac(*this, "dac"), + m_rs232(*this, "rs232") { } void _20pacgal(machine_config &config); @@ -57,10 +60,11 @@ protected: uint8_t m_game_selected = 0; /* 0 = Ms. Pac-Man, 1 = Galaga */ /* devices */ - required_device m_maincpu; + required_device m_maincpu; required_device m_eeprom; required_device m_palette; required_device m_dac; + required_device m_rs232; /* memory */ std::unique_ptr m_sprite_gfx_ram; diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 68e8dad0378..017c66a5dc6 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -37551,6 +37551,9 @@ savia84 // @source:savquest.cpp savquest // +@source:sb180.cpp +sb180 // + @source:sb8085.cpp sb8085 // diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 0f7c8b6f2a4..29d6941871c 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -946,6 +946,7 @@ sapi1.cpp sartorius.cpp saturn.cpp savia84.cpp +sb180.cpp sb8085.cpp sbc6510.cpp sbrain.cpp