heathkit/h_88_cass.cpp, heathkit/h89.cpp: Added H-88-5 Cassette interface and the H88 as clone of H89. (#11898)

New working clones
---------------
Heath Company Heathkit H88
This commit is contained in:
Mark Garlanger 2024-01-07 09:49:30 -06:00 committed by GitHub
parent a693f1e7e3
commit 46dbcf7f79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 426 additions and 101 deletions

View File

@ -43,9 +43,10 @@
#include "emu.h"
#include "h_88_cass.h"
#include "intr_cntrl.h"
#include "tlb.h"
#include "z37_fdc.h"
#include "intr_cntrl.h"
#include "cpu/z80/z80.h"
#include "machine/ins8250.h"
@ -64,10 +65,13 @@
namespace {
class h89_state : public driver_device
/**
* Base Heathkit H89 functionality
*/
class h89_base_state : public driver_device
{
public:
h89_state(const machine_config &mconfig, device_type type, const char *tag):
protected:
h89_base_state(const machine_config &mconfig, device_type type, const char *tag):
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_maincpu_region(*this, "maincpu"),
@ -75,7 +79,6 @@ public:
m_ram(*this, RAM_TAG),
m_floppy_ram(*this, "floppyram"),
m_tlbc(*this, "tlbc"),
m_h37(*this, "h37"),
m_intr_socket(*this, "intr_socket"),
m_console(*this, "console"),
m_serial1(*this, "serial1"),
@ -85,10 +88,7 @@ public:
{
}
void h89(machine_config &config);
private:
void h89_base(machine_config &config);
required_device<z80_device> m_maincpu;
required_memory_region m_maincpu_region;
@ -96,7 +96,6 @@ private:
required_device<ram_device> m_ram;
required_shared_ptr<uint8_t> m_floppy_ram;
required_device<heath_tlb_connector> m_tlbc;
required_device<heath_z37_fdc_device> m_h37;
required_device<heath_intr_socket> m_intr_socket;
required_device<ins8250_device> m_console;
required_device<ins8250_device> m_serial1;
@ -142,7 +141,8 @@ private:
void h89_mem(address_map &map);
void map_fetch(address_map &map);
uint8_t m1_r(offs_t offset);
void h89_io(address_map &map);
void h89_base_io(address_map &map);
uint8_t raise_NMI_r();
void raise_NMI_w(uint8_t data);
@ -151,6 +151,52 @@ private:
void reset_single_step_state();
};
/**
* Heathkit H88
* - BIOS MTR-88
* - H-88-5 Cassette Interface Board
*
*/
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")
{
}
void h88(machine_config &config);
protected:
required_device<heath_h_88_cass_device> m_cassette;
void h88_io(address_map &map);
};
/**
* Heathkit H89
* - Z-89-37 Soft-sectored Floppy Controller
*
*/
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")
{
}
void h89(machine_config &config);
protected:
required_device<heath_z37_fdc_device> m_h37;
void h89_io(address_map &map);
};
/*
The H89 supported 16K, 32K, 48K, or 64K of RAM. The first 8K of address space
is reserved for the monitor ROM, floppy ROM, and scratch pad RAM. For 16k-48K
@ -187,7 +233,7 @@ private:
------------- 0k ------------- 0k
*/
void h89_state::h89_mem(address_map &map)
void h89_base_state::h89_mem(address_map &map)
{
map.unmap_value_high();
@ -208,12 +254,12 @@ void h89_state::h89_mem(address_map &map)
m_mem_view[1](0x1800, 0x1fff).rom().region("maincpu", 0x1800).unmapw();
}
void h89_state::map_fetch(address_map &map)
void h89_base_state::map_fetch(address_map &map)
{
map(0x0000, 0xffff).r(FUNC(h89_state::m1_r));
map(0x0000, 0xffff).r(FUNC(h89_base_state::m1_r));
}
uint8_t h89_state::m1_r(offs_t offset)
uint8_t h89_base_state::m1_r(offs_t offset)
{
uint8_t data = m_program.read_byte(offset);
@ -248,7 +294,6 @@ uint8_t h89_state::m1_r(offs_t offset)
Use | Hex | Octal
--------------------------+-------+---------
Not specified, available | 0-77 | 0-167
Cassette I/O (if used) | 78-79 | 170-171
Disk I/O #1 | 78-7B | 170-173
Disk I/O #2 | 7C-7F | 174-177
Not specified, reserved | 80-CF | 200-317
@ -258,20 +303,20 @@ uint8_t h89_state::m1_r(offs_t offset)
Console I/O | E8-EF | 350-357
NMI | F0-F1 | 360-361
General purpose port | F2 | 362
Cassette I/O(MTR-88) | F8-F9 | 370-371
NMI | FA-FB | 372-373
*/
void h89_state::h89_io(address_map &map)
void h89_base_state::h89_base_io(address_map &map)
{
map.unmap_value_high();
map.global_mask(0xff);
// Disk I/O #1 - 0170-0173 (0x78-0x7b)
// Options
// - Cassette I/O (only uses 0x78 - 0x79) - Requires MTR-88 ROM
// - H37 5-1/4" Soft-sectored Controller - Requires MTR-90 ROM
// - H47 Dual 8" Drives - Requires MTR-89 or MTR-90 ROM
// - H67 8" Hard disk + 8" Floppy Drives - Requires MTR-90 ROM
map(0x78, 0x7b).rw(m_h37, FUNC(heath_z37_fdc_device::read), FUNC(heath_z37_fdc_device::write));
// map(0x78, 0x7b)
// Disk I/O #2 - 0174-0177 (0x7c-0x7f)
// Options
@ -291,16 +336,60 @@ void h89_state::h89_io(address_map &map)
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_state::raise_NMI_r),FUNC(h89_state::raise_NMI_w));
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_state::port_f2_w)).portr("SW501");
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_state::raise_NMI_r), FUNC(h89_state::raise_NMI_w));
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));
}
// Input ports
static INPUT_PORTS_START( h88 )
PORT_START("SW501")
// MTR-88 (444-40)
PORT_DIPUNUSED_DIPLOC(0x01, 0x00, "SW501:1")
PORT_DIPUNUSED_DIPLOC(0x02, 0x00, "SW501:2")
PORT_DIPUNUSED_DIPLOC(0x04, 0x00, "SW501:3")
PORT_DIPUNUSED_DIPLOC(0x08, 0x00, "SW501:4")
PORT_DIPUNUSED_DIPLOC(0x10, 0x00, "SW501:5")
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6")
PORT_DIPSETTING( 0x20, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0xc0, 0x00, "Console Baud rate" ) PORT_DIPLOCATION("SW501:7,8")
PORT_DIPSETTING( 0x00, "9600" )
PORT_DIPSETTING( 0x40, "19200" )
PORT_DIPSETTING( 0x80, "38400" )
PORT_DIPSETTING( 0xc0, "57600" )
PORT_START("CONFIG")
PORT_CONFNAME(0x03, 0x00, "CPU Clock Speed Upgrade")
PORT_CONFSETTING(0x00, DEF_STR( None ) )
PORT_CONFSETTING(0x01, "2 / 4 MHz")
PORT_CONFSETTING(0x02, "2 / 6 MHz")
INPUT_PORTS_END
static INPUT_PORTS_START( h89 )
PORT_START("SW501")
@ -354,53 +443,42 @@ static INPUT_PORTS_START( h89 )
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x80, "Auto" )
// MTR-88 (444-40)
PORT_DIPNAME( 0x1f, 0x00, "Unused" ) PORT_DIPLOCATION("SW501:1,2,3,4,5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x20, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0xc0, 0x00, "Console Baud rate" ) PORT_DIPLOCATION("SW501:7,8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, "9600" )
PORT_DIPSETTING( 0x40, "19200" )
PORT_DIPSETTING( 0x80, "38400" )
PORT_DIPSETTING( 0xc0, "57600" )
// MTR-89 (444-62)
PORT_DIPNAME( 0x03, 0x00, "Disk I/O #2" ) PORT_DIPLOCATION("SW501:1,2") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x03, 0x00, "Disk I/O #2" ) PORT_DIPLOCATION("SW501:1,2") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, "H-88-1" )
PORT_DIPSETTING( 0x01, "H/Z-47" )
PORT_DIPSETTING( 0x02, "Undefined" )
PORT_DIPSETTING( 0x03, "Undefined" )
PORT_DIPNAME( 0x0c, 0x00, "Disk I/O #1" ) PORT_DIPLOCATION("SW501:3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x0c, 0x00, "Disk I/O #1" ) PORT_DIPLOCATION("SW501:3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, "Unused" )
PORT_DIPSETTING( 0x04, "H/Z-47" )
PORT_DIPSETTING( 0x08, "Undefined" )
PORT_DIPSETTING( 0x0c, "Undefined" )
PORT_DIPNAME( 0x10, 0x00, "Primary Boot from" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x10, 0x00, "Primary Boot from" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, "Disk I/O #2" )
PORT_DIPSETTING( 0x10, "Disk I/O #1" )
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x20, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0x40, 0x00, "Console Baud rate" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x40, 0x00, "Console Baud rate" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, "9600" )
PORT_DIPSETTING( 0x40, "19200" )
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x08)
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x80, "Auto" )
// MMS 444-84B (and possibly 444-84A)
PORT_DIPNAME( 0x03, 0x00, "Disk I/O #2" ) PORT_DIPLOCATION("SW501:1,2") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPNAME( 0x03, 0x00, "Disk I/O #2" ) PORT_DIPLOCATION("SW501:1,2") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPSETTING( 0x00, "H-88-1" )
PORT_DIPSETTING( 0x01, "H/Z-47 (Not yet implemented)" )
PORT_DIPSETTING( 0x02, "MMS 77320 SASI or Z-67 (Not yet implemented)" )
PORT_DIPSETTING( 0x03, "MMS 77422 Network Controller" )
PORT_DIPNAME( 0x0c, 0x00, "Disk I/O #1" ) PORT_DIPLOCATION("SW501:3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPNAME( 0x0c, 0x00, "Disk I/O #1" ) PORT_DIPLOCATION("SW501:3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPSETTING( 0x00, "H-89-37" )
PORT_DIPSETTING( 0x04, "H/Z-47 (Not yet implemented)" )
PORT_DIPSETTING( 0x08, "MMS 77320 SASI or Z-67 (Not yet implemented)" )
PORT_DIPSETTING( 0x0c, "MMS 77422 Network Controller" )
PORT_DIPNAME( 0x70, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:5,6,7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPNAME( 0x70, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:5,6,7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPSETTING( 0x00, "MMS 77316 Dbl Den 5\"" )
PORT_DIPSETTING( 0x10, "MMS 77316 Dbl Den 8\"" )
PORT_DIPSETTING( 0x20, "Disk Device at 0x7C" )
@ -409,12 +487,12 @@ static INPUT_PORTS_START( h89 )
PORT_DIPSETTING( 0x50, "reserved for future use" )
PORT_DIPSETTING( 0x60, "MMS Network (77422)" )
PORT_DIPSETTING( 0x70, "Use MMS I/O board Config Port" )
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x0c)
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x80, "Auto" )
// Kres KMR-100
PORT_DIPNAME( 0x0f, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:1,2,3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPNAME( 0x0f, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:1,2,3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPSETTING( 0x00, "H-17 hard-sectored 5\" floppy units 0-2" )
PORT_DIPSETTING( 0x01, "H-37 soft-sectored 5\" floppy units 0-3" )
PORT_DIPSETTING( 0x02, "Corvus hard disk/Magnolia interface, partitions 0-8" )
@ -431,22 +509,22 @@ static INPUT_PORTS_START( h89 )
PORT_DIPSETTING( 0x0d, "Reserved" )
PORT_DIPSETTING( 0x0e, "Reserved" )
PORT_DIPSETTING( 0x0f, "Magnolia 128K pseudo disk, banks 0-1" )
PORT_DIPNAME( 0x10, 0x00, "Map ROM into RAM on boot" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPNAME( 0x10, 0x00, "Map ROM into RAM on boot" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPSETTING( 0x10, DEF_STR( No ) )
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPSETTING( 0x20, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0x40, 0x00, "Have a LLL controller installed" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPNAME( 0x40, 0x00, "Have a LLL controller installed" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPSETTING( 0x00, DEF_STR( No ) )
PORT_DIPSETTING( 0x40, DEF_STR( Yes ) )
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x10)
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x80, "Auto" )
// Ultimeth MTRHEX-4k
// (values based on testing and comparison with the Kres KMR-100 ROM which was also written by Ultimeth)
PORT_DIPNAME( 0x0f, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:1,2,3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x18)
PORT_DIPNAME( 0x0f, 0x00, "Default Boot Device" ) PORT_DIPLOCATION("SW501:1,2,3,4") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPSETTING( 0x00, "H-17 hard-sectored 5\" floppy" )
PORT_DIPSETTING( 0x01, "H-37 soft-sectored 5\" floppy" )
PORT_DIPSETTING( 0x02, "? Corvus hard disk/Magnolia interface" )
@ -463,16 +541,16 @@ static INPUT_PORTS_START( h89 )
PORT_DIPSETTING( 0x0d, "? Reserved" )
PORT_DIPSETTING( 0x0e, "? Reserved" )
PORT_DIPSETTING( 0x0f, "? Magnolia 128K pseudo disk" )
PORT_DIPNAME( 0x10, 0x00, "? Map ROM into RAM on boot" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x18)
PORT_DIPNAME( 0x10, 0x00, "? Map ROM into RAM on boot" ) PORT_DIPLOCATION("SW501:5") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPSETTING( 0x00, "? Yes" )
PORT_DIPSETTING( 0x10, "? No" )
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x18)
PORT_DIPNAME( 0x20, 0x20, "Perform memory test at start" ) PORT_DIPLOCATION("SW501:6") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPSETTING( 0x20, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0x40, 0x00, "? Have a LLL controller installed" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x18)
PORT_DIPNAME( 0x40, 0x00, "? Have a LLL controller installed" ) PORT_DIPLOCATION("SW501:7") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPSETTING( 0x00, "? No" )
PORT_DIPSETTING( 0x40, "? Yes" )
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x18)
PORT_DIPNAME( 0x80, 0x00, "Boot mode" ) PORT_DIPLOCATION("SW501:8") PORT_CONDITION("CONFIG", 0x3c, EQUALS, 0x14)
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x80, "Auto" )
@ -485,16 +563,15 @@ static INPUT_PORTS_START( h89 )
PORT_CONFNAME(0x3c, 0x04, "Switch SW501 Definitions")
PORT_CONFSETTING(0x00, "Generic" )
PORT_CONFSETTING(0x04, "Heath MTR-90")
PORT_CONFSETTING(0x08, "Heath MTR-88")
PORT_CONFSETTING(0x0c, "Heath MTR-89")
PORT_CONFSETTING(0x10, "MMS 444-84B/444-84A")
PORT_CONFSETTING(0x14, "Kres KMR-100")
PORT_CONFSETTING(0x18, "Ultimeth MTRHEX-4k")
PORT_CONFSETTING(0x08, "Heath MTR-89")
PORT_CONFSETTING(0x0c, "MMS 444-84B/444-84A")
PORT_CONFSETTING(0x10, "Kres KMR-100")
PORT_CONFSETTING(0x14, "Ultimeth MTRHEX-4k")
INPUT_PORTS_END
void h89_state::machine_start()
void h89_base_state::machine_start()
{
save_item(NAME(m_gpp));
save_item(NAME(m_rom_enabled));
@ -541,8 +618,7 @@ void h89_state::machine_start()
}
}
void h89_state::machine_reset()
void h89_base_state::machine_reset()
{
m_rom_enabled = true;
m_timer_intr_enabled = true;
@ -577,24 +653,24 @@ void h89_state::machine_reset()
update_mem_view();
}
uint8_t h89_state::raise_NMI_r()
uint8_t h89_base_state::raise_NMI_r()
{
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::from_usec(2));
return 0x00;
}
void h89_state::raise_NMI_w(uint8_t)
void h89_base_state::raise_NMI_w(uint8_t)
{
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::from_usec(2));
}
void h89_state::console_intr(uint8_t data)
void h89_base_state::console_intr(uint8_t data)
{
m_intr_socket->set_irq_level(3, data);
}
void h89_state::reset_line(int data)
void h89_base_state::reset_line(int data)
{
if (bool(data))
{
@ -603,7 +679,7 @@ void h89_state::reset_line(int data)
m_maincpu->set_input_line(INPUT_LINE_RESET, data);
}
TIMER_DEVICE_CALLBACK_MEMBER(h89_state::h89_irq_timer)
TIMER_DEVICE_CALLBACK_MEMBER(h89_base_state::h89_irq_timer)
{
if (m_timer_intr_enabled)
{
@ -611,12 +687,12 @@ TIMER_DEVICE_CALLBACK_MEMBER(h89_state::h89_irq_timer)
}
}
void h89_state::update_mem_view()
void h89_base_state::update_mem_view()
{
m_mem_view.select(m_rom_enabled ? (m_floppy_ram_wp ? 0 : 1) : 2);
}
void h89_state::reset_single_step_state()
void h89_base_state::reset_single_step_state()
{
LOGSS("reset_single_step_state\n");
m_555a_latch = false;
@ -638,7 +714,7 @@ void h89_state::reset_single_step_state()
// 6 Latched bit I/O 0 on I/O exp connector
// 7 Latched bit I/O 1 on I/O exp connector
//
void h89_state::update_gpp(uint8_t gpp)
void h89_base_state::update_gpp(uint8_t gpp)
{
uint8_t changed_gpp = gpp ^ m_gpp;
@ -672,7 +748,7 @@ void h89_state::update_gpp(uint8_t gpp)
}
// General Purpose Port
void h89_state::port_f2_w(uint8_t data)
void h89_base_state::port_f2_w(uint8_t data)
{
update_gpp(data);
@ -696,22 +772,21 @@ static void intr_ctrl_options(device_slot_interface &device)
device.option_add("h37", HEATH_Z37_INTR_CNTRL);
}
void h89_state::h89(machine_config & config)
void h89_base_state::h89_base(machine_config &config)
{
// basic machine hardware
Z80(config, m_maincpu, H89_CLOCK);
m_maincpu->set_m1_map(&h89_state::map_fetch);
m_maincpu->set_memory_map(&h89_state::h89_mem);
m_maincpu->set_io_map(&h89_state::h89_io);
m_maincpu->set_m1_map(&h89_base_state::map_fetch);
m_maincpu->set_memory_map(&h89_base_state::h89_mem);
m_maincpu->set_irq_acknowledge_callback("intr_socket", FUNC(heath_intr_socket::irq_callback));
HEATH_INTR_SOCKET(config, m_intr_socket, intr_ctrl_options, "h37", true);
m_intr_socket->irq_line_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
RAM(config, m_ram).set_default_size("64K").set_extra_options("16K,32K,48K").set_default_value(0x00);
HEATH_INTR_SOCKET(config, m_intr_socket, intr_ctrl_options, nullptr);
m_intr_socket->irq_line_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
INS8250(config, m_console, INS8250_CLOCK);
m_console->out_int_callback().set(FUNC(h89_state::console_intr));
m_console->out_int_callback().set(FUNC(h89_base_state::console_intr));
HEATH_TLB_CONNECTOR(config, m_tlbc, tlb_options, "heath");
@ -723,12 +798,7 @@ void h89_state::h89(machine_config & config)
m_tlbc->rts_callback().set(m_console, FUNC(ins8250_uart_device::cts_w));
m_tlbc->dtr_callback().set(m_console, FUNC(ins8250_uart_device::dsr_w));
m_tlbc->reset_cb().set(FUNC(h89_state::reset_line));
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));
m_tlbc->reset_cb().set(FUNC(h89_base_state::reset_line));
// H-88-3 3-port serial board
INS8250(config, m_serial1, INS8250_CLOCK);
@ -736,9 +806,46 @@ void h89_state::h89(machine_config & config)
INS8250(config, m_serial3, INS8250_CLOCK);
// H89 interrupt interval is 2mSec
TIMER(config, "irq_timer", 0).configure_periodic(FUNC(h89_state::h89_irq_timer), attotime::from_msec(2));
TIMER(config, "irq_timer", 0).configure_periodic(FUNC(h89_base_state::h89_irq_timer), attotime::from_msec(2));
}
void h88_state::h88(machine_config &config)
{
h89_base_state::h89_base(config);
m_maincpu->set_io_map(&h88_state::h88_io);
m_intr_socket->set_default_option("original");
m_intr_socket->set_fixed(true);
// H-88-5 Cassette interface board
HEATH_H88_CASS(config, m_cassette, H89_CLOCK);
}
void h89_state::h89(machine_config &config)
{
h89_base_state::h89_base(config);
m_maincpu->set_io_map(&h89_state::h89_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));
}
// ROM definition
ROM_START( h88 )
ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
ROM_LOAD( "2716_444-19_h17.u520", 0x1800, 0x0800, CRC(26e80ae3) SHA1(0c0ee95d7cb1a760f924769e10c0db1678f2435c))
ROM_LOAD("2716_444-40_mtr88.u518", 0x0000, 0x0800, CRC(093afb79) SHA1(bcc1569ad9da7babf0a4199cab96d8cd59b2dd78))
ROM_END
// ROM definition
ROM_START( h89 )
ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF )
@ -749,26 +856,23 @@ ROM_START( h89 )
ROM_SYSTEM_BIOS(0, "mtr90", "MTR-90 (444-142)")
ROMX_LOAD("2732_444-142_mtr90.u518", 0x0000, 0x1000, CRC(c4ff47c5) SHA1(d6f3d71ff270a663003ec18a3ed1fa49f627123a), ROM_BIOS(0))
ROM_SYSTEM_BIOS(1, "mtr88", "MTR-88 (444-40)")
ROMX_LOAD("2716_444-40_mtr88.u518", 0x0000, 0x0800, CRC(093afb79) SHA1(bcc1569ad9da7babf0a4199cab96d8cd59b2dd78), ROM_BIOS(1))
ROM_SYSTEM_BIOS(1, "mtr89", "MTR-89 (444-62)")
ROMX_LOAD("2716_444-62_mtr89.u518", 0x0000, 0x0800, CRC(8f507972) SHA1(ac6c6c1344ee4e09fb60d53c85c9b761217fe9dc), ROM_BIOS(1))
ROM_SYSTEM_BIOS(2, "mtr89", "MTR-89 (444-62)")
ROMX_LOAD("2716_444-62_mtr89.u518", 0x0000, 0x0800, CRC(8f507972) SHA1(ac6c6c1344ee4e09fb60d53c85c9b761217fe9dc), ROM_BIOS(2))
ROM_SYSTEM_BIOS(2, "mms84b", "MMS 444-84B")
ROMX_LOAD("2732_444_84b_mms.u518", 0x0000, 0x1000, CRC(7e75d6f4) SHA1(baf34e036388d1a191197e31f8a93209f04fc58b), ROM_BIOS(2))
ROM_SYSTEM_BIOS(3, "mms84b", "MMS 444-84B")
ROMX_LOAD("2732_444_84b_mms.u518", 0x0000, 0x1000, CRC(7e75d6f4) SHA1(baf34e036388d1a191197e31f8a93209f04fc58b), ROM_BIOS(3))
ROM_SYSTEM_BIOS(3, "kmr-100", "Kres KMR-100 V3.a.02")
ROMX_LOAD("2732_kmr100_v3_a_02.u518", 0x0000, 0x1000, CRC(fd491592) SHA1(3d5803f95c38b237b07cd230353cd9ddc9858c13), ROM_BIOS(3))
ROM_SYSTEM_BIOS(4, "kmr-100", "Kres KMR-100 V3.a.02")
ROMX_LOAD("2732_kmr100_v3_a_02.u518", 0x0000, 0x1000, CRC(fd491592) SHA1(3d5803f95c38b237b07cd230353cd9ddc9858c13), ROM_BIOS(4))
ROM_SYSTEM_BIOS(4, "mtrhex_4k", "Ultimeth ROM")
ROMX_LOAD("2732_mtrhex_4k.u518", 0x0000, 0x1000, CRC(e26b29a9) SHA1(ba13d6c9deef682a9a8262bc910d46b577929a13), ROM_BIOS(4))
ROM_SYSTEM_BIOS(5, "mtrhex_4k", "Ultimeth ROM")
ROMX_LOAD("2732_mtrhex_4k.u518", 0x0000, 0x1000, CRC(e26b29a9) SHA1(ba13d6c9deef682a9a8262bc910d46b577929a13), ROM_BIOS(5))
ROM_SYSTEM_BIOS(5, "mtr90-84", "Heath's MTR-90 (444-84 - Superseded by 444-142)")
ROMX_LOAD("2732_444-84_mtr90.u518", 0x0000, 0x1000, CRC(f10fca03) SHA1(c4a978153af0f2dfcc9ba05be4c1033d33fee30b), ROM_BIOS(5))
ROM_SYSTEM_BIOS(6, "mtr90-84", "Heath's MTR-90 (444-84 - Superseded by 444-142)")
ROMX_LOAD("2732_444-84_mtr90.u518", 0x0000, 0x1000, CRC(f10fca03) SHA1(c4a978153af0f2dfcc9ba05be4c1033d33fee30b), ROM_BIOS(6))
ROM_SYSTEM_BIOS(7, "mms84a", "MMS 444-84A (Superseded by MMS 444-84B)")
ROMX_LOAD("2732_444_84a_mms.u518", 0x0000, 0x1000, CRC(0e541a7e) SHA1(b1deb620fc89c1068e2e663e14be69d1f337a4b9), ROM_BIOS(7))
ROM_SYSTEM_BIOS(6, "mms84a", "MMS 444-84A (Superseded by MMS 444-84B)")
ROMX_LOAD("2732_444_84a_mms.u518", 0x0000, 0x1000, CRC(0e541a7e) SHA1(b1deb620fc89c1068e2e663e14be69d1f337a4b9), ROM_BIOS(6))
ROM_END
} // anonymous namespace
@ -777,4 +881,5 @@ ROM_END
// Driver
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
COMP( 1979, h88, h89, 0, h88, h88, h88_state, empty_init, "Heath Company", "Heathkit H88", MACHINE_SUPPORTS_SAVE)
COMP( 1979, h89, 0, 0, h89, h89, h89_state, empty_init, "Heath Company", "Heathkit H89", MACHINE_SUPPORTS_SAVE)

View File

@ -0,0 +1,166 @@
// license:BSD-3-Clause
// copyright-holders:Mark Garlanger
/***************************************************************************
Heathkit H-88-5 Cassette Interface Card
Came standard on the H88 computer and was on option for other H89 class
systems.
****************************************************************************/
#include "emu.h"
#include "h_88_cass.h"
#include "machine/clock.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)
#include "logmacro.h"
#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__)
#define LOGLINES(...) LOGMASKED(LOG_LINES, __VA_ARGS__)
#define LOGCASS(...) LOGMASKED(LOG_CASS, __VA_ARGS__)
#define LOGFUNC(...) LOGMASKED(LOG_FUNC, __VA_ARGS__)
#ifdef _MSC_VER
#define FUNCNAME __func__
#else
#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");
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),
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)
{
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
m_uart->write(reg, val);
}
u8 heath_h_88_cass_device::read(offs_t reg)
{
u8 val = m_uart->read(reg);
LOGREG("%s: reg: %d val: 0x%02x\n", FUNCNAME, reg, val);
return val;
}
TIMER_DEVICE_CALLBACK_MEMBER(heath_h_88_cass_device::kansas_w)
{
m_cass_data[3]++;
if (m_cassbit != m_cassold)
{
LOGCASS("%s: m_cassbit changed : %d\n", FUNCNAME, m_cassbit);
m_cass_data[3] = 0;
m_cassold = m_cassbit;
}
LOGCASS("%s: m_cassbit: %d\n", FUNCNAME, m_cassbit);
// 2400Hz -> 0
// 1200Hz -> 1
const int bit_pos = m_cassbit ? 0 : 1;
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)
{
// cassette - turn 1200/2400Hz to a bit
m_cass_data[1]++;
u8 cass_ws = (m_cass_player->input() > +0.03) ? 1 : 0;
LOGCASS("%s: cass_ws: %d\n", FUNCNAME, cass_ws);
if (cass_ws != m_cass_data[0])
{
LOGCASS("%s: cass_ws has changed value\n", FUNCNAME);
m_cass_data[0] = cass_ws;
m_uart->write_rxd((m_cass_data[1] < 12) ? 1 : 0);
m_cass_data[1] = 0;
}
}
void heath_h_88_cass_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)
{
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()
{
save_item(NAME(m_cass_data));
save_item(NAME(m_cassbit));
save_item(NAME(m_cassold));
}
void heath_h_88_cass_device::device_reset()
{
LOGFUNC("%s\n", FUNCNAME);
// cassette
m_cassbit = 1;
m_cassold = 0;
m_cass_data[0] = 0;
m_cass_data[1] = 0;
m_cass_data[2] = 0;
m_cass_data[3] = 0;
m_uart->write_cts(0);
m_uart->write_dsr(0);
m_uart->write_rxd(0);
}
void heath_h_88_cass_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));
clock_device &cassette_clock(CLOCK(config, "cassette_clock", 4800));
cassette_clock.signal_handler().set(m_uart, FUNC(i8251_device::write_txc));
cassette_clock.signal_handler().append(m_uart, FUNC(i8251_device::write_rxc));
SPEAKER(config, "mono").front_right();
CASSETTE(config, m_cass_player);
m_cass_player->set_formats(h8_cassette_formats);
m_cass_player->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
m_cass_player->add_route(ALL_OUTPUTS, "mono", 0.15);
m_cass_player->set_interface("h89_cass_player");
CASSETTE(config, m_cass_recorder);
m_cass_recorder->set_formats(h8_cassette_formats);
m_cass_recorder->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED);
m_cass_recorder->add_route(ALL_OUTPUTS, "mono", 0.15);
m_cass_recorder->set_interface("h89_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));
}

View File

@ -0,0 +1,53 @@
// 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;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
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

@ -19230,7 +19230,8 @@ h8 //
h19 // Heath H19 (Zenith Z-19)
@source:heathkit/h89.cpp
h89 // Heath H89 (H88, Zenith Z-89, Z-90)
h89 // Heath H89 (WH89, Zenith Z-89, Z-90)
h88 // Heath H88 (with cassette tape)
@source:hec2hrp/hec2hrp.cpp
hec2hr //