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.
756 lines
24 KiB
C
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
|