summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Miodrag Milanović <mmicko@gmail.com>2014-11-05 08:11:13 +0100
committer Miodrag Milanović <mmicko@gmail.com>2014-11-05 08:11:13 +0100
commit42014bab0b680eb3547b269017430d3f401bd323 (patch)
treed9d72167525eceba2870db37f451bf6ee5391840
parentecbc6c810e5ec97948c36da7f8ae2e3017867a04 (diff)
parente7492ad4bed32153e4eb2d1dde75ba2f6d97871c (diff)
Merge pull request #34 from shattered/_664d68d
dvk_ksm: DEC VT52-compatible video terminal
-rw-r--r--src/emu/drivers/xtal.h1
-rw-r--r--src/mess/drivers/dvk_ksm.c416
-rw-r--r--src/mess/machine/ms7004.c498
-rw-r--r--src/mess/machine/ms7004.h83
-rw-r--r--src/mess/mess.lst1
-rw-r--r--src/mess/mess.mak1
6 files changed, 1000 insertions, 0 deletions
diff --git a/src/emu/drivers/xtal.h b/src/emu/drivers/xtal.h
index 7aed2542f26..032f91fc466 100644
--- a/src/emu/drivers/xtal.h
+++ b/src/emu/drivers/xtal.h
@@ -133,6 +133,7 @@ enum
XTAL_14_7456MHz = 14745600, /* Namco System 12 & System Super 22/23 for JVS */
XTAL_15MHz = 15000000, /* Sinclair QL, Amusco Poker */
XTAL_15_36MHz = 15360000, /* Visual 1050 */
+ XTAL_15_4MHz = 15400000, /* DVK KSM */
XTAL_15_468MHz = 15468480, /* Bank Panic h/w, Sega G80 */
XTAL_15_8976MHz = 15897600, /* IAI Swyft */
XTAL_16MHz = 16000000, /* Extremely common, used on 100's of PCBs */
diff --git a/src/mess/drivers/dvk_ksm.c b/src/mess/drivers/dvk_ksm.c
new file mode 100644
index 00000000000..778cc6b6ba1
--- /dev/null
+++ b/src/mess/drivers/dvk_ksm.c
@@ -0,0 +1,416 @@
+/***************************************************************************
+
+ KSM (Kontroller Simvolnogo Monitora = Character Display Controller),
+ a single-board replacement for standalone 15IE-00-013 terminal (ie15.c)
+ in later-model DVK desktops.
+
+ MPI (Q-Bus clone) board, consumes only power from the bus.
+ Interfaces with MS7004 (DEC LK201 workalike) keyboard and monochrome CRT.
+
+ Hardware revisions (XXX verify everything):
+ - 7.102.076 -- has DIP switches, SRAM at 0x2000, model name "KSM"
+ - 7.102.228 -- no DIP switches, SRAM at 0x2100, model name "KSM-01"
+
+ Emulates a VT52 without copier (ESC Z response is ESC / M), with
+ Hold Screen mode and Graphics character set (but it is unique and
+ mapped to a different range -- 100..137).
+
+ F4 + 0..9 on numeric keypad = setup mode. 0 changes serial port speed,
+ 1..9 toggle one of mode bits:
+
+ 1 XON/XOFF 0: Off 1: On
+ 2 Character set 0: N0/N1 2: N2
+ 3 Auto LF 0: Off 1: On
+ 4 Auto repeat 0: On 1: Off
+ 5 Auto wraparound 0: On 1: Off
+ 6 Interpret controls 0: Interpret 1: Display
+ 7 Parity check 0: Off 1: On
+ 8 Parity bits 0: None 1: Even
+ 9 Stop bits
+
+ N0/N1 charset has regular ASCII in C0 page and Cyrillic in C1 page,
+ switching between them via SI/SO. N2 charset has uppercase Cyrillic
+ chars in place of lowercase Latin ones.
+
+ F1 toggles Hold Screen mode.
+ F9 resets terminal (clears memory).
+ F20 toggles on/off-line mode.
+
+ Terminfo description would be something like
+
+ksm|DVK KSM,
+ am, bw, dch1=\EP, ich1=\EQ,
+ acsc=hRiTjXkClJmFnNqUtEuPv\174wKxW.M\054Q\055S\053\136~_{@}Z0\177,
+ use=vt52,
+
+ To do:
+ - make Caps Lock work
+ - verify if pixel stretching is done by hw
+ - verify details of hw revisions
+ - baud rate selection (missing feature in bitbanger)
+
+****************************************************************************/
+
+#include "emu.h"
+
+#include "bus/rs232/rs232.h"
+#include "cpu/i8085/i8085.h"
+#include "machine/clock.h"
+#include "machine/i8251.h"
+#include "machine/i8255.h"
+#include "machine/ms7004.h"
+#include "machine/pic8259.h"
+
+#define SCREEN_PAGE (80*48)
+
+#define KSM_TOTAL_HORZ 1000
+#define KSM_DISP_HORZ 800
+#define KSM_HORZ_START 200
+
+#define KSM_TOTAL_VERT 28*11
+#define KSM_DISP_VERT 25*11
+#define KSM_VERT_START 2*11
+
+#define KSM_STATUSLINE_TOTAL 11
+#define KSM_STATUSLINE_VRAM 0xF8B0
+
+#define VERBOSE_DBG 0 /* general debug messages */
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_DBG>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f at %s: %-24s",machine().time().as_double(),machine().describe_context(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+class ksm_state : public driver_device
+{
+public:
+ ksm_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_p_videoram(*this, "videoram"),
+ m_maincpu(*this, "maincpu"),
+ m_pic8259(*this, "pic8259"),
+ m_i8251line(*this, "i8251line"),
+ m_rs232(*this, "rs232"),
+ m_i8251kbd(*this, "i8251kbd"),
+ m_ms7004(*this, "ms7004"),
+ m_screen(*this, "screen")
+ { }
+
+ virtual void machine_reset();
+ virtual void video_start();
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ TIMER_DEVICE_CALLBACK_MEMBER( scanline_callback );
+
+ DECLARE_WRITE_LINE_MEMBER(write_keyboard_clock);
+ DECLARE_WRITE_LINE_MEMBER(write_line_clock);
+
+ DECLARE_WRITE8_MEMBER(ksm_ppi_porta_w);
+ DECLARE_WRITE8_MEMBER(ksm_ppi_portc_w);
+
+private:
+ UINT32 draw_scanline(UINT16 *p, UINT16 offset, UINT8 scanline);
+ rectangle m_tmpclip;
+ bitmap_ind16 m_tmpbmp;
+
+ const UINT8 *m_p_chargen;
+ struct {
+ UINT8 line;
+ UINT16 ptr;
+ } m_video;
+
+protected:
+ required_shared_ptr<UINT8> m_p_videoram;
+ required_device<cpu_device> m_maincpu;
+ required_device<pic8259_device> m_pic8259;
+ required_device<i8251_device> m_i8251line;
+ required_device<rs232_port_device> m_rs232;
+ required_device<i8251_device> m_i8251kbd;
+ required_device<ms7004_device> m_ms7004;
+ required_device<screen_device> m_screen;
+};
+
+static ADDRESS_MAP_START( ksm_mem, AS_PROGRAM, 8, ksm_state )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE (0x0000, 0x0fff) AM_ROM
+ AM_RANGE (0x2000, 0x21ff) AM_RAM
+ AM_RANGE (0xc000, 0xffff) AM_RAM AM_SHARE("videoram")
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( ksm_io, AS_IO, 8, ksm_state )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE (0x5e, 0x5f) AM_DEVREADWRITE("pic8259", pic8259_device, read, write)
+ AM_RANGE (0x6e, 0x6e) AM_DEVREADWRITE("i8251kbd", i8251_device, data_r, data_w)
+ AM_RANGE (0x6f, 0x6f) AM_DEVREADWRITE("i8251kbd", i8251_device, status_r, control_w)
+ AM_RANGE (0x76, 0x76) AM_DEVREADWRITE("i8251line", i8251_device, data_r, data_w)
+ AM_RANGE (0x77, 0x77) AM_DEVREADWRITE("i8251line", i8251_device, status_r, control_w)
+ AM_RANGE (0x78, 0x7b) AM_DEVREADWRITE("ppi8255", i8255_device, read, write)
+ADDRESS_MAP_END
+
+/* Input ports */
+static INPUT_PORTS_START( ksm )
+ PORT_START("SA1")
+ PORT_DIPNAME(0x01, 0x01, "Stop bits")
+ PORT_DIPSETTING(0x00, "2 bits")
+ PORT_DIPSETTING(0x01, "1 bit")
+ PORT_DIPNAME(0x02, 0x00, "Parity bits")
+ PORT_DIPSETTING(0x00, "0 bits")
+ PORT_DIPSETTING(0x02, "1 bit")
+ PORT_DIPNAME(0x04, 0x00, "Parity check")
+ PORT_DIPSETTING(0x00, "Off")
+ PORT_DIPSETTING(0x04, "On")
+ PORT_DIPNAME(0x08, 0x00, "Interpret controls")
+ PORT_DIPSETTING(0x00, "Interpret")
+ PORT_DIPSETTING(0x08, "Display")
+ PORT_DIPNAME(0x10, 0x00, "Auto wraparound")
+ PORT_DIPSETTING(0x00, "On")
+ PORT_DIPSETTING(0x10, "Off")
+ PORT_DIPNAME(0x20, 0x00, "Auto repeat")
+ PORT_DIPSETTING(0x00, "On")
+ PORT_DIPSETTING(0x20, "Off")
+ PORT_DIPNAME(0x40, 0x00, "Auto CR/LF")
+ PORT_DIPSETTING(0x00, "Off")
+ PORT_DIPSETTING(0x40, "On")
+ PORT_DIPNAME(0x80, 0x00, "Character set")
+ PORT_DIPSETTING(0x00, "KOI-8 N0/N1")
+ PORT_DIPSETTING(0x80, "KOI-8 N2")
+ PORT_START("SA2")
+ PORT_DIPNAME(0x01, 0x00, "XON/XOFF")
+ PORT_DIPSETTING(0x00, "Off")
+ PORT_DIPSETTING(0x01, "On")
+ PORT_DIPNAME(0x0E, 0x00, "Baud rate")
+ PORT_DIPSETTING(0x00, "9600")
+ PORT_DIPSETTING(0x02, "4800")
+ PORT_DIPSETTING(0x04, "2400")
+ PORT_DIPSETTING(0x06, "1200")
+ PORT_DIPSETTING(0x08, "600")
+ PORT_DIPSETTING(0x0A, "300")
+ PORT_DIPSETTING(0x0C, "150")
+ PORT_DIPSETTING(0x0E, "75")
+INPUT_PORTS_END
+
+void ksm_state::machine_reset()
+{
+ memset(&m_video, 0, sizeof(m_video));
+}
+
+void ksm_state::video_start()
+{
+ m_p_chargen = memregion("chargen")->base();
+
+ m_tmpclip = rectangle(0, KSM_DISP_HORZ-1, 0, KSM_DISP_VERT-1);
+ m_tmpbmp.allocate(KSM_DISP_HORZ, KSM_DISP_VERT);
+}
+
+WRITE8_MEMBER(ksm_state::ksm_ppi_porta_w)
+{
+ DBG_LOG(1,"PPI port A", ("line %d\n", data));
+ m_video.line = data;
+}
+
+WRITE8_MEMBER(ksm_state::ksm_ppi_portc_w)
+{
+ DBG_LOG(1,"PPI port C", ("blink %d speed %d\n", BIT(data, 7), ((data >> 4) & 7) ));
+}
+
+WRITE_LINE_MEMBER(ksm_state::write_keyboard_clock)
+{
+// KSM never sends data to keyboard
+// m_i8251kbd->write_txc(state);
+ m_i8251kbd->write_rxc(state);
+}
+
+WRITE_LINE_MEMBER(ksm_state::write_line_clock)
+{
+ m_i8251line->write_txc(state);
+ m_i8251line->write_rxc(state);
+}
+
+/*
+ Raster size is 28x11 scan lines.
+ XXX VBlank is active for 2 topmost on-screen rows and 1 at the bottom.
+
+ Usable raster is 800 x 275 pixels (80 x 25 characters). 24 lines are
+ available to the user and 25th (topmost) line is the status line.
+ Status line displays current serial port speed and 9 setup bits.
+
+ No character attributes are available, but in 'display controls' mode
+ control characters stored in memory are shown as blinking chars.
+
+ Character cell is 10 x 11; character generator provides 7 x 8 of that.
+ 3 extra horizontal pixels are always XXX blank. Blinking XXX cursor may be
+ displayed on 3 extra scan lines.
+*/
+
+UINT32 ksm_state::draw_scanline(UINT16 *p, UINT16 offset, UINT8 scanline)
+{
+ UINT8 gfx, fg, bg, ra, blink;
+ UINT16 x, chr;
+
+ bg = 0; fg = 1; ra = scanline % 8;
+ blink = (m_screen->frame_number() % 10) > 4;
+ if (scanline > 7) {
+ offset -= 0x2000;
+ }
+
+ for (x = offset; x < offset + 80; x++)
+ {
+ chr = m_p_videoram[x] << 3;
+ gfx = m_p_chargen[chr | ra];
+
+ if ((scanline > 7 && blink) || ((chr < (0x20<<3)) && !blink))
+ gfx = 0;
+
+ *p++ = BIT(gfx, 6) ? fg : bg;
+ *p++ = BIT(gfx, 5) ? fg : bg;
+ *p++ = BIT(gfx, 4) ? fg : bg;
+ *p++ = BIT(gfx, 3) ? fg : bg;
+ *p++ = BIT(gfx, 2) ? fg : bg;
+ *p++ = BIT(gfx, 1) ? fg : bg;
+ *p++ = BIT(gfx, 0) ? fg : bg;
+ *p++ = bg;
+ *p++ = bg;
+ *p++ = bg;
+ }
+ return 0;
+}
+
+TIMER_DEVICE_CALLBACK_MEMBER(ksm_state::scanline_callback)
+{
+ UINT16 y = m_screen->vpos();
+ UINT16 offset;
+
+ DBG_LOG(2,"scanline_cb",
+ ("addr %02x frame %" I64FMT "d x %.4d y %.3d row %.2d\n",
+ m_video.line, m_screen->frame_number(), m_screen->hpos(), y, y%11));
+
+ if (y < KSM_VERT_START) return;
+ y -= KSM_VERT_START;
+ if (y >= KSM_DISP_VERT) return;
+
+ if (y < KSM_STATUSLINE_TOTAL) {
+ offset = KSM_STATUSLINE_VRAM - 0xC000;
+ } else {
+ offset = 0x2000 + 0x30 + (((m_video.line + y/11 - 1) % 48) << 7);
+ }
+
+ draw_scanline(&m_tmpbmp.pix16(y), offset, y%11);
+}
+
+UINT32 ksm_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ copybitmap(bitmap, m_tmpbmp, 0, 0, KSM_HORZ_START, KSM_VERT_START, cliprect);
+ return 0;
+}
+
+
+/* F4 Character Displayer */
+static const gfx_layout ksm_charlayout =
+{
+ 7, 8, /* 7x8 pixels in 10x11 cell */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 bytes */
+};
+
+static GFXDECODE_START( ksm )
+ GFXDECODE_ENTRY("chargen", 0x0000, ksm_charlayout, 0, 1)
+GFXDECODE_END
+
+static MACHINE_CONFIG_START( ksm, ksm_state )
+ MCFG_CPU_ADD("maincpu", I8080, XTAL_15_4MHz/10)
+ MCFG_CPU_PROGRAM_MAP(ksm_mem)
+ MCFG_CPU_IO_MAP(ksm_io)
+ MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("pic8259", pic8259_device, inta_cb)
+
+ MCFG_TIMER_DRIVER_ADD_PERIODIC("scantimer", ksm_state, scanline_callback, attotime::from_hz(50*28*11))
+ MCFG_TIMER_START_DELAY(attotime::from_hz(XTAL_15_4MHz/KSM_HORZ_START))
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_UPDATE_DRIVER(ksm_state, screen_update)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_15_4MHz, KSM_TOTAL_HORZ, KSM_HORZ_START,
+ KSM_HORZ_START+KSM_DISP_HORZ, KSM_TOTAL_VERT, KSM_VERT_START,
+ KSM_VERT_START+KSM_DISP_VERT);
+
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", ksm)
+ MCFG_PALETTE_ADD_MONOCHROME_GREEN("palette")
+
+ MCFG_PIC8259_ADD( "pic8259", INPUTLINE("maincpu", 0), VCC, NULL )
+
+ MCFG_DEVICE_ADD("ppi8255", I8255, 0)
+ MCFG_I8255_OUT_PORTA_CB(WRITE8(ksm_state, ksm_ppi_porta_w))
+ MCFG_I8255_IN_PORTB_CB(IOPORT("SA1"))
+ MCFG_I8255_IN_PORTC_CB(IOPORT("SA2"))
+ MCFG_I8255_OUT_PORTC_CB(WRITE8(ksm_state, ksm_ppi_portc_w))
+
+ // serial connection to host
+ MCFG_DEVICE_ADD( "i8251line", I8251, 0)
+ MCFG_I8251_TXD_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_txd))
+ MCFG_I8251_DTR_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_dtr))
+ MCFG_I8251_RTS_HANDLER(DEVWRITELINE("rs232", rs232_port_device, write_rts))
+ MCFG_I8251_RXRDY_HANDLER(DEVWRITELINE("pic8259", pic8259_device, ir3_w))
+
+ MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, "null_modem")
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("i8251line", i8251_device, write_rxd))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("i8251line", i8251_device, write_cts))
+ MCFG_RS232_DSR_HANDLER(DEVWRITELINE("i8251line", i8251_device, write_dsr))
+
+ MCFG_DEVICE_ADD("line_clock", CLOCK, 9600*16) // 8251 is set to /16 on the clock input
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(ksm_state, write_line_clock))
+
+ // serial connection to MS7004 keyboard
+ MCFG_DEVICE_ADD( "i8251kbd", I8251, 0)
+ MCFG_I8251_RXRDY_HANDLER(DEVWRITELINE("pic8259", pic8259_device, ir1_w))
+
+ MCFG_DEVICE_ADD("ms7004", MS7004, 0)
+ MCFG_MS7004_TX_HANDLER(DEVWRITELINE("i8251kbd", i8251_device, write_rxd))
+
+ // baud rate is supposed to be 4800 but keyboard is slightly faster
+ MCFG_DEVICE_ADD("keyboard_clock", CLOCK, 4960*16)
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(ksm_state, write_keyboard_clock))
+MACHINE_CONFIG_END
+
+
+/*
+ Assumes that SRAM is at 0x2000, which is where technical manual puts it.
+ Chargen has 1 missing pixel in 'G' character.
+*/
+ROM_START( dvk_ksm )
+ ROM_REGION(0x1000, "maincpu", ROMREGION_ERASE00)
+ ROM_LOAD( "ksm_04_rom0_d32.bin", 0x0000, 0x0800, CRC(6ad62715) SHA1(20f8f95119bc7fc6e0f16c67864e339a86edb44d))
+ ROM_LOAD( "ksm_05_rom1_d33.bin", 0x0800, 0x0800, CRC(5b29bcd2) SHA1(1f4f82c2f88f1e8615ec02076559dc606497e654))
+
+ ROM_REGION(0x0800, "chargen", ROMREGION_ERASE00)
+ ROM_LOAD("ksm_03_cg_d31.bin", 0x0000, 0x0800, CRC(98853aa7) SHA1(09b8e1b5b10a00c0b0ae7e36ad1328113d31230a))
+ROM_END
+
+/*
+ Assumes that SRAM is at 0x2100, otherwise identical.
+ Chargen has no missing pixels in 'G' character.
+*/
+ROM_START( dvk_ksm01 )
+ ROM_REGION(0x1000, "maincpu", ROMREGION_ERASE00)
+ ROM_LOAD( "ksm_04_rom0_d32.bin", 0x0000, 0x0800, CRC(5276dc9a) SHA1(dd41dfb4cb3f1cf22d96d95f1ff6a27fe4eb9a38))
+ ROM_LOAD( "ksm_05_rom1_d33.bin", 0x0800, 0x0800, CRC(5b29bcd2) SHA1(1f4f82c2f88f1e8615ec02076559dc606497e654))
+
+ ROM_REGION(0x0800, "chargen", ROMREGION_ERASE00)
+ ROM_LOAD("ksm_03_cg_d31.bin", 0x0000, 0x0800, CRC(98853aa7) SHA1(c7871a96f135db05c3c8d718fbdf1728e22e72b7))
+ROM_END
+
+/* Driver */
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
+COMP( 1986, dvk_ksm, 0, 0, ksm, ksm, driver_device, 0, "USSR", "DVK KSM", 0)
+COMP( 198?, dvk_ksm01,0 , 0, ksm, ksm, driver_device, 0, "USSR", "DVK KSM-01", 0)
diff --git a/src/mess/machine/ms7004.c b/src/mess/machine/ms7004.c
new file mode 100644
index 00000000000..b145479db2b
--- /dev/null
+++ b/src/mess/machine/ms7004.c
@@ -0,0 +1,498 @@
+/*
+ Electronika MS 7004 keyboard (DEC LK-201 workalike with extra keys
+ for Cyrillic characters).
+
+ To do:
+ - debug keymap
+ - receive data from host (not used by KSM but used by other boards)
+ - connect LEDs and speaker
+*/
+
+#include "emu.h"
+#include "ms7004.h"
+
+#define VERBOSE_DBG 1 /* general debug messages */
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_DBG>=N) \
+ { \
+ logerror("%11.6f at %s: ",machine().time().as_double(),machine().describe_context()); \
+ logerror A; \
+ } \
+ } while (0)
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define MS7004_CPU_TAG "i8048"
+#define MS7004_SPK_TAG "beeper"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MS7004 = &device_creator<ms7004_device>;
+
+ROM_START( ms7004 )
+ ROM_REGION (0x800, MS7004_CPU_TAG, 0)
+ ROM_LOAD ("mc7004_keyboard_original.rom", 0x0000, 0x800, CRC(69fcab53) SHA1(2d7cc7cd182f2ee09ecf2c539e33db3c2195f778))
+ROM_END
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( ms7004_map, AS_IO, 8, ms7004_device )
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_WRITE(p1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_WRITE(p2_w)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(t1_r)
+ AM_RANGE(MCS48_PORT_PROG, MCS48_PORT_PROG) AM_DEVWRITE("i8243", i8243_device, i8243_prog_w)
+ADDRESS_MAP_END
+
+//-------------------------------------------------
+// MACHINE_CONFIG
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( ms7004 )
+ MCFG_CPU_ADD(MS7004_CPU_TAG, I8048, XTAL_4_608MHz)
+ MCFG_CPU_IO_MAP(ms7004_map)
+
+ MCFG_I8243_ADD("i8243", NOOP, WRITE8(ms7004_device, i8243_port_w))
+
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD(MS7004_SPK_TAG, BEEP, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor ms7004_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ms7004 );
+}
+
+const rom_entry *ms7004_device::device_rom_region() const
+{
+ return ROM_NAME( ms7004 );
+}
+
+//-------------------------------------------------
+// INPUT_PORTS( ms7004 )
+//-------------------------------------------------
+/*
+bit sig XSn ВРn
+--- --- --- ---
+0 8 16 15
+1 9 15 14
+2 10 14 13
+3 11 13 12
+4 12 19 16
+5 13 12 11
+6 14 11 10
+7 15 10 9
+8 16 9 8
+9 17 8 7
+10 18 7 6
+11 19 6 5
+12 20 3 1
+13 21 1 2
+14 22 4 3
+15 23 5 4
+
+0xc9 KEY_LANGLE_RANGLE 'резервная клавиша'
+0xbc KEY_DELETE ЗБ
+0xbd KEY_RETURN ВК
+0xbf KEY_TILDE '; +'
+0xc4 - 'Ъ'
+0xca - '/ ?'
+0xed KEY_PERIOD 'Ю @'
+0xf1 - '_'
+<...>
+
+0x56 KEY_F1 СТОП КАДР
+0x57 KEY_F2 ПЕЧАТЬ КАДРА
+0x58 KEY_F3 ПАУЗА
+0x59 KEY_F4 УСТ РЕЖИМА
+0x5a KEY_F5 Ф5
+
+0x64 KEY_F6 ПРЕРЫВ
+0x65 KEY_F7 ПРОДОЛЖ
+0x66 KEY_F8 ОТМЕН
+0x67 KEY_F9 ОСНОВН КАДР
+0x69 KEY_F10 ВЫХОД
+
+0x71 KEY_F11 Ф11 (АР2)
+0x72 KEY_F12 Ф12 (ВШ)
+0x73 KEY_F13 Ф13 (ПС)
+0x74 KEY_F14 ДОП ВАРИАНТ
+
+0x7c KEY_HELP ПМ
+0x7d KEY_MENU ИСП
+
+0x80 KEY_F17 Ф17
+0x81 KEY_F18 Ф18
+0x82 KEY_F19 Ф19
+0x83 KEY_F20 Ф20
+
+0xb0 KEY_LOCK ФКС
+0xae KEY_SHIFT ВР
+0xaf KEY_CTRL СУ
+
+0xb1 KEY_META КМП
+0xb2 - РУС/ЛАТ
+
+0x8a KEY_FIND НТ
+0x8b KEY_INSERT_HERE ВСТ
+0x8c KEY_REMOVE УДАЛ
+0x8d KEY_SELECT ВЫБР
+0x8e KEY_PREV_SCREEN ПРЕД КАДР
+0x8f KEY_NEXT_SCREEN СЛЕД КАДР
+
+nothing sends '@' or '`'
+
+`/~ sends ^/~
+2/@ sends 2/"
+6/^ sends 6/&
+7/& sends 7/'
+8/ * sends 8/(
+9/( sends 9/)
+0/) sends 0/0
+-/_ sends _/_
++/= sends -/=
+;/: sends ;/+
+'/" sends :/ *
+
+F10 sends ^C
+F11 sends ESC
+F12 sends ^H
+*/
+INPUT_PORTS_START( ms7004 )
+ PORT_START("KBD12") // vertical row 1
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Print Screen (F2)") PORT_CODE(KEYCODE_F2)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Hold Screen (F1)") PORT_CODE(KEYCODE_F1)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '{' / '|'
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(";") PORT_CODE(KEYCODE_COLON) // '+'
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Ctrl") PORT_CODE(KEYCODE_LCONTROL)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) // what
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LShift") PORT_CODE(KEYCODE_LSHIFT)
+
+ PORT_START("KBD13") // vertical row 2
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Setup (F3)") PORT_CODE(KEYCODE_F3)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Data / Talk (F4)") PORT_CODE(KEYCODE_F4)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("1") PORT_CODE(KEYCODE_1)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("J") PORT_CODE(KEYCODE_J)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("C") PORT_CODE(KEYCODE_C)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F") PORT_CODE(KEYCODE_F)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Rus/Lat") PORT_CODE(KEYCODE_ESC)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Compose") PORT_CODE(KEYCODE_LALT)
+
+ PORT_START("KBD14") // vertical row 3
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Break (F5)") PORT_CODE(KEYCODE_F5)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("2") PORT_CODE(KEYCODE_2)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("U") PORT_CODE(KEYCODE_U)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Tilde") PORT_CODE(KEYCODE_TILDE) // ^
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD15") // vertical row 4
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("3") PORT_CODE(KEYCODE_3)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("4") PORT_CODE(KEYCODE_4)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("K") PORT_CODE(KEYCODE_K)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("W") PORT_CODE(KEYCODE_W)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("S") PORT_CODE(KEYCODE_S)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD11") // vertical row 5
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Interrupt (F6)") PORT_CODE(KEYCODE_F6)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("5") PORT_CODE(KEYCODE_5)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("E") PORT_CODE(KEYCODE_E)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("P") PORT_CODE(KEYCODE_P)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("A") PORT_CODE(KEYCODE_A)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("M") PORT_CODE(KEYCODE_M)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD10") // vertical row 6
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Resume (F7)") PORT_CODE(KEYCODE_F7)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("6") PORT_CODE(KEYCODE_6)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("N") PORT_CODE(KEYCODE_N)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("G") PORT_CODE(KEYCODE_G)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("R") PORT_CODE(KEYCODE_R)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("T") PORT_CODE(KEYCODE_T)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("I") PORT_CODE(KEYCODE_I)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Space") PORT_CODE(KEYCODE_SPACE)
+
+ PORT_START("KBD9") // vertical row 7
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Cancel (F8)") PORT_CODE(KEYCODE_F8)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Main Screen (F9)") PORT_CODE(KEYCODE_F9)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("7") PORT_CODE(KEYCODE_7)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("[") PORT_CODE(KEYCODE_OPENBRACE)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("]") PORT_CODE(KEYCODE_CLOSEBRACE)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("O") PORT_CODE(KEYCODE_O)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("X") PORT_CODE(KEYCODE_X)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("B") PORT_CODE(KEYCODE_B)
+
+ PORT_START("KBD8") // vertical row 8
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Exit (F10)") PORT_CODE(KEYCODE_F10)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("9") PORT_CODE(KEYCODE_9)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("8") PORT_CODE(KEYCODE_8)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("D") PORT_CODE(KEYCODE_D)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("L") PORT_CODE(KEYCODE_L)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // '@'
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA)
+
+ PORT_START("KBD7") // vertical row 9
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("ESC (F11)") PORT_CODE(KEYCODE_F11)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("0") PORT_CODE(KEYCODE_0)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("=") PORT_CODE(KEYCODE_EQUALS)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("H") PORT_CODE(KEYCODE_H)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("V") PORT_CODE(KEYCODE_V)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("\\") PORT_CODE(KEYCODE_BACKSLASH)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("/") PORT_CODE(KEYCODE_SLASH)
+
+ PORT_START("KBD6") // vertical row 10
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("BS (F12)") PORT_CODE(KEYCODE_F12)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("LF (F13)") PORT_CODE(KEYCODE_PRTSCR)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // '}'
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("'") PORT_CODE(KEYCODE_QUOTE) // ':'
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // 'ъ'
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME(".") PORT_CODE(KEYCODE_STOP)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("-") PORT_CODE(KEYCODE_MINUS)
+
+ PORT_START("KBD5") // vertical row 11
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Additional Options (F14)") PORT_CODE(KEYCODE_PAUSE)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Delete <X") PORT_CODE(KEYCODE_BACKSPACE)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) // ???
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("RShift") PORT_CODE(KEYCODE_RSHIFT)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD3") // vertical row 12
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Help (F15)") PORT_CODE(KEYCODE_RALT)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Insert Here") PORT_CODE(KEYCODE_HOME)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Find") PORT_CODE(KEYCODE_INSERT)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Select") PORT_CODE(KEYCODE_DEL)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Up") PORT_CODE(KEYCODE_UP)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Left") PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD2") // vertical row 13
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Remove") PORT_CODE(KEYCODE_PGUP)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Next [v]") PORT_CODE(KEYCODE_PGDN)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Previous [^]") PORT_CODE(KEYCODE_END)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Right") PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Down") PORT_CODE(KEYCODE_DOWN)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("KBD1") // vertical row 14
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Do (F16)") PORT_CODE(KEYCODE_RCONTROL)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF1") PORT_CODE(KEYCODE_NUMLOCK)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 7") PORT_CODE(KEYCODE_7_PAD)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 4") PORT_CODE(KEYCODE_4_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 1") PORT_CODE(KEYCODE_1_PAD)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 2") PORT_CODE(KEYCODE_2_PAD)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 0") PORT_CODE(KEYCODE_0_PAD)
+
+ PORT_START("KBD0") // vertical row 15
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F17")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F18")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF2") PORT_CODE(KEYCODE_SLASH_PAD)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF3") PORT_CODE(KEYCODE_ASTERISK)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 8") PORT_CODE(KEYCODE_8_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 5") PORT_CODE(KEYCODE_5_PAD)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 6") PORT_CODE(KEYCODE_6_PAD)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 3") PORT_CODE(KEYCODE_3_PAD)
+
+ PORT_START("KBD4") // vertical row 16
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F19")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("F20")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("PF4") PORT_CODE(KEYCODE_MINUS_PAD)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num 9") PORT_CODE(KEYCODE_9_PAD)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num ,") PORT_CODE(KEYCODE_PLUS_PAD)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num -")
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Num .") PORT_CODE(KEYCODE_DEL_PAD) // "." on num.pad
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER_PAD)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor ms7004_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ms7004 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// ms7004_device - constructor
+//-------------------------------------------------
+
+ms7004_device::ms7004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MS7004, "MS7004 keyboard", tag, owner, clock, "ms7004", __FILE__),
+// device_serial_interface(mconfig, *this),
+ m_maincpu(*this, MS7004_CPU_TAG),
+ m_speaker(*this, MS7004_SPK_TAG),
+ m_i8243(*this, "i8243"),
+ m_kbd0(*this, "KBD0"),
+ m_kbd1(*this, "KBD1"),
+ m_kbd2(*this, "KBD2"),
+ m_kbd3(*this, "KBD3"),
+ m_kbd4(*this, "KBD4"),
+ m_kbd5(*this, "KBD5"),
+ m_kbd6(*this, "KBD6"),
+ m_kbd7(*this, "KBD7"),
+ m_kbd8(*this, "KBD8"),
+ m_kbd9(*this, "KBD9"),
+ m_kbd10(*this, "KBD10"),
+ m_kbd11(*this, "KBD11"),
+ m_kbd12(*this, "KBD12"),
+ m_kbd13(*this, "KBD13"),
+ m_kbd14(*this, "KBD14"),
+ m_kbd15(*this, "KBD15"),
+ m_tx_handler(*this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void ms7004_device::device_start()
+{
+ m_tx_handler.resolve_safe();
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void ms7004_device::device_reset()
+{
+}
+
+
+//-------------------------------------------------
+// p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ms7004_device::p1_w )
+{
+ /*
+ bit description
+
+ 0 Matrix row bit 0
+ 1 Matrix row bit 1
+ 2 Matrix row bit 2
+ 3 Speaker
+ 4 -STROBE (to matrix mux)
+ 5 LED "Latin"
+ 6
+ 7 Serial TX
+ */
+ DBG_LOG(1,0,( "%s: p1_w %02x = send %d\n", tag(), data, BIT(data, 7)));
+
+ m_p1 = data;
+ m_tx_handler(BIT(data, 7));
+}
+
+
+//-------------------------------------------------
+// p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ms7004_device::p2_w )
+{
+ /*
+ bit description
+
+ 0 Matrix columns, to 8243 (port 4)
+ 1 Matrix columns, to 8243 (port 5)
+ 2 Matrix columns, to 8243 (port 6)
+ 3 Matrix columns, to 8243 (port 7)
+ 4 LED "Wait"
+ 5 LED "Compose"
+ 6 LED "Caps"
+ 7 LED "Hold"
+ */
+ DBG_LOG(2,0,( "%s: p2_w %02x = col %d\n", tag(), data, data&15));
+
+ m_p2 = data;
+ m_i8243->i8243_p2_w(space, offset, data);
+}
+
+
+//-------------------------------------------------
+// prog_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( ms7004_device::i8243_port_w )
+{
+ int sense = 0;
+
+ DBG_LOG(2,0,( "%s: 8243 port %d data %02xH\n",
+ tag(), offset + 4, data));
+
+ if (data) {
+ switch(offset << 4 | data) {
+ case 0x01: sense = m_kbd0->read(); break;
+ case 0x02: sense = m_kbd1->read(); break;
+ case 0x04: sense = m_kbd2->read(); break;
+ case 0x08: sense = m_kbd3->read(); break;
+ case 0x11: sense = m_kbd4->read(); break;
+ case 0x12: sense = m_kbd5->read(); break;
+ case 0x14: sense = m_kbd6->read(); break;
+ case 0x18: sense = m_kbd7->read(); break;
+ case 0x21: sense = m_kbd8->read(); break;
+ case 0x22: sense = m_kbd9->read(); break;
+ case 0x24: sense = m_kbd10->read(); break;
+ case 0x28: sense = m_kbd11->read(); break;
+ case 0x31: sense = m_kbd12->read(); break;
+ case 0x32: sense = m_kbd13->read(); break;
+ case 0x34: sense = m_kbd14->read(); break;
+ case 0x38: sense = m_kbd15->read(); break;
+ }
+ m_keylatch = BIT(sense, (m_p1 & 7));
+ DBG_LOG(2,0,( "%s: row %d col %02x t1 %d\n",
+ tag(), (m_p1 & 7), (offset << 4 | data), m_keylatch));
+ }
+}
+
+
+//-------------------------------------------------
+// t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( ms7004_device::t1_r )
+{
+ if (!BIT(m_p1,4))
+ return m_keylatch;
+ else
+ return 0;
+}
diff --git a/src/mess/machine/ms7004.h b/src/mess/machine/ms7004.h
new file mode 100644
index 00000000000..1602320d5ea
--- /dev/null
+++ b/src/mess/machine/ms7004.h
@@ -0,0 +1,83 @@
+#pragma once
+
+#ifndef __MS7004_H__
+#define __MS7004_H__
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "machine/i8243.h"
+#include "sound/beep.h"
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_MS7004_TX_HANDLER(_cb) \
+ devcb = &ms7004_device::set_tx_handler(*device, DEVCB_##_cb);
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> ms7004_device
+
+class ms7004_device : public device_t //, public device_serial_interface
+{
+public:
+ // construction/destruction
+ ms7004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ template<class _Object> static devcb_base &set_tx_handler(device_t &device, _Object wr) { return downcast<ms7004_device &>(device).m_tx_handler.set_callback(wr); }
+
+ DECLARE_WRITE8_MEMBER( p1_w );
+ DECLARE_WRITE8_MEMBER( p2_w );
+ DECLARE_READ8_MEMBER( t1_r );
+ DECLARE_WRITE8_MEMBER( i8243_port_w );
+
+protected:
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<beep_device> m_speaker;
+ required_device<i8243_device> m_i8243;
+
+ required_ioport m_kbd0;
+ required_ioport m_kbd1;
+ required_ioport m_kbd2;
+ required_ioport m_kbd3;
+ required_ioport m_kbd4;
+ required_ioport m_kbd5;
+ required_ioport m_kbd6;
+ required_ioport m_kbd7;
+ required_ioport m_kbd8;
+ required_ioport m_kbd9;
+ required_ioport m_kbd10;
+ required_ioport m_kbd11;
+ required_ioport m_kbd12;
+ required_ioport m_kbd13;
+ required_ioport m_kbd14;
+ required_ioport m_kbd15;
+
+ int m_keylatch; // keyboard row latch
+ UINT8 m_p1;
+ UINT8 m_p2;
+
+ devcb_write_line m_tx_handler;
+};
+
+// device type definition
+extern const device_type MS7004;
+
+#endif
diff --git a/src/mess/mess.lst b/src/mess/mess.lst
index ece11427185..110903f6dfa 100644
--- a/src/mess/mess.lst
+++ b/src/mess/mess.lst
@@ -2478,6 +2478,7 @@ itt3030
vax785
ms0515
ie15
+dvk_ksm
asmapro
asma2k
altos5
diff --git a/src/mess/mess.mak b/src/mess/mess.mak
index 4f3aade4f92..caa554cd408 100644
--- a/src/mess/mess.mak
+++ b/src/mess/mess.mak
@@ -1180,6 +1180,7 @@ $(MESSOBJ)/einis.a: \
$(MESSOBJ)/elektrka.a: \
$(MESS_DRIVERS)/bk.o $(MESS_MACHINE)/bk.o $(MESS_VIDEO)/bk.o \
+ $(MESS_DRIVERS)/dvk_ksm.o $(MESS_MACHINE)/ms7004.o \
$(MESS_DRIVERS)/mk85.o \
$(MESS_DRIVERS)/mk90.o \