summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/concept
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/concept')
-rw-r--r--src/mame/concept/concept.cpp233
-rw-r--r--src/mame/concept/concept.h75
-rw-r--r--src/mame/concept/concept_kbd.cpp227
-rw-r--r--src/mame/concept/concept_kbd.h62
-rw-r--r--src/mame/concept/concept_m.cpp362
5 files changed, 959 insertions, 0 deletions
diff --git a/src/mame/concept/concept.cpp b/src/mame/concept/concept.cpp
new file mode 100644
index 00000000000..99e0a8a6e11
--- /dev/null
+++ b/src/mame/concept/concept.cpp
@@ -0,0 +1,233 @@
+// license:GPL-2.0+
+// copyright-holders:Raphael Nabet, Brett Wyer
+/*
+ Corvus Concept driver
+
+ Relatively simple 68k-based system
+
+ * 256 or 512 kbytes of DRAM
+ * 4kbytes of SRAM
+ * 8kbyte boot ROM
+ * optional MacsBugs ROM
+ * two serial ports, keyboard, bitmapped display, simple sound, omninet
+ LAN port (seems more or less similar to AppleTalk)
+ * 4 expansion ports enable to add expansion cards, namely floppy disk
+ and hard disk controllers (the expansion ports are partially compatible
+ with Apple 2 expansion ports; DMA is not supported)
+
+ Video: monochrome bitmapped display, 720*560 visible area (bitmaps are 768
+ pixels wide in memory). One interesting feature is the fact that the
+ monitor can be rotated to give a 560*720 vertical display (you need to
+ throw a switch and reset the machine for the display rotation to be taken
+ into account, though). One oddity is that the video hardware scans the
+ display from the lower-left corner to the upper-left corner (or from the
+ upper-right corner to the lower-left if the screen is flipped).
+ Sound: simpler buzzer connected to the via shift register
+ Keyboard: intelligent controller, connected through an ACIA. See CCOS
+ manual pp. 76 through 78. and User Guide p. 2-1 through 2-9.
+ Clock: mm58174 RTC
+
+ Raphael Nabet, Brett Wyer, 2003-2005
+ Major reworking by R. Belmont 2012-2013 resulting in bootable floppies
+
+ ACIA baud rates are 1.36% slower than normal by design. The clock division
+ used as the BRG input for all three is about 1.818 MHz, not the standard
+ 1.8432 MHz. The schematics indicate a PCB option to leave the 74LS161 at
+ U212 unpopulated and use a secondary XTAL as the baud rate clock. This
+ XTAL is also specified as 1.818 MHz.
+*/
+
+#include "emu.h"
+#include "concept.h"
+#include "concept_kbd.h"
+
+#include "cpu/m68000/m68000.h"
+#include "cpu/m6800/m6801.h"
+#include "bus/a2bus/a2corvus.h"
+#include "bus/a2bus/corvfdc01.h"
+#include "bus/a2bus/corvfdc02.h"
+#include "bus/rs232/rs232.h"
+#include "machine/input_merger.h"
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+
+void concept_state::concept_memmap(address_map &map)
+{
+ map(0x000000, 0x000007).rom().region("maincpu", 0x010000); /* boot ROM mirror */
+ map(0x000008, 0x000fff).ram(); /* static RAM */
+ map(0x010000, 0x011fff).rom().region("maincpu", 0x010000); /* boot ROM */
+ map(0x020000, 0x021fff).rom().region("macsbug", 0x0); /* macsbugs ROM (optional) */
+ map(0x030000, 0x03ffff).rw(FUNC(concept_state::io_r), FUNC(concept_state::io_w)).umask16(0x00ff); /* I/O space */
+
+ map(0x080000, 0x0fffff).ram().share("videoram"); /* .bankrw(2); */ /* DRAM */
+}
+
+
+static INPUT_PORTS_START( corvus_concept )
+ PORT_START("DSW0") /* port 6: on-board DIP switches */
+ PORT_DIPNAME(0x01, 0x00, "Omninet Address bit 0")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x01, DEF_STR( On ))
+ PORT_DIPNAME(0x02, 0x02, "Omninet Address bit 1")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x02, DEF_STR( On ))
+ PORT_DIPNAME(0x04, 0x00, "Omninet Address bit 2")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x04, DEF_STR( On ))
+ PORT_DIPNAME(0x08, 0x00, "Omninet Address bit 3")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x08, DEF_STR( On ))
+ PORT_DIPNAME(0x10, 0x00, "Omninet Address bit 4")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x10, DEF_STR( On ))
+ PORT_DIPNAME(0x20, 0x00, "Omninet Address bit 5")
+ PORT_DIPSETTING(0x00, DEF_STR( Off ))
+ PORT_DIPSETTING(0x20, DEF_STR( On ))
+ PORT_DIPNAME(0xc0, 0x00, "Type of Boot")
+ PORT_DIPSETTING(0x00, "Prompt for type of Boot") // Documentation has 0x00 and 0xc0 reversed per boot PROM
+ PORT_DIPSETTING(0x40, "Boot from Omninet")
+ PORT_DIPSETTING(0x80, "Boot from Local Disk")
+ PORT_DIPSETTING(0xc0, "Boot from Diskette")
+
+#if 0
+ PORT_START("DISPLAY") /* port 7: Display orientation */
+ PORT_DIPNAME(0x01, 0x00, "Screen Orientation")
+ PORT_DIPSETTING(0x00, "Horizontal")
+ PORT_DIPSETTING(0x01, "Vertical")
+#endif
+
+INPUT_PORTS_END
+
+
+void concept_a2_cards(device_slot_interface &device)
+{
+ device.option_add("fchdd", A2BUS_CORVUS); // Corvus flat-cable HDD interface (see notes in a2corvus.c)
+ device.option_add("fdc01", A2BUS_CORVFDC01); // Corvus WD1793 floppy controller
+ device.option_add("fdc02", A2BUS_CORVFDC02); // Corvus NEC765 buffered floppy controller
+}
+
+
+void concept_state::corvus_concept(machine_config &config)
+{
+ /* basic machine hardware */
+ M68000(config, m_maincpu, 16.364_MHz_XTAL / 2);
+ m_maincpu->set_addrmap(AS_PROGRAM, &concept_state::concept_memmap);
+
+ M6801(config, "omni", 10_MHz_XTAL / 2).set_disable();
+
+ config.set_maximum_quantum(attotime::from_hz(60));
+
+ /* video hardware */
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_video_attributes(VIDEO_UPDATE_BEFORE_VBLANK);
+ screen.set_raw(16.364_MHz_XTAL * 2, 944, 0, 720, 578, 0, 560);
+ // Horizontal sync is 34.669 kHz; refresh rate is ~50 or ~60 Hz, jumper-selectable
+ screen.set_screen_update(FUNC(concept_state::screen_update));
+ screen.set_palette("palette");
+
+ /* Is the palette black on white or white on black??? */
+ PALETTE(config, "palette", palette_device::MONOCHROME);
+
+ /* sound */
+ SPEAKER(config, "mono").front_center();
+ SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00);
+
+ /* rtc */
+ MM58174(config, m_mm58174, 32.768_kHz_XTAL);
+
+ /* via */
+ MOS6522(config, m_via0, 16.364_MHz_XTAL / 16);
+ m_via0->readpa_handler().set(FUNC(concept_state::via_in_a));
+ m_via0->readpb_handler().set(FUNC(concept_state::via_in_b));
+ m_via0->writepa_handler().set(FUNC(concept_state::via_out_a));
+ m_via0->writepb_handler().set(FUNC(concept_state::via_out_b));
+ m_via0->cb2_handler().set(FUNC(concept_state::via_out_cb2));
+ m_via0->irq_handler().set_inputline(m_maincpu, M68K_IRQ_5);
+
+ /* ACIAs */
+ MOS6551(config, m_acia0, 16.364_MHz_XTAL / 16);
+ m_acia0->set_xtal(16.364_MHz_XTAL / 9);
+ m_acia0->txd_handler().set("rs232a", FUNC(rs232_port_device::write_txd));
+ m_acia0->irq_handler().set_inputline(m_maincpu, M68K_IRQ_4);
+
+ MOS6551(config, m_acia1, 16.364_MHz_XTAL / 16);
+ m_acia1->set_xtal(16.364_MHz_XTAL / 9);
+ m_acia1->txd_handler().set("rs232b", FUNC(rs232_port_device::write_txd));
+ m_acia1->irq_handler().set_inputline(m_maincpu, M68K_IRQ_2);
+
+ MOS6551(config, m_kbdacia, 16.364_MHz_XTAL / 16);
+ m_kbdacia->set_xtal(16.364_MHz_XTAL / 9);
+ m_kbdacia->txd_handler().set("keyboard", FUNC(concept_keyboard_device::write_rxd));
+ m_kbdacia->dtr_handler().set("keyrxd", FUNC(input_merger_device::in_w<0>)).invert(); // open collector
+ m_kbdacia->irq_handler().set_inputline(m_maincpu, M68K_IRQ_6);
+
+ CONCEPT_KEYBOARD(config, "keyboard").txd_callback().set("keyrxd", FUNC(input_merger_device::in_w<1>));
+
+ INPUT_MERGER_ALL_HIGH(config, "keyrxd").output_handler().set(m_kbdacia, FUNC(mos6551_device::write_rxd));
+
+ /* Apple II bus */
+ A2BUS(config, m_a2bus, 0).set_space(m_maincpu, AS_PROGRAM);
+ m_a2bus->nmi_w().set("iocint", FUNC(input_merger_device::in_w<0>));
+ m_a2bus->irq_w().set("iocint", FUNC(input_merger_device::in_w<1>));
+ A2BUS_SLOT(config, "sl1", 16.364_MHz_XTAL / 2, m_a2bus, concept_a2_cards, nullptr);
+ A2BUS_SLOT(config, "sl2", 16.364_MHz_XTAL / 2, m_a2bus, concept_a2_cards, nullptr);
+ A2BUS_SLOT(config, "sl3", 16.364_MHz_XTAL / 2, m_a2bus, concept_a2_cards, nullptr);
+ A2BUS_SLOT(config, "sl4", 16.364_MHz_XTAL / 2, m_a2bus, concept_a2_cards, "fdc01");
+
+ INPUT_MERGER_ANY_HIGH(config, "iocint").output_handler().set_inputline(m_maincpu, M68K_IRQ_1);
+
+ /* 2x RS232 ports */
+ rs232_port_device &rs232a(RS232_PORT(config, "rs232a", default_rs232_devices, nullptr));
+ rs232a.rxd_handler().set(m_acia0, FUNC(mos6551_device::write_rxd));
+ //rs232a.dcd_handler().set("iocint", FUNC(input_merger_device::in_w<2>)).invert();
+ //rs232a.dsr_handler().set("iocint", FUNC(input_merger_device::in_w<3>)).invert();
+ //rs232a.cts_handler().set("iocint", FUNC(input_merger_device::in_w<4>)).invert();
+
+ rs232_port_device &rs232b(RS232_PORT(config, "rs232b", default_rs232_devices, nullptr));
+ rs232b.rxd_handler().set(m_acia1, FUNC(mos6551_device::write_rxd));
+ //rs232b.dcd_handler().set("iocint", FUNC(input_merger_device::in_w<5>)).invert();
+ //rs232b.dsr_handler().set("iocint", FUNC(input_merger_device::in_w<6>)).invert();
+ //rs232b.cts_handler().set("iocint", FUNC(input_merger_device::in_w<7>)).invert();
+}
+
+
+ROM_START( concept )
+ ROM_REGION16_BE(0x100000,"maincpu",0) /* 68k rom and ram */
+
+ // concept boot ROM
+ ROM_SYSTEM_BIOS(0, "lvl8", "Level 8" ) // v0?
+ ROMX_LOAD("bootl08h", 0x010000, 0x1000, CRC(ee479f51) SHA1(b20ba18564672196076e46507020c6d69a640a2f), ROM_BIOS(0) | ROM_SKIP(1))
+ ROMX_LOAD("bootl08l", 0x010001, 0x1000, CRC(acaefd07) SHA1(de0c7eaacaf4c0652aa45e523cebce2b2993c437), ROM_BIOS(0) | ROM_SKIP(1))
+
+ ROM_SYSTEM_BIOS(1, "lvl7", "Level 7" ) // v0? v1?
+ ROMX_LOAD("cc07h", 0x010000, 0x1000, CRC(455abac8) SHA1(b12e1580220242d34eafed1b486cebd89e823c8b), ROM_BIOS(1) | ROM_SKIP(1))
+ ROMX_LOAD("cc07l", 0x010001, 0x1000, CRC(107a3830) SHA1(0ea12ef13b0d11fcd83b306b3a1bb8014ba910c0), ROM_BIOS(1) | ROM_SKIP(1))
+
+ ROM_SYSTEM_BIOS(2, "lvl6", "Level 6" ) // v0?
+ ROMX_LOAD("cc06h", 0x010000, 0x1000, CRC(66b6b259) SHA1(1199a38ef3e94f695e8da6a7c80c6432da3cb80c), ROM_BIOS(2) | ROM_SKIP(1))
+ ROMX_LOAD("cc06l", 0x010001, 0x1000, CRC(600940d3) SHA1(c3278bf23b3b1c35ea1e3da48a05e877862a8345), ROM_BIOS(2) | ROM_SKIP(1))
+
+#if 0
+ // version 1 lvl 7 release
+ ROM_LOAD16_BYTE("bootl17h", 0x010000, 0x1000, CRC(6dd9718f)) // where does this come from?
+ ROM_LOAD16_BYTE("bootl17l", 0x010001, 0x1000, CRC(107a3830) SHA1(0ea12ef13b0d11fcd83b306b3a1bb8014ba910c0))
+#elif 0
+ // version $F lvl 8 (development version found on a floppy disk along with
+ // the source code)
+ ROM_LOAD16_WORD("cc.prm", 0x010000, 0x2000, CRC(b5a87dab) SHA1(0da59af6cfeeb38672f71731527beac323d9c3d6))
+#endif
+
+ ROM_REGION(0x1000, "omni", 0)
+ ROM_LOAD("sc85180l_3265-02762.u302", 0x0000, 0x1000, NO_DUMP)
+
+ ROM_REGION(0x400, "proms", 0)
+ ROM_LOAD("map04a.bin", 0x000, 0x400, CRC(1ae0db9b) SHA1(cdb6f63bb08072b454b4704e62de51c483ede734) )
+
+ ROM_REGION16_BE(0x2000, "macsbug", 0)
+ ROM_LOAD16_BYTE( "mb20h.bin", 0x000000, 0x001000, CRC(aa357112) SHA1(88211e5f59887928c557c27cdea674f48bf8eaf7) )
+ ROM_LOAD16_BYTE( "mb20l.bin", 0x000001, 0x001000, CRC(b4b59de9) SHA1(3e8b8b5950b5359203c054f94af1fc5b8f0495b9) )
+ROM_END
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
+COMP( 1982, concept, 0, 0, corvus_concept, corvus_concept, concept_state, empty_init, "Corvus Systems", "Concept" , 0 )
diff --git a/src/mame/concept/concept.h b/src/mame/concept/concept.h
new file mode 100644
index 00000000000..6ea4ba70aa9
--- /dev/null
+++ b/src/mame/concept/concept.h
@@ -0,0 +1,75 @@
+// license:GPL-2.0+
+// copyright-holders:Raphael Nabet, Brett Wyer
+/*****************************************************************************
+ *
+ * includes/concept.h
+ *
+ * Corvus Concept driver
+ *
+ * Raphael Nabet, 2003
+ *
+ ****************************************************************************/
+
+#ifndef MAME_CONCEPT_CONCEPT_H
+#define MAME_CONCEPT_CONCEPT_H
+
+#include "cpu/m68000/m68000.h"
+#include "machine/6522via.h"
+#include "machine/mos6551.h"
+#include "machine/mm58174.h"
+#include "sound/spkrdev.h"
+#include "bus/a2bus/a2bus.h"
+
+#define ACIA_0_TAG "acia0"
+#define ACIA_1_TAG "acia1"
+#define VIA_0_TAG "via6522_0"
+#define KBD_ACIA_TAG "kbacia"
+
+class concept_state : public driver_device
+{
+public:
+ concept_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_acia0(*this, ACIA_0_TAG),
+ m_acia1(*this, ACIA_1_TAG),
+ m_via0(*this, VIA_0_TAG),
+ m_kbdacia(*this, KBD_ACIA_TAG),
+ m_speaker(*this, "spkr"),
+ m_mm58174(*this, "mm58174"),
+ m_a2bus(*this, "a2bus"),
+ m_videoram(*this,"videoram")
+ { }
+
+ void corvus_concept(machine_config &config);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<mos6551_device> m_acia0;
+ required_device<mos6551_device> m_acia1;
+ required_device<via6522_device> m_via0;
+ required_device<mos6551_device> m_kbdacia;
+ required_device<speaker_sound_device> m_speaker;
+ required_device<mm58174_device> m_mm58174;
+ required_device<a2bus_device> m_a2bus;
+ required_shared_ptr<uint16_t> m_videoram;
+
+ bool m_clock_enable = false;
+ uint8_t m_clock_address = 0U;
+ uint8_t io_r(offs_t offset);
+ void io_w(offs_t offset, uint8_t data);
+ virtual void machine_start() override ATTR_COLD;
+ virtual void machine_reset() override ATTR_COLD;
+ virtual void video_start() override ATTR_COLD;
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ uint8_t via_in_a();
+ void via_out_a(uint8_t data);
+ uint8_t via_in_b();
+ void via_out_b(uint8_t data);
+ void via_out_cb2(int state);
+
+ void concept_memmap(address_map &map) ATTR_COLD;
+};
+
+#endif // MAME_CONCEPT_CONCEPT_H
diff --git a/src/mame/concept/concept_kbd.cpp b/src/mame/concept/concept_kbd.cpp
new file mode 100644
index 00000000000..e9a5570be20
--- /dev/null
+++ b/src/mame/concept/concept_kbd.cpp
@@ -0,0 +1,227 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/**********************************************************************
+
+ Corvus Concept 91-key keyboard
+
+ This is a rather generic Key Tronic Corp. product using their
+ 22-950-3B and 22-908-03 custom ICs.
+
+ The program outputs raw make and break scan codes in TTL-level
+ asynchronous serial at a rate somewhat less than 600 bits per
+ second (the host ACIA also happens to runs slow). It occupies
+ very little of the external ROM.
+
+ Corvus seems to have swapped the positions of the backspace and
+ backslash keys at least once.
+
+ The serial input from the host ACIA appears to have the sole
+ function of driving the LED on the Break key. The program reads
+ inputs only from the key matrix.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "concept_kbd.h"
+
+
+// device type definition
+DEFINE_DEVICE_TYPE(CONCEPT_KEYBOARD, concept_keyboard_device, "concept_kbd", "Corvus Concept Keyboard")
+
+concept_keyboard_device::concept_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, CONCEPT_KEYBOARD, tag, owner, clock)
+ , m_mcu(*this, "mcu")
+ , m_keys(*this, "KEYS%X", 0U)
+ , m_led(*this, "led")
+ , m_txd_callback(*this)
+ , m_p2_output(0xff)
+ , m_key_input(0xff)
+{
+}
+
+void concept_keyboard_device::device_resolve_objects()
+{
+ m_led.resolve();
+}
+
+void concept_keyboard_device::device_start()
+{
+ save_item(NAME(m_p2_output));
+ save_item(NAME(m_key_input));
+}
+
+void concept_keyboard_device::write_rxd(int state)
+{
+ m_led = !state;
+}
+
+
+u8 concept_keyboard_device::p1_r()
+{
+ return m_key_input;
+}
+
+void concept_keyboard_device::p2_w(u8 data)
+{
+ m_txd_callback(BIT(data, 4));
+
+ if (!BIT(data, 7))
+ m_key_input = 0xff;
+ else if (!BIT(m_p2_output, 7))
+ {
+ u8 row = m_mcu->p1_r() & 0x0f;
+ m_key_input = row >= 0x0c ? 0xff : m_keys[row]->read();
+ }
+
+ m_p2_output = data;
+}
+
+void concept_keyboard_device::prog_map(address_map &map)
+{
+ map(0x000, 0x3ff).rom().region("program", 0);
+}
+
+
+static INPUT_PORTS_START(concept_keyboard)
+ PORT_START("KEYS0")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(COMMA_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+
+ PORT_START("KEYS1")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
+
+ PORT_START("KEYS2")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Back Space") PORT_CHAR(0x08)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_NAME("Return") PORT_CHAR(0x0d)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("] }") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') PORT_CHAR(0x1d)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("\\ |") PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') PORT_CHAR(0x1c)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("KEYS3")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_NAME("P") PORT_CHAR('p') PORT_CHAR('P') PORT_CHAR(0x10)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_NAME("Right Shift")
+
+ PORT_START("KEYS4")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F1) PORT_CHAR(UCHAR_MAMEKEY(F1))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F2) PORT_CHAR(UCHAR_MAMEKEY(F2))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F3) PORT_CHAR(UCHAR_MAMEKEY(F3))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0xe0, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("KEYS5")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_NAME("R") PORT_CHAR('r') PORT_CHAR('R') PORT_CHAR(0x12)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_NAME("T") PORT_CHAR('t') PORT_CHAR('T') PORT_CHAR(0x14)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_NAME("F") PORT_CHAR('f') PORT_CHAR('F') PORT_CHAR(0x06)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_NAME("G") PORT_CHAR('g') PORT_CHAR('G') PORT_CHAR(0x07)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_NAME("V") PORT_CHAR('v') PORT_CHAR('V') PORT_CHAR(0x16)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_NAME("B") PORT_CHAR('b') PORT_CHAR('B') PORT_CHAR(0x02)
+
+ PORT_START("KEYS6")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_NAME("W") PORT_CHAR('w') PORT_CHAR('W') PORT_CHAR(0x17)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_NAME("E") PORT_CHAR('e') PORT_CHAR('E') PORT_CHAR(0x05)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_NAME("S") PORT_CHAR('s') PORT_CHAR('S') PORT_CHAR(0x13)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_NAME("D") PORT_CHAR('d') PORT_CHAR('D') PORT_CHAR(0x04)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_NAME("X") PORT_CHAR('x') PORT_CHAR('X') PORT_CHAR(0x18)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_NAME("C") PORT_CHAR('c') PORT_CHAR('C') PORT_CHAR(0x03)
+
+ PORT_START("KEYS7")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_NAME("Esc") PORT_CHAR(0x1b)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_NAME("Tab") // not normally translated to 0x09 here
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_NAME("Q") PORT_CHAR('q') PORT_CHAR('Q') PORT_CHAR(0x11)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_NAME("Caps Lock") PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_NAME("A") PORT_CHAR('a') PORT_CHAR('A') PORT_CHAR(0x01)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_NAME("Left Shift") PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_NAME("Z") PORT_CHAR('z') PORT_CHAR('Z') PORT_CHAR(0x1a)
+
+ PORT_START("KEYS8")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_NAME("Y") PORT_CHAR('y') PORT_CHAR('Y') PORT_CHAR(0x19)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_NAME("U") PORT_CHAR('u') PORT_CHAR('U') PORT_CHAR(0x14)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_NAME("H") PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_NAME("J") PORT_CHAR('j') PORT_CHAR('J') PORT_CHAR(0x0a)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_NAME("N") PORT_CHAR('n') PORT_CHAR('N') PORT_CHAR(0x0e)
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_NAME("M") PORT_CHAR('m') PORT_CHAR('M')
+
+ PORT_START("KEYS9")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_NAME("Ctrl") PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RCONTROL) PORT_NAME("Fast") // actually between Ctrl and Command
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LALT) PORT_NAME("Command") PORT_CHAR(UCHAR_MAMEKEY(LALT))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Space") PORT_CHAR(' ')
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_NAME("Alt") PORT_CHAR(UCHAR_MAMEKEY(RALT))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_00_PAD) PORT_CHAR(UCHAR_MAMEKEY(00_PAD))
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
+
+ PORT_START("KEYSA")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_NAME("I") PORT_CHAR('i') PORT_CHAR('I') PORT_CHAR(0x09)
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_NAME("O") PORT_CHAR('o') PORT_CHAR('O') PORT_CHAR(0x0f)
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_NAME("K") PORT_CHAR('k') PORT_CHAR('K') PORT_CHAR(0x0b)
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_NAME("L") PORT_CHAR('l') PORT_CHAR('L') PORT_CHAR(0x0c)
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+
+ PORT_START("KEYSB")
+ PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F8) PORT_CHAR(UCHAR_MAMEKEY(F8))
+ PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F9) PORT_CHAR(UCHAR_MAMEKEY(F9))
+ PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F10) PORT_CHAR(UCHAR_MAMEKEY(F10))
+ PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F11) PORT_NAME("Blank key")
+ PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F12) PORT_NAME("Break")
+INPUT_PORTS_END
+
+ioport_constructor concept_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(concept_keyboard);
+}
+
+void concept_keyboard_device::device_add_mconfig(machine_config &config)
+{
+ I8035(config, m_mcu, 4.608_MHz_XTAL); // Intel P8048 in EA mode (XTAL marked "48-300-007")
+ m_mcu->set_addrmap(AS_PROGRAM, &concept_keyboard_device::prog_map);
+ m_mcu->p1_in_cb().set(FUNC(concept_keyboard_device::p1_r));
+ m_mcu->p2_out_cb().set(FUNC(concept_keyboard_device::p2_w));
+}
+
+
+ROM_START(concept_kbd)
+ ROM_REGION(0x400, "program", 0)
+ ROM_LOAD("112.z1", 0x000, 0x400, CRC(b3d37000) SHA1(fc58d77919739b66b85eb52b084af9716cd7f260)) // Intel D2758
+ROM_END
+
+const tiny_rom_entry *concept_keyboard_device::device_rom_region() const
+{
+ return ROM_NAME(concept_kbd);
+}
diff --git a/src/mame/concept/concept_kbd.h b/src/mame/concept/concept_kbd.h
new file mode 100644
index 00000000000..8b5c2657af4
--- /dev/null
+++ b/src/mame/concept/concept_kbd.h
@@ -0,0 +1,62 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+
+#ifndef MAME_CONCEPT_CONCEPT_KBD_H
+#define MAME_CONCEPT_CONCEPT_KBD_H
+
+#pragma once
+
+#include "cpu/mcs48/mcs48.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> concept_keyboard_device
+
+class concept_keyboard_device : public device_t
+{
+public:
+ // device type constructor
+ concept_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
+
+ // callback configuration
+ auto txd_callback() { return m_txd_callback.bind(); }
+
+ // serial line input
+ void write_rxd(int state);
+
+protected:
+ // device-level overrides
+ virtual void device_resolve_objects() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+ virtual ioport_constructor device_input_ports() const override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+ virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
+
+private:
+ // MCU handlers
+ u8 p1_r();
+ void p2_w(u8 data);
+
+ // address maps
+ void prog_map(address_map &map) ATTR_COLD;
+
+ // object finders
+ required_device<mcs48_cpu_device> m_mcu;
+ required_ioport_array<12> m_keys;
+ output_finder<> m_led;
+
+ // output callback
+ devcb_write_line m_txd_callback;
+
+ // internal state
+ u8 m_p2_output;
+ u8 m_key_input;
+};
+
+// device type declaration
+DECLARE_DEVICE_TYPE(CONCEPT_KEYBOARD, concept_keyboard_device)
+
+#endif // MAME_CONCEPT_CONCEPT_KBD_H
diff --git a/src/mame/concept/concept_m.cpp b/src/mame/concept/concept_m.cpp
new file mode 100644
index 00000000000..c410ca38c65
--- /dev/null
+++ b/src/mame/concept/concept_m.cpp
@@ -0,0 +1,362 @@
+// license:GPL-2.0+
+// copyright-holders:Raphael Nabet, Brett Wyer
+/*
+ Corvus Concept driver
+
+ Raphael Nabet, Brett Wyer, 2003-2005
+*/
+
+#include "emu.h"
+#include "concept.h"
+
+
+#define VERBOSE 1
+
+#define LOG(x) do { if (VERBOSE > 0) logerror x; } while (0)
+#define VLOG(x) do { if (VERBOSE > 1) logerror x; } while (0)
+
+
+#if 0
+/* interrupt priority encoder */
+enum
+{
+ IOCINT_level = 1, /* serial lines (CTS, DSR & DCD) and I/O ports */
+ SR1INT_level, /* serial port 1 acia */
+ OMINT_level, /* omninet */
+ SR0INT_level, /* serial port 0 acia */
+ TIMINT_level, /* via */
+ KEYINT_level, /* keyboard acia */
+ NMIINT_level /* reserved */
+};
+#endif
+
+/* Clock interface */
+
+/* Omninet */
+/*static int ready;*/ /* ready line from monochip, role unknown */
+
+/* Via */
+
+
+void concept_state::machine_start()
+{
+ // OS will not boot if TDRE is clear on ACIA 0; this fixes that
+ m_acia0->write_cts(0);
+ m_acia0->write_dcd(0);
+ m_acia0->write_dsr(0);
+ m_acia1->write_cts(0);
+ m_acia1->write_dcd(0);
+ m_acia1->write_dsr(0);
+ m_kbdacia->write_cts(0);
+ m_kbdacia->write_dcd(0);
+ m_kbdacia->write_dsr(0);
+
+ /* initialize clock interface */
+ m_clock_enable = false /*true*/;
+
+ save_item(NAME(m_clock_enable));
+ save_item(NAME(m_clock_address));
+}
+
+
+void concept_state::machine_reset()
+{
+}
+
+void concept_state::video_start()
+{
+}
+
+uint32_t concept_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ /* resolution is 720*560 */
+ for (int y = 0; y < 560; y++)
+ {
+ uint16_t *const line = &bitmap.pix(560-1-y);
+ for (int x = 0; x < 720; x++)
+ line[720-1-x] = (m_videoram[(x+48+y*768)>>4] & (0x8000 >> ((x+48+y*768) & 0xf))) ? 1 : 0;
+ }
+ return 0;
+}
+
+/*
+ VIA port A
+
+ 0: omninet ready (I)
+ 1: CTS0 (I)
+ 2: CTS1 (I)
+ 3: DSR0 (I)
+ 4: DSR1 (I)
+ 5: DCD0 (I)
+ 6: DCD1 (I)
+ 7: IOX (O)
+*/
+uint8_t concept_state::via_in_a()
+{
+ LOG(("via_in_a: VIA port A (Omninet and COMM port status) read\n"));
+ return 1; /* omninet ready always 1 */
+}
+
+void concept_state::via_out_a(uint8_t data)
+{
+ LOG(("via_out_a: VIA port A status written: data=0x%2.2x\n", data));
+ /*iox = (data & 0x80) != 0;*/
+}
+
+/*
+ VIA port B
+
+ 0: video off (O)
+ 1: video address 17 (O)
+ 2: video address 18 (O)
+ 3: monitor orientation (I)
+ 4: CH rate select DC0 (serial port line) (O)
+ 5: CH rate select DC1 (serial port line) (O)
+ 6: boot switch 0 (I)
+ 7: boot switch 1 (I)
+*/
+uint8_t concept_state::via_in_b()
+{
+ uint8_t status;
+
+ status = ((ioport("DSW0")->read() & 0x80) >> 1) | ((ioport("DSW0")->read() & 0x40) << 1);
+ LOG(("via_in_b: VIA port B (DIP switches, Video, Comm Rate) - status: 0x%2.2x\n", status));
+ return status;
+}
+
+void concept_state::via_out_b(uint8_t data)
+{
+ VLOG(("via_out_b: VIA port B (Video Control and COMM rate select) written: data=0x%2.2x\n", data));
+}
+
+/*
+ VIA CB2: used as sound output
+*/
+
+void concept_state::via_out_cb2(int state)
+{
+// LOG(("via_out_cb2: Sound control written: data=0x%2.2x\n", state));
+ m_speaker->level_w(state);
+}
+
+uint8_t concept_state::io_r(offs_t offset)
+{
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1: // IO1 registers
+ case 2: // IO2 registers
+ case 3: // IO3 registers
+ case 4: // IO4 registers
+ {
+ int slot = ((offset >> 4) & 7);
+ device_a2bus_card_interface *card = m_a2bus->get_a2bus_card(slot);
+
+ if (card)
+ {
+ return card->read_c0nx(offset & 0x0f);
+ }
+
+ return 0xff;
+ }
+ break;
+
+ default: // ???
+ logerror("concept_io_r: Slot I/O memory accessed for unknown purpose at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+
+ case 1: // IO1 ROM
+ case 2: // IO2 ROM
+ case 3: // IO3 ROM
+ case 4: // IO4 ROM
+ {
+ int slot = (offset >> 8) & 7;
+ device_a2bus_card_interface *card = m_a2bus->get_a2bus_card(slot);
+
+ if (card)
+ {
+ return card->read_cnxx(offset & 0xff);
+ }
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ LOG(("concept_io_r: Slot status read at address 0x03%4.4x\n", offset << 1));
+ return (~m_a2bus->get_a2bus_nmi_mask() & 0x0f) | (~m_a2bus->get_a2bus_irq_mask() & 0x0f) << 4;
+
+ case 6:
+ /* calendar R/W */
+ VLOG(("concept_io_r: Calendar read at address 0x03%4.4x\n", offset << 1));
+ if (!m_clock_enable)
+ return m_mm58174->read(m_clock_address);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ return m_kbdacia->read(offset & 3);
+
+ case 1:
+ /* NSR0 data comm port 0 */
+ return m_acia0->read(offset & 3);
+
+ case 2:
+ /* NSR1 data comm port 1 */
+ return m_acia1->read(offset & 3);
+
+ case 3:
+ /* NVIA versatile system interface */
+// LOG(("concept_io_r: VIA read at address 0x03%4.4x\n", offset << 1));
+ {
+ return m_via0->read(offset & 0xf);
+ }
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ /* write-only? */
+ LOG(("concept_io_r: NCALM clock/calendar read at address 0x03%4.4x\n", offset << 1));
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_r: NOMNI Omninet Transporter register read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_r: NOMOFF Omninet interrupt flip-flop read at address 0x03%4.4x\n", offset << 1);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe (disables interface RAM) */
+ logerror("concept_io_r: NIOSTRB External I/O ROM strobe read at address 0x03%4.4x\n", offset << 1);
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void concept_state::io_w(offs_t offset, uint8_t data)
+{
+ switch ((offset >> 8) & 7)
+ {
+ case 0:
+ /* I/O slot regs */
+ switch ((offset >> 4) & 7)
+ {
+ case 1: // IO1 registers
+ case 2: // IO2 registers
+ case 3: // IO3 registers
+ case 4: // IO4 registers
+ {
+ int slot = (offset >> 4) & 7;
+ device_a2bus_card_interface *card = m_a2bus->get_a2bus_card(slot);
+
+ if (card)
+ {
+ return card->write_c0nx(offset & 0x0f, data);
+ }
+ }
+ break;
+
+ default: // ???
+ logerror("concept_io_w: Slot I/O memory written for unknown purpose at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+
+ case 1: // IO1 ROM
+ case 2: // IO2 ROM
+ case 3: // IO3 ROM
+ case 4: // IO4 ROM
+ {
+ int slot = (offset >> 8) & 7;
+ device_a2bus_card_interface *card = m_a2bus->get_a2bus_card(slot);
+
+ if (card)
+ {
+ return card->write_cnxx(offset & 0xff, data);
+ }
+ }
+ break;
+
+ case 5:
+ /* slot status */
+ logerror("concept_io_w: Slot status written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* calendar R/W */
+ LOG(("concept_io_w: Calendar written to at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data));
+ if (!m_clock_enable)
+ m_mm58174->write(m_clock_address, data & 0xf);
+ break;
+
+ case 7:
+ /* I/O ports */
+ switch ((offset >> 4) & 7)
+ {
+ case 0:
+ /* NKBP keyboard */
+ m_kbdacia->write(offset & 3, data);
+ break;
+
+ case 1:
+ /* NSR0 data comm port 0 */
+ m_acia0->write(offset & 3, data);
+ break;
+
+ case 2:
+ /* NSR1 data comm port 1 */
+ m_acia1->write(offset & 3, data);
+ break;
+
+ case 3:
+ /* NVIA versatile system interface */
+ {
+ m_via0->write(offset & 0xf, data);
+ }
+ break;
+
+ case 4:
+ /* NCALM clock calendar address and strobe register */
+ if (m_clock_enable != ((data & 0x10) != 0))
+ {
+ m_clock_enable = ((data & 0x10) != 0);
+ if (! m_clock_enable)
+ /* latch address when enable goes low */
+ m_clock_address = data & 0x0f;
+ }
+ /*volume_control = (data & 0x20) != 0;*/
+ /*alt_map = (data & 0x40) != 0;*/
+ break;
+
+ case 5:
+ /* NOMNI omninet strobe */
+ logerror("concept_io_w: NOMNI Omninet Transporter register written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 6:
+ /* NOMOFF reset omninet interrupt flip-flop */
+ logerror("concept_io_w: NOMOFF Omninet flip-flop reset at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+
+ case 7:
+ /* NIOSTRB external I/O ROM strobe */
+ logerror("concept_io_w: NIOSTRB External I/O ROM strobe written at address 0x03%4.4x, data: 0x%4.4x\n", offset << 1, data);
+ break;
+ }
+ break;
+ }
+}