Replaced hacky Kaypro keyboard that bypassed the SIO with emulated

Kaypro 10 keyboard. [Vas Crabb, rfka01, TeamEurope]

(nw) This exposes other issues in MAME.  Some incredibly poorly-written
code in the keyboard MCU depends on the fact that the T register is
updated during S4 then copied to A during S4 when mov a,t is executed.
If it doesn't see zero in this register when mov a,t is executed
immediately before the timer interrupt is taken, it hangs.
Really, the MCS-48 core needs to be re-written so it works at S-cycle
level (if not clock cycle leve), but for now I've worked around this
case in the least intrusive way possible.
This also exposes issues in the Z80DART code.  The keyboard communicates
0.8% slower than the nominal 300 Baud.  This works perfectly in real
life, but it causes occasional corrupted characters with MAME's
implementation, particularly if you hold a key down and let it repeat.
The Z80DART device needs to be fixed so it samples closer to the middle
of the bit intervals and re-aquires on each start bit.
Finally, I haven't hooked up the Kaypro's serial port Baud rate
genrators, or exposed the serial ports as slots.  I'll leave that for
someone else to worry about.
This commit is contained in:
Vas Crabb 2017-10-28 03:50:22 +11:00
parent f1dfb9d544
commit 30361572bd
7 changed files with 454 additions and 523 deletions

View File

@ -7,7 +7,13 @@
reimplement as a push, not a pull
- T0 output clock
- get rid of i/o addressmap, use devcb for mcu pins
- add CMOS devices, 1 new opcode(01 HALT)
- add CMOS devices, 1 new opcode (01 HALT)
- make timer update cleaner:
timer is updated on S4 while I/O happens on S5
due to very bad coding, Kaypro 10 keyboard depends on being able to see T=0 before interrupt is taken
right now this is implemented with a hack in the mov_a_t handler
in theory it should also be possible to see the timer flag before the interrupt is taken
mov_t_a should also update the T register after it's incremented
*/
/***************************************************************************
@ -121,24 +127,6 @@
MACROS
***************************************************************************/
/* ROM is mapped to AS_PROGRAM */
#define program_r(a) m_program->read_byte(a)
/* RAM is mapped to AS_DATA */
#define ram_r(a) m_data->read_byte(a)
#define ram_w(a,V) m_data->write_byte(a, V)
/* ports are mapped to AS_IO and callbacks */
#define ext_r(a) m_io->read_byte(a)
#define ext_w(a,V) m_io->write_byte(a, V)
#define port_r(a) m_port_in_cb[a-1]()
#define port_w(a,V) m_port_out_cb[a-1](V)
#define test_r(a) m_test_in_cb[a]()
#define test_w(a,V) m_test_out_cb[a](V)
#define bus_r() m_bus_in_cb()
#define bus_w(V) m_bus_out_cb(V)
#define prog_w(V) m_prog_out_cb(V)
/* r0-r7 map to memory via the regptr */
#define R0 m_regptr[0]
#define R1 m_regptr[1]
@ -151,24 +139,24 @@
DEFINE_DEVICE_TYPE(I8021, i8021_device, "i8021", "I8021")
DEFINE_DEVICE_TYPE(I8022, i8022_device, "i8022", "I8022")
DEFINE_DEVICE_TYPE(I8035, i8035_device, "i8035", "I8035")
DEFINE_DEVICE_TYPE(I8048, i8048_device, "i8048", "I8048")
DEFINE_DEVICE_TYPE(I8648, i8648_device, "i8648", "I8648")
DEFINE_DEVICE_TYPE(I8748, i8748_device, "i8748", "I8748")
DEFINE_DEVICE_TYPE(I8039, i8039_device, "i8039", "I8039")
DEFINE_DEVICE_TYPE(I8049, i8049_device, "i8049", "I8049")
DEFINE_DEVICE_TYPE(I8749, i8749_device, "i8749", "I8749")
DEFINE_DEVICE_TYPE(I8040, i8040_device, "i8040", "I8040")
DEFINE_DEVICE_TYPE(I8050, i8050_device, "i8050", "I8050")
DEFINE_DEVICE_TYPE(I8041, i8041_device, "i8041", "I8041")
DEFINE_DEVICE_TYPE(I8741, i8741_device, "i8741", "I8741")
DEFINE_DEVICE_TYPE(I8042, i8042_device, "i8042", "I8042")
DEFINE_DEVICE_TYPE(I8242, i8242_device, "i8242", "I8242")
DEFINE_DEVICE_TYPE(I8742, i8742_device, "i8742", "I8742")
DEFINE_DEVICE_TYPE(I8021, i8021_device, "i8021", "I8021")
DEFINE_DEVICE_TYPE(I8022, i8022_device, "i8022", "I8022")
DEFINE_DEVICE_TYPE(I8035, i8035_device, "i8035", "I8035")
DEFINE_DEVICE_TYPE(I8048, i8048_device, "i8048", "I8048")
DEFINE_DEVICE_TYPE(I8648, i8648_device, "i8648", "I8648")
DEFINE_DEVICE_TYPE(I8748, i8748_device, "i8748", "I8748")
DEFINE_DEVICE_TYPE(I8039, i8039_device, "i8039", "I8039")
DEFINE_DEVICE_TYPE(I8049, i8049_device, "i8049", "I8049")
DEFINE_DEVICE_TYPE(I8749, i8749_device, "i8749", "I8749")
DEFINE_DEVICE_TYPE(I8040, i8040_device, "i8040", "I8040")
DEFINE_DEVICE_TYPE(I8050, i8050_device, "i8050", "I8050")
DEFINE_DEVICE_TYPE(I8041, i8041_device, "i8041", "I8041")
DEFINE_DEVICE_TYPE(I8741, i8741_device, "i8741", "I8741")
DEFINE_DEVICE_TYPE(I8042, i8042_device, "i8042", "I8042")
DEFINE_DEVICE_TYPE(I8242, i8242_device, "i8242", "I8242")
DEFINE_DEVICE_TYPE(I8742, i8742_device, "i8742", "I8742")
DEFINE_DEVICE_TYPE(MB8884, mb8884_device, "mb8884", "MB8884")
DEFINE_DEVICE_TYPE(N7751, n7751_device, "n7751", "N7751")
DEFINE_DEVICE_TYPE(N7751, n7751_device, "n7751", "N7751")
DEFINE_DEVICE_TYPE(M58715, m58715_device, "m58715", "M58715")
@ -756,7 +744,7 @@ OPHANDLER( mov_a_r6 ) { m_a = R6; return 1; }
OPHANDLER( mov_a_r7 ) { m_a = R7; return 1; }
OPHANDLER( mov_a_xr0 ) { m_a = ram_r(R0); return 1; }
OPHANDLER( mov_a_xr1 ) { m_a = ram_r(R1); return 1; }
OPHANDLER( mov_a_t ) { m_a = m_timer; return 1; }
OPHANDLER( mov_a_t ) { m_a = m_timer + ((m_timecount_enabled & TIMER_ENABLED) ? 1 : 0); return 1; }
OPHANDLER( mov_psw_a ) { m_psw = m_a; update_regptr(); return 1; }
OPHANDLER( mov_sts_a ) { m_sts = (m_sts & 0x0f) | (m_a & 0xf0); return 1; }

View File

@ -242,6 +242,23 @@ protected:
typedef int (mcs48_cpu_device::*mcs48_ophandler)();
static const mcs48_ophandler s_opcode_table[256];
/* ROM is mapped to AS_PROGRAM */
uint8_t program_r(offs_t a) { return m_program->read_byte(a); }
/* RAM is mapped to AS_DATA */
uint8_t ram_r(offs_t a) { return m_data->read_byte(a); }
void ram_w(offs_t a, uint8_t v) { m_data->write_byte(a, v); }
/* ports are mapped to AS_IO and callbacks */
uint8_t ext_r(offs_t a) { return m_io->read_byte(a); }
void ext_w(offs_t a, uint8_t v) { m_io->write_byte(a, v); }
uint8_t port_r(offs_t a) { return m_port_in_cb[a - 1](); }
void port_w(offs_t a, uint8_t v) { m_port_out_cb[a - 1](v); }
int test_r(offs_t a) { return m_test_in_cb[a](); }
uint8_t bus_r() { return m_bus_in_cb(); }
void bus_w(uint8_t v) { m_bus_out_cb(v); }
void prog_w(int v) { m_prog_out_cb(v); }
uint8_t opcode_fetch();
uint8_t argument_fetch();
void update_regptr();

View File

@ -43,13 +43,15 @@
#include "emu.h"
#include "includes/kaypro.h"
#include "machine/kay_kbd.h"
#include "machine/clock.h"
#include "formats/kaypro_dsk.h"
#include "screen.h"
#include "softlist.h"
#include "speaker.h"
READ8_MEMBER( kaypro_state::kaypro2x_87_r ) { return 0x7f; } /* to bypass unemulated HD controller */
/***********************************************************
@ -68,7 +70,7 @@ static ADDRESS_MAP_START( kayproii_io, AS_IO, 8, kaypro_state )
ADDRESS_MAP_GLOBAL_MASK(0xff)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x00, 0x03) AM_DEVWRITE("brg", com8116_device, stt_w)
AM_RANGE(0x04, 0x07) AM_READWRITE(kaypro_sio_r, kaypro_sio_w)
AM_RANGE(0x04, 0x07) AM_DEVREADWRITE("z80sio", z80sio0_device, cd_ba_r, cd_ba_w)
AM_RANGE(0x08, 0x0b) AM_DEVREADWRITE("z80pio_g", z80pio_device, read_alt, write_alt)
AM_RANGE(0x0c, 0x0f) AM_DEVWRITE("brg", com8116_device, str_w)
AM_RANGE(0x10, 0x13) AM_DEVREADWRITE("fdc", fd1793_device, read, write)
@ -79,7 +81,7 @@ static ADDRESS_MAP_START( kaypro2x_io, AS_IO, 8, kaypro_state )
ADDRESS_MAP_GLOBAL_MASK(0xff)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x00, 0x03) AM_DEVWRITE("brg", com8116_device, str_w)
AM_RANGE(0x04, 0x07) AM_READWRITE(kaypro_sio_r, kaypro_sio_w)
AM_RANGE(0x04, 0x07) AM_DEVREADWRITE("z80sio", z80sio0_device, cd_ba_r, cd_ba_w)
AM_RANGE(0x08, 0x0b) AM_DEVWRITE("brg", com8116_device, stt_w)
AM_RANGE(0x0c, 0x0f) AM_DEVREADWRITE("z80sio_2x", z80sio0_device, ba_cd_r, ba_cd_w)
AM_RANGE(0x10, 0x13) AM_DEVREADWRITE("fdc", fd1793_device, read, write)
@ -105,6 +107,11 @@ static ADDRESS_MAP_START( kaypro2x_io, AS_IO, 8, kaypro_state )
ADDRESS_MAP_END
static INPUT_PORTS_START(kaypro)
// everything comes from the keyboard device
INPUT_PORTS_END
/***************************************************************
F4 CHARACTER DISPLAYER
@ -199,7 +206,6 @@ static MACHINE_CONFIG_START( kayproii )
MCFG_CPU_ADD("maincpu", Z80, XTAL_20MHz / 8)
MCFG_CPU_PROGRAM_MAP(kaypro_map)
MCFG_CPU_IO_MAP(kayproii_io)
MCFG_CPU_VBLANK_INT_DRIVER("screen", kaypro_state, kay_kbd_interrupt) /* this doesn't actually exist, it is to run the keyboard */
MCFG_Z80_DAISY_CHAIN(kayproii_daisy_chain)
MCFG_MACHINE_START_OVERRIDE(kaypro_state, kayproii )
@ -226,6 +232,12 @@ static MACHINE_CONFIG_START( kayproii )
/* devices */
MCFG_QUICKLOAD_ADD("quickload", kaypro_state, kaypro, "com,cpm", 3)
MCFG_DEVICE_ADD("kbd", KAYPRO_10_KEYBOARD, 0)
MCFG_KAYPRO10KBD_RXD_CB(DEVWRITELINE("z80sio", z80sio0_device, rxb_w))
MCFG_CLOCK_ADD("kbdtxrxc", 4800)
MCFG_CLOCK_SIGNAL_HANDLER(DEVWRITELINE("z80sio", z80sio0_device, rxtxcb_w))
MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer")
MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(kaypro_state, write_centronics_busy))
@ -244,6 +256,7 @@ static MACHINE_CONFIG_START( kayproii )
MCFG_DEVICE_ADD("z80sio", Z80SIO0, XTAL_20MHz / 8)
MCFG_Z80DART_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0))
MCFG_Z80DART_OUT_TXDB_CB(DEVWRITELINE("kbd", kaypro_10_keyboard_device, txd_w))
MCFG_FD1793_ADD("fdc", XTAL_20MHz / 20)
MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(kaypro_state, fdc_intrq_w))
@ -269,7 +282,6 @@ static MACHINE_CONFIG_START( kaypro2x )
MCFG_CPU_ADD("maincpu", Z80, XTAL_16MHz / 4)
MCFG_CPU_PROGRAM_MAP(kaypro_map)
MCFG_CPU_IO_MAP(kaypro2x_io)
MCFG_CPU_VBLANK_INT_DRIVER("screen", kaypro_state, kay_kbd_interrupt)
MCFG_Z80_DAISY_CHAIN(kaypro2x_daisy_chain)
MCFG_MACHINE_RESET_OVERRIDE(kaypro_state, kaypro )
@ -300,6 +312,12 @@ static MACHINE_CONFIG_START( kaypro2x )
MCFG_QUICKLOAD_ADD("quickload", kaypro_state, kaypro, "com,cpm", 3)
MCFG_DEVICE_ADD("kbd", KAYPRO_10_KEYBOARD, 0)
MCFG_KAYPRO10KBD_RXD_CB(DEVWRITELINE("z80sio", z80sio0_device, rxb_w))
MCFG_CLOCK_ADD("kbdtxrxc", 4800)
MCFG_CLOCK_SIGNAL_HANDLER(DEVWRITELINE("z80sio", z80sio0_device, rxtxcb_w))
MCFG_CENTRONICS_ADD("centronics", centronics_devices, "printer")
MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE(kaypro_state, write_centronics_busy))
@ -307,6 +325,7 @@ static MACHINE_CONFIG_START( kaypro2x )
MCFG_DEVICE_ADD("z80sio", Z80SIO0, XTAL_16MHz / 4)
MCFG_Z80DART_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0))
MCFG_Z80DART_OUT_TXDB_CB(DEVWRITELINE("kbd", kaypro_10_keyboard_device, txd_w))
MCFG_DEVICE_ADD("z80sio_2x", Z80SIO0, XTAL_16MHz / 4) /* extra sio for modem and printer */
MCFG_Z80DART_OUT_INT_CB(INPUTLINE("maincpu", INPUT_LINE_IRQ0))
@ -465,14 +484,14 @@ ROM_START(robie)
ROM_LOAD("81-235.u9", 0x0000, 0x1000, CRC(5f72da5b) SHA1(8a597000cce1a7e184abfb7bebcb564c6bf24fb7) )
ROM_END
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
COMP( 1982, kayproii, 0, 0, kayproii, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro II - 2/83" , 0 )
COMP( 1983, kaypro4, kayproii, 0, kaypro4, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 - 4/83" , 0 ) // model 81-004
COMP( 1983, kaypro4p88, kayproii, 0, kaypro4, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 plus88 - 4/83" , MACHINE_NOT_WORKING ) // model 81-004 with an added 8088 daughterboard and rom
COMP( 198?, omni2, kayproii, 0, omni2, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Omni II Logic Analyzer" , 0 )
COMP( 198?, omni4, kaypro2x, 0, kaypro2x, kay_kbd, kaypro_state, kaypro, "Omni Logic Inc.", "Omni 4 Logic Analyzer" , MACHINE_NOT_WORKING )
COMP( 1984, kaypro2x, 0, 0, kaypro2x, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 2x" , MACHINE_NOT_WORKING ) // model 81-025
COMP( 1984, kaypro4a, kaypro2x, 0, kaypro2x, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 - 4/84" , MACHINE_NOT_WORKING ) // model 81-015
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
COMP( 1982, kayproii, 0, 0, kayproii, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro II - 2/83" , 0 )
COMP( 1983, kaypro4, kayproii, 0, kaypro4, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 - 4/83" , 0 ) // model 81-004
COMP( 1983, kaypro4p88, kayproii, 0, kaypro4, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 plus88 - 4/83" , MACHINE_NOT_WORKING ) // model 81-004 with an added 8088 daughterboard and rom
COMP( 198?, omni2, kayproii, 0, omni2, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Omni II Logic Analyzer" , 0 )
COMP( 198?, omni4, kaypro2x, 0, kaypro2x, kaypro, kaypro_state, kaypro, "Omni Logic Inc.", "Omni 4 Logic Analyzer" , MACHINE_NOT_WORKING )
COMP( 1984, kaypro2x, 0, 0, kaypro2x, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 2x" , MACHINE_NOT_WORKING ) // model 81-025
COMP( 1984, kaypro4a, kaypro2x, 0, kaypro2x, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 4 - 4/84" , MACHINE_NOT_WORKING ) // model 81-015
// Kaypro 4/84 plus 88 goes here, model 81-015 with an added 8088 daughterboard and rom
COMP( 1983, kaypro10, 0, 0, kaypro10, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 10" , MACHINE_NOT_WORKING ) // model 81-005
COMP( 1984, robie, 0, 0, kaypro2x, kay_kbd, kaypro_state, kaypro, "Non Linear Systems", "Kaypro Robie" , MACHINE_NOT_WORKING ) // model 81-005
COMP( 1983, kaypro10, 0, 0, kaypro10, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro 10" , MACHINE_NOT_WORKING ) // model 81-005
COMP( 1984, robie, 0, 0, kaypro2x, kaypro, kaypro_state, kaypro, "Non Linear Systems", "Kaypro Robie" , MACHINE_NOT_WORKING ) // model 81-005

View File

@ -16,8 +16,6 @@
#include "video/mc6845.h"
#include "machine/wd_fdc.h"
struct kay_kbd_t;
class kaypro_state : public driver_device
{
public:
@ -63,19 +61,14 @@ public:
DECLARE_MACHINE_RESET(kaypro);
DECLARE_VIDEO_START(kaypro);
DECLARE_PALETTE_INIT(kaypro);
DECLARE_MACHINE_RESET(kay_kbd);
DECLARE_DRIVER_INIT(kaypro);
DECLARE_FLOPPY_FORMATS(kayproii_floppy_formats);
DECLARE_FLOPPY_FORMATS(kaypro2x_floppy_formats);
uint32_t screen_update_kayproii(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
uint32_t screen_update_kaypro2x(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
uint32_t screen_update_omni2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(kay_kbd_interrupt);
DECLARE_READ8_MEMBER(kaypro_sio_r);
DECLARE_WRITE8_MEMBER(kaypro_sio_w);
MC6845_UPDATE_ROW(kaypro2x_update_row);
DECLARE_QUICKLOAD_LOAD_MEMBER(kaypro);
TIMER_CALLBACK_MEMBER( kay_kbd_beepoff );
private:
uint8_t m_mc6845_cursor[16];
@ -83,12 +76,7 @@ private:
uint8_t m_mc6845_ind;
uint8_t m_framecnt;
uint8_t *m_p_videoram;
kay_kbd_t *m_kbd;
int m_centronics_busy;
void kay_kbd_in(uint8_t data );
uint8_t kay_kbd_c_r();
uint8_t kay_kbd_d_r();
void kay_kbd_d_w( uint8_t data );
bool m_is_motor_off;
uint8_t m_fdc_rq;
uint8_t m_system_port;

View File

@ -1,28 +1,16 @@
// license:GPL-2.0+
// copyright-holders:Juergen Buchmueller
// copyright-holders:Vas Crabb
/******************************************************************************
*
* kay_kbd.c
* kay_kbd.cpp
*
* Kaypro II Serial Keyboard
*
* Most of this is copied from the old kaypro.c,
* rather than re-inventing the wheel.
*
* Juergen Buchmueller, July 1998
* Benjamin C. W. Sittler, July 1998 (new keyboard table)
*
* Converted to a serial device (as far as MESS will allow)
* by Robbbert, April 2009.
* Kaypro Serial Keyboards
*
******************************************************************************/
#include "emu.h"
#include "machine/kay_kbd.h"
#include "sound/beep.h"
#include "includes/kaypro.h"
/*
* The KAYPRO keyboard has roughly the following layout:
@ -49,463 +37,365 @@
* arrow graphics pointing in the appropriate directions. The F and J keys are specially shaped,
* since they are the "home keys" for touch-typing. The CAPS LOCK key has a build-in red indicator
* which is lit when CAPS LOCK is pressed once, and extinguished when the key is pressed again.
*
* Technical Notes
* ---------------
* The keyboard interfaces to the computer using a serial protocol. Modifier keys are handled
* inside the keyboards, as is the CAPS LOCK key. The arrow keys and the numeric keypad send
* non-ASCII codes which are not affected by the modifier keys. The remaining keys send the
* appropriate ASCII values.
*
* The keyboard has a built-in buzzer which is activated briefly by a non-modifier keypress,
* producing a "clicking" sound for user feedback. Additionally, this buzzer can be activated
* for a longer period by sending a 0x04 byte to the keyboard. This is used by the ROM soft
* terminal to alert the user in case of a BEL.
*
* 2008-05 FP:
* Small note about natural keyboard support: currently,
* - "Line Feed" is mapped to the 'End' key
* - "Keypad ," is not mapped
*/
struct kay_kbd_t
{
beep_device *beeper;
uint8_t buff[16];
uint8_t head;
uint8_t tail;
uint8_t beep_on;
uint8_t control_status;
uint8_t keyrows[10];
int lastrow;
int mask;
int key;
int repeat;
int repeater;
};
INPUT_PORTS_START( kay_kbd )
PORT_START("ROW0")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
/*
Kaypro 10 keyboard
PORT_START("ROW1")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_NAME("BACK SPACE") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
This is a TTL-level asynchronous serial keyboard using mask-programmed
MCS-48 MCU. Serial transmission and reception are handled in software
using the onboard timer/counter interrupt. The frame format is 1 start
bit, 8 data bits, no parity, and 1 stop bit.
PORT_START("ROW2")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
Active components:
* Mitsubishi M5L8049-109P-6 (MCS-48 MCU with 2KiB mask ROM)
* SN74154N (4-to-16 demultiplexer)
* DM7406N (hex inverter with open collector outputs)
* SN75451BP (dual high-speed, high-current line driver with AND inputs)
* 6.000MHz crystal
PORT_START("ROW3")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL))
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
D0-D3 select the key matrix row, only 0x0..0xE are used (0x0F ignored).
PORT_START("ROW4")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
D4 is the CAPS LOCK LED output.
PORT_START("ROW5")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_MAMEKEY(LSHIFT))
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
P1 is connected to the key matrix columns.
PORT_START("ROW6")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_MAMEKEY(RSHIFT))
P2.1, P2.2 and P2.3 are CTRL, CAPS LOCK, and SHIFT inputs.
PORT_START("ROW7")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("LINE FEED") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END))
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD))
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("Keypad ,") PORT_CODE(KEYCODE_PLUS_PAD)
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
P2.6 drives the speaker (1.5625kHz tone generated using timer/counter).
PORT_START("ROW8")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
PORT_BIT(0x10, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
PORT_BIT(0x20, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
PORT_BIT(0x40, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
PORT_BIT(0x80, 0x00, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
P2.7 is the serial data output to the host.
PORT_START("ROW9")
PORT_BIT(0x01, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x91") PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_BIT(0x02, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x93") PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_BIT(0x04, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x90") PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_BIT(0x08, 0x00, IPT_KEYBOARD) PORT_NAME("\xE2\x86\x92") PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_BIT(0xf0, 0x00, IPT_UNUSED)
T1 is the serial data input from the host.
The program appears to be able to support "typewriter shift" and
"bitshift" layouts, and both ASCII and Kaypro control codes for the
numeric keypad, depending on how the matrix is wired. All positions in
the key matrix will produce characters, although it's not clear whether
all of them are designed to serve a purpose - some may just be emergent
behaviour from the decoding algorithm.
The serial rate is generated by reloading the T register with 0xfe and
transfering a bit every 21 interrupts, giving a rate within 1% of the
desired 300 Baud:
6MHz / 15 / 32 / (0x100 - 0xfe) / 21 = 297.62 Baud
This scheme allows only 64 machine cycles between interrupts, and more
than half of thse are consumed by the timer service routine itself.
The program ROM checksum routine is supposed to compute the sum of all
program ROM bytes modulo 256 and the XOR of all program ROM bytes, but
due to bugs it omits the first byte of each page (0x000, 0x100, 0x200,
0x300, 0x400, 0x500, 0x600 and 0x700).
The serial command processing is quite lax in what it accepts:
xxxx xxx1 ignored
xxxx xx10 short beep
xxxx x100 long beep
xxx1 x000 answer back with 0xAA?
The Kaypro II was sold with a different keyboard using an 8751 (MCS-51)
MCU, but we don't have a dump for it.
*/
#include "cpu/mcs48/mcs48.h"
#include "speaker.h"
DEFINE_DEVICE_TYPE(KAYPRO_10_KEYBOARD, kaypro_10_keyboard_device, "kaypro10kbd", "Kaypro 10 Keyboard")
namespace {
ROM_START(kaypro_10_keyboard)
ROM_REGION(0x0800, "mcu", 0)
ROM_LOAD("m5l8049.bin", 0x0000, 0x0800, CRC(dc772f80) SHA1(aa7cd3f476466203294675d56098dff45952b9b0))
ROM_END
INPUT_PORTS_START(kaypro_keyboard_typewriter)
PORT_START("ROW.0")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_NAME("Pad 0")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_NAME("Pad 3")
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_NAME("Pad 6")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_NAME("Pad 9")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf8
PORT_START("ROW.1")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa5
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_CHAR('r') PORT_CHAR('R')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_NAME("Pad 2")
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_NAME("Pad 5")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_NAME("Pad 8")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf7
PORT_START("ROW.2")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa4
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_NAME("Pad 1")
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_NAME("Pad 4")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_NAME("Pad 7")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf6
PORT_START("ROW.3")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RALT) PORT_CHAR(10) PORT_NAME("LINE FEED")
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_CHAR('y') PORT_CHAR('Y')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL) PORT_CHAR(UCHAR_MAMEKEY(DEL)) PORT_NAME("DEL")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xe0
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf5
PORT_START("ROW.4")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa3
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_NAME("RETURN")
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xd4
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8) PORT_NAME("BACK SPACE")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
PORT_START("ROW.5")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('"')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
PORT_START("ROW.6")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) 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_CHAR('i') PORT_CHAR('I')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
PORT_START("ROW.7")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa2
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) 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_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
PORT_START("ROW.8")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa1
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR(';')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf0
PORT_START("ROW.9")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa0
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xb0
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TAB) PORT_CHAR('\t')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ESC) PORT_CHAR(UCHAR_MAMEKEY(ESC))
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xfe
PORT_START("ROW.A")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_NAME("Pad .")
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_G) PORT_CHAR('g') PORT_CHAR('G')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_NAME("Pad ENTER")
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Pad ,")
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_NAME("Pad -")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xf9
PORT_START("ROW.B")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) // 2 for ASCII keypad
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 1 for ASCII keypad
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) // 0 for "bitshift" layout or ASCII keypad
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) // 7 for ASCII keypad
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) // 0 for "bitshift" layout or ASCII keypad
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // 9 for ASCII keypad
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // 8 for ASCII keypad
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // . for ASCII keypad
PORT_START("ROW.C")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) // 6 & for "bitshift" layout
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 3 # for "bitshift" layout? identical to "typewriter shift" anyway
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) // 2 " for "bitshift" layout
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) // "typewriter shift" 2 @ duplicated here
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) // 6 for ASCII keypad
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // 5 for ASCII keypad
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // 4 for ASCII keypad
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // 3 for ASCII keypad
PORT_START("ROW.D")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNUSED) // ` @ for "bitshift" layout
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // - = for "bitshift" layout
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNUSED) // : * for "bitshift" layout
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNUSED) // ~ ^ for "bitshift" layout
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) // "typewriter shift" 6 ^ duplicated here
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) // 9 ) for "bitshift" layout
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // 8 ( for "bitshift" layout
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // 7 ' for "bitshift" layout
PORT_START("ROW.E")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xe0
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0x90
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xa0
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0x00
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xe0
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0xc0
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNKNOWN) // 0x54
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) // ; + for "bitshift" layout
PORT_START("ROW.F")
PORT_BIT(0xff, IP_ACTIVE_LOW, IPT_UNUSED) // not scanned
PORT_START("MOD")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL) PORT_CHAR(UCHAR_SHIFT_2) PORT_NAME("CTRL")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CAPSLOCK) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK)) PORT_NAME("CAPS LOCK")
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_NAME("SHIFT")
INPUT_PORTS_END
static const uint8_t keyboard[8][10][8] = {
{ /* normal */
{ 27,'1','2','3','4','5','6','7'},
{'8','9','0','-','=','`', 8, 9},
{'q','w','e','r','t','y','u','i'},
{'o','p','[',']', 13,127, 0, 0},
{'a','s','d','f','g','h','j','k'},
{'l',';', 39, 92, 0,'z','x','c'},
{'v','b','n','m',',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Shift */
{ 27,'!','@','#','$','%','^','&'},
{'*','(',')','_','+','~', 8, 9},
{'Q','W','E','R','T','Y','U','I'},
{'O','P','{','}', 13,127, 0, 0},
{'A','S','D','F','G','H','J','K'},
{'L',':','"','|', 0,'Z','X','C'},
{'V','B','N','M','<','>','?', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Control */
{ 27,'1','2','3','4','5','6','7'},
{'8','9','0','-','=','`', 8, 9},
{ 17, 23, 5, 18, 20, 25, 21, 9},
{ 15, 16, 27, 29, 13,127, 0, 0},
{ 1, 19, 4, 6, 7, 8, 10, 11},
{ 12,';', 39, 28, 0, 26, 24, 3},
{ 22, 2, 14, 13,',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Shift+Control */
{ 27,'!', 0,'#','$','%', 30,'&'},
{'*','(',')', 31,'+','~', 8, 9},
{ 17, 23, 5, 18, 20, 25, 21, 9},
{ 15, 16, 27, 29, 13,127, 0, 0},
{ 1, 19, 4, 6, 7, 8, 10, 11},
{ 12,':','"', 28, 0, 26, 24, 3},
{ 22, 2, 14, 13,',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* CapsLock */
{ 27,'1','2','3','4','5','6','7'},
{'8','9','0','-','=','`', 8, 9},
{'Q','W','E','R','T','Y','U','I'},
{'O','P','[',']', 13,127, 0, 0},
{'A','S','D','F','G','H','J','K'},
{'L',';', 39, 92, 0,'Z','X','C'},
{'V','B','N','M',',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Shift+CapsLock */
{ 27,'!','@','#','$','%','^','&'},
{'*','(',')','_','+','~', 8, 9},
{'Q','W','E','R','T','Y','U','I'},
{'O','P','{','}', 13,127, 0, 0},
{'A','S','D','F','G','H','J','K'},
{'L',':','"','|', 0,'Z','X','C'},
{'V','B','N','M','<','>','?', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Control+CapsLock */
{ 27,'1','2','3','4','5','6','7'},
{'8','9','0','-','=','`', 8, 9},
{ 17, 23, 5, 18, 20, 25, 21, 9},
{ 15, 16, 27, 29, 13,127, 0, 0},
{ 1, 19, 4, 6, 7, 8, 10, 11},
{ 12,';', 39, 28, 0, 26, 24, 3},
{ 22, 2, 14, 13,',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
{ /* Shift+Control+CapsLock */
{ 27,'!', 0,'#','$','%', 30,'&'},
{'*','(',')', 31,'+','~', 8, 9},
{ 17, 23, 5, 18, 20, 25, 21, 9},
{ 15, 16, 27, 29, 13,127, 0, 0},
{ 1, 19, 4, 6, 7, 8, 10, 11},
{ 12,':','"', 28, 0, 26, 24, 3},
{ 22, 2, 14, 13,',','.','/', 0},
{ 10, 32, 228, 211, 195, 178, 177, 192},
{ 193, 194, 208, 209, 210, 225, 226, 227},
{ 241, 242, 243, 244, 0, 0, 0, 0},
},
};
INPUT_PORTS_START(kaypro_keyboard_bitshift)
PORT_INCLUDE(kaypro_keyboard_typewriter)
MACHINE_RESET_MEMBER(kaypro_state,kay_kbd)
PORT_MODIFY("ROW.2")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 6 ^ for "typewriter shift" layout
PORT_MODIFY("ROW.3")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 7 & for "typewriter shift" layout
PORT_MODIFY("ROW.4")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 8 * for "typewriter shift" layout
PORT_MODIFY("ROW.5")
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) // ' " for "typewriter shift" layout
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // ` ~ for "typewriter shift" layout
PORT_MODIFY("ROW.6")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 9 ) for "typewriter shift" layout
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // - _ for "typewriter shift" layout
PORT_MODIFY("ROW.7")
PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_UNUSED) // ; : for "typewriter shift" layout
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) // = + for "typewriter shift" layout
PORT_MODIFY("ROW.8")
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_UNUSED) // 2 @ for "typewriter shift" layout
PORT_MODIFY("ROW.C")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
PORT_MODIFY("ROW.D")
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('`') PORT_CHAR('@')
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=')
PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR(':') PORT_CHAR('*')
PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('~') PORT_CHAR('^')
PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
PORT_MODIFY("ROW.E")
PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR('+')
INPUT_PORTS_END
} // anonymous namespace
kaypro_10_keyboard_device::kaypro_10_keyboard_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
uint32_t clock)
: device_t(mconfig, KAYPRO_10_KEYBOARD, tag, owner, clock)
, m_bell(*this, "bell")
, m_matrix(*this, "ROW.%X", 0)
, m_modifiers(*this, "MOD")
, m_rxd_cb(*this)
, m_txd(1U)
, m_bus(0U)
{
kay_kbd_t *kbd = m_kbd = auto_alloc_clear(machine(), <kay_kbd_t>());
/* disable CapsLock LED initially */
output().set_led_value(1, 1);
output().set_led_value(1, 0);
kbd->beeper = machine().device<beep_device>("beeper");
kbd->beep_on = 1;
kbd->control_status = 0x14;
kbd->beeper->set_state(0);
kbd->head = kbd->tail = 0; /* init buffer */
}
/******************************************************
* vertical blank interrupt
* used to scan keyboard; newly pressed keys
* are stuffed into a keyboard buffer;
* also drives keyboard LEDs and
* and handles autorepeating keys
******************************************************/
INTERRUPT_GEN_MEMBER(kaypro_state::kay_kbd_interrupt)
tiny_rom_entry const *kaypro_10_keyboard_device::device_rom_region() const
{
kay_kbd_t *kbd = m_kbd;
int mod, row, col, chg, newval;
uint8_t *keyrows = kbd->keyrows;
if( kbd->repeat )
{
if( !--kbd->repeat )
kbd->repeater = 4;
}
else
if( kbd->repeater )
{
kbd->repeat = kbd->repeater;
}
row = 9;
newval = machine().root_device().ioport("ROW9")->read();
chg = keyrows[row] ^ newval;
if (!chg) { newval = machine().root_device().ioport("ROW8")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW7")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW6")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW5")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW4")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW3")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW2")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW1")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) { newval = machine().root_device().ioport("ROW0")->read(); chg = keyrows[--row] ^ newval; }
if (!chg) --row;
if (row >= 0)
{
kbd->repeater = 0x00;
kbd->mask = 0x00;
kbd->key = 0x00;
kbd->lastrow = row;
/* CapsLock LED */
if( row == 3 && chg == 0x80 )
output().set_led_value(1, (kbd->keyrows[3] & 0x80) ? 0 : 1);
if (newval & chg) /* key(s) pressed ? */
{
mod = 0;
/* Shift modifier */
if ( (keyrows[5] & 0x10) || (keyrows[6] & 0x80) )
mod |= 1;
/* Control modifier */
if (keyrows[3] & 0x40)
mod |= 2;
/* CapsLock modifier */
if (keyrows[3] & 0x80)
mod |= 4;
/* find newval key */
kbd->mask = 0x01;
for (col = 0; col < 8; col ++)
{
if (chg & kbd->mask)
{
newval &= kbd->mask;
kbd->key = keyboard[mod][row][col];
break;
}
kbd->mask <<= 1;
}
if( kbd->key ) /* normal key */
{
kbd->repeater = 30;
kay_kbd_in(kbd->key);
}
else
if( (row == 0) && (chg == 0x04) ) /* Ctrl-@ (NUL) */
kay_kbd_in(0);
keyrows[row] |= newval;
}
else
{
kbd->keyrows[row] = newval;
}
kbd->repeat = kbd->repeater;
}
else if ( kbd->key && (keyrows[kbd->lastrow] & kbd->mask) && kbd->repeat == 0 )
{
kay_kbd_in(kbd->key);
}
return ROM_NAME(kaypro_10_keyboard);
}
#if 0
MACHINE_CONFIG_MEMBER(kaypro_10_keyboard_device::device_add_mconfig)
MCFG_CPU_ADD("mcu", I8049, XTAL_6MHz)
MCFG_MCS48_PORT_P1_IN_CB(READ8(kaypro_10_keyboard_device, p1_r))
MCFG_MCS48_PORT_P2_IN_CB(READ8(kaypro_10_keyboard_device, p2_r))
MCFG_MCS48_PORT_P2_OUT_CB(WRITE8(kaypro_10_keyboard_device, p2_w))
MCFG_MCS48_PORT_T1_IN_CB(READLINE(kaypro_10_keyboard_device, t1_r))
MCFG_MCS48_PORT_BUS_IN_CB(READ8(kaypro_10_keyboard_device, bus_r))
MCFG_MCS48_PORT_BUS_OUT_CB(WRITE8(kaypro_10_keyboard_device, bus_w))
/******************************************************
* kaypro_const_w (write console status ;)
* bit
* 0 flush keyboard buffer
******************************************************/
static WRITE8_HANDLER ( kaypro2_const_w )
MCFG_SPEAKER_STANDARD_MONO("keyboard")
MCFG_SOUND_ADD("bell", SPEAKER_SOUND, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "keyboard", 0.25)
MACHINE_CONFIG_END
ioport_constructor kaypro_10_keyboard_device::device_input_ports() const
{
if (data & 1)
kbd->head = kbd->tail = 0;
(void)INPUT_PORTS_NAME(kaypro_keyboard_bitshift);
return INPUT_PORTS_NAME(kaypro_keyboard_typewriter);
}
#endif
/******************************************************
* stuff character into the keyboard buffer
* releases CPU if it was waiting for a key
* sounds bell if buffer would overflow
******************************************************/
void kaypro_state::kay_kbd_in(uint8_t data )
void kaypro_10_keyboard_device::device_start()
{
kay_kbd_t *kbd = m_kbd;
uint8_t kbd_head_old;
m_rxd_cb.resolve_safe();
kbd_head_old = kbd->head;
kbd->buff[kbd->head] = data;
kbd->head = (kbd->head + 1) % sizeof(kbd->buff);
/* will the buffer overflow ? */
if (kbd->head == kbd->tail)
{
kbd->head = kbd_head_old;
kay_kbd_d_w(4);
}
else
kay_kbd_d_w(1);
save_item(NAME(m_txd));
save_item(NAME(m_bus));
}
uint8_t kaypro_state::kay_kbd_c_r()
READ8_MEMBER(kaypro_10_keyboard_device::p1_r)
{
/* d4 transmit buffer empty - 1=ok to send
d2 appears to be receive buffer empty - 1=ok to receive
d0 keyboard buffer empty - 1=key waiting to be used */
kay_kbd_t *kbd = m_kbd;
uint8_t data = kbd->control_status;
if( kbd->head != kbd->tail )
data++;
return data;
return m_matrix[m_bus & 0x0f]->read();
}
uint8_t kaypro_state::kay_kbd_d_r()
READ8_MEMBER(kaypro_10_keyboard_device::p2_r)
{
/* return next key in buffer */
kay_kbd_t *kbd = m_kbd;
uint8_t data = 0;
if (kbd->tail != kbd->head)
{
data = kbd->buff[kbd->tail];
kbd->tail = (kbd->tail + 1) % sizeof(kbd->buff);
}
return data;
return m_modifiers->read() | 0xf8U;
}
TIMER_CALLBACK_MEMBER( kaypro_state::kay_kbd_beepoff )
WRITE8_MEMBER(kaypro_10_keyboard_device::p2_w)
{
kay_kbd_t *kbd = m_kbd;
kbd->beeper->set_state(0);
kbd->control_status |= 4;
m_bell->level_w(BIT(data, 6));
m_rxd_cb(BIT(data, 7));
}
void kaypro_state::kay_kbd_d_w( uint8_t data )
READ_LINE_MEMBER(kaypro_10_keyboard_device::t1_r)
{
/* Beeper control - lengths need verifying
01 - keyclick
02 - short beep
04 - standard bell beep
08 - mute
16 - unmute */
kay_kbd_t *kbd = m_kbd;
uint16_t length = 0;
if (data & 0x10)
kbd->beep_on = 1;
else
if (data & 0x08)
kbd->beep_on = 0;
else
if (kbd->beep_on)
{
if (data & 0x04)
length = 400;
else
if (data & 0x02)
length = 200;
else
if (data & 0x01)
length = 4;
if (length)
{
kbd->control_status &= 0xfb;
machine().scheduler().timer_set(attotime::from_msec(length), timer_expired_delegate(FUNC(kaypro_state::kay_kbd_beepoff),this));
kbd->beeper->set_state(1);
}
}
return m_txd ? 1 : 0;
}
READ8_MEMBER(kaypro_10_keyboard_device::bus_r)
{
return m_bus;
}
WRITE8_MEMBER(kaypro_10_keyboard_device::bus_w)
{
if (BIT(m_bus ^ data, 4))
machine().output().set_value("led_caps_lock", BIT(data, 4));
m_bus = data;
}

View File

@ -1,4 +1,54 @@
// license:BSD-3-Clause
// copyright-holders:Robbbert
// copyright-holders:Vas Crabb
#ifndef MAME_MACHINE_KAY_KBD_H
#define MAME_MACHINE_KAY_KBD_H
INPUT_PORTS_EXTERN( kay_kbd );
#pragma once
#include "sound/spkrdev.h"
#define MCFG_KAYPRO10KBD_RXD_CB(cb) \
devcb = &kaypro_10_keyboard_device::set_rxd_cb(*device, DEVCB_##cb);
class kaypro_10_keyboard_device : public device_t
{
public:
kaypro_10_keyboard_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
uint32_t clock);
template <class Object> static devcb_base &set_rxd_cb(device_t &device, Object &&cb)
{ return downcast<kaypro_10_keyboard_device &>(device).m_rxd_cb.set_callback(std::forward<Object>(cb)); }
DECLARE_WRITE_LINE_MEMBER(txd_w) { m_txd = state ? 1U : 0U; }
protected:
virtual const tiny_rom_entry *device_rom_region() const override;
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
DECLARE_READ8_MEMBER(p1_r);
DECLARE_READ8_MEMBER(p2_r);
DECLARE_WRITE8_MEMBER(p2_w);
DECLARE_READ_LINE_MEMBER(t1_r);
DECLARE_READ8_MEMBER(bus_r);
DECLARE_WRITE8_MEMBER(bus_w);
private:
required_device<speaker_sound_device> m_bell;
required_ioport_array<16> m_matrix;
required_ioport m_modifiers;
devcb_write_line m_rxd_cb;
std::uint8_t m_txd;
std::uint8_t m_bus;
};
DECLARE_DEVICE_TYPE(KAYPRO_10_KEYBOARD, kaypro_10_keyboard_device)
#endif // MAME_MACHINE_KAY_KBD_H

View File

@ -163,29 +163,9 @@ WRITE8_MEMBER( kaypro_state::kaypro2x_system_port_w )
FFh 19200 */
READ8_MEMBER(kaypro_state::kaypro_sio_r)
{
if (offset == 1)
return kay_kbd_d_r();
else
if (offset == 3)
return kay_kbd_c_r();
else
return m_sio->cd_ba_r(space, offset);
}
WRITE8_MEMBER(kaypro_state::kaypro_sio_w)
{
if (offset == 1)
kay_kbd_d_w(data);
else
m_sio->cd_ba_w(space, offset, data);
}
/*************************************************************************************
Floppy DIsk
Floppy Disk
If DRQ or IRQ is set, and cpu is halted, the NMI goes low.
Since the HALT occurs last (and has no callback mechanism), we need to set
@ -248,7 +228,6 @@ MACHINE_START_MEMBER( kaypro_state,kayproii )
MACHINE_RESET_MEMBER( kaypro_state,kaypro )
{
MACHINE_RESET_CALL_MEMBER(kay_kbd);
membank("bankr0")->set_entry(1); // point at rom
membank("bankw0")->set_entry(0); // always write to ram
membank("bank3")->set_entry(1); // point at video ram