heathzenith/h89.cpp: Add initial support for the H-89 (and H-88 and Z-90) slot bus

- Uses the real I/O decoding PROMs
- Z-37 and MMS 77316 floppy controllers converted to cards
- H-88-3 serial and H-88-5 cassette interfaces converted to cards
- Sigmasoft Sound card converted to a card
This commit is contained in:
arbee 2024-10-26 18:37:26 -04:00
parent fe7e897e56
commit 8353b2bd93
21 changed files with 1961 additions and 398 deletions

View File

@ -5739,3 +5739,29 @@ if (BUSES["PLG1X0"]~=null) then
MAME_DIR .. "src/devices/bus/plg1x0/plg150-ap.h",
}
end
---------------------------------------------------
--
--@src/devices/bus/h89/h89bus.h,BUSES["H89BUS"] = true
---------------------------------------------------
if (BUSES["H89BUS"]~=null) then
files {
MAME_DIR .. "src/devices/bus/heathzenith/h89/cards.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/cards.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h89bus.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h89bus.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h_88_3.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h_88_3.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h_88_5.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/h_88_5.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/mms77316_fdc.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/mms77316_fdc.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/sigmasoft_sound.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/sigmasoft_sound.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/we_pullup.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/we_pullup.h",
MAME_DIR .. "src/devices/bus/heathzenith/h89/z37_fdc.cpp",
MAME_DIR .. "src/devices/bus/heathzenith/h89/z37_fdc.h",
}
end

View File

@ -0,0 +1,44 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
H-89 and Z-90 slot cards
***************************************************************************/
#include "emu.h"
#include "cards.h"
#include "h_88_3.h"
#include "h_88_5.h"
#include "mms77316_fdc.h"
#include "sigmasoft_sound.h"
#include "we_pullup.h"
#include "z37_fdc.h"
void h89_left_cards(device_slot_interface &device)
{
}
void h89_right_cards(device_slot_interface &device)
{
device.option_add("h_88_3", H89BUS_H_88_3);
device.option_add("ha_88_3", H89BUS_HA_88_3);
device.option_add("h_88_5", H89BUS_H_88_5);
device.option_add("ss_snd", H89BUS_SIGMASOFT_SND);
device.option_add("z37fdc", H89BUS_Z37);
}
void h89_right_cards_mms(device_slot_interface &device)
{
h89_right_cards(device);
device.option_add("mms77316", H89BUS_MMS77316);
}
void h89_right_p506_cards(device_slot_interface &device)
{
device.option_add("h_88_3", H89BUS_H_88_3);
device.option_add("ha_88_3", H89BUS_HA_88_3);
device.option_add("ss_snd", H89BUS_SIGMASOFT_SND);
device.option_add("we_pullup", H89BUS_WE_PULLUP);
}

View File

@ -0,0 +1,19 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
Heath/Zenith H-89 and Z-90 cards
***************************************************************************/
#ifndef MAME_BUS_HEATHZENITH_H89_CARDS_H
#define MAME_BUS_HEATHZENITH_H89_CARDS_H
#pragma once
void h89_left_cards(device_slot_interface &device) ATTR_COLD;
void h89_right_cards(device_slot_interface &device) ATTR_COLD;
void h89_right_cards_mms(device_slot_interface &device) ATTR_COLD;
void h89_right_p506_cards(device_slot_interface &device) ATTR_COLD;
#endif // MAME_BUS_HEATHZENITH_H89_CARDS_H

View File

@ -0,0 +1,406 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
h89bus.cpp - Heath/Zenith H-89/Z-90 bus
by R. Belmont
This system is weird. There are 3 left-hand slots. These are intended
for RAM expansion and map into the Z80's memory space. They get A0-A12
and some select signals decoded by a pair of PROMs at U516 and U517.
Notably, these slots don't get the Z80's /RD or /WR signals so actual
working boards for these slots always run a cable or jumper(s) to pick
signals from the motherboard. These slots also have no way to signal
an interrupt.
There are also 3 right-hand slots. These connect to the Z80's I/O address
space and are addressed by a 3-bit offset A0/A1/A2 plus select lines /SER0,
/SER1, /LP1 and /CASS (on P504/P510 and P505/P511), or /FLPY (on P506/P512).
P506/P512 replaces the /LP1 select line with the /FMWE signal which write-enables
the "floppy RAM" at 0x1400. These slots have 3 standard interrupt outputs
/INT3, /INT4, and /INT5.
Notable real-world use cases that we support:
- The Sigmasoft parallel card plugs into a left slot but picks the I/O space
select signal off the motherboard. This plus the left slots' nearly full
set of address lines let it decode the I/O space arbitrarily without
having to change the I/O decoder PROM.
- The MMS 77316 floppy controller has jumpers to replace U553 so that it can
intercept the GPP select line output by the PROM and further decode it.
This decode appears to check if A0/A1/A2 = b010. The partial schematic for
the card doesn't include that logic, but based on what signals it has access
to and the fact that the card doesn't respond to A0/A1/A2 = b010 that seems
to be a reasonable guess.
***************************************************************************/
#include "emu.h"
#include "h89bus.h"
#include <algorithm>
#include <cctype>
DEFINE_DEVICE_TYPE(H89BUS_LEFT_SLOT, h89bus_left_slot_device, "h89bus_lslot", "H-89 left (memory) slot")
h89bus_left_slot_device::h89bus_left_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
h89bus_left_slot_device(mconfig, H89BUS_LEFT_SLOT, tag, owner, clock)
{
}
h89bus_left_slot_device::h89bus_left_slot_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_single_card_slot_interface(mconfig, *this),
m_h89bus(*this, finder_base::DUMMY_TAG),
m_h89bus_slottag(nullptr)
{
}
void h89bus_left_slot_device::device_start()
{
}
void h89bus_left_slot_device::device_resolve_objects()
{
device_h89bus_left_card_interface *dev = get_card_device();
if (dev)
{
dev->set_h89bus_tag(m_h89bus.target(), m_h89bus_slottag);
m_h89bus->add_h89bus_left_card(*dev);
}
}
DEFINE_DEVICE_TYPE(H89BUS_RIGHT_SLOT, h89bus_right_slot_device, "h89bus_rslot", "H-89 right (I/O) slot")
h89bus_right_slot_device::h89bus_right_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
h89bus_right_slot_device(mconfig, H89BUS_RIGHT_SLOT, tag, owner, clock)
{
}
h89bus_right_slot_device::h89bus_right_slot_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_single_card_slot_interface(mconfig, *this),
m_h89bus(*this, finder_base::DUMMY_TAG),
m_h89bus_slottag(nullptr),
m_p506_signals(false)
{
}
void h89bus_right_slot_device::device_start()
{
}
void h89bus_right_slot_device::device_resolve_objects()
{
device_h89bus_right_card_interface *dev = get_card_device();
if (dev)
{
dev->set_h89bus_tag(m_h89bus.target(), m_h89bus_slottag);
dev->set_p506_signalling(m_p506_signals);
m_h89bus->add_h89bus_right_card(*dev);
}
}
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
DEFINE_DEVICE_TYPE(H89BUS, h89bus_device, "h89bus", "H-89/Z-90 bus")
ROM_START(h89bus)
ROM_REGION(0x100, "iodecode", 0)
// H88 I/O decoding
ROM_SYSTEM_BIOS(0, "444-43", "Heath/Zenith stock decoding (444-43)")
ROMX_LOAD("444-43.bin", 0x000000, 0x000100, CRC(3e0315f4) SHA1(11da9a9145de07f1f3bf1270a10e059dff30c693), ROM_BIOS(0))
// H89 I/O decoding
ROM_SYSTEM_BIOS(1, "444-61", "Z-37 decoding (444-61)")
ROMX_LOAD("444-61.bin", 0x000000, 0x000100, CRC(0b3c129f) SHA1(92da6484d1339160400d6bc75578a977c5e4d23e), ROM_BIOS(1))
// MMS (Magnolia Micro Systems) I/O decoding
ROM_SYSTEM_BIOS(2, "444-61c", "MMS decoding (444-61c)")
ROMX_LOAD( "444-61c.bin", 0x000000, 0x000100, CRC(e7122061) SHA1(33c124f44c0f9cb99c9b17ad15411b4bc6407eae), ROM_BIOS(2))
ROM_END
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// h89bus_device - constructor
//-------------------------------------------------
h89bus_device::h89bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
h89bus_device(mconfig, H89BUS, tag, owner, clock)
{
}
h89bus_device::h89bus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, type, tag, owner, clock),
m_program_space(*this, finder_base::DUMMY_TAG, -1),
m_io_space(*this, finder_base::DUMMY_TAG, -1),
m_decode_prom(*this, "iodecode"),
m_out_int3_cb(*this),
m_out_int4_cb(*this),
m_out_int5_cb(*this),
m_out_fdcirq_cb(*this),
m_out_fdcdrq_cb(*this),
m_out_blockirq_cb(*this),
m_out_fmwe_cb(*this),
m_out_wait_cb(*this),
m_in_tlb_cb(*this, 0),
m_in_nmi_cb(*this, 0),
m_in_gpp_cb(*this, 0),
m_out_tlb_cb(*this),
m_out_nmi_cb(*this),
m_out_gpp_cb(*this)
{
}
h89bus_device::~h89bus_device()
{
}
const tiny_rom_entry *h89bus_device::device_rom_region() const
{
return ROM_NAME(h89bus);
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void h89bus_device::device_start()
{
// don't claim I/O below 0x10 for now
m_io_space->install_readwrite_handler(0x0010, 0x00ff, emu::rw_delegate(*this, FUNC(h89bus_device::io_dispatch_r)), emu::rw_delegate(*this, FUNC(h89bus_device::io_dispatch_w)));
}
void h89bus_device::add_h89bus_left_card(device_h89bus_left_card_interface &card)
{
m_left_device_list.emplace_back(card);
}
void h89bus_device::add_h89bus_right_card(device_h89bus_right_card_interface &card)
{
m_right_device_list.emplace_back(card);
}
void h89bus_device::set_io0(int state)
{
m_io0 = state;
}
void h89bus_device::set_io1(int state)
{
m_io1 = state;
}
void h89bus_device::set_mem0(int state)
{
m_mem0 = state;
}
void h89bus_device::set_mem1(int state)
{
m_mem1 = state;
}
int h89bus_device::get_io0()
{
return m_io0;
}
int h89bus_device::get_io1()
{
return m_io1;
}
int h89bus_device::get_mem0()
{
return m_mem0;
}
int h89bus_device::get_mem1()
{
return m_mem1;
}
u8 h89bus_device::read_gpp()
{
return m_in_gpp_cb(0);
}
void h89bus_device::write_gpp(u8 data)
{
m_out_gpp_cb(0, data);
}
u8 h89bus_device::io_dispatch_r(offs_t offset)
{
u8 retval = 0;
offset += 0x10;
if (m_decode_prom[offset] != 0xff)
{
u16 decode = m_decode_prom[offset] ^ 0xff;
if ((decode & H89_GPP) && ((offset & 7) == 2)) return m_in_gpp_cb(offset);
if (decode & H89_NMI) return m_in_nmi_cb(offset);
if (decode & H89_TERM) return m_in_tlb_cb(offset & 7);
if (decode)
{
for (device_h89bus_right_card_interface &entry : m_right_device_list)
{
if (entry.m_p506_signals)
{
// p506 has FLPY but not CASS or LP
retval |= entry.read(decode & ~(H89_CASS | H89_LP), offset & 7);
}
else
{
// p504/p505 have CASS and LP but not FLPY
retval |= entry.read(decode & ~H89_FLPY , offset & 7);
}
}
}
// service left-slot cards that have a motherboard connection to snoop the I/O space
for (device_h89bus_left_card_interface &entry : m_left_device_list)
{
retval |= entry.read(H89_IO, offset);
}
}
return retval;
}
void h89bus_device::io_dispatch_w(offs_t offset, u8 data)
{
offset += 0x10;
if (m_decode_prom[offset] != 0xff)
{
u16 decode = m_decode_prom[offset] ^ 0xff;
if (decode & H89_GPP) m_out_gpp_cb(offset, data);
if (decode & H89_NMI) { m_out_nmi_cb(offset, data); return; }
if (decode & H89_TERM) { m_out_tlb_cb(offset & 7, data); return; }
if (decode)
{
for (device_h89bus_right_card_interface &entry : m_right_device_list)
{
if (entry.m_p506_signals)
{
// p506 has FLPY but not CASS or LP1
entry.write(decode & ~H89_CASS, offset & 7, data);
}
else
{
// p504/p505 have LP1 and CASS but not FLPY
entry.write(decode & ~H89_FLPY, offset & 7, data);
}
}
}
// service left-slot cards that have a motherboard connection to snoop the I/O space
for (device_h89bus_left_card_interface &entry : m_left_device_list)
{
entry.write(H89_IO, offset, data);
}
}
}
void h89bus_device::set_int3_line(int state)
{
m_out_int3_cb(state);
}
void h89bus_device::set_int4_line(int state)
{
m_out_int4_cb(state);
}
void h89bus_device::set_int5_line(int state)
{
m_out_int5_cb(state);
}
void h89bus_device::set_fdcirq_line(int state)
{
m_out_fdcirq_cb(state);
}
void h89bus_device::set_fdcdrq_line(int state)
{
m_out_fdcdrq_cb(state);
}
void h89bus_device::set_blockirq_line(int state)
{
m_out_blockirq_cb(state);
}
void h89bus_device::set_fmwe_line(int state)
{
m_out_fmwe_cb(state);
}
void h89bus_device::set_wait_line(int state)
{
m_out_wait_cb(state);
}
//**************************************************************************
// DEVICE H89BUS CARD INTERFACE
//**************************************************************************
//-------------------------------------------------
// device_h89bus_card_interface - constructor
//-------------------------------------------------
device_h89bus_card_interface::device_h89bus_card_interface(const machine_config &mconfig, device_t &device) :
device_interface(device, "h89bus"),
m_h89bus(nullptr)
{
}
//-------------------------------------------------
// ~device_h89bus_card_interface - destructor
//-------------------------------------------------
device_h89bus_card_interface::~device_h89bus_card_interface()
{
}
void device_h89bus_card_interface::interface_pre_start()
{
if (!m_h89bus)
{
fatalerror("Can't find H-89 bus device\n");
}
}
device_h89bus_left_card_interface::device_h89bus_left_card_interface(const machine_config &mconfig, device_t &device) :
device_h89bus_card_interface(mconfig, device)
{
}
device_h89bus_left_card_interface::~device_h89bus_left_card_interface()
{
}
device_h89bus_right_card_interface::device_h89bus_right_card_interface(const machine_config &mconfig, device_t &device) :
device_h89bus_card_interface(mconfig, device),
m_p506_signals(false)
{
}
device_h89bus_right_card_interface::~device_h89bus_right_card_interface()
{
}

View File

@ -0,0 +1,424 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************
h89.h - Heath/Zenith H-89/Z-90 bus
by R. Belmont
Left-side slots of the H89 Right-side slots of the H89
pin P501 P502 P503 P504 P505 P506 pin
1 GND----------GND----------GND-------------GND----------GND----------GND 1
2 D0-----------D0-----------D0--------------D0-----------D0-----------D0 2
3 D1-----------D1-----------D1--------------D1-----------D1-----------D1 3
4 D2-----------D2-----------D2--------------D2-----------D2-----------D2 4
5 D3-----------D3-----------D3--------------D3-----------D3-----------D3 5
6 D4-----------D4-----------D4--------------D4-----------D4-----------D4 6
7 D5-----------D5-----------D5--------------D5-----------D5-----------D5 7
8 D6-----------D6-----------D6--------------D6-----------D6-----------D6 8
9 D7-----------D7-----------D7--------------D7-----------D7-----------D7 9
10 GND----------GND----------GND-------------GND----------GND----------GND 10
P507 P508 P509 P510 P511 P512
1 VCC----------VCC----------VCC-------------VCC----------VCC----------VCC 1
2 GND----------GND----------GND-------------GND----------GND----------GND 2
3 A0-----------A0-----------A0--------------A0-----------A0-----------A0 3
4 A1-----------A1-----------A1--------------A1-----------A1-----------A1 4
5 A2-----------A2-----------A2--------------A2-----------A2-----------A2 5
6 A3-----------A3-----------A3 /BRD---------/BRD---------/BRD 6
7 A4-----------A4-----------A4 /BWR---------/BWR---------/BWR 7
8 A5-----------A5-----------A5 /WAIT--------/WAIT--------/WAIT 8
9 A6-----------A6-----------A6 /SER0--------/SER0--------/SER0 9
10 A7-----------A7-----------A7 /SER1--------/SER1--------/SER1 10
11 A8-----------A8-----------A8 /LP1---------/LP1 /FLPY 11
12 A9-----------A9-----------A9 /CASS--------/CASS /FMWE 12
13 A10----------A10----------A10 2MHz---------2MHz---------2MHz 13
14 A11----------A11----------A11 1.8Mhz-------1.8MHz-------1.8MHz 14
15 A12----------A12----------A12 /RST---------/RST---------/RST 15
16 MEM 0--------MEM 0--------MEM 0 IO 0---------IO 0---------IO 0 16
17 MEM 1--------MEM 1--------MEM 1 IO 1---------IO 1---------IO 1 17
18 RD5----------RD5----------RD5 /INT3--------/INT3--------/INT3 18
19 RD6----------RD6----------RD6 /INT4--------/INT4--------/INT4 19
20 RD7----------RD7----------RD7 /INT5--------/INT5--------/INT5 20
21 (+12V)-------(+12V)-------(+12V)-----------(+12V)-------(+12V)-------(+12V) 21
22 (-12V)-------(-12V)-------(-12V)-----------(-12V)-------(-12V)-------(-12V) 22
23 (-5V)--------(-5V)--------(-5V)------------(-5V)--------(-5V)--------(-5V) 23
24 (+12V)-------(+12V)-------(+12V)-----------(+12V)-------(+12V)-------(+12V) 24
25 GND----------GND----------GND--------------GND----------GND----------GND 25
Signal Description
------------------------------------------
MEM 0 H Controlled by the GPP port
MEM 1 H Controlled by the GPP port
RD5 Tied to +5V when CPU jumpers configured as recommended by Heath's configuration
guide. Could be jumpered to RAS2 (bank select 2: address 32k-48k) (active low)
RD6 Selects the 16k Expansion memory (active low)
RD7 Reserved for future use, 444-66 PROM nevers sets this low. (active low)
BRD L Board Read (active low)
BWR L Board Write (active low)
WAIT L Wait state (active low)
SER0 L Select line for one of the serial ports on the HA-88-3 (active low)
SER1 L Select line for one of the serial ports on the HA-88-3 (active low)
LP 1 L Select line for one of the serial ports on the HA-88-3 (active low)
CASS L Select line originally for the Cassette Interface board, but when used with later PROM it
selected Floppy controllers/interfaces Z-89-37, Z-89-47, Z-89-67 (active low)
2 MHz CPU Clock, actual speed 2.048 MHz
1.8 MHz Serial Port Clock, actual speed 1.8432 MHz
RST L Reset line (active low)
IO 0 H Controlled by the GPP port
IO 1 H Controlled by the GPP port
INT3 L Interrupt level 3 (active low)
INT4 L Interrupt level 4 (active low)
INT5 L Interrupt level 5 (active low)
FLPY L Select line originally for the H-88-1 hard-sectored controller, but also used for the later
Z-89-47 and Z-89-67 when installed in slot P506/P512 (active low)
FMWE H Floppy Memory Write Enable
***************************************************************************/
#ifndef MAME_BUS_HEATHZENITH_H89_H89BUS_H
#define MAME_BUS_HEATHZENITH_H89_H89BUS_H
#pragma once
#include "emu.h"
#include <functional>
#include <utility>
#include <vector>
#include <string.h>
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class h89bus_device;
// ======================> device_h89bus_card_interface
// class representing interface-specific live H-89/Z-89 bus card
class device_h89bus_card_interface : public device_interface
{
friend class h89bus_device;
public:
// construction/destruction
virtual ~device_h89bus_card_interface();
// inline configuration
void set_h89bus_tag(h89bus_device *h89bus, const char *slottag) { m_h89bus = h89bus; m_h89bus_slottag = slottag; }
protected:
device_h89bus_card_interface(const machine_config &mconfig, device_t &device);
virtual void interface_pre_start() override;
h89bus_device &h89bus() { assert(m_h89bus); return *m_h89bus; }
const char *m_h89bus_slottag;
private:
h89bus_device *m_h89bus;
};
class device_h89bus_left_card_interface : public device_h89bus_card_interface
{
public:
// construction/destruction
virtual ~device_h89bus_left_card_interface();
int get_mem0();
int get_mem1();
virtual u8 read(u8 select_lines, u16 offset) { return 0; };
virtual void write(u8 select_lines, u16 offset, u8 data) {};
protected:
device_h89bus_left_card_interface(const machine_config &mconfig, device_t &device);
private:
};
class device_h89bus_right_card_interface : public device_h89bus_card_interface
{
friend class h89bus_device;
public:
// construction/destruction
virtual ~device_h89bus_right_card_interface();
void set_slot_int3(int state);
void set_slot_int4(int state);
void set_slot_int5(int state);
void set_slot_fdcirq(int state);
void set_slot_fdcdrq(int state);
void set_slot_blockirq(int state);
void set_slot_fmwe(int state);
void set_slot_wait(int state);
int get_io0();
int get_io1();
virtual u8 read(u8 select_lines, u8 offset) { return 0; };
virtual void write(u8 select_lines, u8 offset, u8 data) {};
void set_p506_signalling(bool val)
{
m_p506_signals = val;
}
protected:
device_h89bus_right_card_interface(const machine_config &mconfig, device_t &device);
bool m_p506_signals;
private:
};
class h89bus_left_slot_device : public device_t, public device_single_card_slot_interface<device_h89bus_left_card_interface>
{
public:
// construction/destruction
template <typename T, typename U>
h89bus_left_slot_device(const machine_config &mconfig, T &&tag, device_t *owner, const char *sltag, U &&opts, const char *dflt)
: h89bus_left_slot_device(mconfig, tag, owner, (uint32_t)0)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_h89bus_slot(std::forward<T>(sltag), tag);
}
h89bus_left_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// inline configuration
template <typename T>
void set_h89bus_slot(T &&tag, const char *slottag)
{
m_h89bus.set_tag(std::forward<T>(tag));
m_h89bus_slottag = slottag;
}
protected:
h89bus_left_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device_t implementation
virtual void device_resolve_objects() override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
// configuration
required_device<h89bus_device> m_h89bus;
const char *m_h89bus_slottag;
};
// device type definition
DECLARE_DEVICE_TYPE(H89BUS_LEFT_SLOT, h89bus_left_slot_device)
class h89bus_right_slot_device : public device_t, public device_single_card_slot_interface<device_h89bus_right_card_interface>
{
public:
// construction/destruction
template <typename T, typename U>
h89bus_right_slot_device(const machine_config &mconfig, T &&tag, device_t *owner, const char *sltag, U &&opts, const char *dflt)
: h89bus_right_slot_device(mconfig, tag, owner, (uint32_t)0)
{
option_reset();
opts(*this);
set_default_option(dflt);
set_h89bus_slot(std::forward<T>(sltag), tag);
}
h89bus_right_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// inline configuration
template <typename T>
void set_h89bus_slot(T &&tag, const char *slottag)
{
m_h89bus.set_tag(std::forward<T>(tag));
m_h89bus_slottag = slottag;
}
void set_p506_signalling(bool val)
{
m_p506_signals = val;
}
protected:
h89bus_right_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device_t implementation
virtual void device_resolve_objects() override ATTR_COLD;
virtual void device_start() override ATTR_COLD;
// configuration
required_device<h89bus_device> m_h89bus;
const char *m_h89bus_slottag;
bool m_p506_signals;
};
// device type definition
DECLARE_DEVICE_TYPE(H89BUS_RIGHT_SLOT, h89bus_right_slot_device)
// ======================> h89bus_device
class h89bus_device : public device_t
{
friend class h89bus_left_slot_device;
friend class h89bus_right_slot_device;
friend class device_h89bus_left_card_interface;
friend class device_h89bus_right_card_interface;
public:
// left card select lines
static constexpr u8 H89_RD5 = 0x01;
static constexpr u8 H89_RD6 = 0x02;
static constexpr u8 H89_RD7 = 0x04;
// The Sigmasoft parallel card plugs into the left slot and has a jumper to
// get the memory / I/O select signal from the motherboard. This plus the left
// slots' A0-A13 lines means it can claim arbitrary I/O ranges that the PROM doesn't
// select anything at.
static constexpr u8 H89_IO = 0x80;
// right card and on-board I/O space select lines
static constexpr u8 H89_GPP = 0x01;
static constexpr u8 H89_NMI = 0x02;
static constexpr u8 H89_TERM = 0x04;
static constexpr u8 H89_SER1 = 0x08;
static constexpr u8 H89_SER0 = 0x10;
static constexpr u8 H89_LP = 0x20;
static constexpr u8 H89_CASS = 0x40;
static constexpr u8 H89_FLPY = 0x80;
// construction/destruction
h89bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
~h89bus_device();
void set_io0(int state);
void set_io1(int state);
void set_mem0(int state);
void set_mem1(int state);
int get_io0();
int get_io1();
int get_mem0();
int get_mem1();
// inline configuration
template <typename T> void set_program_space(T &&tag, int spacenum) { m_program_space.set_tag(std::forward<T>(tag), spacenum); }
template <typename T> void set_io_space(T &&tag, int spacenum) { m_io_space.set_tag(std::forward<T>(tag), spacenum); }
auto out_int3_callback() { return m_out_int3_cb.bind(); }
auto out_int4_callback() { return m_out_int4_cb.bind(); }
auto out_int5_callback() { return m_out_int5_cb.bind(); }
auto out_fdcirq_callback() { return m_out_fdcirq_cb.bind(); }
auto out_fdcdrq_callback() { return m_out_fdcdrq_cb.bind(); }
auto out_blockirq_callback() { return m_out_blockirq_cb.bind(); }
auto out_fmwe_callback() { return m_out_fmwe_cb.bind(); }
auto out_wait_callback() { return m_out_wait_cb.bind(); }
auto in_tlb_callback() { return m_in_tlb_cb.bind(); }
auto in_nmi_callback() { return m_in_nmi_cb.bind(); }
auto in_gpp_callback() { return m_in_gpp_cb.bind(); }
auto out_tlb_callback() { return m_out_tlb_cb.bind(); }
auto out_nmi_callback() { return m_out_nmi_cb.bind(); }
auto out_gpp_callback() { return m_out_gpp_cb.bind(); }
protected:
h89bus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device_t implementation
virtual void device_start() override ATTR_COLD;
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
// bus-internal handlers
void add_h89bus_left_card(device_h89bus_left_card_interface &card);
void add_h89bus_right_card(device_h89bus_right_card_interface &card);
void set_int3_line(int state);
void set_int4_line(int state);
void set_int5_line(int state);
void set_fdcirq_line(int state);
void set_fdcdrq_line(int state);
void set_blockirq_line(int state);
void set_fmwe_line(int state);
void set_wait_line(int state);
u8 read_gpp();
void write_gpp(u8 data);
// internal state
required_address_space m_program_space, m_io_space;
required_region_ptr<uint8_t> m_decode_prom;
int m_io0, m_io1, m_mem0, m_mem1;
private:
devcb_write_line m_out_int3_cb, m_out_int4_cb, m_out_int5_cb, m_out_fdcirq_cb, m_out_fdcdrq_cb, m_out_blockirq_cb;
devcb_write_line m_out_fmwe_cb, m_out_wait_cb;
devcb_read8 m_in_tlb_cb, m_in_nmi_cb, m_in_gpp_cb;
devcb_write8 m_out_tlb_cb, m_out_nmi_cb, m_out_gpp_cb;
std::vector<std::reference_wrapper<device_h89bus_left_card_interface>> m_left_device_list;
std::vector<std::reference_wrapper<device_h89bus_right_card_interface>> m_right_device_list;
u8 io_dispatch_r(offs_t offset);
void io_dispatch_w(offs_t offset, u8 data);
};
inline int device_h89bus_left_card_interface::get_mem0()
{
return h89bus().get_mem0();
}
inline int device_h89bus_left_card_interface::get_mem1()
{
return h89bus().get_mem1();
}
inline int device_h89bus_right_card_interface::get_io0()
{
return h89bus().get_io0();
}
inline int device_h89bus_right_card_interface::get_io1()
{
return h89bus().get_io1();
}
inline void device_h89bus_right_card_interface::set_slot_int3(int state)
{
h89bus().set_int3_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_int4(int state)
{
h89bus().set_int4_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_int5(int state)
{
h89bus().set_int5_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_fdcirq(int state)
{
h89bus().set_fdcirq_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_fdcdrq(int state)
{
h89bus().set_fdcdrq_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_blockirq(int state)
{
h89bus().set_blockirq_line(state);
}
inline void device_h89bus_right_card_interface::set_slot_fmwe(int state)
{
if (m_p506_signals)
{
h89bus().set_fmwe_line(state);
}
}
inline void device_h89bus_right_card_interface::set_slot_wait(int state)
{
h89bus().set_wait_line(state);
}
// device type definition
DECLARE_DEVICE_TYPE(H89BUS, h89bus_device)
#endif // MAME_BUS_HEATHZENITH_H89_H89BUS_H

View File

@ -0,0 +1,323 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger, R. Belmont
/***************************************************************************
Heath H-88-3 3-port serial port card
Came with 2 serial ports and space to add an additional serial port.
Heath HA-88-3 3-port serial port card
Came standard with 3 serial ports.
****************************************************************************/
#include "emu.h"
#include "h_88_3.h"
#include "bus/rs232/rs232.h"
#include "machine/ins8250.h"
namespace {
class h_88_3_device : public device_t, public device_h89bus_right_card_interface
{
public:
h_88_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = XTAL(1'843'200).value());
virtual void write(u8 select_lines, u8 offset, u8 data) override;
virtual u8 read(u8 select_lines, u8 offset) override;
protected:
h_88_3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
devcb_write_line::array<4> m_int_cb;
required_device<ins8250_device> m_lp;
required_device<ins8250_device> m_aux;
required_device<ins8250_device> m_modem;
required_ioport m_cfg_lp;
required_ioport m_cfg_aux;
required_ioport m_cfg_modem;
bool m_lp_enabled;
bool m_aux_enabled;
bool m_modem_enabled;
u8 m_lp_int_idx;
u8 m_aux_int_idx;
u8 m_modem_int_idx;
private:
void lp_w(offs_t reg, u8 val);
u8 lp_r(offs_t reg);
void aux_w(offs_t reg, u8 val);
u8 aux_r(offs_t reg);
void modem_w(offs_t reg, u8 val);
u8 modem_r(offs_t reg);
void lp_int(int data);
void aux_int(int data);
void modem_int(int data);
};
class ha_88_3_device : public h_88_3_device
{
public:
ha_88_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = XTAL(1'843'200).value());
protected:
virtual ioport_constructor device_input_ports() const override;
};
h_88_3_device::h_88_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
h_88_3_device(mconfig, H89BUS_H_88_3, tag, owner, clock)
{
}
h_88_3_device::h_88_3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, type, tag, owner, clock),
device_h89bus_right_card_interface(mconfig, *this),
m_int_cb(*this),
m_lp(*this, "lp"),
m_aux(*this, "aux"),
m_modem(*this, "modem"),
m_cfg_lp(*this, "CFG_LP"),
m_cfg_aux(*this, "CFG_AUX"),
m_cfg_modem(*this, "CFG_MODEM")
{
}
u8 h_88_3_device::read(u8 select_lines, u8 offset)
{
if ((select_lines & h89bus_device::H89_SER0) && (m_aux_enabled))
{
return aux_r(offset);
}
if ((select_lines & h89bus_device::H89_SER1) && (m_modem_enabled))
{
return modem_r(offset);
}
if ((select_lines & h89bus_device::H89_LP) && (m_lp_enabled))
{
return lp_r(offset);
}
return 0;
}
void h_88_3_device::write(u8 select_lines, u8 offset, u8 data)
{
if ((select_lines & h89bus_device::H89_SER0) && (m_aux_enabled))
{
aux_w(offset, data);
return;
}
if ((select_lines & h89bus_device::H89_SER1) && (m_modem_enabled))
{
modem_w(offset, data);
return;
}
if ((select_lines & h89bus_device::H89_LP) && (m_lp_enabled))
{
lp_w(offset, data);
return;
}
}
u8 h_88_3_device::lp_r(offs_t reg)
{
return m_lp->ins8250_r(reg);
}
void h_88_3_device::lp_w(offs_t reg, u8 val)
{
m_lp->ins8250_w(reg, val);
}
u8 h_88_3_device::aux_r(offs_t reg)
{
return m_aux->ins8250_r(reg);
}
void h_88_3_device::aux_w(offs_t reg, u8 val)
{
m_aux->ins8250_w(reg, val);
}
u8 h_88_3_device::modem_r(offs_t reg)
{
return m_modem->ins8250_r(reg);
}
void h_88_3_device::modem_w(offs_t reg, u8 val)
{
m_modem->ins8250_w(reg, val);
}
void h_88_3_device::device_start()
{
save_item(NAME(m_lp_enabled));
save_item(NAME(m_lp_int_idx));
save_item(NAME(m_aux_enabled));
save_item(NAME(m_aux_int_idx));
save_item(NAME(m_modem_enabled));
save_item(NAME(m_modem_int_idx));
}
void h_88_3_device::device_reset()
{
ioport_value const cfg_lp(m_cfg_lp->read());
ioport_value const cfg_aux(m_cfg_aux->read());
ioport_value const cfg_modem(m_cfg_modem->read());
m_lp_enabled = bool(BIT(cfg_lp, 0));
m_aux_enabled = bool(BIT(cfg_aux, 0));
m_modem_enabled = bool(BIT(cfg_modem, 0));
// LP Interrupt level
m_lp_int_idx = BIT(cfg_lp, 1, 2);
// AUX Interrupt level
m_aux_int_idx = BIT(cfg_aux, 1, 2);
// MODEM Interrupt level
m_modem_int_idx = BIT(cfg_modem, 1, 2);
}
void h_88_3_device::lp_int(int data)
{
m_int_cb[m_lp_int_idx](data);
}
void h_88_3_device::aux_int(int data)
{
m_int_cb[m_aux_int_idx](data);
}
void h_88_3_device::modem_int(int data)
{
m_int_cb[m_modem_int_idx](data);
}
void h_88_3_device::device_add_mconfig(machine_config &config)
{
// LP DCE 0xE0-0xE7 (340 - 347 octal)
INS8250(config, m_lp, m_clock);
m_lp->out_tx_callback().set("dce1", FUNC(rs232_port_device::write_txd));
m_lp->out_dtr_callback().set("dce1", FUNC(rs232_port_device::write_dtr));
m_lp->out_rts_callback().set("dce1", FUNC(rs232_port_device::write_rts));
m_lp->out_int_callback().set(FUNC(h_88_3_device::lp_int));
rs232_port_device &dce1(RS232_PORT(config, "dce1", default_rs232_devices, "printer"));
dce1.rxd_handler().set(m_lp, FUNC(ins8250_device::rx_w));
dce1.dcd_handler().set(m_lp, FUNC(ins8250_device::dcd_w));
dce1.dsr_handler().set(m_lp, FUNC(ins8250_device::dsr_w));
dce1.cts_handler().set(m_lp, FUNC(ins8250_device::cts_w));
dce1.ri_handler().set(m_lp, FUNC(ins8250_device::ri_w));
// AUX DCE 0xD0-0xD7 (320 - 327 octal)
INS8250(config, m_aux, m_clock);
m_aux->out_tx_callback().set("dce2", FUNC(rs232_port_device::write_txd));
m_aux->out_dtr_callback().set("dce2", FUNC(rs232_port_device::write_dtr));
m_aux->out_rts_callback().set("dce2", FUNC(rs232_port_device::write_rts));
m_aux->out_int_callback().set(FUNC(h_88_3_device::aux_int));
rs232_port_device &dce2(RS232_PORT(config, "dce2", default_rs232_devices, "loopback"));
dce2.rxd_handler().set(m_aux, FUNC(ins8250_device::rx_w));
dce2.dcd_handler().set(m_aux, FUNC(ins8250_device::dcd_w));
dce2.dsr_handler().set(m_aux, FUNC(ins8250_device::dsr_w));
dce2.cts_handler().set(m_aux, FUNC(ins8250_device::cts_w));
dce2.ri_handler().set(m_aux, FUNC(ins8250_device::ri_w));
// Modem DTE 0xD7-0xDF (330 - 337 octal)
INS8250(config, m_modem, m_clock);
m_modem->out_tx_callback().set("dte", FUNC(rs232_port_device::write_txd));
m_modem->out_dtr_callback().set("dte", FUNC(rs232_port_device::write_dtr));
m_modem->out_rts_callback().set("dte", FUNC(rs232_port_device::write_rts));
m_modem->out_int_callback().set(FUNC(h_88_3_device::modem_int));
rs232_port_device &dte(RS232_PORT(config, "dte", default_rs232_devices, "loopback"));
dte.rxd_handler().set(m_modem, FUNC(ins8250_device::rx_w));
dte.dcd_handler().set(m_modem, FUNC(ins8250_device::dcd_w));
dte.dsr_handler().set(m_modem, FUNC(ins8250_device::dsr_w));
dte.cts_handler().set(m_modem, FUNC(ins8250_device::cts_w));
dte.ri_handler().set(m_modem, FUNC(ins8250_device::ri_w));
}
static INPUT_PORTS_START( h_88_3_device )
PORT_START("CFG_LP")
PORT_CONFNAME(0x01, 0x01, "LP - DCE (340 octal) Enabled" )
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, DEF_STR( Yes ))
PORT_CONFNAME(0x06, 0x00, "LP - DCE (340 octal) Interrupt level")
PORT_CONFSETTING( 0x00, DEF_STR( None ))
PORT_CONFSETTING( 0x02, "3")
PORT_CONFSETTING( 0x04, "4")
PORT_CONFSETTING( 0x06, "5")
PORT_START("CFG_AUX")
PORT_CONFNAME(0x01, 0x00, "AUX - DCE (320 octal) Enabled" )
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, DEF_STR( Yes ))
PORT_CONFNAME(0x06, 0x00, "AUX - DCE (320 octal) Interrupt level")
PORT_CONFSETTING( 0x00, DEF_STR( None ))
PORT_CONFSETTING( 0x02, "3")
PORT_CONFSETTING( 0x04, "4")
PORT_CONFSETTING( 0x06, "5")
PORT_START("CFG_MODEM")
PORT_CONFNAME(0x01, 0x01, "MODEM - DTE (330 octal) Enabled" )
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, DEF_STR( Yes ))
PORT_CONFNAME(0x06, 0x00, "MODEM - DTE (330 octal) Interrupt level")
PORT_CONFSETTING( 0x00, DEF_STR( None ))
PORT_CONFSETTING( 0x02, "3")
PORT_CONFSETTING( 0x04, "4")
PORT_CONFSETTING( 0x06, "5")
INPUT_PORTS_END
static INPUT_PORTS_START( ha_88_3_device )
PORT_INCLUDE( h_88_3_device )
PORT_MODIFY("CFG_AUX")
PORT_CONFNAME(0x01, 0x01, "AUX - DCE (320 octal) Enabled" )
PORT_CONFSETTING( 0x00, DEF_STR( No ))
PORT_CONFSETTING( 0x01, DEF_STR( Yes ))
INPUT_PORTS_END
ioport_constructor h_88_3_device::device_input_ports() const
{
return INPUT_PORTS_NAME(h_88_3_device);
}
ioport_constructor ha_88_3_device::device_input_ports() const
{
return INPUT_PORTS_NAME(ha_88_3_device);
}
ha_88_3_device::ha_88_3_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
h_88_3_device(mconfig, H89BUS_HA_88_3, tag, owner, clock)
{
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_H_88_3, device_h89bus_right_card_interface, h_88_3_device, "h89h_88_3", "Heath H-88-3 3-port Serial Board");
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_HA_88_3, device_h89bus_right_card_interface, ha_88_3_device, "h89ha_88_3", "Heath HA-88-3 3-port Serial Board");

View File

@ -0,0 +1,13 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef MAME_BUS_HEATHZENITH_H89_H_88_3_H
#define MAME_BUS_HEATHZENITH_H89_H_88_3_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_H_88_3, device_h89bus_right_card_interface)
DECLARE_DEVICE_TYPE(H89BUS_HA_88_3, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_H_88_3_H

View File

@ -11,17 +11,22 @@
#include "emu.h"
#include "h_88_cass.h"
#include "h_88_5.h"
#include "formats/h8_cas.h"
#include "imagedev/cassette.h"
#include "machine/clock.h"
#include "machine/i8251.h"
#include "machine/timer.h"
#include "softlist_dev.h"
#include "speaker.h"
#define LOG_REG (1U << 1)
#define LOG_LINES (1U << 2)
#define LOG_CASS (1U << 3)
#define LOG_FUNC (1U << 4)
//#define VERBOSE (0xff)
#define VERBOSE (0xff)
#include "logmacro.h"
@ -36,33 +41,70 @@
#define FUNCNAME __PRETTY_FUNCTION__
#endif
DEFINE_DEVICE_TYPE(HEATH_H88_CASS, heath_h_88_cass_device, "heath_h_88_cass_device", "Heath H-88-5 Cassette Interface");
namespace {
heath_h_88_cass_device::heath_h_88_cass_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, HEATH_H88_CASS, tag, owner, 0),
class h_88_5_device : public device_t, public device_h89bus_right_card_interface
{
public:
h_88_5_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual void write(u8 select_lines, u8 offset, u8 data) override;
virtual u8 read(u8 select_lines, u8 offset) override;
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void uart_rts(u8 data);
void uart_tx_empty(u8 data);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_r);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_w);
required_device<i8251_device> m_uart;
required_device<cassette_image_device> m_cass_player;
required_device<cassette_image_device> m_cass_recorder;
u8 m_cass_data[4];
bool m_cassbit;
bool m_cassold;
};
h_88_5_device::h_88_5_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, H89BUS_H_88_5, tag, owner, 0),
device_h89bus_right_card_interface(mconfig, *this),
m_uart(*this, "uart"),
m_cass_player(*this, "cassette_player"),
m_cass_recorder(*this, "cassette_recorder")
{
}
void heath_h_88_cass_device::write(offs_t reg, u8 val)
void h_88_5_device::write(u8 select_lines, u8 reg, u8 val)
{
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
if (select_lines & h89bus_device::H89_CASS)
{
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
m_uart->write(reg, val);
m_uart->write(reg, val);
}
}
u8 heath_h_88_cass_device::read(offs_t reg)
u8 h_88_5_device::read(u8 select_lines, u8 reg)
{
u8 val = m_uart->read(reg);
if (select_lines & h89bus_device::H89_CASS)
{
u8 val = m_uart->read(reg);
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
return val;
return val;
}
return 0;
}
TIMER_DEVICE_CALLBACK_MEMBER(heath_h_88_cass_device::kansas_w)
TIMER_DEVICE_CALLBACK_MEMBER(h_88_5_device::kansas_w)
{
m_cass_data[3]++;
@ -81,7 +123,7 @@ TIMER_DEVICE_CALLBACK_MEMBER(heath_h_88_cass_device::kansas_w)
m_cass_recorder->output(BIT(m_cass_data[3], bit_pos) ? -1.0 : +1.0);
}
TIMER_DEVICE_CALLBACK_MEMBER(heath_h_88_cass_device::kansas_r)
TIMER_DEVICE_CALLBACK_MEMBER(h_88_5_device::kansas_r)
{
// cassette - turn 1200/2400Hz to a bit
m_cass_data[1]++;
@ -98,28 +140,28 @@ TIMER_DEVICE_CALLBACK_MEMBER(heath_h_88_cass_device::kansas_r)
}
}
void heath_h_88_cass_device::uart_rts(u8 data)
void h_88_5_device::uart_rts(u8 data)
{
LOGLINES("%s: data: %d\n", FUNCNAME, data);
m_cass_player->change_state(bool(data) ? CASSETTE_STOPPED : CASSETTE_PLAY, CASSETTE_MASK_UISTATE);
}
void heath_h_88_cass_device::uart_tx_empty(u8 data)
void h_88_5_device::uart_tx_empty(u8 data)
{
LOGLINES("%s: data: %d\n", FUNCNAME, data);
m_cass_recorder->change_state(bool(data) ? CASSETTE_STOPPED : CASSETTE_RECORD, CASSETTE_MASK_UISTATE);
}
void heath_h_88_cass_device::device_start()
void h_88_5_device::device_start()
{
save_item(NAME(m_cass_data));
save_item(NAME(m_cassbit));
save_item(NAME(m_cassold));
}
void heath_h_88_cass_device::device_reset()
void h_88_5_device::device_reset()
{
LOGFUNC("%s\n", FUNCNAME);
@ -136,12 +178,12 @@ void heath_h_88_cass_device::device_reset()
m_uart->write_rxd(0);
}
void heath_h_88_cass_device::device_add_mconfig(machine_config &config)
void h_88_5_device::device_add_mconfig(machine_config &config)
{
I8251(config, m_uart, 0);
m_uart->txd_handler().set([this] (bool state) { m_cassbit = state; });
m_uart->rts_handler().set(FUNC(heath_h_88_cass_device::uart_rts));
m_uart->txempty_handler().set(FUNC(heath_h_88_cass_device::uart_tx_empty));
m_uart->rts_handler().set(FUNC(h_88_5_device::uart_rts));
m_uart->txempty_handler().set(FUNC(h_88_5_device::uart_tx_empty));
clock_device &cassette_clock(CLOCK(config, "cassette_clock", 4800));
cassette_clock.signal_handler().set(m_uart, FUNC(i8251_device::write_txc));
@ -161,6 +203,12 @@ void heath_h_88_cass_device::device_add_mconfig(machine_config &config)
m_cass_recorder->add_route(ALL_OUTPUTS, "mono", 0.15);
m_cass_recorder->set_interface("h88_cass_recorder");
TIMER(config, "kansas_w").configure_periodic(FUNC(heath_h_88_cass_device::kansas_w), attotime::from_hz(4800));
TIMER(config, "kansas_r").configure_periodic(FUNC(heath_h_88_cass_device::kansas_r), attotime::from_hz(40000));
SOFTWARE_LIST(config, "cass_list").set_original("h88_cass");
TIMER(config, "kansas_w").configure_periodic(FUNC(h_88_5_device::kansas_w), attotime::from_hz(4800));
TIMER(config, "kansas_r").configure_periodic(FUNC(h_88_5_device::kansas_r), attotime::from_hz(40000));
}
}
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_H_88_5, device_h89bus_right_card_interface, h_88_5_device, "h89h_88_5", "Heath H-88-5 Cassette Interface Board");

View File

@ -0,0 +1,12 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef MAME_BUS_HEATHZENITH_H89_H_88_5_H
#define MAME_BUS_HEATHZENITH_H89_H_88_5_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_H_88_5, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_H_88_5_H

View File

@ -14,6 +14,9 @@
#include "mms77316_fdc.h"
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
#define LOG_REG (1U << 1) // Shows register setup
#define LOG_LINES (1U << 2) // Show control lines
#define LOG_DRIVE (1U << 3) // Show drive select
@ -40,13 +43,58 @@
#define FUNCNAME __PRETTY_FUNCTION__
#endif
DEFINE_DEVICE_TYPE(MMS77316_FDC, mms77316_fdc_device, "mms77316_fdc", "Magnolia MicroSystems 77316 Soft-sectored Controller");
namespace {
class mms77316_fdc_device : public device_t, public device_h89bus_right_card_interface
{
public:
mms77316_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual void write(u8 select_lines, u8 offset, u8 data) override;
virtual u8 read(u8 select_lines, u8 offset) override;
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void ctrl_w(u8 val);
void data_w(u8 val);
u8 data_r();
void set_irq(int state);
void set_drq(int state);
// Burst mode was required for a 2 MHz Z80 to handle 8" DD data rates.
// The typical irq/drq was too slow, this utilizes wait states to read the
// WD1797 data port once the drq line is high.
inline bool burst_mode_r() { return !m_drq_allowed; }
private:
required_device<fd1797_device> m_fdc;
required_device_array<floppy_connector, 8> m_floppies;
bool m_irq_allowed;
bool m_drq_allowed;
bool m_irq;
bool m_drq;
u32 m_drq_count;
/// Bits set in cmd_ControlPort_c
static constexpr u8 ctrl_525DriveSel_c = 2;
static constexpr u8 ctrl_EnableIntReq_c = 3;
static constexpr u8 ctrl_EnableDrqInt_c = 5;
static constexpr u8 ctrl_SetMFMRecording_c = 6;
static constexpr XTAL MASTER_CLOCK = XTAL(8'000'000);
static constexpr XTAL FIVE_IN_CLOCK = MASTER_CLOCK / 8;
static constexpr XTAL EIGHT_IN_CLOCK = MASTER_CLOCK / 4;
};
mms77316_fdc_device::mms77316_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, MMS77316_FDC, tag, owner, 0),
m_irq_cb(*this),
m_drq_cb(*this),
m_wait_cb(*this),
device_t(mconfig, H89BUS_MMS77316, tag, owner, 0),
device_h89bus_right_card_interface(mconfig, *this),
m_fdc(*this, "mms_fdc"),
m_floppies(*this, "mms_fdc:%u", 0U)
{
@ -69,13 +117,13 @@ void mms77316_fdc_device::ctrl_w(u8 val)
if (m_irq_allowed)
{
m_irq_cb(m_irq);
m_drq_cb(m_drq);
set_slot_fdcirq(m_irq);
set_slot_fdcdrq(m_drq);
}
else
{
m_irq_cb(CLEAR_LINE);
m_drq_cb(CLEAR_LINE);
set_slot_fdcirq(CLEAR_LINE);
set_slot_fdcdrq(CLEAR_LINE);
}
LOGDRIVE("%s: floppydrive: %d, 5.25 in: %d\n", FUNCNAME, floppy_drive, five_in_drv);
@ -107,16 +155,21 @@ void mms77316_fdc_device::data_w(u8 val)
{
LOGBURST("%s: burst_mode_r\n", FUNCNAME);
m_wait_cb(ASSERT_LINE);
set_slot_wait(ASSERT_LINE);
return;
}
m_fdc->data_w(val);
}
void mms77316_fdc_device::write(offs_t reg, u8 val)
void mms77316_fdc_device::write(u8 select_lines, u8 reg, u8 val)
{
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
if (!(select_lines & h89bus_device::H89_GPP))
{
return;
}
if (reg != 2) LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
switch (reg)
{
@ -153,7 +206,7 @@ u8 mms77316_fdc_device::data_r()
if (!machine().side_effects_disabled())
{
m_wait_cb(ASSERT_LINE);
set_slot_wait(ASSERT_LINE);
}
}
else
@ -166,8 +219,13 @@ u8 mms77316_fdc_device::data_r()
return data;
}
u8 mms77316_fdc_device::read(offs_t reg)
u8 mms77316_fdc_device::read(u8 select_lines, u8 reg)
{
if (!(select_lines & h89bus_device::H89_GPP))
{
return 0;
}
// default return for the h89
u8 value = 0xff;
@ -215,9 +273,9 @@ void mms77316_fdc_device::device_reset()
m_irq = false;
m_drq_count = 0;
m_irq_cb(CLEAR_LINE);
m_drq_cb(CLEAR_LINE);
m_wait_cb(CLEAR_LINE);
set_slot_fdcirq(CLEAR_LINE);
set_slot_fdcdrq(CLEAR_LINE);
set_slot_wait(CLEAR_LINE);
for (int i = 0; i < 4; i++)
{
@ -293,11 +351,11 @@ void mms77316_fdc_device::set_irq(int state)
if (m_irq)
{
m_wait_cb(CLEAR_LINE);
set_slot_wait(CLEAR_LINE);
m_drq_count = 0;
}
m_irq_cb(m_irq_allowed ? m_irq : CLEAR_LINE);
set_slot_fdcirq(m_irq_allowed ? m_irq : CLEAR_LINE);
}
void mms77316_fdc_device::set_drq(int state)
@ -312,13 +370,17 @@ void mms77316_fdc_device::set_drq(int state)
if (m_drq)
{
m_wait_cb(CLEAR_LINE);
set_slot_wait(CLEAR_LINE);
}
m_drq_cb(m_drq_count == 0 ? m_drq : CLEAR_LINE);
set_slot_fdcdrq(m_drq_count == 0 ? m_drq : CLEAR_LINE);
}
else
{
m_drq_cb(m_drq_allowed ? m_drq : CLEAR_LINE);
set_slot_fdcdrq(m_drq_allowed ? m_drq : CLEAR_LINE);
}
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_MMS77316, device_h89bus_right_card_interface, mms77316_fdc_device, "mms77316_fdc", "Magnolia MicroSystems 77316 Soft-sectored Controller");

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Magnolia Microsystems 77316 soft-sectored floppy controller
****************************************************************************/
#ifndef MAME_BUS_HEATHZENITH_H89_MMS77316_FDC_H
#define MAME_BUS_HEATHZENITH_H89_MMS77316_FDC_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_MMS77316, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_MMS77316_FDC_H

View File

@ -0,0 +1,216 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
SigmaSoft Sound Effects Board
****************************************************************************/
#include "emu.h"
#include "sound/ay8910.h"
#include "speaker.h"
#include "sigmasoft_sound.h"
//
// Logging defines
//
#define LOG_REG (1U << 1) // Shows register setup
#define LOG_FUNC (1U << 2) // Function calls
#define LOG_ERR (1U << 3)
#define VERBOSE (0)
#include "logmacro.h"
#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__)
#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
#define LOGERR(...) LOGMASKED(LOG_ERR, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
#else
#define FUNCNAME __PRETTY_FUNCTION__
#endif
namespace {
class h89bus_sigmasoft_snd_device : public device_t, public device_h89bus_right_card_interface
{
public:
h89bus_sigmasoft_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual u8 read(u8 select_lines, u8 reg) override;
virtual void write(u8 select_lines, u8 reg, u8 val) override;
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
u8 read_joystick();
u8 transform_joystick_input(u8 raw_value);
private:
required_device<ay8910_device> m_ay8910;
required_ioport m_joystick1, m_joystick2;
required_ioport m_config;
u8 port_selection;
};
//**************************************************************************
// INPUT PORTS
//**************************************************************************
static INPUT_PORTS_START( sigma_sound )
PORT_START("joystick_p1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_START("joystick_p2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_START("CONFIG")
PORT_CONFNAME(0x03, 0x01, "Port selection")
PORT_CONFSETTING( 0x00, "Disabled")
PORT_CONFSETTING( 0x01, "AUX - 320 Octal (0xD0)")
PORT_CONFSETTING( 0x02, "MODEM - 330 Octal (0xD8)")
PORT_CONFSETTING( 0x03, "LP - 340 Octal (0xE0)")
INPUT_PORTS_END
h89bus_sigmasoft_snd_device::h89bus_sigmasoft_snd_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, H89BUS_SIGMASOFT_SND, tag, owner, clock),
device_h89bus_right_card_interface(mconfig, *this),
m_ay8910(*this, "ay8910"),
m_joystick1(*this, "joystick_p1"),
m_joystick2(*this, "joystick_p2"),
m_config(*this, "CONFIG")
{
}
void h89bus_sigmasoft_snd_device::write(u8 select_lines, u8 reg, u8 val)
{
// we respond to the SER0 decode
if (!(select_lines & port_selection))
{
return;
}
LOGFUNC("%s: reg: %d val: %d\n", FUNCNAME, reg, val);
switch (reg)
{
case 0:
m_ay8910->data_w(val);
break;
case 1:
m_ay8910->address_w(val);
break;
default:
LOGERR("%s: unexpected port write: %d - 0x%02x]n", FUNCNAME, reg, val);
}
}
u8 h89bus_sigmasoft_snd_device::read(u8 select_lines, u8 reg)
{
if (!(select_lines & port_selection))
{
return 0;
}
u8 value = 0x00;
switch (reg)
{
case 0:
value = m_ay8910->data_r();
break;
case 1:
value = this->read_joystick();
break;
default:
LOGERR("%s: unexpected port read: %d\n", FUNCNAME, reg);
}
LOGFUNC("%s: reg: %d val: %d\n", FUNCNAME, reg, value);
return value;
}
u8 h89bus_sigmasoft_snd_device::transform_joystick_input(u8 raw_value)
{
// when button on joystick is pressed, return 0xf
if (raw_value & 0x10)
{
return 0xf;
}
return raw_value & 0xf;
}
// high nibble is for left joystick, low nibble is for right joystick
// when the button is pressed nibble will be set to 0xf
//
// note: 2 bits may be set if the direction of the joystick is diagonal, such as 0x9 for left & up.
//
u8 h89bus_sigmasoft_snd_device::read_joystick()
{
u8 joy1 = m_joystick1->read();
u8 joy2 = m_joystick2->read();
return this->transform_joystick_input(joy1) << 4 & this->transform_joystick_input(joy2);
}
void h89bus_sigmasoft_snd_device::device_start()
{
}
void h89bus_sigmasoft_snd_device::device_reset()
{
ioport_value const config(m_config->read());
switch (config & 0x03)
{
case 0x00:
port_selection = 0;
break;
case 0x01:
port_selection = h89bus_device::H89_SER0;
break;
case 0x02:
port_selection = h89bus_device::H89_SER1;
break;
case 0x03:
port_selection = h89bus_device::H89_LP;
break;
}
}
ioport_constructor h89bus_sigmasoft_snd_device::device_input_ports() const
{
return INPUT_PORTS_NAME( sigma_sound );
}
void h89bus_sigmasoft_snd_device::device_add_mconfig(machine_config &config)
{
SPEAKER(config, "mono").front_center();
AY8910(config, m_ay8910, XTAL(8'000'000)/4); /* ??? 2.000 MHz */
m_ay8910->add_route(ALL_OUTPUTS, "mono", 0.25);
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_SIGMASOFT_SND, device_h89bus_right_card_interface, h89bus_sigmasoft_snd_device, "h89sigmasnd", "SigmaSoft Sound Effects Board");

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
SigmaSoft Sound Effects Board
****************************************************************************/
#ifndef MAME_BUS_HEATHZENITH_H89_SIGMASOFT_SOUND_H
#define MAME_BUS_HEATHZENITH_H89_SIGMASOFT_SOUND_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_SIGMASOFT_SND, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_SIGMASOFT_SOUND_H

View File

@ -0,0 +1,45 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit Write enable pull
On
****************************************************************************/
#include "emu.h"
#include "we_pullup.h"
namespace {
class h89bus_we_pullup_device : public device_t, public device_h89bus_right_card_interface
{
public:
h89bus_we_pullup_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
};
h89bus_we_pullup_device::h89bus_we_pullup_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, H89BUS_WE_PULLUP, tag, owner, 0),
device_h89bus_right_card_interface(mconfig, *this)
{
}
void h89bus_we_pullup_device::device_start()
{
}
void h89bus_we_pullup_device::device_reset()
{
set_slot_fmwe(ASSERT_LINE);
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_WE_PULLUP, device_h89bus_right_card_interface, h89bus_we_pullup_device, "h89_we_pullup", "Pullup resistor needed when P506 slot is empty");

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit Write Enable Pullup
****************************************************************************/
#ifndef MAME_BUS_HEATHZENITH_H89_WE_PULLUP_H
#define MAME_BUS_HEATHZENITH_H89_WE_PULLUP_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_WE_PULLUP, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_WE_PULLUP_H

View File

@ -10,6 +10,9 @@
#include "emu.h"
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
#include "z37_fdc.h"
#define LOG_REG (1U << 1) // Shows register setup
@ -32,20 +35,66 @@
#define FUNCNAME __PRETTY_FUNCTION__
#endif
DEFINE_DEVICE_TYPE(HEATH_Z37_FDC, heath_z37_fdc_device, "heath_z37_fdc", "Heath H/Z-37 Soft-sectored Controller");
namespace {
heath_z37_fdc_device::heath_z37_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, HEATH_Z37_FDC, tag, owner, 0),
m_irq_cb(*this),
m_drq_cb(*this),
m_block_interrupt_cb(*this),
class h89bus_z37_device : public device_t, public device_h89bus_right_card_interface
{
public:
h89bus_z37_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
virtual void write(u8 select_lines, u8 offset, u8 data) override;
virtual u8 read(u8 select_lines, u8 offset) override;
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void ctrl_w(u8 val);
void intf_w(u8 val);
void cmd_w(u8 val);
u8 stat_r();
void data_w(u8 val);
u8 data_r();
void set_irq(int state);
void set_drq(int state);
private:
required_device<fd1797_device> m_fdc;
required_device_array<floppy_connector, 4> m_floppies;
bool m_irq_allowed;
bool m_drq_allowed;
bool m_access_track_sector;
/// Bits set in cmd_ControlPort_c - DK.CON
static constexpr u8 ctrl_EnableIntReq_c = 0;
static constexpr u8 ctrl_EnableDrqInt_c = 1;
static constexpr u8 ctrl_SetMFMRecording_c = 2;
static constexpr u8 ctrl_MotorsOn_c = 3;
static constexpr u8 ctrl_Drive_0_c = 4;
static constexpr u8 ctrl_Drive_1_c = 5;
static constexpr u8 ctrl_Drive_2_c = 6;
static constexpr u8 ctrl_Drive_3_c = 7;
/// Bits to set alternate registers on InterfaceControl_c - DK.INT
static constexpr u8 if_SelectSectorTrack_c = 0;
};
h89bus_z37_device::h89bus_z37_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock):
device_t(mconfig, H89BUS_Z37, tag, owner, 0),
device_h89bus_right_card_interface(mconfig, *this),
m_fdc(*this, "z37_fdc"),
m_floppies(*this, "z37_fdc:%u", 0U)
{
}
void heath_z37_fdc_device::ctrl_w(u8 val)
void h89bus_z37_device::ctrl_w(u8 val)
{
bool motor_on = bool(BIT(val, ctrl_MotorsOn_c));
@ -58,12 +107,12 @@ void heath_z37_fdc_device::ctrl_w(u8 val)
if (m_drq_allowed)
{
m_block_interrupt_cb(1);
set_slot_blockirq(1);
}
else
{
m_block_interrupt_cb(0);
m_drq_cb(0);
set_slot_blockirq(0);
set_slot_fdcdrq(0);
}
if (BIT(val, ctrl_Drive_0_c))
@ -102,60 +151,70 @@ void heath_z37_fdc_device::ctrl_w(u8 val)
}
}
void heath_z37_fdc_device::intf_w(u8 val)
void h89bus_z37_device::intf_w(u8 val)
{
m_access_track_sector = bool(BIT(val, if_SelectSectorTrack_c));
LOGREG("access track/sector: %d\n", m_access_track_sector);
}
void heath_z37_fdc_device::cmd_w(u8 val)
void h89bus_z37_device::cmd_w(u8 val)
{
m_access_track_sector ? m_fdc->sector_w(val) : m_fdc->cmd_w(val);
}
u8 heath_z37_fdc_device::stat_r()
u8 h89bus_z37_device::stat_r()
{
return m_access_track_sector ? m_fdc->sector_r() : m_fdc->status_r();
}
void heath_z37_fdc_device::data_w(u8 val)
void h89bus_z37_device::data_w(u8 val)
{
m_access_track_sector ? m_fdc->track_w(val) : m_fdc->data_w(val);
}
u8 heath_z37_fdc_device::data_r()
u8 h89bus_z37_device::data_r()
{
return m_access_track_sector ? m_fdc->track_r() : m_fdc->data_r();
}
void heath_z37_fdc_device::write(offs_t reg, u8 val)
void h89bus_z37_device::write(u8 select_lines, u8 offset, u8 data)
{
LOGFUNC("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
if (!(select_lines & h89bus_device::H89_CASS))
{
return;
}
switch (reg)
LOGFUNC("%s: reg: %d val: 0x%02x\n", FUNCNAME, offset, data);
switch (offset)
{
case 0:
ctrl_w(val);
ctrl_w(data);
break;
case 1:
intf_w(val);
intf_w(data);
break;
case 2:
cmd_w(val);
cmd_w(data);
break;
case 3:
data_w(val);
data_w(data);
break;
}
}
u8 heath_z37_fdc_device::read(offs_t reg)
u8 h89bus_z37_device::read(u8 select_lines, u8 offset)
{
if (!(select_lines & h89bus_device::H89_CASS))
{
return 0;
}
// default return for the h89
u8 value = 0xff;
switch (reg)
switch (offset)
{
case 0:
case 1:
@ -169,27 +228,27 @@ u8 heath_z37_fdc_device::read(offs_t reg)
break;
}
LOGFUNC("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, value);
LOGFUNC("%s: reg: %d val: 0x%02x\n", FUNCNAME, offset, value);
return value;
}
void heath_z37_fdc_device::device_start()
void h89bus_z37_device::device_start()
{
save_item(NAME(m_irq_allowed));
save_item(NAME(m_drq_allowed));
save_item(NAME(m_access_track_sector));
}
void heath_z37_fdc_device::device_reset()
void h89bus_z37_device::device_reset()
{
m_irq_allowed = false;
m_drq_allowed = false;
m_access_track_sector = false;
m_irq_cb(0);
m_drq_cb(0);
m_block_interrupt_cb(0);
set_slot_fdcirq(0);
set_slot_fdcdrq(0);
set_slot_blockirq(0);
}
static void z37_floppies(device_slot_interface &device)
@ -204,11 +263,11 @@ static void z37_floppies(device_slot_interface &device)
device.option_add("qd", FLOPPY_525_QD);
}
void heath_z37_fdc_device::device_add_mconfig(machine_config &config)
void h89bus_z37_device::device_add_mconfig(machine_config &config)
{
FD1797(config, m_fdc, 16_MHz_XTAL / 16);
m_fdc->intrq_wr_callback().set(FUNC(heath_z37_fdc_device::set_irq));
m_fdc->drq_wr_callback().set(FUNC(heath_z37_fdc_device::set_drq));
m_fdc->intrq_wr_callback().set(FUNC(h89bus_z37_device::set_irq));
m_fdc->drq_wr_callback().set(FUNC(h89bus_z37_device::set_drq));
// Z-89-37 schematics show the ready line tied high.
m_fdc->set_force_ready(true);
@ -222,16 +281,20 @@ void heath_z37_fdc_device::device_add_mconfig(machine_config &config)
m_floppies[3]->enable_sound(true);
}
void heath_z37_fdc_device::set_irq(int state)
void h89bus_z37_device::set_irq(int state)
{
LOGLINES("set irq, allowed: %d state: %d\n", m_irq_allowed, state);
m_irq_cb(m_irq_allowed ? state : CLEAR_LINE);
set_slot_fdcirq(m_irq_allowed ? state : CLEAR_LINE);
}
void heath_z37_fdc_device::set_drq(int state)
void h89bus_z37_device::set_drq(int state)
{
LOGLINES("set drq, allowed: %d state: %d\n", m_drq_allowed, state);
m_drq_cb(m_drq_allowed ? state : CLEAR_LINE);
set_slot_fdcdrq(m_drq_allowed ? state : CLEAR_LINE);
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(H89BUS_Z37, device_h89bus_right_card_interface, h89bus_z37_device, "h89_z37", "Heathkit Z-37 Floppy Disk Controller");

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit Z-37 Floppy Disk Controller
****************************************************************************/
#ifndef MAME__Z37_FDC_H
#define MAME_BUS_HEATHZENITH_H89_Z37_FDC_H
#pragma once
#include "h89bus.h"
DECLARE_DEVICE_TYPE(H89BUS_Z37, device_h89bus_right_card_interface)
#endif // MAME_BUS_HEATHZENITH_H89_Z37_FDC_H

View File

@ -43,13 +43,13 @@
#include "emu.h"
#include "h_88_cass.h"
#include "intr_cntrl.h"
#include "mms77316_fdc.h"
//#include "mms77316_fdc.h"
#include "sigmasoft_parallel_port.h"
#include "tlb.h"
#include "z37_fdc.h"
#include "bus/heathzenith/h89/h89bus.h"
#include "bus/heathzenith/h89/cards.h"
#include "cpu/z80/z80.h"
#include "machine/ins8250.h"
#include "machine/ram.h"
@ -86,11 +86,10 @@ protected:
m_floppy_ram(*this, "floppyram"),
m_tlbc(*this, "tlbc"),
m_intr_socket(*this, "intr_socket"),
m_h89bus(*this, "h89bus"),
m_console(*this, "console"),
m_serial1(*this, "serial1"),
m_serial2(*this, "serial2"),
m_serial3(*this, "serial3"),
m_config(*this, "CONFIG")
m_config(*this, "CONFIG"),
m_sw501(*this, "SW501")
{
}
@ -103,11 +102,9 @@ protected:
required_shared_ptr<u8> m_floppy_ram;
required_device<heath_tlb_connector> m_tlbc;
required_device<heath_intr_socket> m_intr_socket;
required_device<h89bus_device> m_h89bus;
required_device<ins8250_device> m_console;
required_device<ins8250_device> m_serial1;
required_device<ins8250_device> m_serial2;
required_device<ins8250_device> m_serial3;
required_ioport m_config;
required_ioport m_config, m_sw501;
memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_program;
// General Purpose Port (GPP)
@ -129,16 +126,18 @@ protected:
static constexpr XTAL H89_CLOCK = XTAL(12'288'000) / 6;
static constexpr XTAL INS8250_CLOCK = XTAL(1'843'200);
static constexpr u8 GPP_SINGLE_STEP_BIT = 0;
static constexpr u8 GPP_ENABLE_TIMER_INTERRUPT_BIT = 1;
static constexpr u8 GPP_SPEED_SELECT_BIT = 4;
static constexpr u8 GPP_DISABLE_ROM_BIT = 5;
static constexpr u8 GPP_H17_SIDE_SELECT_BIT = 6;
static constexpr u8 GPP_SINGLE_STEP_BIT = 0;
static constexpr u8 GPP_ENABLE_TIMER_INTERRUPT_BIT = 1;
static constexpr u8 GPP_MEM1_BIT = 2;
static constexpr u8 GPP_MEM0_BIT = 4;
static constexpr u8 GPP_DISABLE_ROM_BIT = 5;
static constexpr u8 GPP_IO0_BIT = 6;
static constexpr u8 GPP_IO1_BIT = 7;
void update_mem_view();
void update_gpp(u8 gpp);
void port_f2_w(u8 data);
void port_f2_w(offs_t offset, u8 data);
virtual void machine_start() override ATTR_COLD;
virtual void machine_reset() override ATTR_COLD;
@ -157,6 +156,8 @@ protected:
void console_intr(int data);
void reset_line(int data);
void reset_single_step_state();
template <int line> void slot_irq(int state);
};
/**
@ -169,17 +170,14 @@ class h88_state : public h89_base_state
{
public:
h88_state(const machine_config &mconfig, device_type type, const char *tag):
h89_base_state(mconfig, type, tag),
m_cassette(*this, "h_88_5")
h89_base_state(mconfig, type, tag)
{
}
void h88(machine_config &config);
protected:
required_device<heath_h_88_cass_device> m_cassette;
void h88_io(address_map &map) ATTR_COLD;
void h88_io(address_map &map);
};
@ -192,20 +190,13 @@ class h89_state : public h89_base_state
{
public:
h89_state(const machine_config &mconfig, device_type type, const char *tag):
h89_base_state(mconfig, type, tag),
m_h37(*this, "h37")
h89_base_state(mconfig, type, tag)
{
}
void h89(machine_config &config);
protected:
required_device<heath_z37_fdc_device> m_h37;
void h89_io(address_map &map) ATTR_COLD;
};
class h89_sigmasoft_state : public h89_state
{
public:
@ -220,7 +211,7 @@ public:
protected:
required_device<sigmasoft_parallel_port> m_sigma_parallel;
void h89_sigmasoft_io(address_map &map) ATTR_COLD;
void h89_sigmasoft_io(address_map &map);
};
@ -248,17 +239,15 @@ class h89_mms_state : public h89_base_state
{
public:
h89_mms_state(const machine_config &mconfig, device_type type, const char *tag):
h89_base_state(mconfig, type, tag),
m_mms316(*this, "mms77316")
h89_base_state(mconfig, type, tag)
{
}
void h89_mms(machine_config &config);
protected:
required_device<mms77316_fdc_device> m_mms316;
void h89_mms_io(address_map &map) ATTR_COLD;
u8 port_f2_mms_r(offs_t offset);
void port_f2_mms_w(offs_t offset, u8 data);
};
@ -389,46 +378,11 @@ void h89_base_state::h89_base_io(address_map &map)
{
map.unmap_value_high();
map.global_mask(0xff);
// 8250 UART DCE 0320 (0xd0)
map(0xd0, 0xd7).rw(m_serial1, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
// 8250 UART DTE 0330 (0xd8) - typically used for modem
map(0xd8, 0xdf).rw(m_serial2, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
// 8250 UART DCE 0340 (0xe0) - typically used for printer
map(0xe0, 0xe7).rw(m_serial3, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
// 8250 UART console - this connects internally to the Terminal Logic board that is also used in the H19.
map(0xe8, 0xef).rw(m_console, FUNC(ins8250_device::ins8250_r), FUNC(ins8250_device::ins8250_w));
// ports defined on the H8. On the H89, access to these addresses causes a NMI
map(0xf0, 0xf1).rw(FUNC(h89_base_state::raise_NMI_r),FUNC(h89_base_state::raise_NMI_w));
// General Purpose Port (GPP)
map(0xf2, 0xf2).w(FUNC(h89_base_state::port_f2_w)).portr("SW501");
// port defined on the H8. On the H89, access to these addresses causes a NMI
map(0xfa, 0xfb).rw(FUNC(h89_base_state::raise_NMI_r), FUNC(h89_base_state::raise_NMI_w));
}
void h88_state::h88_io(address_map &map)
{
h89_base_state::h89_base_io(map);
// Cassette I/O (uses 0xf8 - 0xf9) - Requires MTR-88 ROM
map(0xf8, 0xf9).rw(m_cassette, FUNC(heath_h_88_cass_device::read), FUNC(heath_h_88_cass_device::write));
}
void h89_state::h89_io(address_map &map)
{
h89_base_state::h89_base_io(map);
// H37 5-1/4" Soft-sectored Controller - Requires MTR-90 ROM
map(0x78, 0x7b).rw(m_h37, FUNC(heath_z37_fdc_device::read), FUNC(heath_z37_fdc_device::write));
}
void h89_sigmasoft_state::h89_sigmasoft_io(address_map &map)
{
h89_io(map);
h89_base_io(map);
// Add SigmaSoft parallel port board, required for IGC graphics
map(0x08,0x0f).rw(m_sigma_parallel, FUNC(sigmasoft_parallel_port::read), FUNC(sigmasoft_parallel_port::write));
@ -463,14 +417,6 @@ void h89_sigmasoft_state::h89_sigmasoft_io(address_map &map)
NMI | FA-FB |
Unused | FC-FF |
*/
void h89_mms_state::h89_mms_io(address_map &map)
{
h89_base_state::h89_base_io(map);
// Add MMS 77316 Double Density Controller
map(0x38,0x3f).rw(m_mms316, FUNC(mms77316_fdc_device::read), FUNC(mms77316_fdc_device::write));
}
// Input ports
static INPUT_PORTS_START( h88 )
@ -818,6 +764,15 @@ void h89_base_state::console_intr(int data)
m_intr_socket->set_irq_level(3, data);
}
template <int line> void h89_base_state::slot_irq(int state)
{
m_intr_socket->set_irq_level(line, state);
}
template void h89_base_state::slot_irq<3>(int state);
template void h89_base_state::slot_irq<4>(int state);
template void h89_base_state::slot_irq<5>(int state);
void h89_base_state::reset_line(int data)
{
if (bool(data))
@ -870,6 +825,11 @@ void h89_base_state::update_gpp(u8 gpp)
m_timer_intr_enabled = bool(BIT(m_gpp, GPP_ENABLE_TIMER_INTERRUPT_BIT));
m_h89bus->set_mem0(BIT(m_gpp, GPP_MEM0_BIT));
m_h89bus->set_mem1(BIT(m_gpp, GPP_MEM1_BIT));
m_h89bus->set_io0(BIT(m_gpp, GPP_IO0_BIT));
m_h89bus->set_io1(BIT(m_gpp, GPP_IO1_BIT));
if (BIT(changed_gpp, GPP_SINGLE_STEP_BIT))
{
LOGSS("single step enable: %d\n", BIT(m_gpp, GPP_SINGLE_STEP_BIT));
@ -888,21 +848,46 @@ void h89_base_state::update_gpp(u8 gpp)
update_mem_view();
}
if (BIT(changed_gpp, GPP_SPEED_SELECT_BIT))
if (BIT(changed_gpp, GPP_MEM0_BIT))
{
m_maincpu->set_clock(BIT(m_gpp, GPP_SPEED_SELECT_BIT) ?
m_maincpu->set_clock(BIT(m_gpp, GPP_MEM0_BIT) ?
H89_CLOCK * m_cpu_speed_multiplier : H89_CLOCK);
}
}
// General Purpose Port
void h89_base_state::port_f2_w(u8 data)
void h89_base_state::port_f2_w(offs_t offset, u8 data)
{
update_gpp(data);
m_intr_socket->set_irq_level(1, CLEAR_LINE);
}
// MMS intercepts the GPIO decoding so the GPIO pin on
// the right slots can be used as a card select without
// interfering with normal GPIO port operation.
u8 h89_mms_state::port_f2_mms_r(offs_t offset)
{
if ((offset & 7) != 2)
{
return 0;
}
return m_sw501->read();
}
void h89_mms_state::port_f2_mms_w(offs_t offset, u8 data)
{
if ((offset & 7) != 2)
{
return;
}
update_gpp(data);
m_intr_socket->set_irq_level(1, CLEAR_LINE);
}
static void tlb_options(device_slot_interface &device)
{
device.option_add("heath", HEATH_TLB);
@ -940,6 +925,7 @@ void h89_base_state::h89_base(machine_config &config)
Z80(config, m_maincpu, H89_CLOCK);
m_maincpu->set_m1_map(&h89_base_state::map_fetch);
m_maincpu->set_memory_map(&h89_base_state::h89_mem);
m_maincpu->set_io_map(&h88_state::h89_base_io);
m_maincpu->set_irq_acknowledge_callback("intr_socket", FUNC(heath_intr_socket::irq_callback));
RAM(config, m_ram).set_default_size("64K").set_extra_options("16K,32K,48K").set_default_value(0x00);
@ -962,10 +948,28 @@ void h89_base_state::h89_base(machine_config &config)
m_tlbc->reset_cb().set(FUNC(h89_base_state::reset_line));
// H-88-3 3-port serial board
INS8250(config, m_serial1, INS8250_CLOCK);
INS8250(config, m_serial2, INS8250_CLOCK);
INS8250(config, m_serial3, INS8250_CLOCK);
H89BUS(config, m_h89bus, 0);
m_h89bus->set_program_space(m_maincpu, AS_PROGRAM);
m_h89bus->set_io_space(m_maincpu, AS_IO);
m_h89bus->in_tlb_callback().set(m_console, FUNC(ins8250_device::ins8250_r));
m_h89bus->out_tlb_callback().set(m_console, FUNC(ins8250_device::ins8250_w));
m_h89bus->in_nmi_callback().set(FUNC(h89_base_state::raise_NMI_r));
m_h89bus->out_nmi_callback().set(FUNC(h89_base_state::raise_NMI_w));
m_h89bus->in_gpp_callback().set_ioport("SW501");
m_h89bus->out_gpp_callback().set(FUNC(h89_base_state::port_f2_w));
m_h89bus->out_int3_callback().set(FUNC(h89_base_state::slot_irq<3>));
m_h89bus->out_int4_callback().set(FUNC(h89_base_state::slot_irq<4>));
m_h89bus->out_int5_callback().set(FUNC(h89_base_state::slot_irq<5>));
m_h89bus->out_wait_callback().set(FUNC(h89_base_state::set_wait_state));
m_h89bus->out_fdcirq_callback().set(m_intr_socket, FUNC(heath_intr_socket::set_irq));
m_h89bus->out_fdcdrq_callback().set(m_intr_socket, FUNC(heath_intr_socket::set_drq));
m_h89bus->out_blockirq_callback().set(m_intr_socket, FUNC(heath_intr_socket::block_interrupts));
H89BUS_LEFT_SLOT(config, "p501", "h89bus", h89_left_cards, nullptr);
H89BUS_LEFT_SLOT(config, "p502", "h89bus", h89_left_cards, nullptr);
H89BUS_LEFT_SLOT(config, "p503", "h89bus", h89_left_cards, nullptr);
H89BUS_RIGHT_SLOT(config, "p504", "h89bus", h89_right_cards, nullptr);
H89BUS_RIGHT_SLOT(config, "p505", "h89bus", h89_right_cards, "ha_88_3");
H89BUS_RIGHT_SLOT(config, "p506", "h89bus", h89_right_p506_cards, "we_pullup").set_p506_signalling(true);
// H89 interrupt interval is 2mSec
TIMER(config, "irq_timer", 0).configure_periodic(FUNC(h89_base_state::h89_irq_timer), attotime::from_msec(2));
@ -974,37 +978,31 @@ void h89_base_state::h89_base(machine_config &config)
void h88_state::h88(machine_config &config)
{
h89_base(config);
m_maincpu->set_io_map(&h88_state::h88_io);
m_h89bus->set_default_bios_tag("444-43");
m_intr_socket->set_default_option("original");
m_intr_socket->set_fixed(true);
SOFTWARE_LIST(config, "cass_list").set_original("h88_cass");
// H-88-5 Cassette interface board
HEATH_H88_CASS(config, m_cassette, H89_CLOCK);
H89BUS_RIGHT_SLOT(config.replace(), "p504", "h89bus", h89_right_cards, "h_88_5");
}
void h89_state::h89(machine_config &config)
{
h89_base(config);
m_h89bus->set_default_bios_tag("444-61");
m_maincpu->set_io_map(&h89_state::h89_io);
m_maincpu->set_io_map(&h89_state::h89_base_io);
m_intr_socket->set_default_option("h37");
m_intr_socket->set_fixed(true);
// Z-89-37 Soft-sectored controller
HEATH_Z37_FDC(config, m_h37);
m_h37->drq_cb().set(m_intr_socket, FUNC(heath_intr_socket::set_drq));
m_h37->irq_cb().set(m_intr_socket, FUNC(heath_intr_socket::set_irq));
m_h37->block_interrupt_cb().set(m_intr_socket, FUNC(heath_intr_socket::block_interrupts));
H89BUS_RIGHT_SLOT(config.replace(), "p504", "h89bus", h89_right_cards, "z37fdc");
}
void h89_sigmasoft_state::h89_sigmasoft(machine_config &config)
{
h89(config);
m_h89bus->set_default_bios_tag("444-61");
m_maincpu->set_addrmap(AS_IO, &h89_sigmasoft_state::h89_sigmasoft_io);
sigma_tlb_options(m_tlbc);
@ -1023,15 +1021,18 @@ void h89_sigmasoft_state::h89_sigmasoft(machine_config &config)
void h89_mms_state::h89_mms(machine_config &config)
{
h89_base(config);
m_maincpu->set_addrmap(AS_IO, &h89_mms_state::h89_mms_io);
m_h89bus->set_default_bios_tag("444-61c");
m_h89bus->in_gpp_callback().set(FUNC(h89_mms_state::port_f2_mms_r));
m_h89bus->out_gpp_callback().set(FUNC(h89_mms_state::port_f2_mms_w));
// the card selection is different with the MMS mapping PROM
H89BUS_RIGHT_SLOT(config.replace(), "p504", "h89bus", h89_right_cards_mms, "mms77316");
H89BUS_RIGHT_SLOT(config.replace(), "p505", "h89bus", h89_right_cards_mms, "ha_88_3");
H89BUS_RIGHT_SLOT(config.replace(), "p506", "h89bus", h89_right_cards_mms, nullptr).set_p506_signalling(true);
m_intr_socket->set_default_option("mms");
m_intr_socket->set_fixed(true);
MMS77316_FDC(config, m_mms316);
m_mms316->drq_cb().set(m_intr_socket, FUNC(heath_intr_socket::set_drq));
m_mms316->irq_cb().set(m_intr_socket, FUNC(heath_intr_socket::set_irq));
m_mms316->wait_cb().set(FUNC(h89_mms_state::set_wait_state));
}

View File

@ -1,53 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit H-88-5 Cassette Interface card
****************************************************************************/
#ifndef MAME_HEATHKIT_H_88_CASS_H
#define MAME_HEATHKIT_H_88_CASS_H
#pragma once
#include "imagedev/cassette.h"
#include "machine/i8251.h"
#include "machine/timer.h"
#include "formats/h8_cas.h"
class heath_h_88_cass_device : public device_t
{
public:
heath_h_88_cass_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void write(offs_t reg, u8 val);
u8 read(offs_t reg);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void uart_rts(u8 data);
void uart_tx_empty(u8 data);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_r);
TIMER_DEVICE_CALLBACK_MEMBER(kansas_w);
required_device<i8251_device> m_uart;
required_device<cassette_image_device> m_cass_player;
required_device<cassette_image_device> m_cass_recorder;
u8 m_cass_data[4];
bool m_cassbit;
bool m_cassold;
};
DECLARE_DEVICE_TYPE(HEATH_H88_CASS, heath_h_88_cass_device)
#endif // MAME_HEATHKIT_H_88_CASS_H

View File

@ -1,80 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Magnolia Microsystems 77316 soft-sectored floppy controller
****************************************************************************/
#ifndef MAME_HEATHKIT_MMS77316_FDC_H
#define MAME_HEATHKIT_MMS77316_FDC_H
#pragma once
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
class mms77316_fdc_device : public device_t
{
public:
mms77316_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void write(offs_t reg, u8 val);
u8 read(offs_t reg);
auto irq_cb() { return m_irq_cb.bind(); }
auto drq_cb() { return m_drq_cb.bind(); }
auto wait_cb() { return m_wait_cb.bind(); }
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void ctrl_w(u8 val);
void data_w(u8 val);
u8 data_r();
void set_irq(int state);
void set_drq(int state);
// Burst mode was required for a 2 MHz Z80 to handle 8" DD data rates.
// The typical irq/drq was too slow, this utilizes wait states to read the
// WD1797 data port once the drq line is high.
inline bool burst_mode_r() { return !m_drq_allowed; }
private:
devcb_write_line m_irq_cb;
devcb_write_line m_drq_cb;
devcb_write_line m_wait_cb;
required_device<fd1797_device> m_fdc;
required_device_array<floppy_connector, 8> m_floppies;
bool m_irq_allowed;
bool m_drq_allowed;
bool m_irq;
bool m_drq;
u32 m_drq_count;
/// Bits set in cmd_ControlPort_c
static constexpr u8 ctrl_525DriveSel_c = 2;
static constexpr u8 ctrl_EnableIntReq_c = 3;
static constexpr u8 ctrl_EnableDrqInt_c = 5;
static constexpr u8 ctrl_SetMFMRecording_c = 6;
static constexpr XTAL MASTER_CLOCK = XTAL(8'000'000);
static constexpr XTAL FIVE_IN_CLOCK = MASTER_CLOCK / 8;
static constexpr XTAL EIGHT_IN_CLOCK = MASTER_CLOCK / 4;
};
DECLARE_DEVICE_TYPE(MMS77316_FDC, mms77316_fdc_device)
#endif // MAME_HEATHKIT_MMS77316_FDC_H

View File

@ -1,78 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit Z-37 Floppy Disk Controller
****************************************************************************/
#ifndef MAME_HEATHKIT_Z37_FDC_H
#define MAME_HEATHKIT_Z37_FDC_H
#pragma once
#include "imagedev/floppy.h"
#include "machine/wd_fdc.h"
class heath_z37_fdc_device : public device_t
{
public:
heath_z37_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void write(offs_t reg, u8 val);
u8 read(offs_t reg);
auto irq_cb() { return m_irq_cb.bind(); }
auto drq_cb() { return m_drq_cb.bind(); }
auto block_interrupt_cb() { return m_block_interrupt_cb.bind(); }
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
void ctrl_w(u8 val);
void intf_w(u8 val);
void cmd_w(u8 val);
u8 stat_r();
void data_w(u8 val);
u8 data_r();
void set_irq(int state);
void set_drq(int state);
private:
devcb_write_line m_irq_cb;
devcb_write_line m_drq_cb;
devcb_write_line m_block_interrupt_cb;
required_device<fd1797_device> m_fdc;
required_device_array<floppy_connector, 4> m_floppies;
bool m_irq_allowed;
bool m_drq_allowed;
bool m_access_track_sector;
/// Bits set in cmd_ControlPort_c - DK.CON
static constexpr u8 ctrl_EnableIntReq_c = 0;
static constexpr u8 ctrl_EnableDrqInt_c = 1;
static constexpr u8 ctrl_SetMFMRecording_c = 2;
static constexpr u8 ctrl_MotorsOn_c = 3;
static constexpr u8 ctrl_Drive_0_c = 4;
static constexpr u8 ctrl_Drive_1_c = 5;
static constexpr u8 ctrl_Drive_2_c = 6;
static constexpr u8 ctrl_Drive_3_c = 7;
/// Bits to set alternate registers on InterfaceControl_c - DK.INT
static constexpr u8 if_SelectSectorTrack_c = 0;
};
DECLARE_DEVICE_TYPE(HEATH_Z37_FDC, heath_z37_fdc_device)
#endif // MAME_HEATHKIT_Z37_FDC_H