From c895c5e19865e804d9ba37b1f0f05d9c9bcc19dd Mon Sep 17 00:00:00 2001 From: shattered Date: Mon, 8 Apr 2024 17:17:12 +0000 Subject: bus/multibus: Added Robotron K7071 text-only video card for the A7100 series. (#12188) --- scripts/src/bus.lua | 2 + src/devices/bus/multibus/robotron_k7071.cpp | 222 ++++++++++++++++++++++++++++ src/devices/bus/multibus/robotron_k7071.h | 61 ++++++++ src/mame/robotron/a7150.cpp | 2 + 4 files changed, 287 insertions(+) create mode 100644 src/devices/bus/multibus/robotron_k7071.cpp create mode 100644 src/devices/bus/multibus/robotron_k7071.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index ed1f4e55a7e..2ae59a041cc 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -5265,6 +5265,8 @@ if (BUSES["MULTIBUS"]~=null) then MAME_DIR .. "src/devices/bus/multibus/labtam_z80sbc.h", MAME_DIR .. "src/devices/bus/multibus/robotron_k7070.cpp", MAME_DIR .. "src/devices/bus/multibus/robotron_k7070.h", + MAME_DIR .. "src/devices/bus/multibus/robotron_k7071.cpp", + MAME_DIR .. "src/devices/bus/multibus/robotron_k7071.h", } end diff --git a/src/devices/bus/multibus/robotron_k7071.cpp b/src/devices/bus/multibus/robotron_k7071.cpp new file mode 100644 index 00000000000..89c26dc39cb --- /dev/null +++ b/src/devices/bus/multibus/robotron_k7071.cpp @@ -0,0 +1,222 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +/* + * Robotron K7071 (ABS) text-only video + * + * Reference: http://www.tiffe.de/Robotron/MMS16/ + * + * To do: + * - fix screen corruption (DMA reprogramming timing?) + * - loadable font - CRTC LA0 connected to NMI via gate + */ + +#include "emu.h" +#include "robotron_k7071.h" + +#define VERBOSE 0 +#include "logmacro.h" + +enum kgs_st : u8 +{ + KGS_ST_OBF = 0x01, + KGS_ST_IBF = 0x02, + KGS_ST_INT = 0x04, + KGS_ST_ERR = 0x80, +}; + +DEFINE_DEVICE_TYPE(ROBOTRON_K7071, robotron_k7071_device, "robotron_k7071", "Robotron K7071 ABS") + +robotron_k7071_device::robotron_k7071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) + : device_t(mconfig, ROBOTRON_K7071, tag, owner, clock) + , device_multibus_interface(mconfig, *this) + , m_cpu(*this, "cpu") + , m_dma(*this, "dma") + , m_crtc(*this, "crtc") + , m_screen(*this, "screen") + , m_palette(*this, "palette") + , m_ram(*this, "ram") + , m_p_chargen(*this, "chargen") +{ +} + +ROM_START(robotron_k7071) + ROM_REGION(0x1000, "eprom", ROMREGION_ERASEFF) + ROM_LOAD("q209.bin", 0x0000, 0x0800, CRC(efc4aac0) SHA1(2cb4db3572e6ec7f3d3ae8e70d61b509b1fa3203)) + ROM_LOAD("q210.bin", 0x0800, 0x0800, CRC(d23e00ed) SHA1(eaca53ed784cf263323e9abba24a364b2aadac44)) + + ROM_REGION(0x2000, "chargen", ROMREGION_ERASE00) + ROM_LOAD("q211.bin", 0x0000, 0x0800, CRC(b6241bc5) SHA1(8428e344df95451a34ad01322e245d2357712010)) +ROM_END + +const tiny_rom_entry *robotron_k7071_device::device_rom_region() const +{ + return ROM_NAME(robotron_k7071); +} + +void robotron_k7071_device::device_start() +{ + save_item(NAME(m_kgs_datao)); + save_item(NAME(m_kgs_datai)); + save_item(NAME(m_kgs_ctrl)); + save_item(NAME(m_nmi_enable)); + + m_cpu->space(AS_PROGRAM).specific(m_program); + m_bus->space(AS_IO).install_readwrite_handler(0x200, 0x203, read16s_delegate(*this, FUNC(robotron_k7071_device::io_r)), write16s_delegate(*this, FUNC(robotron_k7071_device::io_w))); +} + +void robotron_k7071_device::device_reset() +{ + m_kgs_ctrl = KGS_ST_IBF | KGS_ST_OBF; + m_kgs_datao = m_kgs_datai = m_nmi_enable = 0; +} + +void robotron_k7071_device::device_add_mconfig(machine_config &config) +{ + Z80(config, m_cpu, XTAL(16'000'000) / 6); + m_cpu->set_addrmap(AS_PROGRAM, &robotron_k7071_device::cpu_mem); + m_cpu->set_addrmap(AS_IO, &robotron_k7071_device::cpu_pio); + + I8257(config, m_dma, XTAL(16'000'000) / 6); + m_dma->out_hrq_cb().set(FUNC(robotron_k7071_device::hrq_w)); + m_dma->in_memr_cb().set([this] (offs_t offset) { return m_program.read_byte(offset); }); + m_dma->out_iow_cb<0>().set(m_crtc, FUNC(i8275_device::dack_w)); + + I8275(config, m_crtc, XTAL(16'000'000) / 8); + m_crtc->set_screen(m_screen); + m_crtc->set_character_width(8); + m_crtc->set_display_callback(FUNC(robotron_k7071_device::display_pixels)); + m_crtc->drq_wr_callback().set(m_dma, FUNC(i8257_device::dreq0_w)); + m_crtc->lc_wr_callback().set([this] (int data) { m_cpu->set_input_line(INPUT_LINE_IRQ0, data == 15 ? ASSERT_LINE : CLEAR_LINE); }); + + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_color(rgb_t::green()); + m_screen->set_raw(XTAL(16'000'000), 736, 0, 640, 432, 0, 416); + m_screen->set_screen_update(m_crtc, FUNC(i8275_device::screen_update)); + + PALETTE(config, m_palette, palette_device::MONOCHROME_HIGHLIGHT); +} + +void robotron_k7071_device::cpu_mem(address_map &map) +{ + map.unmap_value_high(); + + map(0x0000, 0x0fff).rom().region("eprom", 0); + map(0x1400, 0x1fff).ram().share("ram").mirror(0x8000); +} + +void robotron_k7071_device::cpu_pio(address_map &map) +{ + map.unmap_value_high(); + map.global_mask(0xff); + + map(0x00, 0x08).rw(m_dma, FUNC(i8257_device::read), FUNC(i8257_device::write)); + map(0x20, 0x21).rw(m_crtc, FUNC(i8275_device::read), FUNC(i8275_device::write)); + map(0x30, 0x30).noprw(); // chargen ram access + map(0x40, 0x40).nopw(); // line counter input for sync generator + map(0x50, 0x50).lw8(NAME([this] (u8 data) { m_kgs_ctrl |= KGS_ST_INT; int_w(7, ASSERT_LINE); })); + map(0x60, 0x60).lw8(NAME([this] (u8 data) { m_kgs_ctrl |= KGS_ST_ERR; })); + map(0x70, 0x71).rw(FUNC(robotron_k7071_device::kgs_host_r), FUNC(robotron_k7071_device::kgs_host_w)); + map(0x80, 0x80).lw8(NAME([this] (u8 data) { m_nmi_enable = BIT(data, 7); })); + map(0xdf, 0xdf).nopw(); // used by IRQ handler +} + +uint16_t robotron_k7071_device::io_r(offs_t offset, uint16_t mem_mask) +{ + uint8_t data = 0; + + switch (offset) + { + case 0: + data = m_kgs_ctrl; + break; + + case 1: + data = m_kgs_datai; + if (!machine().side_effects_disabled()) + m_kgs_ctrl &= ~KGS_ST_OBF; + break; + } + + return data; +} + +void robotron_k7071_device::io_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + switch (offset) + { + case 0: + m_kgs_ctrl &= ~(KGS_ST_ERR | KGS_ST_INT); + int_w(7, CLEAR_LINE); + break; + + case 1: + if (m_kgs_ctrl & KGS_ST_IBF) + { + m_kgs_ctrl |= KGS_ST_ERR; + } + else + { + m_kgs_datao = data; + m_kgs_ctrl |= KGS_ST_IBF; + } + break; + } +} + + +uint8_t robotron_k7071_device::kgs_host_r(offs_t offset) +{ + uint8_t data = 0; + + switch (offset) + { + case 0: + data = m_kgs_ctrl; + break; + + case 1: + data = m_kgs_datao; + if (!machine().side_effects_disabled()) + m_kgs_ctrl &= ~(KGS_ST_ERR | KGS_ST_IBF); + break; + + default: + break; + } + + return data; +} + +void robotron_k7071_device::kgs_host_w(offs_t offset, uint8_t data) +{ + if (offset) + { + m_kgs_datai = data; + m_kgs_ctrl |= KGS_ST_OBF; + } +} + +void robotron_k7071_device::hrq_w(int state) +{ + // since our Z80 has no support for BUSACK, we assume it is granted immediately + m_cpu->set_input_line(Z80_INPUT_LINE_BUSRQ, state); + m_cpu->set_input_line(INPUT_LINE_HALT, state); // do we need this? + m_dma->hlda_w(state); +} + +I8275_DRAW_CHARACTER_MEMBER(robotron_k7071_device::display_pixels) +{ + using namespace i8275_attributes; + + rgb_t const *const palette = m_palette->palette()->entry_list_raw(); + u8 gfx = (BIT(attrcode, LTEN)) ? 0xff : 0; + if (!BIT(attrcode, VSP)) + gfx = m_p_chargen[linecount | (charcode << 4)]; + + if (BIT(attrcode, RVV)) + gfx ^= 0xff; + + for (u8 i = 0; i < 8; i++) + bitmap.pix(y, x + i) = palette[BIT(gfx, 7-i) ? (BIT(attrcode, HLGT) ? 2 : 1) : 0]; +} diff --git a/src/devices/bus/multibus/robotron_k7071.h b/src/devices/bus/multibus/robotron_k7071.h new file mode 100644 index 00000000000..55efbd3e05e --- /dev/null +++ b/src/devices/bus/multibus/robotron_k7071.h @@ -0,0 +1,61 @@ +// license:BSD-3-Clause +// copyright-holders:Sergey Svishchev + +#ifndef MAME_BUS_MULTIBUS_ROBOTRON_K7071_H +#define MAME_BUS_MULTIBUS_ROBOTRON_K7071_H + +#pragma once + +#include "multibus.h" + +#include "cpu/z80/z80.h" +#include "machine/i8257.h" +#include "video/i8275.h" + +#include "emupal.h" +#include "screen.h" + + +class robotron_k7071_device + : public device_t + , public device_multibus_interface +{ +public: + robotron_k7071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override; + virtual void device_start() override; + virtual void device_reset() override; + virtual const tiny_rom_entry *device_rom_region() const override; + + void cpu_mem(address_map &map); + virtual void cpu_pio(address_map &map); + +private: + required_device m_cpu; + required_device m_dma; + required_device m_crtc; + required_device m_screen; + required_device m_palette; + required_shared_ptr m_ram; + required_region_ptr m_p_chargen; + + memory_access<16, 0, 0, ENDIANNESS_LITTLE>::specific m_program; + + uint8_t m_kgs_datao, m_kgs_datai, m_kgs_ctrl; + bool m_nmi_enable; + + I8275_DRAW_CHARACTER_MEMBER(display_pixels); + void hrq_w(int state); + + uint8_t kgs_host_r(offs_t offset); + void kgs_host_w(offs_t offset, uint8_t data); + + uint16_t io_r(offs_t offset, uint16_t mem_mask); + void io_w(offs_t offset, uint16_t data, uint16_t mem_mask); +}; + +DECLARE_DEVICE_TYPE(ROBOTRON_K7071, robotron_k7071_device) + +#endif // MAME_BUS_MULTIBUS_ROBOTRON_K7071_H diff --git a/src/mame/robotron/a7150.cpp b/src/mame/robotron/a7150.cpp index eaae878352c..448eaaa35a7 100644 --- a/src/mame/robotron/a7150.cpp +++ b/src/mame/robotron/a7150.cpp @@ -34,6 +34,7 @@ To do: #include "bus/multibus/multibus.h" #include "bus/multibus/robotron_k7070.h" +#include "bus/multibus/robotron_k7071.h" #include "bus/rs232/rs232.h" #include "cpu/i86/i86.h" #include "machine/i8087.h" @@ -140,6 +141,7 @@ void a7150_state::machine_start() static void a7150_cards(device_slot_interface &device) { device.option_add("kgs", ROBOTRON_K7070); + device.option_add("abs", ROBOTRON_K7071); } /* -- cgit v1.2.3