diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c
index b1fd0c94..b3eeea6c 100644
--- a/PDP11/pdp11_io_lib.c
+++ b/PDP11/pdp11_io_lib.c
@@ -867,6 +867,8 @@ AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */
{04040}, {0270} }, /* NG - vector display */
{ { "DAZ" }, 1, 1, 0, 0,
{00104} }, /* DAZ */
+ { { "TV" }, 1, 0, 0, 0,
+ {04100} }, /* TV - raster display */
{ { NULL }, -1 } /* end table */
};
diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c
index 80579fb0..56cbc549 100644
--- a/PDP11/pdp11_sys.c
+++ b/PDP11/pdp11_sys.c
@@ -122,6 +122,7 @@ extern DEVICE ch_dev;
#ifdef USE_DISPLAY
extern DEVICE ng_dev;
extern DEVICE daz_dev;
+extern DEVICE tv_dev;
#endif
extern REG cpu_reg[];
extern int32 saved_PC;
@@ -206,6 +207,7 @@ DEVICE *sim_devices[] = {
#ifdef USE_DISPLAY
&ng_dev,
&daz_dev,
+ &tv_dev,
#endif
#else
&clk_dev,
diff --git a/PDP11/pdp11_tv.c b/PDP11/pdp11_tv.c
new file mode 100644
index 00000000..4cadb7a5
--- /dev/null
+++ b/PDP11/pdp11_tv.c
@@ -0,0 +1,624 @@
+#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 uint8 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;
+
+ 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;
+ 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;
+ fprintf(stderr, "Window %d is %p\r\n", i, tv_vptr[i]);
+ 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 */
diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj
index c705c469..c27304a1 100644
--- a/Visual Studio Projects/PDP11.vcproj
+++ b/Visual Studio Projects/PDP11.vcproj
@@ -373,6 +373,10 @@
RelativePath="..\PDP11\pdp11_tu.c"
>
+
+
diff --git a/makefile b/makefile
index 28d2a45e..57d3b3ec 100644
--- a/makefile
+++ b/makefile
@@ -1440,7 +1440,7 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \
${PDP11D}/pdp11_kmc.c ${PDP11D}/pdp11_dup.c ${PDP11D}/pdp11_rs.c \
${PDP11D}/pdp11_vt.c ${PDP11D}/pdp11_td.c ${PDP11D}/pdp11_io_lib.c \
${PDP11D}/pdp11_rom.c ${PDP11D}/pdp11_ch.c ${PDP11D}/pdp11_dh.c \
- ${PDP11D}/pdp11_ng.c ${PDP11D}/pdp11_daz.c \
+ ${PDP11D}/pdp11_ng.c ${PDP11D}/pdp11_daz.c ${PDP11D}/pdp11_tv.c \
${DISPLAYL} ${DISPLAYNG} ${DISPLAYVT}
PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} ${DISPLAY_OPT}