diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 9c4c6e72f9715..d19975c4792c0 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -5816,6 +5816,38 @@ if (BUSES["H89BUS"]~=null) then } end +--------------------------------------------------- +-- +--@src/devices/bus/heathzenith/h8/h8bus.h,BUSES["H8BUS"] = true +--------------------------------------------------- + +if (BUSES["H8BUS"]~=null) then + files { + MAME_DIR .. "src/devices/bus/heathzenith/h8/cards.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/cards.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/cpu8080.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/cpu8080.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/front_panel.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/front_panel.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h8bus.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h8bus.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h_8_1.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h_8_1.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h_8_5.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/h_8_5.h", + MAME_DIR .. "src/devices/bus/heathzenith/h8/wh_8_64.cpp", + MAME_DIR .. "src/devices/bus/heathzenith/h8/wh_8_64.h", + } + + dependency { + { MAME_DIR .. "src/devices/bus/heathzenith/h8/front_panel.cpp", GEN_DIR .. "emu/layout/h8_fp.lh" }, + } + + custombuildtask { + layoutbuildtask("emu/layout", "h8_fp"), + } +end + --------------------------------------------------- -- --@src/devices/bus/heathzenith/intr_cntrl/intr_cntrl.h,BUSES["HEATH_INTR_SOCKET"] = true diff --git a/src/devices/bus/heathzenith/h8/cards.cpp b/src/devices/bus/heathzenith/h8/cards.cpp new file mode 100644 index 0000000000000..a29a2fa7f96a1 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/cards.cpp @@ -0,0 +1,43 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Cards for the H8 Benton Harbor Bus + +***************************************************************************/ + +#include "emu.h" +#include "cards.h" + +#include "cpu8080.h" +#include "front_panel.h" +#include "h8bus.h" +#include "h_8_1.h" +#include "h_8_5.h" +#include "wh_8_64.h" + +// P1 is reserved for the Front Panel +void h8_p1_cards(device_slot_interface &device) +{ + device.option_add("fp", H8BUS_FRONT_PANEL); +} + +// P2 is reserved for the CPU board. +void h8_p2_cards(device_slot_interface &device) +{ + device.option_add("cpu8080", H8BUS_CPU_8080); +} + +// P10 is reserved for the HA-8-8 Extended Configuration Option card, which is +// required to run CP/M with the 8080 CPU board. +// TODO - add the HA-8-8 +void h8_p10_cards(device_slot_interface &device) +{ +} + +void h8_cards(device_slot_interface &device) +{ + device.option_add("h_8_1", H8BUS_H_8_1); + device.option_add("h_8_5", H8BUS_H_8_5); + device.option_add("wh_8_64", H8BUS_WH_8_64); +} diff --git a/src/devices/bus/heathzenith/h8/cards.h b/src/devices/bus/heathzenith/h8/cards.h new file mode 100644 index 0000000000000..c26d12d0701d5 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/cards.h @@ -0,0 +1,19 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Cards for the Heath H8 Benton Harbor Bus + +***************************************************************************/ + +#ifndef MAME_BUS_HEATHZENITH_H8_CARDS_H +#define MAME_BUS_HEATHZENITH_H8_CARDS_H + +#pragma once + +void h8_p1_cards(device_slot_interface &device) ATTR_COLD; +void h8_p2_cards(device_slot_interface &device) ATTR_COLD; +void h8_p10_cards(device_slot_interface &device) ATTR_COLD; +void h8_cards(device_slot_interface &device) ATTR_COLD; + +#endif // MAME_BUS_HEATHZENITH_H8_CARDS_H diff --git a/src/devices/bus/heathzenith/h8/cpu8080.cpp b/src/devices/bus/heathzenith/h8/cpu8080.cpp new file mode 100644 index 0000000000000..ae72b46e37195 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/cpu8080.cpp @@ -0,0 +1,344 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Heathkit 8080A CPU card + + Original 8080A 2.048MHz CPU board from Heath Company. + + + + Onboard Jumpers + + Label Default Emulated Description (if jumper is closed) + ------------------------------------------------------------------------- + B1-B2 Open Yes Allow /INT1 (INT 10) from the BH Bus (pin 8). + + C1-C2 Open Yes Allow /INT2 (Int 20) from the BH Bus (pin 9). + + E1-E2 Close No Allow inverted signal from J jumper to HOLD/HLDA on BH Bus (pin 25) + + F1-F2 Close No Allow /HOLD from the BH Bus (pin 27) to CPU Hold line. + + H1-H3 Open No Tie Ready-in from IC212 Generator to CPU Wait line + H2-H3 Close No Tie Ready-in from IC212 Generator to CPU Ready line + + J1-J2 Close No CPU HLDA out through flip-flop, use /Q output to E jumper + J2-J3 Open No CPU HLDA out through flip-flop, use Q output to E jumper + + K1-K2 Close No Affects Data-in/out buffers enabled signals based on /MEMR & /IOR signals + K1-K3 Open No Affects Data-in/out buffers enabled signals based on /MEMR & /IOR signals + + L1-L2 Close No Tie CPU /INTA to interrupt buffer + L2-L3 Open No Tie CPU /INTA to +12V + + P1-P2 Open No A10 to pin 19 of IC204 ROM + P2-P3 Close No R jumper to pin 19 of IC204 ROM + + R1-R2 Close No +12V selected + R2-R3 Open No S jumper selection selected + + S1-S2 Open No +5V selected + S2-S3 Close No GND selected + + T1-T2 Close No -5V to pin 21 of IC204 ROM + T2-T3 Open No +5V to pin 21 of IC204 ROM + + X1-X2 Open No Allow /ROM_Disable from BH bus (pin 46) to disable ROM + + Z1-Z2 Close No Tie /A10 to ROM decoder select line + Z2-Z3 Open No Tie +5V to ROM decoder select line + + RDYIN Close No Allow RDYIN from BH Bus (pin 20) to IC212 Generator + +****************************************************************************/ + +#include "emu.h" +#include "cpu8080.h" + +#include "bus/heathzenith/intr_cntrl/intr_cntrl.h" +#include "cpu/i8085/i8085.h" + + +namespace { + +class h_8_cpu_8080_device : public device_t, public device_h8bus_p2_card_interface +{ +public: + + h_8_cpu_8080_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + virtual void int1_w(int state) override; + virtual void int2_w(int state) override; + virtual void int3_w(int state) override; + virtual void int4_w(int state) override; + virtual void int5_w(int state) override; + virtual void int6_w(int state) override; + virtual void int7_w(int state) override; + + virtual void p201_reset_w(int state) override; + virtual void p201_int1_w(int state) override; + virtual void p201_int2_w(int state) override; + +protected: + + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + 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 handle_int1(); + void handle_int2(); + +private: + void h8_status_callback(u8 data); + void h8_inte_callback(int state); + + void mem_map(address_map &map) ATTR_COLD; + void io_map(address_map &map) ATTR_COLD; + + void bus_mem_w(offs_t offset, u8 data) { h8bus().space(AS_PROGRAM).write_byte(offset, data); } + u8 bus_mem_r(offs_t offset) { return h8bus().space(AS_PROGRAM).read_byte(offset); } + void bus_io_w(offs_t offset, u8 data) { h8bus().space(AS_IO).write_byte(offset, data); } + u8 bus_io_r(offs_t offset) { return h8bus().space(AS_IO).read_byte(offset); } + + required_device m_maincpu; + required_device m_intr_socket; + required_ioport m_config; + + bool m_m1_state; + bool m_allow_bus_int1; + bool m_allow_bus_int2; + bool m_p201_int1; + bool m_p201_int2; + bool m_bus_int1; + bool m_bus_int2; +}; + +h_8_cpu_8080_device::h_8_cpu_8080_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, H8BUS_CPU_8080, tag, owner, 0) + , device_h8bus_p2_card_interface(mconfig, *this) + , m_maincpu(*this, "maincpu") + , m_intr_socket(*this, "intr_socket") + , m_config(*this, "CONFIG") +{ +} + +void h_8_cpu_8080_device::h8_inte_callback(int state) +{ + set_p201_inte(state); +} + +void h_8_cpu_8080_device::h8_status_callback(u8 data) +{ + int state = (data & i8080_cpu_device::STATUS_M1) ? 1 : 0; + + if (state != m_m1_state) + { + set_slot_m1(state); + + m_m1_state = state; + } +} + +void h_8_cpu_8080_device::int1_w(int state) +{ + if (m_allow_bus_int1) + { + m_bus_int1 = bool(state); + + handle_int1(); + } +} + +void h_8_cpu_8080_device::int2_w(int state) +{ + if (m_allow_bus_int2) + { + m_bus_int2 = bool(state); + + handle_int2(); + } +} + +void h_8_cpu_8080_device::int3_w(int state) +{ + m_intr_socket->set_irq_level(3, state); +} + +void h_8_cpu_8080_device::int4_w(int state) +{ + m_intr_socket->set_irq_level(4, state); +} + +void h_8_cpu_8080_device::int5_w(int state) +{ + m_intr_socket->set_irq_level(5, state); +} + +void h_8_cpu_8080_device::int6_w(int state) +{ + m_intr_socket->set_irq_level(6, state); +} + +void h_8_cpu_8080_device::int7_w(int state) +{ + m_intr_socket->set_irq_level(7, state); +} + +void h_8_cpu_8080_device::p201_reset_w(int state) +{ + if (state) + { + m_maincpu->reset(); + } + + set_slot_reset(state); +} + +void h_8_cpu_8080_device::p201_int1_w(int state) +{ + m_p201_int1 = bool(state); + + handle_int1(); +} + +void h_8_cpu_8080_device::p201_int2_w(int state) +{ + m_p201_int2 = bool(state); + + handle_int2(); +} + +void h_8_cpu_8080_device::handle_int1() +{ + m_intr_socket->set_irq_level(1, (m_p201_int1 || m_bus_int1) ? ASSERT_LINE : CLEAR_LINE); + +} + +void h_8_cpu_8080_device::handle_int2() +{ + m_intr_socket->set_irq_level(2, (m_p201_int2 || m_bus_int2) ? ASSERT_LINE : CLEAR_LINE); +} + + +static void intr_ctrl_options(device_slot_interface &device) +{ + device.option_add("original", HEATH_INTR_CNTRL); +} + +void h_8_cpu_8080_device::mem_map(address_map &map) +{ + map.unmap_value_high(); + + // default mem access to h8bus + map(0x0000, 0xffff).rw(FUNC(h_8_cpu_8080_device::bus_mem_r), FUNC(h_8_cpu_8080_device::bus_mem_w)); + + map(0x0000, 0x0fff).rom(); // main rom + map(0x1400, 0x17ff).ram(); // fdc ram + map(0x1800, 0x1fff).rom(); // fdc rom +} + +void h_8_cpu_8080_device::io_map(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0xff); + + // default io access to h8bus + map(0x0000, 0xff).rw(FUNC(h_8_cpu_8080_device::bus_io_r), FUNC(h_8_cpu_8080_device::bus_io_w)); +} + + +// ROM definition +ROM_START( h8 ) + ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF ) + + // H17 fdc bios - needed by bios2&3 + ROM_LOAD( "2716_444-19_h17.rom", 0x1800, 0x0800, CRC(26e80ae3) SHA1(0c0ee95d7cb1a760f924769e10c0db1678f2435c)) + + ROM_SYSTEM_BIOS(0, "bios0", "Standard") + ROMX_LOAD( "2708_444-13_pam8.rom", 0x0000, 0x0400, CRC(e0745513) SHA1(0e170077b6086be4e5cd10c17e012c0647688c39), ROM_BIOS(0) ) + + ROM_SYSTEM_BIOS(1, "bios1", "Alternate") + ROMX_LOAD( "2708_444-13_pam8go.rom", 0x0000, 0x0400, CRC(9dbad129) SHA1(72421102b881706877f50537625fc2ab0b507752), ROM_BIOS(1) ) + + ROM_SYSTEM_BIOS(2, "bios2", "Disk OS") + ROMX_LOAD( "2716_444-13_pam8at.rom", 0x0000, 0x0800, CRC(fd95ddc1) SHA1(eb1f272439877239f745521139402f654e5403af), ROM_BIOS(2) ) + + ROM_SYSTEM_BIOS(3, "bios3", "Disk OS Alt") + ROMX_LOAD( "2732_444-70_xcon8.rom", 0x0000, 0x1000, CRC(b04368f4) SHA1(965244277a3a8039a987e4c3593b52196e39b7e7), ROM_BIOS(3) ) + + // this one runs off into the weeds + // - it is for the ZA-8-6 Z-80 replacement CPU card, keeping it here, until that card is implemented. + ROM_SYSTEM_BIOS(4, "bios4", "not working") + ROMX_LOAD( "2732_444-140_pam37.rom", 0x0000, 0x1000, CRC(53a540db) SHA1(90082d02ffb1d27e8172b11fff465bd24343486e), ROM_BIOS(4) ) +ROM_END + +static INPUT_PORTS_START( cpu_8080_jumpers ) + + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x00, "Allow INT1 signal on BH Bus - Jumper B1-B2") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x01, DEF_STR( Yes )) + PORT_CONFNAME(0x02, 0x00, "Allow INT2 signal on BH Bus - Jumper C1-C2") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x02, DEF_STR( Yes )) + +INPUT_PORTS_END + +ioport_constructor h_8_cpu_8080_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(cpu_8080_jumpers); +} + +const tiny_rom_entry *h_8_cpu_8080_device::device_rom_region() const +{ + return ROM_NAME(h8); +} + +void h_8_cpu_8080_device::device_start() +{ + save_item(NAME(m_m1_state)); + save_item(NAME(m_p201_int1)); + save_item(NAME(m_p201_int2)); + save_item(NAME(m_bus_int1)); + save_item(NAME(m_bus_int2)); + + h8bus().set_clock(m_maincpu->clock()); +} + +void h_8_cpu_8080_device::device_reset() +{ + m_m1_state = false; + m_p201_int1 = false; + m_p201_int2 = false; + m_bus_int1 = false; + m_bus_int2 = false; + + ioport_value const config(m_config->read()); + + m_allow_bus_int1 = bool(BIT(config, 0)); + m_allow_bus_int2 = bool(BIT(config, 1)); +} + +void h_8_cpu_8080_device::device_add_mconfig(machine_config &config) +{ + constexpr XTAL H8_CLOCK = XTAL(18'432'000) / 9; // 2.048 MHz + + I8080(config, m_maincpu, H8_CLOCK); + m_maincpu->set_addrmap(AS_PROGRAM, &h_8_cpu_8080_device::mem_map); + m_maincpu->set_addrmap(AS_IO, &h_8_cpu_8080_device::io_map); + m_maincpu->out_status_func().set(FUNC(h_8_cpu_8080_device::h8_status_callback)); + m_maincpu->out_inte_func().set(FUNC(h_8_cpu_8080_device::h8_inte_callback)); + m_maincpu->set_irq_acknowledge_callback("intr_socket", FUNC(heath_intr_socket::irq_callback)); + + HEATH_INTR_SOCKET(config, m_intr_socket, intr_ctrl_options, nullptr); + m_intr_socket->irq_line_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ0); + m_intr_socket->set_default_option("original"); + m_intr_socket->set_fixed(true); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(H8BUS_CPU_8080, device_h8bus_card_interface, h_8_cpu_8080_device, "h8_cpu_8080", "Heath 8080A CPU board"); diff --git a/src/devices/bus/heathzenith/h8/cpu8080.h b/src/devices/bus/heathzenith/h8/cpu8080.h new file mode 100644 index 0000000000000..16feaf6a1334b --- /dev/null +++ b/src/devices/bus/heathzenith/h8/cpu8080.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +#ifndef MAME_BUS_HEATHZENITH_H8_CPU8080_H +#define MAME_BUS_HEATHZENITH_H8_CPU8080_H + +#pragma once + +#include "h8bus.h" + +DECLARE_DEVICE_TYPE(H8BUS_CPU_8080, device_h8bus_card_interface) + +#endif // MAME_BUS_HEATHZENITH_H8_CPU8080_H diff --git a/src/devices/bus/heathzenith/h8/front_panel.cpp b/src/devices/bus/heathzenith/h8/front_panel.cpp new file mode 100644 index 0000000000000..5fb0e9bf75694 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/front_panel.cpp @@ -0,0 +1,350 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Heathkit H8 Front Panel card + +****************************************************************************/ + +#include "emu.h" +#include "front_panel.h" + +#include "machine/timer.h" +#include "sound/beep.h" +#include "speaker.h" + +#include "h8_fp.lh" + +#define LOG_PORT_W (1U << 1) +#define LOG_PORT_R (1U << 2) +#define LOG_SS (1U << 3) + +//#define VERBOSE (LOG_SS) + +#include "logmacro.h" + +#define LOGPORTW(...) LOGMASKED(LOG_PORT_W, __VA_ARGS__) +#define LOGPORTR(...) LOGMASKED(LOG_PORT_R, __VA_ARGS__) +#define LOGSS(...) LOGMASKED(LOG_SS, __VA_ARGS__) + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + + +class front_panel_device : public device_t, public device_h8bus_p1_card_interface +{ +public: + front_panel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + virtual void m1_w(int state) override; + virtual void p201_inte(int state) override; + + DECLARE_INPUT_CHANGED_MEMBER(button_0); + +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 portf0_r(); + void portf0_w(u8 data); + void portf1_w(u8 data); + + TIMER_DEVICE_CALLBACK_MEMBER(h8_irq_pulse); + + bool m_installed; + + u8 m_digit; + u8 m_segment; + u8 m_int_en; + bool m_ic108a; + bool m_ic108b; + bool m_allow_int1; + bool m_allow_int2; + + required_device m_beep; + required_ioport_array<2> m_io_keyboard; + output_finder<16> m_digits; + output_finder<> m_mon_led; + output_finder<> m_pwr_led; + output_finder<> m_ion_led; + output_finder<> m_run_led; +}; + + +front_panel_device::front_panel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, H8BUS_FRONT_PANEL, tag, owner, 0) + , device_h8bus_p1_card_interface(mconfig, *this) + , m_beep(*this, "beeper") + , m_io_keyboard(*this, "X%u", 0U) + , m_digits(*this, "digit%u", 0U) + , m_mon_led(*this, "mon_led") + , m_pwr_led(*this, "pwr_led") + , m_ion_led(*this, "ion_led") + , m_run_led(*this, "run_led") +{ +} + +void front_panel_device::m1_w(int state) +{ + // operate the RUN LED + m_run_led = !state; + + // For Single Instruction(SI) mode, there are 2 D flipflops, ic108a and ic108b. Both are held in + // set mode while not in SI mode. The data for ic108a is /INTE and ic108a Q is connected to data on + // ic108b. Both use /M1 for the clock. When the system is in SI mode, an int20 will trigger after + // after 2 M1 cycles, to pause the running program. + if (m_allow_int2) + { + LOGSS("%s: m_int_en: %d, state: %d\n", FUNCNAME, m_int_en, state); + + if (state) + { + m_ic108b = !m_ic108a; + m_ic108a = !m_int_en; + + if (m_ic108b) + { + set_p201_int2(ASSERT_LINE); + } + } + } +} + +void front_panel_device::p201_inte(int state) +{ + // Operate the ION LED + m_ion_led = !state; + + m_int_en = bool(state); +} + +u8 front_panel_device::portf0_r() +{ + u8 data = 0xff; + + // reads the keyboard + u8 keyin = m_io_keyboard[0]->read() ^ 0xff; + + if (keyin) + { + for (int i = 1; i < 8; i++) + { + if (BIT(keyin, i)) + { + data &= ~(i << 1); + } + } + + data &= 0xfe; + } + + keyin = m_io_keyboard[1]->read() ^ 0xff; + + if (keyin) + { + for (int i = 1; i < 8; i++) + { + if (BIT(keyin, i)) + { + data &= ~(i << 5); + } + } + + data &= 0xef; + } + + LOGPORTR("%s: val: 0x%02x\n", FUNCNAME, data); + + return data; +} + +void front_panel_device::portf0_w(u8 data) +{ + // bit description + // ---------------------- + // d0-d3 digit selected + // d4 inhibit int20 + // d5 mon led + // d6 allow int10 + // d7 beeper on + + LOGPORTW("%s: val: 0x%02x\n", FUNCNAME, data); + + // writes to this port always turn off int10 + set_p201_int1(CLEAR_LINE); + + m_digit = data & 0xf; + if (m_digit) + { + m_digits[m_digit] = m_segment; + } + + m_mon_led = !BIT(data, 5); + m_beep->set_state(!BIT(data, 7)); + + m_allow_int1 = BIT(data, 6); + + // Setup Single Instruction interrupt + bool old_allow_int2 = m_allow_int2; + + m_allow_int2 = bool(!BIT(data, 4)); + + if (old_allow_int2 != m_allow_int2) + { + LOGSS("%s: value changed: oldval: %d, allow_int2: %d\n", FUNCNAME, old_allow_int2, m_allow_int2); + + if (!m_allow_int2) + { + m_ic108a = true; + m_ic108b = false; + set_p201_int2(CLEAR_LINE); + } + } +} + +void front_panel_device::portf1_w(u8 data) +{ + // bit segment + // -------------- + // d7 dot + // d6 f + // d5 e + // d4 d + // d3 c + // d2 b + // d1 a + // d0 g + + LOGPORTW("%s: val: 0x%02x\n", FUNCNAME, data); + + m_segment = bitswap<8>(data, 7, 0, 6, 5, 4, 3, 2, 1) ^ 0xff; + + if (m_digit) + { + m_digits[m_digit] = m_segment; + } +} + +// Input ports +static INPUT_PORTS_START( h8 ) + PORT_START("X0") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(front_panel_device::button_0), 0) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("1 SP") PORT_CODE(KEYCODE_1) PORT_CHAR('1') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("2 AF") PORT_CODE(KEYCODE_2) PORT_CHAR('2') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("3 BC") PORT_CODE(KEYCODE_3) PORT_CHAR('3') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 DE GO") PORT_CODE(KEYCODE_4) PORT_CHAR('4') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("5 HL IN") PORT_CODE(KEYCODE_5) PORT_CHAR('5') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 PC OUT") PORT_CODE(KEYCODE_6) PORT_CHAR('6') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("7 SI") PORT_CODE(KEYCODE_7) PORT_CHAR('7') + + PORT_START("X1") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("8 LOAD") PORT_CODE(KEYCODE_8) PORT_CHAR('8') + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("9 DUMP") PORT_CODE(KEYCODE_9) PORT_CHAR('9') + PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_UP) PORT_CHAR('^') + PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_DOWN) PORT_CHAR('V') + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* CANCEL") PORT_CODE(KEYCODE_ESC) PORT_CHAR('Q') + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("/ ALTER RST") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("# MEM RTM") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(". REG") PORT_CODE(KEYCODE_R) PORT_CHAR('R') +INPUT_PORTS_END + +INPUT_CHANGED_MEMBER(front_panel_device::button_0) +{ + if (newval) + { + u8 data = m_io_keyboard[1]->read() ^ 0xff; + + if (BIT(data, 5)) + { + set_p201_reset(ASSERT_LINE); + } + else if (BIT(data, 6)) + { + set_p201_int1(ASSERT_LINE); + } + else + { + set_p201_reset(CLEAR_LINE); + set_p201_int1(CLEAR_LINE); + } + } +} + +void front_panel_device::device_start() +{ + m_digits.resolve(); + m_mon_led.resolve(); + m_pwr_led.resolve(); + m_ion_led.resolve(); + m_run_led.resolve(); + + m_installed = false; + m_digit = 0; + m_segment = 0; + + save_item(NAME(m_installed)); + save_item(NAME(m_digit)); + save_item(NAME(m_segment)); + save_item(NAME(m_ic108a)); + save_item(NAME(m_ic108b)); + save_item(NAME(m_int_en)); + save_item(NAME(m_allow_int1)); + save_item(NAME(m_allow_int2)); +} + +void front_panel_device::device_reset() +{ + m_allow_int1 = true; + m_allow_int2 = false; + m_int_en = false; + m_ic108a = true; + m_ic108b = false; + + // Note: 0 means on and 1 means off + m_pwr_led = 0; + m_run_led = 1; + m_ion_led = 1; + m_mon_led = 1; + + if (!m_installed) + { + h8bus().space(AS_IO).install_readwrite_handler(0xf0, 0xf0, + read8smo_delegate(*this, FUNC(front_panel_device::portf0_r)), + write8smo_delegate(*this, FUNC(front_panel_device::portf0_w))); + + h8bus().space(AS_IO).install_write_handler(0xf1, 0xf1, + write8smo_delegate(*this, FUNC(front_panel_device::portf1_w))); + + m_installed = true; + } +} + +void front_panel_device::device_add_mconfig(machine_config &config) +{ + config.set_default_layout(layout_h8_fp); + + SPEAKER(config, "mono").front_center(); + BEEP(config, m_beep, 1000).add_route(ALL_OUTPUTS, "mono", 1.00); + + TIMER(config, "h8_timer").configure_periodic(FUNC(front_panel_device::h8_irq_pulse), attotime::from_msec(2)); +} + +ioport_constructor front_panel_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(h8); +} + +TIMER_DEVICE_CALLBACK_MEMBER(front_panel_device::h8_irq_pulse) +{ + if (m_allow_int1) + { + set_p201_int1(ASSERT_LINE); + } +} + +DEFINE_DEVICE_TYPE_PRIVATE(H8BUS_FRONT_PANEL, device_h8bus_card_interface, front_panel_device, "h8_fp", "Heath H-8 Front Panel"); diff --git a/src/devices/bus/heathzenith/h8/front_panel.h b/src/devices/bus/heathzenith/h8/front_panel.h new file mode 100644 index 0000000000000..11fcb694077bf --- /dev/null +++ b/src/devices/bus/heathzenith/h8/front_panel.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +#ifndef MAME_BUS_HEATHZENITH_H8_FRONT_PANEL_H +#define MAME_BUS_HEATHZENITH_H8_FRONT_PANEL_H + +#pragma once + +#include "h8bus.h" + +DECLARE_DEVICE_TYPE(H8BUS_FRONT_PANEL, device_h8bus_card_interface) + +#endif // MAME_BUS_HEATHZENITH_H8_FRONT_PANEL_H diff --git a/src/devices/bus/heathzenith/h8/h8bus.cpp b/src/devices/bus/heathzenith/h8/h8bus.cpp new file mode 100644 index 0000000000000..1cfde422d8619 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h8bus.cpp @@ -0,0 +1,370 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + h8bus.cpp - Heath/Zenith H-8 bus + + Also known as the "Benton Harbor Bus" BHBus based on city where the + corporate headquarters were located. + +***************************************************************************/ + +#include "emu.h" + +#include "h8bus.h" + +#include +#include + +#define LOG_INIT (1U << 1) // Shows register setup + +//#define VERBOSE (LOG_INIT) + +#include "logmacro.h" + +#define LOGINIT(...) LOGMASKED(LOG_INIT, __VA_ARGS__) + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + + +device_h8bus_card_interface::device_h8bus_card_interface(const machine_config &mconfig, device_t &device) : + device_interface(device, "h8bus"), + m_h8bus(nullptr) +{ +} + +device_h8bus_card_interface::~device_h8bus_card_interface() +{ +} + +void device_h8bus_card_interface::interface_pre_start() +{ + if (!m_h8bus) + { + throw device_missing_dependencies(); + } +} + +device_h8bus_p1_card_interface::device_h8bus_p1_card_interface(const machine_config &mconfig, device_t &device): + device_h8bus_card_interface(mconfig, device) +{ +} + +device_h8bus_p1_card_interface::~device_h8bus_p1_card_interface() +{ +} + +device_h8bus_p2_card_interface::device_h8bus_p2_card_interface(const machine_config &mconfig, device_t &device) : + device_h8bus_card_interface(mconfig, device) +{ +} + +device_h8bus_p2_card_interface::~device_h8bus_p2_card_interface() +{ +} + +DEFINE_DEVICE_TYPE(H8BUS_SLOT, h8bus_slot_device, "h8bus_slot", "Heath H-8 slot") + +h8bus_slot_device::h8bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : h8bus_slot_device(mconfig, H8BUS_SLOT, tag, owner, clock) +{ +} + +h8bus_slot_device::h8bus_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_h8bus(*this, finder_base::DUMMY_TAG) + , m_h8bus_slottag(nullptr) +{ +} + +void h8bus_slot_device::device_start() +{ +} + +void h8bus_slot_device::device_resolve_objects() +{ + device_h8bus_card_interface *dev = get_card_device(); + + if (dev) + { + dev->set_h8bus_tag(m_h8bus.target(), m_h8bus_slottag); + unsigned slot_num = m_h8bus->add_h8bus_card(*dev); + dev->set_slot_num(slot_num); + } +} + + +DEFINE_DEVICE_TYPE(H8BUS, h8bus_device, "h8bus", "Heathkit H8 bus (Benton Harbor Bus)") + +h8bus_device::h8bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : h8bus_device(mconfig, H8BUS, tag, owner, clock) +{ +} + +h8bus_device::h8bus_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_memory_interface(mconfig, *this) + , m_mem_config("mem", ENDIANNESS_LITTLE, 16, 16, 0, address_map_constructor(FUNC(h8bus_device::mem_map), this)) + , m_io_config("io", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(h8bus_device::io_map), this)) + , m_p1_card(nullptr) + , m_p2_card(nullptr) +{ +} + +h8bus_device::~h8bus_device() +{ +} + +void h8bus_device::device_start() +{ +} + +void h8bus_device::device_reset() +{ + m_int1_slot_states = 0; + m_int2_slot_states = 0; + m_int3_slot_states = 0; + m_int4_slot_states = 0; + m_int5_slot_states = 0; + m_int6_slot_states = 0; + m_int7_slot_states = 0; + m_reset_slot_states = 0; + m_hold_slot_states = 0; + m_m1_slot_states = 0; +} + +void h8bus_device::mem_map(address_map &map) +{ + map.unmap_value_high(); +} + +void h8bus_device::io_map(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0xff); +} + +device_memory_interface::space_config_vector h8bus_device::memory_space_config() const +{ + return space_config_vector { std::make_pair(AS_PROGRAM, &m_mem_config), std::make_pair(AS_IO, &m_io_config) }; +} + +u8 h8bus_device::add_h8bus_card(device_h8bus_card_interface &card) +{ + m_device_list.emplace_back(card); + char* endptr; + long slot_num = strtol(&card.m_h8bus_slottag[1], &endptr, 10) - 1; + + if (slot_num < 0 || slot_num >= 31) + { + // if unable to determine slot number based on tag, set it to 31, + // so it will be in range. + slot_num = 31; + } + + LOGINIT("%s: added card to slot %d, tag: %s\n", FUNCNAME, slot_num, card.m_h8bus_slottag); + + if (strcmp(card.m_h8bus_slottag, "p1") == 0) + { + m_p1_card = (device_h8bus_p1_card_interface*) &card; + } + else if (strcmp(card.m_h8bus_slottag, "p2") == 0) + { + m_p2_card = (device_h8bus_p2_card_interface*) &card; + } + + return slot_num; +} + +bool h8bus_device::update_line_states(u32 &states, unsigned index, int state) +{ + bool const changed(bool(state) != bool(BIT(states, index))); + + if (changed) + { + int old_state = states ? 1 : 0; + + if (state) + { + states |= (1 << index); + } + else + { + states &= ~(1 << index); + } + + int new_state = states ? 1 : 0; + + return (old_state != new_state); + } + + return false; +} + +void h8bus_device::set_int1_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int1_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int1_w(m_int1_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int2_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int2_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int2_w(m_int2_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int3_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int3_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int3_w(m_int3_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int4_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int4_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int4_w(m_int4_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int5_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int5_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int5_w(m_int5_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int6_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int6_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int6_w(m_int6_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_int7_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_int7_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.int7_w(m_int7_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_reset_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_reset_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.reset_w(m_reset_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_hold_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_hold_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.hold_w(m_hold_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_m1_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_m1_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.m1_w(m_m1_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_disable_rom_line(unsigned index, int state) +{ + bool const changed = update_line_states(m_disable_rom_slot_states, index, state); + + if (changed) + { + for (device_h8bus_card_interface &entry : m_device_list) + { + entry.rom_disable_w(m_disable_rom_slot_states ? 1 : 0); + } + } +} + +void h8bus_device::set_p201_inte(int state) +{ + m_p1_card->p201_inte(state); +} + +void h8bus_device::set_p201_reset(int state) +{ + m_p2_card->p201_reset_w(state); +} + +void h8bus_device::set_p201_int1(int state) +{ + m_p2_card->p201_int1_w(state); +} + +void h8bus_device::set_p201_int2(int state) +{ + m_p2_card->p201_int2_w(state); +} diff --git a/src/devices/bus/heathzenith/h8/h8bus.h b/src/devices/bus/heathzenith/h8/h8bus.h new file mode 100644 index 0000000000000..e763394cdab00 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h8bus.h @@ -0,0 +1,412 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/********************************************************************* + + Heathkit H8 expansion slot + + Also referred to as Benton Harbor Bus. + +********************************************************************** + + Slot Cards + -------------------------------------------------------- + P1 Reserved for control/front panel board + P2 Reserved for CPU board + P3 - P9 Available + P10 Reserved for Expansion connector/HA-8-8 Extended Configuration Option + + + + pin P1 - P10 + -------------------------------- + 49 ------- +8V + 48 ------- +8V + 47 ------- +18V + 46 ------- /ROM DISABLE + 45 ------- /A15 + 44 ------- /A14 + 43 ------- /A13 + 42 ------- /A12 + 41 ------- /A11 + 40 ------- /A10 + 39 ------- /A9 + 38 ------- /A8 + 37 ------- /A7 + 36 ------- /A6 + 35 ------- /A5 + 34 ------- /A4 + 33 ------- /A3 + 32 ------- /A2 + 31 ------- /A1 + 30 ------- /A0 + 29 ------- /RESET + 28 ------- MEMR + 27 ------- /HOLD * + 26 ------- I/O R + 25 ------- HLDA * + + 24 ------- GND * + 23 ------- MEMW + 22 ------- O2 + 21 ------- I/O W + 20 ------- RDYIN * + 19 ------- M1 + 18 ------- GND * + 17 ------- /D7 + 16 ------- /D6 + 15 ------- /D5 + 14 ------- /D4 + 13 ------- /D3 + 12 ------- /D2 + 11 ------- /D1 + 10 ------- /D0 + 9 ------- /INT2 * + 8 ------- /INT1 * + 7 ------- /INT7 + 6 ------- /INT6 + 5 ------- /INT5 + 4 ------- /INT4 + 3 ------- /INT3 + 2 ------- -18V + 1 ------- GND + 0 ------- GND + + Notes: + * - Heath Company reserves the right to change these pin designations. + + + Signal Pin Direction Description + (wrt CPU board) + -------------------------------------------------------- + + A0-A15 30-45 Output Address bus + + D0-D7 10-17 Input/Output Data bus + + HOLD 27 Input Hold - request CPU hold state + + HLDA 25 Output Hold Acknowledge - CPU has gone into hold status, and Address bus and + Data bus are in high impedance state + + I/O R 26 Output I/O Read + + I/O W 21 Output I/O Write + + INT1-INT2 8-9 Input Interrupt 1-2 (10, 20) + + INT3-INT7 3-7 Input Interrupt 3-7 (30, 40, 50, 60, 70) + + M1 19 Output Machine cycle 1 - CPU fetch cycle of the first byte of an instruction + + MEMR 28 Output Memory Read + + MEMW 23 Output Memory Write + + ϕ2 22 Output Phase 2 clock + + RDYIN 20 Input Ready Input - Asynchronous wait request to the clock generator, generates + the synchronous READY signal. + + RESET 29 Input Reset - holds CPU in reset, also resets the INTE and HLDA flip-flops + + ROM DISABLE 46 Input ROM Disable - Disable the on-board ROM + + +18 V 47 +18 V Unregulated + +8 V 48,49 +8 V Unregulated + -18 V 2 -18 V Unregulated + GND 0,1 Ground + CPU GND 18,24 CPU Ground + + +*************************************************************************** + + P201 Cable + + Between P1 and P2 was a cable labeled P201 in the schematics. This connected + the Front Panel(P1) card to the CPU board(P2), providing dedicated signal lines + between the two boards. + + Signal Pin Direction Description + -------------------------------------------------------- + + GND 1 Ground + /INT2 (20) 2 P1 -> P2 Interrupt 20 + /INTE 3 P2 -> P1 Interrupts enabled. + /INT1 (10) 4 P1 -> P2 Interrupt 10 + /RESIN 5 P1 -> P2 Reset in, allowed keypad to initiate a reset of the computer + +***************************************************************************/ + +#ifndef MAME_BUS_HEATHZENITH_H8_H8BUS_H +#define MAME_BUS_HEATHZENITH_H8_H8BUS_H + +#pragma once +#include +#include +#include + + +class h8bus_device; + + +class device_h8bus_card_interface : public device_interface +{ + friend class h8bus_device; +public: + virtual ~device_h8bus_card_interface(); + + // signals from the Bus + virtual void int1_w(int state) {} + virtual void int2_w(int state) {} + virtual void int3_w(int state) {} + virtual void int4_w(int state) {} + virtual void int5_w(int state) {} + virtual void int6_w(int state) {} + virtual void int7_w(int state) {} + + virtual void m1_w(int state) {} + virtual void reset_w(int state) {} + virtual void hold_w(int state) {} + virtual void rom_disable_w(int state) {} + + void set_h8bus_tag(h8bus_device *h8bus, const char *slottag) { m_h8bus = h8bus; m_h8bus_slottag = slottag; } + void set_slot_num(u8 slot_num) { m_slot_num = slot_num; } + +protected: + device_h8bus_card_interface(const machine_config &mconfig, device_t &device); + virtual void interface_pre_start() override; + + void set_slot_int1(int state); + void set_slot_int2(int state); + void set_slot_int3(int state); + void set_slot_int4(int state); + void set_slot_int5(int state); + void set_slot_int6(int state); + void set_slot_int7(int state); + void set_slot_reset(int state); + void set_slot_hold(int state); + void set_slot_rom_disable(int state); + void set_slot_m1(int state); + + h8bus_device &h8bus() { assert(m_h8bus); return *m_h8bus; } + + const char *m_h8bus_slottag; + u8 m_slot_num; + +private: + h8bus_device *m_h8bus; +}; + +class device_h8bus_p1_card_interface : public device_h8bus_card_interface +{ +public: + virtual ~device_h8bus_p1_card_interface(); + + virtual void p201_inte(int state) {} + +protected: + device_h8bus_p1_card_interface(const machine_config &mconfig, device_t &device); + + void set_p201_reset(int state); + void set_p201_int1(int state); + void set_p201_int2(int state); +}; + + +class device_h8bus_p2_card_interface : public device_h8bus_card_interface +{ +public: + virtual ~device_h8bus_p2_card_interface(); + + // signals from P201 cable + virtual void p201_reset_w(int state) {} + virtual void p201_int1_w(int state) {} + virtual void p201_int2_w(int state) {} + +protected: + device_h8bus_p2_card_interface(const machine_config &mconfig, device_t &device); + + void set_p201_inte(int state); +}; + + +class h8bus_slot_device : public device_t, public device_single_card_slot_interface +{ +public: + template + h8bus_slot_device(const machine_config &mconfig, T &&tag, device_t *owner, const char *sltag, U &&opts, const char *dflt) + : h8bus_slot_device(mconfig, tag, owner, (uint32_t) 0) + { + option_reset(); + opts(*this); + set_default_option(dflt); + set_h8bus_slot(std::forward(sltag), tag); + } + + h8bus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template + void set_h8bus_slot(T &&tag, const char *slottag) + { + m_h8bus.set_tag(std::forward(tag)); + m_h8bus_slottag = slottag; + } + +protected: + h8bus_slot_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_resolve_objects() override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + + required_device m_h8bus; + const char *m_h8bus_slottag; +}; + +DECLARE_DEVICE_TYPE(H8BUS_SLOT, h8bus_slot_device) + + +class h8bus_device : public device_t, public device_memory_interface +{ + friend class h8bus_slot_device; + friend class device_h8bus_card_interface; + friend class device_h8bus_p1_card_interface; + friend class device_h8bus_p2_card_interface; + +public: + h8bus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + ~h8bus_device(); + +protected: + h8bus_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_memory_interface overrides + virtual space_config_vector memory_space_config() const override; + + u8 add_h8bus_card(device_h8bus_card_interface &card); + void set_int1_line(unsigned index, int state); + void set_int2_line(unsigned index, int state); + void set_int3_line(unsigned index, int state); + void set_int4_line(unsigned index, int state); + void set_int5_line(unsigned index, int state); + void set_int6_line(unsigned index, int state); + void set_int7_line(unsigned index, int state); + void set_reset_line(unsigned index, int state); + void set_hold_line(unsigned index, int state); + void set_disable_rom_line(unsigned index, int state); + void set_m1_line(unsigned index, int state); + + void set_p201_inte(int state); + void set_p201_reset(int state); + void set_p201_int1(int state); + void set_p201_int2(int state); + + bool update_line_states(u32 &states, unsigned index, int state); + + void mem_map(address_map &map); + void io_map(address_map &map); + +private: + u32 m_int1_slot_states; + u32 m_int2_slot_states; + u32 m_int3_slot_states; + u32 m_int4_slot_states; + u32 m_int5_slot_states; + u32 m_int6_slot_states; + u32 m_int7_slot_states; + u32 m_reset_slot_states; + u32 m_hold_slot_states; + u32 m_disable_rom_slot_states; + u32 m_m1_slot_states; + + address_space_config const m_mem_config; + address_space_config const m_io_config; + + std::vector> m_device_list; + + device_h8bus_p1_card_interface *m_p1_card; + device_h8bus_p2_card_interface *m_p2_card; +}; + + +inline void device_h8bus_card_interface::set_slot_int1(int state) +{ + h8bus().set_int1_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int2(int state) +{ + h8bus().set_int2_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int3(int state) +{ + h8bus().set_int3_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int4(int state) +{ + h8bus().set_int4_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int5(int state) +{ + h8bus().set_int5_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int6(int state) +{ + h8bus().set_int6_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_int7(int state) +{ + h8bus().set_int7_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_m1(int state) +{ + h8bus().set_m1_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_reset(int state) +{ + h8bus().set_reset_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_hold(int state) +{ + h8bus().set_hold_line(m_slot_num, state); +} + +inline void device_h8bus_card_interface::set_slot_rom_disable(int state) +{ + h8bus().set_disable_rom_line(m_slot_num, state); +} + +inline void device_h8bus_p1_card_interface::set_p201_reset(int state) +{ + h8bus().set_p201_reset(state); +} + +inline void device_h8bus_p1_card_interface::set_p201_int1(int state) +{ + h8bus().set_p201_int1(state); +} + +inline void device_h8bus_p1_card_interface::set_p201_int2(int state) +{ + h8bus().set_p201_int2(state); +} + +inline void device_h8bus_p2_card_interface::set_p201_inte(int state) +{ + h8bus().set_p201_inte(state); +} + +DECLARE_DEVICE_TYPE(H8BUS, h8bus_device) + + +#endif // MAME_BUS_HEATHZENITH_H8_H8BUS_H diff --git a/src/devices/bus/heathzenith/h8/h_8_1.cpp b/src/devices/bus/heathzenith/h8/h_8_1.cpp new file mode 100644 index 0000000000000..f2951ff03801f --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h_8_1.cpp @@ -0,0 +1,94 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Heathkit H-8-1 4k/8k Static RAM board + +****************************************************************************/ + +#include "emu.h" + +#include "h_8_1.h" + +#include "machine/ram.h" + +namespace { + +class h_8_1_device : public device_t, public device_h8bus_card_interface +{ +public: + + h_8_1_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; + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + + bool m_installed; + + memory_share_creator m_ram; + required_ioport m_jumpers; + required_ioport m_config; +}; + +h_8_1_device::h_8_1_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, H8BUS_H_8_1, tag, owner, 0) + , device_h8bus_card_interface(mconfig, *this) + , m_ram(*this, "ram", 0x2000U, ENDIANNESS_LITTLE) + , m_jumpers(*this, "JUMPERS") + , m_config(*this, "CONFIG") +{ +} + +void h_8_1_device::device_start() +{ + m_installed = false; + + save_item(NAME(m_installed)); +} + +void h_8_1_device::device_reset() +{ + if (!m_installed) + { + ioport_value const jumpers(m_jumpers->read()); + ioport_value const config(m_config->read()); + + u16 base_addr = (jumpers & 0x07) << 13; + u16 top_addr = base_addr + (BIT(config, 0) ? 0x1fff : 0x0fff); + + h8bus().space(AS_PROGRAM).install_ram(base_addr, top_addr, m_ram); + + m_installed = true; + } +} + +static INPUT_PORTS_START( h_8_1_jumpers ) + PORT_START("JUMPERS") + PORT_CONFNAME(0x07, 0x01, "Memory base address" ) + PORT_CONFSETTING( 0x00, "0k") + PORT_CONFSETTING( 0x01, "8k") + PORT_CONFSETTING( 0x02, "16k") + PORT_CONFSETTING( 0x03, "24k") + PORT_CONFSETTING( 0x04, "32k") + PORT_CONFSETTING( 0x05, "40k") + PORT_CONFSETTING( 0x06, "48k") + PORT_CONFSETTING( 0x07, "56k") + + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x01, "Memory installed") + PORT_CONFSETTING( 0x00, "4k") + PORT_CONFSETTING( 0x01, "8k") + +INPUT_PORTS_END + +ioport_constructor h_8_1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(h_8_1_jumpers); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(H8BUS_H_8_1, device_h8bus_card_interface, h_8_1_device, "h8_h_8_1", "Heath H-8-1 8k Static RAM"); diff --git a/src/devices/bus/heathzenith/h8/h_8_1.h b/src/devices/bus/heathzenith/h8/h_8_1.h new file mode 100644 index 0000000000000..fc1ff0427e9a3 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h_8_1.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +#ifndef MAME_BUS_HEATHZENITH_H8_H_8_1_H +#define MAME_BUS_HEATHZENITH_H8_H_8_1_H + +#pragma once + +#include "h8bus.h" + +DECLARE_DEVICE_TYPE(H8BUS_H_8_1, device_h8bus_card_interface) + +#endif // MAME_BUS_HEATHZENITH_H8_H_8_1_H diff --git a/src/devices/bus/heathzenith/h8/h_8_5.cpp b/src/devices/bus/heathzenith/h8/h_8_5.cpp new file mode 100644 index 0000000000000..1f4efd1e45e2c --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h_8_5.cpp @@ -0,0 +1,239 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Heathkit H-8-5 Serial I/O and Cassette Interface + +****************************************************************************/ + +#include "emu.h" + +#include "h_8_5.h" + +#include "imagedev/cassette.h" +#include "machine/clock.h" +#include "machine/i8251.h" +#include "machine/timer.h" +#include "bus/rs232/rs232.h" +#include "formats/h8_cas.h" + +#include "speaker.h" + +#define LOG_LINES (1U << 1) +#define LOG_CASS (1U << 2) +#define LOG_FUNC (1U << 3) +#define VERBOSE (0) + +#include "logmacro.h" + +#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 + +namespace { + +class h_8_5_device : public device_t, public device_h8bus_card_interface +{ +public: + + h_8_5_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; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + void uart_rts(u8 data); + void uart_tx_empty(u8 data); + void irq_callback(int state); + + TIMER_DEVICE_CALLBACK_MEMBER(kansas_r); + TIMER_DEVICE_CALLBACK_MEMBER(kansas_w); + + required_device m_uart; + required_device m_console; + required_device m_cass_player; + required_device m_cass_recorder; + + bool m_installed; + + u8 m_cass_data[4]; + bool m_cassbit; + bool m_cassold; +}; + +h_8_5_device::h_8_5_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, H8BUS_H_8_5, tag, owner, 0) + , device_h8bus_card_interface(mconfig, *this) + , m_uart(*this, "uart") + , m_console(*this, "console") + , m_cass_player(*this, "cassette_player") + , m_cass_recorder(*this, "cassette_recorder") +{ +} + +TIMER_DEVICE_CALLBACK_MEMBER(h_8_5_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(h_8_5_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 h_8_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 h_8_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 h_8_5_device::irq_callback(int state) +{ + LOGFUNC("%s: state: %d\n", FUNCNAME, state); + + set_slot_int3(state); +} + +void h_8_5_device::device_start() +{ + m_installed = false; + + save_item(NAME(m_installed)); + save_item(NAME(m_cass_data)); + save_item(NAME(m_cassbit)); + save_item(NAME(m_cassold)); +} + +void h_8_5_device::device_reset() +{ + LOGFUNC("%s\n", FUNCNAME); + + if (!m_installed) + { + h8bus().space(AS_IO).install_readwrite_handler(0xf8, 0xf9, + read8sm_delegate(m_uart, FUNC(i8251_device::read)), + write8sm_delegate(m_uart, FUNC(i8251_device::write))); + + h8bus().space(AS_IO).install_readwrite_handler(0xfa, 0xfb, + read8sm_delegate(m_console, FUNC(i8251_device::read)), + write8sm_delegate(m_console, FUNC(i8251_device::write))); + + m_installed = true; + } + // 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); +} + +// The usual baud rate is 600. The H8 supported baud rates from 110 to +// 9600. You can change the baud rate if it is changed here and in the +// other places that specify 600 baud. +static DEVICE_INPUT_DEFAULTS_START(terminal) + DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_600) + DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_600) + DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_8) + DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_NONE) + DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1) +DEVICE_INPUT_DEFAULTS_END + +void h_8_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(h_8_5_device::uart_rts)); + m_uart->txempty_handler().set(FUNC(h_8_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)); + cassette_clock.signal_handler().append(m_uart, FUNC(i8251_device::write_rxc)); + + I8251(config, m_console, 0); + + m_console->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd)); + m_console->rts_handler().set("rs232", FUNC(rs232_port_device::write_rts)); + m_console->dtr_handler().set("rs232", FUNC(rs232_port_device::write_dtr)); + // The RxRdy pin on the 8251 USART is normally jumpered to generate a level 3 i/o interrupt. + m_console->rxrdy_handler().set(FUNC(h_8_5_device::irq_callback)); + + // Console UART clock is 16X the baud rate. + clock_device &console_clock(CLOCK(config, "console_clock", 600*16)); + console_clock.signal_handler().set(m_console, FUNC(i8251_device::write_txc)); + console_clock.signal_handler().append(m_console, FUNC(i8251_device::write_rxc)); + + rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal")); + rs232.rxd_handler().set(m_console, FUNC(i8251_device::write_rxd)); + rs232.cts_handler().set(m_console, FUNC(i8251_device::write_cts)); + rs232.dsr_handler().set(m_console, FUNC(i8251_device::write_dsr)); + rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); + + 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("h8_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("h8_cass_recorder"); + + TIMER(config, "kansas_w").configure_periodic(FUNC(h_8_5_device::kansas_w), attotime::from_hz(4800)); + TIMER(config, "kansas_r").configure_periodic(FUNC(h_8_5_device::kansas_r), attotime::from_hz(40000)); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(H8BUS_H_8_5, device_h8bus_card_interface, h_8_5_device, "h8_h_8_5", "Heath H-8-5 Serial/Casette Card"); diff --git a/src/devices/bus/heathzenith/h8/h_8_5.h b/src/devices/bus/heathzenith/h8/h_8_5.h new file mode 100644 index 0000000000000..c47c5a95d16b6 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/h_8_5.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +#ifndef MAME_BUS_HEATHZENITH_H8_H_8_5_H +#define MAME_BUS_HEATHZENITH_H8_H_8_5_H + +#pragma once + +#include "h8bus.h" + +DECLARE_DEVICE_TYPE(H8BUS_H_8_5, device_h8bus_card_interface) + +#endif // MAME_BUS_HEATHZENITH_H8_H_8_5_H diff --git a/src/devices/bus/heathzenith/h8/wh_8_64.cpp b/src/devices/bus/heathzenith/h8/wh_8_64.cpp new file mode 100644 index 0000000000000..54e3f924c5c93 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/wh_8_64.cpp @@ -0,0 +1,269 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +/*************************************************************************** + + Heathkit WH-8-64 32k/64k Dynamic RAM board + +****************************************************************************/ + +#include "emu.h" + +#include "wh_8_64.h" + +#include "machine/ram.h" + +#include +#include + +#define LOG_SW (1U << 1) // Shows register setup + +//#define VERBOSE (LOG_SW) + +#include "logmacro.h" + +#define LOGSW(...) LOGMASKED(LOG_SW, __VA_ARGS__) + +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + +namespace { + +class wh_8_64_device : public device_t, public device_h8bus_card_interface +{ +public: + + wh_8_64_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + +protected: + + virtual ioport_constructor device_input_ports() const override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + std::vector get_addr(u8 sw); + + void install_mem_bank(u8 bank); + + bool m_installed; + + memory_share_array_creator m_ram; + required_ioport_array<4> m_sw; + required_ioport m_config; +}; + + +wh_8_64_device::wh_8_64_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, H8BUS_WH_8_64, tag, owner, 0) + , device_h8bus_card_interface(mconfig, *this) + , m_ram(*this, "rambank%u", 0U, 0x2000U, ENDIANNESS_LITTLE) + , m_sw(*this, "SW%u", 1U) + , m_config(*this, "CONFIG") +{ +} + +void wh_8_64_device::device_start() +{ + m_installed = false; + + save_item(NAME(m_installed)); +} + +void wh_8_64_device::device_reset() +{ + if (!m_installed) + { + ioport_value const config(m_config->read()); + + if (BIT(config, 0)) + { + install_mem_bank(0); + } + if (BIT(config, 1)) + { + install_mem_bank(1); + } + if (BIT(config, 2)) + { + install_mem_bank(2); + } + if (BIT(config, 3)) + { + install_mem_bank(3); + } + + m_installed = true; + } +} + +std::vector wh_8_64_device::get_addr(u8 sw) +{ + std::vector result; + + u8 sw_value = m_sw[sw]->read(); + + for (int i = 0; i < 8; i++) { + if (BIT(sw_value, i)) + { + result.push_back(i * 0x2000); + } + } + + return result; +} + +void wh_8_64_device::install_mem_bank(u8 bank) +{ + std::vector addresses = get_addr(3 - bank); + + // each switch defines where to start each 8k block of the + // 16k bank. Per manual only 2 should be set. Ensure setting + // a max of 2 blocks are defined even if it is just selecting + // the first 2. + int num_addresses = std::min((int) addresses.size(), 2); + int block = bank << 1; + + for (int i = 0; i < num_addresses; i++) + { + int addr = addresses[i]; + + LOGSW("Installing block %d at 0x%04x\n", block, addr); + + h8bus().space(AS_PROGRAM).install_ram(addr, addr + 0x1fff, m_ram[block++]); + } +} + +static INPUT_PORTS_START( wh_8_64 ) + PORT_START("SW1") + // TODO: Properly map the last 8k, needs an HA-8-6 Z80 CPU or HA-8-8 Extended + // Configuration board to handle the ROM/RAM swap. Only one switch is set to 1 + // on SW1. + PORT_DIPNAME( 0x01, 0x00, "Bank 3 - Address Block 0k - 8k") PORT_DIPLOCATION("SW1:1") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "Bank 3 - Address Block 8k - 16k") PORT_DIPLOCATION("SW1:2") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "Bank 3 - Address Block 16k - 24k") PORT_DIPLOCATION("SW1:3") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "Bank 3 - Address Block 24k - 32k") PORT_DIPLOCATION("SW1:4") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "Bank 3 - Address Block 32k - 40k") PORT_DIPLOCATION("SW1:5") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "Bank 3 - Address Block 40k - 48k") PORT_DIPLOCATION("SW1:6") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "Bank 3 - Address Block 48k - 56k") PORT_DIPLOCATION("SW1:7") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x80, "Bank 3 - Address Block 56k - 64k") PORT_DIPLOCATION("SW1:8") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START("SW2") + PORT_DIPNAME( 0x01, 0x00, "Bank 2 - Address Block 0k - 8k") PORT_DIPLOCATION("SW2:1") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "Bank 2 - Address Block 8k - 16k") PORT_DIPLOCATION("SW2:2") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "Bank 2 - Address Block 16k - 24k") PORT_DIPLOCATION("SW2:3") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "Bank 2 - Address Block 24k - 32k") PORT_DIPLOCATION("SW2:4") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "Bank 2 - Address Block 32k - 40k") PORT_DIPLOCATION("SW2:5") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x20, "Bank 2 - Address Block 40k - 48k") PORT_DIPLOCATION("SW2:6") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x40, "Bank 2 - Address Block 48k - 56k") PORT_DIPLOCATION("SW2:7") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "Bank 2 - Address Block 56k - 64k") PORT_DIPLOCATION("SW2:8") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START("SW3") + PORT_DIPNAME( 0x01, 0x00, "Bank 1 - Address Block 0k - 8k") PORT_DIPLOCATION("SW3:1") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x00, "Bank 1 - Address Block 8k - 16k") PORT_DIPLOCATION("SW3:2") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x00, "Bank 1 - Address Block 16k - 24k") PORT_DIPLOCATION("SW3:3") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x08, "Bank 1 - Address Block 24k - 32k") PORT_DIPLOCATION("SW3:4") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x10, "Bank 1 - Address Block 32k - 40k") PORT_DIPLOCATION("SW3:5") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "Bank 1 - Address Block 40k - 48k") PORT_DIPLOCATION("SW3:6") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "Bank 1 - Address Block 48k - 56k") PORT_DIPLOCATION("SW3:7") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "Bank 1 - Address Block 56k - 64k") PORT_DIPLOCATION("SW3:8") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START("SW4") + PORT_DIPNAME( 0x01, 0x00, "Bank 0 - Address Block 0k - 8k") PORT_DIPLOCATION("SW4:1") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x01, DEF_STR( On ) ) + PORT_DIPNAME( 0x02, 0x02, "Bank 0 - Address Block 8k - 16k") PORT_DIPLOCATION("SW4:2") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x02, DEF_STR( On ) ) + PORT_DIPNAME( 0x04, 0x04, "Bank 0 - Address Block 16k - 24k") PORT_DIPLOCATION("SW4:3") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x04, DEF_STR( On ) ) + PORT_DIPNAME( 0x08, 0x00, "Bank 0 - Address Block 24k - 32k") PORT_DIPLOCATION("SW4:4") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x08, DEF_STR( On ) ) + PORT_DIPNAME( 0x10, 0x00, "Bank 0 - Address Block 32k - 40k") PORT_DIPLOCATION("SW4:5") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x10, DEF_STR( On ) ) + PORT_DIPNAME( 0x20, 0x00, "Bank 0 - Address Block 40k - 48k") PORT_DIPLOCATION("SW4:6") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x20, DEF_STR( On ) ) + PORT_DIPNAME( 0x40, 0x00, "Bank 0 - Address Block 48k - 56k") PORT_DIPLOCATION("SW4:7") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x40, DEF_STR( On ) ) + PORT_DIPNAME( 0x80, 0x00, "Bank 0 - Address Block 56k - 64k") PORT_DIPLOCATION("SW4:8") + PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x80, DEF_STR( On ) ) + + PORT_START("CONFIG") + PORT_CONFNAME(0x01, 0x01, "Memory Bank 0 Present") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x01, DEF_STR( Yes )) + PORT_CONFNAME(0x02, 0x02, "Memory Bank 1 Present") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x02, DEF_STR( Yes )) + PORT_CONFNAME(0x04, 0x04, "Memory Bank 2 Present") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x04, DEF_STR( Yes )) + PORT_CONFNAME(0x08, 0x08, "Memory Bank 3 Present") + PORT_CONFSETTING( 0x00, DEF_STR( No )) + PORT_CONFSETTING( 0x08, DEF_STR( Yes )) + +INPUT_PORTS_END + +ioport_constructor wh_8_64_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(wh_8_64); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(H8BUS_WH_8_64, device_h8bus_card_interface, wh_8_64_device, "wh8_h_8_64", "Heath WH-8-64 64k Dynamic RAM"); diff --git a/src/devices/bus/heathzenith/h8/wh_8_64.h b/src/devices/bus/heathzenith/h8/wh_8_64.h new file mode 100644 index 0000000000000..b3dfee3c66414 --- /dev/null +++ b/src/devices/bus/heathzenith/h8/wh_8_64.h @@ -0,0 +1,12 @@ +// license:BSD-3-Clause +// copyright-holders:Mark Garlanger +#ifndef MAME_BUS_HEATHZENITH_H8_WH_8_64_H +#define MAME_BUS_HEATHZENITH_H8_WH_8_64_H + +#pragma once + +#include "h8bus.h" + +DECLARE_DEVICE_TYPE(H8BUS_WH_8_64, device_h8bus_card_interface) + +#endif // MAME_BUS_HEATHZENITH_H8_WH_8_64_H diff --git a/src/mame/layout/h8.lay b/src/emu/layout/h8_fp.lay similarity index 100% rename from src/mame/layout/h8.lay rename to src/emu/layout/h8_fp.lay diff --git a/src/mame/heathzenith/h8.cpp b/src/mame/heathzenith/h8.cpp index 0583cd9985f75..e3bf9cc6e507a 100644 --- a/src/mame/heathzenith/h8.cpp +++ b/src/mame/heathzenith/h8.cpp @@ -1,41 +1,41 @@ // license:BSD-3-Clause -// copyright-holders:Robbbert +// copyright-holders:Mark Garlanger /*************************************************************************** - Heathkit H8 + Heathkit H8 - 2009-05-12 Skeleton driver. + This system uses Octal and Split-Octal rather than the usual hexadecimal. - This system uses Octal rather than the usual hexadecimal. - -STATUS: + STATUS: It runs, keyboard works, you can enter data. Serial console works. You can make it visible by setting Video Options in settings. -Meaning of LEDs: - PWR = power is turned on - MON = controls should work + Meaning of LEDs: + PWR = Power is turned on (+5V is present at on front panel) + MON = The front panel is being serviced by the cpu (controls should work) RUN = CPU is running (not halted) ION = Interrupts are enabled -Pasting: - 0-F : as is - + : ^ - - : V - MEM : - - ALTER : = + Pasting: + H8 | mame key + ----------------------- + 0-F | as is + + | ^ + - | V + MEM | - + ALTER | = Addresses must have all 6 digits entered. Data must have all 3 digits entered. System has a short beep for each key, and a slightly longer beep for each group of 3 digits. The largest number allowed is 377 (=0xFF). -Test Paste: + Test Paste: -041000=123 245 333 144 255 366 077=-041000 Now press up-arrow to confirm the data has been entered. -Official test program from pages 4 to 8 of the operator's manual: + Official test program from pages 4 to 8 of the operator's manual: -040100=076 002 062 010 040 006 004 041 170 040 021 013 040 016 011 176 022 043 023 015 302 117 040 016 003 076 377 315 053 000 015 302 131 040 005 302 112 040 076 062 315 140 002 076 062 315 053 000 @@ -43,25 +43,12 @@ Official test program from pages 4 to 8 of the operator's manual: 377 237 244 377 272 230 377 220 326 302 377 275 272 271 271 373 271 240 377 236 376 362 236 376 362 236 376 362 R6=040100=4 - ****************************************************************************/ #include "emu.h" -#include "bus/heathzenith/intr_cntrl/intr_cntrl.h" -#include "bus/rs232/rs232.h" -#include "cpu/i8085/i8085.h" -#include "imagedev/cassette.h" -#include "machine/clock.h" -#include "machine/i8251.h" -#include "machine/timer.h" -#include "sound/beep.h" - -#include "speaker.h" - -#include "formats/h8_cas.h" - -#include "h8.lh" +#include "bus/heathzenith/h8/cards.h" +#include "bus/heathzenith/h8/h8bus.h" namespace { @@ -70,411 +57,49 @@ class h8_state : public driver_device public: h8_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - , m_intr_socket(*this, "intr_socket") - , m_uart(*this, "uart") - , m_console(*this, "console") - , m_cass(*this, "cassette") - , m_beep(*this, "beeper") - , m_io_keyboard(*this, "X%u", 0U) - , m_digits(*this, "digit%u", 0U) - , m_mon_led(*this, "mon_led") - , m_pwr_led(*this, "pwr_led") - , m_ion_led(*this, "ion_led") - , m_run_led(*this, "run_led") - { } + , m_h8bus(*this, "h8bus") + {} void h8(machine_config &config); - DECLARE_INPUT_CHANGED_MEMBER(button_0); - protected: - virtual void machine_reset() override ATTR_COLD; virtual void machine_start() override ATTR_COLD; private: - u8 portf0_r(); - void portf0_w(u8 data); - void portf1_w(u8 data); - void h8_status_callback(u8 data); - void h8_inte_callback(int state); - void h8_level3_irq_callback(int state); - TIMER_DEVICE_CALLBACK_MEMBER(h8_irq_pulse); - TIMER_DEVICE_CALLBACK_MEMBER(kansas_r); - TIMER_DEVICE_CALLBACK_MEMBER(kansas_w); - - void io_map(address_map &map) ATTR_COLD; - void mem_map(address_map &map) ATTR_COLD; - - u8 m_digit = 0U; - u8 m_segment = 0U; - u8 m_irq_ctl = 0U; - bool m_ff_b = 0; - u8 m_cass_data[4]{}; - bool m_cassbit = 0; - bool m_cassold = 0; - - // clocks - static constexpr XTAL H8_CLOCK = XTAL(12'288'000) / 6; // 2.048 MHz - static constexpr XTAL H8_BEEP_FRQ = H8_CLOCK / 2048; // 1 kHz - static constexpr XTAL H8_IRQ_PULSE = H8_BEEP_FRQ / 2; - - required_device m_maincpu; - required_device m_intr_socket; - required_device m_uart; - required_device m_console; - required_device m_cass; - required_device m_beep; - required_ioport_array<2> m_io_keyboard; - output_finder<16> m_digits; - output_finder<> m_mon_led; - output_finder<> m_pwr_led; - output_finder<> m_ion_led; - output_finder<> m_run_led; + required_device m_h8bus; }; -// The usual baud rate is 600. The H8 supported baud rates from 110 to -// 9600. You can change the baud rate if it is changed here and in the -// other places that specify 600 baud. -static DEVICE_INPUT_DEFAULTS_START(terminal) - DEVICE_INPUT_DEFAULTS("RS232_RXBAUD", 0xff, RS232_BAUD_600) - DEVICE_INPUT_DEFAULTS("RS232_TXBAUD", 0xff, RS232_BAUD_600) - DEVICE_INPUT_DEFAULTS("RS232_DATABITS", 0xff, RS232_DATABITS_8) - DEVICE_INPUT_DEFAULTS("RS232_PARITY", 0xff, RS232_PARITY_NONE) - DEVICE_INPUT_DEFAULTS("RS232_STOPBITS", 0xff, RS232_STOPBITS_1) -DEVICE_INPUT_DEFAULTS_END - -TIMER_DEVICE_CALLBACK_MEMBER(h8_state::h8_irq_pulse) -{ - if (BIT(m_irq_ctl, 0)) - { - m_intr_socket->set_irq_level(1, ASSERT_LINE); - } -} - -u8 h8_state::portf0_r() -{ - // reads the keyboard - - // The following not emulated, can occur any time even if keyboard not being scanned - // - if 0 and RTM pressed, causes int10 - // - if 0 and RST pressed, resets cpu - - u8 i,keyin,data = 0xff; - - keyin = m_io_keyboard[0]->read(); - if (keyin != 0xff) - { - for (i = 1; i < 8; i++) - if (!BIT(keyin,i)) - data &= ~(i<<1); - data &= 0xfe; - } - - keyin = m_io_keyboard[1]->read(); - if (keyin != 0xff) - { - for (i = 1; i < 8; i++) - if (!BIT(keyin,i)) - data &= ~(i<<5); - data &= 0xef; - } - return data; -} - -void h8_state::portf0_w(u8 data) -{ - // this will always turn off int10 that was set by the timer - // d0-d3 = digit select - // d4 = int20 is allowed - // d5 = mon led - // d6 = int10 is allowed - // d7 = beeper enable - - m_digit = data & 15; - if (m_digit) m_digits[m_digit] = m_segment; - - m_mon_led = !BIT(data, 5); - m_beep->set_state(!BIT(data, 7)); - - m_intr_socket->set_irq_level(1, CLEAR_LINE); - - m_irq_ctl &= 0xf0; - if (BIT(data, 6)) m_irq_ctl |= 1; - if (!BIT(data, 4)) m_irq_ctl |= 2; -} - -void h8_state::portf1_w(u8 data) -{ - //d7 segment dot - //d6 segment f - //d5 segment e - //d4 segment d - //d3 segment c - //d2 segment b - //d1 segment a - //d0 segment g - - m_segment = 0xff ^ bitswap<8>(data, 7, 0, 6, 5, 4, 3, 2, 1); - if (m_digit) m_digits[m_digit] = m_segment; -} - -void h8_state::mem_map(address_map &map) -{ - map.unmap_value_high(); - map(0x0000, 0x0fff).rom(); // main rom - map(0x1400, 0x17ff).ram(); // fdc ram - map(0x1800, 0x1fff).rom(); // fdc rom - map(0x2000, 0x9fff).ram(); // main ram -} - -void h8_state::io_map(address_map &map) -{ - map.unmap_value_high(); - map.global_mask(0xff); - map(0xf0, 0xf0).rw(FUNC(h8_state::portf0_r), FUNC(h8_state::portf0_w)); - map(0xf1, 0xf1).w(FUNC(h8_state::portf1_w)); - map(0xf8, 0xf9).rw(m_uart, FUNC(i8251_device::read), FUNC(i8251_device::write)); - // Connection to a serial terminal @ 600 baud - map(0xfa, 0xfb).rw(m_console, FUNC(i8251_device::read), FUNC(i8251_device::write)); -} - -/* Input ports */ +// Input ports static INPUT_PORTS_START( h8 ) - PORT_START("X0") - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(h8_state::button_0), 0) - PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("1 SP") PORT_CODE(KEYCODE_1) PORT_CHAR('1') - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("2 AF") PORT_CODE(KEYCODE_2) PORT_CHAR('2') - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("3 BC") PORT_CODE(KEYCODE_3) PORT_CHAR('3') - PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("4 DE GO") PORT_CODE(KEYCODE_4) PORT_CHAR('4') - PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("5 HL IN") PORT_CODE(KEYCODE_5) PORT_CHAR('5') - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("6 PC OUT") PORT_CODE(KEYCODE_6) PORT_CHAR('6') - PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("7 SI") PORT_CODE(KEYCODE_7) PORT_CHAR('7') - - PORT_START("X1") - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("8 LOAD") PORT_CODE(KEYCODE_8) PORT_CHAR('8') - PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("9 DUMP") PORT_CODE(KEYCODE_9) PORT_CHAR('9') - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("+") PORT_CODE(KEYCODE_UP) PORT_CHAR('^') - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_DOWN) PORT_CHAR('V') - PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* CANCEL") PORT_CODE(KEYCODE_ESC) PORT_CHAR('Q') - PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("/ ALTER RST") PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("# MEM RTM") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') - PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(". REG") PORT_CODE(KEYCODE_R) PORT_CHAR('R') INPUT_PORTS_END -INPUT_CHANGED_MEMBER(h8_state::button_0) -{ - if (newval) - { - u8 data = m_io_keyboard[1]->read() ^ 0xff; - if (BIT(data, 5)) - { - m_maincpu->reset(); - } - else if (BIT(data, 6)) - { - m_intr_socket->set_irq_level(1, ASSERT_LINE); - } - } -} - -void h8_state::machine_reset() -{ - m_pwr_led = 0; - m_irq_ctl = 1; - m_cassbit = 1; - m_cass_data[0] = 0; - m_cass_data[1] = 0; - m_uart->write_cts(0); - m_uart->write_dsr(0); - m_uart->write_rxd(0); - m_cass_data[3] = 0; - m_ff_b = 1; -} - void h8_state::machine_start() { - m_digits.resolve(); - m_mon_led.resolve(); - m_pwr_led.resolve(); - m_ion_led.resolve(); - m_run_led.resolve(); - - save_item(NAME(m_digit)); - save_item(NAME(m_segment)); - save_item(NAME(m_irq_ctl)); - save_item(NAME(m_ff_b)); - save_item(NAME(m_cass_data)); - save_item(NAME(m_cassbit)); - save_item(NAME(m_cassold)); -} - -void h8_state::h8_inte_callback(int state) -{ - // operate the ION LED - m_ion_led = !state; - m_irq_ctl &= 0x7f | ((state) ? 0 : 0x80); -} - -void h8_state::h8_status_callback(u8 data) -{ -/* This is rather messy, but basically there are 2 D flipflops, one drives the other, -the data is /INTE while the clock is /M1. If the system is in Single Instruction mode, -a int20 (output of 2nd flipflop) will occur after 4 M1 steps, to pause the running program. -But, all of this can only occur if bit 4 of port F0 is low. */ - - bool state = (data & i8080_cpu_device::STATUS_M1) ? 0 : 1; - bool c,a = BIT(m_irq_ctl, 7); - - if (BIT(m_irq_ctl, 1)) - { - if (!state) // rising pulse to push data through flipflops - { - c = !m_ff_b; // from /Q of 2nd flipflop - m_ff_b = a; // from Q of 1st flipflop - if (c) - { - m_intr_socket->set_irq_level(2, ASSERT_LINE); - } - } - } - else - { // flipflops are 'set' - c = 0; - m_ff_b = 1; - } - - - // operate the RUN LED - m_run_led = state; -} - -void h8_state::h8_level3_irq_callback(int state) -{ - m_intr_socket->set_irq_level(3, state); -} - -TIMER_DEVICE_CALLBACK_MEMBER(h8_state::kansas_w) -{ - m_cass_data[3]++; - - if (m_cassbit != m_cassold) - { - m_cass_data[3] = 0; - m_cassold = m_cassbit; - } - - if (m_cassbit) - m_cass->output(BIT(m_cass_data[3], 0) ? -1.0 : +1.0); // 2400Hz - else - m_cass->output(BIT(m_cass_data[3], 1) ? -1.0 : +1.0); // 1200Hz -} - -TIMER_DEVICE_CALLBACK_MEMBER(h8_state::kansas_r) -{ - /* cassette - turn 1200/2400Hz to a bit */ - m_cass_data[1]++; - u8 cass_ws = (m_cass->input() > +0.03) ? 1 : 0; - - if (cass_ws != m_cass_data[0]) - { - m_cass_data[0] = cass_ws; - m_uart->write_rxd((m_cass_data[1] < 12) ? 1 : 0); - m_cass_data[1] = 0; - } -} - -static void intr_ctrl_options(device_slot_interface &device) -{ - device.option_add("original", HEATH_INTR_CNTRL); } void h8_state::h8(machine_config &config) { - /* basic machine hardware */ - I8080(config, m_maincpu, H8_CLOCK); - m_maincpu->set_addrmap(AS_PROGRAM, &h8_state::mem_map); - m_maincpu->set_addrmap(AS_IO, &h8_state::io_map); - m_maincpu->out_status_func().set(FUNC(h8_state::h8_status_callback)); - m_maincpu->out_inte_func().set(FUNC(h8_state::h8_inte_callback)); - m_maincpu->set_irq_acknowledge_callback("intr_socket", FUNC(heath_intr_socket::irq_callback)); - - /* video hardware */ - config.set_default_layout(layout_h8); - - HEATH_INTR_SOCKET(config, m_intr_socket, intr_ctrl_options, nullptr); - m_intr_socket->irq_line_cb().set_inputline(m_maincpu, INPUT_LINE_IRQ0); - m_intr_socket->set_default_option("original"); - m_intr_socket->set_fixed(true); - - /* sound hardware */ - SPEAKER(config, "mono").front_center(); - BEEP(config, m_beep, H8_BEEP_FRQ).add_route(ALL_OUTPUTS, "mono", 1.00); - - /* Devices */ - I8251(config, m_uart, 0); - m_uart->txd_handler().set([this] (bool state) { m_cassbit = state; }); - - I8251(config, m_console, 0); - m_console->txd_handler().set("rs232", FUNC(rs232_port_device::write_txd)); - m_console->rts_handler().set("rs232", FUNC(rs232_port_device::write_rts)); - m_console->dtr_handler().set("rs232", FUNC(rs232_port_device::write_dtr)); - // The RxRdy pin on the 8251 USART is normally jumpered to generate a level 3 i/o interrupt. - m_console->rxrdy_handler().set(FUNC(h8_state::h8_level3_irq_callback)); + H8BUS(config, m_h8bus, 0); - rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal")); - rs232.rxd_handler().set(m_console, FUNC(i8251_device::write_rxd)); - rs232.cts_handler().set(m_console, FUNC(i8251_device::write_cts)); - rs232.dsr_handler().set(m_console, FUNC(i8251_device::write_dsr)); - rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal)); - - 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)); - - // Console UART clock is 16X the baud rate. - clock_device &console_clock(CLOCK(config, "console_clock", 600*16)); - console_clock.signal_handler().set(m_console, FUNC(i8251_device::write_txc)); - console_clock.signal_handler().append(m_console, FUNC(i8251_device::write_rxc)); - - CASSETTE(config, m_cass); - m_cass->set_formats(h8_cassette_formats); - m_cass->set_default_state(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_ENABLED); - m_cass->add_route(ALL_OUTPUTS, "mono", 0.05); - m_cass->set_interface("h8_cass"); - - TIMER(config, "kansas_w").configure_periodic(FUNC(h8_state::kansas_w), attotime::from_hz(4800)); - TIMER(config, "kansas_r").configure_periodic(FUNC(h8_state::kansas_r), attotime::from_hz(40000)); - TIMER(config, "h8_timer").configure_periodic(FUNC(h8_state::h8_irq_pulse), attotime::from_hz(H8_IRQ_PULSE)); + H8BUS_SLOT(config, "p1", "h8bus", h8_p1_cards, "fp"); + H8BUS_SLOT(config, "p2", "h8bus", h8_p2_cards, "cpu8080"); + H8BUS_SLOT(config, "p3", "h8bus", h8_cards, "wh_8_64"); + H8BUS_SLOT(config, "p4", "h8bus", h8_cards, nullptr); + H8BUS_SLOT(config, "p5", "h8bus", h8_cards, nullptr); + H8BUS_SLOT(config, "p6", "h8bus", h8_cards, nullptr); + H8BUS_SLOT(config, "p7", "h8bus", h8_cards, nullptr); + H8BUS_SLOT(config, "p8", "h8bus", h8_cards, nullptr); + H8BUS_SLOT(config, "p9", "h8bus", h8_cards, "h_8_5"); + H8BUS_SLOT(config, "p10", "h8bus", h8_p10_cards, nullptr); } -/* ROM definition */ +// ROM definition ROM_START( h8 ) - ROM_REGION( 0x2000, "maincpu", ROMREGION_ERASEFF ) - // H17 fdc bios - needed by bios2&3 - ROM_LOAD( "2716_444-19_h17.rom", 0x1800, 0x0800, CRC(26e80ae3) SHA1(0c0ee95d7cb1a760f924769e10c0db1678f2435c)) - - ROM_SYSTEM_BIOS(0, "bios0", "Standard") - ROMX_LOAD( "2708_444-13_pam8.rom", 0x0000, 0x0400, CRC(e0745513) SHA1(0e170077b6086be4e5cd10c17e012c0647688c39), ROM_BIOS(0) ) - - ROM_SYSTEM_BIOS(1, "bios1", "Alternate") - ROMX_LOAD( "2708_444-13_pam8go.rom", 0x0000, 0x0400, CRC(9dbad129) SHA1(72421102b881706877f50537625fc2ab0b507752), ROM_BIOS(1) ) - - ROM_SYSTEM_BIOS(2, "bios2", "Disk OS") - ROMX_LOAD( "2716_444-13_pam8at.rom", 0x0000, 0x0800, CRC(fd95ddc1) SHA1(eb1f272439877239f745521139402f654e5403af), ROM_BIOS(2) ) - - ROM_SYSTEM_BIOS(3, "bios3", "Disk OS Alt") - ROMX_LOAD( "2732_444-70_xcon8.rom", 0x0000, 0x1000, CRC(b04368f4) SHA1(965244277a3a8039a987e4c3593b52196e39b7e7), ROM_BIOS(3) ) - - // this one runs off into the weeds - ROM_SYSTEM_BIOS(4, "bios4", "not working") - ROMX_LOAD( "2732_444-140_pam37.rom", 0x0000, 0x1000, CRC(53a540db) SHA1(90082d02ffb1d27e8172b11fff465bd24343486e), ROM_BIOS(4) ) ROM_END } // anonymous namespace +// Driver -/* Driver */ - -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS, INIT COMPANY FULLNAME FLAGS -COMP( 1977, h8, 0, 0, h8, h8, h8_state, empty_init, "Heath Company", "Heathkit H8 Digital Computer", MACHINE_SUPPORTS_SAVE ) +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS, INIT COMPANY FULLNAME FLAGS +COMP( 1977, h8, 0, 0, h8, h8, h8_state, empty_init, "Heath Company", "Heathkit H8 Digital Computer", MACHINE_SUPPORTS_SAVE )