simh-testsetgenerator/PDP10/ka10_dd.c
Richard Cornwell 1cb2f3b96c KA10: Fix divide error on KS10, add in some devices.
Fix divide of 0 on KS10 processor.
       Fix write access for auxiliary processor memory.
       Updated support new PIDP10 panel.
       Allow eight Unibux ports on the TEN device.
       Added GE DATANET-760 device to PDP6
       Removed USER mode restriction for idle detection.
       Added Data Disc 6600 Television Display System.
2024-05-21 17:06:39 -04:00

756 lines
24 KiB
C

/* ka10_dd.c: Data Disc 6600 Television Display System, with
PDP-10 interface and video switch made at Stanford AI lab.
Copyright (c) 2022-2023, 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
LARS BRINKHOFF 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 name of Lars Brinkhoff shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Lars Brinkhoff.
*/
#include "kx10_defs.h"
#ifndef NUM_DEVS_DD
#define NUM_DEVS_DD 0
#endif
#if NUM_DEVS_DD > 0
#include "sim_video.h"
#define DD_DEVNUM 0510
#define VDS_DEVNUM 0340
#define DD_WIDTH 512 /* Display width. */
#define DD_HEIGHT 480 /* Display height. */
#define DD_PIXELS (DD_WIDTH * DD_HEIGHT) /* Total number of pixels. */
#define DD_CHANNELS 32 /* Data Disc channels. */
#define DD_COLUMNS 85
#define FONT_WIDTH 6
#define FONT_HEIGHT 12
#define MARGIN 2
#define VDS_OUTPUTS 64 /* Video switch outputs. */
#define III_DISPLAYS 6
#define STATUS u3
#define MA u4 /* Current memory address. */
#define PIA u5
#define COLUMN u6
#define LINE us9
#define CHANNEL us10
/* CONI/O Bits */
#define DD_HALT 000000010 /* CONI: Halted. */
#define DD_RESET 000000010 /* CONO: Reset. */
#define DD_INT 000000020 /* CONI: Interrupting. */
#define DD_FORCE 000000020 /* CONO: Force field. */
#define DD_FIELD 000000040 /* CONI: Field. */
#define DD_HALT_ENA 000000100 /* CONI: Halt interrupt enabled. */
#define DD_DDGO 000000100 /* CONO: Go. */
#define DD_LATE 000000200 /* CONI: Late. */
#define DD_SPGO 000000200 /* CONO */
#define DD_LATE_ENA 000000400 /* Late interrupt enabled. */
#define DD_USER 000001000 /* User mode. */
#define DD_NXM 000002000 /* CONI: Accessed non existing memory. */
/* Function codes. */
#define FC_GRAPHICS 001 /* Graphics mode. */
#define FC_WRITE 002 /* Write to disc. */
#define FC_DARK 004 /* Dark background. */
#define FC_DOUBLE_W 010 /* Double width. */
#define FC_ERASE 010 /* Erase graphics. */
#define FC_ADDITIVE 020 /* Additive graphics. */
#define FC_SINGLE_H 040 /* Single height. */
/* There are 64 displays, fed from the video switch. */
static uint32 vds_surface[VDS_OUTPUTS][DD_PIXELS];
static uint32 vds_palette[VDS_OUTPUTS][2];
static VID_DISPLAY *vds_vptr[VDS_OUTPUTS];
/* There are 32 channels on the Data Disc. */
static uint8 dd_channel[DD_CHANNELS][DD_PIXELS];
static uint8 dd_changed[DD_CHANNELS];
static int dd_windows = 1;
static uint8 dd_function_code = 0;
static uint16 dd_line_buffer[DD_COLUMNS + 1];
static int dd_line_buffer_address = 0;
static int dd_line_buffer_written = 0;
#define WRITTEN 0400
uint32 vds_channel; /* Currently selected video outputs. */
uint8 vds_changed[VDS_OUTPUTS];
uint32 vds_selection[VDS_OUTPUTS]; /* Data Disc channels. */
uint32 vds_sync_inhibit[VDS_OUTPUTS];
uint32 vds_analog[VDS_OUTPUTS]; /* Analog channel. */
#include "ka10_dd_font.h"
static t_stat dd_set_windows (UNIT *uptr, int32 val, CONST char *cptr, void *desc) ;
static t_stat dd_show_windows (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static void dd_chargen (char c, int column);
static void dd_graphics (uint8 data, int column);
static t_stat dd_devio(uint32 dev, uint64 *data);
static t_stat vds_devio(uint32 dev, uint64 *data);
static t_stat dd_svc(UNIT *uptr);
static t_stat vds_svc(UNIT *uptr);
static t_stat dd_reset(DEVICE *dptr);
static t_stat vds_reset(DEVICE *dptr);
static t_stat dd_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
static t_stat vds_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
static const char *dd_description (DEVICE *dptr);
static const char *vds_description (DEVICE *dptr);
DIB dd_dib = { DD_DEVNUM, 1, dd_devio, NULL};
UNIT dd_unit = {
UDATA (&dd_svc, UNIT_IDLE, 0)
};
MTAB dd_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "WINDOWS", "WINDOWS",
&dd_set_windows, &dd_show_windows, NULL},
{ 0 }
};
DEVICE dd_dev = {
"DD", &dd_unit, NULL, dd_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, dd_reset,
NULL, NULL, NULL, &dd_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_DISPLAY, 0, dev_debug,
NULL, NULL, &dd_help, NULL, NULL, &dd_description
};
UNIT vds_unit = {
UDATA (&vds_svc, UNIT_IDLE, 0)
};
DIB vds_dib = { VDS_DEVNUM, 1, vds_devio, NULL};
DEVICE vds_dev = {
"VDS", &vds_unit, NULL, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, vds_reset,
NULL, NULL, NULL, &vds_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_DISPLAY, 0, dev_debug,
NULL, NULL, &vds_help, NULL, NULL, &vds_description
};
static void unimplemented (const char *text)
{
fprintf (stderr, "\r\n[UNIMPLEMENTED: %s]\r\n", text);
}
static void
dd_hang (const char *msg)
{
sim_debug(DEBUG_CMD, &dd_dev, "HANG: %s\n", msg);
dd_unit.STATUS |= DD_HALT;
}
static void
dd_halt (const char *msg)
{
sim_debug(DEBUG_CMD, &dd_dev, "HALT: %s\n", msg);
dd_unit.STATUS |= DD_HALT;
}
static void
dd_execute (const char *msg)
{
int i;
sim_debug(DEBUG_CMD, &dd_dev, "%s; %s mode\n",
msg, (dd_function_code & FC_GRAPHICS) ? "graphics" : "text");
if (dd_unit.LINE >= DD_HEIGHT)
return;
if (dd_function_code & FC_GRAPHICS) {
for (i = 1; i <= 64; i++) {
if (dd_line_buffer[i] & WRITTEN)
dd_graphics (dd_line_buffer[i] & 0377, i - 1);
}
} else {
for (i = 1; i <= DD_COLUMNS; i++) {
if (dd_line_buffer[i] & WRITTEN)
dd_chargen (dd_line_buffer[i] & 0177, i - 1);
}
}
memset (dd_line_buffer, 0, sizeof dd_line_buffer);
dd_line_buffer_address = 1;
dd_line_buffer_written = 0;
}
static t_stat
dd_devio(uint32 dev, uint64 *data) {
UNIT *uptr = &dd_unit;
switch(dev & 3) {
case CONI:
*data = uptr->PIA | uptr->STATUS;
sim_debug (DEBUG_CONI, &dd_dev, "%06llo (%6o)\n", *data, PC);
break;
case CONO:
sim_debug (DEBUG_CONO, &dd_dev, "%06llo (%6o)\n", *data, PC);
uptr->STATUS &= ~DD_HALT;
clr_interrupt (DD_DEVNUM);
uptr->PIA = (uint32)(*data & 7);
if (*data & DD_RESET) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Reset.\n");
uptr->PIA = 0;
uptr->STATUS = 0;
uptr->COLUMN = dd_line_buffer_address = 1;
uptr->LINE = 0;
dd_function_code = 0;
sim_cancel (uptr);
}
if (*data & DD_FORCE) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Force field.\n");
}
if (*data & 040) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Halt interrupt enabled.\n");
uptr->STATUS |= DD_HALT_ENA;
}
if (*data & DD_DDGO) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Go.\n");
}
if (*data & DD_SPGO) {
sim_debug(DEBUG_DETAIL, &dd_dev, "SPGO\n");
}
if (*data & DD_LATE_ENA) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Late interrupt enabled.\n");
uptr->STATUS |= DD_LATE_ENA;
}
if (*data & DD_USER) {
sim_debug(DEBUG_DETAIL, &dd_dev, "User mode.\n");
uptr->STATUS |= DD_USER;
}
break;
case DATAI:
*data = 0;
sim_debug(DEBUG_DATAIO, &dd_dev, "DATAI (%6o)\n", PC);
break;
case DATAO:
uptr->MA = *data & 0777777;
sim_debug(DEBUG_DATAIO, &dd_dev, "DATAO %06o (%6o)\n", uptr->MA, PC);
if (uptr->STATUS & DD_DDGO)
sim_activate (uptr, 1);
break;
}
return SCPE_OK;
}
static void
dd_pixel (int x, int y, uint8 pixel)
{
if (x >= DD_WIDTH)
return;
if (y >= DD_HEIGHT)
return;
pixel &= 1;
if (!(dd_function_code & FC_DARK))
pixel ^= 1;
if (dd_function_code & FC_ADDITIVE)
dd_channel[dd_unit.CHANNEL][DD_WIDTH * y + x] |= pixel;
else
dd_channel[dd_unit.CHANNEL][DD_WIDTH * y + x] = pixel;
dd_changed[dd_unit.CHANNEL] = 1;
}
static void
dd_chargen (char c, int column)
{
int i, j;
uint8 pixels;
int line = dd_unit.LINE;
int field = line & 1;
if (line >= DD_HEIGHT || column >= DD_COLUMNS)
return;
sim_debug (DEBUG_DETAIL, &dd_dev, "CHARGEN %03o %d@(%d,%d)\n",
c, dd_unit.CHANNEL, column, dd_unit.LINE);
for (i = 0; i < FONT_HEIGHT-1; i += 2, line += 2) {
pixels = font[c][i + field];
for (j = 0; j < FONT_WIDTH-1; j++) {
dd_pixel (6 * column + j, line, pixels >> 4);
pixels <<= 1;
}
}
}
static void
dd_byte (uint8 data)
{
int max = (dd_function_code & FC_GRAPHICS) ? 64 : DD_COLUMNS;
if (dd_line_buffer_address <= max) {
sim_debug(DEBUG_DETAIL, &dd_dev, "Buffer[%d] %03o\n",
dd_line_buffer_address, data);
dd_line_buffer[dd_line_buffer_address] = data | WRITTEN;
}
dd_line_buffer_address++;
dd_line_buffer_address &= 0177;
}
static void
dd_text (uint64 insn)
{
int rubout = 0;
char text[6];
int i;
text[0] = (insn >> 29) & 0177;
text[1] = (insn >> 22) & 0177;
text[2] = (insn >> 15) & 0177;
text[3] = (insn >> 8) & 0177;
text[4] = (insn >> 1) & 0177;
text[5] = 0;
sim_debug(DEBUG_CMD, &dd_dev, "TEXT \"%s\" to %d@(%d,%d)\n",
text, dd_unit.CHANNEL, dd_unit.COLUMN, dd_unit.LINE);
for (i = 0; i < 5; i++) {
switch (text[i]) {
case 000:
case 0177:
sim_debug (DEBUG_DETAIL, &dd_dev, "CHAR %03o ignored\n", text[i]);
break;
case 012:
if (rubout)
goto print;
if (dd_line_buffer_written) {
sim_debug (DEBUG_DETAIL, &dd_dev, "LF clear rest of line\n");
while (dd_line_buffer_address <= DD_COLUMNS)
dd_byte (040);
dd_execute ("LF execute");
}
dd_unit.LINE += FONT_HEIGHT;
if (!(dd_function_code & FC_SINGLE_H))
dd_unit.LINE += FONT_HEIGHT;
dd_unit.LINE &= 0777;
sim_debug (DEBUG_DETAIL, &dd_dev, "CHAR 012 LF -> (%d,%d)\n",
dd_unit.COLUMN, dd_unit.LINE);
break;
case 015:
if (rubout)
goto print;
if (dd_line_buffer_written) {
sim_debug (DEBUG_DETAIL, &dd_dev, "CR clear rest of line\n");
while (dd_line_buffer_address <= DD_COLUMNS)
dd_byte (040);
dd_execute ("CR execute");
}
dd_unit.COLUMN = dd_line_buffer_address = MARGIN;
sim_debug (DEBUG_DETAIL, &dd_dev, "CHAR 015 CR -> (%d,%d)\n",
dd_unit.COLUMN, dd_unit.LINE);
break;
case 010:
case 011:
if (!rubout)
break;
/* Fall through. */
default:
print:
{
char ch[2];
memset (ch, 0, 2);
if (text[i] > 040 && text[i] < 0177)
ch[0] = text[i];
sim_debug (DEBUG_DETAIL, &dd_dev, "CHAR %03o %s (%d,%d)\n",
text[i], ch, dd_line_buffer_address, dd_unit.LINE);
}
dd_byte (text[i]);
dd_line_buffer_written = 1;
dd_unit.COLUMN++;
dd_unit.COLUMN &= 0177;
break;
}
rubout = (text[i] == 0177);
}
}
static void
dd_graphics (uint8 data, int column)
{
int i, j;
sim_debug (DEBUG_CMD, &dd_dev, "GRAPHICS %03o %d@(%d,%d)\n",
data, dd_unit.CHANNEL, column, dd_unit.LINE);
column = 8 * column + 4;
for (i = 0; i < 8; i++) {
dd_pixel (column, dd_unit.LINE, data >> 7);
column++;
data <<= 1;
}
}
static void
dd_function (uint8 data)
{
dd_function_code = data;
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: function code %03o\n", data);
if (data & FC_GRAPHICS)
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: graphics mode\n");
else
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: text mode\n");
if (data & FC_WRITE)
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: write to disc\n");
else
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: write to display\n");
if (data & FC_DARK)
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: dark background\n");
else
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: light background\n");
switch (data & (FC_GRAPHICS|FC_DOUBLE_W)) {
case 000:
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: single width\n");
break;
case FC_DOUBLE_W:
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: double width\n");
break;
case FC_GRAPHICS|FC_ERASE:
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: erase\n");
break;
}
if (data & FC_ADDITIVE)
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: additive\n");
else
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: replace\n");
if (data & FC_SINGLE_H)
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: single height\n");
else
sim_debug(DEBUG_DETAIL, &dd_dev, "Function: double height\n");
}
static void
dd_command (uint32 command, uint8 data)
{
int i;
switch (command) {
case 0:
dd_execute ("COMMAND: execute");
break;
case 1:
dd_function (data);
break;
case 2:
dd_unit.CHANNEL = data & 077;
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: channel select %d\n",
dd_unit.CHANNEL);
if ((dd_function_code & (FC_GRAPHICS|FC_ERASE)) == (FC_GRAPHICS|FC_ERASE)) {
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: erase channel %d\n",
dd_unit.CHANNEL);
dd_changed[dd_unit.CHANNEL] = 1;
for (i = 0; i < DD_PIXELS; i++)
dd_channel[dd_unit.CHANNEL][i] = 0;
}
break;
case 3:
dd_unit.COLUMN = dd_line_buffer_address = data & 0177;
if (dd_unit.COLUMN == 0 || dd_unit.COLUMN > DD_COLUMNS)
dd_hang ("Text column outside bounds");
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: column select %d\n",
dd_unit.COLUMN);
break;
case 4:
dd_unit.LINE = ((data & 037) << 4) | (dd_unit.LINE & 017);
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: high order line address -> %d\n",
dd_unit.LINE);
break;
case 5:
dd_unit.LINE = (data & 017) | (dd_unit.LINE & 0760);
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: low order line address -> %d\n",
dd_unit.LINE);
break;
case 6:
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: write directly %03o (%d,%d)\n",
data, dd_unit.COLUMN, dd_unit.LINE);
dd_unit.COLUMN++;
dd_unit.COLUMN &= 0177;
break;
case 7:
dd_line_buffer_address = data & 0177;
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: line buffer address %03o\n",
dd_line_buffer_address);
break;
}
}
static void
dd_decode (uint64 insn)
{
switch (insn & 077) {
case 001: case 003: case 005: case 007:
case 011: case 013: case 015: case 017:
case 021: case 023: case 025: case 027:
case 031: case 033: case 035: case 037:
case 041: case 043: case 045: case 047:
case 051: case 053: case 055: case 057:
case 061: case 063: case 065: case 067:
case 071: case 073: case 075: case 077:
dd_text (insn);
break;
case 002: case 022: case 042: case 062:
sim_debug(DEBUG_CMD, &dd_dev, "COMMAND: graphics %012llo\n", insn >> 4);
dd_byte ((insn >> 28) & 0377);
dd_byte ((insn >> 20) & 0377);
dd_byte ((insn >> 12) & 0377);
dd_byte ((insn >> 4) & 0377);
break;
case 000: case 040: case 060:
dd_halt ("halt instruction");
break;
case 020:
dd_unit.MA = insn >> 18;
sim_debug(DEBUG_CMD, &dd_dev, "JUMP %06o\n", dd_unit.MA);
break;
case 006: case 016: case 026: case 036:
case 046: case 056: case 066: case 076:
case 012: case 032: case 052: case 072:
sim_debug(DEBUG_CMD, &dd_dev, "NOP\n");
break;
case 010: case 030: case 050: case 070:
sim_debug(DEBUG_CMD, &dd_dev, "(weird command)\n");
case 004: case 014: case 024: case 034:
case 044: case 054: case 064: case 074:
dd_command ((insn >> 9) & 7, (insn >> 28) & 0377);
dd_command ((insn >> 6) & 7, (insn >> 20) & 0377);
dd_command ((insn >> 3) & 7, (insn >> 12) & 0377);
break;
default:
sim_debug(DEBUG_CMD, &dd_dev, "(UNDOCUMENTED %012llo)\n", insn);
break;
}
}
static t_stat
dd_svc (UNIT *uptr)
{
if (uptr->MA >= MEMSIZE) {
uptr->STATUS |= DD_NXM;
dd_halt ("NXM");
} else {
dd_decode (M[uptr->MA++]);
}
if (uptr->STATUS & DD_HALT) {
uptr->STATUS |= DD_INT;
if (uptr->STATUS & DD_HALT_ENA) {
sim_debug(DEBUG_IRQ, &dd_dev, "Interrupt: halt\n");
set_interrupt (DD_DEVNUM, uptr->PIA);
}
} else
sim_activate_after (uptr, 100);
return SCPE_OK;
}
static void
dd_display (int n)
{
uint32 selection = vds_selection[n];
int i, j;
if (selection == 0) {
sim_debug(DEBUG_DETAIL, &vds_dev, "Output %d displays no channels\n", n);
return;
}
#if 1
if (!(selection & (selection - 1))) {
for (i = 0; (selection & 020000000000) == 0; i++)
selection <<= 1;
if (!dd_changed[i] && !vds_changed[n])
return;
sim_debug(DEBUG_DETAIL, &vds_dev, "Output %d from channel %d\n", n, i);
for (j = 0; j < DD_PIXELS; j++)
vds_surface[n][j] = vds_palette[n][dd_channel[i][j]];
} else {
#endif
#if 0
for (j = 0; j < DD_PIXELS; j++) {
uint8 pixel = 0;
for (i = 0; i < DD_CHANNELS; i++, selection <<= 1) {
if (selection & 020000000000)
pixel |= dd_channel[i][j];
vds_surface[n][j] = vds_palette[n][pixel];
}
}
#else
}
#endif
vid_draw_window (vds_vptr[n], 0, 0, DD_WIDTH, DD_HEIGHT, vds_surface[n]);
vid_refresh_window (vds_vptr[n]);
sim_debug (DEBUG_DETAIL, &vds_dev, "Refresh window %p\n", vds_vptr[n]);
}
static t_stat
vds_svc (UNIT *uptr)
{
int i;
for (i = III_DISPLAYS; i < dd_windows + III_DISPLAYS; i++)
dd_display (i);
for (i = 0; i < DD_CHANNELS; i++)
dd_changed[i] = 0;
for (i = 0; i < VDS_OUTPUTS; i++)
vds_changed[i] = 0;
sim_activate_after (uptr, 33333);
return SCPE_OK;
}
uint32 dd_keyboard_line (void *p)
{
int i;
VID_DISPLAY *vptr = (VID_DISPLAY *)p;
sim_debug(DEBUG_DETAIL, &vds_dev, "Key event on window %p\n", vptr);
for (i = 0; i < VDS_OUTPUTS; i++) {
if (vptr == vds_vptr[i])
return i;
}
return ~0U;
}
static t_stat
dd_reset (DEVICE *dptr)
{
if (dptr->flags & DEV_DIS || sim_switches & SWMASK('P')) {
sim_cancel (&dd_unit);
memset (dd_channel, 0, sizeof dd_channel);
memset (dd_changed, 0, sizeof dd_changed);
return SCPE_OK;
}
if (dptr->flags & DEV_DIS)
set_cmd (0, "VDS DISABLED");
else
set_cmd (0, "VDS ENABLED");
return SCPE_OK;
}
static t_stat dd_set_windows (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_value x;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
x = get_uint (cptr, 10, 32, &r);
if (r != SCPE_OK)
return r;
dd_windows = x;
return SCPE_OK;
}
static t_stat dd_show_windows (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
if (uptr == NULL)
return SCPE_IERR;
fprintf (st, "WINDOWS=%d", dd_windows);
return SCPE_OK;
}
static t_stat
dd_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
return SCPE_OK;
}
static const char *
dd_description (DEVICE *dptr)
{
return "Data Disc Television Display System";
}
static t_stat
vds_reset (DEVICE *dptr)
{
t_stat r;
int i;
if (dptr->flags & DEV_DIS || sim_switches & SWMASK('P')) {
for (i = 0; i < VDS_OUTPUTS; i++) {
if (vds_vptr[i] != NULL)
vid_close_window (vds_vptr[i]);
}
vds_channel = 0;
memset (vds_vptr, 0, sizeof vds_vptr);
memset (vds_palette, 0, sizeof vds_palette);
memset (vds_selection, 0, sizeof vds_selection);
memset (vds_sync_inhibit, 0, sizeof vds_sync_inhibit);
memset (vds_analog, 0, sizeof vds_analog);
sim_cancel (&vds_unit);
return SCPE_OK;
}
for (i = III_DISPLAYS; i < dd_windows + III_DISPLAYS; i++) {
if (vds_vptr[i] == NULL) {
char title[40];
snprintf (title, sizeof title, "Data Disc display %d", i);
r = vid_open_window (&vds_vptr[i], &dd_dev, title, DD_WIDTH, DD_HEIGHT, 0);
if (r != SCPE_OK)
return r;
fprintf(stderr, "Window %d is %p\r\n", i, vds_vptr[i]);
vds_palette[i][0] = vid_map_rgb_window (vds_vptr[i], 0x00, 0x00, 0x00);
vds_palette[i][1] = vid_map_rgb_window (vds_vptr[i], 0x00, 0xFF, 0x30);
}
}
sim_activate (&vds_unit, 1);
return SCPE_OK;
}
static t_stat
vds_devio(uint32 dev, uint64 *data)
{
switch(dev & 3) {
case CONO:
sim_debug(DEBUG_CONO, &vds_dev, "%012llo (%6o)\n", *data, PC);
vds_channel = *data & 077;
break;
case DATAO:
sim_debug(DEBUG_DATAIO, &vds_dev, "%012llo (%6o)\n", *data, PC);
vds_changed[vds_channel] = 1;
vds_selection[vds_channel] = *data >> 4;
vds_sync_inhibit[vds_channel] = (*data >> 3) & 1;
vds_analog[vds_channel] = *data & 7;
sim_debug(DEBUG_DETAIL, &vds_dev, "Output %d selection %011o\n",
vds_channel, vds_selection[vds_channel]);
#if 0
sim_debug(DEBUG_DETAIL, &vds_dev, "Sync inhibit %d\n",
vds_sync_inhibit[vds_channel]);
sim_debug(DEBUG_DETAIL, &vds_dev, "Analog %d\n",
vds_analog[vds_channel]);
#endif
break;
}
return SCPE_OK;
}
static t_stat
vds_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
return SCPE_OK;
}
static const char *
vds_description (DEVICE *dptr)
{
return "Video Switch";
}
#endif