mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
cpu/z180: Added CSIO emulation. [Vas Crabb, Sandro Ronco]
This commit is contained in:
parent
cdd5569296
commit
2eba8b2112
@ -2890,11 +2890,13 @@ if CPUS["Z180"] then
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180ed.hxx",
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180fd.hxx",
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180op.hxx",
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180xy.hxx",
|
||||
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",
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180csio.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/z180/z180csio.h",
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -15,6 +15,32 @@
|
||||
work. Currently, only timers are implemented. Ideally, the
|
||||
burn_cycles routine would go away and halt processing be
|
||||
implemented in cpu_execute.
|
||||
|
||||
- Documentation for RXS/CTS1 pin is contradictory.
|
||||
|
||||
From page 12:
|
||||
"During RESET, this pin is initialized as RXS pin. If CTS1E
|
||||
bit in ASCI status register ch1 (STAT1) is set to 1, CTS1
|
||||
function is selected. If CTS1E bit is set to 0, RXS function
|
||||
is selected."
|
||||
|
||||
However, there is no CTS1E bit in the ASCI status register.
|
||||
|
||||
From pages 43-44:
|
||||
"CTS/PS: Clear to Send/Prescale (bit 5)—If bit 5 of the System
|
||||
Configuration Register is 0, the CTS0/RxS pin features the
|
||||
CTS0 function, and the state of the pin can be read in bit 5
|
||||
of CNTLB0 in a real-time, positive-logic fashion (HIGH = 1 ,
|
||||
LOW = 0). If bit 5 in the System Configuration Register is 0
|
||||
to auto-enable CTS0, and the pin is negated (High), the TDRE
|
||||
bit is inhibited (forced to 0). Bit 5 of CNTLB1 reads back as
|
||||
0."
|
||||
|
||||
This contradicts everything else in the documentation as it
|
||||
implies RXS shares a pin with CTS0 (rather than CTS1)
|
||||
|
||||
For now, the input is always sent to both RXS and CTS1.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
@ -94,12 +120,12 @@ z180_device::z180_device(const machine_config &mconfig, device_type type, const
|
||||
, 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_csio(*this, "csio")
|
||||
, m_extended_io(extended_io)
|
||||
, m_tend0_cb(*this)
|
||||
, m_tend1_cb(*this)
|
||||
{
|
||||
// some arbitrary initial values
|
||||
m_csio_trdr = 0;
|
||||
m_tmdr[0].w = m_tmdr[1].w = 0;
|
||||
m_rldr[0].w = m_rldr[1].w = 0xffff;
|
||||
m_dma_sar0.d = 0;
|
||||
@ -236,15 +262,6 @@ bool z180_device::get_tend1()
|
||||
#define _LY m_IY.b.l
|
||||
|
||||
|
||||
/* 0a CSI/O control/status register (EF is read-only) */
|
||||
#define Z180_CNTR_EF 0x80
|
||||
#define Z180_CNTR_EIE 0x40
|
||||
#define Z180_CNTR_RE 0x20
|
||||
#define Z180_CNTR_TE 0x10
|
||||
#define Z180_CNTR_SS 0x07
|
||||
|
||||
#define Z180_CNTR_MASK 0xf7
|
||||
|
||||
/* 10 TIMER control register (TIF1 and TIF0 are read-only) */
|
||||
#define Z180_TCR_TIF1 0x80
|
||||
#define Z180_TCR_TIF0 0x40
|
||||
@ -450,13 +467,11 @@ uint8_t z180_device::z180_internal_port_read(uint8_t port)
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
data = m_csio_cntr | ~Z180_CNTR_MASK;
|
||||
LOG("Z180 CNTR rd $%02x ($%02x)\n", data, m_csio_cntr);
|
||||
data = m_csio->cntr_r();
|
||||
break;
|
||||
|
||||
case 0x0b:
|
||||
data = m_csio_trdr;
|
||||
LOG("Z180 TRDR rd $%02x\n", data);
|
||||
data = m_csio->trdr_r();
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
@ -788,14 +803,11 @@ void z180_device::z180_internal_port_write(uint8_t port, uint8_t data)
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
// Inhibit setting up TE & RE flags due to the lack of CSIO implementation
|
||||
LOG("Z180 CNTR wr $%02x ($%02x)\n", data, data & ~(Z180_CNTR_EF | Z180_CNTR_RE | Z180_CNTR_TE));
|
||||
m_csio_cntr = (m_csio_cntr & (Z180_CNTR_EF | Z180_CNTR_RE | Z180_CNTR_TE)) | (data & ~(Z180_CNTR_EF | Z180_CNTR_RE | Z180_CNTR_TE));
|
||||
m_csio->cntr_w(data);
|
||||
break;
|
||||
|
||||
case 0x0b:
|
||||
LOG("Z180 TRDR wr $%02x\n", data);
|
||||
m_csio_trdr = data;
|
||||
m_csio->trdr_w(data);
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
@ -1566,8 +1578,7 @@ void z180_device::device_start()
|
||||
|
||||
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);
|
||||
m_csio->state_add(*this);
|
||||
|
||||
state_add(Z180_TMDR0, "TMDR0", m_tmdr_value[0]);
|
||||
state_add(Z180_RLDR0, "RLDR0", m_rldr[0].w);
|
||||
@ -1627,8 +1638,6 @@ void z180_device::device_start()
|
||||
save_item(NAME(m_tmdrh));
|
||||
save_item(NAME(m_tmdr_latch));
|
||||
|
||||
save_item(NAME(m_csio_cntr));
|
||||
save_item(NAME(m_csio_trdr));
|
||||
save_item(NAME(m_tmdr[0].w));
|
||||
save_item(NAME(m_tmdr[1].w));
|
||||
save_item(NAME(m_rldr[0].w));
|
||||
@ -1727,7 +1736,6 @@ void z180_device::device_reset()
|
||||
m_frc_prescale = 0;
|
||||
|
||||
/* reset io registers */
|
||||
m_csio_cntr = 0x07;
|
||||
m_tcr = 0x00;
|
||||
m_dma_iar1.b.h2 = 0x00;
|
||||
m_dstat = Z180_DSTAT_DWE1 | Z180_DSTAT_DWE0;
|
||||
@ -1750,6 +1758,8 @@ 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));
|
||||
|
||||
Z180CSIO(config, m_csio, DERIVED_CLOCK(1,2));
|
||||
}
|
||||
|
||||
void z8s180_device::device_add_mconfig(machine_config &config)
|
||||
@ -1757,6 +1767,8 @@ 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));
|
||||
|
||||
Z180CSIO(config, m_csio, DERIVED_CLOCK(1,2));
|
||||
}
|
||||
|
||||
void z8s180_device::device_reset()
|
||||
@ -1770,8 +1782,10 @@ void z8s180_device::device_reset()
|
||||
|
||||
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));
|
||||
auto const rate = (m_cmr & 0x80) ? DERIVED_CLOCK(2,1) : (m_ccr & 0x80) ? DERIVED_CLOCK(1,1) : DERIVED_CLOCK(1,2);
|
||||
m_asci[0]->set_clock(rate);
|
||||
m_asci[1]->set_clock(rate);
|
||||
m_csio->set_clock(rate);
|
||||
}
|
||||
|
||||
/* Handle PRT timers, decreasing them after 20 clocks and returning the new icount base that needs to be used for the next check */
|
||||
@ -1818,9 +1832,6 @@ void z180_device::clock_timers()
|
||||
|
||||
int z180_device::check_interrupts()
|
||||
{
|
||||
int i;
|
||||
int cycles = 0;
|
||||
|
||||
/* check for IRQs before each instruction */
|
||||
if (m_IFF1 && !m_after_EI)
|
||||
{
|
||||
@ -1833,19 +1844,26 @@ 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_CSIO] = m_csio->check_interrupt();
|
||||
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++)
|
||||
int cycles = 0;
|
||||
for (int i = 0; i <= Z180_INT_MAX; i++)
|
||||
{
|
||||
if (m_int_pending[i])
|
||||
{
|
||||
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();
|
||||
switch (i)
|
||||
{
|
||||
case Z180_INT_ASCI0: m_asci[0]->clear_interrupt(); break;
|
||||
case Z180_INT_ASCI1: m_asci[1]->clear_interrupt(); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
@ -5,8 +5,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "machine/z80daisy.h"
|
||||
#include "z180asci.h"
|
||||
#include "z180csio.h"
|
||||
|
||||
#include "machine/z80daisy.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
@ -90,16 +93,16 @@ enum
|
||||
Z180_TABLE_ed,
|
||||
Z180_TABLE_xy,
|
||||
Z180_TABLE_xycb,
|
||||
Z180_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
|
||||
Z180_TABLE_ex // cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
|
||||
};
|
||||
|
||||
// input lines
|
||||
enum {
|
||||
Z180_INPUT_LINE_IRQ0, /* Execute IRQ1 */
|
||||
Z180_INPUT_LINE_IRQ1, /* Execute IRQ1 */
|
||||
Z180_INPUT_LINE_IRQ2, /* Execute IRQ2 */
|
||||
Z180_INPUT_LINE_DREQ0, /* Start DMA0 */
|
||||
Z180_INPUT_LINE_DREQ1 /* Start DMA1 */
|
||||
Z180_INPUT_LINE_IRQ0, // Execute IRQ1
|
||||
Z180_INPUT_LINE_IRQ1, // Execute IRQ1
|
||||
Z180_INPUT_LINE_IRQ2, // Execute IRQ2
|
||||
Z180_INPUT_LINE_DREQ0, // Start DMA0
|
||||
Z180_INPUT_LINE_DREQ1 // Start DMA1
|
||||
};
|
||||
|
||||
class z180_device : public cpu_device, public z80_daisy_chain_interface
|
||||
@ -112,17 +115,20 @@ public:
|
||||
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(); }
|
||||
auto cks_wr_callback() { return subdevice<z180csio_device>("csio")->cks_handler(); }
|
||||
auto txs_wr_callback() { return subdevice<z180csio_device>("csio")->txs_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); }
|
||||
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( rxs_cts1_w ) { m_asci[1]->cts_wr(state); m_csio->rxs_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); }
|
||||
DECLARE_WRITE_LINE_MEMBER( cks_w ) { m_csio->cks_wr(state); }
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
@ -165,6 +171,7 @@ protected:
|
||||
address_space_config m_io_config;
|
||||
address_space_config m_decrypted_opcodes_config;
|
||||
required_device_array<z180asci_channel_base, 2> m_asci;
|
||||
required_device<z180csio_device> m_csio;
|
||||
|
||||
void set_address_width(int bits);
|
||||
|
||||
@ -184,8 +191,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_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
|
||||
PAIR16 m_rldr[2]; // PRT reload register ch 0-1
|
||||
uint8_t m_tcr; // PRT control register
|
||||
|
@ -220,7 +220,7 @@ uint8_t z180asci_channel_base::cntla_r()
|
||||
|
||||
uint8_t z180asci_channel_base::cntlb_r()
|
||||
{
|
||||
uint8_t data = (m_asci_cntlb & 0x0d) | (m_cts << 5);
|
||||
uint8_t data = (m_asci_cntlb & 0xdf) | (m_cts << 5);
|
||||
LOG("Z180 CNTLB%d rd $%02x\n", m_id, data);
|
||||
return data;
|
||||
}
|
||||
|
258
src/devices/cpu/z180/z180csio.cpp
Normal file
258
src/devices/cpu/z180/z180csio.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb, Sandro Ronco, Miodrag Milanovic
|
||||
/*********************************************************************
|
||||
|
||||
z180csio.cpp
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
|
||||
TODO:
|
||||
- Handle entering IOSTOP mode.
|
||||
- Handle mid-transfer clock frequency changes.
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "z180.h"
|
||||
|
||||
//#define VERBOSE 1
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
// 0x0a CSI/O control/status register (EF is read-only)
|
||||
static constexpr u8 Z180_CNTR_EF = 0x80;
|
||||
static constexpr u8 Z180_CNTR_EIE = 0x40;
|
||||
static constexpr u8 Z180_CNTR_RE = 0x20;
|
||||
static constexpr u8 Z180_CNTR_TE = 0x10;
|
||||
static constexpr u8 Z180_CNTR_SS = 0x07;
|
||||
|
||||
static constexpr u8 Z180_CNTR_MASK = 0xf7;
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// z180csio_device
|
||||
//**************************************************************************
|
||||
|
||||
z180csio_device::z180csio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, Z180CSIO, tag, owner, clock)
|
||||
, m_cks_cb(*this)
|
||||
, m_txs_cb(*this)
|
||||
, m_internal_clock(nullptr)
|
||||
, m_cntr(0)
|
||||
, m_trdr(0)
|
||||
, m_shift_cnt(0)
|
||||
, m_irq(0)
|
||||
, m_cks_in(1)
|
||||
, m_rxs_in(1)
|
||||
, m_cks_out(1)
|
||||
, m_txs_out(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::device_resolve_objects()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_cks_cb.resolve_safe();
|
||||
m_txs_cb.resolve_safe();
|
||||
|
||||
// set default input line state
|
||||
m_cks_in = 1;
|
||||
m_rxs_in = 1;
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::device_start()
|
||||
{
|
||||
// TRDR is not affected by reset - set it here to make behaviour deterministic
|
||||
m_trdr = 0;
|
||||
|
||||
save_item(NAME(m_cntr));
|
||||
save_item(NAME(m_trdr));
|
||||
save_item(NAME(m_shift_cnt));
|
||||
save_item(NAME(m_irq));
|
||||
save_item(NAME(m_cks_in));
|
||||
save_item(NAME(m_rxs_in));
|
||||
save_item(NAME(m_cks_out));
|
||||
save_item(NAME(m_txs_out));
|
||||
|
||||
m_internal_clock = timer_alloc(timer_expired_delegate(FUNC(z180csio_device::internal_clock), this));
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::device_reset()
|
||||
{
|
||||
m_cntr = 0x07;
|
||||
m_shift_cnt = 0;
|
||||
m_irq = 0;
|
||||
m_cks_out = 1;
|
||||
m_txs_out = 1; // TODO: is this affected by reset?
|
||||
|
||||
m_internal_clock->adjust(attotime::never);
|
||||
|
||||
m_cks_cb(m_cks_out);
|
||||
m_txs_cb(m_txs_out);
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::state_add(device_state_interface &parent)
|
||||
{
|
||||
parent.state_add(Z180_CNTR, "CNTR", m_cntr).mask(Z180_CNTR_MASK);
|
||||
parent.state_add(Z180_TRDR, "TRDR", m_trdr);
|
||||
}
|
||||
|
||||
|
||||
u8 z180csio_device::cntr_r()
|
||||
{
|
||||
LOG("Z180 CNTR rd $%02x\n", m_cntr);
|
||||
return m_cntr & Z180_CNTR_MASK;
|
||||
}
|
||||
|
||||
|
||||
u8 z180csio_device::trdr_r()
|
||||
{
|
||||
// TODO: from manual page 47: "Program access of TRDR only occurs if EF = 1."
|
||||
// Should access be suppressed if EF is clear?
|
||||
|
||||
LOG("Z180 TRDR rd $%02x\n", m_trdr);
|
||||
if (!machine().side_effects_disabled())
|
||||
m_cntr &= ~Z180_CNTR_EF;
|
||||
|
||||
return m_trdr;
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::cntr_w(u8 data)
|
||||
{
|
||||
// TODO:
|
||||
// From manual page 47: "TE and RE are never both set to 1 at the same time."
|
||||
// If one attempts to write 1 to both at the same time, which takes precedence?
|
||||
|
||||
LOG("Z180 CNTR wr $%02x\n", data);
|
||||
|
||||
if (data & (Z180_CNTR_RE | Z180_CNTR_TE))
|
||||
{
|
||||
// if receive or transmit will be enabled, start clock if necessary
|
||||
if (!(m_cntr & (Z180_CNTR_RE | Z180_CNTR_TE)))
|
||||
{
|
||||
if ((data & Z180_CNTR_SS) != 7)
|
||||
m_internal_clock->adjust(attotime::from_hz(clock()));
|
||||
else
|
||||
m_internal_clock->adjust(attotime::never);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shift_cnt = 0;
|
||||
if (!m_cks_out)
|
||||
{
|
||||
// this probably takes at least one clock to take actually happen
|
||||
m_cks_out = 1;
|
||||
if ((data & Z180_CNTR_SS) != 7)
|
||||
m_cks_cb(1);
|
||||
}
|
||||
m_internal_clock->adjust(attotime::never);
|
||||
}
|
||||
|
||||
// TODO: if switching internal/external clock, update CKS output and trigger a clock edge if necessary
|
||||
|
||||
m_cntr = (m_cntr & Z180_CNTR_EF) | (data & ~Z180_CNTR_EF & Z180_CNTR_MASK); // EF is read-only
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::trdr_w(u8 data)
|
||||
{
|
||||
// TODO: from manual page 47: "Program access of TRDR only occurs if EF = 1."
|
||||
// Should access be suppressed if EF is clear?
|
||||
|
||||
LOG("Z180 TRDR wr $%02x\n", data);
|
||||
m_cntr &= ~Z180_CNTR_EF;
|
||||
m_trdr = data;
|
||||
}
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(z180csio_device::internal_clock)
|
||||
{
|
||||
if ((m_cntr & Z180_CNTR_SS) != 7)
|
||||
{
|
||||
m_cks_out ^= 1;
|
||||
m_cks_cb(m_cks_out);
|
||||
clock_edge(m_cks_out);
|
||||
|
||||
if (m_cntr & (Z180_CNTR_RE | Z180_CNTR_TE))
|
||||
{
|
||||
int div;
|
||||
switch (m_cntr & Z180_CNTR_SS)
|
||||
{
|
||||
default: // just to pacify compilers
|
||||
case 0: div = 20; break;
|
||||
case 1: div = 40; break;
|
||||
case 2: div = 80; break;
|
||||
case 3: div = 160; break;
|
||||
case 4: div = 320; break;
|
||||
case 5: div = 640; break;
|
||||
case 6: div = 1280; break;
|
||||
}
|
||||
m_internal_clock->adjust(attotime::from_hz(clock() / div));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(z180csio_device::cks_wr)
|
||||
{
|
||||
state = state ? 1 : 0;
|
||||
if (m_cks_in != state)
|
||||
{
|
||||
m_cks_in = state;
|
||||
if ((m_cntr & Z180_CNTR_SS) == 0x07)
|
||||
clock_edge(m_cks_in);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(z180csio_device::rxs_wr)
|
||||
{
|
||||
m_rxs_in = state ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void z180csio_device::clock_edge(u8 cks)
|
||||
{
|
||||
if (!cks)
|
||||
{
|
||||
// TXS updated on falling edge
|
||||
if (m_cntr & Z180_CNTR_TE)
|
||||
{
|
||||
u8 const txs = BIT(m_trdr, m_shift_cnt);
|
||||
if (m_txs_out != txs)
|
||||
{
|
||||
m_txs_out = txs;
|
||||
m_txs_cb(txs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sample RXS on rising edge (ignore minimum setup/sampling time)
|
||||
if (m_cntr & Z180_CNTR_RE)
|
||||
m_trdr = (m_trdr & ~(u8(1) << m_shift_cnt)) | (m_rxs_in << m_shift_cnt);
|
||||
|
||||
// EF/RE/TE updated on rising edge
|
||||
if (m_cntr & (Z180_CNTR_RE | Z180_CNTR_TE))
|
||||
{
|
||||
m_shift_cnt = (m_shift_cnt + 1) & 7;
|
||||
if (!m_shift_cnt)
|
||||
m_cntr = Z180_CNTR_EF | (m_cntr & ~(Z180_CNTR_RE | Z180_CNTR_TE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
DEFINE_DEVICE_TYPE(Z180CSIO, z180csio_device, "z180csio", "Z180 CSIO")
|
70
src/devices/cpu/z180/z180csio.h
Normal file
70
src/devices/cpu/z180/z180csio.h
Normal file
@ -0,0 +1,70 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb, Sandro Ronco, Miodrag Milanovic
|
||||
/*********************************************************************
|
||||
|
||||
z180csio.h
|
||||
|
||||
*********************************************************************/
|
||||
#ifndef MAME_CPU_Z180_Z180CSIO_H
|
||||
#define MAME_CPU_Z180_Z180CSIO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// z180csio_device
|
||||
//**************************************************************************
|
||||
|
||||
class z180csio_device : public device_t
|
||||
{
|
||||
public:
|
||||
z180csio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
auto cks_handler() { return m_cks_cb.bind(); }
|
||||
auto txs_handler() { return m_txs_cb.bind(); }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(cks_wr);
|
||||
DECLARE_WRITE_LINE_MEMBER(rxs_wr);
|
||||
|
||||
u8 cntr_r();
|
||||
u8 trdr_r();
|
||||
void cntr_w(u8 data);
|
||||
void trdr_w(u8 data);
|
||||
|
||||
void state_add(device_state_interface &parent);
|
||||
|
||||
int check_interrupt() { return BIT(m_cntr, 7) && BIT(m_cntr, 6); }
|
||||
|
||||
protected:
|
||||
// device_t implementation
|
||||
virtual void device_resolve_objects() override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
void clock_edge(u8 cks);
|
||||
|
||||
TIMER_CALLBACK_MEMBER(internal_clock);
|
||||
|
||||
devcb_write_line m_cks_cb;
|
||||
devcb_write_line m_txs_cb;
|
||||
|
||||
emu_timer *m_internal_clock;
|
||||
|
||||
u8 m_cntr; // CSI/O Control/Status Register
|
||||
u8 m_trdr; // CSI/O Transmit/Receive Data Register
|
||||
u8 m_shift_cnt;
|
||||
u8 m_irq;
|
||||
u8 m_cks_in;
|
||||
u8 m_rxs_in;
|
||||
u8 m_cks_out;
|
||||
u8 m_txs_out;
|
||||
};
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
DECLARE_DEVICE_TYPE(Z180CSIO, z180csio_device)
|
||||
|
||||
#endif // MAME_CPU_Z180_Z180CSIO_H
|
Loading…
Reference in New Issue
Block a user