summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author mahlemiut <bsr@xnet.co.nz>2014-12-03 15:16:01 +1300
committer mahlemiut <bsr@xnet.co.nz>2014-12-03 15:16:11 +1300
commit2e290e4faedb9d33d61822587a83370d96f114a8 (patch)
tree24a76962ec5150ea9f46910d74713409ce5fa232
parent34ce110109e5b541a25b1a23b332581073999df6 (diff)
(MESS) ngen: started keyboard support, plus a few minor updates.
-rw-r--r--src/mess/drivers/ngen.c148
-rw-r--r--src/mess/machine/ngen_kb.c219
-rw-r--r--src/mess/machine/ngen_kb.h30
-rw-r--r--src/mess/mess.mak2
4 files changed, 363 insertions, 36 deletions
diff --git a/src/mess/drivers/ngen.c b/src/mess/drivers/ngen.c
index f70dfa31bcc..3757e2b7755 100644
--- a/src/mess/drivers/ngen.c
+++ b/src/mess/drivers/ngen.c
@@ -4,6 +4,11 @@
10-11-14 - Skeleton driver
+ Interrupts based on patents:
+ level 1 - SIO
+ level 3 - timer (from PIT, presumably channel 0? Patent says "channel 3")
+ level 4 - "interrupt detector" - keyboard, printer, RTC
+ level 7 - floppy/hard disk
*/
#include "emu.h"
@@ -16,6 +21,8 @@
#include "machine/pit8253.h"
#include "machine/z80dart.h"
#include "bus/rs232/rs232.h"
+#include "machine/ngen_kb.h"
+#include "machine/clock.h"
class ngen_state : public driver_device
{
@@ -36,21 +43,35 @@ public:
DECLARE_WRITE_LINE_MEMBER(pit_out0_w);
DECLARE_WRITE_LINE_MEMBER(pit_out1_w);
DECLARE_WRITE_LINE_MEMBER(pit_out2_w);
+ DECLARE_WRITE_LINE_MEMBER(cpu_timer_w);
+ DECLARE_WRITE_LINE_MEMBER(timer_clk_out);
DECLARE_WRITE16_MEMBER(cpu_peripheral_cb);
DECLARE_WRITE16_MEMBER(peripheral_w);
DECLARE_READ16_MEMBER(peripheral_r);
DECLARE_WRITE16_MEMBER(port00_w);
DECLARE_READ16_MEMBER(port00_r);
DECLARE_WRITE_LINE_MEMBER(dma_hrq_changed);
+ DECLARE_WRITE_LINE_MEMBER(dma_eop_changed);
DECLARE_WRITE_LINE_MEMBER(dack0_w);
DECLARE_WRITE_LINE_MEMBER(dack1_w);
DECLARE_WRITE_LINE_MEMBER(dack2_w);
DECLARE_WRITE_LINE_MEMBER(dack3_w);
- DECLARE_READ8_MEMBER(dma_read_byte);
- DECLARE_WRITE8_MEMBER(dma_write_byte);
+ DECLARE_READ8_MEMBER(dma_read_word);
+ DECLARE_WRITE8_MEMBER(dma_write_word);
MC6845_UPDATE_ROW(crtc_update_row);
+ // TODO: sort out what devices use which channels
+ DECLARE_READ8_MEMBER( dma_0_dack_r ) { UINT16 ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
+ DECLARE_READ8_MEMBER( dma_1_dack_r ) { UINT16 ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
+ DECLARE_READ8_MEMBER( dma_2_dack_r ) { UINT16 ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
+ DECLARE_READ8_MEMBER( dma_3_dack_r ) { UINT16 ret = 0xffff; m_dma_high_byte = ret & 0xff00; return ret; }
+ DECLARE_WRITE8_MEMBER( dma_0_dack_w ){ popmessage("IOW: data %02x",data); }
+ DECLARE_WRITE8_MEMBER( dma_1_dack_w ){ }
+ DECLARE_WRITE8_MEMBER( dma_2_dack_w ){ }
+ DECLARE_WRITE8_MEMBER( dma_3_dack_w ){ }
protected:
+ virtual void machine_reset();
+
private:
required_device<cpu_device> m_maincpu;
required_device<mc6845_device> m_crtc;
@@ -71,25 +92,39 @@ private:
UINT16 m_periph141;
UINT8 m_dma_offset[4];
INT8 m_dma_channel;
+ UINT16 m_dma_high_byte;
+ UINT16 m_control;
};
WRITE_LINE_MEMBER(ngen_state::pit_out0_w)
{
- //m_pic->ir0_w(state);
- logerror("80186 Timer 1 state %i\n",state);
+ m_pic->ir3_w(state); // Timer interrupt
+ popmessage("PIT Timer 0 state %i\n",state);
}
WRITE_LINE_MEMBER(ngen_state::pit_out1_w)
{
- logerror("PIT Timer 1 state %i\n",state);
+ popmessage("PIT Timer 1 state %i\n",state);
+ m_iouart->rxcb_w(state);
+ m_iouart->txcb_w(state); // channels in the correct order?
}
WRITE_LINE_MEMBER(ngen_state::pit_out2_w)
{
m_iouart->rxca_w(state);
- m_iouart->rxcb_w(state);
m_iouart->txca_w(state);
- m_iouart->txcb_w(state);
+ //logerror("PIT Timer 2 state %i\n",state);
+}
+
+WRITE_LINE_MEMBER(ngen_state::cpu_timer_w)
+{
+ logerror("80186 Timer 1 state %i\n",state);
+}
+
+WRITE_LINE_MEMBER(ngen_state::timer_clk_out)
+{
+ m_viduart->write_rxc(state); // Keyboard UART Rx/Tx clocks
+ m_viduart->write_txc(state);
}
WRITE16_MEMBER(ngen_state::cpu_peripheral_cb)
@@ -184,10 +219,12 @@ WRITE16_MEMBER(ngen_state::peripheral_w)
m_crtc->register_w(space,0,data & 0xff);
break;
case 0x146:
- logerror("Video write offset 0x146 data %04x mask %04x\n",data,mem_mask);
+ if(mem_mask & 0x00ff)
+ m_viduart->data_w(space,0,data & 0xff);
break;
case 0x147:
- //logerror("Video write offset 0x147 data %04x mask %04x\n",data,mem_mask);
+ if(mem_mask & 0x00ff)
+ m_viduart->control_w(space,0,data & 0xff);
break;
case 0x1a0: // serial?
logerror("(PC=%06x) Serial(?) 0x1a0 write offset %04x data %04x mask %04x\n",m_maincpu->device_t::safe_pc(),offset,data,mem_mask);
@@ -257,15 +294,16 @@ READ16_MEMBER(ngen_state::peripheral_r)
ret = m_crtc->register_r(space,0);
break;
case 0x146:
+ if(mem_mask & 0x00ff)
+ ret = m_viduart->data_r(space,0);
break;
- case 0x147: // definitely video related, maybe UART sending data to the monitor?
- // expects bit 0 to be set (Video ready signal?)
- ret = 0;
- ret |= 1;
+ case 0x147: // keyboard UART
+ // expects bit 0 to be set (UART transmit ready)
+ if(mem_mask & 0x00ff)
+ ret = m_viduart->status_r(space,0);
break;
- case 0x1a0: // status?
- ret = 0;
- ret |= 0x02; // end of DMA transfer?
+ case 0x1a0: // I/O control register?
+ ret = m_control; // end of DMA transfer? (maybe a per-channel EOP?) Add a '| 0x40' to force a serial I/O failure, so that the keyboard can be tested
break;
case 0x1b1:
ret = 0;
@@ -299,6 +337,17 @@ WRITE_LINE_MEMBER( ngen_state::dma_hrq_changed )
m_maincpu->set_input_line(INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
}
+WRITE_LINE_MEMBER( ngen_state::dma_eop_changed )
+{
+ if(m_dma_channel == 0)
+ {
+ if(state)
+ m_control |= 0x02;
+ else
+ m_control &= ~0x02;
+ }
+}
+
void ngen_state::set_dma_channel(int channel, int state)
{
if(!state)
@@ -312,29 +361,30 @@ WRITE_LINE_MEMBER( ngen_state::dack1_w ) { set_dma_channel(1, state); }
WRITE_LINE_MEMBER( ngen_state::dack2_w ) { set_dma_channel(2, state); }
WRITE_LINE_MEMBER( ngen_state::dack3_w ) { set_dma_channel(3, state); }
-READ8_MEMBER(ngen_state::dma_read_byte)
+READ8_MEMBER(ngen_state::dma_read_word)
{
address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
- UINT8 result;
+ UINT16 result;
if(m_dma_channel == -1)
return 0xff;
- offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0xFF0000;
+ offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0xFE0000;
- result = prog_space.read_byte(page_offset + offset);
- popmessage("DMA byte address %06x read %02x\n",page_offset+offset,result);
- return result;
+ result = prog_space.read_word(page_offset + (offset << 1));
+ m_dma_high_byte = result & 0xFF00;
+ popmessage("DMA byte address %06x read %04x\n",page_offset+(offset<<1),result);
+ return result & 0xff;
}
-WRITE8_MEMBER(ngen_state::dma_write_byte)
+WRITE8_MEMBER(ngen_state::dma_write_word)
{
address_space& prog_space = m_maincpu->space(AS_PROGRAM); // get the right address space
if(m_dma_channel == -1)
return;
- offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0xFF0000;
+ offs_t page_offset = (((offs_t) m_dma_offset[m_dma_channel]) << 16) & 0xFE0000;
- prog_space.write_byte(page_offset + offset, data);
- popmessage("DMA byte address %06x write %02x\n",page_offset+offset,data);
+ prog_space.write_word(page_offset + (offset << 1), data);
+ popmessage("DMA byte address %06x write %04x\n",page_offset+(offset<<1), m_dma_high_byte | data);
}
@@ -355,6 +405,13 @@ MC6845_UPDATE_ROW( ngen_state::crtc_update_row )
}
}
+void ngen_state::machine_reset()
+{
+ m_control = 0;
+ m_viduart->write_dsr(0);
+ m_viduart->write_cts(0);
+}
+
static ADDRESS_MAP_START( ngen_mem, AS_PROGRAM, 16, ngen_state )
AM_RANGE(0x00000, 0xf7fff) AM_RAM
AM_RANGE(0xf8000, 0xf9fff) AM_RAM AM_SHARE("vram")
@@ -385,32 +442,45 @@ ADDRESS_MAP_END
static INPUT_PORTS_START( ngen )
INPUT_PORTS_END
+static SLOT_INTERFACE_START(keyboard)
+ SLOT_INTERFACE("ngen", NGEN_KEYBOARD)
+SLOT_INTERFACE_END
+
static MACHINE_CONFIG_START( ngen, ngen_state )
// basic machine hardware
MCFG_CPU_ADD("maincpu", I80186, XTAL_16MHz / 2)
MCFG_CPU_PROGRAM_MAP(ngen_mem)
MCFG_CPU_IO_MAP(ngen_io)
MCFG_80186_CHIP_SELECT_CB(WRITE16(ngen_state, cpu_peripheral_cb))
- MCFG_80186_TMROUT1_HANDLER(WRITELINE(ngen_state, pit_out0_w))
+ MCFG_80186_TMROUT1_HANDLER(WRITELINE(ngen_state, cpu_timer_w))
MCFG_PIC8259_ADD( "pic", INPUTLINE("maincpu", 0), VCC, NULL )
MCFG_DEVICE_ADD("pit", PIT8254, 0)
- MCFG_PIT8253_CLK0(XTAL_14_7456MHz/8) // correct?
- MCFG_PIT8253_OUT0_HANDLER(WRITELINE(ngen_state, pit_out0_w))
- MCFG_PIT8253_CLK1(XTAL_14_7456MHz/8)
- MCFG_PIT8253_OUT1_HANDLER(WRITELINE(ngen_state, pit_out1_w))
- MCFG_PIT8253_CLK2(XTAL_14_7456MHz/8)
+ MCFG_PIT8253_CLK0(78120/4) // 19.53kHz, /4 of the CPU timer output?
+ MCFG_PIT8253_OUT0_HANDLER(WRITELINE(ngen_state, pit_out0_w)) // RS232 channel B baud rate
+ MCFG_PIT8253_CLK1(XTAL_14_7456MHz/12) // correct? - based on patent
+ MCFG_PIT8253_OUT1_HANDLER(WRITELINE(ngen_state, pit_out1_w)) // RS232 channel A baud rate
+ MCFG_PIT8253_CLK2(XTAL_14_7456MHz/12)
MCFG_PIT8253_OUT2_HANDLER(WRITELINE(ngen_state, pit_out2_w))
MCFG_DEVICE_ADD("dmac", AM9517A, XTAL_14_7456MHz / 3) // NEC D8237A, divisor unknown
MCFG_I8237_OUT_HREQ_CB(WRITELINE(ngen_state, dma_hrq_changed))
- MCFG_I8237_IN_MEMR_CB(READ8(ngen_state, dma_read_byte))
- MCFG_I8237_OUT_MEMW_CB(WRITE8(ngen_state, dma_write_byte))
+ MCFG_I8237_OUT_EOP_CB(WRITELINE(ngen_state, dma_eop_changed))
+ MCFG_I8237_IN_MEMR_CB(READ8(ngen_state, dma_read_word)) // DMA is always 16-bit
+ MCFG_I8237_OUT_MEMW_CB(WRITE8(ngen_state, dma_write_word))
MCFG_I8237_OUT_DACK_0_CB(WRITELINE(ngen_state, dack0_w))
MCFG_I8237_OUT_DACK_1_CB(WRITELINE(ngen_state, dack1_w))
MCFG_I8237_OUT_DACK_2_CB(WRITELINE(ngen_state, dack2_w))
MCFG_I8237_OUT_DACK_3_CB(WRITELINE(ngen_state, dack3_w))
+ MCFG_I8237_IN_IOR_0_CB(READ8(ngen_state, dma_0_dack_r))
+ MCFG_I8237_IN_IOR_1_CB(READ8(ngen_state, dma_1_dack_r))
+ MCFG_I8237_IN_IOR_2_CB(READ8(ngen_state, dma_2_dack_r))
+ MCFG_I8237_IN_IOR_3_CB(READ8(ngen_state, dma_3_dack_r))
+ MCFG_I8237_OUT_IOW_0_CB(WRITE8(ngen_state, dma_0_dack_w))
+ MCFG_I8237_OUT_IOW_1_CB(WRITE8(ngen_state, dma_1_dack_w))
+ MCFG_I8237_OUT_IOW_2_CB(WRITE8(ngen_state, dma_2_dack_w))
+ MCFG_I8237_OUT_IOW_3_CB(WRITE8(ngen_state, dma_3_dack_w))
// I/O board
MCFG_UPD7201_ADD("iouart",0,0,0,0,0) // clocked by PIT channel 2?
@@ -447,7 +517,15 @@ static MACHINE_CONFIG_START( ngen, ngen_state )
MCFG_MC6845_UPDATE_ROW_CB(ngen_state, crtc_update_row)
MCFG_VIDEO_SET_SCREEN("screen")
- MCFG_DEVICE_ADD("videouart", I8251, 19980000 / 9) // divisor unknown
+ // keyboard UART (patent says i8251 is used for keyboard communications, it is located on the video board)
+ MCFG_DEVICE_ADD("videouart", I8251, 0) // main clock unknown, Rx/Tx clocks are 19.53kHz
+ MCFG_I8251_TXEMPTY_HANDLER(DEVWRITELINE("pic",pic8259_device,ir4_w))
+ MCFG_I8251_TXD_HANDLER(DEVWRITELINE("keyboard", rs232_port_device, write_txd))
+ MCFG_RS232_PORT_ADD("keyboard", keyboard, "ngen")
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("videouart", i8251_device, write_rxd))
+
+ MCFG_DEVICE_ADD("refresh_clock", CLOCK, 19200*16) // should be 19530Hz
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(ngen_state,timer_clk_out))
MACHINE_CONFIG_END
diff --git a/src/mess/machine/ngen_kb.c b/src/mess/machine/ngen_kb.c
new file mode 100644
index 00000000000..498a49dd7fb
--- /dev/null
+++ b/src/mess/machine/ngen_kb.c
@@ -0,0 +1,219 @@
+// Convergent NGEN keyboard device
+
+#include "ngen_kb.h"
+
+ngen_keyboard_device::ngen_keyboard_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
+ serial_keyboard_device(mconfig, NGEN_KEYBOARD, "NGEN Keyboard", tag, owner, 0, "ngen_keyboard", __FILE__),
+ m_keys_down(false)
+{
+}
+
+
+void ngen_keyboard_device::write(UINT8 data)
+{
+ // To be figured out
+ logerror("KB: received character %02x\n",data);
+}
+
+UINT8 ngen_keyboard_device::row_number(UINT8 code)
+{
+ if BIT(code,0) return 0;
+ if BIT(code,1) return 1;
+ if BIT(code,2) return 2;
+ if BIT(code,3) return 3;
+ if BIT(code,4) return 4;
+ if BIT(code,5) return 5;
+ if BIT(code,6) return 6;
+ if BIT(code,7) return 7;
+ return 0;
+}
+
+UINT8 ngen_keyboard_device::keyboard_handler(UINT8 last_code, UINT8 *scan_line)
+{
+ int i;
+ UINT8 code = 0;
+ UINT8 key_code = 0;
+ UINT8 retVal = 0;
+ UINT8 shift = BIT(m_io_kbdc->read(), 1);
+ UINT8 caps = BIT(m_io_kbdc->read(), 2);
+ UINT8 ctrl = BIT(m_io_kbdc->read(), 0);
+ i = *scan_line;
+ {
+ if (i == 0) code = m_io_kbd0->read();
+ else
+ if (i == 1) code = m_io_kbd1->read();
+ else
+ if (i == 2) code = m_io_kbd2->read();
+ else
+ if (i == 3) code = m_io_kbd3->read();
+ else
+ if (i == 4) code = m_io_kbd4->read();
+ else
+ if (i == 5) code = m_io_kbd5->read();
+ else
+ if (i == 6) code = m_io_kbd6->read();
+ else
+ if (i == 7) code = m_io_kbd7->read();
+ else
+ if (i == 8) code = m_io_kbd8->read();
+ else
+ if (i == 9) code = m_io_kbd9->read();
+
+ if (code != 0)
+ {
+ if (i==0 && shift==0) {
+ key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs
+ }
+ if (i==0 && shift==1) {
+ key_code = 0x20 + row_number(code) + 8*i; // for shifted numbers
+ }
+ if (i==1 && shift==0) {
+ if (row_number(code) < 4) {
+ key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs
+ } else {
+ key_code = 0x20 + row_number(code) + 8*i; // for numbers and some signs
+ }
+ }
+ if (i==1 && shift==1) {
+ if (row_number(code) < 4) {
+ key_code = 0x20 + row_number(code) + 8*i; // for numbers and some signs
+ } else {
+ key_code = 0x30 + row_number(code) + 8*i; // for numbers and some signs
+ }
+ }
+ if (i>=2 && i<=4 && (shift ^ caps)==0 && ctrl==0) {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for small letters
+ }
+ if (i>=2 && i<=4 && (shift ^ caps)==1 && ctrl==0) {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for big letters
+ }
+ if (i>=2 && i<=5 && ctrl==1) {
+ key_code = 0x00 + row_number(code) + (i-2)*8; // for CTRL + letters
+ }
+ if (i==5 && shift==1 && ctrl==0) {
+ if (row_number(code)<7) {
+ if (row_number(code)<3) {
+ key_code = (caps ? 0x60 : 0x40) + row_number(code) + (i-2)*8; // for big letters
+ } else {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for upper symbols letters
+ }
+ } else {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for DEL it is switched
+ }
+ }
+ if (i==5 && shift==0 && ctrl==0) {
+ if (row_number(code)<7) {
+ if (row_number(code)<3) {
+ key_code = (caps ? 0x40 : 0x60) + row_number(code) + (i-2)*8; // for small letters
+ } else {
+ key_code = 0x40 + row_number(code) + (i-2)*8; // for lower symbols letters
+ }
+ } else {
+ key_code = 0x60 + row_number(code) + (i-2)*8; // for DEL it is switched
+ }
+ }
+
+ if (i==6) {
+ switch(row_number(code))
+ {
+/* case 0: key_code = 0x11; break;
+ case 1: key_code = 0x12; break;
+ case 2: key_code = 0x13; break;
+ case 3: key_code = 0x14; break;*/
+ case 4: key_code = 0x20; break; // Space
+ case 5: key_code = 0x0A; break; // LineFeed
+ case 6: key_code = 0x09; break; // TAB
+ case 7: key_code = 0x0D; break; // Enter
+ }
+ }
+ if (i==7)
+ {
+ switch(row_number(code))
+ {
+ case 0: key_code = 0x1B; break; // Escape
+ case 1: key_code = 0x08; break; // Backspace
+ }
+ }
+ else
+ if (i==8)
+ {
+ key_code = row_number(code)+0x81;
+ if (ctrl) key_code+=0x10;
+ if (shift) key_code+=0x20;
+ }
+ else
+ if (i==9)
+ {
+ key_code = row_number(code)+0x89;
+ if (ctrl) key_code+=0x10;
+ if (shift) key_code+=0x20;
+ }
+ m_keys_down = true;
+ retVal = key_code;
+ }
+ else
+ {
+ *scan_line += 1;
+ if (*scan_line==10)
+ *scan_line = 0;
+ if(m_keys_down)
+ {
+ retVal = 0xc0;
+ m_keys_down = false;
+ }
+ }
+ }
+ // TODO: add scan code 0xc0 (all keys up)
+ return retVal;
+}
+
+static INPUT_PORTS_START( ngen_keyboard )
+ PORT_INCLUDE(generic_keyboard)
+
+ PORT_START("RS232_TXBAUD")
+ PORT_CONFNAME(0xff, RS232_BAUD_19200, "TX Baud") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, serial_keyboard_device, update_serial)
+ PORT_CONFSETTING( RS232_BAUD_19200, "19200") // TODO: Based on the RAM refresh timer (~78kHz) to be 19530Hz
+
+ PORT_START("RS232_STARTBITS")
+ PORT_CONFNAME(0xff, RS232_STARTBITS_1, "Start Bits") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, serial_keyboard_device, update_serial)
+ PORT_CONFSETTING( RS232_STARTBITS_1, "1")
+
+ PORT_START("RS232_DATABITS")
+ PORT_CONFNAME(0xff, RS232_DATABITS_8, "Data Bits") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, serial_keyboard_device, update_serial)
+ PORT_CONFSETTING( RS232_DATABITS_8, "8")
+
+ PORT_START("RS232_PARITY")
+ PORT_CONFNAME(0xff, RS232_PARITY_NONE, "Parity") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, serial_keyboard_device, update_serial)
+ PORT_CONFSETTING( RS232_PARITY_NONE, "None")
+
+ PORT_START("RS232_STOPBITS")
+ PORT_CONFNAME(0xff, RS232_STOPBITS_2, "Stop Bits") PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, serial_keyboard_device, update_serial)
+ PORT_CONFSETTING( RS232_STOPBITS_2, "2")
+INPUT_PORTS_END
+
+
+ioport_constructor ngen_keyboard_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(ngen_keyboard);
+}
+
+void ngen_keyboard_device::device_start()
+{
+ serial_keyboard_device::device_start();
+ set_rcv_rate(19200);
+}
+
+void ngen_keyboard_device::device_reset()
+{
+ serial_keyboard_device::device_reset();
+ m_keys_down = false;
+}
+
+void ngen_keyboard_device::rcv_complete()
+{
+ receive_register_extract();
+ write(get_received_char());
+}
+
+const device_type NGEN_KEYBOARD = &device_creator<ngen_keyboard_device>;
+
diff --git a/src/mess/machine/ngen_kb.h b/src/mess/machine/ngen_kb.h
new file mode 100644
index 00000000000..09efc237666
--- /dev/null
+++ b/src/mess/machine/ngen_kb.h
@@ -0,0 +1,30 @@
+// Convergent NGEN keyboard
+
+#ifndef NGEN_KB_H_
+#define NGEN_KB_H_
+
+#include "bus/rs232/keyboard.h"
+
+class ngen_keyboard_device : public serial_keyboard_device
+{
+public:
+ ngen_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ioport_constructor device_input_ports() const;
+ virtual DECLARE_WRITE_LINE_MEMBER( input_txd ) {/* printf("TX: %i\n",state);*/ device_serial_interface::rx_w(state); }
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void rcv_complete();
+
+private:
+ virtual UINT8 keyboard_handler(UINT8 last_code, UINT8 *scan_line);
+ UINT8 row_number(UINT8 code);
+ void write(UINT8 data);
+
+ bool m_keys_down;
+};
+
+extern const device_type NGEN_KEYBOARD;
+
+#endif /* NGENKB_H_ */
diff --git a/src/mess/mess.mak b/src/mess/mess.mak
index 025cb059ae0..624ce654a85 100644
--- a/src/mess/mess.mak
+++ b/src/mess/mess.mak
@@ -1952,7 +1952,7 @@ $(MESSOBJ)/skeleton.a: \
$(MESS_DRIVERS)/mx2178.o \
$(MESS_DRIVERS)/mycom.o \
$(MESS_DRIVERS)/myvision.o \
- $(MESS_DRIVERS)/ngen.o \
+ $(MESS_DRIVERS)/ngen.o $(MESS_MACHINE)/ngen_kb.o \
$(MESS_DRIVERS)/octopus.o \
$(MESS_DRIVERS)/onyx.o \
$(MESS_DRIVERS)/okean240.o \