mirror of
https://github.com/holub/mame
synced 2025-04-23 08:49:55 +03:00
to8, to9, to9p: Split out serial keyboards as separate devices
This commit is contained in:
parent
d7211e631d
commit
366d6fea79
@ -460,10 +460,6 @@ static INPUT_PORTS_START ( to7_keyboard )
|
||||
KEY ( 6, "7 ' \302\264", 7 ) PORT_CHAR('7') PORT_CHAR('\'')
|
||||
KEY ( 7, "6 &", 6 ) PORT_CHAR('6') PORT_CHAR('&')
|
||||
|
||||
/* unused */
|
||||
PORT_START ( "keyboard.8" )
|
||||
PORT_START ( "keyboard.9" )
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START ( to7 )
|
||||
@ -1062,7 +1058,7 @@ void to9_state::to9_map(address_map &map)
|
||||
map(0xe7c8, 0xe7cb).rw("pia_0", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
|
||||
map(0xe7cc, 0xe7cf).rw("pia_1", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
|
||||
map(0xe7da, 0xe7dd).rw(FUNC(to9_state::to9_vreg_r), FUNC(to9_state::to9_vreg_w));
|
||||
map(0xe7de, 0xe7df).rw(FUNC(to9_state::to9_kbd_r), FUNC(to9_state::to9_kbd_w));
|
||||
map(0xe7de, 0xe7df).rw(m_to9_kbd, FUNC(to9_keyboard_device::kbd_acia_r), FUNC(to9_keyboard_device::kbd_acia_w));
|
||||
map(0xe7e4, 0xe7e7).rw(FUNC(to9_state::to9_gatearray_r), FUNC(to9_state::to9_gatearray_w));
|
||||
/* map(0xe7f0, 0xe7f7).rw(FUNC(to9_state::to9_ieee_r), FUNC(to9_state::to9_ieee_w )); */
|
||||
map(0xe800, 0xffff).rom(); /* system bios */
|
||||
@ -1127,105 +1123,23 @@ ROM_END
|
||||
|
||||
/* ------------ inputs ------------ */
|
||||
|
||||
static INPUT_PORTS_START ( to9_keyboard )
|
||||
PORT_START ( "keyboard.0" )
|
||||
KEY ( 0, "F2 F7", F2 ) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7))
|
||||
KEY ( 1, "_ 6", 6 ) PORT_CHAR('_') PORT_CHAR('6')
|
||||
KEY ( 2, "Y", Y ) PORT_CHAR('Y')
|
||||
KEY ( 3, "H \302\250", H ) PORT_CHAR('H')
|
||||
KEY ( 4, UTF8_UP, UP ) PORT_CHAR(UCHAR_MAMEKEY(UP))
|
||||
KEY ( 5, UTF8_RIGHT, RIGHT ) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
|
||||
KEY ( 6, "Home Clear", HOME ) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CHAR(UCHAR_MAMEKEY(ESC))
|
||||
KEY ( 7, "N", N ) PORT_CHAR('N')
|
||||
PORT_START ( "keyboard.1" )
|
||||
KEY ( 0, "F3 F8", F3 ) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8))
|
||||
KEY ( 1, "( 5", 5 ) PORT_CHAR('(') PORT_CHAR('5')
|
||||
KEY ( 2, "T", T ) PORT_CHAR('T')
|
||||
KEY ( 3, "G", G ) PORT_CHAR('G')
|
||||
KEY ( 4, "= +", EQUALS ) PORT_CHAR('=') PORT_CHAR('+')
|
||||
KEY ( 5, UTF8_LEFT, LEFT ) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
|
||||
KEY ( 6, "Insert", INSERT ) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
|
||||
KEY ( 7, "B \302\264", B ) PORT_CHAR('B')
|
||||
PORT_START ( "keyboard.2" )
|
||||
KEY ( 0, "F4 F9", F4 ) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9))
|
||||
KEY ( 1, "' 4", 4 ) PORT_CHAR('\'') PORT_CHAR('4')
|
||||
KEY ( 2, "R", R ) PORT_CHAR('R')
|
||||
KEY ( 3, "F", F ) PORT_CHAR('F')
|
||||
KEY ( 4, "Accent", END ) PORT_CHAR(UCHAR_MAMEKEY(END))
|
||||
KEY ( 5, "Keypad 1", 1_PAD ) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
|
||||
KEY ( 6, "Delete Backspace", DEL ) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE))
|
||||
KEY ( 7, "V", V ) PORT_CHAR('V')
|
||||
PORT_START ( "keyboard.3" )
|
||||
KEY ( 0, "F5 F10", F5 ) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10))
|
||||
KEY ( 1, "\" 3", 3 ) PORT_CHAR('"') PORT_CHAR('3')
|
||||
KEY ( 2, "E", E ) PORT_CHAR('E')
|
||||
KEY ( 3, "D", D ) PORT_CHAR('D')
|
||||
KEY ( 4, "Keypad 7", 7_PAD ) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
|
||||
KEY ( 5, "Keypad 4", 4_PAD ) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
|
||||
KEY ( 6, "Keypad 0", 0_PAD ) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
|
||||
KEY ( 7, "C \136", C ) PORT_CHAR('C')
|
||||
PORT_START ( "keyboard.4" )
|
||||
KEY ( 0, "F1 F6", F1 ) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6))
|
||||
KEY ( 1, "\303\251 2", 2 ) PORT_CHAR( 0xe9 ) PORT_CHAR('2')
|
||||
KEY ( 2, "Z", Z ) PORT_CHAR('Z')
|
||||
KEY ( 3, "S", S ) PORT_CHAR('S')
|
||||
KEY ( 4, "Keypad 8", 8_PAD ) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
|
||||
KEY ( 5, "Keypad 2", 2_PAD ) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
|
||||
KEY ( 6, "Keypad .", DEL_PAD ) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
|
||||
KEY ( 7, "X", X ) PORT_CHAR('X')
|
||||
PORT_START ( "keyboard.5" )
|
||||
KEY ( 0, "# @", TILDE ) PORT_CHAR('#') PORT_CHAR('@')
|
||||
KEY ( 1, "* 1", 1 ) PORT_CHAR('*') PORT_CHAR('1')
|
||||
KEY ( 2, "A \140", A ) PORT_CHAR('A')
|
||||
KEY ( 3, "Q", Q ) PORT_CHAR('Q')
|
||||
KEY ( 4, "[ {", QUOTE ) PORT_CHAR('[') PORT_CHAR('{')
|
||||
KEY ( 5, "Keypad 5", 5_PAD ) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
|
||||
KEY ( 6, "Keypad 6", 6_PAD ) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
|
||||
KEY ( 7, "W", W ) PORT_CHAR('W')
|
||||
PORT_START ( "keyboard.6" )
|
||||
KEY ( 0, "Stop", TAB ) PORT_CHAR(27)
|
||||
KEY ( 1, "\303\250 7", 7 ) PORT_CHAR( 0xe8 ) PORT_CHAR('7')
|
||||
KEY ( 2, "U", U ) PORT_CHAR('U')
|
||||
KEY ( 3, "J", J ) PORT_CHAR('J')
|
||||
KEY ( 4, "Space", SPACE ) PORT_CHAR(' ')
|
||||
KEY ( 5, "Keypad 9", 9_PAD ) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
|
||||
KEY ( 6, "Keypad Enter", ENTER_PAD ) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
|
||||
KEY ( 7, ", ?", COMMA ) PORT_CHAR(',') PORT_CHAR('?')
|
||||
PORT_START ( "keyboard.7" )
|
||||
KEY ( 0, "Control", LCONTROL ) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
|
||||
KEY ( 1, "! 8", 8 ) PORT_CHAR('!') PORT_CHAR('8')
|
||||
KEY ( 2, "I", I ) PORT_CHAR('I')
|
||||
KEY ( 3, "K", K ) PORT_CHAR('K')
|
||||
KEY ( 4, "$ &", CLOSEBRACE ) PORT_CHAR('$') PORT_CHAR('&')
|
||||
KEY ( 5, UTF8_DOWN, DOWN ) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
|
||||
KEY ( 6, "] }", BACKSLASH ) PORT_CHAR(']') PORT_CHAR('}')
|
||||
KEY ( 7, "; .", STOP ) PORT_CHAR(';') PORT_CHAR('.')
|
||||
PORT_START ( "keyboard.8" )
|
||||
KEY ( 0, "Caps-Lock", CAPSLOCK ) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
|
||||
KEY ( 1, "\303\247 9", 9 ) PORT_CHAR( 0xe7 ) PORT_CHAR('9')
|
||||
KEY ( 2, "O", O ) PORT_CHAR('O')
|
||||
KEY ( 3, "L", L ) PORT_CHAR('L')
|
||||
KEY ( 4, "- \\", BACKSPACE ) PORT_CHAR('-') PORT_CHAR('\\')
|
||||
KEY ( 5, "\303\271 %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%')
|
||||
KEY ( 6, "Enter", ENTER ) PORT_CHAR(13)
|
||||
KEY ( 7, ": /", SLASH ) PORT_CHAR(':') PORT_CHAR('/')
|
||||
PORT_START ( "keyboard.9" )
|
||||
KEY ( 0, "Shift", LSHIFT ) PORT_CODE ( KEYCODE_RSHIFT ) PORT_CHAR(UCHAR_SHIFT_1)
|
||||
KEY ( 1, "\303\240 0", 0 ) PORT_CHAR( 0xe0 ) PORT_CHAR('0')
|
||||
KEY ( 2, "P", P ) PORT_CHAR('P')
|
||||
KEY ( 3, "M", M ) PORT_CHAR('M')
|
||||
KEY ( 4, ") \302\260", MINUS ) PORT_CHAR(')') PORT_CHAR( 0xb0 )
|
||||
KEY ( 5, "\342\206\221 \302\250", OPENBRACE ) PORT_CHAR('^') PORT_CHAR( 0xa8 )
|
||||
KEY ( 6, "Keypad 3", 3_PAD ) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
|
||||
KEY ( 7, "> <", BACKSLASH2 ) PORT_CHAR('>') PORT_CHAR('<')
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START ( to9 )
|
||||
PORT_INCLUDE ( thom_lightpen )
|
||||
PORT_INCLUDE ( thom_game_port )
|
||||
PORT_INCLUDE ( to9_keyboard )
|
||||
PORT_INCLUDE ( to7_config )
|
||||
PORT_INCLUDE ( to7_vconfig )
|
||||
|
||||
PORT_START ( "config" )
|
||||
PORT_BIT ( 0x01, 0x00, IPT_UNUSED )
|
||||
|
||||
PORT_MODIFY ( "mouse_x" )
|
||||
PORT_BIT ( 0xffff, 0x00, IPT_UNUSED )
|
||||
|
||||
PORT_MODIFY ( "mouse_y" )
|
||||
PORT_BIT ( 0xffff, 0x00, IPT_UNUSED )
|
||||
|
||||
PORT_MODIFY ( "mouse_button" )
|
||||
PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
INPUT_PORTS_END
|
||||
|
||||
/* ------------ driver ------------ */
|
||||
@ -1238,6 +1152,9 @@ void to9_state::to9(machine_config &config)
|
||||
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to9_map);
|
||||
|
||||
TO9_KEYBOARD(config, m_to9_kbd);
|
||||
m_to9_kbd->irq_cb().set(m_mainirq, FUNC(input_merger_device::in_w<4>));
|
||||
|
||||
m_pia_sys->readpa_handler().set(FUNC(to9_state::to9_sys_porta_in));
|
||||
m_pia_sys->readpb_handler().set_constant(0);
|
||||
m_pia_sys->writepa_handler().set(FUNC(to9_state::to9_sys_porta_out));
|
||||
@ -1412,25 +1329,10 @@ ROM_END
|
||||
|
||||
/* ------------ inputs ------------ */
|
||||
|
||||
static INPUT_PORTS_START ( to8_config )
|
||||
PORT_START ( "config" )
|
||||
|
||||
PORT_CONFNAME ( 0x01, 0x00, "Game Port" )
|
||||
PORT_CONFSETTING ( 0x00, DEF_STR( Joystick ) )
|
||||
PORT_CONFSETTING ( 0x01, "Mouse" )
|
||||
|
||||
PORT_CONFNAME ( 0x02, 0x00, "Keyboard" )
|
||||
PORT_CONFSETTING ( 0x00, "Enabled" )
|
||||
PORT_CONFSETTING ( 0x02, "Disabled" )
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
static INPUT_PORTS_START ( to8 )
|
||||
PORT_INCLUDE ( thom_lightpen )
|
||||
PORT_INCLUDE ( thom_game_port )
|
||||
PORT_INCLUDE ( to9_keyboard )
|
||||
PORT_INCLUDE ( to8_config )
|
||||
PORT_INCLUDE ( to7_config )
|
||||
PORT_INCLUDE ( to7_vconfig )
|
||||
INPUT_PORTS_END
|
||||
|
||||
@ -1449,7 +1351,8 @@ void to9_state::to8(machine_config &config)
|
||||
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to8_map);
|
||||
|
||||
//MC6804(config, "kbdmcu", 11_MHz_XTAL);
|
||||
TO8_KEYBOARD(config, m_to8_kbd);
|
||||
m_to8_kbd->data_cb().set(m_mc6846, FUNC(mc6846_device::set_input_cp1));
|
||||
|
||||
m_pia_sys->readpa_handler().set(FUNC(to9_state::to8_sys_porta_in));
|
||||
m_pia_sys->readpb_handler().set_constant(0);
|
||||
@ -1537,7 +1440,7 @@ void to9_state::to9p_map(address_map &map)
|
||||
map(0xe7c8, 0xe7cb).rw("pia_0", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
|
||||
map(0xe7cc, 0xe7cf).rw("pia_1", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
|
||||
map(0xe7da, 0xe7dd).rw(FUNC(to9_state::to8_vreg_r), FUNC(to9_state::to8_vreg_w));
|
||||
map(0xe7de, 0xe7df).rw(FUNC(to9_state::to9_kbd_r), FUNC(to9_state::to9_kbd_w));
|
||||
map(0xe7de, 0xe7df).rw(m_to9_kbd, FUNC(to9_keyboard_device::kbd_acia_r), FUNC(to9_keyboard_device::kbd_acia_w));
|
||||
map(0xe7e4, 0xe7e7).rw(FUNC(to9_state::to8_gatearray_r), FUNC(to9_state::to8_gatearray_w));
|
||||
/* map(0xe7f0, 0xe7f7).rw(FUNC(to9_state::to9_ieee_r), FUNC(to9_state::to9_ieee_w )); */
|
||||
|
||||
@ -1588,7 +1491,6 @@ ROM_END
|
||||
static INPUT_PORTS_START ( to9p )
|
||||
PORT_INCLUDE ( thom_lightpen )
|
||||
PORT_INCLUDE ( thom_game_port )
|
||||
PORT_INCLUDE ( to9_keyboard )
|
||||
PORT_INCLUDE ( to7_config )
|
||||
PORT_INCLUDE ( to7_vconfig )
|
||||
INPUT_PORTS_END
|
||||
@ -1603,6 +1505,9 @@ void to9_state::to9p(machine_config &config)
|
||||
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &to9_state::to9p_map);
|
||||
|
||||
TO9P_KEYBOARD(config, m_to9_kbd);
|
||||
m_to9_kbd->irq_cb().set(m_mainirq, FUNC(input_merger_device::in_w<4>));
|
||||
|
||||
m_pia_sys->readpa_handler().set(FUNC(to9_state::to9_sys_porta_in));
|
||||
m_pia_sys->readpb_handler().set_constant(0);
|
||||
m_pia_sys->writepa_handler().set(FUNC(to9_state::to9_sys_porta_out));
|
||||
@ -1861,9 +1766,6 @@ static INPUT_PORTS_START ( mo6_keyboard )
|
||||
KEY ( 4, "\303\271 %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%')
|
||||
PORT_BIT ( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
|
||||
/* unused */
|
||||
PORT_START ( "keyboard.9" )
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
/* QWERTY version */
|
||||
@ -2169,10 +2071,6 @@ static INPUT_PORTS_START ( mo5nr_keyboard )
|
||||
KEY ( 6, "Stop", TAB ) PORT_CHAR(27)
|
||||
PORT_BIT ( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
|
||||
|
||||
/* unused */
|
||||
PORT_START ( "keyboard.8" )
|
||||
PORT_START ( "keyboard.9" )
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START ( mo5nr )
|
||||
|
@ -13,6 +13,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "to_kbd.h"
|
||||
|
||||
#include "cpu/m6809/m6809.h"
|
||||
#include "imagedev/cassette.h"
|
||||
#include "machine/6821pia.h"
|
||||
@ -231,7 +233,7 @@ protected:
|
||||
required_ioport m_io_lightpen_button;
|
||||
required_ioport m_io_config;
|
||||
required_ioport m_io_vconfig;
|
||||
required_ioport_array<10> m_io_keyboard;
|
||||
optional_ioport_array<9> m_io_keyboard;
|
||||
required_memory_bank m_vrambank;
|
||||
optional_memory_bank m_cartbank;
|
||||
optional_memory_bank m_rambank;
|
||||
@ -384,6 +386,8 @@ class to9_state : public thomson_state
|
||||
public:
|
||||
to9_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
thomson_state(mconfig, type, tag),
|
||||
m_to8_kbd(*this, "to8_kbd"),
|
||||
m_to9_kbd(*this, "to9_kbd"),
|
||||
m_centronics(*this, "centronics"),
|
||||
m_cent_data_out(*this, "cent_data_out"),
|
||||
m_syslobank(*this, TO8_SYS_LO),
|
||||
@ -400,6 +404,8 @@ public:
|
||||
void to9p(machine_config &config);
|
||||
|
||||
protected:
|
||||
optional_device<to8_keyboard_device> m_to8_kbd;
|
||||
optional_device<to9_keyboard_device> m_to9_kbd;
|
||||
optional_device<centronics_device> m_centronics;
|
||||
optional_device<output_latch_device> m_cent_data_out;
|
||||
|
||||
@ -411,14 +417,6 @@ protected:
|
||||
|
||||
int m_centronics_busy = 0;
|
||||
|
||||
uint8_t m_to8_kbd_ack = 0; /* 1 = cpu inits / accepts transfers */
|
||||
uint16_t m_to8_kbd_data = 0; /* data to transmit */
|
||||
uint16_t m_to8_kbd_step = 0; /* transmission automaton state */
|
||||
uint8_t m_to8_kbd_last_key = 0; /* last key (for repetition) */
|
||||
uint32_t m_to8_kbd_key_count = 0; /* keypress time (for repetition) */
|
||||
uint8_t m_to8_kbd_caps = 0; /* caps lock */
|
||||
emu_timer* m_to8_kbd_timer = nullptr; /* bit-send */
|
||||
emu_timer* m_to8_kbd_signal = nullptr; /* signal from CPU */
|
||||
uint8_t m_to8_data_vpage = 0;
|
||||
uint8_t m_to8_cart_vpage = 0;
|
||||
uint8_t m_to8_reg_ram = 0;
|
||||
@ -430,7 +428,6 @@ protected:
|
||||
uint8_t m_to8_soft_bank = 0;
|
||||
uint8_t m_to8_bios_bank = 0;
|
||||
|
||||
TIMER_CALLBACK_MEMBER( to8_kbd_timer_cb );
|
||||
void to8_update_ram_bank_postload();
|
||||
void to8_update_cart_bank_postload();
|
||||
void to8_cartridge_w(offs_t offset, uint8_t data);
|
||||
@ -456,12 +453,6 @@ protected:
|
||||
void to8_data_hi_w(offs_t offset, uint8_t data);
|
||||
void to8_vcart_w(offs_t offset, uint8_t data);
|
||||
|
||||
int to8_kbd_ktest();
|
||||
int to8_kbd_get_key();
|
||||
void to8_kbd_timer_func();
|
||||
void to8_kbd_set_ack( int data );
|
||||
void to8_kbd_reset();
|
||||
void to8_kbd_init();
|
||||
void to8_update_ram_bank();
|
||||
void to8_update_cart_bank();
|
||||
|
||||
@ -475,9 +466,6 @@ protected:
|
||||
void to9_cartridge_w(offs_t offset, uint8_t data);
|
||||
uint8_t to9_cartridge_r(offs_t offset);
|
||||
void to9_update_ram_bank_postload();
|
||||
uint8_t to9_kbd_r(offs_t offset);
|
||||
void to9_kbd_w(offs_t offset, uint8_t data);
|
||||
TIMER_CALLBACK_MEMBER( to9_kbd_timer_cb );
|
||||
uint8_t to9_sys_porta_in();
|
||||
void to9_sys_porta_out(uint8_t data);
|
||||
void to9_sys_portb_out(uint8_t data);
|
||||
@ -496,31 +484,11 @@ protected:
|
||||
uint8_t m_to9_palette_data[32]{};
|
||||
uint8_t m_to9_palette_idx = 0;
|
||||
uint8_t m_to9_soft_bank = 0;
|
||||
uint8_t m_to9_kbd_parity = 0; /* 0=even, 1=odd, 2=no parity */
|
||||
uint8_t m_to9_kbd_intr = 0; /* interrupt mode */
|
||||
uint8_t m_to9_kbd_in = 0; /* data from keyboard */
|
||||
uint8_t m_to9_kbd_status = 0; /* status */
|
||||
uint8_t m_to9_kbd_overrun = 0; /* character lost */
|
||||
uint8_t m_to9_kbd_periph = 0; /* peripheral mode */
|
||||
uint8_t m_to9_kbd_byte_count = 0; /* byte-count in peripheral mode */
|
||||
uint16_t m_to9_mouse_x = 0;
|
||||
uint16_t m_to9_mouse_y = 0;
|
||||
uint8_t m_to9_kbd_last_key = 0; /* for key repetition */
|
||||
uint16_t m_to9_kbd_key_count = 0;
|
||||
uint8_t m_to9_kbd_caps = 0; /* caps-lock */
|
||||
uint8_t m_to9_kbd_pad = 0; /* keypad outputs special codes */
|
||||
emu_timer* m_to9_kbd_timer = nullptr;
|
||||
|
||||
void to9_set_video_mode( uint8_t data, int style );
|
||||
void to9_palette_init();
|
||||
void to9_update_cart_bank();
|
||||
void to9_update_ram_bank();
|
||||
int to9_kbd_ktest();
|
||||
void to9_kbd_update_irq();
|
||||
void to9_kbd_send( uint8_t data, int parity );
|
||||
int to9_kbd_get_key();
|
||||
void to9_kbd_reset();
|
||||
void to9_kbd_init();
|
||||
};
|
||||
|
||||
class mo6_state : public to9_state
|
||||
|
@ -224,19 +224,6 @@ void thomson_state::thom_irq_reset()
|
||||
|
||||
|
||||
|
||||
/* ------------ 6850 defines ------------ */
|
||||
|
||||
#define ACIA_6850_RDRF 0x01 /* Receive data register full */
|
||||
#define ACIA_6850_TDRE 0x02 /* Transmit data register empty */
|
||||
#define ACIA_6850_dcd 0x04 /* Data carrier detect, active low */
|
||||
#define ACIA_6850_cts 0x08 /* Clear to send, active low */
|
||||
#define ACIA_6850_FE 0x10 /* Framing error */
|
||||
#define ACIA_6850_OVRN 0x20 /* Receiver overrun */
|
||||
#define ACIA_6850_PE 0x40 /* Parity error */
|
||||
#define ACIA_6850_irq 0x80 /* Interrupt request, active low */
|
||||
|
||||
|
||||
|
||||
/***************************** TO7 / T9000 *************************/
|
||||
|
||||
DEVICE_IMAGE_LOAD_MEMBER( thomson_state::to7_cartridge )
|
||||
@ -1689,451 +1676,11 @@ void to9_state::to9_update_ram_bank_postload()
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------ keyboard (6850 ACIA + 6805 CPU) ------------ */
|
||||
|
||||
/* The 6805 chip scans the keyboard and sends ASCII codes to the 6909.
|
||||
Data between the 6809 and 6805 is serialized at 9600 bauds.
|
||||
On the 6809 side, a 6850 ACIA is used.
|
||||
We do not emulate the seral line but pass bytes directly between the
|
||||
keyboard and the 6850 registers.
|
||||
Note that the keyboard protocol uses the parity bit as an extra data bit.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* normal mode: polling interval */
|
||||
#define TO9_KBD_POLL_PERIOD attotime::from_msec( 10 )
|
||||
|
||||
/* peripheral mode: time between two bytes, and after last byte */
|
||||
#define TO9_KBD_BYTE_SPACE attotime::from_usec( 300 )
|
||||
#define TO9_KBD_END_SPACE attotime::from_usec( 9100 )
|
||||
|
||||
/* first and subsequent repeat periods, in TO9_KBD_POLL_PERIOD units */
|
||||
#define TO9_KBD_REPEAT_DELAY 80 /* 800 ms */
|
||||
#define TO9_KBD_REPEAT_PERIOD 7 /* 70 ms */
|
||||
|
||||
|
||||
|
||||
/* quick keyboard scan */
|
||||
int to9_state::to9_kbd_ktest()
|
||||
{
|
||||
int line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to9_kbd_update_irq()
|
||||
{
|
||||
if ( (m_to9_kbd_intr & 4) && (m_to9_kbd_status & ACIA_6850_RDRF) )
|
||||
m_to9_kbd_status |= ACIA_6850_irq; /* byte received interrupt */
|
||||
|
||||
if ( (m_to9_kbd_intr & 4) && (m_to9_kbd_status & ACIA_6850_OVRN) )
|
||||
m_to9_kbd_status |= ACIA_6850_irq; /* overrun interrupt */
|
||||
|
||||
if ( (m_to9_kbd_intr & 3) == 1 && (m_to9_kbd_status & ACIA_6850_TDRE) )
|
||||
m_to9_kbd_status |= ACIA_6850_irq; /* ready to transmit interrupt */
|
||||
|
||||
m_mainirq->in_w<3>( m_to9_kbd_status & ACIA_6850_irq );
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t to9_state::to9_kbd_r(offs_t offset)
|
||||
{
|
||||
/* ACIA 6850 registers */
|
||||
|
||||
switch ( offset )
|
||||
{
|
||||
case 0: /* get status */
|
||||
/* bit 0: data received */
|
||||
/* bit 1: ready to transmit data (always 1) */
|
||||
/* bit 2: data carrier detect (ignored) */
|
||||
/* bit 3: clear to send (ignored) */
|
||||
/* bit 4: framing error (ignored) */
|
||||
/* bit 5: overrun */
|
||||
/* bit 6: parity error */
|
||||
/* bit 7: interrupt */
|
||||
|
||||
LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, pe=%i, irq=%i)\n",
|
||||
m_maincpu->pc(), machine().time().as_double(), m_to9_kbd_status,
|
||||
(m_to9_kbd_status & ACIA_6850_RDRF) ? 1 : 0,
|
||||
(m_to9_kbd_status & ACIA_6850_TDRE) ? 1 : 0,
|
||||
(m_to9_kbd_status & ACIA_6850_OVRN) ? 1 : 0,
|
||||
(m_to9_kbd_status & ACIA_6850_PE) ? 1 : 0,
|
||||
(m_to9_kbd_status & ACIA_6850_irq) ? 1 : 0 );
|
||||
return m_to9_kbd_status;
|
||||
|
||||
case 1: /* get input data */
|
||||
if ( !machine().side_effects_disabled() )
|
||||
{
|
||||
m_to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_PE);
|
||||
if ( m_to9_kbd_overrun )
|
||||
m_to9_kbd_status |= ACIA_6850_OVRN;
|
||||
else
|
||||
m_to9_kbd_status &= ~(ACIA_6850_OVRN | ACIA_6850_RDRF);
|
||||
m_to9_kbd_overrun = 0;
|
||||
LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_r: read data $%02X\n", m_maincpu->pc(), machine().time().as_double(), m_to9_kbd_in);
|
||||
to9_kbd_update_irq();
|
||||
}
|
||||
return m_to9_kbd_in;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "$%04x to9_kbd_r: invalid offset %i\n", m_maincpu->pc(), offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to9_kbd_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
/* ACIA 6850 registers */
|
||||
|
||||
switch ( offset )
|
||||
{
|
||||
case 0: /* set control */
|
||||
/* bits 0-1: clock divide (ignored) or reset */
|
||||
if ( (data & 3) == 3 )
|
||||
{
|
||||
/* reset */
|
||||
m_to9_kbd_overrun = 0;
|
||||
m_to9_kbd_status = ACIA_6850_TDRE;
|
||||
m_to9_kbd_intr = 0;
|
||||
LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_w: reset (data=$%02X)\n", m_maincpu->pc(), machine().time().as_double(), data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bits 2-4: parity */
|
||||
if ( (data & 0x18) == 0x10 )
|
||||
m_to9_kbd_parity = 2;
|
||||
else
|
||||
m_to9_kbd_parity = (data >> 2) & 1;
|
||||
/* bits 5-6: interrupt on transmit */
|
||||
/* bit 7: interrupt on receive */
|
||||
m_to9_kbd_intr = data >> 5;
|
||||
|
||||
LOGMASKED(LOG_KBD, "$%04x %f to9_kbd_w: set control to $%02X (parity=%i, intr in=%i out=%i)\n",
|
||||
m_maincpu->pc(), machine().time().as_double(),
|
||||
data, m_to9_kbd_parity, m_to9_kbd_intr >> 2,
|
||||
(m_to9_kbd_intr & 3) ? 1 : 0);
|
||||
}
|
||||
to9_kbd_update_irq();
|
||||
break;
|
||||
|
||||
case 1: /* output data */
|
||||
m_to9_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE);
|
||||
to9_kbd_update_irq();
|
||||
/* TODO: 1 ms delay here ? */
|
||||
m_to9_kbd_status |= ACIA_6850_TDRE; /* data transmit ready again */
|
||||
to9_kbd_update_irq();
|
||||
|
||||
switch ( data )
|
||||
{
|
||||
case 0xF8:
|
||||
/* reset */
|
||||
m_to9_kbd_caps = 1;
|
||||
m_to9_kbd_periph = 0;
|
||||
m_to9_kbd_pad = 0;
|
||||
break;
|
||||
|
||||
case 0xF9: m_to9_kbd_caps = 1; break;
|
||||
case 0xFA: m_to9_kbd_caps = 0; break;
|
||||
case 0xFB: m_to9_kbd_pad = 1; break;
|
||||
case 0xFC: m_to9_kbd_pad = 0; break;
|
||||
case 0xFD: m_to9_kbd_periph = 1; break;
|
||||
case 0xFE: m_to9_kbd_periph = 0; break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "$%04x %f to9_kbd_w: unknown kbd command %02X\n", m_maincpu->pc(), machine().time().as_double(), data);
|
||||
}
|
||||
|
||||
m_caps_led = !m_to9_kbd_caps;
|
||||
|
||||
LOG("$%04x %f to9_kbd_w: kbd command %02X (caps=%i, pad=%i, periph=%i)\n",
|
||||
m_maincpu->pc(), machine().time().as_double(), data,
|
||||
m_to9_kbd_caps, m_to9_kbd_pad, m_to9_kbd_periph);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "$%04x to9_kbd_w: invalid offset %i (data=$%02X) \n", m_maincpu->pc(), offset, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* send a key to the CPU, 8-bit + parity bit (0=even, 1=odd)
|
||||
note: parity is not used as a checksum but to actually transmit a 9-th bit
|
||||
of information!
|
||||
*/
|
||||
void to9_state::to9_kbd_send( uint8_t data, int parity )
|
||||
{
|
||||
if ( m_to9_kbd_status & ACIA_6850_RDRF )
|
||||
{
|
||||
/* overrun will be set when the current valid byte is read */
|
||||
m_to9_kbd_overrun = 1;
|
||||
LOGMASKED(LOG_KBD, "%f to9_kbd_send: overrun => drop data=$%02X, parity=%i\n", machine().time().as_double(), data, parity);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* valid byte */
|
||||
m_to9_kbd_in = data;
|
||||
m_to9_kbd_status |= ACIA_6850_RDRF; /* raise data received flag */
|
||||
if ( m_to9_kbd_parity == 2 || m_to9_kbd_parity == parity )
|
||||
m_to9_kbd_status &= ~ACIA_6850_PE; /* parity OK */
|
||||
else
|
||||
m_to9_kbd_status |= ACIA_6850_PE; /* parity error */
|
||||
LOGMASKED(LOG_KBD, "%f to9_kbd_send: data=$%02X, parity=%i, status=$%02X\n", machine().time().as_double(), data, parity, m_to9_kbd_status);
|
||||
}
|
||||
to9_kbd_update_irq();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* keycode => TO9 code (extended ASCII), shifted and un-shifted */
|
||||
static const int to9_kbd_code[80][2] =
|
||||
{
|
||||
{ 145, 150 }, { '_', '6' }, { 'Y', 'Y' }, { 'H', 'H' },
|
||||
{ 11, 11 }, { 9, 9 }, { 30, 12 }, { 'N', 'N' },
|
||||
|
||||
{ 146, 151 }, { '(', '5' }, { 'T', 'T' }, { 'G', 'G' },
|
||||
{ '=', '+' }, { 8, 8 }, { 28, 28 }, { 'B', 'B' },
|
||||
|
||||
{ 147, 152 }, { '\'', '4' }, { 'R', 'R' }, { 'F', 'F' },
|
||||
{ 22, 22 }, { 155, 155 }, { 29, 127 }, { 'V', 'V' },
|
||||
|
||||
{ 148, 153 }, { '"', '3' }, { 'E', 'E' }, { 'D', 'D' },
|
||||
{ 161, 161 }, { 158, 158 },
|
||||
{ 154, 154 }, { 'C', 'C' },
|
||||
|
||||
{ 144, 149 }, { 128, '2' }, { 'Z', 'Z' }, { 'S', 'S' },
|
||||
{ 162, 162 }, { 156, 156 },
|
||||
{ 164, 164 }, { 'X', 'X' },
|
||||
|
||||
{ '#', '@' }, { '*', '1' }, { 'A', 'A' }, { 'Q', 'Q' },
|
||||
{ '[', '{' }, { 159, 159 }, { 160, 160 }, { 'W', 'W' },
|
||||
|
||||
{ 2, 2 }, { 129, '7' }, { 'U', 'U' }, { 'J', 'J' },
|
||||
{ ' ', ' ' }, { 163, 163 }, { 165, 165 },
|
||||
{ ',', '?' },
|
||||
|
||||
{ 0, 0 }, { '!', '8' }, { 'I', 'I' }, { 'K', 'K' },
|
||||
{ '$', '&' }, { 10, 10 }, { ']', '}' }, { ';', '.' },
|
||||
|
||||
{ 0, 0 }, { 130, '9' }, { 'O', 'O' }, { 'L', 'L' },
|
||||
{ '-', '\\' }, { 132, '%' }, { 13, 13 }, { ':', '/' },
|
||||
|
||||
{ 0, 0 }, { 131, '0' }, { 'P', 'P' }, { 'M', 'M' },
|
||||
{ ')', 134 }, { '^', 133 }, { 157, 157 }, { '>', '<' }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* returns the ASCII code for the key, or 0 for no key */
|
||||
int to9_state::to9_kbd_get_key()
|
||||
{
|
||||
int control = ! (m_io_keyboard[7]->read() & 1);
|
||||
int shift = ! (m_io_keyboard[9]->read() & 1);
|
||||
int key = -1, line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
/* TODO: correct handling of simultaneous keystokes:
|
||||
return the new key preferably & disable repeat
|
||||
*/
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
key = line * 8 + bit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == -1 )
|
||||
{
|
||||
m_to9_kbd_last_key = 0xff;
|
||||
m_to9_kbd_key_count = 0;
|
||||
return 0;
|
||||
}
|
||||
else if ( key == 64 )
|
||||
{
|
||||
/* caps lock */
|
||||
if ( m_to9_kbd_last_key == key )
|
||||
return 0; /* no repeat */
|
||||
|
||||
m_to9_kbd_last_key = key;
|
||||
m_to9_kbd_caps = !m_to9_kbd_caps;
|
||||
m_caps_led = !m_to9_kbd_caps;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int asc;
|
||||
asc = to9_kbd_code[key][shift];
|
||||
if ( ! asc ) return 0;
|
||||
|
||||
/* keypad */
|
||||
if ( ! m_to9_kbd_pad ) {
|
||||
if ( asc >= 154 && asc <= 163 )
|
||||
asc += '0' - 154;
|
||||
else if ( asc == 164 )
|
||||
asc = '.';
|
||||
else if ( asc == 165 )
|
||||
asc = 13;
|
||||
}
|
||||
|
||||
/* shifted letter */
|
||||
if ( asc >= 'A' && asc <= 'Z' && ( ! m_to9_kbd_caps ) && ( ! shift ) )
|
||||
asc += 'a' - 'A';
|
||||
|
||||
/* control */
|
||||
if ( control )
|
||||
asc &= ~0x40;
|
||||
|
||||
if ( key == m_to9_kbd_last_key )
|
||||
{
|
||||
/* repeat */
|
||||
m_to9_kbd_key_count++;
|
||||
if ( m_to9_kbd_key_count < TO9_KBD_REPEAT_DELAY || (m_to9_kbd_key_count - TO9_KBD_REPEAT_DELAY) % TO9_KBD_REPEAT_PERIOD )
|
||||
return 0;
|
||||
LOGMASKED(LOG_KBD, "to9_kbd_get_key: repeat key $%02X '%c'\n", asc, asc);
|
||||
return asc;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_to9_kbd_last_key = key;
|
||||
m_to9_kbd_key_count = 0;
|
||||
LOGMASKED(LOG_KBD, "to9_kbd_get_key: key down $%02X '%c'\n", asc, asc);
|
||||
return asc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(to9_state::to9_kbd_timer_cb)
|
||||
{
|
||||
if ( m_to9_kbd_periph )
|
||||
{
|
||||
/* peripheral mode: every 10 ms we send 4 bytes */
|
||||
|
||||
switch ( m_to9_kbd_byte_count )
|
||||
{
|
||||
case 0: /* key */
|
||||
to9_kbd_send( to9_kbd_get_key(), 0 );
|
||||
break;
|
||||
|
||||
case 1: /* x axis */
|
||||
{
|
||||
int newx = m_io_mouse_x->read();
|
||||
uint8_t data = ( (newx - m_to9_mouse_x) & 0xf ) - 8;
|
||||
to9_kbd_send( data, 1 );
|
||||
m_to9_mouse_x = newx;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: /* y axis */
|
||||
{
|
||||
int newy = m_io_mouse_y->read();
|
||||
uint8_t data = ( (newy - m_to9_mouse_y) & 0xf ) - 8;
|
||||
to9_kbd_send( data, 1 );
|
||||
m_to9_mouse_y = newy;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: /* axis overflow & buttons */
|
||||
{
|
||||
int b = m_io_mouse_button->read();
|
||||
uint8_t data = 0;
|
||||
if ( b & 1 ) data |= 1;
|
||||
if ( b & 2 ) data |= 4;
|
||||
to9_kbd_send( data, 1 );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_to9_kbd_byte_count = ( m_to9_kbd_byte_count + 1 ) & 3;
|
||||
m_to9_kbd_timer->adjust(m_to9_kbd_byte_count ? TO9_KBD_BYTE_SPACE : TO9_KBD_END_SPACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int key = to9_kbd_get_key();
|
||||
/* keyboard mode: send a byte only if a key is down */
|
||||
if ( key )
|
||||
to9_kbd_send( key, 0 );
|
||||
m_to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to9_kbd_reset()
|
||||
{
|
||||
LOG("to9_kbd_reset called\n");
|
||||
m_to9_kbd_overrun = 0; /* no byte lost */
|
||||
m_to9_kbd_status = ACIA_6850_TDRE; /* clear to transmit */
|
||||
m_to9_kbd_intr = 0; /* interrupt disabled */
|
||||
m_to9_kbd_caps = 1;
|
||||
m_to9_kbd_periph = 0;
|
||||
m_to9_kbd_pad = 0;
|
||||
m_to9_kbd_byte_count = 0;
|
||||
m_caps_led = !m_to9_kbd_caps;
|
||||
m_to9_kbd_key_count = 0;
|
||||
m_to9_kbd_last_key = 0xff;
|
||||
to9_kbd_update_irq();
|
||||
m_to9_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to9_kbd_init()
|
||||
{
|
||||
LOG("to9_kbd_init called\n");
|
||||
m_to9_kbd_timer = timer_alloc(FUNC(to9_state::to9_kbd_timer_cb), this);
|
||||
save_item(NAME(m_to9_kbd_parity));
|
||||
save_item(NAME(m_to9_kbd_intr));
|
||||
save_item(NAME(m_to9_kbd_in));
|
||||
save_item(NAME(m_to9_kbd_status));
|
||||
save_item(NAME(m_to9_kbd_overrun));
|
||||
save_item(NAME(m_to9_kbd_last_key));
|
||||
save_item(NAME(m_to9_kbd_key_count));
|
||||
save_item(NAME(m_to9_kbd_caps));
|
||||
save_item(NAME(m_to9_kbd_periph));
|
||||
save_item(NAME(m_to9_kbd_pad));
|
||||
save_item(NAME(m_to9_kbd_byte_count));
|
||||
save_item(NAME(m_to9_mouse_x));
|
||||
save_item(NAME(m_to9_mouse_y));
|
||||
}
|
||||
|
||||
|
||||
/* ------------ system PIA 6821 ------------ */
|
||||
|
||||
uint8_t to9_state::to9_sys_porta_in()
|
||||
{
|
||||
uint8_t ktest = to9_kbd_ktest();
|
||||
uint8_t ktest = m_to9_kbd->ktest_r();
|
||||
|
||||
LOGMASKED(LOG_KBD, "to9_sys_porta_in: ktest=%i\n", ktest);
|
||||
|
||||
@ -2192,7 +1739,6 @@ MACHINE_RESET_MEMBER( to9_state, to9 )
|
||||
/* subsystems */
|
||||
thom_irq_reset();
|
||||
to7_game_reset();
|
||||
to9_kbd_reset();
|
||||
|
||||
m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf);
|
||||
m_extension->io_map (m_maincpu->space(AS_PROGRAM), 0xe7c0, 0xe7ff);
|
||||
@ -2229,7 +1775,6 @@ MACHINE_START_MEMBER( to9_state, to9 )
|
||||
|
||||
/* subsystems */
|
||||
to7_game_init();
|
||||
to9_kbd_init();
|
||||
to9_palette_init();
|
||||
|
||||
m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf);
|
||||
@ -2264,318 +1809,6 @@ MACHINE_START_MEMBER( to9_state, to9 )
|
||||
/***************************** TO8 *************************/
|
||||
|
||||
|
||||
/* ------------ keyboard (6804) ------------ */
|
||||
|
||||
/* The 6804 chip scans the keyboard and sends keycodes to the 6809.
|
||||
Data is serialized using variable pulse length encoding.
|
||||
Unlike the TO9, there is no decoding chip on the 6809 side, only
|
||||
1-bit PIA ports (6821 & 6846). The 6809 does the decoding.
|
||||
|
||||
We do not emulate the 6804 but pass serialized data directly through the
|
||||
PIA ports.
|
||||
|
||||
Note: if we conform to the (scarce) documentation the CPU tend to lock
|
||||
waiting for keyboard input.
|
||||
The protocol documentation is pretty scarce and does not account for these
|
||||
behaviors!
|
||||
The emulation code contains many hacks (delays, timeouts, spurious
|
||||
pulses) to improve the stability.
|
||||
This works well, but is not very accurate.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* polling interval */
|
||||
#define TO8_KBD_POLL_PERIOD attotime::from_msec( 1 )
|
||||
|
||||
/* first and subsequent repeat periods, in TO8_KBD_POLL_PERIOD units */
|
||||
#define TO8_KBD_REPEAT_DELAY 800 /* 800 ms */
|
||||
#define TO8_KBD_REPEAT_PERIOD 70 /* 70 ms */
|
||||
|
||||
/* timeout waiting for CPU */
|
||||
#define TO8_KBD_TIMEOUT attotime::from_msec( 100 )
|
||||
|
||||
|
||||
|
||||
/* quick keyboard scan */
|
||||
int to9_state::to8_kbd_ktest()
|
||||
{
|
||||
int line, bit;
|
||||
uint8_t port;
|
||||
|
||||
if ( m_io_config->read() & 2 )
|
||||
return 0; /* disabled */
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* keyboard scan & return keycode (or -1) */
|
||||
int to9_state::to8_kbd_get_key()
|
||||
{
|
||||
int control = (m_io_keyboard[7]->read() & 1) ? 0 : 0x100;
|
||||
int shift = (m_io_keyboard[9]->read() & 1) ? 0 : 0x080;
|
||||
int key = -1, line, bit;
|
||||
uint8_t port;
|
||||
|
||||
if ( m_io_config->read() & 2 )
|
||||
return -1; /* disabled */
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
/* TODO: correct handling of simultaneous keystokes:
|
||||
return the new key preferably & disable repeat
|
||||
*/
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
key = line * 8 + bit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == -1 )
|
||||
{
|
||||
m_to8_kbd_last_key = 0xff;
|
||||
m_to8_kbd_key_count = 0;
|
||||
return -1;
|
||||
}
|
||||
else if ( key == 64 )
|
||||
{
|
||||
/* caps lock */
|
||||
if ( m_to8_kbd_last_key == key )
|
||||
return -1; /* no repeat */
|
||||
m_to8_kbd_last_key = key;
|
||||
m_to8_kbd_caps = !m_to8_kbd_caps;
|
||||
if ( m_to8_kbd_caps )
|
||||
key |= 0x080; /* auto-shift */
|
||||
m_caps_led = !m_to8_kbd_caps;
|
||||
return key;
|
||||
}
|
||||
else if ( key == m_to8_kbd_last_key )
|
||||
{
|
||||
/* repeat */
|
||||
m_to8_kbd_key_count++;
|
||||
if ( m_to8_kbd_key_count < TO8_KBD_REPEAT_DELAY || (m_to8_kbd_key_count - TO8_KBD_REPEAT_DELAY) % TO8_KBD_REPEAT_PERIOD )
|
||||
return -1;
|
||||
return key | shift | control;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_to8_kbd_last_key = key;
|
||||
m_to8_kbd_key_count = 0;
|
||||
return key | shift | control;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* steps:
|
||||
0 = idle, key polling
|
||||
1 = wait for ack to go down (key to send)
|
||||
99-117 = key data transmit
|
||||
91-117 = signal
|
||||
255 = timeout
|
||||
*/
|
||||
|
||||
/* keyboard automaton */
|
||||
void to9_state::to8_kbd_timer_func()
|
||||
{
|
||||
attotime d;
|
||||
|
||||
LOGMASKED(LOG_KBD, "%f to8_kbd_timer_cb: step=%i ack=%i data=$%03X\n", machine().time().as_double(), m_to8_kbd_step, m_to8_kbd_ack, m_to8_kbd_data);
|
||||
|
||||
if( ! m_to8_kbd_step )
|
||||
{
|
||||
/* key polling */
|
||||
int k = to8_kbd_get_key();
|
||||
/* if not in transfer, send pulse from time to time
|
||||
(helps avoiding CPU lock)
|
||||
*/
|
||||
if ( ! m_to8_kbd_ack )
|
||||
m_mc6846->set_input_cp1(0);
|
||||
m_mc6846->set_input_cp1(1);
|
||||
|
||||
if ( k == -1 )
|
||||
d = TO8_KBD_POLL_PERIOD;
|
||||
else
|
||||
{
|
||||
/* got key! */
|
||||
LOGMASKED(LOG_KBD, "to8_kbd_timer_cb: got key $%03X\n", k);
|
||||
m_to8_kbd_data = k;
|
||||
m_to8_kbd_step = 1;
|
||||
d = attotime::from_usec( 100 );
|
||||
}
|
||||
}
|
||||
else if ( m_to8_kbd_step == 255 )
|
||||
{
|
||||
/* timeout */
|
||||
m_to8_kbd_last_key = 0xff;
|
||||
m_to8_kbd_key_count = 0;
|
||||
m_to8_kbd_step = 0;
|
||||
m_mc6846->set_input_cp1(1);
|
||||
d = TO8_KBD_POLL_PERIOD;
|
||||
}
|
||||
else if ( m_to8_kbd_step == 1 )
|
||||
{
|
||||
/* schedule timeout waiting for ack to go down */
|
||||
m_mc6846->set_input_cp1(0);
|
||||
m_to8_kbd_step = 255;
|
||||
d = TO8_KBD_TIMEOUT;
|
||||
}
|
||||
else if ( m_to8_kbd_step == 117 )
|
||||
{
|
||||
/* schedule timeout waiting for ack to go up */
|
||||
m_mc6846->set_input_cp1(0);
|
||||
m_to8_kbd_step = 255;
|
||||
d = TO8_KBD_TIMEOUT;
|
||||
}
|
||||
else if ( m_to8_kbd_step & 1 )
|
||||
{
|
||||
/* send silence between bits */
|
||||
m_mc6846->set_input_cp1(0);
|
||||
d = attotime::from_usec( 100 );
|
||||
m_to8_kbd_step++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send bit */
|
||||
int bpos = 8 - ( (m_to8_kbd_step - 100) / 2);
|
||||
int bit = (m_to8_kbd_data >> bpos) & 1;
|
||||
m_mc6846->set_input_cp1(1);
|
||||
d = attotime::from_usec( bit ? 56 : 38 );
|
||||
m_to8_kbd_step++;
|
||||
}
|
||||
m_to8_kbd_timer->adjust(d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(to9_state::to8_kbd_timer_cb)
|
||||
{
|
||||
to8_kbd_timer_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* cpu <-> keyboard hand-check */
|
||||
void to9_state::to8_kbd_set_ack( int data )
|
||||
{
|
||||
if ( data == m_to8_kbd_ack )
|
||||
return;
|
||||
m_to8_kbd_ack = data;
|
||||
|
||||
if ( data )
|
||||
{
|
||||
double len = m_to8_kbd_signal->elapsed( ).as_double() * 1000. - 2.;
|
||||
LOGMASKED(LOG_KBD, "%f to8_kbd_set_ack: CPU end ack, len=%f\n", machine().time().as_double(), len);
|
||||
if ( m_to8_kbd_data == 0xfff )
|
||||
{
|
||||
/* end signal from CPU */
|
||||
if ( len >= 0.6 && len <= 0.8 )
|
||||
{
|
||||
LOG("%f to8_kbd_set_ack: INIT signal\n", machine().time().as_double());
|
||||
m_to8_kbd_last_key = 0xff;
|
||||
m_to8_kbd_key_count = 0;
|
||||
m_to8_kbd_caps = 1;
|
||||
/* send back signal: TODO returned codes ? */
|
||||
m_to8_kbd_data = 0;
|
||||
m_to8_kbd_step = 0;
|
||||
m_to8_kbd_timer->adjust(attotime::from_msec( 1 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_to8_kbd_step = 0;
|
||||
m_to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
|
||||
if ( len >= 1.2 && len <= 1.4 )
|
||||
{
|
||||
LOG("%f to8_kbd_set_ack: CAPS on signal\n", machine().time().as_double());
|
||||
m_to8_kbd_caps = 1;
|
||||
}
|
||||
else if ( len >= 1.8 && len <= 2.0 )
|
||||
{
|
||||
LOG("%f to8_kbd_set_ack: CAPS off signal\n", machine().time().as_double());
|
||||
m_to8_kbd_caps = 0;
|
||||
}
|
||||
}
|
||||
m_caps_led = !m_to8_kbd_caps;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* end key transmission */
|
||||
m_to8_kbd_step = 0;
|
||||
m_to8_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( m_to8_kbd_step == 255 )
|
||||
{
|
||||
/* CPU accepts key */
|
||||
m_to8_kbd_step = 99;
|
||||
m_to8_kbd_timer->adjust(attotime::from_usec( 400 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start signal from CPU */
|
||||
m_to8_kbd_data = 0xfff;
|
||||
m_to8_kbd_step = 91;
|
||||
m_to8_kbd_timer->adjust(attotime::from_usec( 400 ));
|
||||
m_to8_kbd_signal->adjust(attotime::never);
|
||||
}
|
||||
LOGMASKED(LOG_KBD, "%f to8_kbd_set_ack: CPU ack, data=$%03X\n", machine().time().as_double(), m_to8_kbd_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to8_kbd_reset()
|
||||
{
|
||||
m_to8_kbd_last_key = 0xff;
|
||||
m_to8_kbd_key_count = 0;
|
||||
m_to8_kbd_step = 0;
|
||||
m_to8_kbd_data = 0;
|
||||
m_to8_kbd_ack = 1;
|
||||
m_to8_kbd_caps = 1;
|
||||
m_caps_led = !m_to8_kbd_caps;
|
||||
to8_kbd_timer_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_state::to8_kbd_init()
|
||||
{
|
||||
m_to8_kbd_timer = timer_alloc(FUNC(to9_state::to8_kbd_timer_cb), this);
|
||||
m_to8_kbd_signal = machine().scheduler().timer_alloc(timer_expired_delegate());
|
||||
save_item(NAME(m_to8_kbd_ack));
|
||||
save_item(NAME(m_to8_kbd_data));
|
||||
save_item(NAME(m_to8_kbd_step));
|
||||
save_item(NAME(m_to8_kbd_last_key));
|
||||
save_item(NAME(m_to8_kbd_key_count));
|
||||
save_item(NAME(m_to8_kbd_caps));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------ RAM / ROM banking ------------ */
|
||||
|
||||
void to9_state::to8_update_ram_bank()
|
||||
@ -3006,7 +2239,7 @@ void to9_state::to8_vreg_w(offs_t offset, uint8_t data)
|
||||
|
||||
uint8_t to9_state::to8_sys_porta_in()
|
||||
{
|
||||
int ktest = to8_kbd_ktest();
|
||||
int ktest = m_to8_kbd->ktest_r();
|
||||
|
||||
LOGMASKED(LOG_KBD, "$%04x %f: to8_sys_porta_in ktest=%i\n", m_maincpu->pc(), machine().time().as_double(), ktest);
|
||||
|
||||
@ -3042,7 +2275,7 @@ uint8_t to9_state::to8_timer_port_in()
|
||||
int lightpen = (m_io_lightpen_button->read() & 1) ? 2 : 0;
|
||||
int cass = to7_get_cassette() ? 0x80 : 0;
|
||||
int dtr = m_centronics_busy << 6;
|
||||
int lock = m_to8_kbd_caps ? 0 : 8; /* undocumented! */
|
||||
int lock = m_to8_kbd->caps_r() ? 0 : 8; /* undocumented! */
|
||||
return lightpen | cass | dtr | lock;
|
||||
}
|
||||
|
||||
@ -3056,7 +2289,7 @@ void to9_state::to8_timer_port_out(uint8_t data)
|
||||
m_biosbank->set_entry( m_to8_bios_bank );
|
||||
m_to8_soft_select = (data & 0x04) ? 1 : 0; /* bit 2: internal ROM select */
|
||||
to8_update_cart_bank();
|
||||
to8_kbd_set_ack(ack);
|
||||
m_to8_kbd->set_ack(ack);
|
||||
}
|
||||
|
||||
|
||||
@ -3096,7 +2329,6 @@ MACHINE_RESET_MEMBER( to9_state, to8 )
|
||||
/* subsystems */
|
||||
thom_irq_reset();
|
||||
to7_game_reset();
|
||||
to8_kbd_reset();
|
||||
|
||||
/* gate-array */
|
||||
m_to7_lightpen = 0;
|
||||
@ -3141,7 +2373,6 @@ MACHINE_START_MEMBER( to9_state, to8 )
|
||||
|
||||
/* subsystems */
|
||||
to7_game_init();
|
||||
to8_kbd_init();
|
||||
to9_palette_init();
|
||||
|
||||
m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf);
|
||||
@ -3241,7 +2472,6 @@ MACHINE_RESET_MEMBER( to9_state, to9p )
|
||||
/* subsystems */
|
||||
thom_irq_reset();
|
||||
to7_game_reset();
|
||||
to9_kbd_reset();
|
||||
|
||||
/* gate-array */
|
||||
m_to7_lightpen = 0;
|
||||
@ -3285,7 +2515,6 @@ MACHINE_START_MEMBER( to9_state, to9p )
|
||||
|
||||
/* subsystems */
|
||||
to7_game_init();
|
||||
to9_kbd_init();
|
||||
to9_palette_init();
|
||||
|
||||
m_extension->rom_map(m_maincpu->space(AS_PROGRAM), 0xe000, 0xe7bf);
|
||||
|
999
src/mame/thomson/to_kbd.cpp
Normal file
999
src/mame/thomson/to_kbd.cpp
Normal file
@ -0,0 +1,999 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Antoine Mine
|
||||
/**********************************************************************
|
||||
|
||||
Copyright (C) Antoine Mine' 2006
|
||||
|
||||
Thomson TO8 built-in keyboard & TO9 detached keyboard
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "to_kbd.h"
|
||||
|
||||
#include "cpu/m6805/m68705.h"
|
||||
|
||||
#define LOG_KBD (1U << 1)
|
||||
#define LOG_ERRORS (1U << 2)
|
||||
|
||||
#define VERBOSE (LOG_KBD | LOG_ERRORS)
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
// device type definitions
|
||||
DEFINE_DEVICE_TYPE(TO8_KEYBOARD, to8_keyboard_device, "to8_kbd", "Thomson TO8 keyboard")
|
||||
DEFINE_DEVICE_TYPE(TO9_KEYBOARD, to9_keyboard_device, "to9_kbd", "Thomson TO9 keyboard")
|
||||
DEFINE_DEVICE_TYPE(TO9P_KEYBOARD, to9p_keyboard_device, "to9p_kbd", "Thomson TO9+ keyboard")
|
||||
|
||||
to8_keyboard_device::to8_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, TO8_KEYBOARD, tag, owner, clock)
|
||||
, m_data_cb(*this)
|
||||
, m_io_keyboard(*this, "keyboard.%u", 0)
|
||||
, m_caps_led(*this, "led0")
|
||||
{
|
||||
}
|
||||
|
||||
to9_keyboard_device::to9_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, m_irq_cb(*this)
|
||||
, m_io_keyboard(*this, "keyboard.%u", 0)
|
||||
, m_io_mouse_x(*this, "mouse_x")
|
||||
, m_io_mouse_y(*this, "mouse_y")
|
||||
, m_io_mouse_button(*this, "mouse_button")
|
||||
, m_caps_led(*this, "led0")
|
||||
{
|
||||
}
|
||||
|
||||
to9_keyboard_device::to9_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: to9_keyboard_device(mconfig, TO9_KEYBOARD, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
to9p_keyboard_device::to9p_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: to9_keyboard_device(mconfig, TO9P_KEYBOARD, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void to8_keyboard_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
//MC6804P2(config, "mcu", 11_MHz_XTAL).set_disable();
|
||||
}
|
||||
|
||||
void to9_keyboard_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
M6805U2(config, "mcu", 4_MHz_XTAL).set_disable(); // 40 pins, actual model unknown
|
||||
}
|
||||
|
||||
void to9p_keyboard_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
M6805P2(config, "mcu", 4_MHz_XTAL).set_disable();
|
||||
}
|
||||
|
||||
ROM_START(to8_kbd)
|
||||
ROM_REGION(0x440, "mcu", 0)
|
||||
ROM_LOAD("ef6804p2p_clav--to8.bin", 0x000, 0x440, NO_DUMP)
|
||||
ROM_END
|
||||
|
||||
ROM_START(to9_kbd)
|
||||
ROM_REGION(0x1000, "mcu", 0)
|
||||
ROM_LOAD("6805.bin", 0x0000, 0x1000, NO_DUMP)
|
||||
ROM_END
|
||||
|
||||
ROM_START(to9p_kbd)
|
||||
ROM_REGION(0x800, "mcu", 0)
|
||||
ROM_LOAD("6805p2.bin", 0x000, 0x800, NO_DUMP)
|
||||
ROM_END
|
||||
|
||||
const tiny_rom_entry *to8_keyboard_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(to8_kbd);
|
||||
}
|
||||
|
||||
const tiny_rom_entry *to9_keyboard_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(to9_kbd);
|
||||
}
|
||||
|
||||
const tiny_rom_entry *to9p_keyboard_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME(to9p_kbd);
|
||||
}
|
||||
|
||||
|
||||
/* ------------ inputs ------------ */
|
||||
|
||||
#define KEY(pos,name,key) \
|
||||
PORT_BIT ( 1<<(pos), IP_ACTIVE_LOW, IPT_KEYBOARD ) \
|
||||
PORT_NAME ( name ) \
|
||||
PORT_CODE ( KEYCODE_##key )
|
||||
|
||||
static INPUT_PORTS_START ( to8_keyboard )
|
||||
PORT_START ( "keyboard.0" )
|
||||
KEY ( 0, "F2 F7", F2 ) PORT_CHAR(UCHAR_MAMEKEY(F2)) PORT_CHAR(UCHAR_MAMEKEY(F7))
|
||||
KEY ( 1, "_ 6", 6 ) PORT_CHAR('_') PORT_CHAR('6')
|
||||
KEY ( 2, "Y", Y ) PORT_CHAR('Y')
|
||||
KEY ( 3, "H", H ) PORT_CHAR('H')
|
||||
KEY ( 4, u8"\u2191", UP ) PORT_CHAR(UCHAR_MAMEKEY(UP))
|
||||
KEY ( 5, u8"\u2192", RIGHT ) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
|
||||
KEY ( 6, "Home Clear", HOME ) PORT_CHAR(UCHAR_MAMEKEY(HOME)) PORT_CHAR(UCHAR_MAMEKEY(ESC))
|
||||
KEY ( 7, "N", N ) PORT_CHAR('N')
|
||||
PORT_START ( "keyboard.1" )
|
||||
KEY ( 0, "F3 F8", F3 ) PORT_CHAR(UCHAR_MAMEKEY(F3)) PORT_CHAR(UCHAR_MAMEKEY(F8))
|
||||
KEY ( 1, "( 5", 5 ) PORT_CHAR('(') PORT_CHAR('5')
|
||||
KEY ( 2, "T", T ) PORT_CHAR('T')
|
||||
KEY ( 3, "G", G ) PORT_CHAR('G')
|
||||
KEY ( 4, "= +", EQUALS ) PORT_CHAR('=') PORT_CHAR('+')
|
||||
KEY ( 5, "\u2190", LEFT ) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
|
||||
KEY ( 6, "Insert", INSERT ) PORT_CHAR(UCHAR_MAMEKEY(INSERT))
|
||||
KEY ( 7, "B", B ) PORT_CHAR('B')
|
||||
PORT_START ( "keyboard.2" )
|
||||
KEY ( 0, "F4 F9", F4 ) PORT_CHAR(UCHAR_MAMEKEY(F4)) PORT_CHAR(UCHAR_MAMEKEY(F9))
|
||||
KEY ( 1, "' 4", 4 ) PORT_CHAR('\'') PORT_CHAR('4')
|
||||
KEY ( 2, "R", R ) PORT_CHAR('R')
|
||||
KEY ( 3, "F", F ) PORT_CHAR('F')
|
||||
KEY ( 4, "Accent", END ) PORT_CHAR(UCHAR_MAMEKEY(END))
|
||||
KEY ( 5, "Keypad 1", 1_PAD ) PORT_CHAR(UCHAR_MAMEKEY(1_PAD))
|
||||
KEY ( 6, "Delete Backspace", DEL ) PORT_CHAR(8) PORT_CHAR(UCHAR_MAMEKEY(BACKSPACE))
|
||||
KEY ( 7, "V", V ) PORT_CHAR('V')
|
||||
PORT_START ( "keyboard.3" )
|
||||
KEY ( 0, "F5 F10", F5 ) PORT_CHAR(UCHAR_MAMEKEY(F5)) PORT_CHAR(UCHAR_MAMEKEY(F10))
|
||||
KEY ( 1, "\" 3", 3 ) PORT_CHAR('"') PORT_CHAR('3')
|
||||
KEY ( 2, "E", E ) PORT_CHAR('E')
|
||||
KEY ( 3, "D", D ) PORT_CHAR('D')
|
||||
KEY ( 4, "Keypad 7", 7_PAD ) PORT_CHAR(UCHAR_MAMEKEY(7_PAD))
|
||||
KEY ( 5, "Keypad 4", 4_PAD ) PORT_CHAR(UCHAR_MAMEKEY(4_PAD))
|
||||
KEY ( 6, "Keypad 0", 0_PAD ) PORT_CHAR(UCHAR_MAMEKEY(0_PAD))
|
||||
KEY ( 7, "C \136", C ) PORT_CHAR('C')
|
||||
PORT_START ( "keyboard.4" )
|
||||
KEY ( 0, "F1 F6", F1 ) PORT_CHAR(UCHAR_MAMEKEY(F1)) PORT_CHAR(UCHAR_MAMEKEY(F6))
|
||||
KEY ( 1, u8"é 2", 2 ) PORT_CHAR( 0xe9 ) PORT_CHAR('2')
|
||||
KEY ( 2, "Z", Z ) PORT_CHAR('Z')
|
||||
KEY ( 3, "S", S ) PORT_CHAR('S')
|
||||
KEY ( 4, "Keypad 8", 8_PAD ) PORT_CHAR(UCHAR_MAMEKEY(8_PAD))
|
||||
KEY ( 5, "Keypad 2", 2_PAD ) PORT_CHAR(UCHAR_MAMEKEY(2_PAD))
|
||||
KEY ( 6, "Keypad .", DEL_PAD ) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD))
|
||||
KEY ( 7, "X", X ) PORT_CHAR('X')
|
||||
PORT_START ( "keyboard.5" )
|
||||
KEY ( 0, "# @", TILDE ) PORT_CHAR('#') PORT_CHAR('@')
|
||||
KEY ( 1, "* 1", 1 ) PORT_CHAR('*') PORT_CHAR('1')
|
||||
KEY ( 2, "A \140", A ) PORT_CHAR('A')
|
||||
KEY ( 3, "Q", Q ) PORT_CHAR('Q')
|
||||
KEY ( 4, "[ {", QUOTE ) PORT_CHAR('[') PORT_CHAR('{')
|
||||
KEY ( 5, "Keypad 5", 5_PAD ) PORT_CHAR(UCHAR_MAMEKEY(5_PAD))
|
||||
KEY ( 6, "Keypad 6", 6_PAD ) PORT_CHAR(UCHAR_MAMEKEY(6_PAD))
|
||||
KEY ( 7, "W", W ) PORT_CHAR('W')
|
||||
PORT_START ( "keyboard.6" )
|
||||
KEY ( 0, "Stop", TAB ) PORT_CHAR(27)
|
||||
KEY ( 1, u8"è 7", 7 ) PORT_CHAR( 0xe8 ) PORT_CHAR('7')
|
||||
KEY ( 2, "U", U ) PORT_CHAR('U')
|
||||
KEY ( 3, "J", J ) PORT_CHAR('J')
|
||||
KEY ( 4, "Space", SPACE ) PORT_CHAR(' ')
|
||||
KEY ( 5, "Keypad 9", 9_PAD ) PORT_CHAR(UCHAR_MAMEKEY(9_PAD))
|
||||
KEY ( 6, "Keypad Enter", ENTER_PAD ) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
|
||||
KEY ( 7, ", ?", COMMA ) PORT_CHAR(',') PORT_CHAR('?')
|
||||
PORT_START ( "keyboard.7" )
|
||||
KEY ( 0, "Control", LCONTROL ) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL))
|
||||
KEY ( 1, "! 8", 8 ) PORT_CHAR('!') PORT_CHAR('8')
|
||||
KEY ( 2, "I", I ) PORT_CHAR('I')
|
||||
KEY ( 3, "K", K ) PORT_CHAR('K')
|
||||
KEY ( 4, "$ &", CLOSEBRACE ) PORT_CHAR('$') PORT_CHAR('&')
|
||||
KEY ( 5, u8"\u2193", DOWN ) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
|
||||
KEY ( 6, "] }", BACKSLASH ) PORT_CHAR(']') PORT_CHAR('}')
|
||||
KEY ( 7, "; .", STOP ) PORT_CHAR(';') PORT_CHAR('.')
|
||||
PORT_START ( "keyboard.8" )
|
||||
KEY ( 0, "Caps-Lock", CAPSLOCK ) PORT_CHAR(UCHAR_MAMEKEY(CAPSLOCK))
|
||||
KEY ( 1, u8"ç 9", 9 ) PORT_CHAR( 0xe7 ) PORT_CHAR('9')
|
||||
KEY ( 2, "O", O ) PORT_CHAR('O')
|
||||
KEY ( 3, "L", L ) PORT_CHAR('L')
|
||||
KEY ( 4, "- \\", BACKSPACE ) PORT_CHAR('-') PORT_CHAR('\\')
|
||||
KEY ( 5, u8"ù %", COLON ) PORT_CHAR( 0xf9 ) PORT_CHAR('%')
|
||||
KEY ( 6, "Enter", ENTER ) PORT_CHAR(13)
|
||||
KEY ( 7, ": /", SLASH ) PORT_CHAR(':') PORT_CHAR('/')
|
||||
PORT_START ( "keyboard.9" )
|
||||
KEY ( 0, "Shift", LSHIFT ) PORT_CODE ( KEYCODE_RSHIFT ) PORT_CHAR(UCHAR_SHIFT_1)
|
||||
KEY ( 1, u8"à 0", 0 ) PORT_CHAR( 0xe0 ) PORT_CHAR('0')
|
||||
KEY ( 2, "P", P ) PORT_CHAR('P')
|
||||
KEY ( 3, "M", M ) PORT_CHAR('M')
|
||||
KEY ( 4, u8") °", MINUS ) PORT_CHAR(')') PORT_CHAR( 0xb0 )
|
||||
KEY ( 5, u8"^ ¨", OPENBRACE ) PORT_CHAR('^') PORT_CHAR( 0xa8 )
|
||||
KEY ( 6, "Keypad 3", 3_PAD ) PORT_CHAR(UCHAR_MAMEKEY(3_PAD))
|
||||
KEY ( 7, "> <", BACKSLASH2 ) PORT_CHAR('>') PORT_CHAR('<')
|
||||
INPUT_PORTS_END
|
||||
|
||||
static INPUT_PORTS_START ( to9_keyboard )
|
||||
PORT_INCLUDE( to8_keyboard )
|
||||
|
||||
PORT_START ( "mouse_x" )
|
||||
PORT_BIT ( 0xffff, 0x00, IPT_MOUSE_X )
|
||||
PORT_NAME ( "Mouse X" )
|
||||
PORT_SENSITIVITY ( 150 )
|
||||
PORT_PLAYER (1)
|
||||
|
||||
PORT_START ( "mouse_y" )
|
||||
PORT_BIT ( 0xffff, 0x00, IPT_MOUSE_Y )
|
||||
PORT_NAME ( "Mouse Y" )
|
||||
PORT_SENSITIVITY ( 150 )
|
||||
PORT_PLAYER (1)
|
||||
|
||||
PORT_START ( "mouse_button" )
|
||||
PORT_BIT ( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
|
||||
PORT_NAME ( "Left Mouse Button" )
|
||||
PORT_CODE( MOUSECODE_BUTTON1 )
|
||||
PORT_BIT ( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
|
||||
PORT_NAME ( "Right Mouse Button" )
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor to8_keyboard_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(to8_keyboard);
|
||||
}
|
||||
|
||||
ioport_constructor to9_keyboard_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(to9_keyboard);
|
||||
}
|
||||
|
||||
ioport_constructor to9p_keyboard_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(to8_keyboard);
|
||||
}
|
||||
|
||||
|
||||
/* ------------ keyboard (6804) ------------ */
|
||||
|
||||
/* The 6804 chip scans the keyboard and sends keycodes to the 6809.
|
||||
Data is serialized using variable pulse length encoding.
|
||||
Unlike the TO9, there is no decoding chip on the 6809 side, only
|
||||
1-bit PIA ports (6821 & 6846). The 6809 does the decoding.
|
||||
|
||||
We do not emulate the 6804 but pass serialized data directly through the
|
||||
PIA ports.
|
||||
|
||||
Note: if we conform to the (scarce) documentation the CPU tend to lock
|
||||
waiting for keyboard input.
|
||||
The protocol documentation is pretty scarce and does not account for these
|
||||
behaviors!
|
||||
The emulation code contains many hacks (delays, timeouts, spurious
|
||||
pulses) to improve the stability.
|
||||
This works well, but is not very accurate.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* polling interval */
|
||||
#define TO8_KBD_POLL_PERIOD attotime::from_msec( 1 )
|
||||
|
||||
/* first and subsequent repeat periods, in TO8_KBD_POLL_PERIOD units */
|
||||
#define TO8_KBD_REPEAT_DELAY 800 /* 800 ms */
|
||||
#define TO8_KBD_REPEAT_PERIOD 70 /* 70 ms */
|
||||
|
||||
/* timeout waiting for CPU */
|
||||
#define TO8_KBD_TIMEOUT attotime::from_msec( 100 )
|
||||
|
||||
|
||||
|
||||
/* quick keyboard scan */
|
||||
int to8_keyboard_device::ktest_r()
|
||||
{
|
||||
int line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* keyboard scan & return keycode (or -1) */
|
||||
int to8_keyboard_device::get_key()
|
||||
{
|
||||
int control = (m_io_keyboard[7]->read() & 1) ? 0 : 0x100;
|
||||
int shift = (m_io_keyboard[9]->read() & 1) ? 0 : 0x080;
|
||||
int key = -1, line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
/* TODO: correct handling of simultaneous keystokes:
|
||||
return the new key preferably & disable repeat
|
||||
*/
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
key = line * 8 + bit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == -1 )
|
||||
{
|
||||
m_kbd_last_key = 0xff;
|
||||
m_kbd_key_count = 0;
|
||||
return -1;
|
||||
}
|
||||
else if ( key == 64 )
|
||||
{
|
||||
/* caps lock */
|
||||
if ( m_kbd_last_key == key )
|
||||
return -1; /* no repeat */
|
||||
m_kbd_last_key = key;
|
||||
m_kbd_caps = !m_kbd_caps;
|
||||
if ( m_kbd_caps )
|
||||
key |= 0x080; /* auto-shift */
|
||||
m_caps_led = !m_kbd_caps;
|
||||
return key;
|
||||
}
|
||||
else if ( key == m_kbd_last_key )
|
||||
{
|
||||
/* repeat */
|
||||
m_kbd_key_count++;
|
||||
if ( m_kbd_key_count < TO8_KBD_REPEAT_DELAY || (m_kbd_key_count - TO8_KBD_REPEAT_DELAY) % TO8_KBD_REPEAT_PERIOD )
|
||||
return -1;
|
||||
return key | shift | control;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kbd_last_key = key;
|
||||
m_kbd_key_count = 0;
|
||||
return key | shift | control;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* steps:
|
||||
0 = idle, key polling
|
||||
1 = wait for ack to go down (key to send)
|
||||
99-117 = key data transmit
|
||||
91-117 = signal
|
||||
255 = timeout
|
||||
*/
|
||||
|
||||
/* keyboard automaton */
|
||||
void to8_keyboard_device::timer_func()
|
||||
{
|
||||
attotime d;
|
||||
|
||||
LOGMASKED(LOG_KBD, "%f timer_func: step=%i ack=%i data=$%03X\n", machine().time().as_double(), m_kbd_step, m_kbd_ack, m_kbd_data);
|
||||
|
||||
if( ! m_kbd_step )
|
||||
{
|
||||
/* key polling */
|
||||
int k = get_key();
|
||||
/* if not in transfer, send pulse from time to time
|
||||
(helps avoiding CPU lock)
|
||||
*/
|
||||
if ( ! m_kbd_ack )
|
||||
m_data_cb(0);
|
||||
m_data_cb(1);
|
||||
|
||||
if ( k == -1 )
|
||||
d = TO8_KBD_POLL_PERIOD;
|
||||
else
|
||||
{
|
||||
/* got key! */
|
||||
LOGMASKED(LOG_KBD, "timer_func: got key $%03X\n", k);
|
||||
m_kbd_data = k;
|
||||
m_kbd_step = 1;
|
||||
d = attotime::from_usec( 100 );
|
||||
}
|
||||
}
|
||||
else if ( m_kbd_step == 255 )
|
||||
{
|
||||
/* timeout */
|
||||
m_kbd_last_key = 0xff;
|
||||
m_kbd_key_count = 0;
|
||||
m_kbd_step = 0;
|
||||
m_data_cb(1);
|
||||
d = TO8_KBD_POLL_PERIOD;
|
||||
}
|
||||
else if ( m_kbd_step == 1 )
|
||||
{
|
||||
/* schedule timeout waiting for ack to go down */
|
||||
m_data_cb(0);
|
||||
m_kbd_step = 255;
|
||||
d = TO8_KBD_TIMEOUT;
|
||||
}
|
||||
else if ( m_kbd_step == 117 )
|
||||
{
|
||||
/* schedule timeout waiting for ack to go up */
|
||||
m_data_cb(0);
|
||||
m_kbd_step = 255;
|
||||
d = TO8_KBD_TIMEOUT;
|
||||
}
|
||||
else if ( m_kbd_step & 1 )
|
||||
{
|
||||
/* send silence between bits */
|
||||
m_data_cb(0);
|
||||
d = attotime::from_usec( 100 );
|
||||
m_kbd_step++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* send bit */
|
||||
int bpos = 8 - ( (m_kbd_step - 100) / 2);
|
||||
int bit = (m_kbd_data >> bpos) & 1;
|
||||
m_data_cb(1);
|
||||
d = attotime::from_usec( bit ? 56 : 38 );
|
||||
m_kbd_step++;
|
||||
}
|
||||
m_kbd_timer->adjust(d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(to8_keyboard_device::timer_cb)
|
||||
{
|
||||
timer_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* cpu <-> keyboard hand-check */
|
||||
void to8_keyboard_device::set_ack( int data )
|
||||
{
|
||||
if ( data == m_kbd_ack )
|
||||
return;
|
||||
m_kbd_ack = data;
|
||||
|
||||
if ( data )
|
||||
{
|
||||
double len = m_kbd_signal->elapsed( ).as_double() * 1000. - 2.;
|
||||
LOGMASKED(LOG_KBD, "%f set_ack: CPU end ack, len=%f\n", machine().time().as_double(), len);
|
||||
if ( m_kbd_data == 0xfff )
|
||||
{
|
||||
/* end signal from CPU */
|
||||
if ( len >= 0.6 && len <= 0.8 )
|
||||
{
|
||||
LOG("%f set_ack: INIT signal\n", machine().time().as_double());
|
||||
m_kbd_last_key = 0xff;
|
||||
m_kbd_key_count = 0;
|
||||
m_kbd_caps = 1;
|
||||
/* send back signal: TODO returned codes ? */
|
||||
m_kbd_data = 0;
|
||||
m_kbd_step = 0;
|
||||
m_kbd_timer->adjust(attotime::from_msec( 1 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kbd_step = 0;
|
||||
m_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
|
||||
if ( len >= 1.2 && len <= 1.4 )
|
||||
{
|
||||
LOG("%f set_ack: CAPS on signal\n", machine().time().as_double());
|
||||
m_kbd_caps = 1;
|
||||
}
|
||||
else if ( len >= 1.8 && len <= 2.0 )
|
||||
{
|
||||
LOG("%f set_ack: CAPS off signal\n", machine().time().as_double());
|
||||
m_kbd_caps = 0;
|
||||
}
|
||||
}
|
||||
m_caps_led = !m_kbd_caps;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* end key transmission */
|
||||
m_kbd_step = 0;
|
||||
m_kbd_timer->adjust(TO8_KBD_POLL_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( m_kbd_step == 255 )
|
||||
{
|
||||
/* CPU accepts key */
|
||||
m_kbd_step = 99;
|
||||
m_kbd_timer->adjust(attotime::from_usec( 400 ));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* start signal from CPU */
|
||||
m_kbd_data = 0xfff;
|
||||
m_kbd_step = 91;
|
||||
m_kbd_timer->adjust(attotime::from_usec( 400 ));
|
||||
m_kbd_signal->adjust(attotime::never);
|
||||
}
|
||||
LOGMASKED(LOG_KBD, "%f set_ack: CPU ack, data=$%03X\n", machine().time().as_double(), m_kbd_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to8_keyboard_device::device_reset()
|
||||
{
|
||||
m_kbd_last_key = 0xff;
|
||||
m_kbd_key_count = 0;
|
||||
m_kbd_step = 0;
|
||||
m_kbd_data = 0;
|
||||
m_kbd_ack = 1;
|
||||
m_kbd_caps = 1;
|
||||
m_caps_led = !m_kbd_caps;
|
||||
timer_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to8_keyboard_device::device_start()
|
||||
{
|
||||
m_caps_led.resolve();
|
||||
|
||||
m_kbd_timer = timer_alloc(FUNC(to8_keyboard_device::timer_cb), this);
|
||||
m_kbd_signal = machine().scheduler().timer_alloc(timer_expired_delegate());
|
||||
save_item(NAME(m_kbd_ack));
|
||||
save_item(NAME(m_kbd_data));
|
||||
save_item(NAME(m_kbd_step));
|
||||
save_item(NAME(m_kbd_last_key));
|
||||
save_item(NAME(m_kbd_key_count));
|
||||
save_item(NAME(m_kbd_caps));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------ 6850 defines ------------ */
|
||||
|
||||
#define ACIA_6850_RDRF 0x01 /* Receive data register full */
|
||||
#define ACIA_6850_TDRE 0x02 /* Transmit data register empty */
|
||||
#define ACIA_6850_dcd 0x04 /* Data carrier detect, active low */
|
||||
#define ACIA_6850_cts 0x08 /* Clear to send, active low */
|
||||
#define ACIA_6850_FE 0x10 /* Framing error */
|
||||
#define ACIA_6850_OVRN 0x20 /* Receiver overrun */
|
||||
#define ACIA_6850_PE 0x40 /* Parity error */
|
||||
#define ACIA_6850_irq 0x80 /* Interrupt request, active low */
|
||||
|
||||
|
||||
|
||||
/* ------------ keyboard (6850 ACIA + 6805 CPU) ------------ */
|
||||
|
||||
/* The 6805 chip scans the keyboard and sends ASCII codes to the 6909.
|
||||
Data between the 6809 and 6805 is serialized at 9600 bauds.
|
||||
On the 6809 side, a 6850 ACIA is used.
|
||||
We do not emulate the seral line but pass bytes directly between the
|
||||
keyboard and the 6850 registers.
|
||||
Note that the keyboard protocol uses the parity bit as an extra data bit.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* normal mode: polling interval */
|
||||
#define TO9_KBD_POLL_PERIOD attotime::from_msec( 10 )
|
||||
|
||||
/* peripheral mode: time between two bytes, and after last byte */
|
||||
#define TO9_KBD_BYTE_SPACE attotime::from_usec( 300 )
|
||||
#define TO9_KBD_END_SPACE attotime::from_usec( 9100 )
|
||||
|
||||
/* first and subsequent repeat periods, in TO9_KBD_POLL_PERIOD units */
|
||||
#define TO9_KBD_REPEAT_DELAY 80 /* 800 ms */
|
||||
#define TO9_KBD_REPEAT_PERIOD 7 /* 70 ms */
|
||||
|
||||
|
||||
|
||||
/* quick keyboard scan */
|
||||
int to9_keyboard_device::ktest_r()
|
||||
{
|
||||
int line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_keyboard_device::update_irq()
|
||||
{
|
||||
if ( (m_kbd_intr & 4) && (m_kbd_status & ACIA_6850_RDRF) )
|
||||
m_kbd_status |= ACIA_6850_irq; /* byte received interrupt */
|
||||
|
||||
if ( (m_kbd_intr & 4) && (m_kbd_status & ACIA_6850_OVRN) )
|
||||
m_kbd_status |= ACIA_6850_irq; /* overrun interrupt */
|
||||
|
||||
if ( (m_kbd_intr & 3) == 1 && (m_kbd_status & ACIA_6850_TDRE) )
|
||||
m_kbd_status |= ACIA_6850_irq; /* ready to transmit interrupt */
|
||||
|
||||
m_irq_cb( (m_kbd_status & ACIA_6850_irq) ? 1 : 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t to9_keyboard_device::kbd_acia_r(offs_t offset)
|
||||
{
|
||||
/* ACIA 6850 registers */
|
||||
|
||||
switch ( offset )
|
||||
{
|
||||
case 0: /* get status */
|
||||
/* bit 0: data received */
|
||||
/* bit 1: ready to transmit data (always 1) */
|
||||
/* bit 2: data carrier detect (ignored) */
|
||||
/* bit 3: clear to send (ignored) */
|
||||
/* bit 4: framing error (ignored) */
|
||||
/* bit 5: overrun */
|
||||
/* bit 6: parity error */
|
||||
/* bit 7: interrupt */
|
||||
|
||||
LOG("%s %f kbd_acia_r: status $%02X (rdrf=%i, tdre=%i, ovrn=%i, pe=%i, irq=%i)\n",
|
||||
machine().describe_context(), machine().time().as_double(), m_kbd_status,
|
||||
(m_kbd_status & ACIA_6850_RDRF) ? 1 : 0,
|
||||
(m_kbd_status & ACIA_6850_TDRE) ? 1 : 0,
|
||||
(m_kbd_status & ACIA_6850_OVRN) ? 1 : 0,
|
||||
(m_kbd_status & ACIA_6850_PE) ? 1 : 0,
|
||||
(m_kbd_status & ACIA_6850_irq) ? 1 : 0 );
|
||||
return m_kbd_status;
|
||||
|
||||
case 1: /* get input data */
|
||||
if ( !machine().side_effects_disabled() )
|
||||
{
|
||||
m_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_PE);
|
||||
if ( m_kbd_overrun )
|
||||
m_kbd_status |= ACIA_6850_OVRN;
|
||||
else
|
||||
m_kbd_status &= ~(ACIA_6850_OVRN | ACIA_6850_RDRF);
|
||||
m_kbd_overrun = 0;
|
||||
LOGMASKED(LOG_KBD, "%s %f kbd_acia_r: read data $%02X\n", machine().describe_context(), machine().time().as_double(), m_kbd_in);
|
||||
update_irq();
|
||||
}
|
||||
return m_kbd_in;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "%s kbd_acia_r: invalid offset %i\n", machine().describe_context(), offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_keyboard_device::kbd_acia_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
/* ACIA 6850 registers */
|
||||
|
||||
switch ( offset )
|
||||
{
|
||||
case 0: /* set control */
|
||||
/* bits 0-1: clock divide (ignored) or reset */
|
||||
if ( (data & 3) == 3 )
|
||||
{
|
||||
/* reset */
|
||||
m_kbd_overrun = 0;
|
||||
m_kbd_status = ACIA_6850_TDRE;
|
||||
m_kbd_intr = 0;
|
||||
LOGMASKED(LOG_KBD, "%s %f kbd_acia_w: reset (data=$%02X)\n", machine().describe_context(), machine().time().as_double(), data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* bits 2-4: parity */
|
||||
if ( (data & 0x18) == 0x10 )
|
||||
m_kbd_parity = 2;
|
||||
else
|
||||
m_kbd_parity = (data >> 2) & 1;
|
||||
/* bits 5-6: interrupt on transmit */
|
||||
/* bit 7: interrupt on receive */
|
||||
m_kbd_intr = data >> 5;
|
||||
|
||||
LOGMASKED(LOG_KBD, "%s %f kbd_acia_w: set control to $%02X (parity=%i, intr in=%i out=%i)\n",
|
||||
machine().describe_context(), machine().time().as_double(),
|
||||
data, m_kbd_parity, m_kbd_intr >> 2,
|
||||
(m_kbd_intr & 3) ? 1 : 0);
|
||||
}
|
||||
update_irq();
|
||||
break;
|
||||
|
||||
case 1: /* output data */
|
||||
m_kbd_status &= ~(ACIA_6850_irq | ACIA_6850_TDRE);
|
||||
update_irq();
|
||||
/* TODO: 1 ms delay here ? */
|
||||
m_kbd_status |= ACIA_6850_TDRE; /* data transmit ready again */
|
||||
update_irq();
|
||||
|
||||
switch ( data )
|
||||
{
|
||||
case 0xF8:
|
||||
/* reset */
|
||||
m_kbd_caps = 1;
|
||||
m_kbd_periph = 0;
|
||||
m_kbd_pad = 0;
|
||||
break;
|
||||
|
||||
case 0xF9: m_kbd_caps = 1; break;
|
||||
case 0xFA: m_kbd_caps = 0; break;
|
||||
case 0xFB: m_kbd_pad = 1; break;
|
||||
case 0xFC: m_kbd_pad = 0; break;
|
||||
case 0xFD: m_kbd_periph = 1; break;
|
||||
case 0xFE: m_kbd_periph = 0; break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "%s %f kbd_acia_w: unknown kbd command %02X\n", machine().describe_context(), machine().time().as_double(), data);
|
||||
}
|
||||
|
||||
m_caps_led = !m_kbd_caps;
|
||||
|
||||
LOG("%s %f kbd_acia_w: kbd command %02X (caps=%i, pad=%i, periph=%i)\n",
|
||||
machine().describe_context(), machine().time().as_double(), data,
|
||||
m_kbd_caps, m_kbd_pad, m_kbd_periph);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_ERRORS, "%s kbd_acia_w: invalid offset %i (data=$%02X) \n", machine().describe_context(), offset, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* send a key to the CPU, 8-bit + parity bit (0=even, 1=odd)
|
||||
note: parity is not used as a checksum but to actually transmit a 9-th bit
|
||||
of information!
|
||||
*/
|
||||
void to9_keyboard_device::send( uint8_t data, int parity )
|
||||
{
|
||||
if ( m_kbd_status & ACIA_6850_RDRF )
|
||||
{
|
||||
/* overrun will be set when the current valid byte is read */
|
||||
m_kbd_overrun = 1;
|
||||
LOGMASKED(LOG_KBD, "%f send: overrun => drop data=$%02X, parity=%i\n", machine().time().as_double(), data, parity);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* valid byte */
|
||||
m_kbd_in = data;
|
||||
m_kbd_status |= ACIA_6850_RDRF; /* raise data received flag */
|
||||
if ( m_kbd_parity == 2 || m_kbd_parity == parity )
|
||||
m_kbd_status &= ~ACIA_6850_PE; /* parity OK */
|
||||
else
|
||||
m_kbd_status |= ACIA_6850_PE; /* parity error */
|
||||
LOGMASKED(LOG_KBD, "%f send: data=$%02X, parity=%i, status=$%02X\n", machine().time().as_double(), data, parity, m_kbd_status);
|
||||
}
|
||||
update_irq();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* keycode => TO9 code (extended ASCII), shifted and un-shifted */
|
||||
static const int to9_kbd_code[80][2] =
|
||||
{
|
||||
{ 145, 150 }, { '_', '6' }, { 'Y', 'Y' }, { 'H', 'H' },
|
||||
{ 11, 11 }, { 9, 9 }, { 30, 12 }, { 'N', 'N' },
|
||||
|
||||
{ 146, 151 }, { '(', '5' }, { 'T', 'T' }, { 'G', 'G' },
|
||||
{ '=', '+' }, { 8, 8 }, { 28, 28 }, { 'B', 'B' },
|
||||
|
||||
{ 147, 152 }, { '\'', '4' }, { 'R', 'R' }, { 'F', 'F' },
|
||||
{ 22, 22 }, { 155, 155 }, { 29, 127 }, { 'V', 'V' },
|
||||
|
||||
{ 148, 153 }, { '"', '3' }, { 'E', 'E' }, { 'D', 'D' },
|
||||
{ 161, 161 }, { 158, 158 },
|
||||
{ 154, 154 }, { 'C', 'C' },
|
||||
|
||||
{ 144, 149 }, { 128, '2' }, { 'Z', 'Z' }, { 'S', 'S' },
|
||||
{ 162, 162 }, { 156, 156 },
|
||||
{ 164, 164 }, { 'X', 'X' },
|
||||
|
||||
{ '#', '@' }, { '*', '1' }, { 'A', 'A' }, { 'Q', 'Q' },
|
||||
{ '[', '{' }, { 159, 159 }, { 160, 160 }, { 'W', 'W' },
|
||||
|
||||
{ 2, 2 }, { 129, '7' }, { 'U', 'U' }, { 'J', 'J' },
|
||||
{ ' ', ' ' }, { 163, 163 }, { 165, 165 },
|
||||
{ ',', '?' },
|
||||
|
||||
{ 0, 0 }, { '!', '8' }, { 'I', 'I' }, { 'K', 'K' },
|
||||
{ '$', '&' }, { 10, 10 }, { ']', '}' }, { ';', '.' },
|
||||
|
||||
{ 0, 0 }, { 130, '9' }, { 'O', 'O' }, { 'L', 'L' },
|
||||
{ '-', '\\' }, { 132, '%' }, { 13, 13 }, { ':', '/' },
|
||||
|
||||
{ 0, 0 }, { 131, '0' }, { 'P', 'P' }, { 'M', 'M' },
|
||||
{ ')', 134 }, { '^', 133 }, { 157, 157 }, { '>', '<' }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* returns the ASCII code for the key, or 0 for no key */
|
||||
int to9_keyboard_device::get_key()
|
||||
{
|
||||
int control = ! (m_io_keyboard[7]->read() & 1);
|
||||
int shift = ! (m_io_keyboard[9]->read() & 1);
|
||||
int key = -1, line, bit;
|
||||
uint8_t port;
|
||||
|
||||
for ( line = 0; line < 10; line++ )
|
||||
{
|
||||
port = m_io_keyboard[line]->read();
|
||||
|
||||
if ( line == 7 || line == 9 )
|
||||
port |= 1; /* shift & control */
|
||||
|
||||
/* TODO: correct handling of simultaneous keystokes:
|
||||
return the new key preferably & disable repeat
|
||||
*/
|
||||
for ( bit = 0; bit < 8; bit++ )
|
||||
{
|
||||
if ( ! (port & (1 << bit)) )
|
||||
key = line * 8 + bit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( key == -1 )
|
||||
{
|
||||
m_kbd_last_key = 0xff;
|
||||
m_kbd_key_count = 0;
|
||||
return 0;
|
||||
}
|
||||
else if ( key == 64 )
|
||||
{
|
||||
/* caps lock */
|
||||
if ( m_kbd_last_key == key )
|
||||
return 0; /* no repeat */
|
||||
|
||||
m_kbd_last_key = key;
|
||||
m_kbd_caps = !m_kbd_caps;
|
||||
m_caps_led = !m_kbd_caps;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int asc;
|
||||
asc = to9_kbd_code[key][shift];
|
||||
if ( ! asc ) return 0;
|
||||
|
||||
/* keypad */
|
||||
if ( ! m_kbd_pad ) {
|
||||
if ( asc >= 154 && asc <= 163 )
|
||||
asc += '0' - 154;
|
||||
else if ( asc == 164 )
|
||||
asc = '.';
|
||||
else if ( asc == 165 )
|
||||
asc = 13;
|
||||
}
|
||||
|
||||
/* shifted letter */
|
||||
if ( asc >= 'A' && asc <= 'Z' && ( ! m_kbd_caps ) && ( ! shift ) )
|
||||
asc += 'a' - 'A';
|
||||
|
||||
/* control */
|
||||
if ( control )
|
||||
asc &= ~0x40;
|
||||
|
||||
if ( key == m_kbd_last_key )
|
||||
{
|
||||
/* repeat */
|
||||
m_kbd_key_count++;
|
||||
if ( m_kbd_key_count < TO9_KBD_REPEAT_DELAY || (m_kbd_key_count - TO9_KBD_REPEAT_DELAY) % TO9_KBD_REPEAT_PERIOD )
|
||||
return 0;
|
||||
LOGMASKED(LOG_KBD, "to9_kbd_get_key: repeat key $%02X '%c'\n", asc, asc);
|
||||
return asc;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kbd_last_key = key;
|
||||
m_kbd_key_count = 0;
|
||||
LOGMASKED(LOG_KBD, "to9_kbd_get_key: key down $%02X '%c'\n", asc, asc);
|
||||
return asc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(to9_keyboard_device::timer_cb)
|
||||
{
|
||||
if ( m_kbd_periph )
|
||||
{
|
||||
/* peripheral mode: every 10 ms we send 4 bytes */
|
||||
|
||||
switch ( m_kbd_byte_count )
|
||||
{
|
||||
case 0: /* key */
|
||||
send( get_key(), 0 );
|
||||
break;
|
||||
|
||||
case 1: /* x axis */
|
||||
{
|
||||
int newx = m_io_mouse_x.read_safe(0);
|
||||
uint8_t data = ( (newx - m_mouse_x) & 0xf ) - 8;
|
||||
send( data, 1 );
|
||||
m_mouse_x = newx;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: /* y axis */
|
||||
{
|
||||
int newy = m_io_mouse_y.read_safe(0);
|
||||
uint8_t data = ( (newy - m_mouse_y) & 0xf ) - 8;
|
||||
send( data, 1 );
|
||||
m_mouse_y = newy;
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: /* axis overflow & buttons */
|
||||
{
|
||||
int b = m_io_mouse_button.read_safe(~0);
|
||||
uint8_t data = 0;
|
||||
if ( b & 1 ) data |= 1;
|
||||
if ( b & 2 ) data |= 4;
|
||||
send( data, 1 );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_kbd_byte_count = ( m_kbd_byte_count + 1 ) & 3;
|
||||
m_kbd_timer->adjust(m_kbd_byte_count ? TO9_KBD_BYTE_SPACE : TO9_KBD_END_SPACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int key = get_key();
|
||||
/* keyboard mode: send a byte only if a key is down */
|
||||
if ( key )
|
||||
send( key, 0 );
|
||||
m_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_keyboard_device::device_reset()
|
||||
{
|
||||
m_kbd_overrun = 0; /* no byte lost */
|
||||
m_kbd_status = ACIA_6850_TDRE; /* clear to transmit */
|
||||
m_kbd_intr = 0; /* interrupt disabled */
|
||||
m_kbd_caps = 1;
|
||||
m_kbd_periph = 0;
|
||||
m_kbd_pad = 0;
|
||||
m_kbd_byte_count = 0;
|
||||
m_caps_led = !m_kbd_caps;
|
||||
m_kbd_key_count = 0;
|
||||
m_kbd_last_key = 0xff;
|
||||
update_irq();
|
||||
m_kbd_timer->adjust(TO9_KBD_POLL_PERIOD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void to9_keyboard_device::device_start()
|
||||
{
|
||||
m_caps_led.resolve();
|
||||
|
||||
m_kbd_timer = timer_alloc(FUNC(to9_keyboard_device::timer_cb), this);
|
||||
save_item(NAME(m_kbd_parity));
|
||||
save_item(NAME(m_kbd_intr));
|
||||
save_item(NAME(m_kbd_in));
|
||||
save_item(NAME(m_kbd_status));
|
||||
save_item(NAME(m_kbd_overrun));
|
||||
save_item(NAME(m_kbd_last_key));
|
||||
save_item(NAME(m_kbd_key_count));
|
||||
save_item(NAME(m_kbd_caps));
|
||||
save_item(NAME(m_kbd_periph));
|
||||
save_item(NAME(m_kbd_pad));
|
||||
save_item(NAME(m_kbd_byte_count));
|
||||
save_item(NAME(m_mouse_x));
|
||||
save_item(NAME(m_mouse_y));
|
||||
}
|
121
src/mame/thomson/to_kbd.h
Normal file
121
src/mame/thomson/to_kbd.h
Normal file
@ -0,0 +1,121 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Antoine Mine
|
||||
/**********************************************************************
|
||||
|
||||
Copyright (C) Antoine Mine' 2006
|
||||
|
||||
Thomson TO8 built-in keyboard & TO9 detached keyboard
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_THOMSON_TO_KBD_H
|
||||
#define MAME_THOMSON_TO_KBD_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class to8_keyboard_device : public device_t
|
||||
{
|
||||
public:
|
||||
to8_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
|
||||
|
||||
auto data_cb() { return m_data_cb.bind(); }
|
||||
|
||||
int ktest_r();
|
||||
int caps_r() { return m_kbd_caps; }
|
||||
void set_ack( int data );
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
devcb_write_line m_data_cb;
|
||||
|
||||
required_ioport_array<10> m_io_keyboard;
|
||||
output_finder<> m_caps_led;
|
||||
|
||||
uint8_t m_kbd_ack = 0; /* 1 = cpu inits / accepts transfers */
|
||||
uint16_t m_kbd_data = 0; /* data to transmit */
|
||||
uint16_t m_kbd_step = 0; /* transmission automaton state */
|
||||
uint8_t m_kbd_last_key = 0; /* last key (for repetition) */
|
||||
uint32_t m_kbd_key_count = 0; /* keypress time (for repetition) */
|
||||
uint8_t m_kbd_caps = 0; /* caps lock */
|
||||
emu_timer* m_kbd_timer = nullptr; /* bit-send */
|
||||
emu_timer* m_kbd_signal = nullptr; /* signal from CPU */
|
||||
|
||||
TIMER_CALLBACK_MEMBER( timer_cb );
|
||||
int get_key();
|
||||
void timer_func();
|
||||
};
|
||||
|
||||
class to9_keyboard_device : public device_t
|
||||
{
|
||||
public:
|
||||
to9_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
|
||||
|
||||
auto irq_cb() { return m_irq_cb.bind(); }
|
||||
|
||||
uint8_t kbd_acia_r(offs_t offset);
|
||||
void kbd_acia_w(offs_t offset, uint8_t data);
|
||||
|
||||
int ktest_r();
|
||||
|
||||
protected:
|
||||
to9_keyboard_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock = 0U);
|
||||
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
devcb_write_line m_irq_cb;
|
||||
|
||||
required_ioport_array<10> m_io_keyboard;
|
||||
optional_ioport m_io_mouse_x;
|
||||
optional_ioport m_io_mouse_y;
|
||||
optional_ioport m_io_mouse_button;
|
||||
output_finder<> m_caps_led;
|
||||
|
||||
uint8_t m_kbd_parity = 0; /* 0=even, 1=odd, 2=no parity */
|
||||
uint8_t m_kbd_intr = 0; /* interrupt mode */
|
||||
uint8_t m_kbd_in = 0; /* data from keyboard */
|
||||
uint8_t m_kbd_status = 0; /* status */
|
||||
uint8_t m_kbd_overrun = 0; /* character lost */
|
||||
uint8_t m_kbd_periph = 0; /* peripheral mode */
|
||||
uint8_t m_kbd_byte_count = 0; /* byte-count in peripheral mode */
|
||||
uint16_t m_mouse_x = 0;
|
||||
uint16_t m_mouse_y = 0;
|
||||
uint8_t m_kbd_last_key = 0; /* for key repetition */
|
||||
uint16_t m_kbd_key_count = 0;
|
||||
uint8_t m_kbd_caps = 0; /* caps-lock */
|
||||
uint8_t m_kbd_pad = 0; /* keypad outputs special codes */
|
||||
emu_timer* m_kbd_timer = nullptr;
|
||||
|
||||
TIMER_CALLBACK_MEMBER( timer_cb );
|
||||
void update_irq();
|
||||
void send( uint8_t data, int parity );
|
||||
int get_key();
|
||||
};
|
||||
|
||||
class to9p_keyboard_device : public to9_keyboard_device
|
||||
{
|
||||
public:
|
||||
to9p_keyboard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0U);
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD;
|
||||
};
|
||||
|
||||
// device type declarations
|
||||
DECLARE_DEVICE_TYPE(TO8_KEYBOARD, to8_keyboard_device)
|
||||
DECLARE_DEVICE_TYPE(TO9_KEYBOARD, to9_keyboard_device)
|
||||
DECLARE_DEVICE_TYPE(TO9P_KEYBOARD, to9p_keyboard_device)
|
||||
|
||||
#endif // MAME_THOMSON_TO_KBD_H
|
Loading…
Reference in New Issue
Block a user