From 46dbcf7f79ce4e48e7c86500965638440ca96725 Mon Sep 17 00:00:00 2001 From: Mark Garlanger Date: Sun, 7 Jan 2024 09:49:30 -0600 Subject: 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 --- src/mame/heathkit/h89.cpp | 305 +++++++++++++++++++++++++++------------- src/mame/heathkit/h_88_cass.cpp | 166 ++++++++++++++++++++++ src/mame/heathkit/h_88_cass.h | 53 +++++++ src/mame/mame.lst | 3 +- 4 files changed, 426 insertions(+), 101 deletions(-) create mode 100644 src/mame/heathkit/h_88_cass.cpp create mode 100644 src/mame/heathkit/h_88_cass.h diff --git a/src/mame/heathkit/h89.cpp b/src/mame/heathkit/h89.cpp index bb50d44b5c6..826927a87a4 100644 --- a/src/mame/heathkit/h89.cpp +++ b/src/mame/heathkit/h89.cpp @@ -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 m_maincpu; required_memory_region m_maincpu_region; @@ -96,7 +96,6 @@ private: required_device m_ram; required_shared_ptr m_floppy_ram; required_device m_tlbc; - required_device m_h37; required_device m_intr_socket; required_device m_console; required_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 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 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(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(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(3, "mms84b", "MMS 444-84B") - ROMX_LOAD("2732_444_84b_mms.u518", 0x0000, 0x1000, CRC(7e75d6f4) SHA1(baf34e036388d1a191197e31f8a93209f04fc58b), ROM_BIOS(3)) + 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(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(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(5, "mtrhex_4k", "Ultimeth ROM") - ROMX_LOAD("2732_mtrhex_4k.u518", 0x0000, 0x1000, CRC(e26b29a9) SHA1(ba13d6c9deef682a9a8262bc910d46b577929a13), ROM_BIOS(5)) + 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(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(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(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) diff --git a/src/mame/heathkit/h_88_cass.cpp b/src/mame/heathkit/h_88_cass.cpp new file mode 100644 index 00000000000..5f09426f964 --- /dev/null +++ b/src/mame/heathkit/h_88_cass.cpp @@ -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)); +} diff --git a/src/mame/heathkit/h_88_cass.h b/src/mame/heathkit/h_88_cass.h new file mode 100644 index 00000000000..8656ee6bbf4 --- /dev/null +++ b/src/mame/heathkit/h_88_cass.h @@ -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 m_uart; + required_device m_cass_player; + required_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 diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 4394718fd1f..8d261119eb0 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -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 // -- cgit v1.2.3