Systems promoted to working

---------------------------
Micro-Professor 1 Plus [Nigel Barnes]

New working clones
------------------
MT-80Z [anonymous]

New systems marked not working
------------------------------
Robot Training Arm CS-113 [anonymous]

multitech/mpf1: Added expansion and ROM U7 slots.
- Added ROM software list.

multitech/mpf1p: Replaced bad dump of monitor ROM.
- Corrected layout to use 14 seg LED's.
- Added keyboard.
- Added expansion and ROM U3 slots.
- Added ROM software list.

bus/mpf1: Added Micro-Professor 1 expansion boards:
- Multitech EPB-MPF (Eprom Programmer Board)
- Multitech EPB-MPF-IBP (Eprom Programmer Board)
- Multitech IOM-MPF-IP (I/O and Memory Board)
- Multitech PRT-MPF (Printer)
- Multitech PRT-MPF-IP (Printer)
- Multitech SGB-MPF (Sound Generation Board)
- Multitech SSB-MPF (Speech Synthesizer Board)
- Multitech TVA-MPF-IP (Video Board)
- Bardehle VIDEO-MPF-I (Video Board)
This commit is contained in:
Nigel Barnes 2024-07-01 22:16:03 +01:00
parent 50805594da
commit bf1822976c
23 changed files with 1947 additions and 319 deletions

View File

@ -1900,6 +1900,32 @@ if (BUSES["JAKKS_GAMEKEY"]~=null) then
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

122
src/devices/bus/mpf1/slot.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

77
src/mame/layout/mt80z.lay Normal file
View File

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

View File

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

View File

@ -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 )
INPUT_CHANGED_MEMBER( mpf1_state::trigger_special )
{
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 )
{
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);
mpf1(config);
/* 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));
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);
mpf1b(config);
/* video hardware */
config.set_default_layout(layout_mpf1p);
config.set_default_layout(layout_mt80z);
/* 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));
CASSETTE(config, m_cassette);
m_cassette->set_default_state(CASSETTE_STOPPED | CASSETTE_SPEAKER_ENABLED | CASSETTE_MOTOR_ENABLED);
/* 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( 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( cs113 )
ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
ROM_LOAD("cs113.bin", 0x0000, 0x2000, CRC(d293a83b) SHA1(890e8b478e38fed6326b4151bf68c587f82f6a94))
ROM_END
/* System Drivers */
ROM_START( mt80z )
ROM_REGION(0x3000, "maincpu", ROMREGION_ERASEFF)
ROM_LOAD("fox.u6", 0x0000, 0x0800, CRC(298ffc59) SHA1(26d144aa63581407dd2f14437646afd807d2bb34))
ROM_END
void mpf1_state::init_mpf1()
{
m_program = &m_maincpu->space(AS_PROGRAM);
}
} // anonymous namespace
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 )

View File

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

View File

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