Project standard source code has tabs converted to spaces and CRLF line endings. Other text files have CRLF line endings.
628 lines
17 KiB
C
628 lines
17 KiB
C
#ifdef USE_DISPLAY
|
|
/* pdp11_tv.c: TV, Logo TV raster display
|
|
|
|
Copyright (c) 2022, Lars Brinkhoff
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the names of the authors shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from the authors.
|
|
*/
|
|
|
|
#include "pdp11_defs.h"
|
|
#include "sim_video.h"
|
|
|
|
t_stat tv_rd(int32 *data, int32 PA, int32 access);
|
|
t_stat tv_wr(int32 data, int32 PA, int32 access);
|
|
t_stat tv_svc(UNIT *uptr);
|
|
t_stat tv_reset(DEVICE *dptr);
|
|
const char *tv_description (DEVICE *dptr);
|
|
|
|
#define TV_WINDOWS 2
|
|
#define TV_WIDTH 576 /* Display width. */
|
|
#define TV_HEIGHT 454 /* Display height. */
|
|
#define TV_PIXELS (TV_WIDTH * TV_HEIGHT) /* Total number of pixels. */
|
|
#define TV_KEYS 16 /* Max keys in buffer. */
|
|
|
|
static uint32 tv_surface[TV_WINDOWS][TV_PIXELS];
|
|
static uint32 tv_palette[TV_WINDOWS][2];
|
|
static VID_DISPLAY *tv_vptr[TV_WINDOWS];
|
|
static char tv_updated[TV_WINDOWS];
|
|
|
|
static int tv_keys = 0;
|
|
static uint16 tv_key[TV_KEYS]; /* Buffer for LKBB. */
|
|
static uint16 COLORD;
|
|
static uint16 VIDSW; /* Video switch register. */
|
|
static uint16 COLORA;
|
|
static uint8 tv_source[256];
|
|
static uint8 tv_display[256];
|
|
static uint16 TVINCR;
|
|
static uint16 TVSEL; /* Frame buffer select. */
|
|
static uint16 TVRADR;
|
|
static uint16 tvdata;
|
|
static uint16 TVWC;
|
|
static uint16 TVDADR;
|
|
static uint16 TVSHR;
|
|
static uint16 TVMSK;
|
|
static uint16 TVDWIN;
|
|
static uint16 TVRWIN;
|
|
static uint16 TVCNSL[64];
|
|
|
|
#define FB (16*1024)
|
|
static uint16 RAM[64*FB];
|
|
|
|
#define BASE ((TVSEL & 077) * FB)
|
|
|
|
/* VIDSW bits. */
|
|
// Low byte is the console number.
|
|
// High byte is the video source.
|
|
|
|
/* TVINCR bits. */
|
|
#define TVINC 0077 /* Mask for the increment. */
|
|
|
|
/* TVSEL bits. */
|
|
#define TVRCNS 0077 /* The console number mask. */
|
|
#define TVNSH 0000 /* No shift write mode. */
|
|
#define TVIOR 0100 /* The inclusive or mode. */
|
|
#define TVXOR 0200 /* The xor mode. */
|
|
#define TVMOV 0300 /* The move function. */
|
|
|
|
/* TVSHR bits. */
|
|
#define TVSHCN 0017 /* The shift count. */
|
|
|
|
/* TVCNSL bits. */
|
|
#define SCROLL 007777 /* Scroll pointer. */
|
|
#define REVSCR 010000 /* Reverse video. */
|
|
|
|
#define IOLN_TV 064
|
|
DIB tv_dib = {
|
|
IOBA_AUTO, IOLN_TV, &tv_rd, &tv_wr,
|
|
0, 0, 0, {NULL}, IOLN_TV
|
|
};
|
|
|
|
UNIT tv_unit = {
|
|
UDATA (&tv_svc, UNIT_IDLE, 0), 0
|
|
};
|
|
|
|
REG tv_reg[] = {
|
|
{ ORDATAD(LKBB, tv_key[0], 16, "Lebel keyboard interface") },
|
|
{ ORDATAD(COLORA, COLORA, 16, "Color map address") },
|
|
{ ORDATAD(VIDSW, VIDSW, 16, "Video switch") },
|
|
{ ORDATAD(COLORD, COLORD, 16, "Color map data") },
|
|
{ ORDATAD(TVINCR, TVINCR, 16, "Increment") },
|
|
{ ORDATAD(TVSEL, TVSEL, 16, "Console select") },
|
|
{ ORDATAD(TVRADR, TVRADR, 16, "Regular transfer address") },
|
|
{ ORDATAD(TVWC, TVWC, 16, "Word count") },
|
|
{ ORDATAD(TVDADR, TVDADR, 16, "Disk transfer address") },
|
|
{ ORDATAD(TVSHR, TVSHR, 16, "Shift register") },
|
|
{ ORDATAD(TVMSK, TVMSK, 16, "Mask") },
|
|
{ ORDATAD(TVDWIN, TVDWIN, 16, "Disk data window") },
|
|
{ ORDATAD(TVRWIN, TVRWIN, 16, "Regular data window") },
|
|
{ ORDATAD(TVCNSL, TVCNSL[0], 16, "Console status") },
|
|
{ NULL }
|
|
};
|
|
|
|
MTAB tv_mod[] = {
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 020, "ADDRESS", "ADDRESS",
|
|
&set_addr, &show_addr, NULL, "Bus address" },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", "VECTOR",
|
|
&set_vec, &show_vec, NULL, "Interrupt vector" },
|
|
{ MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE",
|
|
&set_addr_flt, NULL, NULL, "Enable autoconfiguration of address & vector" },
|
|
{ 0 } };
|
|
|
|
#define DBG_IO 0001
|
|
#define DBG_VID 0002
|
|
#define DBG_KEY 0004
|
|
|
|
DEBTAB tv_deb[] = {
|
|
{ "IO", DBG_IO, "IO page" },
|
|
{ "VID", DBG_VID, "video" },
|
|
{ "KEY", DBG_KEY, "keyboard" },
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
DEVICE tv_dev = {
|
|
"TV", &tv_unit, tv_reg, tv_mod,
|
|
1, 8, 16, 1, 8, 16,
|
|
NULL, NULL, &tv_reset,
|
|
NULL, NULL, NULL,
|
|
&tv_dib, DEV_DIS | DEV_DISABLE | DEV_UBUS | DEV_DEBUG,
|
|
0, tv_deb, NULL, NULL, NULL, NULL, NULL,
|
|
&tv_description
|
|
};
|
|
|
|
static void
|
|
render_word (uint8 buffer, uint16 address)
|
|
{
|
|
uint8 display = tv_display[buffer];
|
|
uint16 data;
|
|
int i;
|
|
|
|
if (display >= TV_WINDOWS)
|
|
return;
|
|
|
|
buffer &= 077;
|
|
address /= 2;
|
|
address += (TVCNSL[buffer] & SCROLL) << 2;
|
|
address &= FB-1;
|
|
data = RAM[FB * buffer + address];
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
int pixel = (data & (0100000 >> i)) ? 0 : 1;
|
|
if (TVCNSL[buffer] & REVSCR)
|
|
pixel ^= 1;
|
|
tv_surface[display][address * 16 + i] =
|
|
tv_palette[display][pixel];
|
|
}
|
|
}
|
|
|
|
static void
|
|
render_display (uint16 display)
|
|
{
|
|
uint8 buffer = tv_source[display];
|
|
int i;
|
|
if (display >= TV_WINDOWS)
|
|
return;
|
|
sim_debug (DBG_VID, &tv_dev, "Render display %d buffer %d\n",
|
|
display, buffer);
|
|
for (i = 0; i < (TV_PIXELS / 8); i += 2)
|
|
render_word (buffer, i);
|
|
tv_updated[display] = 1;
|
|
}
|
|
|
|
static void
|
|
tv_alu (void)
|
|
{
|
|
uint16 data = RAM[BASE + (TVRADR/2)];
|
|
uint16 data2 = tvdata;
|
|
int sh = (TVSHR & TVSHCN);
|
|
|
|
if (TVSEL & TVMOV)
|
|
data2 = (data2 << sh) | (data2 >> (16 - sh));
|
|
data2 &= ~TVMSK;
|
|
switch (TVSEL & TVMOV) {
|
|
case TVIOR: data |= data2; break;
|
|
case TVXOR: data ^= data2; break;
|
|
case TVNSH:
|
|
case TVMOV: data = (data & TVMSK) | data2; break;
|
|
}
|
|
RAM[BASE + (TVRADR/2)] = data;
|
|
render_word (TVSEL & 077, TVRADR);
|
|
tv_updated[tv_display[TVSEL & 077]] = 1;
|
|
TVRADR += 2 * (TVINCR & TVINC);
|
|
}
|
|
|
|
static void
|
|
tv_loop (void)
|
|
{
|
|
while (TVWC != 0) {
|
|
tv_alu ();
|
|
TVWC++;
|
|
}
|
|
}
|
|
|
|
t_stat
|
|
tv_rd(int32 *data, int32 PA, int32 access)
|
|
{
|
|
t_stat stat = SCPE_OK;
|
|
*data = 0;
|
|
switch (PA & 077) {
|
|
case 000:
|
|
if (tv_keys > 0)
|
|
*data = tv_key[--tv_keys];
|
|
else
|
|
*data = 0;
|
|
sim_debug (DBG_IO, &tv_dev, "READ LKBB %06o\n", *data);
|
|
break;
|
|
case 002:
|
|
*data = COLORD;
|
|
sim_debug (DBG_IO, &tv_dev, "READ COLORD %06o\n", *data);
|
|
break;
|
|
case 004:
|
|
*data = VIDSW;
|
|
sim_debug (DBG_IO, &tv_dev, "READ VIDSW %06o\n", *data);
|
|
break;
|
|
case 006:
|
|
*data = COLORA;
|
|
sim_debug (DBG_IO, &tv_dev, "READ COLORA %06o\n", *data);
|
|
break;
|
|
case 040:
|
|
*data = TVINCR;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVINCR %06o\n", *data);
|
|
break;
|
|
case 042:
|
|
*data = TVSEL;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVSEL %06o\n", *data);
|
|
break;
|
|
case 044:
|
|
*data = TVRADR;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVRADR %06o\n", *data);
|
|
break;
|
|
case 046:
|
|
*data = TVWC;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVWC %06o\n", *data);
|
|
break;
|
|
case 050:
|
|
*data = TVDADR;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVDADR %06o\n", *data);
|
|
break;
|
|
case 052:
|
|
*data = TVSHR;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVSHR %06o\n", *data);
|
|
break;
|
|
case 053:
|
|
*data = TVSHR >> 8;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVSHR+1 %06o\n", *data);
|
|
break;
|
|
case 054:
|
|
*data = TVMSK;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVMSK %06o\n", *data);
|
|
break;
|
|
case 056:
|
|
*data = TVDWIN;
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVDWIN %06o\n", *data);
|
|
break;
|
|
case 060:
|
|
*data = RAM[BASE + (TVRADR/2)];
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVRWIN[%06o] %06o\n",
|
|
TVRADR, *data);
|
|
break;
|
|
case 062:
|
|
*data = TVCNSL[TVSEL & 077];
|
|
sim_debug (DBG_IO, &tv_dev, "READ TVCNSL %06o\n", *data);
|
|
break;
|
|
default:
|
|
sim_debug (DBG_IO, &tv_dev, "READ %06o\n", PA);
|
|
break;
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
t_stat
|
|
tv_wr(int32 data, int32 PA, int32 access)
|
|
{
|
|
t_stat stat = SCPE_OK;
|
|
uint16 x;
|
|
const char *a = "WRITE";
|
|
if (access == WRITEB)
|
|
a = "WRITEB";
|
|
switch (PA & 077) {
|
|
case 000:
|
|
sim_debug (DBG_IO, &tv_dev, "%s LKBB %06o\n", a, data);
|
|
break;
|
|
case 002:
|
|
sim_debug (DBG_IO, &tv_dev, "%s COLORD %06o\n", a, data);
|
|
COLORD = data;
|
|
break;
|
|
case 004:
|
|
sim_debug (DBG_IO, &tv_dev, "%s VIDSW %06o\n", a, data);
|
|
tv_source[data >> 8] = data & 0377;
|
|
tv_display[data & 0377] = data >> 8;
|
|
render_display (data >> 8);
|
|
break;
|
|
case 006:
|
|
sim_debug (DBG_IO, &tv_dev, "%s COLORA %06o\n", a, data);
|
|
COLORA = data;
|
|
break;
|
|
case 040:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVINCR %06o\n", a, data);
|
|
TVINCR = data;
|
|
break;
|
|
case 042:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVSEL %06o\n", a, data);
|
|
if (access == WRITEB) {
|
|
data &= 0377;
|
|
data |= TVSEL & 0177400;
|
|
}
|
|
TVSEL = data;
|
|
break;
|
|
case 044:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVRADR %06o\n", a, data);
|
|
TVRADR = data;
|
|
break;
|
|
case 046:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVWC %06o\n", a, data);
|
|
TVWC = data;
|
|
tv_loop ();
|
|
break;
|
|
case 050:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVDADR %06o\n", a, data);
|
|
TVDADR = data;
|
|
break;
|
|
case 052:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVSHR %06o\n", a, data);
|
|
TVSHR = data;
|
|
break;
|
|
case 053:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVSHR+1 %06o\n", a, data);
|
|
TVSHR &= 0377;
|
|
TVSHR |= (data & 0377) << 8;
|
|
break;
|
|
case 054:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVMSK %06o\n", a, data);
|
|
TVMSK = data;
|
|
break;
|
|
case 056:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVDWIN %06o\n", a, data);
|
|
TVDWIN = data;
|
|
break;
|
|
case 060:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVRWIN[%06o] %06o\n",
|
|
a, TVRADR, data);
|
|
tvdata = data;
|
|
tv_alu ();
|
|
break;
|
|
case 062:
|
|
sim_debug (DBG_IO, &tv_dev, "%s TVCNSL %06o\n", a, data);
|
|
x = TVCNSL[TVSEL & 077];
|
|
TVCNSL[TVSEL & 077] = data;
|
|
if (x ^ data)
|
|
render_display (tv_display[TVSEL & 077]);
|
|
break;
|
|
default:
|
|
sim_debug (DBG_IO, &tv_dev, "%s %06o %06o\n", a, PA, data);
|
|
break;
|
|
}
|
|
return stat;
|
|
}
|
|
|
|
static void
|
|
toggle_fullscreen (VID_DISPLAY *vptr)
|
|
{
|
|
vid_set_fullscreen_window (vptr, !vid_is_fullscreen_window (vptr));
|
|
}
|
|
|
|
#define KEY(NORMAL, SHIFTED) (shifted ? (SHIFTED) : (NORMAL))
|
|
#define CTL(NORMAL, SHIFTED, CTLED) \
|
|
(control ? (CTLED) : KEY(NORMAL, SHIFTED))
|
|
|
|
static uint16
|
|
translate_key (SIM_KEY_EVENT *ev)
|
|
{
|
|
static int shifted = 0;
|
|
static int control = 0;
|
|
|
|
if (ev->state == SIM_KEYPRESS_UP) {
|
|
switch (ev->key) {
|
|
case SIM_KEY_F11:
|
|
toggle_fullscreen (ev->vptr);
|
|
break;
|
|
case SIM_KEY_SHIFT_L:
|
|
case SIM_KEY_SHIFT_R:
|
|
shifted = 0;
|
|
break;
|
|
case SIM_KEY_CTRL_L:
|
|
case SIM_KEY_CTRL_R:
|
|
case SIM_KEY_CAPS_LOCK:
|
|
control = 0;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
switch (ev->key) {
|
|
case SIM_KEY_SHIFT_L:
|
|
case SIM_KEY_SHIFT_R:
|
|
shifted = 1;
|
|
return 0;
|
|
case SIM_KEY_CTRL_L:
|
|
case SIM_KEY_CTRL_R:
|
|
case SIM_KEY_CAPS_LOCK:
|
|
control = 1;
|
|
return 0;
|
|
case SIM_KEY_0:
|
|
return KEY (0060, 0004);
|
|
case SIM_KEY_1:
|
|
return KEY (0061, 0041);
|
|
case SIM_KEY_2:
|
|
return KEY (0062, 0052);
|
|
case SIM_KEY_3:
|
|
return KEY (0063, 0043);
|
|
case SIM_KEY_4:
|
|
return KEY (0064, 0044);
|
|
case SIM_KEY_5:
|
|
return KEY (0065, 0045);
|
|
case SIM_KEY_6:
|
|
return CTL (0066, 0137, 0037);
|
|
case SIM_KEY_7:
|
|
return KEY (0067, 0136);
|
|
case SIM_KEY_8:
|
|
return KEY (0070, 0030);
|
|
case SIM_KEY_9:
|
|
return KEY (0071, 0003);
|
|
case SIM_KEY_A:
|
|
return CTL (0141, 0101, 0000);
|
|
case SIM_KEY_B:
|
|
return CTL (0142, 0102, 0000);
|
|
case SIM_KEY_C:
|
|
return CTL (0143, 0103, 0000);
|
|
case SIM_KEY_D:
|
|
return CTL (0144, 0104, 0002);
|
|
case SIM_KEY_E:
|
|
return CTL (0145, 0105, 0000);
|
|
case SIM_KEY_F:
|
|
return CTL (0146, 0106, 0014);
|
|
case SIM_KEY_G:
|
|
return CTL (0147, 0107, 0034);
|
|
case SIM_KEY_H:
|
|
return CTL (0150, 0110, 0000);
|
|
case SIM_KEY_I:
|
|
return CTL (0151, 0111, 0012);
|
|
case SIM_KEY_J:
|
|
return CTL (0152, 0112, 0007);
|
|
case SIM_KEY_K:
|
|
return CTL (0153, 0113, 0000);
|
|
case SIM_KEY_L:
|
|
return CTL (0154, 0114, 0013);
|
|
case SIM_KEY_M:
|
|
return CTL (0155, 0115, 0015);
|
|
case SIM_KEY_N:
|
|
return CTL (0156, 0116, 0000);
|
|
case SIM_KEY_O:
|
|
return CTL (0157, 0117, 0000);
|
|
case SIM_KEY_P:
|
|
return CTL (0160, 0120, 0000);
|
|
case SIM_KEY_Q:
|
|
return CTL (0161, 0121, 0000);
|
|
case SIM_KEY_R:
|
|
return CTL (0162, 0122, 0000);
|
|
case SIM_KEY_S:
|
|
return CTL (0163, 0123, 0000);
|
|
case SIM_KEY_T:
|
|
return CTL (0164, 0124, 0000);
|
|
case SIM_KEY_U:
|
|
return CTL (0165, 0125, 0177);
|
|
case SIM_KEY_V:
|
|
return CTL (0166, 0126, 0000);
|
|
case SIM_KEY_W:
|
|
return CTL (0167, 0127, 0000);
|
|
case SIM_KEY_X:
|
|
return CTL (0170, 0130, 0000);
|
|
case SIM_KEY_Y:
|
|
return CTL (0171, 0131, 0000);
|
|
case SIM_KEY_Z:
|
|
return CTL (0172, 0132, 0000);
|
|
case SIM_KEY_BACKQUOTE:
|
|
return KEY (0050, 0051);
|
|
case SIM_KEY_MINUS:
|
|
return CTL (0020, 0033, 005);
|
|
case SIM_KEY_EQUALS:
|
|
return KEY (0055, 0001);
|
|
case SIM_KEY_LEFT_BRACKET:
|
|
return CTL (0133, 0000, 0011);
|
|
case SIM_KEY_RIGHT_BRACKET:
|
|
return CTL (0134, 0000, 0036);
|
|
case SIM_KEY_SEMICOLON:
|
|
return KEY (0042, 0047);
|
|
case SIM_KEY_SINGLE_QUOTE:
|
|
return KEY (0046, 0073);
|
|
case SIM_KEY_BACKSLASH:
|
|
case SIM_KEY_LEFT_BACKSLASH:
|
|
return CTL (0032, 0176, 0035);
|
|
case SIM_KEY_COMMA:
|
|
return KEY (0054, 0075);
|
|
case SIM_KEY_PERIOD:
|
|
return KEY (0056, 0140);
|
|
case SIM_KEY_SLASH:
|
|
return KEY (0027, 0057);
|
|
case SIM_KEY_ESC:
|
|
case SIM_KEY_F1:
|
|
return 011;
|
|
case SIM_KEY_BACKSPACE:
|
|
case SIM_KEY_DELETE:
|
|
return 031;
|
|
case SIM_KEY_TAB:
|
|
return 012;
|
|
case SIM_KEY_ENTER:
|
|
return 015;
|
|
case SIM_KEY_SPACE:
|
|
return 040;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static uint16
|
|
keyboard_number (VID_DISPLAY *vptr, uint16 code)
|
|
{
|
|
int i;
|
|
for (i = 0; i < TV_WINDOWS; i++) {
|
|
if (vptr == tv_vptr[i])
|
|
return code | (i << 8);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
t_stat tv_svc(UNIT *uptr)
|
|
{
|
|
SIM_KEY_EVENT ev;
|
|
uint16 key;
|
|
int i;
|
|
|
|
for (i = 0; i < TV_WINDOWS; i++) {
|
|
if (!tv_updated[i])
|
|
continue;
|
|
vid_draw_window (tv_vptr[i], 0, 0, TV_WIDTH, TV_HEIGHT, tv_surface[i]);
|
|
vid_refresh_window (tv_vptr[i]);
|
|
tv_updated[i] = 0;
|
|
sim_debug (DBG_VID, &tv_dev, "Display %d refreshed.\n", i);
|
|
}
|
|
|
|
while (vid_poll_kb (&ev) == SCPE_OK) {
|
|
key = translate_key (&ev);
|
|
if (key != 0)
|
|
key = keyboard_number (ev.vptr, key);
|
|
sim_debug (DBG_KEY, &tv_dev, "Keyboard %06o.\n", key);
|
|
if (tv_keys < TV_KEYS)
|
|
tv_key[tv_keys++] = key;
|
|
}
|
|
|
|
sim_activate_after (&tv_unit, 10000);
|
|
|
|
return SCPE_OK;
|
|
}
|
|
|
|
t_stat tv_reset(DEVICE *dptr)
|
|
{
|
|
t_stat r;
|
|
int i;
|
|
|
|
if (dptr->flags & DEV_DIS || sim_switches & SWMASK('P')) {
|
|
for (i = 0; i < TV_WINDOWS; i++) {
|
|
if (tv_vptr[i] != NULL)
|
|
vid_close_window (tv_vptr[i]);
|
|
}
|
|
memset (tv_vptr, 0, sizeof tv_vptr);
|
|
memset (tv_palette, 0, sizeof tv_palette);
|
|
memset (tv_updated, 0, sizeof tv_updated);
|
|
sim_cancel (&tv_unit);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
for (i = 0; i < TV_WINDOWS; i++) {
|
|
if (tv_vptr[i] == NULL) {
|
|
char title[40];
|
|
snprintf (title, sizeof title, "Display %d", i);
|
|
r = vid_open_window (&tv_vptr[i], &tv_dev, title, TV_WIDTH, TV_HEIGHT, 0);
|
|
if (r != SCPE_OK)
|
|
return r;
|
|
tv_palette[i][0] = vid_map_rgb_window (tv_vptr[i], 0x00, 0x00, 0x00);
|
|
tv_palette[i][1] = vid_map_rgb_window (tv_vptr[i], 0x00, 0xFF, 0x30);
|
|
memset (TVCNSL, 0, sizeof TVCNSL);
|
|
memset (tv_source, 0, sizeof tv_source);
|
|
memset (tv_display, 0, sizeof tv_display);
|
|
render_display (i);
|
|
}
|
|
}
|
|
|
|
tv_keys = 0;
|
|
|
|
sim_activate (&tv_unit, 1);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
const char *tv_description (DEVICE *dptr)
|
|
{
|
|
return "Raster display controller for MIT Logo PDP-11/45";
|
|
}
|
|
|
|
#else /* USE_DISPLAY not defined */
|
|
char pdp11_tv_unused; /* sometimes empty object modules cause problems */
|
|
#endif /* USE_DISPLAY not defined */
|