1 // license:GPL-2.0+
2 // copyright-holders:Raphael Nabet
3 /*
4     TI 911 VDT core.  To be operated with the TI 990 line of computers (can be connected to
5     any model, as communication uses the CRU bus).
6 
7     Raphael Nabet 2002
8 
9 TODO:
10     * add more flexibility, so that we can create multiple-terminal configurations.
11     * support test mode???
12 */
13 
14 
15 #include "emu.h"
16 #include "911_vdt.h"
17 #include "911_chr.h"
18 #include "911_key.h"
19 
20 #include "speaker.h"
21 
22 
23 #define MAX_VDT 1
24 
25 static const gfx_layout fontlayout_7bit =
26 {
27 	7, 10,          /* 7*10 characters */
28 	128,            /* 128 characters */
29 	1,              /* 1 bit per pixel */
30 	{ 0 },
31 	{ 1, 2, 3, 4, 5, 6, 7 },            /* straightforward layout */
32 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
33 	10*8            /* every char takes 10 consecutive bytes */
34 };
35 
36 static const gfx_layout fontlayout_8bit =
37 {
38 	7, 10,          /* 7*10 characters */
39 	128,            /* 128 characters */
40 	1,              /* 1 bit per pixel */
41 	{ 0 },
42 	{ 1, 2, 3, 4, 5, 6, 7 },                /* straightforward layout */
43 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 8*8, 9*8 },
44 	10*8            /* every char takes 10 consecutive bytes */
45 };
46 
47 static GFXDECODE_START( gfx_vdt911 )
48 	// Caution: Array must use same order as vdt911_model_t
49 	// US
50 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::US_chr_offset, fontlayout_7bit, 0, 4 )
51 
52 	// UK
53 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::UK_chr_offset, fontlayout_7bit, 0, 4 )
54 
55 	// French (without accented characters)
56 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::US_chr_offset, fontlayout_7bit, 0, 4 )
57 
58 	// German
59 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::german_chr_offset, fontlayout_7bit, 0, 4 )
60 
61 	// Swedish
62 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::swedish_chr_offset, fontlayout_7bit, 0, 4 )
63 
64 	// Norwegian
65 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::norwegian_chr_offset, fontlayout_7bit, 0, 4 )
66 
67 	// Japanese
68 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::japanese_chr_offset, fontlayout_8bit, 0, 4 )
69 
70 	// Arabic
71 	// GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::arabic_chr_offset, fontlayout_8bit, 0, 4 )
72 
73 	// FrenchWP (contains accented characters)
74 	GFXDECODE_ENTRY( vdt911_chr_region, vdt911_device::frenchWP_chr_offset, fontlayout_7bit, 0, 4 )
75 GFXDECODE_END
76 
77 static constexpr rgb_t vdt911_colors[] =
78 {
79 	{ 0x00, 0x00, 0x00 }, // black
80 	{ 0xc0, 0xc0, 0xc0 }, // low intensity
81 	{ 0xff, 0xff, 0xff }  // high intensity
82 };
83 
84 static const unsigned short vdt911_pens[] =
85 {
86 	0, 2,   // high intensity
87 	0, 1,   // low intensity
88 	2, 0,   // high intensity, reverse
89 	2, 1    // low intensity, reverse
90 };
91 
92 /*
93     Macros for model features
94 */
95 /* TRUE for Japanese and Arabic terminals, which use 8-bit charcodes and keyboard shift modes */
96 #define USES_8BIT_CHARCODES() ((m_model == model::Japanese) /*|| (m_model == model::Arabic)*/)
97 /* TRUE for keyboards which have this extra key (on the left of TAB/SKIP)
98     (Most localized keyboards have it) */
99 #define HAS_EXTRA_KEY_67() (! ((m_model == model::US) || (m_model == model::UK) || (m_model == model::French)))
100 /* TRUE for keyboards which have this extra key (on the right of space),
101     AND do not use it as a modifier */
102 #define HAS_EXTRA_KEY_91() ((m_model == model::German) || (m_model == model::Swedish) || (m_model == model::Norwegian))
103 
104 /*
105     Initialize vdt911 palette
106 */
vdt911_palette(palette_device & palette) const107 void vdt911_device::vdt911_palette(palette_device &palette) const
108 {
109 	for (int i = 0; i < ARRAY_LENGTH(vdt911_colors); i++)
110 		palette.set_indirect_color(i, vdt911_colors[i]);
111 
112 	for (int i = 0; i < ARRAY_LENGTH(vdt911_pens); i++)
113 		palette.set_pen_indirect(i, vdt911_pens[i]);
114 }
115 
116 /*
117     Copy a character bitmap array to another location in memory
118 */
copy_character_matrix_array(const uint8_t char_array[128][10],uint8_t * dest)119 static void copy_character_matrix_array(const uint8_t char_array[128][10], uint8_t *dest)
120 {
121 	int i, j;
122 
123 	for (i=0; i<128; i++)
124 		for (j=0; j<10; j++)
125 			*(dest++) = char_array[i][j];
126 }
127 
128 /*
129     Patch a character bitmap array according to an array of char_override_t
130 */
apply_char_overrides(int nb_char_overrides,const char_override_t char_overrides[],uint8_t * dest)131 static void apply_char_overrides(int nb_char_overrides, const char_override_t char_overrides[], uint8_t *dest)
132 {
133 	int i, j;
134 
135 	for (i=0; i<nb_char_overrides; i++)
136 	{
137 		for (j=0; j<10; j++)
138 			dest[char_overrides[i].char_index*10+j] = char_defs[char_overrides[i].symbol_index][j];
139 	}
140 }
141 
142 DEFINE_DEVICE_TYPE(VDT911, vdt911_device, "vdt911", "911 VDT")
143 
vdt911_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)144 vdt911_device::vdt911_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
145 	: device_t(mconfig, VDT911, tag, owner, clock)
146 	, device_gfx_interface(mconfig, *this, gfx_vdt911, "palette")
147 	, m_beeper(*this, "beeper")
148 	, m_screen(*this, "screen")
149 	, m_keys(*this, "KEY%u", 0U)
150 	, m_keyint_line(*this)
151 	, m_lineint_line(*this)
152 {
153 }
154 
155 enum
156 {
157 	BLINK_TIMER,
158 	BEEP_TIMER,
159 	LINE_TIMER
160 };
161 
162 //-------------------------------------------------
163 //  device_start - device-specific startup
164 //-------------------------------------------------
165 
device_start()166 void vdt911_device::device_start()
167 {
168 	m_last_key_pressed = 0x80;
169 
170 	m_keyboard_data_ready = false;
171 	m_display_enable = false;
172 	m_blink_state = false;
173 
174 	m_keyint_line.resolve();
175 	m_lineint_line.resolve();
176 
177 	/* set up cursor blink clock.  2Hz frequency -> .25s half-period. */
178 	/*m_blink_clock =*/
179 
180 	m_blink_timer = timer_alloc(BLINK_TIMER);
181 	m_beep_timer = timer_alloc(BEEP_TIMER);
182 	m_line_timer = timer_alloc(LINE_TIMER);
183 
184 	m_blink_timer->adjust(attotime::from_msec(0), 0, attotime::from_msec(250));
185 
186 	uint8_t *base;
187 	uint8_t *chr = machine().root_device().memregion(vdt911_chr_region)->base();
188 
189 	/* set up US character definitions */
190 	base = chr+US_chr_offset;
191 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
192 
193 	/* set up UK character definitions */
194 	base = chr+UK_chr_offset;
195 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
196 	apply_char_overrides(sizeof(UK_overrides)/sizeof(char_override_t), UK_overrides, base);
197 
198 	/* French character set is identical to US character set */
199 
200 	/* set up German character definitions */
201 	base = chr+german_chr_offset;
202 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
203 	apply_char_overrides(sizeof(german_overrides)/sizeof(char_override_t), german_overrides, base);
204 
205 	/* set up Swedish/Finnish character definitions */
206 	base = chr+swedish_chr_offset;
207 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
208 	apply_char_overrides(sizeof(swedish_overrides)/sizeof(char_override_t), swedish_overrides, base);
209 
210 	/* set up Norwegian/Danish character definitions */
211 	base = chr+norwegian_chr_offset;
212 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
213 	apply_char_overrides(sizeof(norwegian_overrides)/sizeof(char_override_t), norwegian_overrides, base);
214 
215 	/* set up French word processing character definitions */
216 	base = chr+frenchWP_chr_offset;
217 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
218 	apply_char_overrides(sizeof(frenchWP_overrides)/sizeof(char_override_t), frenchWP_overrides, base);
219 
220 	/* set up Katakana Japanese character definitions */
221 	base = chr+japanese_chr_offset;
222 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
223 	apply_char_overrides(sizeof(japanese_overrides)/sizeof(char_override_t), japanese_overrides, base);
224 	base = chr+japanese_chr_offset+128*single_char_len;
225 	copy_character_matrix_array(char_defs+char_defs_katakana_base, base);
226 
227 #if 0
228 	/* set up Arabic character definitions */
229 	base = chr+arabic_chr_offset;
230 	copy_character_matrix_array(char_defs+char_defs_US_base, base);
231 	apply_char_overrides(sizeof(arabic_overrides)/sizeof(char_override_t), arabic_overrides, base);
232 	base = chr+arabic_chr_offset+128*single_char_len;
233 	copy_character_matrix_array(char_defs+char_defs_arabic_base, base);
234 #endif
235 }
236 
237 
device_reset()238 void vdt911_device::device_reset()
239 {
240 	m_model = model(ioport("LOCALE")->read());
241 	m_screen_size = screen_size(ioport("SCREEN")->read());
242 
243 	if (m_screen_size == screen_size::char_960)
244 		m_cursor_address_mask = 0x3ff;   /* 1kb of RAM */
245 	else
246 		m_cursor_address_mask = 0x7ff;   /* 2 kb of RAM */
247 
248 	// European models have 50 Hz
249 	int lines = (m_model == model::US) || (m_model == model::Japanese) ? 262 : 314;
250 	attotime refresh = attotime::from_hz(11.004_MHz_XTAL / 700 / lines);
251 	m_screen->configure(700, lines, m_screen->visible_area(), refresh.as_attoseconds());
252 	m_line_timer->adjust(attotime::from_msec(0), 0, refresh);
253 }
254 
255 /*
256     Timer callbacks
257 */
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)258 void vdt911_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
259 {
260 	switch (id)
261 	{
262 	case BLINK_TIMER:
263 		m_blink_state = !m_blink_state;
264 		break;
265 	case BEEP_TIMER:
266 		m_beeper->set_state(0);
267 		break;
268 	case LINE_TIMER:
269 		check_keyboard();
270 		m_lineint_line(ASSERT_LINE);
271 		m_lineint_line(CLEAR_LINE);
272 		break;
273 	}
274 }
275 
276 /*
277     CRU interface read
278 */
cru_r(offs_t offset)279 uint8_t vdt911_device::cru_r(offs_t offset)
280 {
281 	int reply=0;
282 
283 	offset &= 0xf;
284 
285 	if (!m_word_select)
286 	{   /* select word 0 */
287 		switch (offset >> 3)
288 		{
289 		case 0:
290 			reply = m_display_RAM[m_cursor_address];
291 			break;
292 
293 		case 1:
294 			reply = m_keyboard_data & 0x7f;
295 			if (m_keyboard_data_ready)
296 				reply |= 0x80;
297 			break;
298 		}
299 	}
300 	else
301 	{   /* select word 1 */
302 		switch (offset >> 3)
303 		{
304 		case 0:
305 			reply = m_cursor_address & 0xff;
306 			break;
307 
308 		case 1:
309 			reply = (m_cursor_address >> 8) & 0x07;
310 			if (m_keyboard_data & 0x80)
311 				reply |= 0x08;
312 			/*if (!m_terminal_ready)
313 			    reply |= 0x10;*/
314 			if (m_previous_word_select)
315 				reply |= 0x20;
316 			/*if (m_keyboard_parity_error)
317 			    reply |= 0x40;*/
318 			if (m_keyboard_data_ready)
319 				reply |= 0x80;
320 			break;
321 		}
322 	}
323 
324 	return BIT(reply, offset & 3);
325 }
326 
327 /*
328     CRU interface write
329 */
cru_w(offs_t offset,uint8_t data)330 void vdt911_device::cru_w(offs_t offset, uint8_t data)
331 {
332 	offset &= 0xf;
333 
334 	if (!m_word_select)
335 	{   /* select word 0 */
336 		switch (offset)
337 		{
338 		case 0x0:
339 		case 0x1:
340 		case 0x2:
341 		case 0x3:
342 		case 0x4:
343 		case 0x5:
344 		case 0x6:
345 		case 0x7:
346 			/* display memory write data */
347 			if (data)
348 				m_data_reg |= (1 << offset);
349 			else
350 				m_data_reg &= ~ (1 << offset);
351 			break;
352 
353 		case 0x8:
354 			/* write data strobe */
355 				m_display_RAM[m_cursor_address] = m_data_reg;
356 			break;
357 
358 		case 0x9:
359 			/* test mode */
360 			/* ... */
361 			break;
362 
363 		case 0xa:
364 			/* cursor move */
365 			if (data)
366 				m_cursor_address--;
367 			else
368 				m_cursor_address++;
369 			m_cursor_address &= m_cursor_address_mask;
370 			break;
371 
372 		case 0xb:
373 			/* blinking cursor enable */
374 			m_blinking_cursor_enable = data;
375 			break;
376 
377 		case 0xc:
378 			/* keyboard interrupt enable */
379 			m_keyboard_interrupt_enable = data;
380 			m_keyint_line(m_keyboard_interrupt_enable && m_keyboard_data_ready);
381 			break;
382 
383 		case 0xd:
384 			/* dual intensity enable */
385 			m_dual_intensity_enable = data;
386 			break;
387 
388 		case 0xe:
389 			/* display enable */
390 			m_display_enable = data;
391 			break;
392 
393 		case 0xf:
394 			/* select word */
395 			m_previous_word_select = m_word_select;
396 			m_word_select = data;
397 			break;
398 		}
399 	}
400 	else
401 	{   /* select word 1 */
402 		switch (offset)
403 		{
404 		case 0x0:
405 		case 0x1:
406 		case 0x2:
407 		case 0x3:
408 		case 0x4:
409 		case 0x5:
410 		case 0x6:
411 		case 0x7:
412 		case 0x8:
413 		case 0x9:
414 		case 0xa:
415 			/* cursor address */
416 			if (data)
417 				m_cursor_address |= (1 << offset);
418 			else
419 				m_cursor_address &= ~ (1 << offset);
420 			m_cursor_address &= m_cursor_address_mask;
421 			break;
422 
423 		case 0xb:
424 			/* not used */
425 			break;
426 
427 		case 0xc:
428 			/* display cursor */
429 			m_display_cursor = data;
430 			break;
431 
432 		case 0xd:
433 			/* keyboard acknowledge */
434 			if (m_keyboard_data_ready)
435 			{
436 				m_keyboard_data_ready = 0;
437 				if (m_keyboard_interrupt_enable)
438 					m_keyint_line(CLEAR_LINE);
439 			}
440 			/*m_keyboard_parity_error = 0;*/
441 			break;
442 
443 		case 0xe:
444 			/* beep enable strobe - not tested */
445 			m_beeper->set_state(1);
446 			m_beep_timer->adjust(attotime::from_usec(300));
447 			break;
448 
449 		case 0xf:
450 			/* select word */
451 			m_previous_word_select = m_word_select;
452 			m_word_select = data;
453 			break;
454 		}
455 	}
456 }
457 
458 /*
459     Video refresh
460 */
refresh(bitmap_ind16 & bitmap,const rectangle & cliprect,int x,int y)461 void vdt911_device::refresh(bitmap_ind16 &bitmap, const rectangle &cliprect, int x, int y)
462 {
463 	gfx_element *gfx = this->gfx(unsigned(m_model));
464 	int height = (m_screen_size == screen_size::char_960) ? 12 : 24;
465 
466 	int use_8bit_charcodes = USES_8BIT_CHARCODES();
467 	int address = 0;
468 	int i, j;
469 	int cur_char;
470 	int color;
471 
472 	/*if (use_8bit_charcodes)
473 	    color = vdt->dual_intensity_enable ? 1 : 0;*/
474 
475 	if (!m_display_enable)
476 	{
477 		rectangle my_rect(x, x + 80*7 - 1, y, y + height*10 - 1);
478 
479 		bitmap.fill(0, my_rect);
480 	}
481 	else
482 	{
483 		for (i=0; i<height; i++)
484 		{
485 			for (j=0; j<80; j++)
486 			{
487 				cur_char = m_display_RAM[address];
488 				/* does dual intensity work with 8-bit character set? */
489 				color = (m_dual_intensity_enable && (cur_char & 0x80)) ? 1 : 0;
490 				if (!use_8bit_charcodes)
491 					cur_char &= 0x7f;
492 
493 				/* display cursor in reverse video */
494 				if ((address == m_cursor_address) && m_display_cursor
495 					&& ((!m_blinking_cursor_enable) || m_blink_state))
496 				color += 2;
497 
498 				address++;
499 
500 				gfx->opaque(bitmap, cliprect, cur_char, color, 0, 0,
501 					x+j*7, y+i*10);
502 			}
503 		}
504 	}
505 }
506 
507 static const unsigned char (*const key_translate[])[91] =
508 {   /* array must use same order as vdt911_model_t!!! */
509 	/* US */
510 	US_key_translate,
511 	/* UK */
512 	US_key_translate,
513 	/* French */
514 	French_key_translate,
515 	/* German */
516 	German_key_translate,
517 	/* Swedish */
518 	Swedish_key_translate,
519 	/* Norwegian */
520 	Norwegian_key_translate,
521 	/* Japanese */
522 	Japanese_key_translate,
523 	/* Arabic */
524 	/*Arabic_key_translate,*/
525 	/* FrenchWP */
526 	FrenchWP_key_translate
527 };
528 
529 /*
530     keyboard handler: should be called regularly by machine code, for instance
531     every Video Blank Interrupt.
532 */
check_keyboard()533 void vdt911_device::check_keyboard()
534 {
535 	enum modifier_state_t
536 	{
537 		/* states for Western keyboards and katakana/Arabic keyboards in romaji/Latin mode */
538 		lower_case = 0, upper_case, shift, control,
539 		/* states for katakana/Arabic keyboards in katakana/Arabic mode */
540 		foreign, foreign_shift,
541 		/* special value to stop repeat if the modifier state changes */
542 		special_debounce = -1
543 	};
544 
545 	static unsigned char repeat_timer;
546 	enum { repeat_delay = 5 /* approx. 1/10s */ };
547 
548 	uint16_t key_buf[6];
549 	int i, j;
550 	modifier_state_t modifier_state;
551 	int repeat_mode;
552 
553 	/* read current key state */
554 	for (i = 0; i < 6; i++)
555 	{
556 		key_buf[i] = m_keys[i]->read();
557 	}
558 
559 	/* parse modifier keys */
560 	if ((USES_8BIT_CHARCODES())
561 		&& ((key_buf[5] & 0x0400) || ((!(key_buf[5] & 0x0100)) && m_foreign_mode)))
562 	{   /* we are in katakana/Arabic mode */
563 		m_foreign_mode = true;
564 
565 		if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
566 			modifier_state = foreign_shift;
567 		else
568 			modifier_state = foreign;
569 	}
570 	else
571 	{   /* we are using a Western keyboard, or a katakana/Arabic keyboard in
572 	    romaji/Latin mode */
573 		m_foreign_mode = false;
574 
575 		if (key_buf[3] & 0x0040)
576 			modifier_state = control;
577 		else if ((key_buf[4] & 0x0400) || (key_buf[5] & 0x0020))
578 			modifier_state = shift;
579 		else if ((key_buf[0] & 0x2000))
580 			modifier_state = upper_case;
581 		else
582 			modifier_state = lower_case;
583 	}
584 
585 
586 	/* test repeat key */
587 	repeat_mode = key_buf[2] & 0x0002;
588 
589 
590 	/* remove modifier keys */
591 	key_buf[0] &= ~0x2000;
592 	key_buf[2] &= ~0x0002;
593 	key_buf[3] &= ~0x0040;
594 	key_buf[4] &= ~0x0400;
595 	key_buf[5] &= ~0x0120;
596 
597 	/* remove unused keys */
598 	if (! HAS_EXTRA_KEY_91())
599 		key_buf[5] &= ~0x0400;
600 
601 	if (! HAS_EXTRA_KEY_67())
602 		key_buf[4] &= ~0x0004;
603 
604 
605 	if (! repeat_mode)
606 		/* reset REPEAT timer if the REPEAT key is not pressed */
607 		repeat_timer = 0;
608 
609 	if (!(m_last_key_pressed & 0x80) && (key_buf[m_last_key_pressed >> 4] & (1 << (m_last_key_pressed & 0xf))))
610 	{
611 		/* last key has not been released */
612 		if (modifier_state == m_last_modifier_state)
613 		{
614 			/* handle REPEAT mode if applicable */
615 			if ((repeat_mode) && (++repeat_timer == repeat_delay))
616 			{
617 				if (m_keyboard_data_ready)
618 				{   /* keyboard buffer full */
619 					repeat_timer--;
620 				}
621 				else
622 				{   /* repeat current key */
623 					m_keyboard_data_ready = 1;
624 					repeat_timer = 0;
625 				}
626 			}
627 		}
628 		else
629 		{
630 			repeat_timer = 0;
631 			m_last_modifier_state = special_debounce;
632 		}
633 	}
634 	else
635 	{
636 		m_last_key_pressed = 0x80;
637 
638 		if (m_keyboard_data_ready)
639 		{   /* keyboard buffer full */
640 			/* do nothing */
641 		}
642 		else
643 		{
644 			for (i=0; i<6; i++)
645 			{
646 				for (j=0; j<16; j++)
647 				{
648 					if (key_buf[i] & (1 << j))
649 					{
650 						m_last_key_pressed = (i << 4) | j;
651 						m_last_modifier_state = modifier_state;
652 
653 						m_keyboard_data = (int)key_translate[unsigned(m_model)][modifier_state][m_last_key_pressed];
654 						m_keyboard_data_ready = 1;
655 						if (m_keyboard_interrupt_enable)
656 							m_keyint_line(ASSERT_LINE);
657 						return;
658 					}
659 				}
660 			}
661 		}
662 	}
663 }
664 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)665 uint32_t vdt911_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
666 {
667 	refresh(bitmap, cliprect, 0, 0);
668 	return 0;
669 }
670 
671 INPUT_PORTS_START( vdt911 )
672 	PORT_START( "LOCALE" )
673 	PORT_CONFNAME( 0x0f, 0x00, "Terminal language" )
ioport_value(vdt911_device::model::US)674 		PORT_CONFSETTING( ioport_value(vdt911_device::model::US), "English US" )
675 		PORT_CONFSETTING( ioport_value(vdt911_device::model::UK), "English UK" )
676 		PORT_CONFSETTING( ioport_value(vdt911_device::model::French), "French" )
677 		PORT_CONFSETTING( ioport_value(vdt911_device::model::German), "German" )
678 		PORT_CONFSETTING( ioport_value(vdt911_device::model::Swedish), "Swedish" )
679 		PORT_CONFSETTING( ioport_value(vdt911_device::model::Norwegian), "Norwegian" )
680 		PORT_CONFSETTING( ioport_value(vdt911_device::model::Japanese), "Japanese" )
681 		// PORT_CONFSETTING( ioport_value(vdt911_device::model::Arabic), "Arabic" )
682 		PORT_CONFSETTING( ioport_value(vdt911_device::model::FrenchWP), "French Word Processing" )
683 
684 	PORT_START( "SCREEN" )
685 	PORT_CONFNAME( 0x01, ioport_value(vdt911_device::screen_size::char_960), "Terminal screen size" )
686 		PORT_CONFSETTING( ioport_value(vdt911_device::screen_size::char_960), "960 chars (12 lines)")
687 		PORT_CONFSETTING( ioport_value(vdt911_device::screen_size::char_1920), "1920 chars (24 lines)")
688 
689 	PORT_START("KEY0")  /* keys 1-16 */                                                                 \
690 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F1") PORT_CODE(KEYCODE_F1)        \
691 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F2") PORT_CODE(KEYCODE_F2)        \
692 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F3") PORT_CODE(KEYCODE_F3)        \
693 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F4") PORT_CODE(KEYCODE_F4)        \
694 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F5") PORT_CODE(KEYCODE_F5)        \
695 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F6") PORT_CODE(KEYCODE_F6)        \
696 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F7") PORT_CODE(KEYCODE_F7)        \
697 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F8") PORT_CODE(KEYCODE_F8)        \
698 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CMD") PORT_CODE(KEYCODE_F9)       \
699 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(red)") PORT_CODE(KEYCODE_F10)        \
700 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE FIELD") PORT_CODE(KEYCODE_END)  \
701 		PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ERASE INPUT") PORT_CODE(KEYCODE_PGDN) \
702 		PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(grey)") PORT_CODE(KEYCODE_F11)       \
703 		PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UPPER CAPS LOCK") PORT_CODE(KEYCODE_CAPSLOCK)  PORT_TOGGLE\
704 		PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1)        \
705 		PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 @") PORT_CODE(KEYCODE_2)        \
706 																								\
707 	PORT_START("KEY1")  /* keys 17-32 */                                                                \
708 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 #") PORT_CODE(KEYCODE_3)        \
709 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4)        \
710 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5)        \
711 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6)        \
712 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7)        \
713 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8)        \
714 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9)        \
715 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0)        \
716 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ [") PORT_CODE(KEYCODE_MINUS)    \
717 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- ]") PORT_CODE(KEYCODE_EQUALS)   \
718 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("_ =") PORT_CODE(KEYCODE_BACKSPACE)    \
719 		PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESC") PORT_CODE(KEYCODE_ESC)      \
720 		PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 (numpad)") PORT_CODE(KEYCODE_7_PAD) \
721 		PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 (numpad)") PORT_CODE(KEYCODE_8_PAD) \
722 		PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (numpad)") PORT_CODE(KEYCODE_9_PAD) \
723 		PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("PRINT") PORT_CODE(KEYCODE_PRTSCR) \
724 																								\
725 	PORT_START("KEY2")  /* keys 33-48 */                                                                \
726 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(up)") PORT_CODE(KEYCODE_UP)      \
727 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("REPEAT") PORT_CODE(KEYCODE_LALT)  \
728 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ENTER") PORT_CODE(KEYCODE_ENTER_PAD)  \
729 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)      \
730 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W)      \
731 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E)      \
732 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R)      \
733 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T)      \
734 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)      \
735 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U)      \
736 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I)      \
737 		PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O)      \
738 		PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P)      \
739 		PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CHAR (left/right)") PORT_CODE(KEYCODE_OPENBRACE)  \
740 		PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("FIELD (left/right)") PORT_CODE(KEYCODE_CLOSEBRACE)    \
741 		PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER) \
742 																								\
743 	PORT_START("KEY3")  /* keys 49-64 */                                                                \
744 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 (numpad)") PORT_CODE(KEYCODE_4_PAD) \
745 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 (numpad)") PORT_CODE(KEYCODE_5_PAD) \
746 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 (numpad)") PORT_CODE(KEYCODE_6_PAD) \
747 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(left)") PORT_CODE(KEYCODE_LEFT)  \
748 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME)    \
749 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(right)") PORT_CODE(KEYCODE_RIGHT)    \
750 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) \
751 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A)      \
752 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S)      \
753 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D)      \
754 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F)      \
755 		PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G)      \
756 		PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H)      \
757 		PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J)      \
758 		PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K)      \
759 		PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L)      \
760 																								\
761 	PORT_START("KEY4")  /* keys 65-80 */                                                                \
762 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("; :") PORT_CODE(KEYCODE_COLON)    \
763 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("' \"") PORT_CODE(KEYCODE_QUOTE)   \
764 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_BACKSLASH)   \
765 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SKIP TAB") PORT_CODE(KEYCODE_TAB) \
766 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 (numpad)") PORT_CODE(KEYCODE_1_PAD) \
767 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 (numpad)") PORT_CODE(KEYCODE_2_PAD) \
768 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3 (numpad)") PORT_CODE(KEYCODE_3_PAD) \
769 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("INS CHAR") PORT_CODE(KEYCODE_INSERT)  \
770 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(down)") PORT_CODE(KEYCODE_DOWN)  \
771 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL CHAR") PORT_CODE(KEYCODE_DEL) \
772 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) \
773 		PORT_BIT(0x0800, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)      \
774 		PORT_BIT(0x1000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X)      \
775 		PORT_BIT(0x2000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)      \
776 		PORT_BIT(0x4000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V)      \
777 		PORT_BIT(0x8000, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B)      \
778 																								\
779 	PORT_START("KEY5")  /* keys 81-91 */                                                                \
780 		PORT_BIT(0x0001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N)      \
781 		PORT_BIT(0x0002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M)      \
782 		PORT_BIT(0x0004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(", <") PORT_CODE(KEYCODE_COMMA)    \
783 		PORT_BIT(0x0008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". >") PORT_CODE(KEYCODE_STOP) \
784 		PORT_BIT(0x0010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ ?") PORT_CODE(KEYCODE_SLASH)    \
785 		PORT_BIT(0x0020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_RSHIFT) \
786 		PORT_BIT(0x0040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 (numpad)") PORT_CODE(KEYCODE_0_PAD) \
787 		PORT_BIT(0x0080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(". (numpad)") PORT_CODE(KEYCODE_DEL_PAD)   \
788 		PORT_BIT(0x0100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_MINUS_PAD)   \
789 		PORT_BIT(0x0200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE)  \
790 		PORT_BIT(0x0400, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("(not on US keyboard)") PORT_CODE(KEYCODE_PLUS_PAD)
791 INPUT_PORTS_END
792 
793 //-------------------------------------------------
794 //  device_add_mconfig - add device configuration
795 //-------------------------------------------------
796 
797 void vdt911_device::device_add_mconfig(machine_config &config)
798 {
799 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
800 	m_screen->set_raw(11.004_MHz_XTAL, 700, 0, 560, 262, 0, 240);
801 	m_screen->set_screen_update(FUNC(vdt911_device::screen_update));
802 	m_screen->set_palette("palette");
803 
804 	SPEAKER(config, "speaker").front_center();
805 	BEEP(config, m_beeper, 3250).add_route(ALL_OUTPUTS, "speaker", 0.50);
806 
807 	PALETTE(config, "palette", FUNC(vdt911_device::vdt911_palette), ARRAY_LENGTH(vdt911_pens), ARRAY_LENGTH(vdt911_colors));
808 }
809 
device_input_ports() const810 ioport_constructor vdt911_device::device_input_ports() const
811 {
812 	return INPUT_PORTS_NAME( vdt911 );
813 }
814