diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 19bea082740..bd9c56f4718 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -4120,6 +4120,8 @@ if (BUSES["TI99"]~=null) then MAME_DIR .. "src/devices/bus/ti99/internal/genkbd.h", MAME_DIR .. "src/devices/bus/ti99/internal/ioport.cpp", MAME_DIR .. "src/devices/bus/ti99/internal/ioport.h", + MAME_DIR .. "src/devices/bus/ti99/internal/splitter.cpp", + MAME_DIR .. "src/devices/bus/ti99/internal/splitter.h", MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.cpp", MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.h", MAME_DIR .. "src/devices/bus/ti99/colorbus/colorbus.cpp", diff --git a/src/devices/bus/ti99/internal/ioport.cpp b/src/devices/bus/ti99/internal/ioport.cpp index 25252569e6d..3dccc08ed0e 100644 --- a/src/devices/bus/ti99/internal/ioport.cpp +++ b/src/devices/bus/ti99/internal/ioport.cpp @@ -78,6 +78,7 @@ #include "emu.h" #include "ioport.h" +#include "splitter.h" #include "bus/ti99/peb/peribox.h" DEFINE_DEVICE_TYPE(TI99_IOPORT, bus::ti99::internal::ioport_device, "ti99_ioport", "TI-99 I/O Port") @@ -174,9 +175,18 @@ void ioport_attached_device::set_ready(int state) void ti99_ioport_options_plain(device_slot_interface &device) { device.option_add("peb", TI99_PERIBOX); + device.option_add("splitter", TI99_IOSPLIT); } void ti99_ioport_options_evpc(device_slot_interface &device) { device.option_add("peb", TI99_PERIBOX_EV); + device.option_add("splitter", TI99_IOSPLIT); +} + +// Used for the splitter (to avoid getting multiple EVPCs in the system) +void ti99_ioport_options_evpc1(device_slot_interface &device) +{ + device.option_add("peb", TI99_PERIBOX_EV1); + device.option_add("splitter", TI99_IOSPLIT); } diff --git a/src/devices/bus/ti99/internal/ioport.h b/src/devices/bus/ti99/internal/ioport.h index 39dcd955492..867ff6dccf4 100644 --- a/src/devices/bus/ti99/internal/ioport.h +++ b/src/devices/bus/ti99/internal/ioport.h @@ -103,5 +103,6 @@ DECLARE_DEVICE_TYPE_NS(TI99_IOPORT, bus::ti99::internal, ioport_device) void ti99_ioport_options_plain(device_slot_interface &device); void ti99_ioport_options_evpc(device_slot_interface &device); +void ti99_ioport_options_evpc1(device_slot_interface &device); #endif /* __TI99IOPORT__ */ diff --git a/src/devices/bus/ti99/internal/splitter.cpp b/src/devices/bus/ti99/internal/splitter.cpp new file mode 100644 index 00000000000..b839d9793e3 --- /dev/null +++ b/src/devices/bus/ti99/internal/splitter.cpp @@ -0,0 +1,190 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + I/O port splitter + + The I/O port splitter connects to the TI-99/4(A) console at its I/O port + and provides two I/O ports. That way, two Peripheral Expansion boxes or + one PEB and a sidecar chain may be connected. + + | Port 2 + v + +---+ + +----------------+ | | + | TI-99/4(A) |---+ +--+ + +------------+---+ Splitter | <-- Port 1 + | oooooooooo | |----------+ + | oooooooooo | | + +----------------- + + The splitter was designed 2015 by Jim Fetzner (as Tekumel Software) + + March 2025, Michael Zapf + +*****************************************************************************/ + +#include "emu.h" +#include "ioport.h" +#include "splitter.h" +#include "bus/ti99/peb/peribox.h" + +#define LOG_WARN (1U << 1) // Warnings +#define LOG_CONFIG (1U << 2) // Configuration +#define LOG_INT (1U << 3) +#define LOG_READY (1U << 4) + +#define VERBOSE (LOG_CONFIG | LOG_WARN) + +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(TI99_IOSPLIT, bus::ti99::internal::ioport_splitter_device, "ti99_iosplit", "TI-99 I/O Port Splitter") + +namespace bus::ti99::internal { + +#define PORT1 "port1" +#define PORT2 "port2" + +ioport_splitter_device::ioport_splitter_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : ioport_attached_device(mconfig, type, tag, owner, clock), + m_port1(*this, PORT1), + m_port2(*this, PORT2) +{ +} + +ioport_splitter_device::ioport_splitter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ioport_splitter_device(mconfig, TI99_IOSPLIT, tag, owner, clock) +{ +} + +void ioport_splitter_device::readz(offs_t offset, uint8_t *value) +{ + // With a proper configuration, only one device on one of the branches + // will respond. + if (m_port1 != nullptr) + m_port1->readz(offset, value); + + if (m_port2 != nullptr) + m_port2->readz(offset, value); +} + +void ioport_splitter_device::write(offs_t offset, uint8_t data) +{ + if (m_port1 != nullptr) + m_port1->write(offset, data); + + if (m_port2 != nullptr) + m_port2->write(offset, data); +} + +void ioport_splitter_device::setaddress_dbin(offs_t offset, int state) +{ + if (m_port1 != nullptr) + m_port1->setaddress_dbin(offset, state); + + if (m_port2 != nullptr) + m_port2->setaddress_dbin(offset, state); +} + +void ioport_splitter_device::crureadz(offs_t offset, uint8_t *value) +{ + if (m_port1 != nullptr) + m_port1->crureadz(offset, value); + + if (m_port2 != nullptr) + m_port2->crureadz(offset, value); +} + +void ioport_splitter_device::cruwrite(offs_t offset, uint8_t data) +{ + if (m_port1 != nullptr) + m_port1->cruwrite(offset, data); + + if (m_port2 != nullptr) + m_port2->cruwrite(offset, data); +} + +void ioport_splitter_device::memen_in(int state) +{ + if (m_port1 != nullptr) + m_port1->memen_in(state); + + if (m_port2 != nullptr) + m_port2->memen_in(state); +} + +void ioport_splitter_device::msast_in(int state) +{ + if (m_port1 != nullptr) + m_port1->msast_in(state); + + if (m_port2 != nullptr) + m_port2->msast_in(state); +} + +void ioport_splitter_device::clock_in(int state) +{ + if (m_port1 != nullptr) + m_port1->clock_in(state); + + if (m_port2 != nullptr) + m_port2->clock_in(state); +} + +void ioport_splitter_device::reset_in(int state) +{ + if (m_port1 != nullptr) + m_port1->reset_in(state); + + if (m_port2 != nullptr) + m_port2->reset_in(state); +} + +template +void ioport_splitter_device::extint(int state) +{ + LOGMASKED(LOG_INT, "propagating INTA from port %d to console: %d\n", port, state); + if (state==ASSERT_LINE) + m_inta_flag |= port; // 1 or 2 + else + m_inta_flag &= ~port; // 1 or 2 + + set_extint((m_inta_flag != 0)? ASSERT_LINE : CLEAR_LINE); +} + +template +void ioport_splitter_device::ready(int state) +{ + LOGMASKED(LOG_READY, "Incoming READY=%d from port %d\n", state, port); + // We store the inverse state + if (state==CLEAR_LINE) + m_ready_flag |= port; // 1 or 2 + else + m_ready_flag &= ~port; // 1 or 2 + + set_ready((m_ready_flag != 0)? CLEAR_LINE : ASSERT_LINE); +} + +void ioport_splitter_device::device_start() +{ + LOG("Starting I/O Port Splitter\n"); +} + + +void ioport_splitter_device::device_config_complete() +{ + m_inta_flag = 0; + m_ready_flag = 0; +} + +void ioport_splitter_device::device_add_mconfig(machine_config &config) +{ + TI99_IOPORT(config, m_port1, 1, ti99_ioport_options_evpc1, nullptr); + TI99_IOPORT(config, m_port2, 2, ti99_ioport_options_evpc1, nullptr); + + m_port1->extint_cb().set(FUNC(ioport_splitter_device::extint<1>)); + m_port2->extint_cb().set(FUNC(ioport_splitter_device::extint<2>)); + m_port1->ready_cb().set(FUNC(ioport_splitter_device::ready<1>)); + m_port2->ready_cb().set(FUNC(ioport_splitter_device::ready<2>)); +} + +} // end namespace bus::ti99::internal diff --git a/src/devices/bus/ti99/internal/splitter.h b/src/devices/bus/ti99/internal/splitter.h new file mode 100644 index 00000000000..350b4f2666d --- /dev/null +++ b/src/devices/bus/ti99/internal/splitter.h @@ -0,0 +1,65 @@ +// license:LGPL-2.1+ +// copyright-holders:Michael Zapf +/**************************************************************************** + + I/O port splitter + + This plugs into the I/O port of the console as an + ioport_attached_device, and it offers two new I/O ports. + +*****************************************************************************/ + +#ifndef MAME_BUS_TI99_INTERNAL_SPLITTER_H +#define MAME_BUS_TI99_INTERNAL_SPLITTER_H + +#pragma once + +#include "ioport.h" + +namespace bus::ti99::internal { + +class ioport_splitter_device : public ioport_attached_device +{ + +public: + ioport_splitter_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // Next methods are called from the console + void readz(offs_t offset, uint8_t *value) override; + void write(offs_t offset, uint8_t data) override; + void setaddress_dbin(offs_t offset, int state) override; + + void crureadz(offs_t offset, uint8_t *value) override; + void cruwrite(offs_t offset, uint8_t data) override; + + void memen_in(int state) override; + void msast_in(int state) override; + + void clock_in(int state) override; + void reset_in(int state) override; + +protected: + ioport_splitter_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_config_complete() override; + + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + // Callbacks from the two ports + template void extint(int state); + template void ready(int state); + + int m_inta_flag; + int m_ready_flag; + +private: + required_device m_port1; + required_device m_port2; +}; + +} // end namespace bus::ti99::internal + +DECLARE_DEVICE_TYPE_NS(TI99_IOSPLIT, bus::ti99::internal, ioport_splitter_device) + +#endif /* __TI99SPLITTER__ */ diff --git a/src/devices/bus/ti99/peb/peribox.cpp b/src/devices/bus/ti99/peb/peribox.cpp index 4df80e153d5..d89293c3b6d 100644 --- a/src/devices/bus/ti99/peb/peribox.cpp +++ b/src/devices/bus/ti99/peb/peribox.cpp @@ -216,7 +216,10 @@ CRUCLK* 51||52 DBIN DEFINE_DEVICE_TYPE(TI99_PERIBOX, bus::ti99::peb::peribox_device, "peribox", "Peripheral expansion box") // Peripheral box which has a EVPC card in slot 2 (for use with the ti99_4ev) -DEFINE_DEVICE_TYPE(TI99_PERIBOX_EV, bus::ti99::peb::peribox_ev_device, "peribox_ev", "Peripheral expansion box with EVPC") +DEFINE_DEVICE_TYPE(TI99_PERIBOX_EV, bus::ti99::peb::peribox_ev_device, "peribox_ev", "Peripheral expansion box with EVPC inserted") + +// Peripheral box with EVPC (for use with the ti99_4ev with the port splitter) +DEFINE_DEVICE_TYPE(TI99_PERIBOX_EV1, bus::ti99::peb::peribox_ev1_device, "peribox_ev1", "Peripheral expansion box with EVPC") // Peripheral box which hosts the SGCPU card in slot 1 DEFINE_DEVICE_TYPE(TI99_PERIBOX_SG, bus::ti99::peb::peribox_sg_device, "peribox_sg", "Peripheral expansion box SGCPU") @@ -476,31 +479,54 @@ void peribox_device::device_config_complete() m_ready_flag = 0; } -void ti99_peribox_slot_standard(device_slot_interface &device) +// Slot options that work with TI-99/4A (with and without EVPC), SGCPU, Geneve, +// and TI-99/8 (untested) +void peribox_common_slots(device_slot_interface &device) { - device.option_add("32kmem", TI99_32KMEM); - device.option_add("myarcmem", TI99_MYARCMEM); - device.option_add("samsmem", TI99_SAMSMEM); - device.option_add("pcode", TI99_P_CODE); - device.option_add("hsgpl", TI99_HSGPL); device.option_add("tirs232", TI99_RS232); device.option_add("speech", TI99_SPEECH); device.option_add("horizon", TI99_HORIZON); - device.option_add("pgram", TI99_PGRAM); device.option_add("ide", TI99_IDE); device.option_add("usbsm", TI99_USBSM); - device.option_add("bwg", TI99_BWG); device.option_add("hfdc", TI99_HFDC); device.option_add("tifdc", TI99_FDC); device.option_add("ccdcc", TI99_CCDCC); device.option_add("ccfdc", TI99_CCFDC); device.option_add("ddcc1", TI99_DDCC1); device.option_add("forti", TI99_FORTI); - device.option_add("sidmaster", TI99_SIDMASTER); device.option_add("whtscsi", TI99_WHTSCSI); device.option_add("tipi", TI99_TIPI); } +// Slot options for TI-99/4A with or without EVPC and SGCPU +// The BwG controller will not run with the Geneve due to its wait state +// logic (see bwg.cpp) +// The SID master card may have trouble with the Geneve because of its CRU +// handling (see sidmaster.cpp) +void peribox_ti99_slots(device_slot_interface &device) +{ + device.option_add("myarcmem", TI99_MYARCMEM); + device.option_add("samsmem", TI99_SAMSMEM); + device.option_add("pcode", TI99_P_CODE); + device.option_add("hsgpl", TI99_HSGPL); + device.option_add("bwg", TI99_BWG); + device.option_add("sidmaster", TI99_SIDMASTER); + peribox_common_slots(device); +} + +// Geneve and SGCPU do not work with these memory expansions +void peribox_std_slots(device_slot_interface &device) +{ + device.option_add("32kmem", TI99_32KMEM); + device.option_add("pgram", TI99_PGRAM); + peribox_ti99_slots(device); +} + +void ti99_peribox_slot_standard(device_slot_interface &device) +{ + peribox_std_slots(device); +} + void peribox_device::device_add_mconfig(machine_config &config) { TI99_PERIBOX_SLOT(config, m_slot2, 2, ti99_peribox_slot_standard, nullptr); @@ -524,28 +550,8 @@ peribox_ev_device::peribox_ev_device(const machine_config &mconfig, const char * void ti99_peribox_slot_evpc(device_slot_interface &device) { - device.option_add("evpc", TI99_EVPC); - device.option_add("32kmem", TI99_32KMEM); - device.option_add("myarcmem", TI99_MYARCMEM); - device.option_add("samsmem", TI99_SAMSMEM); - device.option_add("pcode", TI99_P_CODE); - device.option_add("hsgpl", TI99_HSGPL); - device.option_add("tirs232", TI99_RS232); - device.option_add("speech", TI99_SPEECH); - device.option_add("horizon", TI99_HORIZON); - device.option_add("pgram", TI99_PGRAM); - device.option_add("ide", TI99_IDE); - device.option_add("usbsm", TI99_USBSM); - device.option_add("bwg", TI99_BWG); - device.option_add("hfdc", TI99_HFDC); - device.option_add("tifdc", TI99_FDC); - device.option_add("ccdcc", TI99_CCDCC); - device.option_add("ccfdc", TI99_CCFDC); - device.option_add("ddcc1", TI99_DDCC1); - device.option_add("forti", TI99_FORTI); - device.option_add("sidmaster", TI99_SIDMASTER); - device.option_add("whtscsi", TI99_WHTSCSI); - device.option_add("tipi", TI99_TIPI); + device.option_add("evpc", TI99_EVPC); + peribox_std_slots(device); } void peribox_ev_device::device_add_mconfig(machine_config &config) @@ -559,6 +565,28 @@ void peribox_ev_device::device_add_mconfig(machine_config &config) TI99_PERIBOX_SLOT(config, m_slot8, 8, ti99_peribox_slot_evpc, nullptr); } +/**************************************************************************** + A variant of the box used for the TI-99/4A with EVPC, not inserted +*****************************************************************************/ + +peribox_ev1_device::peribox_ev1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : peribox_device(mconfig, TI99_PERIBOX_EV1, tag, owner, clock) +{ + m_address_prefix = 0x70000; +} + +void peribox_ev1_device::device_add_mconfig(machine_config &config) +{ + TI99_PERIBOX_SLOT(config, m_slot2, 2, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot3, 3, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot4, 4, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot5, 5, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot6, 6, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot7, 7, ti99_peribox_slot_evpc, nullptr); + TI99_PERIBOX_SLOT(config, m_slot8, 8, ti99_peribox_slot_evpc, nullptr); +} + + /**************************************************************************** A variant of the box used for the Geneve. *****************************************************************************/ @@ -582,28 +610,11 @@ peribox_genmod_device::peribox_genmod_device(const machine_config &mconfig, cons { } -// The BwG controller will not run with the Geneve due to its wait state -// logic (see bwg.cpp) -// The SID master card may have trouble with the Geneve because of its CRU -// handling (see sidmaster.cpp) - +// All common slot options plus Memex. void ti99_peribox_slot_geneve(device_slot_interface &device) { - device.option_add("memex", TI99_MEMEX); - device.option_add("tirs232", TI99_RS232); - device.option_add("speech", TI99_SPEECH); - device.option_add("horizon", TI99_HORIZON); - device.option_add("ide", TI99_IDE); - device.option_add("usbsm", TI99_USBSM); - device.option_add("hfdc", TI99_HFDC); - device.option_add("tifdc", TI99_FDC); - device.option_add("ccdcc", TI99_CCDCC); - device.option_add("ccfdc", TI99_CCFDC); - device.option_add("ddcc1", TI99_DDCC1); - device.option_add("forti", TI99_FORTI); - device.option_add("sidmaster", TI99_SIDMASTER); - device.option_add("whtscsi", TI99_WHTSCSI); - device.option_add("tipi", TI99_TIPI); + device.option_add("memex", TI99_MEMEX); + peribox_common_slots(device); } void peribox_gen_device::device_add_mconfig(machine_config &config) @@ -642,26 +653,8 @@ peribox_sg_device::peribox_sg_device(const machine_config &mconfig, const char * void ti99_peribox_slot_sgcpu(device_slot_interface &device) { - device.option_add("evpc", TI99_EVPC); - device.option_add("myarcmem", TI99_MYARCMEM); - device.option_add("samsmem", TI99_SAMSMEM); - device.option_add("pcode", TI99_P_CODE); - device.option_add("hsgpl", TI99_HSGPL); - device.option_add("tirs232", TI99_RS232); - device.option_add("speech", TI99_SPEECH); - device.option_add("horizon", TI99_HORIZON); - device.option_add("ide", TI99_IDE); - device.option_add("usbsm", TI99_USBSM); - device.option_add("bwg", TI99_BWG); - device.option_add("hfdc", TI99_HFDC); - device.option_add("tifdc", TI99_FDC); - device.option_add("ccdcc", TI99_CCDCC); - device.option_add("ccfdc", TI99_CCFDC); - device.option_add("ddcc1", TI99_DDCC1); - device.option_add("forti", TI99_FORTI); - device.option_add("sidmaster", TI99_SIDMASTER); - device.option_add("whtscsi", TI99_WHTSCSI); - device.option_add("tipi", TI99_TIPI); + device.option_add("evpc", TI99_EVPC); + peribox_ti99_slots(device); } void peribox_sg_device::device_add_mconfig(machine_config &config) diff --git a/src/devices/bus/ti99/peb/peribox.h b/src/devices/bus/ti99/peb/peribox.h index ef33b9e5945..7d9c0b6f9e9 100644 --- a/src/devices/bus/ti99/peb/peribox.h +++ b/src/devices/bus/ti99/peb/peribox.h @@ -140,6 +140,18 @@ protected: virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; }; +/* + Variation for ti99_4ev without EVPC inserted +*/ +class peribox_ev1_device : public peribox_device +{ +public: + peribox_ev1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; +}; + /* Variation for Geneve. @@ -266,6 +278,7 @@ private: DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX, bus::ti99::peb, peribox_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_EV, bus::ti99::peb, peribox_ev_device) +DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_EV1, bus::ti99::peb, peribox_ev1_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_SLOT, bus::ti99::peb, peribox_slot_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_SG, bus::ti99::peb, peribox_sg_device) DECLARE_DEVICE_TYPE_NS(TI99_PERIBOX_GEN, bus::ti99::peb, peribox_gen_device)