From 31e73fea7d5e486c63c430cbb0ec02cb9941e10d Mon Sep 17 00:00:00 2001 From: Mark Garlanger Date: Fri, 17 Nov 2023 11:49:28 -0600 Subject: [PATCH] heathkit/tlb.cpp: Added Imaginator I-100 terminal for Heath H19/H89. (#11735) --- src/mame/heathkit/h19.cpp | 1 + src/mame/heathkit/h89.cpp | 1 + src/mame/heathkit/tlb.cpp | 304 ++++++++++++++++++++++++++++++++++++-- src/mame/heathkit/tlb.h | 55 ++++++- 4 files changed, 348 insertions(+), 13 deletions(-) diff --git a/src/mame/heathkit/h19.cpp b/src/mame/heathkit/h19.cpp index 96fed64beac..ed35cd43a40 100644 --- a/src/mame/heathkit/h19.cpp +++ b/src/mame/heathkit/h19.cpp @@ -36,6 +36,7 @@ static void tlb_options(device_slot_interface &device) { device.option_add("heath", HEATH_TLB); device.option_add("gp19", HEATH_GP19); + device.option_add("imaginator", HEATH_IMAGINATOR); device.option_add("super19", HEATH_SUPER19); device.option_add("superset", HEATH_SUPERSET); device.option_add("ultrarom", HEATH_ULTRA); diff --git a/src/mame/heathkit/h89.cpp b/src/mame/heathkit/h89.cpp index 93727e84aef..5427a492f41 100644 --- a/src/mame/heathkit/h89.cpp +++ b/src/mame/heathkit/h89.cpp @@ -573,6 +573,7 @@ static void tlb_options(device_slot_interface &device) { device.option_add("heath", HEATH_TLB); device.option_add("gp19", HEATH_GP19); + device.option_add("imaginator", HEATH_IMAGINATOR); device.option_add("super19", HEATH_SUPER19); device.option_add("superset", HEATH_SUPERSET); device.option_add("ultrarom", HEATH_ULTRA); diff --git a/src/mame/heathkit/tlb.cpp b/src/mame/heathkit/tlb.cpp index 0736f533bbe..4602377e517 100644 --- a/src/mame/heathkit/tlb.cpp +++ b/src/mame/heathkit/tlb.cpp @@ -21,14 +21,17 @@ - In 49/50 row mode, character descenders are cut off. ****************************************************************************/ /*************************************************************************** + Memory Layout The U435 three-to-eight line decoder uses A14 and A15 to generate - three memory addresses: + three memory address spaces: - 1. Program ROM 0x0000 - 2. Scratchpad RAM 0x4000 - 3. Display Memory 0xF800 + Address Description + ---------------------------------------------------- + 0x0000 Program ROM + 0x4000 Scratchpad RAM + 0xF800 (0xC000) Display Memory Port Layout @@ -86,12 +89,13 @@ static constexpr uint8_t KB_STATUS_KEYBOARD_STROBE_MASK = 0x80; DEFINE_DEVICE_TYPE(HEATH_TLB_CONNECTOR, heath_tlb_connector, "heath_tlb_connector", "Heath Terminal Logic board connector abstraction") -DEFINE_DEVICE_TYPE(HEATH_TLB, heath_tlb_device, "heath_tlb", "Heath Terminal Logic Board"); -DEFINE_DEVICE_TYPE(HEATH_SUPER19, heath_super19_tlb_device, "heath_super19_tlb", "Heath Terminal Logic Board w/Super19 ROM"); -DEFINE_DEVICE_TYPE(HEATH_SUPERSET, heath_superset_tlb_device, "heath_superset_tlb", "Heath Terminal Logic Board w/Superset ROM"); -DEFINE_DEVICE_TYPE(HEATH_ULTRA, heath_ultra_tlb_device, "heath_ultra_tlb", "Heath Terminal Logic Board w/Ultra ROM"); -DEFINE_DEVICE_TYPE(HEATH_WATZ, heath_watz_tlb_device, "heath_watz_tlb", "Heath Terminal Logic Board w/Watzman ROM"); +DEFINE_DEVICE_TYPE(HEATH_TLB, heath_tlb_device, "heath_tlb", "Heath Terminal Logic Board") +DEFINE_DEVICE_TYPE(HEATH_SUPER19, heath_super19_tlb_device, "heath_super19_tlb", "Heath Terminal Logic Board w/Super19 ROM") +DEFINE_DEVICE_TYPE(HEATH_SUPERSET, heath_superset_tlb_device, "heath_superset_tlb", "Heath Terminal Logic Board w/Superset ROM") +DEFINE_DEVICE_TYPE(HEATH_ULTRA, heath_ultra_tlb_device, "heath_ultra_tlb", "Heath Terminal Logic Board w/Ultra ROM") +DEFINE_DEVICE_TYPE(HEATH_WATZ, heath_watz_tlb_device, "heath_watz_tlb", "Heath Terminal Logic Board w/Watzman ROM") DEFINE_DEVICE_TYPE(HEATH_GP19, heath_gp19_tlb_device, "heath_gp19_tlb", "Heath Terminal Logic Board plus Northwest Digital Systems GP-19") +DEFINE_DEVICE_TYPE(HEATH_IMAGINATOR, heath_imaginator_tlb_device, "heath_imaginator_tlb", "Heath Terminal Logic Board plus Cleveland Codonics Imaginator I-100") @@ -103,7 +107,7 @@ device_heath_tlb_card_interface::device_heath_tlb_card_interface(const machine_c /** - * base Heath h19 functionality + * base Heath H19 functionality */ heath_tlb_device::heath_tlb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : heath_tlb_device(mconfig, HEATH_TLB, tag, owner, clock) @@ -154,8 +158,14 @@ TIMER_CALLBACK_MEMBER(heath_tlb_device::bell_off) void heath_tlb_device::mem_map(address_map &map) { map.unmap_value_high(); + + // H19 ROM map(0x0000, 0x0fff).mirror(0x3000).rom(); + + // Scratchpad memory map(0x4000, 0x40ff).mirror(0x3f00).ram(); + + // Video Memory map(0xc000, 0xc7ff).mirror(0x3800).ram().share(m_p_videoram); } @@ -232,7 +242,7 @@ void heath_tlb_device::device_reset() } // Set screen color - switch (BIT(cfg,2, 2)) + switch (BIT(cfg, 2, 2)) { case 0x01: m_screen->set_color(rgb_t::white()); @@ -939,6 +949,23 @@ ROM_START( gp19 ) ROM_LOAD( "2716_444-37_h19keyb.u445", 0x0000, 0x0800, CRC(5c3e6972) SHA1(df49ce64ae48652346a91648c58178a34fb37d3c)) ROM_END +ROM_START( imaginator ) + // Program code + ROM_REGION( 0x4000, "maincpu", ROMREGION_ERASEFF ) + // Original terminal code + ROM_LOAD( "2732_444-46_h19code.u437", 0x0000, 0x1000, CRC(f4447da0) SHA1(fb4093d5b763be21a9580a0defebed664b1f7a7b)) + // Imaginator ROMs + ROM_LOAD( "2732_imaginator_gpc_rev_1.2_pn_9000_0002.u9a", 0x2000, 0x1000, CRC(507bb13f) SHA1(5b210f8d77e22fdf063f611eb5c29636cdb01250)) + + // Original font + ROM_REGION( 0x0800, "chargen", 0 ) + ROM_LOAD( "2716_444-29_h19font.u420", 0x0000, 0x0800, CRC(d595ac1d) SHA1(130fb4ea8754106340c318592eec2d8a0deaf3d0)) + + // Original keyboard + ROM_REGION( 0x0800, "keyboard", 0 ) + ROM_LOAD( "2716_444-37_h19keyb.u445", 0x0000, 0x0800, CRC(5c3e6972) SHA1(df49ce64ae48652346a91648c58178a34fb37d3c)) +ROM_END + ioport_constructor heath_tlb_device::device_input_ports() const { @@ -1390,6 +1417,261 @@ ioport_constructor heath_gp19_tlb_device::device_input_ports() const } +/** + * Cleveland Codonics Imaginator-100 (I-100) add-in board + * + * Memory Range Description + * ----------------------------------------------------------------- + * 0x0000-0x1fff Program ROM (Heath TLB board) + * 0x2000-0x3fff Graphics Command Processor(GCP) ROM (I-100) + * 0x4000-0x5fff Scratchpad RAM (Heath TLB board) + * 0x6000-0x7fff Graphics Scratchpad R/W RAM (I-100) + * 0x8000-0xbfff Graphics Display R/W RAM(I-100) + * 0xc000-0xdfff Optional Graphics Command Processor memory (I-100) + * 0xe000-0xffff Display Memory (Heath TLB board) + * + * New interrupt source + * - horizontal retrace interrupt + * + */ +heath_imaginator_tlb_device::heath_imaginator_tlb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + heath_tlb_device(mconfig, HEATH_IMAGINATOR, tag, owner, clock), + m_mem_view(*this, "memmap"), + m_p_graphic_ram(*this, "graphicram") +{ +} + +void heath_imaginator_tlb_device::device_add_mconfig(machine_config &config) +{ + heath_tlb_device::device_add_mconfig(config); + + m_maincpu->set_addrmap(AS_PROGRAM, &heath_imaginator_tlb_device::mem_map); + m_maincpu->set_addrmap(AS_IO, &heath_imaginator_tlb_device::io_map); + m_maincpu->set_irq_acknowledge_callback(FUNC(heath_imaginator_tlb_device::irq_ack_cb)); + + m_crtc->out_hsync_callback().set(FUNC(heath_imaginator_tlb_device::crtc_hsync_w)); +} + +void heath_imaginator_tlb_device::device_start() +{ + heath_tlb_device::device_start(); + + save_item(NAME(m_mem_map)); + save_item(NAME(m_im2_val)); + save_item(NAME(m_alphanumeric_mode_active)); + save_item(NAME(m_graphics_mode_active)); + save_item(NAME(m_allow_tlb_interrupts)); + save_item(NAME(m_allow_imaginator_interrupts)); + save_item(NAME(m_hsync_irq_raised)); + + m_maincpu->space(AS_PROGRAM).install_readwrite_tap(0x6000, 0x7fff, "mem_map_update", + [this](offs_t offset, u8 &data, u8 mem_mask) { if (!machine().side_effects_disabled()) { tap_6000h(); } }, + [this](offs_t offset, u8 &data, u8 mem_mask) { if (!machine().side_effects_disabled()) { tap_6000h(); } }); + + m_maincpu->space(AS_PROGRAM).install_readwrite_tap(0x8000, 0xbfff, "irq_update", + [this](offs_t offset, u8 &data, u8 mem_mask) { if (!machine().side_effects_disabled()) { tap_8000h(); } }, + [this](offs_t offset, u8 &data, u8 mem_mask) { if (!machine().side_effects_disabled()) { tap_8000h(); } }); +} + +void heath_imaginator_tlb_device::device_reset() +{ + m_mem_map = 1; + + m_mem_view.select(m_mem_map); + + m_alphanumeric_mode_active = true; + m_graphics_mode_active = false; + + m_hsync_irq_raised = false; + + allow_tlb_intr(); +} + +/* + * Memory map for the I-100 + * + * 0x0000-0x1fff Program ROM (Heath TLB board) + * 0x2000-0x3fff Graphics Command Processor(GCP) ROM (I-100) + * 0x4000-0x5fff Scratchpad RAM (Heath TLB board) + * 0x6000-0x7fff Graphics Scratchpad R/W RAM (I-100) + * 0x8000-0xbfff Graphics Display R/W RAM(I-100) + * 0xc000-0xdfff Optional Graphics Command Processor memory (I-100) + * 0xe000-0xffff Display Memory (Heath TLB board) + */ +void heath_imaginator_tlb_device::mem_map(address_map &map) +{ + map.unmap_value_high(); + + map(0x0000, 0x1fff).view(m_mem_view); + + // H19 standard ROM + m_mem_view[0](0x0000, 0x1fff).rom().region("maincpu", 0); + + // GCP ROM mapped to 0x0000 on power-up/reset + m_mem_view[1](0x0000, 0x1fff).rom().region("maincpu", 0x2000); + + // Normal spot of the GCP ROM + map(0x2000, 0x3fff).rom(); + + // TLB Scratchpad + map(0x4000, 0x40ff).mirror(0x1f00).ram(); + + // GCP Scratchpad + map(0x6000, 0x607f).mirror(0x1f80).ram(); + + // Graphics RAM + map(0x8000, 0xbfff).ram().share(m_p_graphic_ram); + + // optional Graphics Command Processor (GCP) + // map(0xc000, 0xdfff); + + // Alphanumeric RAM + map(0xe000, 0xe7ff).mirror(0x1800).ram().share(m_p_videoram); + +} + +void heath_imaginator_tlb_device::tap_6000h() +{ + if (m_mem_map != 0) + { + m_mem_map = 0; + m_mem_view.select(m_mem_map); + } +} + +void heath_imaginator_tlb_device::tap_8000h() +{ + if (!m_allow_tlb_interrupts) + { + allow_tlb_intr(); + + set_irq_line(); + } +} + +void heath_imaginator_tlb_device::allow_tlb_intr() +{ + m_allow_tlb_interrupts = true; + m_allow_imaginator_interrupts = false; + m_im2_val = 0x02; +} + +void heath_imaginator_tlb_device::allow_hsync_intr() +{ + m_allow_tlb_interrupts = false; + m_allow_imaginator_interrupts = true; + m_im2_val = 0x00; +} + +/** + * An input/output request (IORQ) is sent to the TERMINAL LOGIC board only when + * both IORQ (pin 20 of U7) AND A4 are low. + */ +void heath_imaginator_tlb_device::io_map(address_map &map) +{ + heath_tlb_device::io_map(map); + + // interrupt routing + map(0x10, 0x10).select(0x08).mirror(0x07).w(FUNC(heath_imaginator_tlb_device::config_irq_w)); + + // display enabling (graphics or alphanumeric) + map(0x30, 0x30).select(0xc0).mirror(0x0f).w(FUNC(heath_imaginator_tlb_device::display_enable_w)); + + // Avoids writes to TLB when a4 is high on unused + map(0x50, 0x50).select(0x80).mirror(0x0f).w(FUNC(heath_imaginator_tlb_device::nop_w)); +} + +IRQ_CALLBACK_MEMBER(heath_imaginator_tlb_device::irq_ack_cb) +{ + return m_im2_val; +} + +void heath_imaginator_tlb_device::config_irq_w(offs_t reg, uint8_t val) +{ + if (BIT(reg,3)) + { + allow_tlb_intr(); + } + else + { + allow_hsync_intr(); + } + + set_irq_line(); +} + +void heath_imaginator_tlb_device::display_enable_w(offs_t reg, uint8_t val) +{ + m_alphanumeric_mode_active = bool(BIT(reg, 7)); + m_graphics_mode_active = bool(BIT(reg, 6)); +} + +void heath_imaginator_tlb_device::nop_w(offs_t, uint8_t) +{ +} + +const tiny_rom_entry *heath_imaginator_tlb_device::device_rom_region() const +{ + return ROM_NAME(imaginator); +} + +MC6845_UPDATE_ROW(heath_imaginator_tlb_device::crtc_update_row) +{ + rgb_t const *const palette = m_palette->palette()->entry_list_raw(); + uint32_t *p = &bitmap.pix(y); + + if (de) + { + for (int x = 0; x < x_count; x++) + { + uint8_t output = 0x00; + + if (m_alphanumeric_mode_active) + { + uint8_t inv = (x == cursor_x) ? 0xff : 0; + uint8_t chr = m_p_videoram[(ma + x) & 0x7ff]; + + if (chr & 0x80) + { + inv ^= 0xff; + chr &= 0x7f; + } + + output |= bitswap<8>(m_p_chargen[(chr << 4) | ra] ^ inv, 0, 1, 2, 3, 4, 5, 6, 7); + } + + if (m_graphics_mode_active && (x > 7 ) && (x < 73)) + { + output |= m_p_graphic_ram[((y * 64) + (x - 8)) & 0x3fff]; + } + + for (int b = 0; 8 > b; ++b) + { + *p++ = palette[BIT(output, b)]; + } + } + } + else + { + std::fill_n(p, x_count * 8, palette[0]); + } +} + +void heath_imaginator_tlb_device::crtc_hsync_w(int val) +{ + m_hsync_irq_raised = bool(val); + + set_irq_line(); +} + +void heath_imaginator_tlb_device::set_irq_line() +{ + m_maincpu->set_input_line(INPUT_LINE_IRQ0, + (m_allow_imaginator_interrupts && m_hsync_irq_raised) || + (m_allow_tlb_interrupts && (m_keyboard_irq_raised || m_serial_irq_raised || m_break_key_irq_raised)) ? + ASSERT_LINE : CLEAR_LINE); +} + heath_tlb_connector::heath_tlb_connector(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, HEATH_TLB_CONNECTOR, tag, owner, clock), device_single_card_slot_interface(mconfig, *this), diff --git a/src/mame/heathkit/tlb.h b/src/mame/heathkit/tlb.h index 30517c04fb6..1d3b6f15f8e 100644 --- a/src/mame/heathkit/tlb.h +++ b/src/mame/heathkit/tlb.h @@ -89,8 +89,8 @@ protected: required_ioport m_config; required_device m_ace; -private: - void set_irq_line(); +//private: + virtual void set_irq_line(); void check_for_reset(); void key_click_w(uint8_t data); @@ -237,8 +237,59 @@ protected: bool m_reverse_video; }; +/** + * Heath TLB plus Cleveland Codonics Imaginator-100 + */ +class heath_imaginator_tlb_device : public heath_tlb_device +{ +public: + heath_imaginator_tlb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + +protected: + virtual const tiny_rom_entry *device_rom_region() const override; + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_add_mconfig(machine_config &config) override; + + void mem_map(address_map &map); + void io_map(address_map &map); + + virtual MC6845_UPDATE_ROW(crtc_update_row) override; + void crtc_hsync_w(int val); + + IRQ_CALLBACK_MEMBER(irq_ack_cb); + + void tap_6000h(); + void tap_8000h(); + + void allow_tlb_intr(); + void allow_hsync_intr(); + + void display_enable_w(offs_t reg, uint8_t val); + void config_irq_w(offs_t reg, uint8_t val); + void nop_w(offs_t reg, uint8_t val); + virtual void set_irq_line() override; + + memory_view m_mem_view; + required_shared_ptr m_p_graphic_ram; + + uint8_t m_mem_map; + uint8_t m_im2_val; + + bool m_alphanumeric_mode_active; + bool m_graphics_mode_active; + + bool m_allow_tlb_interrupts; + bool m_allow_imaginator_interrupts; + + bool m_hsync_irq_raised; +}; + + DECLARE_DEVICE_TYPE(HEATH_TLB, heath_tlb_device) DECLARE_DEVICE_TYPE(HEATH_GP19, heath_gp19_tlb_device) +DECLARE_DEVICE_TYPE(HEATH_IMAGINATOR, heath_imaginator_tlb_device) DECLARE_DEVICE_TYPE(HEATH_SUPER19, heath_super19_tlb_device) DECLARE_DEVICE_TYPE(HEATH_SUPERSET, heath_superset_tlb_device) DECLARE_DEVICE_TYPE(HEATH_WATZ, heath_watz_tlb_device)