// license:GPL-2.0+
// copyright-holders:Raphael Nabet
/*
TI 911 VDT core. To be operated with the TI 990 line of computers (can be connected to
any model, as communication uses the CRU bus).
Raphael Nabet 2002
TODO:
* add more flexibility, so that we can create multiple-terminal configurations.
* support test mode???
*/
#include "emu.h"
#include "911_vdt.h"
#include "911_chr.h"
#include "911_key.h"
#include "speaker.h"
#define MAX_VDT 1
static const gfx_layout fontlayout_7bit =
{
7, 10, /* 7*10 characters */
128, /* 128 characters */
1, /* 1 bit per pixel */
{ 0 },
{ 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
10*8 /* every char takes 10 consecutive bytes */
};
static const gfx_layout fontlayout_8bit =
{
7, 10, /* 7*10 characters */
128, /* 128 characters */
1, /* 1 bit per pixel */
{ 0 },
{ 1, 2, 3, 4, 5, 6, 7 }, /* straightforward layout */
{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
10*8 /* every char takes 10 consecutive bytes */
};
static GFXDECODE_START( gfx_vdt911 )
// Caution: Array must use same order as vdt911_model_t
// US
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::US_chr_offset, fontlayout_7bit, 0, 4 )
// UK
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::UK_chr_offset, fontlayout_7bit, 0, 4 )
// French (without accented characters)
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::US_chr_offset, fontlayout_7bit, 0, 4 )
// German
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::german_chr_offset, fontlayout_7bit, 0, 4 )
// Swedish
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::swedish_chr_offset, fontlayout_7bit, 0, 4 )
// Norwegian
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::norwegian_chr_offset, fontlayout_7bit, 0, 4 )
// Japanese
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::japanese_chr_offset, fontlayout_8bit, 0, 4 )
// Arabic
// GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::arabic_chr_offset, fontlayout_8bit, 0, 4 )
// FrenchWP (contains accented characters)
GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::frenchWP_chr_offset, fontlayout_7bit, 0, 4 )
GFXDECODE_END
static constexpr rgb_t vdt911_colors[] =
{
{ 0x00, 0x00, 0x00 }, // black
{ 0xc0, 0xc0, 0xc0 }, // low intensity
{ 0xff, 0xff, 0xff } // high intensity
};
static const unsigned short vdt911_pens[] =
{
0, 2, // high intensity
0, 1, // low intensity
2, 0, // high intensity, reverse
2, 1 // low intensity, reverse
};
/*
Macros for model features
*/
/* TRUE for Japanese and Arabic terminals, which use 8-bit charcodes and keyboard shift modes */
#define USES_8BIT_CHARCODES() ((m_model == model::Japanese) /*|| (m_model == model::Arabic)*/)
/* TRUE for keyboards which have this extra key (on the left of TAB/SKIP)
(Most localized keyboards have it) */
#define HAS_EXTRA_KEY_67() (! ((m_model == model::US) || (m_model == model::UK) || (m_model == model::French)))
/* TRUE for keyboards which have this extra key (on the right of space),
AND do not use it as a modifier */
#define HAS_EXTRA_KEY_91() ((m_model == model::German) || (m_model == model::Swedish) || (m_model == model::Norwegian))
/*
Initialize vdt911 palette
*/
void vdt911_device::vdt911_palette(palette_device &palette) const
{
for (int i = 0; i < ARRAY_LENGTH(vdt911_colors); i++)
palette.set_indirect_color(i, vdt911_colors[i]);
for (int i = 0; i < ARRAY_LENGTH(vdt911_pens); i++)
palette.set_pen_indirect(i, vdt911_pens[i]);
}
/*
Copy a character bitmap array to another location in memory
*/
static void copy_character_matrix_array(const uint8_t char_array[128][10], uint8_t *dest)
{
int i, j;
for (i=0; i<128; i++)
for (j=0; j<10; j++)
*(dest++) = char_array[i][j];
}
/*
Patch a character bitmap array according to an array of char_override_t
*/
static void apply_char_overrides(int nb_char_overrides, const char_override_t char_overrides[], uint8_t *dest)
{
int i, j;
for (i=0; i<nb_char_overrides; i++)
{
for (j=0; j<10; j++)
dest[char_overrides[i].char_index*10+j] = char_defs[char_overrides[i].symbol_index][j];
}
}
DEFINE_DEVICE_TYPE(VDT911, vdt911_device, "vdt911", "911 VDT")
vdt911_device::vdt911_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, VDT911, tag, owner, clock)
, device_gfx_interface(mconfig, *this, gfx_vdt911, "palette")
, m_beeper(*this, "beeper")
, m_screen(*this, "screen")
, m_keys(*this, "KEY%u", 0U)
, m_keyint_line(*this)
, m_lineint_line(*this)
{
}
enum
{
BLINK_TIMER,
BEEP_TIMER,
LINE_TIMER
};
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void vdt911_device::device_start()
{
m_last_key_pressed = 0x80;
m_keyboard_data_ready = false;
m_display_enable = false;
m_blink_state = false;
m_keyint_line.resolve();
m_lineint_line.resolve();
/* set up cursor blink clock. 2Hz frequency -> .25s half-period. */
/*m_blink_clock =*/
m_blink_timer = timer_alloc(BLINK_TIMER);
m_beep_timer = timer_alloc(BEEP_TIMER);
m_line_timer = timer_alloc(LINE_TIMER);
m_blink_timer->adjust(attotime::from_msec(0), 0, attotime::from_msec(250));
uint8_t *base;
uint8_t *chr = machine().root_device().memregion(vdt911_chr_region)->base();
/* set up US character definitions */
base = chr+US_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
/* set up UK character definitions */
base = chr+UK_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(UK_overrides)/sizeof(char_override_t), UK_overrides, base);
/* French character set is identical to US character set */
/* set up German character definitions */
base = chr+german_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(german_overrides)/sizeof(char_override_t), german_overrides, base);
/* set up Swedish/Finnish character definitions */
base = chr+swedish_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(swedish_overrides)/sizeof(char_override_t), swedish_overrides, base);
/* set up Norwegian/Danish character definitions */
base = chr+norwegian_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(norwegian_overrides)/sizeof(char_override_t), norwegian_overrides, base);
/* set up French word processing character definitions */
base = chr+frenchWP_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(frenchWP_overrides)/sizeof(char_override_t), frenchWP_overrides, base);
/* set up Katakana Japanese character definitions */
base = chr+japanese_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(japanese_overrides)/sizeof(char_override_t), japanese_overrides, base);
base = chr+japanese_chr_offset+128*single_char_len;
copy_character_matrix_array(char_defs+char_defs_katakana_base, base);
#if 0
/* set up Arabic character definitions */
base = chr+arabic_chr_offset;
copy_character_matrix_array(char_defs+char_defs_US_base, base);
apply_char_overrides(sizeof(arabic_overrides)/sizeof(char_override_t), arabic_overrides, base);
base = chr+arabic_chr_offset+128*single_char_len;
copy_character_matrix_array(char_defs+char_defs_arabic_base, base);
#endif
}
void vdt911_device::device_reset()
{
m_model = model(ioport("LOCALE")->read());
m_screen_size = screen_size(ioport("SCREEN")->read());
if (m_screen_size == screen_size::char_960)
m_cursor_address_mask = 0x3ff; /* 1kb of RAM */
else
m_cursor_address_mask = 0x7ff; /* 2 kb of RAM */
// European models have 50 Hz
int lines = (m_model == model::US) || (m_model == model::Japanese) ? 262 : 314;
attotime refresh = attotime::from_hz(11.004_MHz_XTAL / 700 / lines);
m_screen->configure(700, lines, m_screen->visible_area(), refresh.as_attoseconds());
m_line_timer->adjust(attotime::from_msec(0), 0, refresh);
}
/*
Timer callbacks
*/
void vdt911_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case BLINK_TIMER:
m_blink_state = !m_blink_state;
break;
case BEEP_TIMER:
m_beeper->set_state(0);
break;
case LINE_TIMER:
check_keyboard();
m_lineint_line(ASSERT_LINE);
m_lineint_line(CLEAR_LINE);
break;
}
}
/*
CRU interface read
*/
READ8_MEMBER( vdt911_device::cru_r )
{
int reply=0;
offset &= 0xf;
if (!m_word_select)
{ /* select word 0 */
switch (offset >> 3)
{
case 0:
reply = m_display_RAM[m_cursor_address];
break;
case 1:
reply = m_keyboard_data & 0x7f;
if (m_keyboard_data_ready)
reply |= 0x80;
break;
}
}
else
{ /* select word 1 */
switch (offset >> 3)
{
case 0:
reply = m_cursor_address & 0xff;
break;
case 1:
reply = (m_cursor_address >> 8) & 0x07;
if (m_keyboard_data & 0x80)
reply |= 0x08;
/*if (!m_terminal_ready)
reply |= 0x10;*/
if (m_previous_word_select)
reply |= 0x20;
/*if (m_keyboard_parity_error)
reply |= 0x40;*/
if (m_keyboard_data_ready)
reply |= 0x80;
break;
}
}
return BIT(reply, offset & 3);
}
/*
CRU interface write
*/
WRITE8_MEMBER( vdt911_device::cru_w )
{
offset &= 0xf;
if (!m_word_select)
{ /* select word 0 */
switch (offset)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
/* display memory write data */
if (data)
m_data_reg |= (1 << offset);
else
m_data_reg &= ~ (1 << offset);
break;
case 0x8:
/* write data strobe */
m_display_RAM[m_cursor_address] = m_data_reg;
break;
case 0x9:
/* test mode */
/* ... */
break;
case 0xa:
/* cursor move */
if (data)
m_cursor_address--;
else
m_cursor_address++;
m_cursor_address &= m_cursor_address_mask;
break;
case 0xb:
/* blinking cursor enable */
m_blinking_cursor_enable = data;
break;
case 0xc:
/* keyboard interrupt enable */
m_keyboard_interrupt_enable = data;
m_keyint_line(m_keyboard_interrupt_enable && m_keyboard_data_ready);
break;
case 0xd:
/* dual intensity enable */
m_dual_intensity_enable = data;
break;
case 0xe:
/* display enable */
m_display_enable = data;
break;
case 0xf:
/* select word */
m_previous_word_select = m_word_select;
m_word_select = data;
break;
}
}
else
{ /* select word 1 */
switch (offset)
{
case 0x0:
case 0x1:
case 0x2:
case 0x3:
case 0x4:
case 0x5:
case 0x6:
case 0x7:
case 0x8:
case 0x9:
case 0xa:
/* cursor address */
if (data)
m_cursor_address |= (1 << offset);
else
m_cursor_address &= ~ (1 << offset);
m_cursor_address &= m_cursor_address_mask;
break;
case 0xb:
/* not used */
break;
case 0xc:
/* display cursor */
m_display_cursor = data;
break;
case 0xd:
/* keyboard acknowledge */
if (m_keyboard_data_ready)
{
m_keyboard_data_ready = 0;
if (m_keyboard_interrupt_enable)
m_keyint_line(CLEAR_LINE);
}
/*m_keyboard_parity_error = 0;*/
break;
case 0xe:
/* beep enable strobe - not tested */
m_beeper->set_state(1);
m_beep_timer->adjust(attotime::from_usec(300));
break;
case 0xf:
/* select word */
m_previous_word_select = m_word_select;
m_word_select = data;
break;
}
}
}
/*
Video refresh
*/
void vdt911_device::refresh(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y)
{
gfx_element *gfx = this->gfx(unsigned(m_model));
int height = (m_screen_size == screen_size::char_960) ? 12 : 24;
int use_8bit_charcodes = USES_8BIT_CHARCODES();
int address = 0;
int i, j;
int cur_char;
int color;
/*if (use_8bit_charcodes)
color = vdt->dual_intensity_enable ? 1 : 0;*/
if (!m_display_enable)
{
rectangle my_rect(x, x + 80*7 - 1, y, y + height*10 - 1);
bitmap.fill(0, my_rect);
}
else
{
for (i=0; i<height; i++)
{
for (j=0; j<80; j++)
{
cur_char = m_display_RAM[address];
/* does dual intensity work with 8-bit character set? */
color = (m_dual_intensity_enable && (cur_char & 0x80)) ? 1 : 0;
if (!use_8bit_charcodes)
cur_char &= 0x7f;
/* display cursor in reverse video */
if ((address == m_cursor_address) && m_display_cursor
&& ((!m_blinking_cursor_enable) || m_blink_state))
color += 2;
address++;
gfx->opaque(bitmap, cliprect, cur_char, color, 0, 0,
x+j*7, y+i*10);
}
}
}
}
static const unsigned char (*const key_translate[])[91] =
{ /* array must use same order as vdt911_model_t!!! */
/* US */
US_key_translate,
/* UK */
US_key_translate,
/* French */
French_key_translate,
/* German */
German_key_translate,
/* Swedish */
Swedish_key_translate,
/* Norwegian */
Norwegian_key_translate,
/* Japanese */
Japanese_key_translate,
/* Arabic */
/*Arabic_key_translate,*/
/* FrenchWP */
FrenchWP_key_translate
};
/*
keyboard handler: should be called regularly by machine code, for instance
every Video Blank Interrupt.
*/
void vdt911_device::check_keyboard()
{
enum modifier_state_t
{
/* states for Western keyboards and katakana/Arabic keyboards in romaji/Latin mode */
lower_case = 0, upper_case, shift, control,
/* states for katakana/Arabic keyboards in katakana/Arabic mode */
foreign, foreign_shift,
/* special value to stop repeat if the modifier state changes */
special_debounce = -1
};
static unsigned char repeat_timer;
enum { repeat_delay = 5 /* approx. 1/10s */ };
uint16_t key_buf[6];
int i, j;
modifier_state_t modifier_state;
int repeat_mode;
/* read current key state */
for (i = 0; i < 6; i++)
{
key_buf[i] = m_keys[i]->read();
}
/* parse modifier keys */
if ((USES_8BIT_CHARCODES())
&& ((key_buf[5] & 0x0400) || ((!(key_buf[5] & 0x0100)) && m_foreign_mode)))
{ /* we are in katakana/Arabic mode */
m_foreign_mode = true;
if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
modifier_state = foreign_shift;
else
modifier_state = foreign;
}
else
{ /* we are using a Western keyboard, or a katakana/Arabic keyboard in
romaji/Latin mode */
m_foreign_mode = false;
if (key_buf[3] & 0x0040)
modifier_state = control;
else if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
modifier_state = shift;
else if ((key_buf[0] & 0x2000))
modifier_state = upper_case;
else
modifier_state = lower_case;
}
/* test repeat key */
repeat_mode = key_buf[2] & 0x0002;
/* remove modifier keys */
key_buf[0] &= ~0x2000;
key_buf[2] &= ~0x0002;
key_buf[3] &= ~0x0040;
key_buf[4] &= ~0x0400;
key_buf[5] &= ~0x0120;
/* remove unused keys */
if (! HAS_EXTRA_KEY_91())
key_buf[5] &= ~0x0400;
if (! HAS_EXTRA_KEY_67())
key_buf[4] &= ~0x0004;
if (! repeat_mode)
/* reset REPEAT timer if the REPEAT key is not pressed */
repeat_timer = 0;
if (!(m_last_key_pressed & 0x80) && (key_buf[m_last_key_pressed >> 4] & (1 << (m_last_key_pressed & 0xf))))
{
/* last key has not been released */
if (modifier_state == m_last_modifier_state)
{
/* handle REPEAT mode if applicable */
if ((repeat_mode) && (++repeat_timer == repeat_delay))
{
if (m_keyboard_data_ready)
{ /* keyboard buffer full */
repeat_timer--;
}
else
{ /* repeat current key */
m_keyboard_data_ready = 1;
repeat_timer = 0;
}
}
}
else
{
repeat_timer = 0;
m_last_modifier_state = special_debounce;
}
}
else
{
m_last_key_pressed = 0x80;
if (m_keyboard_data_ready)
{ /* keyboard buffer full */
/* do nothing */
}
else
{
for (i=0; i<6; i++)
{
for (j=0; j<16; j++)
{
if (key_buf[i] & (1 << j))
{
m_last_key_pressed = (i << 4) | j;
m_last_modifier_state = modifier_state;
m_keyboard_data = (int)key_translate[unsigned(m_model)][modifier_state][m_last_key_pressed];
m_keyboard_data_ready = 1;
if (m_keyboard_interrupt_enable)
m_keyint_line(ASSERT_LINE);
return;
}
}
}
}
}
}
uint32_t vdt911_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
refresh(bitmap, cliprect, 0, 0);
return 0;
}
INPUT_PORTS_START( vdt911 )
PORT_START( "LOCALE" )
PORT_CONFNAME( 0x0f, 0x00, "Terminal language" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::US), "English US" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::UK), "English UK" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::French), "French" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::German), "German" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::Swedish), "Swedish" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::Norwegian), "Norwegian" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::Japanese), "Japanese" )
// PORT_CONFSETTING( ioport_value(vdt911_device::model::Arabic), "Arabic" )
PORT_CONFSETTING( ioport_value(vdt911_device::model::FrenchWP), "French Word Processing" )
PORT_START( "SCREEN" )
PORT_CONFNAME( 0x01, ioport_value(vdt911_device::screen_size::char_960), "Terminal screen size" )
PORT_CONFSETTING( ioport_value(vdt911_device::screen_size::char_960), "960 chars (12 lines)")
PORT_CONFSETTING( ioport_value(vdt911_device::screen_size::char_1920), "1920 chars (24 lines)")
PORT_START("KEY0") /* keys 1-16 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CMD") PORT_CODE(KEYCODE_F9) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(red)") PORT_CODE(KEYCODE_F10) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE FIELD") PORT_CODE(KEYCODE_END) \
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE INPUT") PORT_CODE(KEYCODE_PGDN) \
PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(grey)") PORT_CODE(KEYCODE_F11) \
PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UPPER CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE\
PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1) \
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2) \
\
PORT_START("KEY1") /* keys 17-32 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ [") PORT_CODE(KEYCODE_MINUS) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- ]") PORT_CODE(KEYCODE_EQUALS) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("_ =") PORT_CODE(KEYCODE_BACKSPACE) \
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC) \
PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 (numpad)") PORT_CODE(KEYCODE_7_PAD) \
PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 (numpad)") PORT_CODE(KEYCODE_8_PAD) \
PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (numpad)") PORT_CODE(KEYCODE_9_PAD) \
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PRINT") PORT_CODE(KEYCODE_PRTSCR) \
\
PORT_START("KEY2") /* keys 33-48 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(up)") PORT_CODE(KEYCODE_UP) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REPEAT") PORT_CODE(KEYCODE_LALT) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER_PAD) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I) \
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O) \
PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P) \
PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CHAR (left/right)") PORT_CODE(KEYCODE_OPENBRACE) \
PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("FIELD (left/right)") PORT_CODE(KEYCODE_CLOSEBRACE) \
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) \
\
PORT_START("KEY3") /* keys 49-64 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 (numpad)") PORT_CODE(KEYCODE_4_PAD) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 (numpad)") PORT_CODE(KEYCODE_5_PAD) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 (numpad)") PORT_CODE(KEYCODE_6_PAD) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(left)") PORT_CODE(KEYCODE_LEFT) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(right)") PORT_CODE(KEYCODE_RIGHT) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F) \
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G) \
PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H) \
PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J) \
PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K) \
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L) \
\
PORT_START("KEY4") /* keys 65-80 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_BACKSLASH) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SKIP TAB") PORT_CODE(KEYCODE_TAB) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 (numpad)") PORT_CODE(KEYCODE_1_PAD) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 (numpad)") PORT_CODE(KEYCODE_2_PAD) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 (numpad)") PORT_CODE(KEYCODE_3_PAD) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("INS CHAR") PORT_CODE(KEYCODE_INSERT) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(down)") PORT_CODE(KEYCODE_DOWN) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL CHAR") PORT_CODE(KEYCODE_DEL) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) \
PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z) \
PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X) \
PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C) \
PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V) \
PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B) \
\
PORT_START("KEY5") /* keys 81-91 */ \
PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N) \
PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M) \
PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA) \
PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) \
PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH) \
PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) \
PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 (numpad)") PORT_CODE(KEYCODE_0_PAD) \
PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". (numpad)") PORT_CODE(KEYCODE_DEL_PAD) \
PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_MINUS_PAD) \
PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) \
PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_PLUS_PAD)
INPUT_PORTS_END
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void vdt911_device::device_add_mconfig(machine_config &config)
{
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_raw(11.004_MHz_XTAL, 700, 0, 560, 262, 0, 240);
m_screen->set_screen_update(FUNC(vdt911_device::screen_update));
m_screen->set_palette("palette");
SPEAKER(config, "speaker").front_center();
BEEP(config, m_beeper, 3250).add_route(ALL_OUTPUTS, "speaker", 0.50);
PALETTE(config, "palette", FUNC(vdt911_device::vdt911_palette), ARRAY_LENGTH(vdt911_pens), ARRAY_LENGTH(vdt911_colors));
}
ioport_constructor vdt911_device::device_input_ports() const
{
return INPUT_PORTS_NAME( vdt911 );
}