summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/multibus/robotron_k7071.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/multibus/robotron_k7071.cpp')
-rw-r--r--src/devices/bus/multibus/robotron_k7071.cpp222
1 files changed, 222 insertions, 0 deletions
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];
+}