summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/bus.lua26
-rw-r--r--src/devices/bus/mpf1/epb.cpp131
-rw-r--r--src/devices/bus/mpf1/epb.h14
-rw-r--r--src/devices/bus/mpf1/iom.cpp145
-rw-r--r--src/devices/bus/mpf1/iom.h13
-rw-r--r--src/devices/bus/mpf1/prt.cpp138
-rw-r--r--src/devices/bus/mpf1/prt.h14
-rw-r--r--src/devices/bus/mpf1/sgb.cpp73
-rw-r--r--src/devices/bus/mpf1/sgb.h13
-rw-r--r--src/devices/bus/mpf1/slot.cpp126
-rw-r--r--src/devices/bus/mpf1/slot.h122
-rw-r--r--src/devices/bus/mpf1/ssb.cpp93
-rw-r--r--src/devices/bus/mpf1/ssb.h13
-rw-r--r--src/devices/bus/mpf1/tva.cpp85
-rw-r--r--src/devices/bus/mpf1/tva.h13
-rw-r--r--src/devices/bus/mpf1/vid.cpp158
-rw-r--r--src/devices/bus/mpf1/vid.h13
-rw-r--r--src/mame/layout/mpf1p.lay114
-rw-r--r--src/mame/layout/mt80z.lay77
-rw-r--r--src/mame/mame.lst10
-rw-r--r--src/mame/multitech/mpf1.cpp391
-rw-r--r--src/mame/multitech/mpf1.h88
-rw-r--r--src/mame/multitech/mpf1p.cpp396
23 files changed, 1947 insertions, 319 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 7ef89b621a3..10ea963a65d 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -1902,6 +1902,32 @@ end
---------------------------------------------------
--
+--@src/devices/bus/mpf1/slot.h,BUSES["MPF1"] = true
+---------------------------------------------------
+
+if (BUSES["MPF1"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/mpf1/slot.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/slot.h",
+ MAME_DIR .. "src/devices/bus/mpf1/epb.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/epb.h",
+ MAME_DIR .. "src/devices/bus/mpf1/iom.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/iom.h",
+ MAME_DIR .. "src/devices/bus/mpf1/prt.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/prt.h",
+ MAME_DIR .. "src/devices/bus/mpf1/sgb.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/sgb.h",
+ MAME_DIR .. "src/devices/bus/mpf1/ssb.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/ssb.h",
+ MAME_DIR .. "src/devices/bus/mpf1/tva.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/tva.h",
+ MAME_DIR .. "src/devices/bus/mpf1/vid.cpp",
+ MAME_DIR .. "src/devices/bus/mpf1/vid.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/bus/msx/ctrl/ctrl.h,BUSES["MSX_CTRL"] = true
---------------------------------------------------
diff --git a/src/devices/bus/mpf1/epb.cpp b/src/devices/bus/mpf1/epb.cpp
new file mode 100644
index 00000000000..718f904965d
--- /dev/null
+++ b/src/devices/bus/mpf1/epb.cpp
@@ -0,0 +1,131 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech Eprom Programmer Board
+
+ EPB-MPF :
+ MPF-1B : ADDR 9000 GO
+
+ EPB-MPF-IBP :
+ MPF-1P : G 9000
+ MPF-1B : ADDR 9800 GO
+
+***************************************************************************/
+
+#include "emu.h"
+#include "epb.h"
+#include "machine/i8255.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_epb )
+ ROM_REGION(0x0800, "rom", 0)
+ ROM_LOAD("epb-ib.u8", 0x0000, 0x0800, CRC(bbd854f5) SHA1(489e597c12a14a1cf9568d18b299e4f4ae656f71))
+ROM_END
+
+ROM_START( mpf_epb_ibp )
+ ROM_REGION(0x1000, "rom", 0)
+ ROM_LOAD("ebp-ibp.u8", 0x0000, 0x1000, CRC(0156387a) SHA1(296842ee5bac23f41f46534663d4f0bfc04075cf))
+ROM_END
+
+
+//-------------------------------------------------
+// mpf_epb_device - constructor
+//-------------------------------------------------
+
+class mpf_epb_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ static constexpr feature_type unemulated_features() { return feature::ROM; }
+
+ mpf_epb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mpf_epb_device(mconfig, MPF_EPB, tag, owner, clock)
+ {
+ }
+
+protected:
+ mpf_epb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom(*this, "rom")
+ , m_ppi(*this, "ppi")
+ {
+ }
+
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ I8255(config, m_ppi);
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_epb );
+ }
+
+ virtual void device_start() override
+ {
+ m_ram = make_unique_clear<uint8_t[]>(0x1000);
+
+ // register for save states
+ save_pointer(NAME(m_ram), 0x1000);
+ }
+
+ virtual void device_reset() override
+ {
+ program_space().install_ram(0x8000, 0x8fff, m_ram.get());
+ program_space().install_rom(0x9000, 0x97ff, m_rom->base());
+
+ io_space().install_readwrite_handler(0xcc, 0xcf, emu::rw_delegate(*m_ppi, FUNC(i8255_device::read)), emu::rw_delegate(*m_ppi, FUNC(i8255_device::write)));
+ }
+
+ required_memory_region m_rom;
+ required_device<i8255_device> m_ppi;
+
+ std::unique_ptr<uint8_t[]> m_ram;
+};
+
+
+// ======================> mpf_epb_ibp_device
+
+class mpf_epb_ibp_device : public mpf_epb_device
+{
+public:
+ mpf_epb_ibp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mpf_epb_device(mconfig, MPF_EPB_IBP, tag, owner, clock)
+ {
+ }
+
+protected:
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_epb_ibp );
+ }
+
+ virtual void device_start() override
+ {
+ m_ram = make_unique_clear<uint8_t[]>(0x1800);
+
+ // register for save states
+ save_pointer(NAME(m_ram), 0x1800);
+ }
+
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0x9000, 0x9fff, m_rom->base());
+ program_space().install_ram(0xd800, 0xefff, m_ram.get());
+
+ io_space().install_readwrite_handler(0x70, 0x7f, emu::rw_delegate(*m_ppi, FUNC(i8255_device::read)), emu::rw_delegate(*m_ppi, FUNC(i8255_device::write)));
+ }
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_EPB, device_mpf1_exp_interface, mpf_epb_device, "mpf1_epb", "Multitech EPB-MPF (Eprom Programmer Board)")
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_EPB_IBP, device_mpf1_exp_interface, mpf_epb_ibp_device, "mpf1_epb_ibp", "Multitech EPB-MPF-IBP (Eprom Programmer Board)")
diff --git a/src/devices/bus/mpf1/epb.h b/src/devices/bus/mpf1/epb.h
new file mode 100644
index 00000000000..d52d52099e3
--- /dev/null
+++ b/src/devices/bus/mpf1/epb.h
@@ -0,0 +1,14 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_EPB_H
+#define MAME_BUS_MPF1_EPB_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_EPB, device_mpf1_exp_interface)
+DECLARE_DEVICE_TYPE(MPF_EPB_IBP, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_EPB_H
diff --git a/src/devices/bus/mpf1/iom.cpp b/src/devices/bus/mpf1/iom.cpp
new file mode 100644
index 00000000000..e7b2df0213f
--- /dev/null
+++ b/src/devices/bus/mpf1/iom.cpp
@@ -0,0 +1,145 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech I/O and Memory Board
+
+ PIO Application Example : G B000
+ CTC Application Example : G B100
+ 8251 Application Example : G B300
+
+***************************************************************************/
+
+#include "emu.h"
+#include "iom.h"
+#include "machine/i8251.h"
+#include "machine/z80ctc.h"
+#include "machine/z80pio.h"
+#include "bus/rs232/rs232.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START(mpf_iom_ip)
+ ROM_REGION(0x1000, "rom", 0)
+ ROM_LOAD("ip-iom.bin", 0x0000, 0x1000, CRC(bf789c58) SHA1(2c3c26290e041e913d00d7e0d65d53480e27187c))
+ROM_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START(mpf_iom_ip)
+ PORT_START("DIPSW")
+ PORT_DIPNAME(0xf, 0xa, "Baud Rate")
+ PORT_DIPSETTING(0x0, "50")
+ PORT_DIPSETTING(0x1, "75")
+ PORT_DIPSETTING(0x2, "110")
+ PORT_DIPSETTING(0x3, "150")
+ PORT_DIPSETTING(0x4, "200")
+ PORT_DIPSETTING(0x5, "300")
+ PORT_DIPSETTING(0x6, "600")
+ PORT_DIPSETTING(0x7, "1200")
+ PORT_DIPSETTING(0x8, "2400")
+ PORT_DIPSETTING(0x9, "4800")
+ PORT_DIPSETTING(0xa, "9600")
+INPUT_PORTS_END
+
+
+static DEVICE_INPUT_DEFAULTS_START( terminal )
+ DEVICE_INPUT_DEFAULTS( "RS232_TXBAUD", 0xff, RS232_BAUD_9600 )
+ DEVICE_INPUT_DEFAULTS( "RS232_RXBAUD", 0xff, RS232_BAUD_9600 )
+ DEVICE_INPUT_DEFAULTS( "RS232_DATABITS", 0xff, RS232_DATABITS_7 )
+ DEVICE_INPUT_DEFAULTS( "RS232_PARITY", 0xff, RS232_PARITY_EVEN )
+ DEVICE_INPUT_DEFAULTS( "RS232_STOPBITS", 0xff, RS232_STOPBITS_1 )
+DEVICE_INPUT_DEFAULTS_END
+
+
+//-------------------------------------------------
+// mpf_iom_device - constructor
+//-------------------------------------------------
+
+class mpf_iom_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ mpf_iom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF_IOM_IP, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom(*this, "rom")
+ , m_ctc(*this, "ctc")
+ , m_pio(*this, "pio")
+ , m_usart(*this, "uart")
+ {
+ }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ Z80PIO(config, m_pio, DERIVED_CLOCK(1, 1));
+ m_pio->out_int_callback().set(DEVICE_SELF_OWNER, FUNC(mpf1_exp_device::int_w));
+
+ Z80CTC(config, m_ctc, DERIVED_CLOCK(1, 1));
+ m_ctc->set_clk<2>(DERIVED_CLOCK(1, 1));
+ m_ctc->zc_callback<2>().set(m_usart, FUNC(i8251_device::write_txc));
+ m_ctc->zc_callback<2>().append(m_usart, FUNC(i8251_device::write_rxc));
+ m_ctc->intr_callback().set(DEVICE_SELF_OWNER, FUNC(mpf1_exp_device::int_w));
+
+ I8251(config, m_usart, DERIVED_CLOCK(1, 1));
+ m_usart->rxrdy_handler().set(m_ctc, FUNC(z80ctc_device::trg3));
+ m_usart->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd));
+ m_usart->dtr_handler().set("rs232", FUNC(rs232_port_device::write_dtr));
+ m_usart->rts_handler().set("rs232", FUNC(rs232_port_device::write_rts));
+
+ rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, nullptr));
+ rs232.rxd_handler().set(m_usart, FUNC(i8251_device::write_rxd));
+ rs232.cts_handler().set(m_usart, FUNC(i8251_device::write_cts));
+ rs232.dsr_handler().set(m_usart, FUNC(i8251_device::write_dsr));
+ rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal));
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME(mpf_iom_ip);
+ }
+
+ virtual ioport_constructor device_input_ports() const override
+ {
+ return INPUT_PORTS_NAME(mpf_iom_ip);
+ }
+
+ virtual void device_start() override
+ {
+ m_ram = make_unique_clear<uint8_t[]>(0x1800);
+
+ save_pointer(NAME(m_ram), 0x1800);
+ }
+
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0xb000, 0xbfff, m_rom->base());
+ program_space().install_ram(0xd800, 0xefff, m_ram.get());
+
+ io_space().install_readwrite_handler(0x60, 0x61, emu::rw_delegate(*m_usart, FUNC(i8251_device::read)), emu::rw_delegate(*m_usart, FUNC(i8251_device::write)));
+ io_space().install_readwrite_handler(0x64, 0x67, emu::rw_delegate(*m_ctc, FUNC(z80ctc_device::read)), emu::rw_delegate(*m_ctc, FUNC(z80ctc_device::write)));
+ io_space().install_readwrite_handler(0x68, 0x6b, emu::rw_delegate(*m_pio, FUNC(z80pio_device::read)), emu::rw_delegate(*m_pio, FUNC(z80pio_device::write)));
+ io_space().install_read_port(0x6c, 0x6c, "DIPSW");
+ }
+
+private:
+ required_memory_region m_rom;
+ required_device<z80ctc_device> m_ctc;
+ required_device<z80pio_device> m_pio;
+ required_device<i8251_device> m_usart;
+
+ std::unique_ptr<uint8_t[]> m_ram;
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_IOM_IP, device_mpf1_exp_interface, mpf_iom_device, "mpf1_iom_ip", "Multitech IOM-MPF-IP (I/O and Memory Board)")
diff --git a/src/devices/bus/mpf1/iom.h b/src/devices/bus/mpf1/iom.h
new file mode 100644
index 00000000000..02fb9ff496d
--- /dev/null
+++ b/src/devices/bus/mpf1/iom.h
@@ -0,0 +1,13 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_IOM_H
+#define MAME_BUS_MPF1_IOM_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_IOM_IP, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_IOM_H
diff --git a/src/devices/bus/mpf1/prt.cpp b/src/devices/bus/mpf1/prt.cpp
new file mode 100644
index 00000000000..1962d2dcad9
--- /dev/null
+++ b/src/devices/bus/mpf1/prt.cpp
@@ -0,0 +1,138 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech Printer
+
+ PRT-MPF :
+ Printer driver utility : ADDR 65AC GO
+ Z80-Disassembler listing utility : ADDR 6000 GO
+ Memory dump utility : ADDR 6300 GO
+ BASIC program listing utility : ADDR 6400 GO
+ Printer line feed : ADDR 6500 GO
+
+ PRT-MPF-IP : Address Mnemonic Function
+ 6A00 SHIFT Drive the thermal head shift right
+ 6A10 PLINEFD Line feed
+ 6A30 PLINE Drive the paper vertically by two lines
+ 6A40 MTPPRT Print out the contents of the line buffer
+
+***************************************************************************/
+
+#include "emu.h"
+#include "prt.h"
+#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_prt )
+ ROM_REGION(0x1000, "u5", 0)
+ ROM_LOAD("prt-ib.u5", 0x0000, 0x1000, CRC(730f2fb0) SHA1(f31536ee9dbb9babb9ce16a7490db654ca0b5749))
+ROM_END
+
+ROM_START( mpf_prt_ip )
+ ROM_REGION(0x1000, "u5", 0)
+ ROM_LOAD("prt-ip_v1.1.u5", 0x0000, 0x1000, CRC(4dd2a4eb) SHA1(6a3e7daa7834d67fd572261ed4a9a62c4594fe3f))
+ROM_END
+
+
+//-------------------------------------------------
+// mpf_prt_device - constructor
+//-------------------------------------------------
+
+class mpf_prt_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ static constexpr feature_type unemulated_features() { return feature::PRINTER; }
+
+ mpf_prt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mpf_prt_device(mconfig, MPF_PRT, tag, owner, clock)
+ {
+ }
+
+protected:
+ mpf_prt_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom_u5(*this, "u5")
+ , m_rom_u6(*this, "u6")
+ {
+ }
+
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ // TODO: Seikosha MTP201A thermal printer
+
+ GENERIC_SOCKET(config, "u6", generic_linear_slot, nullptr, "bin,rom");
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_prt );
+ }
+
+ virtual void device_start() override { }
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0x6000, 0x6fff, m_rom_u5->base());
+ program_space().install_read_handler(0x7000, 0x7fff, emu::rw_delegate(*m_rom_u6, FUNC(generic_slot_device::read_rom)));
+
+ io_space().install_write_handler(0xca, 0xca, emu::rw_delegate(*this, FUNC(mpf_prt_device::prt_w)));
+ io_space().install_read_handler(0xcb, 0xcb, emu::rw_delegate(*this, FUNC(mpf_prt_device::prt_r)));
+ }
+
+private:
+ required_memory_region m_rom_u5;
+ required_device<generic_slot_device> m_rom_u6;
+
+ uint8_t prt_r()
+ {
+ uint8_t data = 0x00;
+
+ // bit 0 TGP
+ // bit 1 HP
+
+ return data;
+ }
+
+ void prt_w(uint8_t data)
+ {
+ // bit 0 TH7
+ // bit 1 TH6
+ // bit 2 TH5
+ // bit 3 TH4
+ // bit 4 TH3
+ // bit 5 TH2
+ // bit 6 TH1
+ // bit 7 MOTOR
+ }
+};
+
+
+class mpf_prt_ip_device : public mpf_prt_device
+{
+public:
+ mpf_prt_ip_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : mpf_prt_device(mconfig, MPF_PRT_IP, tag, owner, clock)
+ {
+ }
+
+protected:
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_prt_ip );
+ }
+
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_PRT, device_mpf1_exp_interface, mpf_prt_device, "mpf1_prt", "Multitech PRT-MPF (Printer)")
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_PRT_IP, device_mpf1_exp_interface, mpf_prt_ip_device, "mpf1_prt_ip", "Multitech PRT-MPF-IP (Printer)")
diff --git a/src/devices/bus/mpf1/prt.h b/src/devices/bus/mpf1/prt.h
new file mode 100644
index 00000000000..fb465fe356f
--- /dev/null
+++ b/src/devices/bus/mpf1/prt.h
@@ -0,0 +1,14 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_PRT_H
+#define MAME_BUS_MPF1_PRT_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_PRT, device_mpf1_exp_interface)
+DECLARE_DEVICE_TYPE(MPF_PRT_IP, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_PRT_H
diff --git a/src/devices/bus/mpf1/sgb.cpp b/src/devices/bus/mpf1/sgb.cpp
new file mode 100644
index 00000000000..9866c05844d
--- /dev/null
+++ b/src/devices/bus/mpf1/sgb.cpp
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech Sound Generation Board
+
+ Piano : ADDR C200 GO
+
+***************************************************************************/
+
+#include "emu.h"
+#include "sgb.h"
+#include "sound/ay8910.h"
+#include "speaker.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_sgb )
+ ROM_REGION(0x1000, "rom", 0)
+ ROM_LOAD("sgb-mpf.bin", 0x0000, 0x1000, CRC(2d51d964) SHA1(13f3c7243d691b66ad5f0dcbbc16488c8905a394))
+ROM_END
+
+
+//-------------------------------------------------
+// mpf_sgb_device - constructor
+//-------------------------------------------------
+
+class mpf_sgb_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ mpf_sgb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF_SGB, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom(*this, "rom")
+ , m_ay(*this, "ay8910")
+ {
+ }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ SPEAKER(config, "mono").front_center();
+ AY8910(config, m_ay, DERIVED_CLOCK(1, 1)).add_route(ALL_OUTPUTS, "mono", 1.0);
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_sgb );
+ }
+
+ virtual void device_start() override { }
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0xc000, 0xcfff, m_rom->base());
+
+ io_space().install_read_handler(0xc1, 0xc1, emu::rw_delegate(*m_ay, FUNC(ay8910_device::data_r)));
+ io_space().install_write_handler(0xc2, 0xc3, emu::rw_delegate(*m_ay, FUNC(ay8910_device::data_address_w)));
+ }
+
+private:
+ required_memory_region m_rom;
+ required_device<ay8910_device> m_ay;
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_SGB, device_mpf1_exp_interface, mpf_sgb_device, "mpf1_sgb", "Multitech SGB-MPF (Sound Generation Board)")
diff --git a/src/devices/bus/mpf1/sgb.h b/src/devices/bus/mpf1/sgb.h
new file mode 100644
index 00000000000..4ae172a62cf
--- /dev/null
+++ b/src/devices/bus/mpf1/sgb.h
@@ -0,0 +1,13 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_SGB_H
+#define MAME_BUS_MPF1_SGB_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_SGB, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_SGB_H
diff --git a/src/devices/bus/mpf1/slot.cpp b/src/devices/bus/mpf1/slot.cpp
new file mode 100644
index 00000000000..d1470beb862
--- /dev/null
+++ b/src/devices/bus/mpf1/slot.cpp
@@ -0,0 +1,126 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Micro-Professor Expansion Slot
+
+***************************************************************************/
+
+#include "emu.h"
+#include "slot.h"
+
+// supported devices
+#include "epb.h"
+#include "iom.h"
+#include "prt.h"
+#include "sgb.h"
+#include "ssb.h"
+#include "tva.h"
+#include "vid.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE(MPF1_EXP, mpf1_exp_device, "mpf_exp", "Micro-Professor Expansion Slot")
+
+
+//**************************************************************************
+// SLOT DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mpf1_exp_device - constructor
+//-------------------------------------------------
+
+mpf1_exp_device::mpf1_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF1_EXP, tag, owner, clock)
+ , device_single_card_slot_interface<device_mpf1_exp_interface>(mconfig, *this)
+ , m_program(*this, finder_base::DUMMY_TAG, -1)
+ , m_io(*this, finder_base::DUMMY_TAG, -1)
+ , m_card(nullptr)
+ , m_int_handler(*this)
+ , m_nmi_handler(*this)
+ , m_wait_handler(*this)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void mpf1_exp_device::device_config_complete()
+{
+ // for pass-through connectors, use the parent slot's spaces
+ if (dynamic_cast<device_mpf1_exp_interface *>(owner()) != nullptr)
+ {
+ auto parent = dynamic_cast<mpf1_exp_device *>(owner()->owner());
+ if (parent != nullptr)
+ {
+ if (m_program.finder_tag() == finder_base::DUMMY_TAG)
+ m_program.set_tag(parent->m_program, parent->m_program.spacenum());
+ if (m_io.finder_tag() == finder_base::DUMMY_TAG)
+ m_io.set_tag(parent->m_io, parent->m_io.spacenum());
+ }
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mpf1_exp_device::device_start()
+{
+ m_card = get_card_device();
+}
+
+
+//**************************************************************************
+// CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_mpf1_exp_interface - constructor
+//-------------------------------------------------
+
+device_mpf1_exp_interface::device_mpf1_exp_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device, "mpf1exp")
+ , m_slot(dynamic_cast<mpf1_exp_device *>(device.owner()))
+{
+}
+
+
+//**************************************************************************
+// SLOT INTERFACE
+//**************************************************************************
+
+void mpf1_exp_devices(device_slot_interface &device)
+{
+ device.option_add("epb", MPF_EPB);
+ device.option_add("epb_ibp", MPF_EPB_IBP);
+ device.option_add("prt", MPF_PRT);
+ device.option_add("sgb", MPF_SGB);
+ device.option_add("ssb", MPF_SSB);
+ //device.option_add("vid", MPF_VID);
+}
+
+void mpf1p_exp_devices(device_slot_interface &device)
+{
+ device.option_add("epb_ibp", MPF_EPB_IBP);
+ //device.option_add("epb_ip", MPF_EPB_IP);
+ device.option_add("iom_ip", MPF_IOM_IP);
+ device.option_add("prt_ip", MPF_PRT_IP);
+ //device.option_add("sgb_ip", MPF_SGB_IP);
+ //device.option_add("ssb_ip", MPF_SSB_IP);
+ device.option_add("tva", MPF_TVA_IP);
+ device.option_add("vid", MPF_VID);
+}
+
+void mpf1_88_exp_devices(device_slot_interface &device)
+{
+ //device.option_add("epb_i88", MPF_EPB_I88);
+ //device.option_add("prt_i88", MPF_PRT_I88);
+}
diff --git a/src/devices/bus/mpf1/slot.h b/src/devices/bus/mpf1/slot.h
new file mode 100644
index 00000000000..7e2c338d361
--- /dev/null
+++ b/src/devices/bus/mpf1/slot.h
@@ -0,0 +1,122 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Micro-Professor Expansion Slot
+
+ 60-pin slot
+
+ +5V 1 2 D7
+ +5V 3 4 D6
+ GND 5 6 D5
+ GND 7 8 D4
+ GND 9 10 D3
+ GND 11 12 D2
+ GND 13 14 D1
+ GND 15 16 D0
+ GND 17 18 A15
+ A14 19 20 A13
+ A12 21 22 A11
+ A10 23 24 A9
+ A8 25 26 A7
+ A6 27 28 A5
+ A4 29 30 A3
+ A2 31 32 A1
+ A0 33 34 /RESET
+ GND 35 36 /RFSH
+ GND 37 38 /M1
+ GND 39 40 /BUSACK
+ GND 41 42 /WR
+ GND 43 44 /RD
+ GND 45 46 /IORQ
+ GND 47 48 /MREQ
+ GND 49 50 /HALT
+ GND 51 52 /NMI
+ GND 53 54 /INT
+ GND 55 56 /WAIT
+ GND 57 58 /BUSREQ
+ GND 59 60 SYSCLK
+
+***************************************************************************/
+
+#ifndef MAME_BUS_MPF1_SLOT_H
+#define MAME_BUS_MPF1_SLOT_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class device_mpf1_exp_interface;
+
+class mpf1_exp_device : public device_t, public device_single_card_slot_interface<device_mpf1_exp_interface>
+{
+ friend class device_mpf1_exp_interface;
+public:
+ // construction/destruction
+ template <typename T>
+ mpf1_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&opts, const char *dflt)
+ : mpf1_exp_device(mconfig, tag, owner, clock)
+ {
+ option_reset();
+ opts(*this);
+ set_default_option(dflt);
+ set_fixed(false);
+ }
+
+ mpf1_exp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_program_space(T &&tag, int spacenum) { m_program.set_tag(std::forward<T>(tag), spacenum); }
+ template <typename T> void set_io_space(T &&tag, int spacenum) { m_io.set_tag(std::forward<T>(tag), spacenum); }
+
+ // callbacks
+ auto int_handler() { return m_int_handler.bind(); }
+ auto nmi_handler() { return m_nmi_handler.bind(); }
+ auto wait_handler() { return m_wait_handler.bind(); }
+
+ // called from card device
+ void int_w(int state) { m_int_handler(state); }
+ void nmi_w(int state) { m_nmi_handler(state); }
+ void wait_w(int state) { m_wait_handler(state); }
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete() override;
+ virtual void device_start() override;
+
+ required_address_space m_program;
+ required_address_space m_io;
+
+ device_mpf1_exp_interface *m_card;
+
+private:
+ devcb_write_line m_int_handler;
+ devcb_write_line m_nmi_handler;
+ devcb_write_line m_wait_handler;
+};
+
+
+class device_mpf1_exp_interface : public device_interface
+{
+public:
+ // construction/destruction
+ device_mpf1_exp_interface(const machine_config &mconfig, device_t &device);
+
+protected:
+ address_space &program_space() { return *m_slot->m_program; }
+ address_space &io_space() { return *m_slot->m_io; }
+
+ mpf1_exp_device *m_slot;
+};
+
+// device type definition
+DECLARE_DEVICE_TYPE(MPF1_EXP, mpf1_exp_device)
+
+// supported devices
+void mpf1_exp_devices(device_slot_interface &device);
+void mpf1p_exp_devices(device_slot_interface &device);
+void mpf1_88_exp_devices(device_slot_interface &device);
+
+#endif // MAME_BUS_MPF1_SLOT_H
diff --git a/src/devices/bus/mpf1/ssb.cpp b/src/devices/bus/mpf1/ssb.cpp
new file mode 100644
index 00000000000..1c6a00dd3d7
--- /dev/null
+++ b/src/devices/bus/mpf1/ssb.cpp
@@ -0,0 +1,93 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech Speech Synthesizer Board
+
+ PROG 1 : Time-clock program ADDR 5000 GO
+ CHECK-CODE : Self-test, speak all vocabulary ADDR 51DC GO
+ PROG 2 : Speech program utility ADDR 5200 GO
+
+ TODO: improve VSP READY callback to Z80 WAIT, currently VSP FIFO overflows.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ssb.h"
+#include "machine/spchrom.h"
+#include "sound/tms5220.h"
+#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+#include "speaker.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_ssb )
+ ROM_REGION(0x1000, "u5", 0)
+ ROM_LOAD("ssb-mpf.bin", 0x0000, 0x1000, CRC(f926334f) SHA1(35847f8164eed4c0794a8b74e5d7fa972b10eb90))
+ROM_END
+
+
+//-------------------------------------------------
+// mpf_ssb_device - constructor
+//-------------------------------------------------
+
+class mpf_ssb_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ static constexpr feature_type imperfect_features() { return feature::SOUND; }
+
+ mpf_ssb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF_SSB, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom_u5(*this, "u5")
+ , m_rom_u4(*this, "u4")
+ , m_rom_u3(*this, "u3")
+ , m_vsp(*this, "vsp")
+ {
+ }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ SPEAKER(config, "mono").front_center();
+
+ TMS5200(config, m_vsp, 640000);
+ m_vsp->ready_cb().set(DEVICE_SELF_OWNER, FUNC(mpf1_exp_device::wait_w));
+ m_vsp->add_route(ALL_OUTPUTS, "mono", 0.5);
+
+ GENERIC_SOCKET(config, "u4", generic_linear_slot, nullptr, "bin,rom");
+ GENERIC_SOCKET(config, "u3", generic_linear_slot, nullptr, "bin,rom");
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_ssb );
+ }
+
+ virtual void device_start() override { }
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0x5000, 0x5fff, m_rom_u5->base());
+ program_space().install_read_handler(0x6000, 0x6fff, emu::rw_delegate(*m_rom_u4, FUNC(generic_slot_device::read_rom)));
+ program_space().install_read_handler(0x7000, 0x7fff, emu::rw_delegate(*m_rom_u3, FUNC(generic_slot_device::read_rom)));
+
+ io_space().install_readwrite_handler(0xfe, 0xfe, emu::rw_delegate(*m_vsp, FUNC(tms5200_device::status_r)), emu::rw_delegate(*m_vsp, FUNC(tms5200_device::data_w)));
+ }
+
+private:
+ required_memory_region m_rom_u5;
+ required_device<generic_slot_device> m_rom_u4;
+ required_device<generic_slot_device> m_rom_u3;
+ required_device<tms5200_device> m_vsp;
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_SSB, device_mpf1_exp_interface, mpf_ssb_device, "mpf1_ssb", "Multitech SSB-MPF (Speech Synthesizer Board)")
diff --git a/src/devices/bus/mpf1/ssb.h b/src/devices/bus/mpf1/ssb.h
new file mode 100644
index 00000000000..00a618f842a
--- /dev/null
+++ b/src/devices/bus/mpf1/ssb.h
@@ -0,0 +1,13 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_SSB_H
+#define MAME_BUS_MPF1_SSB_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_SSB, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_SSB_H
diff --git a/src/devices/bus/mpf1/tva.cpp b/src/devices/bus/mpf1/tva.cpp
new file mode 100644
index 00000000000..206ff6cea6f
--- /dev/null
+++ b/src/devices/bus/mpf1/tva.cpp
@@ -0,0 +1,85 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Multitech TVA-MPF-IP
+
+ TODO:
+ - no known documentation so emulation not verified.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "tva.h"
+#include "screen.h"
+#include "video/ef9365.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_tva )
+ ROM_REGION(0x1000, "rom", 0)
+ ROM_LOAD("tva.bin", 0x0000, 0x1000, CRC(a9d4f261) SHA1(3a5b0dba5d1e2edda8563b55010c86efd1548d0b))
+ROM_END
+
+
+//-------------------------------------------------
+// mpf_tva_ip_device - constructor
+//-------------------------------------------------
+
+class mpf_tva_ip_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ static constexpr feature_type imperfect_features() { return feature::GRAPHICS; }
+
+ mpf_tva_ip_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF_TVA_IP, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom(*this, "rom")
+ , m_gdp(*this, "ef9367")
+ {
+ }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_size(512, 312);
+ screen.set_visarea(0, 512 - 1, 0, 256 - 1);
+ screen.set_refresh_hz(50);
+ screen.set_screen_update("ef9367", FUNC(ef9365_device::screen_update));
+ PALETTE(config, "palette", palette_device::MONOCHROME);
+
+ EF9365(config, m_gdp, 1750000); // EF9367
+ m_gdp->set_screen("screen");
+ m_gdp->set_palette_tag("palette");
+ m_gdp->set_nb_bitplanes(1);
+ m_gdp->set_display_mode(ef9365_device::DISPLAY_MODE_512x256);
+ m_gdp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(mpf1_exp_device::int_w));
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_tva );
+ }
+
+ virtual void device_start() override { }
+ virtual void device_reset() override
+ {
+ program_space().install_rom(0xa000, 0xafff, m_rom->base());
+ program_space().install_readwrite_handler(0xafe0, 0xafef, emu::rw_delegate(*m_gdp, FUNC(ef9365_device::data_r)), emu::rw_delegate(*m_gdp, FUNC(ef9365_device::data_w)));
+ }
+
+private:
+ required_memory_region m_rom;
+ required_device<ef9365_device> m_gdp;
+};
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_TVA_IP, device_mpf1_exp_interface, mpf_tva_ip_device, "mpf1_tva_ip", "Multitech TVA-MPF-IP (Video Board)")
diff --git a/src/devices/bus/mpf1/tva.h b/src/devices/bus/mpf1/tva.h
new file mode 100644
index 00000000000..9810d876923
--- /dev/null
+++ b/src/devices/bus/mpf1/tva.h
@@ -0,0 +1,13 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_TVA_H
+#define MAME_BUS_MPF1_TVA_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_TVA_IP, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_TVA_H
diff --git a/src/devices/bus/mpf1/vid.cpp b/src/devices/bus/mpf1/vid.cpp
new file mode 100644
index 00000000000..4ef0634a51c
--- /dev/null
+++ b/src/devices/bus/mpf1/vid.cpp
@@ -0,0 +1,158 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/***************************************************************************
+
+ Bardehle Electronics VIDEO-MPF-I
+
+***************************************************************************/
+
+#include "emu.h"
+#include "vid.h"
+#include "video/mc6845.h"
+#include "emupal.h"
+#include "screen.h"
+
+
+namespace {
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( mpf_vid )
+ ROM_REGION(0x0800, "rom", 0)
+ ROM_SYSTEM_BIOS(0, "20", "2.0")
+ ROMX_LOAD("vidmon_v20.bin", 0x0000, 0x0800, CRC(3a2293a0) SHA1(281092d82a272383b584b31064421296add20c46), ROM_BIOS(0))
+
+ ROM_REGION(0x0800, "chargen", 0)
+ ROM_LOAD("vidchar.bin", 0x0000, 0x0800, CRC(d56211f9) SHA1(9cf717de353b86c38f94b805d31a16d8079896af))
+ROM_END
+
+
+//-------------------------------------------------
+// gfx_layout mpf_vid_charlayout
+//-------------------------------------------------
+
+static const gfx_layout mpf_vid_charlayout =
+{
+ 8, 12, /* 8 x 12 characters */
+ 128, /* 128 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0 * 8, 1 * 8, 2 * 8, 3 * 8, 4 * 8, 5 * 8, 6 * 8, 7 * 8, 8 * 8, 9 * 8, 10 * 8, 11 * 8 },
+ 8 * 16 /* every char takes 16 bytes */
+};
+
+//-------------------------------------------------
+// GFXDECODE( gfx_mpf_vid )
+//-------------------------------------------------
+
+static GFXDECODE_START(gfx_mpf_vid)
+ GFXDECODE_ENTRY("chargen", 0, mpf_vid_charlayout, 0, 1)
+GFXDECODE_END
+
+
+//-------------------------------------------------
+// mpf_vid_device - constructor
+//-------------------------------------------------
+
+class mpf_vid_device : public device_t, public device_mpf1_exp_interface
+{
+public:
+ static constexpr feature_type imperfect_features() { return feature::GRAPHICS; }
+
+ mpf_vid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MPF_VID, tag, owner, clock)
+ , device_mpf1_exp_interface(mconfig, *this)
+ , m_rom(*this, "rom")
+ , m_chargen(*this, "chargen")
+ , m_crtc(*this, "mc6845")
+ , m_palette(*this, "palette")
+ {
+ }
+
+protected:
+ virtual void device_add_mconfig(machine_config &config) override
+ {
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_raw(8_MHz_XTAL, 512, 0, 320, 326, 0, 240);
+ screen.set_screen_update("mc6845", FUNC(mc6845_device::screen_update));
+
+ GFXDECODE(config, "gfxdecode", m_palette, gfx_mpf_vid);
+ PALETTE(config, m_palette, palette_device::MONOCHROME);
+
+ MC6845(config, m_crtc, 8_MHz_XTAL / 8); // UM6845
+ m_crtc->set_screen("screen");
+ m_crtc->set_show_border_area(false);
+ m_crtc->set_char_width(8);
+ m_crtc->set_update_row_callback(FUNC(mpf_vid_device::crtc_update_row));
+ }
+
+ virtual const tiny_rom_entry *device_rom_region() const override
+ {
+ return ROM_NAME( mpf_vid );
+ }
+
+ virtual void device_start() override
+ {
+ m_videoram = make_unique_clear<uint8_t[]>(0x0800);
+
+ save_pointer(NAME(m_videoram), 0x0800);
+ }
+
+ virtual void device_reset() override
+ {
+ program_space().install_ram(0x4000, 0x47ff, 0x800, m_videoram.get());
+ program_space().install_rom(0xa000, 0xa7ff, m_rom->base());
+
+ io_space().nop_read(0xf0, 0xf0); // TODO: UM6845 Status Register (b7 must be high)
+ io_space().install_write_handler(0xf0, 0xf0, emu::rw_delegate(*m_crtc, FUNC(mc6845_device::address_w)));
+ io_space().install_readwrite_handler(0xf1, 0xf1, emu::rw_delegate(*m_crtc, FUNC(mc6845_device::register_r)), emu::rw_delegate(*m_crtc, FUNC(mc6845_device::register_w)));
+ }
+
+private:
+ required_memory_region m_rom;
+ required_memory_region m_chargen;
+ required_device<mc6845_device> m_crtc;
+ required_device<palette_device> m_palette;
+
+ MC6845_UPDATE_ROW(crtc_update_row);
+
+ std::unique_ptr<uint8_t[]> m_videoram;
+};
+
+
+//**************************************************************************
+// IMPLEMENTATION
+//**************************************************************************
+
+MC6845_UPDATE_ROW(mpf_vid_device::crtc_update_row)
+{
+ uint32_t *p = &bitmap.pix(y);
+
+ for (int column = 0; column < x_count; column++)
+ {
+ uint8_t code = m_videoram[(ma + column) & 0x7ff];
+ uint16_t addr = (code << 4) | (ra & 0x0f);
+ uint8_t data = m_chargen->base()[addr & 0x7ff];
+
+ if (column == cursor_x)
+ {
+ data = 0xff;
+ }
+
+ for (int bit = 0; bit < 8; bit++)
+ {
+ *p++ = m_palette->pen(BIT(code, 7) ? !BIT(data, 7) : BIT(data, 7));
+ data <<= 1;
+ }
+ }
+}
+
+} // anonymous namespace
+
+
+DEFINE_DEVICE_TYPE_PRIVATE(MPF_VID, device_mpf1_exp_interface, mpf_vid_device, "mpf1_vid", "Bardehle VIDEO-MPF-I (Video Board)")
diff --git a/src/devices/bus/mpf1/vid.h b/src/devices/bus/mpf1/vid.h
new file mode 100644
index 00000000000..83573004514
--- /dev/null
+++ b/src/devices/bus/mpf1/vid.h
@@ -0,0 +1,13 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+#ifndef MAME_BUS_MPF1_VID_H
+#define MAME_BUS_MPF1_VID_H
+
+#pragma once
+
+#include "slot.h"
+
+
+DECLARE_DEVICE_TYPE(MPF_VID, device_mpf1_exp_interface)
+
+#endif // MAME_BUS_MPF1_VID_H
diff --git a/src/mame/layout/mpf1p.lay b/src/mame/layout/mpf1p.lay
index fb787457be6..7f9608383eb 100644
--- a/src/mame/layout/mpf1p.lay
+++ b/src/mame/layout/mpf1p.lay
@@ -16,9 +16,9 @@ license:CC0-1.0
</element>
<element name="digit" defstate="0">
- <led16seg>
- <color red="0.0" green="1.0" blue="1.0" />
- </led16seg>
+ <led14segsc>
+ <color red="0.0" green="1.0" blue="1.0" />
+ </led14segsc>
</element>
<element name="dot" defstate="0">
@@ -41,59 +41,59 @@ license:CC0-1.0
<element name="digit1" ref="digit">
<bounds x="20" y="0" width="20" height="30" />
</element>
- <element name="digit2" ref="digit">
- <bounds x="40" y="0" width="20" height="30" />
- </element>
- <element name="digit3" ref="digit">
- <bounds x="60" y="0" width="20" height="30" />
- </element>
- <element name="digit4" ref="digit">
- <bounds x="80" y="0" width="20" height="30" />
- </element>
- <element name="digit5" ref="digit">
- <bounds x="100" y="0" width="20" height="30" />
- </element>
- <element name="digit6" ref="digit">
- <bounds x="120" y="0" width="20" height="30" />
- </element>
- <element name="digit7" ref="digit">
- <bounds x="140" y="0" width="20" height="30" />
- </element>
- <element name="digit8" ref="digit">
- <bounds x="160" y="0" width="20" height="30" />
- </element>
- <element name="digit9" ref="digit">
- <bounds x="180" y="0" width="20" height="30" />
- </element>
- <element name="digit10" ref="digit">
- <bounds x="200" y="0" width="20" height="30" />
- </element>
- <element name="digit11" ref="digit">
- <bounds x="220" y="0" width="20" height="30" />
- </element>
- <element name="digit12" ref="digit">
- <bounds x="240" y="0" width="20" height="30" />
- </element>
- <element name="digit13" ref="digit">
- <bounds x="260" y="0" width="20" height="30" />
- </element>
- <element name="digit14" ref="digit">
- <bounds x="280" y="0" width="20" height="30" />
- </element>
- <element name="digit15" ref="digit">
- <bounds x="300" y="0" width="20" height="30" />
- </element>
- <element name="digit16" ref="digit">
- <bounds x="320" y="0" width="20" height="30" />
- </element>
- <element name="digit17" ref="digit">
- <bounds x="340" y="0" width="20" height="30" />
- </element>
- <element name="digit18" ref="digit">
- <bounds x="360" y="0" width="20" height="30" />
- </element>
- <element name="digit19" ref="digit">
- <bounds x="380" y="0" width="20" height="30" />
- </element>
+ <element name="digit2" ref="digit">
+ <bounds x="40" y="0" width="20" height="30" />
+ </element>
+ <element name="digit3" ref="digit">
+ <bounds x="60" y="0" width="20" height="30" />
+ </element>
+ <element name="digit4" ref="digit">
+ <bounds x="80" y="0" width="20" height="30" />
+ </element>
+ <element name="digit5" ref="digit">
+ <bounds x="100" y="0" width="20" height="30" />
+ </element>
+ <element name="digit6" ref="digit">
+ <bounds x="120" y="0" width="20" height="30" />
+ </element>
+ <element name="digit7" ref="digit">
+ <bounds x="140" y="0" width="20" height="30" />
+ </element>
+ <element name="digit8" ref="digit">
+ <bounds x="160" y="0" width="20" height="30" />
+ </element>
+ <element name="digit9" ref="digit">
+ <bounds x="180" y="0" width="20" height="30" />
+ </element>
+ <element name="digit10" ref="digit">
+ <bounds x="200" y="0" width="20" height="30" />
+ </element>
+ <element name="digit11" ref="digit">
+ <bounds x="220" y="0" width="20" height="30" />
+ </element>
+ <element name="digit12" ref="digit">
+ <bounds x="240" y="0" width="20" height="30" />
+ </element>
+ <element name="digit13" ref="digit">
+ <bounds x="260" y="0" width="20" height="30" />
+ </element>
+ <element name="digit14" ref="digit">
+ <bounds x="280" y="0" width="20" height="30" />
+ </element>
+ <element name="digit15" ref="digit">
+ <bounds x="300" y="0" width="20" height="30" />
+ </element>
+ <element name="digit16" ref="digit">
+ <bounds x="320" y="0" width="20" height="30" />
+ </element>
+ <element name="digit17" ref="digit">
+ <bounds x="340" y="0" width="20" height="30" />
+ </element>
+ <element name="digit18" ref="digit">
+ <bounds x="360" y="0" width="20" height="30" />
+ </element>
+ <element name="digit19" ref="digit">
+ <bounds x="380" y="0" width="20" height="30" />
+ </element>
</view>
</mamelayout>
diff --git a/src/mame/layout/mt80z.lay b/src/mame/layout/mt80z.lay
new file mode 100644
index 00000000000..8e856d41ffc
--- /dev/null
+++ b/src/mame/layout/mt80z.lay
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<!--
+license:CC0-1.0
+-->
+<mamelayout version="2">
+ <element name="ledred" defstate="0">
+ <disk state="1">
+ <color red="1.0" green="0.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <element name="ledgreen" defstate="0">
+ <disk state="1">
+ <color red="0.0" green="1.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <element name="digit" defstate="0">
+ <led7seg>
+ <color red="0.75" green="0.0" blue="0.0" />
+ </led7seg>
+ </element>
+
+ <element name="dot" defstate="0">
+ <disk state="1">
+ <color red="0.75" green="0.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <view name="Default Layout">
+ <element name="led0" ref="ledgreen">
+ <bounds x="277" y="375" width="15" height="15" />
+ </element>
+ <element name="led1" ref="ledred">
+ <bounds x="277" y="394" width="15" height="15" />
+ </element>
+
+ <element name="digit0" ref="digit">
+ <bounds x="19" y="377" width="28" height="38" />
+ </element>
+ <element name="digit1" ref="digit">
+ <bounds x="58" y="377" width="28" height="38" />
+ </element>
+ <element name="digit2" ref="digit">
+ <bounds x="96" y="377" width="28" height="38" />
+ </element>
+ <element name="digit3" ref="digit">
+ <bounds x="134" y="377" width="28" height="38" />
+ </element>
+ <element name="digit4" ref="digit">
+ <bounds x="185" y="377" width="28" height="38" />
+ </element>
+ <element name="digit5" ref="digit">
+ <bounds x="223" y="377" width="28" height="38" />
+ </element>
+
+ <element name="led2" ref="dot">
+ <bounds x="43" y="409" width="4" height="5" />
+ </element>
+ <element name="led3" ref="dot">
+ <bounds x="82" y="409" width="4" height="5" />
+ </element>
+ <element name="led4" ref="dot">
+ <bounds x="120" y="409" width="4" height="5" />
+ </element>
+ <element name="led5" ref="dot">
+ <bounds x="158" y="409" width="4" height="5" />
+ </element>
+ <element name="led6" ref="dot">
+ <bounds x="209" y="409" width="4" height="5" />
+ </element>
+ <element name="led7" ref="dot">
+ <bounds x="247" y="409" width="4" height="5" />
+ </element>
+
+ </view>
+</mamelayout>
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 1d433262fc3..cb94b0dd175 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -32686,9 +32686,13 @@ mkit09 //
mkit09a //
@source:multitech/mpf1.cpp
-mpf1 // 1979 Multitech Micro Professor 1
-mpf1b // 1979 Multitech Micro Professor 1B
-mpf1p //
+cs113 // 198? Sciento Robot Arm
+mpf1 // 1981 Multitech Micro-Professor 1
+mpf1b // 1982 Multitech Micro-Professor 1B
+mt80z // 1982 MT-80Z
+
+@source:multitech/mpf1p.cpp
+mpf1p // 1983 Multitech Micro-Professor 1P
@source:multitech/mpf1_88.cpp
mpf1_88 // 1985 Multitech Micro-Professor I/88
diff --git a/src/mame/multitech/mpf1.cpp b/src/mame/multitech/mpf1.cpp
index 4c689a84eab..cd72bf8ff2f 100644
--- a/src/mame/multitech/mpf1.cpp
+++ b/src/mame/multitech/mpf1.cpp
@@ -35,26 +35,93 @@
Now press up-arrow to confirm the data has been entered.
TODO:
-
- - remove halt callback
- crt board
- - speech board
- - printers
- clickable artwork
- - video board (has 6845)
- - mpf1p has 49-key keyboard
- computer can't keep up with paste
- paste only set up for mpf1
*/
#include "emu.h"
-#include "mpf1.h"
+#include "cpu/z80/z80.h"
+#include "machine/i8255.h"
+#include "machine/timer.h"
+#include "machine/z80ctc.h"
+#include "machine/z80daisy.h"
+#include "machine/z80pio.h"
+#include "sound/spkrdev.h"
+
+#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+#include "bus/mpf1/slot.h"
+#include "imagedev/cassette.h"
+
+#include "softlist_dev.h"
#include "speaker.h"
#include "mpf1.lh"
#include "mpf1b.lh"
-#include "mpf1p.lh"
+#include "mt80z.lh"
+
+
+namespace {
+
+class mpf1_state : public driver_device
+{
+public:
+ mpf1_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_speaker(*this, "speaker")
+ , m_cassette(*this, "cassette")
+ , m_rom_region(*this, "maincpu")
+ , m_rom_u7(*this, "rom_u7")
+ , m_pc(*this, "PC%u", 0U)
+ , m_special(*this, "SPECIAL")
+ , m_digits(*this, "digit%u", 0U)
+ , m_leds(*this, "led%u", 0U)
+ { }
+
+ void mpf1(machine_config &config);
+ void mpf1b(machine_config &config);
+ void mt80z(machine_config &config);
+
+ DECLARE_INPUT_CHANGED_MEMBER( trigger_special );
+
+protected:
+ virtual void machine_start() override;
+ virtual void machine_reset() override;
+
+private:
+ required_device<z80_device> m_maincpu;
+ required_device<speaker_sound_device> m_speaker;
+ required_device<cassette_image_device> m_cassette;
+ required_region_ptr<uint8_t> m_rom_region;
+ required_device<generic_slot_device> m_rom_u7;
+ required_ioport_array<6> m_pc;
+ required_ioport m_special;
+ output_finder<6> m_digits;
+ output_finder<2> m_leds;
+
+ void mpf1_io_map(address_map &map);
+ void mpf1_map(address_map &map);
+ void mpf1_step(address_map &map);
+
+ uint8_t rom_r(offs_t offset);
+ uint8_t step_r(offs_t offset);
+ uint8_t ppi_pa_r();
+ void ppi_pb_w(uint8_t data);
+ void ppi_pc_w(uint8_t data);
+
+ int m_break = 0;
+ int m_m1 = 0;
+
+ uint8_t m_lednum = 0;
+
+ emu_timer *m_led_refresh_timer = nullptr;
+
+ TIMER_CALLBACK_MEMBER(led_refresh);
+};
/* Address Maps */
@@ -63,6 +130,7 @@ void mpf1_state::mpf1_map(address_map &map)
map.unmap_value_high();
map(0x0000, 0x0fff).rom();
map(0x1800, 0x1fff).ram();
+ map(0x2000, 0x2fff).r(FUNC(mpf1_state::rom_r));
}
void mpf1_state::mpf1_step(address_map &map)
@@ -70,87 +138,50 @@ void mpf1_state::mpf1_step(address_map &map)
map(0x0000, 0xffff).r(FUNC(mpf1_state::step_r));
}
-void mpf1_state::mpf1b_map(address_map &map)
-{
- map.unmap_value_high();
- map(0x0000, 0x0fff).rom();
- map(0x1800, 0x1fff).ram();
- map(0x2000, 0x2fff).rom();
- map(0x5000, 0x6fff).rom();
-}
-
-void mpf1_state::mpf1p_map(address_map &map)
-{
- map(0x0000, 0x1fff).rom();
- map(0x6000, 0x6fff).rom();
- map(0xf000, 0xffff).ram();
-}
-
void mpf1_state::mpf1_io_map(address_map &map)
{
map.unmap_value_high();
map.global_mask(0xff);
- map(0x00, 0x03).mirror(0x3c).rw(I8255A_TAG, FUNC(i8255_device::read), FUNC(i8255_device::write));
- map(0x40, 0x43).mirror(0x3c).rw(m_ctc, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
- map(0x80, 0x83).mirror(0x3c).rw(Z80PIO_TAG, FUNC(z80pio_device::read), FUNC(z80pio_device::write));
+ map(0x00, 0x03).mirror(0x3c).rw("ppi", FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0x40, 0x43).mirror(0x3c).rw("ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
+ map(0x80, 0x83).mirror(0x3c).rw("pio", FUNC(z80pio_device::read), FUNC(z80pio_device::write));
}
-void mpf1_state::mpf1b_io_map(address_map &map)
+uint8_t mpf1_state::rom_r(offs_t offset)
{
- map.unmap_value_high();
- map.global_mask(0xff);
- map(0x00, 0x03).mirror(0x3c).rw(I8255A_TAG, FUNC(i8255_device::read), FUNC(i8255_device::write));
- map(0x40, 0x43).mirror(0x3c).rw(m_ctc, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
- map(0x80, 0x83).mirror(0x3c).rw(Z80PIO_TAG, FUNC(z80pio_device::read), FUNC(z80pio_device::write));
- map(0xfe, 0xfe).mirror(0x01).rw(TMS5220_TAG, FUNC(tms5220_device::status_r), FUNC(tms5220_device::data_w));
-}
-
-void mpf1_state::mpf1p_io_map(address_map &map)
-{
- map.unmap_value_high();
- map.global_mask(0xff);
- map(0x00, 0x03).mirror(0x3c).rw(I8255A_TAG, FUNC(i8255_device::read), FUNC(i8255_device::write));
- map(0x40, 0x43).mirror(0x3c).rw(m_ctc, FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
- map(0x80, 0x83).mirror(0x3c).rw(Z80PIO_TAG, FUNC(z80pio_device::read), FUNC(z80pio_device::write));
+ if (m_rom_u7->exists())
+ return m_rom_u7->read_rom(offset & 0x1fff);
+ else
+ return m_rom_region[offset + 0x2000];
}
/* Input Ports */
-INPUT_CHANGED_MEMBER( mpf1_state::trigger_nmi )
-{
- m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? CLEAR_LINE : ASSERT_LINE);
-}
-
-INPUT_CHANGED_MEMBER( mpf1_state::trigger_irq )
-{
- m_maincpu->set_input_line(INPUT_LINE_IRQ0, newval ? CLEAR_LINE : ASSERT_LINE);
-}
-
-INPUT_CHANGED_MEMBER( mpf1_state::trigger_res )
+INPUT_CHANGED_MEMBER( mpf1_state::trigger_special )
{
- m_maincpu->set_input_line(INPUT_LINE_RESET, newval ? CLEAR_LINE : ASSERT_LINE);
+ m_maincpu->set_input_line(param, newval ? CLEAR_LINE : ASSERT_LINE);
}
static INPUT_PORTS_START( mpf1 )
PORT_START("PC0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("3 HL") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("7 HL'") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B I*IF") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F *PNC'") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B I.IF") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F .PNC'") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PC1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("2 DE") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 DE'") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A SP") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E SZ*H'") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E SZ.H'") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PC2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("1 BC") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("5 BC'") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("9 IY") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D *PNC") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D .PNC") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("STEP") PORT_CODE(KEYCODE_F1)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAPE RD") PORT_CODE(KEYCODE_F5)
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
@@ -159,7 +190,7 @@ static INPUT_PORTS_START( mpf1 )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("0 AF") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 AF'") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("8 IX") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C SZ*H") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C SZ.H") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GO") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TAPE WR") PORT_CODE(KEYCODE_F6)
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
@@ -184,9 +215,9 @@ static INPUT_PORTS_START( mpf1 )
PORT_START("SPECIAL")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("USER KEY") PORT_CODE(KEYCODE_U)
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MONI") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_nmi, 0)
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INTR") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_irq, 0)
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_res, 0)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MONI") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_NMI)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INTR") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_IRQ0)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_RESET)
INPUT_PORTS_END
static INPUT_PORTS_START( mpf1b )
@@ -223,30 +254,89 @@ static INPUT_PORTS_START( mpf1b )
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PC4")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("IF/\xE2\x88\xA7") PORT_CODE(KEYCODE_PGUP)
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("TO/\xE2\x86\x93") PORT_CODE(KEYCODE_T) PORT_CODE(KEYCODE_DOWN)
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("THEN/\xE2\x88\xA8") PORT_CODE(KEYCODE_PGDN)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"IF/\u2227") PORT_CODE(KEYCODE_PGUP) // U+2227 = ∧
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"TO/\u21e9") PORT_CODE(KEYCODE_T) PORT_CODE(KEYCODE_DOWN) // U+21E9 = ⇩
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"THEN/\u2228") PORT_CODE(KEYCODE_PGDN) // U+2228 = ∨
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GOTO") PORT_CODE(KEYCODE_G)
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RET/\xE2\x89\x81") PORT_CODE(KEYCODE_R)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RET/~") PORT_CODE(KEYCODE_R)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GOSUB") PORT_CODE(KEYCODE_O)
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("PC5")
- PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("FOR/\xE2\x86\x91") PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"FOR/\u21e7") PORT_CODE(KEYCODE_H) PORT_CODE(KEYCODE_UP) // U+21E7 = ⇧
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LIST") PORT_CODE(KEYCODE_L)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEW") PORT_CODE(KEYCODE_N)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER)
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CLR/\xE2\x86\x92") PORT_CODE(KEYCODE_INSERT) PORT_CODE(KEYCODE_RIGHT)
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DEL/\xE2\x86\x90") PORT_CODE(KEYCODE_DEL) PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"CLR/\u21e8") PORT_CODE(KEYCODE_INSERT) PORT_CODE(KEYCODE_RIGHT) // U+21E8 = ⇨
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(u8"DEL/\u21e6") PORT_CODE(KEYCODE_DEL) PORT_CODE(KEYCODE_LEFT) // U+21E6 = ⇦
PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("SPECIAL")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT)
- PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MONI") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_nmi, 0)
- PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INTR") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_irq, 0)
- PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_res, 0)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("MONI") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_NMI)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INTR") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_IRQ0)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_RESET)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( mt80z )
+ PORT_START("PC0")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GO") PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DUMP") PORT_CODE(KEYCODE_F6)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("COPY") PORT_CODE(KEYCODE_QUOTE)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEXT") PORT_CODE(KEYCODE_UP) PORT_CHAR('^')
+ PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("STEP") PORT_CODE(KEYCODE_F1)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("LOAD") PORT_CODE(KEYCODE_F5)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DEL") PORT_CODE(KEYCODE_SLASH)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PREV") PORT_CODE(KEYCODE_DOWN) PORT_CHAR('V')
+ PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("PC") PORT_CODE(KEYCODE_P) PORT_CHAR('P')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CLR BRK PT") PORT_CODE(KEYCODE_N)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INS") PORT_CODE(KEYCODE_COLON)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("DATA") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("9 IY") PORT_CODE(KEYCODE_9) PORT_CHAR('9')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("C SZ.H") PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REG") PORT_CODE(KEYCODE_COMMA)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SET BRK PT") PORT_CODE(KEYCODE_H)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RELA") PORT_CODE(KEYCODE_RCONTROL)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("ADDR") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("D .PNC") PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("8 IX") PORT_CODE(KEYCODE_8) PORT_CHAR('8')
+ PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 DE'") PORT_CODE(KEYCODE_6) PORT_CHAR('6')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("3 HL") PORT_CODE(KEYCODE_3) PORT_CHAR('3')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("7 HL'") PORT_CODE(KEYCODE_7) PORT_CHAR('7')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("F .PNC'") PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("5 BC'") PORT_CODE(KEYCODE_5) PORT_CHAR('5')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 AF'") PORT_CODE(KEYCODE_4) PORT_CHAR('4')
+ PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC5")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("2 DE") PORT_CODE(KEYCODE_2) PORT_CHAR('2')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("A SP") PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("B I.IF") PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("E SZ.H'") PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("1 BC") PORT_CODE(KEYCODE_1) PORT_CHAR('1')
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("0 AF") PORT_CODE(KEYCODE_0) PORT_CHAR('0')
+ PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("SPECIAL")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("USER KEY") PORT_CODE(KEYCODE_U)
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("BREAK") PORT_CODE(KEYCODE_M) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_NMI)
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INTR") PORT_CODE(KEYCODE_I) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_IRQ0)
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1_state, trigger_special, INPUT_LINE_RESET)
INPUT_PORTS_END
+
/* Intel 8255A Interface */
TIMER_CALLBACK_MEMBER(mpf1_state::led_refresh)
@@ -269,14 +359,14 @@ uint8_t mpf1_state::ppi_pa_r()
data &= m_special->read() & 1 ? 0xff : 0xbf;
/* bit 7, tape input */
- data |= ((m_cassette)->input() > 0) ? 0x80 : 0;
+ data |= (m_cassette->input() > 0) ? 0x80 : 0x00;
return data;
}
void mpf1_state::ppi_pb_w(uint8_t data)
{
- /* swap bits around for the mame 7-segment emulation */
+ /* swap bits around for the 7-segment emulation */
uint8_t led_data = bitswap<8>(data, 6, 1, 2, 0, 7, 5, 4, 3);
/* timer to update segments */
@@ -301,7 +391,7 @@ void mpf1_state::ppi_pc_w(uint8_t data)
/* bit 7, tape output, tone and led */
m_leds[0] = !BIT(data, 7);
m_speaker->level_w(BIT(data, 7));
- m_cassette->output( BIT(data, 7) ? 1.0 : -1.0);
+ m_cassette->output(BIT(data, 7) ? 1.0 : -1.0);
}
uint8_t mpf1_state::step_r(offs_t offset)
@@ -314,27 +404,21 @@ uint8_t mpf1_state::step_r(offs_t offset)
m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
}
- return m_program->read_byte(offset);
+ return m_maincpu->space(AS_PROGRAM).read_byte(offset);
}
+
/* Z80 Daisy Chain */
static const z80_daisy_config mpf1_daisy_chain[] =
{
- { Z80CTC_TAG },
- { Z80PIO_TAG },
+ { "ctc" },
+ { "pio" },
{ nullptr }
};
-/* Machine Initialization */
-TIMER_DEVICE_CALLBACK_MEMBER(mpf1_state::check_halt_callback)
-{
- // halt-LED; the red one, is turned on when the processor is halted
- // TODO: processor seems to halt, but restarts(?) at 0x0000 after a while -> fix
- int64_t led_halt = m_maincpu->state_int(Z80_HALT);
- m_leds[1] = led_halt;
-}
+/* Machine Initialization */
void mpf1_state::machine_start()
{
@@ -353,25 +437,27 @@ void mpf1_state::machine_reset()
m_lednum = 0;
}
+
/* Machine Drivers */
void mpf1_state::mpf1(machine_config &config)
{
/* basic machine hardware */
- Z80(config, m_maincpu, XTAL(3'579'545)/2);
+ Z80(config, m_maincpu, 3.579545_MHz_XTAL / 2);
m_maincpu->set_addrmap(AS_PROGRAM, &mpf1_state::mpf1_map);
m_maincpu->set_addrmap(AS_OPCODES, &mpf1_state::mpf1_step);
m_maincpu->set_addrmap(AS_IO, &mpf1_state::mpf1_io_map);
+ m_maincpu->halt_cb().set_output("led1");
m_maincpu->set_daisy_config(mpf1_daisy_chain);
/* devices */
- z80pio_device& pio(Z80PIO(config, Z80PIO_TAG, XTAL(3'579'545)/2));
+ z80pio_device &pio(Z80PIO(config, "pio", 3.579545_MHz_XTAL / 2));
pio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
- Z80CTC(config, m_ctc, XTAL(3'579'545)/2);
- m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+ z80ctc_device &ctc(Z80CTC(config, "ctc", 3.579545_MHz_XTAL / 2));
+ ctc.intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
- i8255_device &ppi(I8255A(config, I8255A_TAG));
+ i8255_device &ppi(I8255A(config, "ppi"));
ppi.in_pa_callback().set(FUNC(mpf1_state::ppi_pa_r));
ppi.out_pb_callback().set(FUNC(mpf1_state::ppi_pb_w));
ppi.out_pc_callback().set(FUNC(mpf1_state::ppi_pc_w));
@@ -386,107 +472,70 @@ void mpf1_state::mpf1(machine_config &config)
SPEAKER(config, "mono").front_center();
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
- TIMER(config, "halt_timer").configure_periodic(FUNC(mpf1_state::check_halt_callback), attotime::from_hz(1));
+ /* expansion */
+ mpf1_exp_device &exp(MPF1_EXP(config, "exp", 3.579545_MHz_XTAL / 2, mpf1_exp_devices, nullptr));
+ exp.set_program_space(m_maincpu, AS_PROGRAM);
+ exp.set_io_space(m_maincpu, AS_IO);
+ exp.int_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+ exp.nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI);
+ exp.wait_handler().set_inputline(m_maincpu, Z80_INPUT_LINE_WAIT);
+
+ GENERIC_SOCKET(config, m_rom_u7, generic_linear_slot, "mpf1_rom", "bin,rom");
+
+ SOFTWARE_LIST(config, "rom_ls").set_original("mpf1_rom").set_filter("IA");
}
void mpf1_state::mpf1b(machine_config &config)
{
- /* basic machine hardware */
- Z80(config, m_maincpu, XTAL(3'579'545)/2);
- m_maincpu->set_addrmap(AS_PROGRAM, &mpf1_state::mpf1b_map);
- m_maincpu->set_addrmap(AS_OPCODES, &mpf1_state::mpf1_step);
- m_maincpu->set_addrmap(AS_IO, &mpf1_state::mpf1b_io_map);
- m_maincpu->set_daisy_config(mpf1_daisy_chain);
-
- /* devices */
- z80pio_device& pio(Z80PIO(config, Z80PIO_TAG, XTAL(3'579'545)/2));
- pio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
-
- Z80CTC(config, m_ctc, XTAL(3'579'545)/2);
- m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
-
- i8255_device &ppi(I8255A(config, I8255A_TAG));
- ppi.in_pa_callback().set(FUNC(mpf1_state::ppi_pa_r));
- ppi.out_pb_callback().set(FUNC(mpf1_state::ppi_pb_w));
- ppi.out_pc_callback().set(FUNC(mpf1_state::ppi_pc_w));
+ mpf1(config);
- CASSETTE(config, m_cassette);
- m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
-
- /* video hardware */
config.set_default_layout(layout_mpf1b);
- /* sound hardware */
- SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
-
- TMS5220(config, TMS5220_TAG, 680000L).add_route(ALL_OUTPUTS, "mono", 0.50);
-
- TIMER(config, "halt_timer").configure_periodic(FUNC(mpf1_state::check_halt_callback), attotime::from_hz(1));
+ subdevice<software_list_device>("rom_ls")->set_filter("IA,IB");
}
-void mpf1_state::mpf1p(machine_config &config)
+void mpf1_state::mt80z(machine_config &config)
{
- /* basic machine hardware */
- Z80(config, m_maincpu, 2500000);
- m_maincpu->set_addrmap(AS_PROGRAM, &mpf1_state::mpf1p_map);
- m_maincpu->set_addrmap(AS_OPCODES, &mpf1_state::mpf1_step);
- m_maincpu->set_addrmap(AS_IO, &mpf1_state::mpf1p_io_map);
- m_maincpu->set_daisy_config(mpf1_daisy_chain);
-
- /* video hardware */
- config.set_default_layout(layout_mpf1p);
-
- /* devices */
- z80pio_device& pio(Z80PIO(config, Z80PIO_TAG, 2500000));
- pio.out_int_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
-
- Z80CTC(config, m_ctc, 2500000);
- m_ctc->intr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
-
- i8255_device &ppi(I8255A(config, I8255A_TAG));
- ppi.in_pa_callback().set(FUNC(mpf1_state::ppi_pa_r));
- ppi.out_pb_callback().set(FUNC(mpf1_state::ppi_pb_w));
- ppi.out_pc_callback().set(FUNC(mpf1_state::ppi_pc_w));
+ mpf1b(config);
- CASSETTE(config, m_cassette);
- m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
+ config.set_default_layout(layout_mt80z);
- /* sound hardware */
- SPEAKER(config, "mono").front_center();
- SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
-
- TIMER(config, "halt_timer").configure_periodic(FUNC(mpf1_state::check_halt_callback), attotime::from_hz(1));
+ // TODO: MT-80Z expansion board with switches (DIPs) and indicators (LEDs).
}
-/* ROMs */
ROM_START( mpf1 )
- ROM_REGION( 0x10000, Z80_TAG, 0 )
- ROM_LOAD( "mpf.u6", 0x0000, 0x1000, CRC(b60249ce) SHA1(78e0e8874d1497fabfdd6378266d041175e3797f) )
+ ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
+ ROM_LOAD("mpf1.u6", 0x0000, 0x0800, CRC(820030b1) SHA1(f618e2044b8f6e055e4d9a4c719b53bf16e22330))
ROM_END
ROM_START( mpf1b )
- ROM_REGION( 0x10000, Z80_TAG, 0 )
- ROM_LOAD( "c55167.u6", 0x0000, 0x1000, CRC(28b06dac) SHA1(99cfbab739d71a914c39302d384d77bddc4b705b) )
- ROM_LOAD( "basic.u7", 0x2000, 0x1000, CRC(d276ed6b) SHA1(a45fb98961be5e5396988498c6ed589a35398dcf) )
- ROM_LOAD( "ssb-mpf.u", 0x5000, 0x1000, CRC(f926334f) SHA1(35847f8164eed4c0794a8b74e5d7fa972b10eb90) )
- ROM_LOAD( "prt-mpf.u5", 0x6000, 0x1000, CRC(730f2fb0) SHA1(f31536ee9dbb9babb9ce16a7490db654ca0b5749) )
+ ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
+ ROM_SYSTEM_BIOS(0, "basic", "BASIC")
+ ROMX_LOAD("mpf1b.u6", 0x0000, 0x1000, CRC(28b06dac) SHA1(99cfbab739d71a914c39302d384d77bddc4b705b), ROM_BIOS(0))
+ ROMX_LOAD("unknown.u7", 0x2000, 0x1000, CRC(d276ed6b) SHA1(a45fb98961be5e5396988498c6ed589a35398dcf), ROM_BIOS(0)) // TODO: this was previously labelled as BASIC, it's not and is unknown.
+ ROM_SYSTEM_BIOS(1, "olsl1", "OLS-L1")
+ ROMX_LOAD("ols_l1.u6", 0x0000, 0x1000, CRC(b60249ce) SHA1(78e0e8874d1497fabfdd6378266d041175e3797f), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(2, "olsl2", "OLS-L2")
+ ROMX_LOAD("ols_l1-3.u6", 0x0000, 0x1000, CRC(2f038b4b) SHA1(58ba895d2683d26d48da36afdcee9f1dae2f7b7c), ROM_BIOS(2))
+ ROMX_LOAD("ols_l2.u7", 0x2000, 0x1000, CRC(77e51dde) SHA1(45d2c4b520291d5a346a0c3567bcb4b4406675f9), ROM_BIOS(2))
+ROM_END
+
+ROM_START( cs113 )
+ ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
+ ROM_LOAD("cs113.bin", 0x0000, 0x2000, CRC(d293a83b) SHA1(890e8b478e38fed6326b4151bf68c587f82f6a94))
ROM_END
-ROM_START( mpf1p )
- ROM_REGION( 0x10000, Z80_TAG, 0 )
- ROM_LOAD( "mpf1pmon.bin", 0x0000, 0x2000, BAD_DUMP CRC(91ace7d3) SHA1(22e3c16a81ac09f37741ad1b526a4456b2ba9493) ) // A9 stuck low when dumped
- ROM_LOAD( "prt-mpf-ip.u5", 0x6000, 0x1000, CRC(4dd2a4eb) SHA1(6a3e7daa7834d67fd572261ed4a9a62c4594fe3f) )
+ROM_START( mt80z )
+ ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
+ ROM_LOAD("fox.u6", 0x0000, 0x0800, CRC(298ffc59) SHA1(26d144aa63581407dd2f14437646afd807d2bb34))
ROM_END
-/* System Drivers */
+} // anonymous namespace
-void mpf1_state::init_mpf1()
-{
- m_program = &m_maincpu->space(AS_PROGRAM);
-}
-COMP( 1979, mpf1, 0, 0, mpf1, mpf1, mpf1_state, init_mpf1, "Multitech", "Micro Professor 1", 0 )
-COMP( 1979, mpf1b, mpf1, 0, mpf1b,mpf1b, mpf1_state, init_mpf1, "Multitech", "Micro Professor 1B", 0 )
-COMP( 1982, mpf1p, mpf1, 0, mpf1p,mpf1b, mpf1_state, init_mpf1, "Multitech", "Micro Professor 1 Plus", MACHINE_NOT_WORKING )
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
+COMP( 1981, mpf1, 0, 0, mpf1, mpf1, mpf1_state, empty_init, "Multitech", "Micro-Professor 1", 0 )
+COMP( 1982, mpf1b, mpf1, 0, mpf1b, mpf1b, mpf1_state, empty_init, "Multitech", "Micro-Professor 1B", 0 )
+COMP( 198?, cs113, 0, 0, mpf1, mpf1, mpf1_state, empty_init, "Sciento b.v.", "Robot Training Arm CS-113", MACHINE_NOT_WORKING )
+COMP( 1982, mt80z, mpf1, 0, mt80z, mt80z, mpf1_state, empty_init, "E&L Instruments", "MT-80Z", 0 )
diff --git a/src/mame/multitech/mpf1.h b/src/mame/multitech/mpf1.h
deleted file mode 100644
index 72e6cfea8e6..00000000000
--- a/src/mame/multitech/mpf1.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Wilbert Pol, Curt Coder
-#ifndef MAME_MULTITECH_MPF1_H
-#define MAME_MULTITECH_MPF1_H
-
-#pragma once
-
-
-#include "machine/spchrom.h"
-#include "cpu/z80/z80.h"
-#include "machine/z80daisy.h"
-#include "imagedev/cassette.h"
-#include "machine/i8255.h"
-#include "machine/timer.h"
-#include "machine/z80ctc.h"
-#include "machine/z80pio.h"
-#include "sound/spkrdev.h"
-#include "sound/tms5220.h"
-
-#define Z80_TAG "u1"
-#define Z80CTC_TAG "u11"
-#define Z80PIO_TAG "u10"
-#define I8255A_TAG "u14"
-#define TMS5220_TAG "tms5220"
-
-class mpf1_state : public driver_device
-{
-public:
- mpf1_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, Z80_TAG),
- m_ctc(*this, Z80CTC_TAG),
- m_speaker(*this, "speaker"),
- m_cassette(*this, "cassette"),
- m_pc(*this, "PC%u", 0U),
- m_special(*this, "SPECIAL"),
- m_digits(*this, "digit%u", 0U),
- m_leds(*this, "led%u", 0U)
- { }
-
- void mpf1p(machine_config &config);
- void mpf1b(machine_config &config);
- void mpf1(machine_config &config);
-
- void init_mpf1();
-
- DECLARE_INPUT_CHANGED_MEMBER( trigger_nmi );
- DECLARE_INPUT_CHANGED_MEMBER( trigger_irq );
- DECLARE_INPUT_CHANGED_MEMBER( trigger_res );
-
-private:
- required_device<z80_device> m_maincpu;
- required_device<z80ctc_device> m_ctc;
- required_device<speaker_sound_device> m_speaker;
- required_device<cassette_image_device> m_cassette;
- required_ioport_array<6> m_pc;
- required_ioport m_special;
- output_finder<6> m_digits;
- output_finder<2> m_leds;
-
- virtual void machine_start() override;
- virtual void machine_reset() override;
-
- uint8_t step_r(offs_t offset);
- uint8_t ppi_pa_r();
- void ppi_pb_w(uint8_t data);
- void ppi_pc_w(uint8_t data);
-
- int m_break = 0;
- int m_m1 = 0;
-
- uint8_t m_lednum = 0;
-
- emu_timer *m_led_refresh_timer = nullptr;
- address_space *m_program = nullptr;
-
- TIMER_CALLBACK_MEMBER(led_refresh);
- TIMER_DEVICE_CALLBACK_MEMBER(check_halt_callback);
- void mpf1_io_map(address_map &map);
- void mpf1_map(address_map &map);
- void mpf1_step(address_map &map);
- void mpf1b_io_map(address_map &map);
- void mpf1b_map(address_map &map);
- void mpf1p_io_map(address_map &map);
- void mpf1p_map(address_map &map);
-};
-
-#endif // MAME_MULTITECH_MPF1_H
diff --git a/src/mame/multitech/mpf1p.cpp b/src/mame/multitech/mpf1p.cpp
new file mode 100644
index 00000000000..e8e1c061364
--- /dev/null
+++ b/src/mame/multitech/mpf1p.cpp
@@ -0,0 +1,396 @@
+// license:BSD-3-Clause
+// copyright-holders:Nigel Barnes
+/************************************************\
+* Multitech Micro Professor 1 Plus *
+* *
+* CPU: Z80 @ 1.79 MHz *
+* ROM: 8-kilobyte ROM monitor *
+* RAM: 4 kilobytes *
+* Input: 49 key keyboard *
+* Storage: Cassette tape *
+* Video: 20x 16-segment LED display *
+* Sound: Speaker *
+\************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "machine/i8255.h"
+#include "machine/timer.h"
+#include "sound/spkrdev.h"
+
+#include "bus/generic/carts.h"
+#include "bus/generic/slot.h"
+#include "bus/mpf1/slot.h"
+#include "imagedev/cassette.h"
+
+#include "softlist_dev.h"
+#include "speaker.h"
+
+#include "mpf1p.lh"
+
+
+namespace {
+
+class mpf1p_state : public driver_device
+{
+public:
+ mpf1p_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_speaker(*this, "speaker")
+ , m_cassette(*this, "cassette")
+ , m_key(*this, "PC%u", 1U)
+ , m_special(*this, "SPECIAL")
+ , m_digits(*this, "digit%u", 0U)
+ , m_leds(*this, "led%u", 0U)
+ { }
+
+ void mpf1p(machine_config &config);
+
+ DECLARE_INPUT_CHANGED_MEMBER( trigger_res );
+
+protected:
+ virtual void machine_start() override;
+
+private:
+ required_device<z80_device> m_maincpu;
+ required_device<speaker_sound_device> m_speaker;
+ required_device<cassette_image_device> m_cassette;
+ required_ioport_array<20> m_key;
+ required_ioport m_special;
+ output_finder<20> m_digits;
+ output_finder<2> m_leds;
+
+ void mpf1_step(address_map &map);
+ void mpf1p_io_map(address_map &map);
+ void mpf1p_map(address_map &map);
+
+ uint8_t step_r(offs_t offset);
+
+ uint8_t ppi1_pc_r();
+ void ppi1_pa_w(uint8_t data);
+ void ppi1_pb_w(uint8_t data);
+ void ppi1_pc_w(uint8_t data);
+
+ uint8_t ppi2_pc_r();
+ void ppi2_pa_w(uint8_t data);
+ void ppi2_pb_w(uint8_t data);
+ void ppi2_pc_w(uint8_t data);
+
+ int m_break = 0;
+ int m_m1 = 0;
+
+ uint32_t m_lednum = 0;
+ uint16_t m_led_data = 0;
+
+ void led_refresh(uint16_t data);
+};
+
+
+void mpf1p_state::mpf1p_map(address_map &map)
+{
+ map.unmap_value_high();
+ map(0x0000, 0x1fff).rom().region("rom_u2", 0);
+ map(0x2000, 0x3fff).r("rom_u3", FUNC(generic_slot_device::read_rom));
+ map(0xf000, 0xffff).ram();
+}
+
+void mpf1p_state::mpf1_step(address_map &map)
+{
+ map(0x0000, 0xffff).r(FUNC(mpf1p_state::step_r));
+}
+
+void mpf1p_state::mpf1p_io_map(address_map &map)
+{
+ map.unmap_value_high();
+ map.global_mask(0xff);
+ map(0x80, 0x83).mirror(0x0c).rw("ppi_1", FUNC(i8255_device::read), FUNC(i8255_device::write));
+ map(0x90, 0x93).mirror(0x0c).rw("ppi_2", FUNC(i8255_device::read), FUNC(i8255_device::write));
+}
+
+
+INPUT_CHANGED_MEMBER( mpf1p_state::trigger_res )
+{
+ m_maincpu->set_input_line(INPUT_LINE_RESET, newval ? CLEAR_LINE : ASSERT_LINE);
+}
+
+static INPUT_PORTS_START( mpf1p )
+ PORT_START("PC1")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC3")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC4")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC5")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC6")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC7")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC8")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('^')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC9")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('@')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC10")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('*')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(':') PORT_CHAR(';')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC11")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC12")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC13")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC14")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC15")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC16")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC17")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC18")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('-')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC19")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('=')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("PC20")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('+')
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('?') PORT_CHAR('/')
+ PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("SPECIAL")
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL)
+ PORT_BIT( 0xcf, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ PORT_START("RESET")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RESET") PORT_CODE(KEYCODE_F3) PORT_CHANGED_MEMBER(DEVICE_SELF, mpf1p_state, trigger_res, 0)
+INPUT_PORTS_END
+
+
+void mpf1p_state::led_refresh(uint16_t data)
+{
+ for (int digit = 0; digit < 20; digit++)
+ {
+ if (!BIT(m_lednum, digit))
+ m_digits[digit] = data ^ 0xffff;
+ }
+}
+
+
+uint8_t mpf1p_state::ppi1_pc_r()
+{
+ uint8_t data = 0xff;
+
+ // bit 4 and 5, shift and control keys
+ data &= m_special->read();
+
+ return data;
+}
+
+void mpf1p_state::ppi1_pa_w(uint8_t data)
+{
+ m_lednum = (m_lednum & 0xffffff00) | data;
+
+ led_refresh(m_led_data);
+}
+
+void mpf1p_state::ppi1_pb_w(uint8_t data)
+{
+ m_lednum = (m_lednum & 0xffff00ff) | (data << 8);
+
+ led_refresh(m_led_data);
+}
+
+void mpf1p_state::ppi1_pc_w(uint8_t data)
+{
+ m_lednum = (m_lednum & 0xfff0ffff) | (data << 16);
+
+ led_refresh(m_led_data);
+}
+
+uint8_t mpf1p_state::ppi2_pc_r()
+{
+ uint8_t data = 0xf7;
+
+ // bit 0 to 2, keyboard rows 0 to 20
+ for (int row = 0; row < 20; row++)
+ if (!BIT(m_lednum, row))
+ data &= m_key[row]->read();
+
+ // bit 3, tape input
+ data |= (m_cassette->input() > 0) ? 0x08 : 0x00;
+
+ return data;
+}
+
+void mpf1p_state::ppi2_pa_w(uint8_t data)
+{
+ m_led_data = (m_led_data & 0xff00) | data;
+}
+
+void mpf1p_state::ppi2_pb_w(uint8_t data)
+{
+ // swap bits around for the 14-segment emulation
+ data = bitswap<8>(data, 7, 6, 4, 2, 3, 5, 1, 0);
+
+ m_led_data = (m_led_data & 0x00ff) | (data << 8);
+}
+
+void mpf1p_state::ppi2_pc_w(uint8_t data)
+{
+ // bit 4, monitor break control
+ m_break = BIT(data, 4);
+
+ if (m_break)
+ {
+ m_m1 = 0;
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+ }
+
+ // bit 5, tape output, tone and led
+ m_leds[0] = !BIT(data, 5);
+ m_speaker->level_w(BIT(data, 5));
+ m_cassette->output(BIT(data, 5) ? 1.0 : -1.0);
+}
+
+
+uint8_t mpf1p_state::step_r(offs_t offset)
+{
+ if (!m_break)
+ {
+ m_m1++;
+
+ if (m_m1 == 5)
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+ }
+
+ return m_maincpu->space(AS_PROGRAM).read_byte(offset);
+}
+
+
+void mpf1p_state::machine_start()
+{
+ m_digits.resolve();
+ m_leds.resolve();
+
+ // register for state saving */
+ save_item(NAME(m_break));
+ save_item(NAME(m_m1));
+ save_item(NAME(m_lednum));
+}
+
+
+void mpf1p_state::mpf1p(machine_config &config)
+{
+ Z80(config, m_maincpu, 3.579545_MHz_XTAL/2);
+ m_maincpu->set_addrmap(AS_PROGRAM, &mpf1p_state::mpf1p_map);
+ m_maincpu->set_addrmap(AS_OPCODES, &mpf1p_state::mpf1_step);
+ m_maincpu->set_addrmap(AS_IO, &mpf1p_state::mpf1p_io_map);
+ m_maincpu->halt_cb().set_output("led1");
+
+ config.set_default_layout(layout_mpf1p);
+
+ i8255_device &ppi_1(I8255A(config, "ppi_1"));
+ ppi_1.out_pa_callback().set(FUNC(mpf1p_state::ppi1_pa_w));
+ ppi_1.out_pb_callback().set(FUNC(mpf1p_state::ppi1_pb_w));
+ ppi_1.out_pc_callback().set(FUNC(mpf1p_state::ppi1_pc_w));
+ ppi_1.in_pc_callback().set(FUNC(mpf1p_state::ppi1_pc_r));
+
+ i8255_device &ppi_2(I8255A(config, "ppi_2"));
+ ppi_2.out_pa_callback().set(FUNC(mpf1p_state::ppi2_pa_w));
+ ppi_2.out_pb_callback().set(FUNC(mpf1p_state::ppi2_pb_w));
+ ppi_2.out_pc_callback().set(FUNC(mpf1p_state::ppi2_pc_w));
+ ppi_2.in_pc_callback().set(FUNC(mpf1p_state::ppi2_pc_r));
+
+ CASSETTE(config, m_cassette);
+ m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
+
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 0.25);
+
+ mpf1_exp_device &exp(MPF1_EXP(config, "exp", 3.579545_MHz_XTAL/2, mpf1p_exp_devices, nullptr));
+ exp.set_program_space(m_maincpu, AS_PROGRAM);
+ exp.set_io_space(m_maincpu, AS_IO);
+ exp.int_handler().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
+ exp.nmi_handler().set_inputline(m_maincpu, INPUT_LINE_NMI);
+ exp.wait_handler().set_inputline(m_maincpu, Z80_INPUT_LINE_WAIT);
+
+ GENERIC_SOCKET(config, "rom_u3", generic_linear_slot, "mpf1_rom", "bin,rom");
+
+ SOFTWARE_LIST(config, "rom_ls").set_original("mpf1_rom").set_filter("IP");
+}
+
+} // anonymous namespace
+
+
+ROM_START( mpf1p )
+ ROM_REGION(0x2000, "rom_u2", 0)
+ ROM_LOAD("mpf-1p_v1.1.u2", 0x0000, 0x2000, CRC(8bb241d3) SHA1(a05cf397452fe6a03e1ea9320985654f5910b20f))
+ROM_END
+
+// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
+COMP( 1983, mpf1p, 0, 0, mpf1p, mpf1p, mpf1p_state, empty_init, "Multitech", "Micro-Professor 1 Plus", 0 )