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
This commit is contained in:
Miodrag Milanović 2022-06-06 10:48:41 +02:00 committed by GitHub
parent 4a587fd7c1
commit b26c4ed848
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1139 additions and 223 deletions

View File

@ -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

View File

@ -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",

View File

@ -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;
}

View File

@ -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<z180asci_channel_base>("asci_0")->txa_handler(); }
auto txa1_wr_callback() { return subdevice<z180asci_channel_base>("asci_1")->txa_handler(); }
auto rts0_wr_callback() { return subdevice<z180asci_channel_base>("asci_0")->rts_handler(); }
auto cka0_wr_callback() { return subdevice<z180asci_channel_base>("asci_0")->cka_handler(); }
auto cka1_wr_callback() { return subdevice<z180asci_channel_base>("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<z180asci_channel_base, 2> 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
};

View File

@ -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")

View File

@ -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

View File

@ -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");
}

124
src/mame/drivers/sb180.cpp Normal file
View File

@ -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<z180_device> m_maincpu;
required_device<upd765a_device> m_fdc;
required_device_array<floppy_connector, 4> 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)

View File

@ -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 */

View File

@ -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<cpu_device> m_maincpu;
required_device<z180_device> m_maincpu;
required_device<eeprom_serial_93cxx_device> m_eeprom;
required_device<palette_device> m_palette;
required_device<dac_8bit_r2r_device> m_dac;
required_device<rs232_port_device> m_rs232;
/* memory */
std::unique_ptr<uint8_t[]> m_sprite_gfx_ram;

View File

@ -37551,6 +37551,9 @@ savia84 //
@source:savquest.cpp
savquest //
@source:sb180.cpp
sb180 //
@source:sb8085.cpp
sb8085 //

View File

@ -946,6 +946,7 @@ sapi1.cpp
sartorius.cpp
saturn.cpp
savia84.cpp
sb180.cpp
sb8085.cpp
sbc6510.cpp
sbrain.cpp