z80ctc: Allow a fixed-rate clock input to be configured for each channel. This improves performance by alleviating the need to drive the CLK/TRG inputs with high-frequency timers.

This commit is contained in:
AJR 2018-11-10 14:40:45 -05:00
parent aebfca6f33
commit fc20d899ab
13 changed files with 83 additions and 97 deletions

View File

@ -123,12 +123,15 @@ WRITE_LINE_MEMBER( z80ctc_device::trg3 ) { m_channel[3]->trigger(state != 0); }
// machine configuration
//-------------------------------------------------
void z80ctc_device::device_add_mconfig(machine_config & config)
void z80ctc_device::device_add_mconfig(machine_config &config)
{
Z80CTC_CHANNEL(config, m_channel[0], 0);
Z80CTC_CHANNEL(config, m_channel[1], 0);
Z80CTC_CHANNEL(config, m_channel[2], 0);
Z80CTC_CHANNEL(config, m_channel[3], 0);
for (int ch = 0; ch < 4; ch++)
{
Z80CTC_CHANNEL(config, m_channel[ch]);
// assign channel index
m_channel[ch]->m_index = ch;
}
}
@ -142,13 +145,8 @@ void z80ctc_device::device_resolve_objects()
{
// resolve callbacks
m_intr_cb.resolve_safe();
for (int ch = 0; ch < 4; ch++)
{
m_zc_cb[ch].resolve_safe();
// assign channel index
m_channel[ch]->m_index = ch;
}
for (auto &cb : m_zc_cb)
cb.resolve_safe();
}
@ -342,14 +340,11 @@ attotime z80ctc_channel_device::period() const
{
// if reset active, no period
if ((m_mode & RESET) == RESET_ACTIVE)
return attotime::zero;
return attotime::never;
// if counter mode, no real period
// if counter mode, no real period unless the channel clock is specifically configured
if ((m_mode & MODE) == MODE_COUNTER)
{
logerror("CounterMode : Can't calculate period\n");
return attotime::zero;
}
return clocks_to_attotime(m_tconst);
// compute the period
attotime period = m_device->clocks_to_attotime((m_mode & PRESCALER) == PRESCALER_16 ? 16 : 256);
@ -364,20 +359,21 @@ attotime z80ctc_channel_device::period() const
u8 z80ctc_channel_device::read()
{
// if we're in counter mode, just return the count
if ((m_mode & MODE) == MODE_COUNTER || (m_mode & WAITING_FOR_TRIG))
if (!m_timer->enabled() || (m_mode & WAITING_FOR_TRIG))
return m_down;
// else compute the down counter value
else
{
attotime period = m_device->clocks_to_attotime((m_mode & PRESCALER) == PRESCALER_16 ? 16 : 256);
attotime period;
if ((m_mode & MODE) == MODE_COUNTER)
period = clocks_to_attotime(1);
else
period = m_device->clocks_to_attotime((m_mode & PRESCALER) == PRESCALER_16 ? 16 : 256);
LOG("CTC clock %f\n", period.as_hz());
if (m_timer != nullptr)
return ((int)(m_timer->remaining().as_double() / period.as_double()) + 1) & 0xff;
else
return 0;
return u8((m_timer->remaining().as_double() / period.as_double()) + 1.0);
}
}
@ -402,19 +398,18 @@ void z80ctc_channel_device::write(u8 data)
// also clear the reset, since the constant gets it going again
m_mode &= ~RESET;
// if we're in timer mode....
if ((m_mode & MODE) == MODE_TIMER)
// if we're triggering on the time constant, reset the down counter now
if ((m_mode & MODE) == MODE_COUNTER || (m_mode & TRIGGER) == TRIGGER_AUTO)
{
// if we're triggering on the time constant, reset the down counter now
if ((m_mode & TRIGGER) == TRIGGER_AUTO)
{
attotime curperiod = period();
m_timer->adjust(curperiod, 0, curperiod);
}
attotime curperiod = period();
m_timer->adjust(curperiod, 0, curperiod);
}
// else set the bit indicating that we're waiting for the appropriate trigger
else
m_mode |= WAITING_FOR_TRIG;
// else set the bit indicating that we're waiting for the appropriate trigger
else
{
m_mode |= WAITING_FOR_TRIG;
m_timer->adjust(clocks_to_attotime(1));
}
// also set the down counter in case we're clocking externally
@ -443,6 +438,15 @@ void z80ctc_channel_device::write(u8 data)
m_timer->adjust(attotime::never);
}
// if we're being reset, clear out any pending timers for this channel
if ((data & RESET) == RESET_ACTIVE)
{
// remember the present count
m_down = read();
m_timer->adjust(attotime::never);
// note that we don't clear the interrupt state here!
}
// set the new mode
m_mode = data;
LOG("Channel mode = %02x\n", data);
@ -454,13 +458,6 @@ void z80ctc_channel_device::write(u8 data)
LOG("Interrupt forced off\n");
m_device->interrupt_check();
}
// if we're being reset, clear out any pending timers for this channel
if ((data & RESET) == RESET_ACTIVE)
{
m_timer->adjust(attotime::never);
// note that we don't clear the interrupt state here!
}
}
}
@ -510,6 +507,18 @@ void z80ctc_channel_device::trigger(bool state)
TIMER_CALLBACK_MEMBER(z80ctc_channel_device::timer_callback)
{
if (m_mode & WAITING_FOR_TRIG)
{
attotime curperiod = period();
LOG("Period = %s\n", curperiod.as_string());
m_timer->adjust(curperiod, 0, curperiod);
// we're no longer waiting
m_mode &= ~WAITING_FOR_TRIG;
return;
}
// down counter has reached zero - see if we should interrupt
if ((m_mode & INTERRUPT) == INTERRUPT_ON)
{
@ -518,8 +527,7 @@ TIMER_CALLBACK_MEMBER(z80ctc_channel_device::timer_callback)
m_device->interrupt_check();
}
// generate the clock pulse
// FIXME: should only be cleared after one cycle of the channel input clock
// generate the clock pulse (FIXME: pulse width is based on bus clock)
m_device->m_zc_cb[m_index](1);
m_device->m_zc_cb[m_index](0);

View File

@ -47,7 +47,7 @@ class z80ctc_channel_device : public device_t
public:
// construction/destruction
z80ctc_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
z80ctc_channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
protected:
// device-level overrides
@ -84,6 +84,8 @@ public:
auto intr_callback() { return m_intr_cb.bind(); }
template <int Channel> auto zc_callback() { return m_zc_cb[Channel].bind(); } // m_zc_cb[3] not supported on a standard ctc, only used for the tmpz84c015
template <int Channel> void set_clk(u32 clock) { channel_config(Channel).set_clock(clock); }
template <int Channel> void set_clk(const XTAL &xtal) { channel_config(Channel).set_clock(xtal); }
// read/write handlers
DECLARE_READ8_MEMBER( read );
@ -93,7 +95,7 @@ public:
DECLARE_WRITE_LINE_MEMBER( trg2 );
DECLARE_WRITE_LINE_MEMBER( trg3 );
u16 get_channel_constant(u8 channel) const { return m_channel[channel]->m_tconst; }
u16 get_channel_constant(int ch) const { return m_channel[ch]->m_tconst; }
protected:
// device-level overrides
@ -111,6 +113,8 @@ private:
// internal helpers
void interrupt_check();
z80ctc_channel_device &channel_config(int ch) { return *subdevice<z80ctc_channel_device>(m_channel[ch].finder_tag()); }
// internal state
devcb_write_line m_intr_cb; // interrupt callback
devcb_write_line m_zc_cb[4]; // zero crossing/timer output callbacks

View File

@ -19,7 +19,6 @@ Keyboard: P8035L CPU, undumped 2716 labelled "358_2758", XTAL marked "4608-300-1
#include "machine/z80daisy.h"
#include "machine/z80ctc.h"
#include "machine/z80dart.h"
#include "machine/clock.h"
#include "machine/x2212.h"
#include "sound/beep.h"
//#include "video/crt9006.h"
@ -139,13 +138,11 @@ void altos2_state::altos2(machine_config &config)
m_maincpu->set_addrmap(AS_IO, &altos2_state::io_map);
m_maincpu->set_daisy_config(daisy_chain);
clock_device &ctc_clock(CLOCK(config, "ctc_clock", 4.9152_MHz_XTAL / 4));
ctc_clock.signal_handler().set("ctc", FUNC(z80ctc_device::trg0));
ctc_clock.signal_handler().append("ctc", FUNC(z80ctc_device::trg1));
ctc_clock.signal_handler().append("ctc", FUNC(z80ctc_device::trg2));
z80ctc_device &ctc(Z80CTC(config, "ctc", 8_MHz_XTAL / 2));
ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
ctc.set_clk<0>(4.9152_MHz_XTAL / 4);
ctc.set_clk<1>(4.9152_MHz_XTAL / 4);
ctc.set_clk<2>(4.9152_MHz_XTAL / 4);
ctc.zc_callback<0>().set("dart1", FUNC(z80dart_device::txca_w));
ctc.zc_callback<0>().append("dart1", FUNC(z80dart_device::rxca_w));
ctc.zc_callback<1>().set("dart2", FUNC(z80dart_device::rxca_w));

View File

@ -70,7 +70,6 @@
#include "machine/z80daisy.h"
#include "bus/rs232/rs232.h"
#include "machine/am9517a.h"
#include "machine/clock.h"
#include "machine/msm5832.h"
#include "machine/nvram.h"
#include "machine/ram.h"
@ -1163,15 +1162,13 @@ MACHINE_CONFIG_START(attache_state::attache)
rs232b.cts_handler().set(m_sio, FUNC(z80sio_device::ctsb_w));
Z80CTC(config, m_ctc, 8_MHz_XTAL / 2);
m_ctc->set_clk<0>(8_MHz_XTAL / 26); // 307.692 KHz
m_ctc->set_clk<1>(8_MHz_XTAL / 26); // 307.692 KHz
m_ctc->zc_callback<0>().set(m_sio, FUNC(z80sio_device::rxca_w));
m_ctc->zc_callback<0>().append(m_sio, FUNC(z80sio_device::txca_w));
m_ctc->zc_callback<1>().set(m_sio, FUNC(z80sio_device::rxtxcb_w));
m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
clock_device &brc(CLOCK(config, "brc", 8_MHz_XTAL / 26)); // 307.692 KHz
brc.signal_handler().set(m_ctc, FUNC(z80ctc_device::trg0));
brc.signal_handler().append(m_ctc, FUNC(z80ctc_device::trg1));
AM9517A(config, m_dma, 8_MHz_XTAL / 4);
m_dma->out_hreq_callback().set(FUNC(attache_state::hreq_w));
m_dma->out_eop_callback().set(FUNC(attache_state::eop_w));
@ -1246,15 +1243,13 @@ MACHINE_CONFIG_START(attache816_state::attache816)
rs232b.cts_handler().set(m_sio, FUNC(z80sio_device::ctsb_w));
Z80CTC(config, m_ctc, 8_MHz_XTAL / 2);
m_ctc->set_clk<0>(8_MHz_XTAL / 26); // 307.692 KHz
m_ctc->set_clk<1>(8_MHz_XTAL / 26); // 307.692 KHz
m_ctc->zc_callback<0>().set(m_sio, FUNC(z80sio_device::rxca_w));
m_ctc->zc_callback<0>().append(m_sio, FUNC(z80sio_device::txca_w));
m_ctc->zc_callback<1>().set(m_sio, FUNC(z80sio_device::rxtxcb_w));
m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
clock_device &brc(CLOCK(config, "brc", 8_MHz_XTAL / 26)); // 307.692 KHz
brc.signal_handler().set(m_ctc, FUNC(z80ctc_device::trg0));
brc.signal_handler().append(m_ctc, FUNC(z80ctc_device::trg1));
I8255A(config, m_ppi, 0);
m_ppi->out_pa_callback().set(FUNC(attache816_state::x86_comms_w));
m_ppi->in_pa_callback().set(FUNC(attache816_state::x86_comms_r));

View File

@ -524,13 +524,11 @@ MACHINE_CONFIG_START(aussiebyte_state::aussiebyte)
INPUT_BUFFER(config, "cent_data_in");
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
clock_device &ctc_clock(CLOCK(config, "ctc_clock", 4.9152_MHz_XTAL / 4));
ctc_clock.signal_handler().set(m_ctc, FUNC(z80ctc_device::trg0));
ctc_clock.signal_handler().append(m_ctc, FUNC(z80ctc_device::trg1));
ctc_clock.signal_handler().append(m_ctc, FUNC(z80ctc_device::trg2));
Z80CTC(config, m_ctc, 16_MHz_XTAL / 4);
m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
m_ctc->set_clk<0>(4.9152_MHz_XTAL / 4);
m_ctc->set_clk<1>(4.9152_MHz_XTAL / 4);
m_ctc->set_clk<2>(4.9152_MHz_XTAL / 4);
m_ctc->zc_callback<0>().set("sio1", FUNC(z80sio_device::rxca_w));
m_ctc->zc_callback<0>().append("sio1", FUNC(z80sio_device::txca_w));
m_ctc->zc_callback<1>().set("sio1", FUNC(z80sio_device::rxtxcb_w));

View File

@ -232,16 +232,14 @@ void facit4440_state::facit4440(machine_config &config)
z80ctc_device &ctc(Z80CTC(config, "ctc", 32_MHz_XTAL / 8));
ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
ctc.set_clk<0>(2.4576_MHz_XTAL / 4);
ctc.set_clk<1>(2.4576_MHz_XTAL / 4);
ctc.set_clk<2>(2.4576_MHz_XTAL / 4);
ctc.zc_callback<0>().set("iodart", FUNC(z80dart_device::txca_w));
ctc.zc_callback<1>().set("iodart", FUNC(z80dart_device::rxca_w));
ctc.zc_callback<2>().set("iodart", FUNC(z80dart_device::txcb_w));
ctc.zc_callback<2>().append("iodart", FUNC(z80dart_device::rxcb_w));
clock_device &baudclk(CLOCK(config, "baudclk", 2.4576_MHz_XTAL / 4));
baudclk.signal_handler().set("ctc", FUNC(z80ctc_device::trg0));
baudclk.signal_handler().append("ctc", FUNC(z80ctc_device::trg1));
baudclk.signal_handler().append("ctc", FUNC(z80ctc_device::trg2));
clock_device &keybclk(CLOCK(config, "keybclk", 2.4576_MHz_XTAL / 32)); // unclear
keybclk.signal_handler().set("kbdart", FUNC(z80dart_device::txca_w));
keybclk.signal_handler().append("kbdart", FUNC(z80dart_device::rxca_w));

View File

@ -16,7 +16,6 @@
#include "emu.h"
#include "cpu/z80/z80.h"
#include "machine/clock.h"
#include "machine/z80ctc.h"
#include "machine/z80sio.h"
#include "bus/rs232/rs232.h"
@ -72,11 +71,10 @@ void jade_state::jade(machine_config &config)
Z80CTC(config, "ctc1", 4_MHz_XTAL);
z80ctc_device &ctc2(Z80CTC(config, "ctc2", 4_MHz_XTAL));
ctc2.set_clk<0>(4_MHz_XTAL / 2);
ctc2.zc_callback<0>().set("sio", FUNC(z80sio_device::rxca_w));
ctc2.zc_callback<0>().append("sio", FUNC(z80sio_device::txca_w));
CLOCK(config, "trg0", 4_MHz_XTAL / 2).signal_handler().set("ctc2", FUNC(z80ctc_device::trg0));
/* Devices */
z80sio_device& sio(Z80SIO(config, "sio", 4_MHz_XTAL));
//sio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); // no evidence of a daisy chain because IM2 is not set

View File

@ -14,7 +14,6 @@ When it says DIAGNOSTIC RAZ P, press enter.
#include "cpu/z80/z80.h"
#include "machine/z80ctc.h"
#include "machine/z80sio.h"
#include "machine/clock.h"
#include "bus/rs232/rs232.h"
#include "emupal.h"
#include "screen.h"
@ -152,10 +151,8 @@ MACHINE_CONFIG_START(k8915_state::k8915)
MCFG_PALETTE_ADD_MONOCHROME("palette")
MCFG_DEVICE_ADD("ctc_clock", CLOCK, XTAL(4'915'200) / 2)
MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE("ctc", z80ctc_device, trg2))
z80ctc_device& ctc(Z80CTC(config, "ctc", XTAL(4'915'200) / 2));
ctc.set_clk<2>(XTAL(4'915'200) / 2);
ctc.zc_callback<2>().set("sio", FUNC(z80sio_device::rxtxcb_w));
z80sio_device& sio(Z80SIO(config, "sio", XTAL(4'915'200) / 2));

View File

@ -28,7 +28,6 @@
#include "machine/i8255.h"
#include "machine/z80ctc.h"
#include "machine/z80sio.h"
#include "machine/clock.h"
#include "sound/beep.h"
#include "bus/centronics/ctronics.h"
#include "bus/rs232/rs232.h"
@ -291,12 +290,9 @@ MACHINE_CONFIG_START(m79152pc_state::m79152pc)
MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_m79152pc)
MCFG_PALETTE_ADD_MONOCHROME("palette")
clock_device &baudclk(CLOCK(config, "baudclk", 921600));
baudclk.signal_handler().set("ctc", FUNC(z80ctc_device::trg2));
baudclk.signal_handler().append("pit", FUNC(pit8253_device::write_clk1));
baudclk.signal_handler().append("pit", FUNC(pit8253_device::write_clk2));
pit8253_device &pit(PIT8253(config, "pit", 0)); // КР580ВИ53
pit.set_clk<1>(921600);
pit.set_clk<2>(921600);
pit.out_handler<1>().set(m_uart, FUNC(z80sio_device::txcb_w));
pit.out_handler<2>().set(m_uart, FUNC(z80sio_device::rxcb_w));
@ -321,6 +317,7 @@ MACHINE_CONFIG_START(m79152pc_state::m79152pc)
z80ctc_device &ctc(Z80CTC(config, "ctc", 4'000'000));
ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
ctc.set_clk<2>(921600);
ctc.zc_callback<2>().set(m_uart, FUNC(z80sio_device::txca_w));
ctc.zc_callback<2>().append(m_uart, FUNC(z80sio_device::rxca_w));

View File

@ -10,7 +10,6 @@ Skeleton driver for M6800-based display terminals by Qume.
#include "cpu/m6800/m6800.h"
#include "cpu/mcs48/mcs48.h"
#include "machine/6850acia.h"
#include "machine/clock.h"
#include "machine/nvram.h"
#include "machine/z80ctc.h"
#include "video/mc6845.h"
@ -80,13 +79,11 @@ MACHINE_CONFIG_START(qvt6800_state::qvt102)
MCFG_DEVICE_ADD("acia", ACIA6850, 0)
z80ctc_device& ctc(Z80CTC(config, "ctc", XTAL(16'669'800) / 9));
ctc.set_clk<0>(16.6698_MHz_XTAL / 18); // OR of CRTC CLK and ϕ1
ctc.set_clk<1>(16.6698_MHz_XTAL / 18); // OR of CRTC CLK and ϕ1
ctc.zc_callback<0>().set("acia", FUNC(acia6850_device::write_txc));
ctc.zc_callback<1>().set("acia", FUNC(acia6850_device::write_rxc));
clock_device &ctcclk(CLOCK(config, "ctcclk", 16.6698_MHz_XTAL / 18)); // OR of CRTC CLK and ϕ1
ctcclk.signal_handler().set("ctc", FUNC(z80ctc_device::trg0));
ctcclk.signal_handler().append("ctc", FUNC(z80ctc_device::trg1));
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_RAW_PARAMS(XTAL(16'669'800), 882, 0, 720, 315, 0, 300)
MCFG_SCREEN_UPDATE_DEVICE("crtc", mc6845_device, screen_update)

View File

@ -164,6 +164,7 @@ MACHINE_CONFIG_START(sys9002_state::sys9002)
uart2.txd_handler().set("rs232b", FUNC(rs232_port_device::write_txd));
uart2.dtr_handler().set("rs232b", FUNC(rs232_port_device::write_dtr));
uart2.rts_handler().set("rs232b", FUNC(rs232_port_device::write_rts));
uart2.rxrdy_handler().set_inputline("maincpu", I8085_RST55_LINE);
rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, "terminal"));
rs232b.rxd_handler().set("uart2", FUNC(i8251_device::write_rxd));

View File

@ -39,7 +39,6 @@
#include "machine/z80ctc.h"
#include "machine/z80sio.h"
#include "machine/z80pio.h"
#include "machine/clock.h"
#include "bus/rs232/rs232.h"
@ -91,15 +90,13 @@ void zsbc3_state::zsbc3(machine_config &config)
m_maincpu->set_addrmap(AS_IO, &zsbc3_state::zsbc3_io);
z80ctc_device &ctc(Z80CTC(config, "ctc", 16_MHz_XTAL / 4));
ctc.set_clk<0>(16_MHz_XTAL / 8);
ctc.set_clk<1>(16_MHz_XTAL / 8);
ctc.set_clk<2>(16_MHz_XTAL / 8);
ctc.set_clk<3>(16_MHz_XTAL / 8);
ctc.zc_callback<0>().set("sio", FUNC(z80sio_device::txca_w));
ctc.zc_callback<0>().append("sio", FUNC(z80sio_device::rxca_w));
clock_device &clk2mhz(CLOCK(config, "clk2mhz", 16_MHz_XTAL / 8));
clk2mhz.signal_handler().set("ctc", FUNC(z80ctc_device::trg0));
clk2mhz.signal_handler().append("ctc", FUNC(z80ctc_device::trg1));
clk2mhz.signal_handler().append("ctc", FUNC(z80ctc_device::trg2));
clk2mhz.signal_handler().append("ctc", FUNC(z80ctc_device::trg3));
z80sio_device &sio(Z80SIO(config, "sio", 16_MHz_XTAL / 4));
//sio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0); // no evidence of a daisy chain because IM2 is not set
sio.out_txda_callback().set("rs232", FUNC(rs232_port_device::write_txd));

View File

@ -16,7 +16,6 @@
#include "cpu/z80/z80.h"
#include "machine/z80daisy.h"
#include "machine/clock.h"
#include "machine/msm5832.h"
#include "machine/wd_fdc.h"
#include "machine/z80ctc.h"