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.
This commit is contained in:
Richard Cornwell 2024-05-19 14:18:37 -04:00 committed by Paul Koning
parent 9515201238
commit 1cb2f3b96c
29 changed files with 7066 additions and 304 deletions

View file

@ -103,6 +103,8 @@ add_simulator(pdp10-ka
${KA10D}/kx10_disk.c ${KA10D}/kx10_disk.c
${KA10D}/ka10_pclk.c ${KA10D}/ka10_pclk.c
${KA10D}/ka10_tv.c ${KA10D}/ka10_tv.c
${KA10D}/ka10_dd.c
${KA10D}/kx10_ddc.c
${DISPLAY340} ${DISPLAY340}
${DISPLAYIII} ${DISPLAYIII}
INCLUDES INCLUDES
@ -149,6 +151,8 @@ add_simulator(pdp10-ki
${KI10D}/kx10_imp.c ${KI10D}/kx10_imp.c
${KI10D}/kx10_dpy.c ${KI10D}/kx10_dpy.c
${KI10D}/kx10_disk.c ${KI10D}/kx10_disk.c
${KI10D}/kx10_ddc.c
${KI10D}/kx10_tym.c
${DISPLAY340} ${DISPLAY340}
INCLUDES INCLUDES
${KI10D} ${KI10D}
@ -236,6 +240,7 @@ add_simulator(pdp6
${PDP6D}/pdp6_dcs.c ${PDP6D}/pdp6_dcs.c
${PDP6D}/kx10_dpy.c ${PDP6D}/kx10_dpy.c
${PDP6D}/pdp6_slave.c ${PDP6D}/pdp6_slave.c
${PDP6D}/pdp6_ge.c
${DISPLAY340} ${DISPLAY340}
INCLUDES INCLUDES
${PDP6D} ${PDP6D}

756
PDP10/ka10_dd.c Normal file
View file

@ -0,0 +1,756 @@
/* 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

1858
PDP10/ka10_dd_font.c Normal file

File diff suppressed because it is too large Load diff

134
PDP10/ka10_dd_font.h Normal file
View file

@ -0,0 +1,134 @@
/* ka10_dd_font.h: Font data for Data Disc 6600 Television Display System.
Copyright (c) 2022-2023, Lars Brinkhoff */
static uint8 font[128][12] = {
{ 000, 000, 037, 021, 025, 021, 037, 000, 000, 000, 000, 000 }, // 000
{ 000, 004, 004, 004, 025, 016, 004, 000, 000, 000, 000, 000 }, // 001
{ 000, 000, 000, 015, 022, 022, 015, 000, 000, 000, 000, 000 }, // 002
{ 000, 006, 011, 016, 011, 011, 016, 010, 000, 000, 000, 000 }, // 003
{ 000, 000, 004, 012, 021, 000, 000, 000, 000, 000, 000, 000 }, // 004
{ 000, 000, 000, 037, 001, 001, 000, 000, 000, 000, 000, 000 }, // 005
{ 000, 000, 007, 010, 016, 010, 007, 000, 000, 000, 000, 000 }, // 006
{ 000, 000, 037, 012, 012, 012, 011, 000, 000, 000, 000, 000 }, // 007
{ 000, 020, 010, 004, 012, 021, 021, 000, 000, 000, 000, 000 }, // 010
{ 000, 034, 010, 016, 015, 006, 005, 006, 000, 000, 000, 000 }, // 011
{ 000, 020, 020, 027, 034, 007, 004, 004, 000, 000, 000, 000 }, // 012
{ 000, 012, 012, 004, 007, 002, 002, 002, 000, 000, 000, 000 }, // 013
{ 000, 034, 020, 037, 024, 026, 004, 004, 000, 000, 000, 000 }, // 014
{ 000, 016, 020, 026, 025, 016, 005, 005, 000, 000, 000, 000 }, // 015
{ 000, 000, 012, 025, 025, 025, 012, 000, 000, 000, 000, 000 }, // 016
{ 000, 014, 002, 007, 011, 011, 006, 000, 000, 000, 000, 000 }, // 017
{ 000, 000, 017, 020, 020, 017, 000, 000, 000, 000, 000, 000 }, // 020
{ 000, 000, 036, 001, 001, 036, 000, 000, 000, 000, 000, 000 }, // 021
{ 000, 006, 011, 011, 011, 011, 011, 000, 000, 000, 000, 000 }, // 022
{ 000, 011, 011, 011, 011, 011, 006, 000, 000, 000, 000, 000 }, // 023
{ 000, 021, 021, 037, 021, 012, 004, 000, 000, 000, 000, 000 }, // 024
{ 000, 037, 001, 007, 001, 001, 037, 000, 000, 000, 000, 000 }, // 025
{ 000, 000, 016, 025, 033, 025, 016, 000, 000, 000, 000, 000 }, // 026
{ 000, 000, 000, 012, 037, 012, 000, 000, 000, 000, 000, 000 }, // 027
{ 000, 000, 000, 000, 000, 000, 000, 000, 077, 000, 000, 000 }, // 030
{ 000, 000, 004, 002, 037, 002, 004, 000, 000, 000, 000, 000 }, // 031
{ 000, 000, 010, 025, 002, 000, 000, 000, 000, 000, 000, 000 }, // 032
{ 000, 001, 002, 037, 004, 037, 010, 020, 000, 000, 000, 000 }, // 033
{ 000, 000, 002, 004, 010, 004, 002, 017, 000, 000, 000, 000 }, // 034
{ 000, 000, 010, 004, 002, 004, 010, 036, 000, 000, 000, 000 }, // 035
{ 000, 000, 037, 000, 037, 000, 037, 000, 000, 000, 000, 000 }, // 036
{ 000, 000, 021, 012, 004, 000, 000, 000, 000, 000, 000, 000 }, // 037
{ 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000 }, // 040
{ 000, 006, 006, 006, 006, 000, 006, 000, 000, 000, 000, 000 }, // 041
{ 000, 012, 012, 012, 000, 000, 000, 000, 000, 000, 000, 000 }, // 042
{ 000, 012, 037, 012, 012, 037, 012, 000, 000, 000, 000, 000 }, // 043
{ 000, 004, 017, 024, 016, 005, 036, 004, 000, 000, 000, 000 }, // 044
{ 000, 037, 031, 002, 004, 013, 023, 000, 000, 000, 000, 000 }, // 045
{ 000, 014, 024, 010, 025, 022, 035, 000, 000, 000, 000, 000 }, // 046
{ 000, 006, 002, 004, 000, 000, 000, 000, 000, 000, 000, 000 }, // 047
{ 000, 002, 004, 010, 010, 010, 004, 002, 000, 000, 000, 000 }, // 050
{ 000, 010, 004, 002, 002, 002, 004, 010, 000, 000, 000, 000 }, // 051
{ 000, 000, 025, 016, 033, 016, 025, 000, 000, 000, 000, 000 }, // 052
{ 000, 000, 004, 004, 037, 004, 004, 000, 000, 000, 000, 000 }, // 053
{ 000, 000, 000, 000, 000, 006, 002, 004, 000, 000, 000, 000 }, // 054
{ 000, 000, 000, 000, 077, 000, 000, 000, 000, 000, 000, 000 }, // 055
{ 000, 000, 000, 000, 000, 004, 004, 000, 000, 000, 000, 000 }, // 056
{ 000, 001, 002, 002, 004, 004, 010, 000, 000, 000, 000, 000 }, // 057
{ 000, 006, 011, 013, 015, 011, 006, 000, 000, 000, 000, 000 }, // 060
{ 000, 002, 006, 002, 002, 002, 007, 000, 000, 000, 000, 000 }, // 061
{ 000, 016, 021, 001, 016, 020, 037, 000, 000, 000, 000, 000 }, // 062
{ 000, 016, 021, 006, 001, 021, 016, 000, 000, 000, 000, 000 }, // 063
{ 000, 002, 006, 012, 037, 002, 002, 000, 000, 000, 000, 000 }, // 064
{ 000, 037, 020, 036, 001, 021, 016, 000, 000, 000, 000, 000 }, // 065
{ 000, 016, 020, 036, 021, 021, 016, 000, 000, 000, 000, 000 }, // 066
{ 000, 037, 001, 002, 002, 004, 004, 000, 000, 000, 000, 000 }, // 067
{ 000, 016, 021, 016, 021, 021, 016, 000, 000, 000, 000, 000 }, // 070
{ 000, 016, 021, 021, 017, 001, 016, 000, 000, 000, 000, 000 }, // 071
{ 000, 000, 004, 004, 000, 004, 004, 000, 000, 000, 000, 000 }, // 072
{ 000, 000, 004, 004, 000, 006, 002, 004, 000, 000, 000, 000 }, // 073
{ 000, 000, 002, 004, 010, 004, 002, 000, 000, 000, 000, 000 }, // 074
{ 000, 000, 000, 037, 000, 037, 000, 000, 000, 000, 000, 000 }, // 075
{ 000, 000, 010, 004, 002, 004, 010, 000, 000, 000, 000, 000 }, // 076
{ 000, 016, 021, 001, 006, 000, 004, 000, 000, 000, 000, 000 }, // 077
{ 000, 016, 021, 027, 027, 020, 016, 000, 000, 000, 000, 000 }, // 100
{ 000, 016, 021, 037, 021, 021, 021, 000, 000, 000, 000, 000 }, // 101
{ 000, 036, 021, 036, 021, 021, 036, 000, 000, 000, 000, 000 }, // 102
{ 000, 016, 021, 020, 020, 021, 016, 000, 000, 000, 000, 000 }, // 103
{ 000, 036, 021, 021, 021, 021, 036, 000, 000, 000, 000, 000 }, // 104
{ 000, 037, 020, 036, 020, 020, 037, 000, 000, 000, 000, 000 }, // 105
{ 000, 037, 020, 036, 020, 020, 020, 000, 000, 000, 000, 000 }, // 106
{ 000, 016, 021, 020, 023, 021, 016, 000, 000, 000, 000, 000 }, // 107
{ 000, 021, 021, 037, 021, 021, 021, 000, 000, 000, 000, 000 }, // 110
{ 000, 016, 004, 004, 004, 004, 016, 000, 000, 000, 000, 000 }, // 111
{ 000, 001, 001, 001, 001, 021, 016, 000, 000, 000, 000, 000 }, // 112
{ 000, 021, 022, 024, 034, 022, 021, 000, 000, 000, 000, 000 }, // 113
{ 000, 020, 020, 020, 020, 020, 037, 000, 000, 000, 000, 000 }, // 114
{ 000, 021, 033, 025, 025, 021, 021, 000, 000, 000, 000, 000 }, // 115
{ 000, 021, 031, 025, 023, 021, 021, 000, 000, 000, 000, 000 }, // 116
{ 000, 016, 021, 021, 021, 021, 016, 000, 000, 000, 000, 000 }, // 117
{ 000, 036, 021, 036, 020, 020, 020, 000, 000, 000, 000, 000 }, // 120
{ 000, 016, 021, 021, 025, 023, 016, 001, 000, 000, 000, 000 }, // 121
{ 000, 036, 021, 036, 024, 022, 021, 000, 000, 000, 000, 000 }, // 122
{ 000, 016, 021, 014, 002, 021, 016, 000, 000, 000, 000, 000 }, // 123
{ 000, 037, 004, 004, 004, 004, 004, 000, 000, 000, 000, 000 }, // 124
{ 000, 021, 021, 021, 021, 021, 016, 000, 000, 000, 000, 000 }, // 125
{ 000, 021, 021, 021, 012, 012, 004, 000, 000, 000, 000, 000 }, // 126
{ 000, 021, 021, 025, 025, 033, 021, 000, 000, 000, 000, 000 }, // 127
{ 000, 021, 012, 004, 012, 021, 021, 000, 000, 000, 000, 000 }, // 130
{ 000, 021, 021, 016, 004, 004, 004, 000, 000, 000, 000, 000 }, // 131
{ 000, 037, 001, 002, 010, 020, 037, 000, 000, 000, 000, 000 }, // 132
{ 000, 016, 010, 010, 010, 010, 010, 016, 000, 000, 000, 000 }, // 133
{ 000, 020, 010, 004, 004, 002, 001, 000, 000, 000, 000, 000 }, // 134
{ 000, 016, 002, 002, 002, 002, 002, 016, 000, 000, 000, 000 }, // 135
{ 000, 004, 016, 025, 004, 004, 004, 000, 000, 000, 000, 000 }, // 136
{ 000, 000, 004, 010, 037, 010, 004, 000, 000, 000, 000, 000 }, // 137
{ 000, 006, 004, 002, 000, 000, 000, 000, 000, 000, 000, 000 }, // 140
{ 000, 000, 016, 001, 017, 021, 015, 000, 000, 000, 000, 000 }, // 141
{ 000, 020, 026, 031, 021, 021, 026, 000, 000, 000, 000, 000 }, // 142
{ 000, 000, 016, 020, 020, 020, 016, 000, 000, 000, 000, 000 }, // 143
{ 000, 001, 015, 023, 021, 021, 015, 000, 000, 000, 000, 000 }, // 144
{ 000, 000, 016, 021, 037, 020, 016, 000, 000, 000, 000, 000 }, // 145
{ 000, 007, 010, 036, 010, 010, 010, 000, 000, 000, 000, 000 }, // 146
{ 000, 000, 017, 021, 021, 016, 001, 036, 000, 000, 000, 000 }, // 147
{ 000, 020, 026, 031, 021, 021, 021, 000, 000, 000, 000, 000 }, // 150
{ 000, 004, 000, 014, 004, 004, 004, 000, 000, 000, 000, 000 }, // 151
{ 000, 002, 000, 006, 002, 002, 002, 014, 000, 000, 000, 000 }, // 152
{ 000, 010, 011, 012, 014, 012, 011, 000, 000, 000, 000, 000 }, // 153
{ 000, 014, 004, 004, 004, 004, 004, 000, 000, 000, 000, 000 }, // 154
{ 000, 000, 032, 025, 025, 025, 025, 000, 000, 000, 000, 000 }, // 155
{ 000, 000, 026, 031, 021, 021, 021, 000, 000, 000, 000, 000 }, // 156
{ 000, 000, 016, 021, 021, 021, 016, 000, 000, 000, 000, 000 }, // 157
{ 000, 000, 026, 031, 021, 021, 026, 020, 000, 000, 000, 000 }, // 160
{ 000, 000, 015, 023, 021, 021, 015, 001, 000, 000, 000, 000 }, // 161
{ 000, 000, 026, 031, 020, 020, 020, 000, 000, 000, 000, 000 }, // 162
{ 000, 000, 017, 020, 016, 001, 036, 000, 000, 000, 000, 000 }, // 163
{ 000, 010, 037, 010, 010, 010, 006, 000, 000, 000, 000, 000 }, // 164
{ 000, 000, 021, 021, 021, 021, 015, 000, 000, 000, 000, 000 }, // 165
{ 000, 000, 021, 021, 012, 012, 004, 000, 000, 000, 000, 000 }, // 166
{ 000, 000, 021, 021, 025, 025, 012, 000, 000, 000, 000, 000 }, // 167
{ 000, 000, 021, 012, 004, 012, 021, 000, 000, 000, 000, 000 }, // 170
{ 000, 000, 021, 021, 021, 017, 001, 016, 000, 000, 000, 000 }, // 171
{ 000, 000, 037, 002, 004, 010, 037, 000, 000, 000, 000, 000 }, // 172
{ 000, 003, 004, 004, 010, 004, 004, 003, 000, 000, 000, 000 }, // 173
{ 000, 004, 004, 004, 004, 004, 004, 004, 000, 000, 000, 000 }, // 174
{ 000, 000, 004, 012, 021, 012, 004, 000, 000, 000, 000, 000 }, // 175
{ 000, 030, 004, 004, 002, 004, 004, 030, 000, 000, 000, 000 }, // 176
{ 000, 077, 077, 077, 077, 077, 077, 077, 077, 000, 000, 000 }, // 177
};

763
PDP10/ka10_pipanel.c Normal file
View file

@ -0,0 +1,763 @@
/* kx10_pipanel.c: PDP-10 PiDP10 front panel.
Copyright (c) 2022, Richard Cornwell
Based on code by Oscar Vermeulen
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
RICHARD CORNWELL 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 Richard Cornwell shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Richard Cornwell
*/
#if PIDP10
/* The following includes are ok since this code can only be run on a
* Rasberry PI under Linux.
*
* To Build this:
* make PIDP10=1 pdp10-ka
*/
#include <pthread.h> /* Needed for pthread */
#include <unistd.h> /* Needed for sleep/geteuid */
#include <sys/types.h>
#include <editline/readline.h>
#include "pinctrl/gpiolib.h"
#include "kx10_defs.h"
extern uint64 SW; /* Switch register */
extern t_addr AS; /* Address switches */
extern uint64 MB; /* Memory Bus register */
extern uint64 MI; /* Memory indicator register */
extern uint8 MI_flag; /* Memory indicator mode */
extern uint32 FLAGS; /* Flags register */
extern uint8 RUN; /* Run flag */
extern uint32 IR; /* Instruction register */
extern uint32 AC; /* Accumulator */
extern uint8 IX; /* Index register */
extern uint8 IND; /* Indirect flag */
extern t_addr AB; /* Memory address register */
extern t_addr PC; /* Program counter register */
#if KA | KI
extern int nxm_stop; /* Stop if non-existent memory access */
extern int adr_cond; /* Address stop condition */
#endif
extern uint8 IOB_PI; /* Pending Interrupt requests */
extern uint8 PIR; /* Current Interrupt requests */
extern uint8 PIH; /* Currently held interrupts */
extern uint8 PIE; /* Currently enabled interrupts */
extern int pi_enable; /* Interrupt system enabled */
extern uint8 prog_stop; /* Program stop */
extern uint8 examine_sw; /* Examine memory */
extern uint8 deposit_sw; /* Deposit memory */
extern uint8 sing_inst_sw;/* Execute single instruction */
extern uint8 xct_sw; /* Execute an instruction */
extern uint8 stop_sw; /* Stop the simulator */
extern uint8 MI_disable; /* Disable MI display */
extern int watch_stop; /* Memory Stop */
extern uint32 rdrin_dev; /* Read in device. */
extern uint8 MI_disable; /* Disable MI */
int repeat_sw; /* Repeat switch state */
int par_stop; /* Parity stop */
int pwr_off; /* Power off system */
int rep_rate; /* Rate of repeat function */
int rep_count; /* Count down to repeat trigger */
/* led row 0 */
#define MB_MASK0 RMASK /* 18-35 */
#define MB_V_0 0 /* right */
/* led row 1 */
#define MB_MASK1 LMASK /* 0-17 */
#define MB_V_1 18 /* right */
/* led row 2 */
#define AB_MASK2 RMASK /* 18-35 */
#define AB_V_2 0 /* right */
/* led row 3 */
#define IX_MASK3 017
#define IX_V_3 0 /* left */
#define IND_LAMP 020
#define AC_MASK3 017
#define AC_V_3 5 /* left */
#define IR_MASK3 0777 /* 0-9 */
#define IR_V_3 9 /* left */
/* led row 4 */
#define PC_MASK4 RMASK /* 18-35 */
#define PC_V_4 0 /* right */
/* led row 5 */
#define PI_IOB_MASK5 0177
#define PI_IOB_V_5 7 /* left */
#define PI_ENB_MASK5 0177
#define PI_ENB_V_5 0 /* left */
#define PROG_STOP_LAMP 0040000
#define USER_LAMP 0100000
#define MEM_STOP_LAMP 0200000
#define PWR_LAMP 0400000
/* led row 6 */
#define PI_REQ_MASK6 0177
#define PI_REQ_V_6 0 /* left */
#define PI_PRO_MASK6 0177
#define PI_PRO_V_6 7 /* left */
#define RUN_LAMP 0040000
#define PION_LAMP 0100000
#define PI_LAMP 0200000
#define MI_LAMP 0400000
/* switch row 0 */
#define SR_MASK0 RMASK
#define SR_V_0 0 /* Left */
/* switch row 1 */
#define SR_MASK1 LMASK
#define SR_V_1 18 /* Left */
/* Switch row 2 */
#define MA_SW_MASK3 RMASK
#define MA_SW_V_3 0 /* Left */
/* Switch row 3 */
#define EXAM_NEXT 000001 /* SW=0 */
#define EXAM_THIS 000002 /* SW=1 */
#define XCT_SW 000004 /* SW=2 Set xct_inst */
#define RESET_SW 000010 /* SW=3 Call reset */
#define STOP_SW 000020 /* SW=4 Set RUN = 0 */
#define CONT_SW 000040 /* SW=5 call sim_instr */
#define START_SW 000100 /* SW=6 Call reset then sim_instr */
#define READ_SW 000200 /* SW=7 Boot function */
#define DEP_NEXT 000400 /* SW=8 */
#define DEP_THIS 001000 /* SW=9 */
/* Switch row 4 */
#define ADR_BRK_SW 000001 /* Address Break */
#define ADR_STOP_SW 000002 /* Address stop */
#define WRITE_SW 000004 /* Write stop */
#define DATA_FETCH 000010 /* Data fetch stop */
#define INST_FETCH 000020 /* Instruct fetch stop */
#define REP_SW 000040 /* Repeat switch */
#define NXM_STOP 000100 /* set nxm_stop */
#define PAR_STOP 000200 /* Nop */
#define SING_CYCL 000400 /* Nop */
#define SING_INST 001000 /* set sing_inst */
int xrows[3] = { 4, 17, 27 };
int xIO = 22; /* GPIO 22: */
int cols[18] = { 21,20,16,12,7,8,25,24,23,18,10,9,11,5,6,13,19,26 };
long intervl = 50000;
struct {
int last_state; /* last state */
int state; /* Stable state */
int debounce; /* Debounce timer */
int changed; /* Switch changed state */
} switch_state[16];
void *blink(void *ptr); /* the real-time GPIO multiplexing process to start up */
pthread_t blink_thread;
int blink_thread_terminate = 0;
t_stat gpio_mux_thread_start()
{
int res;
res = pthread_create(&blink_thread, NULL, blink, &blink_thread_terminate);
if (res) {
return sim_messagef(SCPE_IERR,
"Error creating gpio_mux thread, return code %d\n", res);
}
sim_messagef(SCPE_OK, "Created blink_thread\n");
sleep(2); /* allow 2 sec for multiplex to start */
return SCPE_OK;
}
/*
* Debounce a momentary switch.
*/
static void debounce_sw(int state, int sw)
{
if (switch_state[sw].state == state) {
if (switch_state[sw].debounce != 0) {
switch_state[sw].debounce--;
} else {
if (switch_state[sw].last_state != switch_state[sw].state) {
switch_state[sw].changed = 1;
}
switch_state[sw].last_state = switch_state[sw].state;
}
} else {
switch_state[sw].debounce = 8;
switch_state[sw].changed = 0;
switch_state[sw].state = state;
}
}
static t_addr
read_sw()
{
int col, row, i;
t_uint64 sw;
t_addr new_as;
struct timespec spec;
gpio_set_drive(xIO, DRIVE_HIGH);
for (i = 0; i < 18; i++) {
gpio_set_dir(cols[i], DIR_INPUT);
}
spec.tv_sec = 0;
new_as = 0;
for (row=0; row<5; row++) {
/* Select row address */
for (i = 0; i < 3; i++) {
if ((row & (1 << i)) == 0) {
gpio_set_drive(xrows[i], DRIVE_LOW);
} else {
gpio_set_drive(xrows[i], DRIVE_HIGH);
}
}
spec.tv_nsec = intervl/10;
nanosleep(&spec, NULL);
sw = 0;
for (i = 0; i < 18; i++) {
if (gpio_get_level(cols[i])) {
sw |= 1 << i;
}
}
/* Map row to values */
switch (row) {
default:
case 0:
SW = (SW & SR_MASK1) | ((~sw << SR_V_0) & SR_MASK0);
break;
case 1:
SW = (SW & SR_MASK0) | ((~sw << SR_V_1) & SR_MASK1);
break;
case 2:
new_as = (t_addr)(~sw << MA_SW_V_3) & MA_SW_MASK3;
break;
case 3: /* Momentary switches */
for (col = 0; col < 10; col++) {
int state = (sw & (1 << col)) == 0;
debounce_sw(state, col);
}
break;
case 4:
#if KA | KI
adr_cond = 0;
adr_cond |= ((sw & INST_FETCH) == 0) ? ADR_IFETCH : 0;
adr_cond |= ((sw & DATA_FETCH) == 0) ? ADR_DFETCH : 0;
adr_cond |= ((sw & WRITE_SW) == 0) ? ADR_WRITE : 0;
adr_cond |= ((sw & ADR_STOP_SW) == 0) ? ADR_STOP : 0;
adr_cond |= ((sw & ADR_BRK_SW) == 0) ? ADR_BREAK : 0;
nxm_stop = (sw & NXM_STOP) == 0;
#endif
sing_inst_sw = ((sw & SING_INST) == 0) ||
((sw & SING_CYCL) == 0);
/* PAR_STOP handle special features */
par_stop = (sw & PAR_STOP) == 0;
/* SING_CYCL no function yet */
repeat_sw = (sw & REP_SW) == 0;
break;
}
}
return new_as;
}
void *blink(void *ptr)
{
int *terminate = (int *)ptr;
int col, row, i;
int num_gpios, ret;
uint32 leds;
t_addr new_as;
struct timespec spec;
struct sched_param sp;
spec.tv_sec = 0;
sp.sched_priority = 98; // maybe 99, 32, 31?
if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp))
fprintf(stderr, "warning: failed to set RT priority\n");
ret = gpiolib_init();
if (ret < 0) {
sim_messagef(SCPE_IERR, "Unable to initialize gpiolib- %d\n", ret);
return (void *)-1;
}
num_gpios = ret;
if (num_gpios == 0) {
sim_messagef(SCPE_IERR, "No GPIO chips found\n");
return (void *)-1;
}
ret = gpiolib_mmap();
if (ret) {
if (ret == EACCES && geteuid()) {
sim_messagef(SCPE_IERR, "Must be root\n");
} else {
sim_perror("Failed to mmap gpiolib");
}
return (void *)-1;
}
/* Initialize GPIO pins */
gpio_set_fsel(xIO, GPIO_FSEL_OUTPUT);
gpio_set_dir(xIO, DIR_OUTPUT);
gpio_set_drive(xIO, DRIVE_HIGH);
/* Row address pins */
for (row = 0; row < 3; row++) {
gpio_set_fsel(xrows[row], GPIO_FSEL_OUTPUT);
gpio_set_dir(xrows[row], DIR_OUTPUT);
gpio_set_drive(xrows[row], DRIVE_HIGH);
}
/* Columns */
for (col = 0; col < 10; col++) {
gpio_set_fsel(cols[col], GPIO_FSEL_INPUT);
gpio_set_pull(cols[col], PULL_UP);
}
/* Read initial value of switches */
new_as = read_sw();
sim_messagef(SCPE_OK, "PiDP-10 FP on\n");
/* start the actual multiplexing */
while (*terminate == 0)
{
/* Set to point to switchs while updating digits */
gpio_set_drive(xIO, DRIVE_HIGH);
/* Set direction of columns to output */
for (i = 0; i < 18; i++) {
gpio_set_dir(cols[i], DIR_OUTPUT);
}
/* Display each row */
for (row=0; row<7; row++) { /* 7 rows of LEDS get lit */
switch (row) {
default:
case 0:
leds = (((MI_flag)? MI : MB) & MB_MASK0) >> MB_V_0;
break;
case 1:
leds = (((MI_flag)? MI : MB) & MB_MASK1) >> MB_V_1;
break;
case 2:
if (par_stop) {
leds = rdrin_dev & 0777;
leds |= rep_rate << 12;
leds |= MI_disable << 10;
} else {
leds = (AB & AB_MASK2) >> AB_V_2;
}
break;
case 3:
leds = (IR & IR_MASK3) << IR_V_3;
leds |= (AC & AC_MASK3) << AC_V_3;
leds |= (IND) ? IND_LAMP : 0;
leds |= (IX & IX_MASK3) << IX_V_3;
break;
case 4:
leds = (PC & PC_MASK4) >> PC_V_4;
break;
case 5:
leds = PWR_LAMP;
leds |= (IOB_PI & PI_IOB_MASK5) << PI_IOB_V_5;
leds |= (PIE & PI_ENB_MASK5) << PI_ENB_V_5;
leds |= (FLAGS & USER) ? USER_LAMP : 0;
leds |= (prog_stop) ? PROG_STOP_LAMP: 0;
leds |= (watch_stop) ? MEM_STOP_LAMP: 0;
break;
case 6:
leds = (RUN) ? RUN_LAMP : 0;
leds |= (pi_enable) ? PION_LAMP : 0;
leds |= (PIR & PI_REQ_MASK6) << PI_REQ_V_6;
leds |= (PIH & PI_PRO_MASK6) << PI_PRO_V_6;
leds |= (MI_flag) ? PI_LAMP : MI_LAMP;
break;
}
/* Select correct row to display */
for (i = 0; i < 3; i++) {
if ((row & (1 << i)) == 0) {
gpio_set_drive(xrows[i], DRIVE_LOW);
} else {
gpio_set_drive(xrows[i], DRIVE_HIGH);
}
}
/* Update the leds for output */
for (i = 0; i < 18; i++) {
if ((leds & (1 << i)) == 0) {
gpio_set_drive(cols[i], DRIVE_HIGH);
} else {
gpio_set_drive(cols[i], DRIVE_LOW);
}
}
/* Select output */
gpio_set_drive(xIO, DRIVE_LOW);
spec.tv_nsec = intervl;
nanosleep(&spec, NULL);
/* Deselect output */
gpio_set_drive(xIO, DRIVE_HIGH);
spec.tv_nsec = intervl/10;
nanosleep(&spec, NULL);
}
/* Read in switches */
new_as = read_sw();
/* If running, check for switch changes */
if (par_stop) {
/* Process all momentary switches */
for (col = 0; col < 10; col++) {
if (switch_state[col].changed && switch_state[col].state) {
switch_state[col].changed = 0;
switch (col) {
case 1: /* Examine this */
rep_rate = (new_as >> 14) & 0xf;
break;
case 4: /* Stop function */
stop_sw = 1;
pwr_off = 1;
break;
case 5: /* Continue */
MI_disable = !MI_disable;
if (MI_disable)
MI_flag = 0;
break;
#if KA | KI
case 7: /* ReadIN */
rdrin_dev = 0774 & new_as;
break;
#endif
case 0: /* Examine next */
case 2: /* Execute function */
case 3: /* Reset function */
case 6: /* Start */
case 8: /* Deposit next */
case 9: /* Deposit this */
default:
break;
}
}
}
} else {
AS = new_as;
}
/* Check repeat count */
if (rep_count > 0 && --rep_count == 0) {
for (col = 0; col < 10; col++) {
switch_state[col].changed = switch_state[col].state;
}
}
/* Process switch changes if running */
if (RUN) {
for (col = 0; col < 10; col++) {
if (switch_state[col].changed && switch_state[col].state) {
/* If repeat switch set, trigger timer */
if (repeat_sw) {
rep_count = (rep_rate + 1) * 16;
}
switch (col) {
case 1: /* Examine this */
examine_sw = 1;
MI_flag = 0;
switch_state[col].changed = 0;
break;
case 0: /* Examine next */
case 5: /* Continue */
case 6: /* Start */
case 7: /* ReadIN */
case 8: /* Deposit next */
default:
switch_state[col].changed = 0;
break;
case 2: /* Execute function */
xct_sw = 1;
switch_state[col].changed = 0;
break;
case 3: /* Reset function */
stop_sw = 1;
break;
case 4: /* Stop function */
stop_sw = 1;
switch_state[col].changed = 0;
break;
case 9: /* Deposit this */
deposit_sw = 1;
MI_flag = 0;
switch_state[col].changed = 0;
break;
}
}
}
}
/* done with reading the switches,
* so start the next cycle of lighting up LEDs
*/
}
/* received terminate signal, close down */
gpio_set_drive(xIO, DRIVE_HIGH);
for (i = 0; i < 18; i++) {
gpio_set_dir(cols[i], DIR_INPUT);
}
for (row = 0; row < 3; row++) {
gpio_set_drive(xrows[row], DRIVE_HIGH);
}
}
volatile int input_wait;
static char *input_buffer = NULL;
/*
* Handler for EditLine package when line is complete.
*/
static void
read_line_handler(char *line)
{
if (line != NULL) {
input_buffer = line;
input_wait = 0;
add_history(line);
}
}
/*
* Process input from stdin or switches.
*/
static char *
vm_read(char *cptr, int32 sz, FILE *file)
{
struct timeval tv = {0,10000}; /* Wait for 10ms */
fd_set read_set;
int fd = fileno(file); /* What to wait on */
int col;
if (input_buffer != NULL)
free(input_buffer);
rl_callback_handler_install(sim_prompt, (rl_vcpfunc_t*) &read_line_handler);
input_wait = 1;
input_buffer = NULL;
while (input_wait) {
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
tv.tv_sec = 0;
tv.tv_usec = 10000;
(void)select(fd+1, &read_set, NULL, NULL, &tv);
if (FD_ISSET(fd, &read_set)) {
rl_callback_read_char();
} else {
if (pwr_off) {
if ((input_buffer = (char *)malloc(20)) != 0) {
strcpy(input_buffer, "quit\r");
stop_sw = 1;
pwr_off = 0;
input_wait = 0;
}
break;
}
/* Process switches */
for (col = 0; col < 10; col++) {
if (switch_state[col].changed && switch_state[col].state) {
/* If repeat switch set, trigger timer */
if (repeat_sw) {
rep_count = (rep_rate + 1) * 16;
}
switch (col) {
case 0: /* Examine next */
AB++;
MB = (AB < 020) ? FM[AB] : M[AB];
MI_flag = 0;
break;
case 1: /* Examine this */
AB = AS;
MB = (AS < 020) ? FM[AS] : M[AS];
MI_flag = 0;
break;
case 2: /* Execute function */
if ((input_buffer = (char *)malloc(20)) != 0) {
strcpy(input_buffer, "step\r");
xct_sw = 1;
input_wait = 0;
}
break;
case 3: /* Reset function */
if ((input_buffer = (char *)malloc(20)) != 0) {
strcpy(input_buffer, "reset all\r");
input_wait = 0;
}
break;
case 4: /* Stop function */
break;
case 5: /* Continue */
if ((input_buffer = (char *)malloc(10)) != 0) {
strcpy(input_buffer,
(sing_inst_sw) ? "step\r" : "cont\r");
input_wait = 0;
}
break;
case 6: /* Start */
if ((input_buffer = (char *)malloc(20)) != 0) {
sprintf(input_buffer, "run %06o\r", AS);
input_wait = 0;
}
break;
#if KA | KI
case 7: /* ReadIN */
if ((input_buffer = (char *)malloc(20)) != 0) {
DEVICE *dptr;
int i;
/* Scan all devices to find match */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp && !(dptr->flags & DEV_DIS) &&
(dibp->dev_num == (rdrin_dev & 0774))) {
if (dptr->numunits > 1)
sprintf(input_buffer, "boot %s0\r",
dptr->name);
else
sprintf(input_buffer, "boot %s\r",
dptr->name);
input_wait = 0;
break;
}
}
}
/* If we did not find a boot device, free command */
if (input_wait) {
free(input_buffer);
input_buffer = NULL;
sim_messagef(SCPE_OK, "Device %03o not found\n",
rdrin_dev);
}
break;
#endif
case 8: /* Deposit next */
AB++;
if (AB < 020) {
FM[AB] = SW;
MB = FM[AB];
} else {
M[AB] = SW;
MB = M[AB];
}
MI_flag = 0;
break;
case 9: /* Deposit this */
AB = AS;
if (AS < 020) {
FM[AS] = SW;
MB = FM[AS];
} else {
M[AS] = SW;
MB = M[AS];
}
MI_flag = 0;
break;
}
switch_state[col].changed = 0;
}
}
}
}
rl_callback_handler_remove();
return input_buffer;
}
static void
vm_post(t_bool from_scp)
{
}
/*
* Start panel thread, and install console read functions.
*/
t_stat pi_panel_start(void)
{
int terminate = 1;
int i,j;
t_stat r;
/* start up multiplexing thread */
r = gpio_mux_thread_start();
sim_vm_read = &vm_read;
sim_vm_post = &vm_post;
return r;
}
/*
* Stop display thread.
*/
void pi_panel_stop(void)
{
if (blink_thread_terminate == 0) {
blink_thread_terminate=1;
sim_vm_read = NULL;
sleep (2); /* allow threads to close down */
}
}
#endif

View file

@ -39,6 +39,9 @@ static uint64 ten11_pager[256];
t_addr ten11_base = 03000000; t_addr ten11_base = 03000000;
t_addr ten11_end = 04000000; t_addr ten11_end = 04000000;
/* Number of Unibuses. */
#define UNIBUSES 8
/* Physical address of 10-11 control page. */ /* Physical address of 10-11 control page. */
#define T11CPA 0776000 //Offset inside TEN11 moby. #define T11CPA 0776000 //Offset inside TEN11 moby.
@ -116,8 +119,8 @@ DEVICE ten11_dev = {
&ten11_description, /* description */ &ten11_description, /* description */
}; };
static TMLN ten11_ldsc; /* line descriptor */ static TMLN ten11_ldsc[UNIBUSES]; /* line descriptor */
static TMXR ten11_desc = { 1, 0, 0, &ten11_ldsc }; /* mux descriptor */ static TMXR ten11_desc = { 8, 0, 0, ten11_ldsc }; /* mux descriptor */
static t_stat ten11_reset (DEVICE *dptr) static t_stat ten11_reset (DEVICE *dptr)
{ {
@ -175,14 +178,20 @@ static void build (unsigned char *request, unsigned char octet)
static t_stat ten11_svc (UNIT *uptr) static t_stat ten11_svc (UNIT *uptr)
{ {
int i;
tmxr_poll_rx (&ten11_desc); tmxr_poll_rx (&ten11_desc);
if (ten11_ldsc.rcve && !ten11_ldsc.conn) {
ten11_ldsc.rcve = 0; for (i = 0; i < UNIBUSES; i++) {
tmxr_reset_ln (&ten11_ldsc); if (ten11_ldsc[i].rcve && !ten11_ldsc[i].conn) {
ten11_ldsc[i].rcve = 0;
tmxr_reset_ln (&ten11_ldsc[i]);
} }
if (tmxr_poll_conn(&ten11_desc) >= 0) { }
i = tmxr_poll_conn(&ten11_desc);
if (i >= 0) {
sim_debug(DBG_CMD, &ten11_dev, "got connection\n"); sim_debug(DBG_CMD, &ten11_dev, "got connection\n");
ten11_ldsc.rcve = 1; ten11_ldsc[i].rcve = 1;
uptr->wait = TEN11_POLL; uptr->wait = TEN11_POLL;
} }
sim_clock_coschedule (uptr, uptr->wait); sim_clock_coschedule (uptr, uptr->wait);
@ -214,38 +223,40 @@ static const char *ten11_description (DEVICE *dptr)
return "Rubin PDP-10 to PDP-11 interface"; return "Rubin PDP-10 to PDP-11 interface";
} }
static int error (const char *message) static int error (int unibus, const char *message)
{ {
sim_debug (DBG_TRC, &ten11_dev, "%s\r\n", message); sim_debug (DBG_TRC, &ten11_dev, "Port %d: %s\r\n", unibus, message);
sim_debug (DBG_TRC, &ten11_dev, "CLOSE\r\n"); sim_debug (DBG_TRC, &ten11_dev, "CLOSE\r\n");
ten11_ldsc.rcve = 0; ten11_ldsc[unibus].rcve = 0;
tmxr_reset_ln (&ten11_ldsc); tmxr_reset_ln (&ten11_ldsc[unibus]);
return -1; return -1;
} }
static int transaction (unsigned char *request, unsigned char *response) static int transaction (int unibus, unsigned char *request, unsigned char *response)
{ {
const uint8 *ten11_request; const uint8 *ten11_request;
size_t size; size_t size;
t_stat stat; t_stat stat;
stat = tmxr_put_packet_ln (&ten11_ldsc, request + 1, (size_t)request[0]); stat = tmxr_put_packet_ln (&ten11_ldsc[unibus], request + 1, (size_t)request[0]);
if (stat != SCPE_OK) if (stat != SCPE_OK)
return error ("Write error in transaction"); return error (unibus, "Write error in transaction");
do { do {
tmxr_poll_rx (&ten11_desc); tmxr_poll_rx (&ten11_desc);
stat = tmxr_get_packet_ln (&ten11_ldsc, &ten11_request, &size); stat = tmxr_get_packet_ln (&ten11_ldsc[unibus], &ten11_request, &size);
if (!ten11_ldsc[unibus].conn)
return error (unibus, "Connection lost");
} while (stat != SCPE_OK || size == 0); } while (stat != SCPE_OK || size == 0);
if (size > 7) if (size > 7)
return error ("Malformed transaction"); return error (unibus, "Malformed transaction");
memcpy (response, ten11_request, size); memcpy (response, ten11_request, size);
return 0; return 0;
} }
static int read_word (t_addr addr, int *data) static int read_word (int unibus, t_addr addr, int *data)
{ {
unsigned char request[8]; unsigned char request[8];
unsigned char response[8]; unsigned char response[8];
@ -263,7 +274,7 @@ static int read_word (t_addr addr, int *data)
build (request, (addr >> 8) & 0377); build (request, (addr >> 8) & 0377);
build (request, (addr) & 0377); build (request, (addr) & 0377);
if (transaction (request, response) == -1) { if (transaction (unibus, request, response) == -1) {
/* Network error. */ /* Network error. */
*data = 0; *data = 0;
return 0; return 0;
@ -285,7 +296,7 @@ static int read_word (t_addr addr, int *data)
*data = 0; *data = 0;
break; break;
default: default:
return error ("Protocol error"); return error (unibus, "Protocol error");
} }
return 0; return 0;
@ -325,8 +336,8 @@ int ten11_read (t_addr addr, uint64 *data)
uaddr = ((mapping & T11ADDR) >> 10) + offset; uaddr = ((mapping & T11ADDR) >> 10) + offset;
uaddr <<= 2; uaddr <<= 2;
read_word (uaddr, &word1); read_word (unibus, uaddr, &word1);
read_word (uaddr + 2, &word2); read_word (unibus, uaddr + 2, &word2);
*data = ((uint64)word1 << 20) | (word2 << 4); *data = ((uint64)word1 << 20) | (word2 << 4);
sim_debug (DBG_TRC, &ten11_dev, sim_debug (DBG_TRC, &ten11_dev,
@ -336,7 +347,7 @@ int ten11_read (t_addr addr, uint64 *data)
return 0; return 0;
} }
static int write_word (t_addr addr, uint16 data) static int write_word (int unibus, t_addr addr, uint16 data)
{ {
unsigned char request[8]; unsigned char request[8];
unsigned char response[8]; unsigned char response[8];
@ -355,7 +366,7 @@ static int write_word (t_addr addr, uint16 data)
build (request, (data >> 8) & 0377); build (request, (data >> 8) & 0377);
build (request, (data) & 0377); build (request, (data) & 0377);
transaction (request, response); transaction (unibus, request, response);
switch (response[0]) switch (response[0])
{ {
@ -368,7 +379,7 @@ static int write_word (t_addr addr, uint16 data)
fprintf (stderr, "TEN11: Write timeout %06o\r\n", addr); fprintf (stderr, "TEN11: Write timeout %06o\r\n", addr);
break; break;
default: default:
return error ("Protocol error"); return error (unibus, "Protocol error");
} }
return 0; return 0;
@ -417,9 +428,9 @@ int ten11_write (t_addr addr, uint64 data)
unibus, uaddr, data); unibus, uaddr, data);
if ((data & 010) == 0) if ((data & 010) == 0)
write_word (uaddr, (data >> 20) & 0177777); write_word (unibus, uaddr, (data >> 20) & 0177777);
if ((data & 004) == 0) if ((data & 004) == 0)
write_word (uaddr + 2, (data >> 4) & 0177777); write_word (unibus, uaddr + 2, (data >> 4) & 0177777);
} }
return 0; return 0;
} }

1188
PDP10/kl10_dn.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -447,7 +447,6 @@ dz_checkirq(struct pdp_dib *dibp)
int ln; int ln;
int stop; int stop;
TMLN *lp; TMLN *lp;
int irq = 0;
for (i = 0; i < NUM_DEVS_DZ; i++) { for (i = 0; i < NUM_DEVS_DZ; i++) {
if ((dz_csr[i] & MSE) == 0) if ((dz_csr[i] & MSE) == 0)

View file

@ -81,7 +81,6 @@ tcu_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
int int
tcu_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access) tcu_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{ {
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
time_t curtim; time_t curtim;
struct tm *tptr; struct tm *tptr;

View file

@ -79,11 +79,8 @@ uba_read(t_addr addr, int ctl, uint64 *data, int access)
*data = (uint64)uba_map[ubm][addr & 077]; *data = (uint64)uba_map[ubm][addr & 077];
return 0; return 0;
} else if ((addr & 077) == 0) { } else if ((addr & 077) == 0) {
int pih, pil;
int irqf = 0; int irqf = 0;
*data = (uint64)uba_status[ubm]; *data = (uint64)uba_status[ubm];
pih = 0200 >> ((uba_status[ubm] >> 3) & 07);
pil = 0200 >> (uba_status[ubm] & 07);
for (i = 0; i < 128; i++) { for (i = 0; i < 128; i++) {
if ((uba_irq_ctlr[i] & VECT_CTR) == ctl) if ((uba_irq_ctlr[i] & VECT_CTR) == ctl)
irqf |= uba_irq_ctlr[i]; irqf |= uba_irq_ctlr[i];

View file

@ -140,9 +140,7 @@ uint32 rdrin_dev; /* Read in device */
uint8 IX; /* Index register */ uint8 IX; /* Index register */
uint8 IND; /* Indirect flag */ uint8 IND; /* Indirect flag */
#endif #endif
#if PDP6 | KA | KI
t_addr AS; /* Address switches */ t_addr AS; /* Address switches */
#endif
int BYF5; /* Flag for second half of LDB/DPB instruction */ int BYF5; /* Flag for second half of LDB/DPB instruction */
int uuo_cycle; /* Uuo cycle in progress */ int uuo_cycle; /* Uuo cycle in progress */
int SC; /* Shift count */ int SC; /* Shift count */
@ -1356,7 +1354,6 @@ t_stat dev_apr(uint32 dev, uint64 *data) {
* MTR device for KL10. * MTR device for KL10.
*/ */
t_stat dev_mtr(uint32 dev, uint64 *data) { t_stat dev_mtr(uint32 dev, uint64 *data) {
uint64 res = 0;
switch(dev & 03) { switch(dev & 03) {
case CONI: case CONI:
@ -3525,6 +3522,7 @@ int Mem_read_its(int flag, int cur_context, int fetch, int mod) {
check_apr_irq(); check_apr_irq();
return 1; return 1;
} }
return 0;
} }
#endif #endif
#if NUM_DEVS_TEN11 > 0 #if NUM_DEVS_TEN11 > 0
@ -3579,6 +3577,16 @@ int Mem_write_its(int flag, int cur_context) {
} }
if (!page_lookup_its(AB, flag, &addr, 1, cur_context, 0, 0)) if (!page_lookup_its(AB, flag, &addr, 1, cur_context, 0, 0))
return 1; return 1;
#if NUM_DEVS_AUXCPU > 0
if (AUXCPURANGE(addr) && QAUXCPU) {
if (auxcpu_write (addr, MB)) {
nxm_flag = 1;
check_apr_irq();
return 1;
}
return 0;
}
#endif
#if NUM_DEVS_TEN11 > 0 #if NUM_DEVS_TEN11 > 0
if (T11RANGE(addr) && QTEN11) { if (T11RANGE(addr) && QTEN11) {
if (ten11_write (addr, MB)) { if (ten11_write (addr, MB)) {
@ -3588,15 +3596,6 @@ int Mem_write_its(int flag, int cur_context) {
} }
return 0; return 0;
} }
#endif
#if NUM_DEVS_AUXCPU > 0
if (AUXCPURANGE(addr) && QAUXCPU) {
if (auxcpu_write (addr, MB)) {
nxm_flag = 1;
check_apr_irq();
return 1;
}
}
#endif #endif
if (addr >= MEMSIZE) { if (addr >= MEMSIZE) {
nxm_flag = 1; nxm_flag = 1;
@ -4486,13 +4485,13 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */
#if PIDP10 #if PIDP10
if (examine_sw) { /* Examine memory switch */ if (examine_sw) { /* Examine memory switch */
AB = AS; AB = AS;
(void)Mem_read(1, 0, 0, 0); (void)Mem_read_nopage();
examine_sw = 0; examine_sw = 0;
} }
if (deposit_sw) { /* Deposit memory switch */ if (deposit_sw) { /* Deposit memory switch */
AB = AS; AB = AS;
MB = SW; MB = SW;
(void)Mem_write(1, 0); (void)Mem_write_nopage();
deposit_sw = 0; deposit_sw = 0;
} }
if (xct_sw) { /* Handle Front panel xct switch */ if (xct_sw) { /* Handle Front panel xct switch */
@ -4500,13 +4499,14 @@ if ((reason = build_dev_tab ()) != SCPE_OK) /* build, chk dib_tab */
xct_flag = 0; xct_flag = 0;
uuo_cycle = 1; uuo_cycle = 1;
f_pc_inh = 1; f_pc_inh = 1;
f_load_pc = 0;
MB = SW; MB = SW;
xct_sw = 0;
goto no_fetch; goto no_fetch;
} }
if (stop_sw) { /* Stop switch set */ if (stop_sw) { /* Stop switch set */
RUN = 0; RUN = 0;
stop_sw = 0; stop_sw = 0;
reason = STOP_HALT;
} }
if (sing_inst_sw) { /* Handle Front panel single instruction */ if (sing_inst_sw) { /* Handle Front panel single instruction */
instr_count = 1; instr_count = 1;
@ -4854,7 +4854,7 @@ st_pi:
/* Check if possible idle loop */ /* Check if possible idle loop */
if (sim_idle_enab && if (sim_idle_enab &&
(((FLAGS & USER) != 0 && PC < 020 && AB < 020 && (IR & 0740) == 0340) || ((PC < 020 && AB < 020 && (IR & 0740) == 0340) ||
(uuo_cycle && (IR & 0740) == 0 && IA == 041))) { (uuo_cycle && (IR & 0740) == 0 && IA == 041))) {
sim_idle (TMR_RTC, FALSE); sim_idle (TMR_RTC, FALSE);
} }
@ -4906,6 +4906,11 @@ st_pi:
nrf = 0; nrf = 0;
fxu_hold_set = 0; fxu_hold_set = 0;
modify = 0; modify = 0;
#if PIDP10
if (xct_sw) { /* Handle Front panel xct switch */
xct_sw = 0;
} else
#endif
f_pc_inh = 0; f_pc_inh = 0;
#if KL | KS #if KL | KS
if (extend) { if (extend) {
@ -7182,9 +7187,6 @@ fnormx:
SC--; SC--;
} else { } else {
AR = BR; AR = BR;
#if KS
FLAGS |= NODIV|TRP1;
#endif
break; break;
} }
} }
@ -7243,10 +7245,8 @@ fnormx:
SC--; SC--;
} }
AR &= FMASK; AR &= FMASK;
#if KL | KS
if ((SC & 01600) != 01600) if ((SC & 01600) != 01600)
fxu_hold_set = 1; fxu_hold_set = 1;
#endif
if (AR == (SMASK|EXPO)) { if (AR == (SMASK|EXPO)) {
AR = (AR >> 1) | (AR & SMASK); AR = (AR >> 1) | (AR & SMASK);
SC ++; SC ++;
@ -12263,6 +12263,7 @@ last:
if (QITS) if (QITS)
load_quantum(); load_quantum();
#endif #endif
RUN = 0;
return SCPE_STEP; return SCPE_STEP;
} }
} }
@ -13499,7 +13500,11 @@ rtc_srv(UNIT * uptr)
tmxr_poll = t/2; tmxr_poll = t/2;
#if PDP6 | KA | KI #if PDP6 | KA | KI
clk_flg = 1; clk_flg = 1;
#if PIDP10
if (clk_en && !sing_inst_sw) {
#else
if (clk_en) { if (clk_en) {
#endif
sim_debug(DEBUG_CONO, &cpu_dev, "CONO timmer\n"); sim_debug(DEBUG_CONO, &cpu_dev, "CONO timmer\n");
set_interrupt(4, clk_irq); set_interrupt(4, clk_irq);
} }
@ -13576,12 +13581,16 @@ static const char *pdp10_clock_precalibrate_commands[] = {
t_stat cpu_reset (DEVICE *dptr) t_stat cpu_reset (DEVICE *dptr)
{ {
int i; int i;
t_stat r = SCPE_OK;
static int initialized = 0; static int initialized = 0;
if (!initialized) { if (!initialized) {
initialized = 1; initialized = 1;
#if PIDP10 #if PIDP10
pi_panel_start(); r = pi_panel_start();
if (r != SCPE_OK) {
return r;
}
#endif #endif
} }
sim_debug(DEBUG_CONO, dptr, "CPU reset\n"); sim_debug(DEBUG_CONO, dptr, "CPU reset\n");
@ -13656,7 +13665,7 @@ t_stat cpu_reset (DEVICE *dptr)
#endif #endif
sim_vm_interval_units = "cycles"; sim_vm_interval_units = "cycles";
sim_vm_step_unit = "instruction"; sim_vm_step_unit = "instruction";
return SCPE_OK; return r;
} }
/* Memory examine */ /* Memory examine */
@ -13859,6 +13868,7 @@ t_bool build_dev_tab (void)
if ((nia_dev.flags & DEV_DIS) == 0 && dptr != &nia_dev && if ((nia_dev.flags & DEV_DIS) == 0 && dptr != &nia_dev &&
rh20 == (((DIB *)nia_dev.ctxt)->dev_num & 0777)) rh20 == (((DIB *)nia_dev.ctxt)->dev_num & 0777))
rh20 += 4; rh20 += 4;
else
/* If NIA20, then assign it to it's requested address */ /* If NIA20, then assign it to it's requested address */
if ((nia_dev.flags & DEV_DIS) == 0 && dptr == &nia_dev) if ((nia_dev.flags & DEV_DIS) == 0 && dptr == &nia_dev)
d = dibp->dev_num & 0777; d = dibp->dev_num & 0777;

402
PDP10/kx10_ddc.c Normal file
View file

@ -0,0 +1,402 @@
/* kx10_ddc.c: Drum RES-10 Disk Controller.
Copyright (c) 2013-2022, Richard Cornwell
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 MEDDCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
RICHARD CORNWELL 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.
*/
#include "kx10_defs.h"
#ifndef NUM_DEVS_DDC
#define NUM_DEVS_DDC 0
#endif
#if (NUM_DEVS_DDC > 0)
#define DDC_DEVNUM 0440 /* 0174 */
#define NUM_UNITS_DDC 4
/* Flags in the unit flags word */
#define UNIT_V_DTYPE (UNIT_V_UF + 0) /* disk type */
#define UNIT_M_DTYPE 1
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
/* Parameters in the unit descriptor */
#define STATUS u3 /* Current status */
#define POS u4 /* Position in sector buffer */
#define UFLAGS u5 /* Function */
#define SEC us9 /* Sector counter */
/* CONI bits */
#define QUEUE_PAR 0400000000000LL
#define DDC_BSY 0000001000000LL
#define DDC_DON 0000000400000LL
#define DDC_CSE 0000000001000LL
#define DDC_QF 0000000000400LL
#define DDC_RDY 0000000000200LL /* Drum Ready */
#define DDC_SPA 0000000000100LL /* Drum Silo Parity Error */
#define DDC_NXM 0000000000040LL /* NXM */
#define DDC_EXC 0000000000020LL /* Exceed Capacity */
#define DDC_HUD 0000000000010LL /* Drum Hung */
#define DDC_MPE 0000000000004LL /* MPE */
#define DDC_OVR 0000000000002LL /* Data overrun */
#define DDC_CKR 0000000000001LL /* Checksum error */
/* CONO bits */
#define DDC_RST 0000000600000LL /* Drum Reset */
#define DDC_CLR 0000000400000LL /* Clear Int */
#define DDC_ERR 0000000200000LL /* Clear Errors */
#define DDC_EXF 0000000100000LL /* Execute FR */
#define DDC_EXQ 0000000040000LL /* Execute Queue */
/* Command words */
#define DDC_CMD 0700000000000LL /* Drum command */
#define DDC_SEQ 0003700000000LL /* Sequence number */
#define DDC_PIA 0000070000000LL /* PIA */
#define DDC_FUNC 0000006000000LL /* Function */
#define DDC_READ 0000002000000LL
#define DDC_WRITE 0000004000000LL
#define DDC_DISK 0000001400000LL /* Logical Disc */
#define DDC_TRK 0000000377600LL /* Track */
#define DDC_SEC 0000000000177LL /* Sector */
/* DataI bits */
/* DDC_SEC 0000000000177LL Sector */
#define DDC_DONE 0400000000000LL /* Done flag */
/* Drum Status */
#define DDC_PWB 0700000000000LL
#define DDC_SECCNT 0017700000000LL /* Sequence counter */
#define DDC_ADDR 0000000777777LL
/* DataI */
/* 177 Sector number */
/* Number of sectors = 13 */
/* Sector size = 0200 words */
#define DDC10_WDS 0200
#define DDC_SIZE (7000 * DDC10_WDS)
uint64 ddc_buf[DDC10_WDS];
uint64 ddc_cmd[16];
int ddc_cmdptr;
int ddc_putptr;
t_stat ddc_devio(uint32 dev, uint64 *data);
t_stat ddc_svc(UNIT *);
void ddc_ini(UNIT *, t_bool);
t_stat ddc_reset(DEVICE *);
t_stat ddc_attach(UNIT *, CONST char *);
t_stat ddc_detach(UNIT *);
t_stat ddc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *ddc_description (DEVICE *dptr);
UNIT ddc_unit[] = {
/* Controller 1 */
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DDC_SIZE) },
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DDC_SIZE) },
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DDC_SIZE) },
{ UDATA (&ddc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+
UNIT_ROABLE, DDC_SIZE) },
};
DIB ddc_dib = {DDC_DEVNUM, 1, &ddc_devio, NULL};
MTAB ddc_mod[] = {
{ MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED",
&set_writelock, &show_writelock, NULL, "Write enable drive" },
{ MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED",
&set_writelock, NULL, NULL, "Write lock drive" },
{0}
};
REG ddc_reg[] = {
{0}
};
DEVICE ddc_dev = {
"DDC", ddc_unit, ddc_reg, ddc_mod,
NUM_UNITS_DDC, 8, 18, 1, 8, 36,
NULL, NULL, &ddc_reset, NULL, &ddc_attach, &ddc_detach,
&ddc_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &ddc_help, NULL, NULL, &ddc_description
};
t_stat ddc_devio(uint32 dev, uint64 *data) {
UNIT *uptr;
DEVICE *dptr;
dptr = &ddc_dev;
uptr = &dptr->units[0];
switch(dev & 3) {
case CONI:
sim_debug(DEBUG_CONI, dptr, "DDC %03o CONI %06o PC=%o\n", dev,
(uint32)*data, PC);
*data = uptr->STATUS;
if (ddc_cmdptr != ((ddc_putptr + 2) & 0xf)) {
*data |= DDC_RDY;
}
if (ddc_cmdptr == ddc_putptr) {
*data |= DDC_BSY;
}
*data |= ((t_uint64)uptr->UFLAGS) << 25;
break;
case CONO:
if (*data & DDC_CLR) { /* Clear irq */
uptr->STATUS &= ~(DDC_DON);
clr_interrupt(ddc_dib.dev_num);
}
if (*data & DDC_ERR) { /* Clear error */
uptr->STATUS &= ~(DDC_SPA|DDC_NXM|DDC_EXC|DDC_HUD|DDC_MPE|
DDC_OVR|DDC_CKR|DDC_QF);
}
if (*data & DDC_EXF) { /* Execute FR */
}
if (*data & DDC_EXQ) { /* Execute Queue */
if (!sim_is_active(uptr)) {
sim_activate(uptr, 100);
uptr->POS = 0;
}
}
sim_debug(DEBUG_CONO, dptr, "DDC %03o CONO %06o PC=%o\n", dev,
(uint32)*data, PC);
break;
case DATAI:
*data = (t_uint64)(uptr->SEC++);
uptr->SEC &= 0177;
if (uptr->SEC > (13 << 2))
uptr->SEC = 0;
if ((uptr->STATUS & DDC_DON) != 0)
*data |= DDC_DONE;
sim_debug(DEBUG_DATAIO, dptr, "DDC %03o DATI %012llo PC=%o\n",
dev, *data, PC);
break;
case DATAO:
sim_debug(DEBUG_DATAIO, dptr, "DDC %03o DATO %012llo, PC=%o\n",
dev, *data, PC);
/* Insert the command into the queue */
if (((ddc_putptr + 1) & 0xf) != ddc_cmdptr) {
int func;
int pia;
int dsk;
int trk;
int sec;
int seq;
ddc_cmd[ddc_putptr] = *data;
sec = ddc_cmd[ddc_putptr] & DDC_SEC;
trk = (ddc_cmd[ddc_putptr] & DDC_TRK) >> 7;
dsk = (ddc_cmd[ddc_putptr] & DDC_DISK) >> 17;
func = (ddc_cmd[ddc_putptr] & DDC_FUNC) >> 19;
pia = (ddc_cmd[ddc_putptr] & DDC_PIA) >> 21;
seq = (ddc_cmd[ddc_putptr] & DDC_SEQ) >> 24;
sim_debug(DEBUG_DETAIL, dptr, "DDC %d cmd %d %d %d %d %o\n",
dsk, trk, sec, func, pia, seq);
ddc_putptr = (ddc_putptr + 1) & 0xf;
} else {
uptr->STATUS |= DDC_QF;
}
break;
}
return SCPE_OK;
}
t_stat ddc_svc (UNIT *uptr)
{
int wc;
int func;
int pia;
int dsk;
int trk;
int sec;
int seq;
t_addr adr;
uint64 word;
DEVICE *dptr;
UNIT *duptr;
dptr = &ddc_dev;
sec = (ddc_cmd[ddc_cmdptr] & DDC_SEC) >> 2;
trk = (ddc_cmd[ddc_cmdptr] & DDC_TRK) >> 7;
dsk = (ddc_cmd[ddc_cmdptr] & DDC_DISK) >> 17;
func = (ddc_cmd[ddc_cmdptr] & DDC_FUNC) >> 19;
pia = (ddc_cmd[ddc_cmdptr] & DDC_PIA) >> 21;
seq = (ddc_cmd[ddc_cmdptr] & DDC_SEQ) >> 24;
word = ddc_cmd[ddc_cmdptr+1];
adr = word & RMASK;
duptr = &ddc_dev.units[dsk];
if ((duptr->flags & UNIT_ATT) == 0) {
uptr->STATUS |= DDC_DON|DDC_HUD;
uptr->UFLAGS = seq;
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Set done %d %d\n", dsk, pia, seq);
set_interrupt(ddc_dib.dev_num, pia);
uptr->POS = 0;
ddc_cmdptr += 2;
ddc_cmdptr &= 0xf;
if (ddc_cmdptr != ddc_putptr)
sim_activate(uptr, 100);
}
if (uptr->POS == 0) {
int da;
da = ((trk * 13) + sec) * DDC10_WDS;
(void)sim_fseek(duptr->fileref, da * sizeof(uint64), SEEK_SET);
wc = sim_fread (&ddc_buf[0], sizeof(uint64),
DDC10_WDS, duptr->fileref);
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Read %d %d %d %d %d %o\n",
dsk, da, trk, sec, func, pia, seq);
for (; wc < DDC10_WDS; wc++)
ddc_buf[wc] = 0;
}
if (func == 2) {
if (Mem_write_word(adr, &ddc_buf[uptr->POS], 0)) {
uptr->STATUS |= DDC_NXM;
goto done;
}
} else if (func == 1) {
if (Mem_read_word(adr, &ddc_buf[uptr->POS], 0)) {
uptr->STATUS |= DDC_NXM;
goto done;
}
}
sim_debug(DEBUG_DATA, dptr, "DDC %d xfer %06o %012llo\n",
dsk, adr, ddc_buf[uptr->POS]);
uptr->POS++;
word = (word & LMASK) | ((adr + 1) & RMASK);
if (uptr->POS == DDC10_WDS) {
done:
if (func == 2) {
int da;
da = ((trk * 13) + sec) * DDC10_WDS;
(void)sim_fseek(duptr->fileref, da * sizeof(uint64), SEEK_SET);
wc = sim_fwrite (&ddc_buf[0], sizeof(uint64),
DDC10_WDS, duptr->fileref);
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Write %d %d %d %d %d %o\n",
dsk, da, trk, sec, func, pia, seq);
}
sec ++;
ddc_cmd[ddc_cmdptr] &= ~DDC_SEC;
ddc_cmd[ddc_cmdptr] |= (DDC_SEC & (sec << 2));
word += 0000100000000LL;
sim_debug(DEBUG_DETAIL, dptr, "DDC %d next sect %012llo %012llo\n", dsk, word, ddc_cmd[ddc_cmdptr]);
if ((word & DDC_SECCNT) == 0) {
ddc_cmd[ddc_cmdptr+1] = (word & (DDC_SECCNT|DDC_PWB)) | (adr & RMASK);
uptr->STATUS |= DDC_DON;
uptr->UFLAGS = seq;
uptr->SEC = sec << 2;
sim_debug(DEBUG_DETAIL, dptr, "DDC %d Set done %d %d\n", dsk, pia, seq);
set_interrupt(ddc_dib.dev_num, pia);
uptr->POS = 0;
ddc_cmdptr += 2;
ddc_cmdptr &= 0xf;
if (ddc_cmdptr != ddc_putptr)
sim_activate(uptr, 100);
return SCPE_OK;
}
uptr->POS = 0;
}
ddc_cmd[ddc_cmdptr+1] = word;
sim_activate(uptr, 100);
return SCPE_OK;
}
t_stat
ddc_reset(DEVICE * dptr)
{
UNIT *uptr;
int i;
ddc_cmdptr = ddc_putptr = 0;
for (i = 0; i < NUM_UNITS_DDC; i++) {
uptr = &dptr->units[i];
uptr->SEC = 0;
uptr->UFLAGS = 0;
uptr->STATUS = 0;
}
return SCPE_OK;
}
/* Device attach */
t_stat ddc_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
r = attach_unit (uptr, cptr);
if (r != SCPE_OK || (sim_switches & SIM_SW_REST) != 0)
return r;
return SCPE_OK;
}
/* Device detach */
t_stat ddc_detach (UNIT *uptr)
{
if (!(uptr->flags & UNIT_ATT)) /* attached? */
return SCPE_OK;
if (sim_is_active (uptr)) /* unit active? */
sim_cancel (uptr); /* cancel operation */
return detach_unit (uptr);
}
t_stat ddc_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "DDC-10 Drum Drives (DDC)\n\n");
fprintf (st, "The DDC controller implements the RES-10 disk controller that talked\n");
fprintf (st, "to drum drives.\n");
fprintf (st, "Options include the ability to set units write enabled or write locked, to\n");
fprintf (st, "set the drive type to one of two disk types\n\n");
fprint_set_help (st, dptr);
fprint_show_help (st, dptr);
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
fprint_reg_help (st, dptr);
return SCPE_OK;
}
const char *ddc_description (DEVICE *dptr)
{
return "DDC-10 disk controller";
}
#endif

View file

@ -513,6 +513,8 @@ extern DEVICE pd_dev;
extern DEVICE pclk_dev; extern DEVICE pclk_dev;
extern DEVICE dpy_dev; extern DEVICE dpy_dev;
extern DEVICE iii_dev; extern DEVICE iii_dev;
extern DEVICE dd_dev;
extern DEVICE vds_dev;
extern DEVICE imx_dev; extern DEVICE imx_dev;
extern DEVICE imp_dev; extern DEVICE imp_dev;
extern DEVICE ch10_dev; extern DEVICE ch10_dev;
@ -528,7 +530,6 @@ extern DEVICE tv_dev;
extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */ extern DEVICE wcnsls_dev; /* MIT Spacewar Consoles */
extern DEVICE ocnsls_dev; /* Old MIT Spacewar Consoles */ extern DEVICE ocnsls_dev; /* Old MIT Spacewar Consoles */
extern DEVICE ai_dev; extern DEVICE ai_dev;
extern DEVICE dn_dev;
extern DEVICE dct_dev; /* PDP6 devices. */ extern DEVICE dct_dev; /* PDP6 devices. */
extern DEVICE dtc_dev; extern DEVICE dtc_dev;
extern DEVICE mtc_dev; extern DEVICE mtc_dev;
@ -540,6 +541,8 @@ extern DEVICE dup_dev;
extern DEVICE tcu_dev; extern DEVICE tcu_dev;
extern DEVICE ddc_dev; extern DEVICE ddc_dev;
extern DEVICE tym_dev; extern DEVICE tym_dev;
extern DEVICE ge_dev;
extern DEVICE gtyo_dev;
#if KS #if KS
@ -729,6 +732,8 @@ extern void ka10_lights_set_aux (int);
extern void ka10_lights_clear_aux (int); extern void ka10_lights_clear_aux (int);
#endif #endif
#define IBM_DEV 04000
/* I/O system parameters */ /* I/O system parameters */
#if !(PDP6 | KS) #if !(PDP6 | KS)
#define NUM_DEVS_LP 1 #define NUM_DEVS_LP 1
@ -748,6 +753,7 @@ extern void ka10_lights_clear_aux (int);
#define NUM_DEVS_DSK 1 #define NUM_DEVS_DSK 1
#define NUM_DEVS_DCS 1 #define NUM_DEVS_DCS 1
#define NUM_DEVS_SLAVE PDP6 #define NUM_DEVS_SLAVE PDP6
#define NUM_DEVS_GE PDP6
#endif #endif
#if !(PDP6 | KS) #if !(PDP6 | KS)
#define NUM_DEVS_DC 1 #define NUM_DEVS_DC 1
@ -758,7 +764,6 @@ extern void ka10_lights_clear_aux (int);
#define NUM_DEVS_TTY 1 #define NUM_DEVS_TTY 1
#define NUM_LINES_TTY 64 #define NUM_LINES_TTY 64
#define NUM_DEVS_NIA 1 #define NUM_DEVS_NIA 1
#define NUM_DEVS_DN 0
#elif KS #elif KS
#define NUM_DEVS_LP20 1 #define NUM_DEVS_LP20 1
#define NUM_DEVS_DZ 4 #define NUM_DEVS_DZ 4
@ -791,6 +796,7 @@ extern void ka10_lights_clear_aux (int);
#define NUM_DEVS_DKB (WAITS * USE_DISPLAY) #define NUM_DEVS_DKB (WAITS * USE_DISPLAY)
#define NUM_DEVS_III (WAITS * USE_DISPLAY) #define NUM_DEVS_III (WAITS * USE_DISPLAY)
#define NUM_DEVS_TV (WAITS * USE_DISPLAY) #define NUM_DEVS_TV (WAITS * USE_DISPLAY)
#define NUM_DEVS_DD (WAITS * USE_DISPLAY)
#define NUM_DEVS_PD ITS #define NUM_DEVS_PD ITS
#define NUM_DEVS_PCLK WAITS #define NUM_DEVS_PCLK WAITS
#define NUM_DEVS_IMX ITS #define NUM_DEVS_IMX ITS
@ -851,7 +857,7 @@ extern uint32 dd_keyboard_line (void *);
#endif #endif
#if PIDP10 #if PIDP10
void pi_panel_start(); t_stat pi_panel_start();
void pi_panel_stop(); void pi_panel_stop();
#endif #endif

View file

@ -363,6 +363,7 @@ static void dpy_joy_button(int which, int button, int state)
} }
} }
#if ITS
static int dpy_keyboard (SIM_KEY_EVENT *ev) static int dpy_keyboard (SIM_KEY_EVENT *ev)
{ {
sim_debug(DEBUG_DATA, &dpy_dev, "Key %d %s\n", sim_debug(DEBUG_DATA, &dpy_dev, "Key %d %s\n",
@ -373,6 +374,7 @@ static int dpy_keyboard (SIM_KEY_EVENT *ev)
} }
return 0; return 0;
} }
#endif
/* Reset routine */ /* Reset routine */

View file

@ -545,7 +545,6 @@ t_stat dt_devio(uint32 dev, uint64 *data) {
} }
void dt_getword(uint64 *data, int req) { void dt_getword(uint64 *data, int req) {
int dev = dt_dib.dev_num;
clr_interrupt(DT_DEVNUM|4); clr_interrupt(DT_DEVNUM|4);
if (dtsb & DTB_DATREQ) { if (dtsb & DTB_DATREQ) {
dtsb |= DTB_MIS; dtsb |= DTB_MIS;
@ -559,7 +558,6 @@ void dt_getword(uint64 *data, int req) {
} }
void dt_putword(uint64 *data) { void dt_putword(uint64 *data) {
int dev = dt_dib.dev_num;
clr_interrupt(DT_DEVNUM|4); clr_interrupt(DT_DEVNUM|4);
if (dtsb & DTB_DATREQ) { if (dtsb & DTB_DATREQ) {
dtsb |= DTB_MIS; dtsb |= DTB_MIS;

View file

@ -1094,18 +1094,17 @@ rp_boot(int32 unit_num, DEVICE * rptr)
{ {
UNIT *uptr = &rptr->units[unit_num]; UNIT *uptr = &rptr->units[unit_num];
int ctlr = GET_CNTRL_RH(uptr->flags); int ctlr = GET_CNTRL_RH(uptr->flags);
int dtype = GET_DTYPE(uptr->flags);
uint16 *regs = (uint16 *)(uptr->up7); uint16 *regs = (uint16 *)(uptr->up7);
struct rh_if *rhc = &rp_rh[ctlr]; struct rh_if *rhc = &rp_rh[ctlr];
DEVICE *dptr = uptr->dptr; DEVICE *dptr = uptr->dptr;
uint32 addr; uint32 addr;
uint32 ptr = 0;
uint64 word; uint64 word;
#if !KS #if !KS
int wc; int wc;
#endif #endif
#if KS #if KS
int dtype = GET_DTYPE(uptr->flags);
int da; int da;
t_stat r; t_stat r;
uint64 len; uint64 len;
@ -1147,7 +1146,7 @@ rp_boot(int32 unit_num, DEVICE * rptr)
regs[RPDC] = (int32)((rp_buf[0][04] >> 24) << DC_V_CY); regs[RPDC] = (int32)((rp_buf[0][04] >> 24) << DC_V_CY);
len = (int)(((rp_buf[0][05] & 077) * 4) & RMASK); len = (int)(((rp_buf[0][05] & 077) * 4) & RMASK);
} }
if (len == 0) if (len == 0)
len = 4; len = 4;
/* Read len sectors into address 1000 */ /* Read len sectors into address 1000 */
addr = 01000; addr = 01000;
@ -1176,6 +1175,8 @@ if (len == 0)
rh_boot_unit = unit_num; rh_boot_unit = unit_num;
#elif KL #elif KL
int sect; int sect;
uint32 ptr = 0;
/* KL does not support readin, so fake it by reading in sectors 4 to 7 */ /* KL does not support readin, so fake it by reading in sectors 4 to 7 */
/* Possible in future find boot loader in FE file system */ /* Possible in future find boot loader in FE file system */
addr = (MEMSIZE - 512) & RMASK; addr = (MEMSIZE - 512) & RMASK;
@ -1189,6 +1190,8 @@ if (len == 0)
} }
word = (MEMSIZE - 512) & RMASK; word = (MEMSIZE - 512) & RMASK;
#else #else
uint32 ptr = 0;
disk_read(uptr, &rp_buf[0][0], 0, RP_NUMWD); disk_read(uptr, &rp_buf[0][0], 0, RP_NUMWD);
addr = rp_buf[0][ptr] & RMASK; addr = rp_buf[0][ptr] & RMASK;
wc = (rp_buf[0][ptr++] >> 18) & RMASK; wc = (rp_buf[0][ptr++] >> 18) & RMASK;

View file

@ -177,6 +177,10 @@ DEVICE *sim_devices[] = {
#if (NUM_DEVS_TV > 0) #if (NUM_DEVS_TV > 0)
&tv_dev, &tv_dev,
#endif #endif
#if (NUM_DEVS_DD > 0)
&dd_dev,
&vds_dev,
#endif
#if NUM_DEVS_IMP > 0 #if NUM_DEVS_IMP > 0
&imp_dev, &imp_dev,
#endif #endif
@ -233,8 +237,15 @@ DEVICE *sim_devices[] = {
#if NUM_DEVS_DUP > 0 #if NUM_DEVS_DUP > 0
&dup_dev, &dup_dev,
#endif #endif
#if NUM_DEVS_DN > 0 #if NUM_DEVS_DDC > 0
&dn_dev, &ddc_dev,
#endif
#if NUM_DEVS_TYM > 0
&tym_dev,
#endif
#if NUM_DEVS_GE > 0
&ge_dev,
&gtyo_dev,
#endif #endif
NULL NULL
}; };
@ -720,6 +731,8 @@ t_stat load_exe (FILE *fileref, int ftype)
} }
if ((sim_switches & SWMASK ('M')) == 0) { /* -m? */ if ((sim_switches & SWMASK ('M')) == 0) { /* -m? */
ma = mpage << PAG_V_PN; /* mem addr */ ma = mpage << PAG_V_PN; /* mem addr */
} else {
ma = mpage;
} }
for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */ for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */
if (ma > MEMSIZE) if (ma > MEMSIZE)

View file

@ -416,7 +416,6 @@ tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
int int
tu_read(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 *data) { tu_read(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 *data) {
int ctlr = GET_CNTRL_RH(dptr->units[0].flags);
uint16 *regs = &rhc->regs[0]; uint16 *regs = &rhc->regs[0];
int unit = regs[TUTC] & 07; int unit = regs[TUTC] & 07;
UNIT *uptr = &dptr->units[unit]; UNIT *uptr = &dptr->units[unit];

684
PDP10/kx10_tym.c Normal file
View file

@ -0,0 +1,684 @@
/* kx10_tym.c: TYM, interface to Tymbase and Tymnet.
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
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.
*/
#include "kx10_defs.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_TYM
#define NUM_DEVS_TYM 0
#endif
#if NUM_DEVS_TYM > 0
#define TYM_NAME "TYM"
#define MAX_LINES 32 /* Maximum found in the wild. */
#define KEY 0633751506262LL /* Base key. */
#define BASE 02000 /* Default base address. */
#define SIZE 01000 /* Default size. */
#define LOCK 000 /* Key. */
#define DUMP 002 /* Base dump loc * 16. */
#define IRNG 003 /* Input ring loc * 16. */
#define ISIZ 004 /* Input ring size * 16. */
#define IHP 005 /* Host set input pointer. */
#define IBP 006 /* Base set input pointer. */
#define ORNG 007 /* Output ring loc * 16. */
#define OSIZ 010 /* Output ring size * 16. */
#define OHP 011 /* Host set output pointer. */
#define OBP 012 /* Base set output pointer. */
#define BCRSH 013 /* Base set crash indicator + reason. */
#define HCRSH 014 /* Host set crash reason. */
#define TYMBAS_ANS 001
#define TYMBAS_SHT 002
#define TYMBAS_CRS 003
#define TYMBAS_DIE 004
#define TYMBAS_NSP 005
#define TYMBAS_LOG 006
#define TYMBAS_AUX 007
#define TYMBAS_NOP 010
#define TYMBAS_OUP 011
#define TYMBAS_GOB 012
#define TYMBAS_ZAP 013
#define TYMBAS_EDC 014
#define TYMBAS_LDC 015
#define TYMBAS_GRN 016
#define TYMBAS_RED 017
#define TYMBAS_YEL 020
#define TYMBAS_ORG 021
#define TYMBAS_HNG 022
#define TYMBAS_ETM 023
#define TYMBAS_LTM 024
#define TYMBAS_LOS 025
#define TYMBAS_SUP 026
#define TYMBAS_SUR 027
#define TYMBAS_AXC 030
#define TYMBAS_TSP 031
#define TYMBAS_TSR 032
#define TYMBAS_SAD 033
#define TYMBAS_ECN 034
#define TYMBAS_ECF 035
#define TYMBAS_TCS 036
#define TYMBAS_TCP 037
#define TYMBAS_TCR 040
#define TYMBAS_HSI 041
#define TYMBAS_DATA 0200
static t_stat tym_reset(DEVICE *dptr);
static t_stat tym_attach(UNIT * uptr, CONST char * cptr);
static t_stat tym_detach(UNIT * uptr);
static t_stat tym_interface_srv(UNIT *);
static t_stat tym_alive_srv(UNIT *);
static t_stat tym_input_srv(UNIT *);
static t_stat tym_output_srv(UNIT *);
static const char *tym_description(DEVICE *dptr);
static TMLN tym_ldsc[MAX_LINES] = { 0 };
static TMXR tym_desc = { MAX_LINES, 0, 0, tym_ldsc };
static UNIT tym_unit[] = {
{ UDATA(tym_input_srv, TT_MODE_8B|UNIT_IDLE|UNIT_ATTABLE, 0) },
{ UDATA(tym_output_srv, UNIT_IDLE, 0) },
{ UDATA(tym_interface_srv, UNIT_IDLE, 0) },
{ UDATA(tym_alive_srv, UNIT_IDLE, 0) }
};
static MTAB tym_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &tym_desc, "Disconnect a specific line" },
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
NULL, &tmxr_show_summ, (void *) &tym_desc, "Display a summary of line states" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &tym_desc, "Display current connections" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &tym_desc, "Display multiplexer statistics" },
{ 0 }
};
/* Simulator debug controls */
static DEBTAB tym_debug[] = {
{"CMD", DEBUG_CMD, "Show command execution to devices"},
{"DATA", DEBUG_DATA, "Show data transfers"},
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"EXP", DEBUG_EXP, "Show exception information"},
{"IRQ", DEBUG_IRQ, "Show IRQ requests"},
{0, 0}
};
static int tym_host = 0;
static int tym_base = BASE;
static int tym_size = SIZE;
static uint64 tym_key = KEY;
static int output_port;
static int output_count;
static REG tym_reg[] = {
{ ORDATA(HOST, tym_host, 16) },
{ ORDATA(BASE, tym_base, 22) },
{ ORDATA(SIZE, tym_size, 18) },
{ ORDATA(KEY, tym_key, 36) },
{ ORDATA(PORTS, tym_desc.lines, 8) },
{ 0 }
};
DEVICE tym_dev = {
"TYM", tym_unit, tym_reg, tym_mod,
4, 8, 0, 1, 8, 36,
NULL, NULL, &tym_reset, NULL, &tym_attach, &tym_detach,
NULL, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, tym_debug,
NULL, NULL, NULL, NULL, NULL, &tym_description
};
static t_stat tym_reset(DEVICE *dptr)
{
if (tym_unit[0].flags & UNIT_ATT) {
sim_activate(&tym_unit[2], 1000);
sim_activate(&tym_unit[3], 1000);
} else {
sim_cancel(&tym_unit[0]);
sim_cancel(&tym_unit[1]);
sim_cancel(&tym_unit[2]);
sim_cancel(&tym_unit[3]);
}
return SCPE_OK;
}
static void block(void)
{
int i;
for (i = 0; i < MAX_LINES; i++) {
tym_ldsc[i].rcve = 0;
tym_ldsc[i].xmte = 0;
}
}
static t_stat tym_attach(UNIT *uptr, CONST char *cptr)
{
t_stat stat = tmxr_attach(&tym_desc, uptr, cptr);
block();
tym_reset(&tym_dev);
return stat;
}
static t_stat tym_detach(UNIT *uptr)
{
t_stat stat = tmxr_detach(&tym_desc, uptr);
block();
tym_reset(&tym_dev);
return stat;
}
static uint64 word(int pointer, int base)
{
t_addr address = (M[tym_base + base] >> 4) & RMASK;
address += M[tym_base + pointer] & RMASK;
return M[address];
}
static void next(int pointer, int size)
{
uint64 modulo = M[tym_base + size] >> 4;
M[tym_base + pointer] = (M[tym_base + pointer] + 1) % modulo;
}
static void tym_input(uint64 data)
{
t_addr address = (M[tym_base + IRNG] >> 4) & RMASK;
address += M[tym_base + IBP] & RMASK;
M[address] = data;
}
static uint64 room (int h, int t, int s)
{
uint64 head = M[tym_base + h];
uint64 tail = M[tym_base + t];
uint64 size = M[tym_base + s] >> 4;
return size - (head - tail) % size;
}
static void send_word(int type, int port, int data1, int data2)
{
uint64 data;
sim_debug(DEBUG_DETAIL, &tym_dev,
"Input from base: %03o %03o %03o %03o\n",
type, port, data1, data2);
/* The input ring buffer must have at least one word free. */
if (room (IBP, IHP, ISIZ) <= 1)
return;
data = (uint64)type << 28;
data |= (uint64)port << 20;
data |= (uint64)data1 << 12;
data |= (uint64)data2 << 4;
tym_input(data);
next(IBP, ISIZ);
}
static void send_character(int port, int c)
{
sim_debug(DEBUG_DATA, &tym_dev, "Base: send port %d %03o '%c'.\n",
port, c, c);
send_word(TYMBAS_DATA | 1, port, c, 0);
}
static void send_string(int port, const char *string)
{
int n = strlen(string);
int m;
for (;;) {
if (n <= 0)
return;
else if (n == 1) {
send_character(port, string[0]);
return;
}
m = n > 0177 ? 0177 : n;
n -= m;
send_word(TYMBAS_DATA | m, port, string[0], string[1]);
string += 2;
m -= 2;
while (m > 0) {
send_word(string[0], string[1], string[2], string[3]);
string += 4;
m -= 4;
}
}
}
static void send_login(int port)
{
sim_debug(DEBUG_CMD, &tym_dev, "Base: send login %d.\n", port);
send_word(TYMBAS_LOG, port, 0, 0);
/* This isn't right, but good enough for now. */
send_string(port, ".....USER\r");
}
static void send_zap(int port)
{
sim_debug(DEBUG_CMD, &tym_dev, "Base: send zap %d.\n", port);
send_word(TYMBAS_ZAP, port, 0, 0);
}
static void send_orange (int port)
{
sim_debug(DEBUG_CMD, &tym_dev, "Base: send orange ball %d.\n", port);
send_word(TYMBAS_ORG, port, 0, 0);
}
static void recv_ans(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "system is answering\n");
sim_activate(&tym_unit[0], 1000);
}
static void recv_sht(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "system is up but shut\n");
}
static void recv_crs(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "sender is crashed\n");
}
static void recv_die(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "recipient should crash\n");
}
static void recv_nsp(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "base taken over by new supervisor\n");
}
static void recv_log(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "login\n");
//next 4 data chrs are the info about terminal type, and port or
//origin, then name, etc.
}
static void recv_aux(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "supervisor response to establishing auxillary circuit\n");
}
static void recv_nop(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " backpressure on\n");
}
static void recv_oup(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " backpressure off\n");
}
static void recv_gob(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " character gobbler\n");
}
static void recv_zap(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, "Zap circuit, port %d\n", port);
tmxr_reset_ln (&tym_ldsc[port]);
tym_ldsc[port].rcve = 0;
tym_ldsc[port].xmte = 0;
}
static void recv_edc(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " enter defered echo mode\n");
}
static void recv_ldc(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " leave deferred echo mode\n");
}
static void recv_grn(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " green ball\n");
}
static void recv_red(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " red ball\n");
}
static void recv_yel(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " yellow ball\n");
send_orange (port);
}
static void recv_org(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " orange ball\n");
}
static void recv_hng(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " hang character - not used\n");
}
static void recv_etm(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " enter 2741 transparent mode\n");
}
static void recv_ltm(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " leave 2741 transparent mode\n");
}
static void recv_los(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " lost ball\n");
//data has been lost from buffers. the data filed may tell how
//many were lost
}
static void recv_sup(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " supervisor request(aux circuits)\n");
}
static void recv_sur(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " supervisor response(aux circuits)\n");
}
static void recv_axc(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " supervisor string character\n");
}
static void recv_tsp(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " test pattern probe\n");
}
static void recv_tsr(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " test pattern response\n");
}
static void recv_sad(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " host sad\n");
}
static void recv_ecn(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " echo on\n");
}
static void recv_ecf(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " echo off\n");
}
static void recv_tcs(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " term characteristics\n");
//first data byte indicates which characteristics second data byte
//indicates value to set to
}
static void recv_tcp(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " term characteristcs probe\n");
//data byte indicates which terminal characteristic were requested
}
static void recv_tcr(int port, int subtype, int data)
{
sim_debug(DEBUG_CMD, &tym_dev, " term characteristcs response\n");
//data is just like tcs, comes in response to a probe; also is
//reflected by remote when terminal characteristics are sent
}
static void recv_hsi(int port, int subtype, int data)
{
tym_host = (subtype << 8) | data;
sim_debug(DEBUG_CMD, &tym_dev, "Host number %06o, %d ports\n",
tym_host, port);
/* Close ports above the host-annonuced maximum. */
tym_desc.lines = port;
if (tym_desc.lines > MAX_LINES)
tym_desc.lines = MAX_LINES;
for (port = tym_desc.lines; port < MAX_LINES; port++)
tmxr_reset_ln (&tym_ldsc[port]);
sim_activate(&tym_unit[0], 1000);
}
typedef void (*msgfn) (int, int, int);
static msgfn output[] = {
NULL,
recv_ans,
recv_sht,
recv_crs,
recv_die,
recv_nsp,
recv_log,
recv_aux,
recv_nop,
recv_oup,
recv_gob,
recv_zap,
recv_edc,
recv_ldc,
recv_grn,
recv_red,
recv_yel,
recv_org,
recv_hng,
recv_etm,
recv_ltm,
recv_los,
recv_sup,
recv_sur,
recv_axc,
recv_tsp,
recv_tsr,
recv_sad,
recv_ecn,
recv_ecf,
recv_tcs,
recv_tcp,
recv_tcr,
recv_hsi
};
static void output_data(int port, int n)
{
uint64 data;
int i = 2, c;
sim_debug(DEBUG_DATA, &tym_dev,
"Output from host: %d characters to port %d\n", n, port);
data = word(OBP, ORNG) << 16; /* Discard header. */
goto start;
while (n > 0) {
data = word(OBP, ORNG);
start:
for (; i < 4 && n > 0; i++, n--) {
c = (data >> 28) & 0177;
data <<= 8;
sim_debug(DEBUG_DATA, &tym_dev,
"Host: send port %d %03o '%c'.\n", port, c, c);
tmxr_putc_ln(&tym_ldsc[port], c);
tmxr_poll_tx(&tym_desc);
}
i = 0;
next(OBP, OSIZ);
}
}
static void tym_output(void)
{
int type, port, subtype, data;
while (M[tym_base + OBP] != M[tym_base + OHP]) {
sim_debug(DEBUG_DETAIL, &tym_dev, "Output from host: %llu %012llo\n",
M[tym_base + OBP], word(OBP, ORNG));
type = word(OBP, ORNG) >> 28;
port = (word(OBP, ORNG) >> 20) & 0377;
subtype = (word(OBP, ORNG) >> 12) & 0377;
data = (word(OBP, ORNG) >> 4) & 0377;
sim_debug(DEBUG_DETAIL, &tym_dev,
"Type %03o, port %03o, subtype %03o, data %03o\n",
type, port, subtype, data);
if (type >= 1 && type <= 41) {
output[type] (port, subtype, data);
next(OBP, OSIZ);
} else if (type & 0200)
output_data(port, type & 0177);
}
}
static uint64 lock = ~0ULL;
static uint64 dump = ~0ULL;
static uint64 irng = ~0ULL;
static uint64 isiz = ~0ULL;
static uint64 ihp = ~0ULL;
static uint64 ibp = ~0ULL;
static uint64 orng = ~0ULL;
static uint64 osiz = ~0ULL;
static uint64 ohp = ~0ULL;
static uint64 obp = ~0ULL;
static uint64 bcrsh = ~0ULL;
static uint64 hcrsh = ~0ULL;
static void check(const char *name, int offset, uint64 *value)
{
uint64 x = M[tym_base + offset];
if (x != *value) {
sim_debug(DEBUG_DETAIL, &tym_dev, "%s: %012llo\n", name, x);
*value = x;
}
}
static t_stat tym_interface_srv(UNIT *uptr)
{
check("Dump location", DUMP, &dump);
check("Input ring location", IRNG, &irng);
check("Input ring size", ISIZ, &isiz);
check("Host input pointer", IHP, &ihp);
check("Base input pointer", IBP, &ibp);
check("Output ring location", ORNG, &orng);
check("Output ring size", OSIZ, &osiz);
check("Host output pointer", OHP, &ohp);
check("Base output pointer", OBP, &obp);
check("Base crash reason", BCRSH, &bcrsh);
check("Host crash reason", HCRSH, &hcrsh);
if (ohp != obp)
tym_output();
sim_activate_after(&tym_unit[2], 1000);
return SCPE_OK;
}
static t_stat tym_alive_srv(UNIT *uptr)
{
if (M[tym_base + LOCK] == tym_key) {
M[tym_base + LOCK] = 1;
}
sim_activate_after(&tym_unit[3], 500000);
return SCPE_OK;
}
static t_stat tym_input_srv(UNIT *uptr)
{
int32 ch;
int i;
if (room (IBP, IHP, ISIZ) > 1) {
i = tmxr_poll_conn(&tym_desc);
if (i >= 0) {
tym_ldsc[i].rcve = 1;
tym_ldsc[i].xmte = 1;
send_login(i);
}
}
tmxr_poll_rx(&tym_desc);
for (i = 0; i < tym_desc.lines; i++) {
if (tym_ldsc[i].xmte && tym_ldsc[i].conn == 0) {
tmxr_reset_ln (&tym_ldsc[i]);
tym_ldsc[i].rcve = 0;
tym_ldsc[i].xmte = 0;
send_zap(i);
continue;
}
/* The input ring buffer must have at least one word free. */
if (room (IBP, IHP, ISIZ) <= 1)
continue;
ch = tmxr_getc_ln(&tym_ldsc[i]);
if (ch & TMXR_VALID)
send_character(i, ch & 0377);
}
sim_activate(&tym_unit[0], 1000);
return SCPE_OK;
}
static t_stat tym_output_srv(UNIT *uptr)
{
uint64 data;
int c;
if (!tmxr_txdone_ln(&tym_ldsc[output_port])) {
sim_activate(&tym_unit[1], 1000);
return SCPE_OK;
}
data = word(OBP, ORNG);
c = (data >> 28) & 0177;
data <<= 8;
sim_debug(DEBUG_DATA, &tym_dev,
"Host: send port %d %03o '%c'.\n", output_port, c, c);
if (tmxr_putc_ln(&tym_ldsc[output_port], c) == SCPE_STALL)
return SCPE_OK;
next(OBP, OSIZ);
if (output_count > 0)
sim_activate(&tym_unit[1], 1000);
return SCPE_OK;
}
static const char *tym_description(DEVICE *dptr)
{
return "Tymnet interface";
}
#endif

493
PDP10/pdp11_ddcmp.h Normal file
View file

@ -0,0 +1,493 @@
/* pdp11_ddcmp.h: Digital Data Communications Message Protocol support
Copyright (c) 2013, Mark Pizzolato
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
ROBERT M SUPNIK 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 Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
Digital Data Communications Message Protocol - DDCMP support routines
29-May-13 MP Initial implementation
*/
#ifndef PDP11_DDCMP_H_
#define PDP11_DDCMP_H_ 0
#include "sim_tmxr.h"
/* DDCMP packet types */
#define DDCMP_SYN 0226u /* Sync character on synchronous links */
#define DDCMP_DEL 0377u /* Sync character on asynchronous links */
#define DDCMP_SOH 0201u /* Numbered Data Message Identifier */
#define DDCMP_ENQ 0005u /* Control Message Identifier */
#define DDCMP_DLE 0220u /* Maintenance Message Identifier */
#define DDCMP_CTL_ACK 1 /* Control Message ACK Type */
#define DDCMP_CTL_NAK 2 /* Control Message NAK Type */
#define DDCMP_CTL_REP 3 /* Control Message REP Type */
#define DDCMP_CTL_STRT 6 /* Control Message STRT Type */
#define DDCMP_CTL_STACK 7 /* Control Message STACK Type */
#define DDCMP_FLAG_SELECT 0x2 /* Link Select */
#define DDCMP_FLAG_QSYNC 0x1 /* Quick Sync (next message won't abut this message) */
#define DDCMP_CRC_SIZE 2 /* Bytes in DDCMP CRC fields */
#define DDCMP_HEADER_SIZE 8 /* Bytes in DDCMP Control and Data Message headers (including header CRC) */
#define DDCMP_RESP_OFFSET 3 /* Byte offset of response (ack) number field */
#define DDCMP_NUM_OFFSET 4 /* Byte offset of packet number field */
#define DDCMP_PACKET_TIMEOUT 4 /* Seconds before sending REP command for unacknowledged packets */
#define DDCMP_DBG_PXMT TMXR_DBG_PXMT /* Debug Transmitted Packet Header Contents */
#define DDCMP_DBG_PRCV TMXR_DBG_PRCV /* Debug Received Packet Header Contents */
#define DDCMP_DBG_PDAT 0x00004000 /* Debug Packet Data */
/* Support routines */
/* crc16 polynomial x^16 + x^15 + x^2 + 1 (0xA001) CCITT LSB */
static uint16 crc16_nibble[16] = {
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400,
};
static uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len)
{
const unsigned char* buf = (const unsigned char*)vbuf;
while(0 != len--) {
crc = (crc>>4) ^ crc16_nibble[(*buf ^ crc) & 0xF];
crc = (crc>>4) ^ crc16_nibble[((*buf++)>>4 ^ crc) & 0xF];
};
return(crc);
}
/* Debug routines */
#include <ctype.h>
static void ddcmp_packet_trace (uint32 reason, DEVICE *dptr, const char *txt, const uint8 *msg, int32 len)
{
if (sim_deb && dptr && (reason & dptr->dctrl)) {
int i, same, group, sidx, oidx;
char outbuf[80], strbuf[18];
static const char hex[] = "0123456789ABCDEF";
static const char *const flags [4] = { "..", ".Q", "S.", "SQ" };
static const char *const nak[18] = { "", " (HCRC)", " (DCRC)", " (REPREPLY)", /* 0-3 */
"", "", "", "", /* 4-7 */
" (NOBUF)", " (RXOVR)", "", "", /* 8-11 */
"", "", "", "", /* 12-15 */
" (TOOLONG)", " (HDRFMT)" }; /* 16-17 */
const char *flag = flags[msg[2]>>6];
int msg2 = msg[2] & 0x3F;
sim_debug(reason, dptr, "%s len: %d\n", txt, len);
switch (msg[0]) {
case DDCMP_SOH: /* Data Message */
sim_debug (reason, dptr, "Data Message, Count: %d, Num: %d, Flags: %s, Resp: %d, HDRCRC: %s, DATACRC: %s\n", (msg2 << 8)|msg[1], msg[4], flag, msg[3],
(0 == ddcmp_crc16 (0, msg, 8)) ? "OK" : "BAD", (0 == ddcmp_crc16 (0, msg+8, 2+((msg2 << 8)|msg[1]))) ? "OK" : "BAD");
break;
case DDCMP_ENQ: /* Control Message */
sim_debug (reason, dptr, "Control: Type: %d ", msg[1]);
switch (msg[1]) {
case DDCMP_CTL_ACK: /* ACK */
sim_debug (reason, dptr, "(ACK) ACKSUB: %d, Flags: %s, Resp: %d\n", msg2, flag, msg[3]);
break;
case DDCMP_CTL_NAK: /* NAK */
sim_debug (reason, dptr, "(NAK) Reason: %d%s, Flags: %s, Resp: %d\n", msg2, ((msg2 > 17)? "": nak[msg2]), flag, msg[3]);
break;
case DDCMP_CTL_REP: /* REP */
sim_debug (reason, dptr, "(REP) REPSUB: %d, Num: %d, Flags: %s\n", msg2, msg[4], flag);
break;
case DDCMP_CTL_STRT: /* STRT */
sim_debug (reason, dptr, "(STRT) STRTSUB: %d, Flags: %s\n", msg2, flag);
break;
case DDCMP_CTL_STACK: /* STACK */
sim_debug (reason, dptr, "(STACK) STCKSUB: %d, Flags: %s\n", msg2, flag);
break;
default: /* Unknown */
sim_debug (reason, dptr, "(Unknown=0%o)\n", msg[1]);
break;
}
if (len != DDCMP_HEADER_SIZE) {
sim_debug (reason, dptr, "Unexpected Control Message Length: %d expected %d\n", len, DDCMP_HEADER_SIZE);
}
if (0 != ddcmp_crc16 (0, msg, len)) {
sim_debug (reason, dptr, "Unexpected Message CRC\n");
}
break;
case DDCMP_DLE: /* Maintenance Message */
sim_debug (reason, dptr, "Maintenance Message, Count: %d, Flags: %s, Addr: %d, HDRCRC: %s, DATACRC: %s\n", (msg2 << 8)|msg[1], flag, msg[5],
(0 == ddcmp_crc16 (0, msg, DDCMP_HEADER_SIZE)) ? "OK" : "BAD", (0 == ddcmp_crc16 (0, msg+DDCMP_HEADER_SIZE, 2+((msg2 << 8)|msg[1]))) ? "OK" : "BAD");
break;
}
if (DDCMP_DBG_PDAT & dptr->dctrl) {
for (i=same=0; i<len; i += 16) {
if ((i > 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) {
++same;
continue;
}
if (same > 0) {
sim_debug(reason, dptr, "%04X thru %04X same as above\n", i-(16*same), i-1);
same = 0;
}
group = (((len - i) > 16) ? 16 : (len - i));
for (sidx=oidx=0; sidx<group; ++sidx) {
outbuf[oidx++] = ' ';
outbuf[oidx++] = hex[(msg[i+sidx]>>4)&0xf];
outbuf[oidx++] = hex[msg[i+sidx]&0xf];
if (isprint(msg[i+sidx]))
strbuf[sidx] = msg[i+sidx];
else
strbuf[sidx] = '.';
}
outbuf[oidx] = '\0';
strbuf[sidx] = '\0';
sim_debug(reason, dptr, "%04X%-48s %s\n", i, outbuf, strbuf);
}
if (same > 0) {
sim_debug(reason, dptr, "%04X thru %04X same as above\n", i-(16*same), len-1);
}
}
}
}
uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len);
/* Data corruption troll, which simulates imperfect links.
*/
/* Evaluate the corruption troll's appetite.
*
* A message can be eaten (dropped), nibbled (corrupted) or spared.
*
* The probability of a message not being spared is trollHungerLevel,
* expressed in milli-gulps - 0.1%. The troll selects which action
* to taken on selected messages with equal probability.
*
* Nibbled messages' CRCs are changed when possible to simplify
* identifying them when debugging. When it's too much work to
* find the CRC, the first byte of data is changed. The change
* is an XOR to make it possible to reconstruct the original data.
*
* A particularly unfortunate message can be nibbled by both
* the transmitter and receiver; thus the troll applies a direction-
* dependent pattern.
*
* Return TRUE if the troll ate the message.
* Return FALSE if the message was nibbled or spared.
*/
static t_bool ddcmp_feedCorruptionTroll (TMLN *lp, uint8 *msg, t_bool rx, int32 trollHungerLevel)
{
double r, rmax;
char msgbuf[80];
if (trollHungerLevel == 0)
return FALSE;
r = rand();
rmax = (double)RAND_MAX;
if (msg[0] == DDCMP_ENQ) {
int eat = 0 + (int) (2000.0 * (r / (rmax + 1.0)));
if (eat <= (trollHungerLevel * 2)) { /* Hungry? */
if (eat <= trollHungerLevel) { /* Eat the packet */
sprintf (msgbuf, "troll ate a %s control message\n", rx ? "RCV" : "XMT");
tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf);
return TRUE;
}
sprintf (msgbuf, "troll bit a %s control message\n", rx ? "RCV" : "XMT");
tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf);
msg[6] ^= rx? 0114: 0154; /* Eat the CRC */
}
}
else {
int eat = 0 + (int) (3000.0 * (r / (rmax + 1.0)));
if (eat <= (trollHungerLevel * 3)) { /* Hungry? */
if (eat <= trollHungerLevel) { /* Eat the packet */
sprintf (msgbuf, "troll ate a %s %s message\n", rx ? "RCV" : "XMT", (msg[0] == DDCMP_SOH)? "data" : "maintenance");
tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf);
return TRUE;
}
if (eat <= (trollHungerLevel * 2)) { /* HCRC */
sprintf (msgbuf, "troll bit a %s %s message\n", rx ? "RCV" : "XMT", (msg[0] == DDCMP_SOH)? "data" : "maintenance");
tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf);
msg[6] ^= rx? 0124: 0164;
}
else { /* DCRC */
sprintf (msgbuf, "troll bit %s %s DCRC\n", (rx? "RCV" : "XMT"), ((msg[0] == DDCMP_SOH)? "data" : "maintenance"));
tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf);
msg[8] ^= rx? 0114: 0154; /* Rather than find the CRC, the first data byte will do */
}
}
}
return FALSE;
}
/* Get packet from specific line
Inputs:
*lp = pointer to terminal line descriptor
**pbuf = pointer to pointer of packet contents
*psize = pointer to packet size
Output:
SCPE_LOST link state lost
SCPE_OK Packet returned OR no packet available
Implementation notes:
1. If a packet is not yet available, then the pbuf address returned is
NULL, but success (SCPE_OK) is returned
*/
static t_stat ddcmp_tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, uint16 *psize, int32 corruptrate)
{
int32 c;
size_t payloadsize;
char msg[32];
while (TMXR_VALID & (c = tmxr_getc_ln (lp))) {
c &= ~TMXR_VALID;
if (lp->rxpboffset + 1 > lp->rxpbsize) {
lp->rxpbsize += 512;
lp->rxpb = (uint8 *)realloc (lp->rxpb, lp->rxpbsize);
}
lp->rxpb[lp->rxpboffset] = (uint8)c;
if ((lp->rxpboffset == 0) && ((c == DDCMP_SYN) || (c == DDCMP_DEL))) {
tmxr_debug (DDCMP_DBG_PRCV, lp, "Ignoring Interframe Sync Character", (char *)&lp->rxpb[0], 1);
continue;
}
lp->rxpboffset += 1;
if (lp->rxpboffset == 1) {
switch (c) {
default:
tmxr_debug (DDCMP_DBG_PRCV, lp, "Ignoring unexpected byte in DDCMP mode", (char *)&lp->rxpb[0], 1);
lp->rxpboffset = 0;
case DDCMP_SOH:
case DDCMP_ENQ:
case DDCMP_DLE:
continue;
}
}
if (lp->rxpboffset >= DDCMP_HEADER_SIZE) {
if (lp->rxpb[0] == DDCMP_ENQ) { /* Control Message? */
++lp->rxpcnt;
*pbuf = lp->rxpb;
*psize = DDCMP_HEADER_SIZE;
lp->rxpboffset = 0;
if (lp->mp->lines > 1)
sprintf (msg, "Line%d: <<< RCV Packet", (int)(lp-lp->mp->ldsc));
else
strcpy (msg, "<<< RCV Packet");
ddcmp_packet_trace (DDCMP_DBG_PRCV, lp->mp->dptr, msg, lp->rxpb, *psize);
if (ddcmp_feedCorruptionTroll (lp, lp->rxpb, TRUE, corruptrate))
break;
return SCPE_OK;
}
payloadsize = ((lp->rxpb[2] & 0x3F) << 8)| lp->rxpb[1];
if (lp->rxpboffset >= 10 + payloadsize) {
++lp->rxpcnt;
*pbuf = lp->rxpb;
*psize = (uint16)(10 + payloadsize);
if (lp->mp->lines > 1)
sprintf (msg, "Line%d: <<< RCV Packet", (int)(lp-lp->mp->ldsc));
else
strcpy (msg, "<<< RCV Packet");
ddcmp_packet_trace (DDCMP_DBG_PRCV, lp->mp->dptr, msg, lp->rxpb, *psize);
lp->rxpboffset = 0;
if (ddcmp_feedCorruptionTroll (lp, lp->rxpb, TRUE, corruptrate))
break;
return SCPE_OK;
}
}
}
*pbuf = NULL;
*psize = 0;
if (lp->conn)
return SCPE_OK;
return SCPE_LOST;
}
/* Store packet in line buffer (or store packet in line buffer and add needed CRCs)
Inputs:
*lp = pointer to line descriptor
*buf = pointer to packet data
size = size of packet
Outputs:
status = ok, connection lost, or stall
Implementation notea:
1. If the line is not connected, SCPE_LOST is returned.
2. If prior packet transmission still in progress, SCPE_STALL is
returned and no packet data is stored. The caller must retry later.
*/
static t_stat ddcmp_tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size, int32 corruptrate)
{
t_stat r;
char msg[32];
if (!lp->conn)
return SCPE_LOST;
if (lp->txppoffset < lp->txppsize) {
tmxr_debug (DDCMP_DBG_PXMT, lp, "Skipped Sending Packet - Transmit Busy", (char *)&lp->txpb[3], size);
return SCPE_STALL;
}
if (lp->txpbsize < size) {
lp->txpbsize = size;
lp->txpb = (uint8 *)realloc (lp->txpb, lp->txpbsize);
}
memcpy (lp->txpb, buf, size);
lp->txppsize = size;
lp->txppoffset = 0;
if (lp->mp->lines > 1)
sprintf (msg, "Line%d: >>> XMT Packet", (int)(lp-lp->mp->ldsc));
else
strcpy (msg, ">>> XMT Packet");
ddcmp_packet_trace (DDCMP_DBG_PXMT, lp->mp->dptr, msg, lp->txpb, lp->txppsize);
if (!ddcmp_feedCorruptionTroll (lp, lp->txpb, FALSE, corruptrate)) {
++lp->txpcnt;
while ((lp->txppoffset < lp->txppsize) &&
(SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
++lp->txppoffset;
tmxr_send_buffered_data (lp);
}
else {/* Packet eaten, so discard it */
lp->txppoffset = lp->txppsize; /* Act like all data was sent */
}
return lp->conn ? SCPE_OK : SCPE_LOST;
}
static t_stat ddcmp_tmxr_put_packet_crc_ln (TMLN *lp, uint8 *buf, size_t size, int32 corruptrate)
{
uint16 hdr_crc16 = ddcmp_crc16(0, buf, DDCMP_HEADER_SIZE-DDCMP_CRC_SIZE);
buf[DDCMP_HEADER_SIZE-DDCMP_CRC_SIZE] = hdr_crc16 & 0xFF;
buf[DDCMP_HEADER_SIZE-DDCMP_CRC_SIZE+1] = (hdr_crc16>>8) & 0xFF;
if (size > DDCMP_HEADER_SIZE) {
uint16 data_crc16 = ddcmp_crc16(0, buf+DDCMP_HEADER_SIZE, size-(DDCMP_HEADER_SIZE+DDCMP_CRC_SIZE));
buf[size-DDCMP_CRC_SIZE] = data_crc16 & 0xFF;
buf[size-DDCMP_CRC_SIZE+1] = (data_crc16>>8) & 0xFF;
}
return ddcmp_tmxr_put_packet_ln (lp, buf, size, corruptrate);
}
static void ddcmp_build_data_packet (uint8 *buf, size_t size, uint8 flags, uint8 sequence, uint8 ack)
{
buf[0] = DDCMP_SOH;
buf[1] = size & 0xFF;
buf[2] = ((size >> 8) & 0x3F) | (flags << 6);
buf[3] = ack;
buf[4] = sequence;
buf[5] = 1;
}
static void ddcmp_build_maintenance_packet (uint8 *buf, size_t size)
{
buf[0] = DDCMP_DLE;
buf[1] = size & 0xFF;
buf[2] = ((size >> 8) & 0x3F) | ((DDCMP_FLAG_SELECT|DDCMP_FLAG_QSYNC) << 6);
buf[3] = 0;
buf[4] = 0;
buf[5] = 1;
}
static t_stat ddcmp_tmxr_put_data_packet_ln (TMLN *lp, uint8 *buf, size_t size, uint8 flags, uint8 sequence, uint8 ack)
{
ddcmp_build_data_packet (buf, size, flags, sequence, ack);
return ddcmp_tmxr_put_packet_crc_ln (lp, buf, size, 0);
}
static void ddcmp_build_control_packet (uint8 *buf, uint8 type, uint8 subtype, uint8 flags, uint8 sndr, uint8 rcvr)
{
buf[0] = DDCMP_ENQ; /* Control Message */
buf[1] = type; /* STACK type */
buf[2] = (subtype & 0x3f) | (flags << 6);
/* STACKSUB type and flags */
buf[3] = rcvr; /* RCVR */
buf[4] = sndr; /* SNDR */
buf[5] = 1; /* ADDR */
}
static t_stat ddcmp_tmxr_put_control_packet_ln (TMLN *lp, uint8 *buf, uint8 type, uint8 subtype, uint8 flags, uint8 sndr, uint8 rcvr)
{
ddcmp_build_control_packet (buf, type, subtype, flags, sndr, rcvr);
return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0);
}
static void ddcmp_build_ack_packet (uint8 *buf, uint8 ack, uint8 flags)
{
ddcmp_build_control_packet (buf, DDCMP_CTL_ACK, 0, flags, 0, ack);
}
static t_stat ddcmp_tmxr_put_ack_packet_ln (TMLN *lp, uint8 *buf, uint8 ack, uint8 flags)
{
ddcmp_build_ack_packet (buf, ack, flags);
return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0);
}
static void ddcmp_build_nak_packet (uint8 *buf, uint8 reason, uint8 nack, uint8 flags)
{
ddcmp_build_control_packet (buf, DDCMP_CTL_NAK, reason, flags, 0, nack);
}
static t_stat ddcmp_tmxr_put_nak_packet_ln (TMLN *lp, uint8 *buf, uint8 reason, uint8 nack, uint8 flags)
{
return ddcmp_tmxr_put_control_packet_ln (lp, buf, DDCMP_CTL_NAK, reason, flags, 0, nack);
}
static void ddcmp_build_rep_packet (uint8 *buf, uint8 ack, uint8 flags)
{
ddcmp_build_control_packet (buf, DDCMP_CTL_REP, 0, flags, ack, 0);
}
static t_stat ddcmp_tmxr_put_rep_packet_ln (TMLN *lp, uint8 *buf, uint8 ack, uint8 flags)
{
return ddcmp_tmxr_put_control_packet_ln (lp, buf, DDCMP_CTL_REP, 0, flags, ack, 0);
}
static void ddcmp_build_start_packet (uint8 *buf)
{
ddcmp_build_control_packet (buf, DDCMP_CTL_STRT, 0, DDCMP_FLAG_SELECT|DDCMP_FLAG_QSYNC, 0, 0);
}
static t_stat ddcmp_tmxr_put_start_packet_ln (TMLN *lp, uint8 *buf)
{
ddcmp_build_start_packet (buf);
return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0);
}
static void ddcmp_build_start_ack_packet (uint8 *buf)
{
ddcmp_build_control_packet (buf, DDCMP_CTL_STACK, 0, DDCMP_FLAG_SELECT|DDCMP_FLAG_QSYNC, 0, 0);
}
static t_stat ddcmp_tmxr_put_start_ack_packet_ln (TMLN *lp, uint8 *buf)
{
ddcmp_build_start_ack_packet (buf);
return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0);
}
#endif /* PDP11_DDCMP_H_ */

View file

@ -263,7 +263,6 @@ dsk_svc (UNIT *uptr)
int wc; int wc;
uint64 data; uint64 data;
DEVICE *dptr; DEVICE *dptr;
t_stat err;
dptr = &dsk_dev; dptr = &dsk_dev;
@ -279,7 +278,7 @@ dsk_svc (UNIT *uptr)
if (sec > DSK_SECS) if (sec > DSK_SECS)
sec -= DSK_SECS; sec -= DSK_SECS;
da = (sec + (cyl * DSK_SECS)) * DSK_WDS; da = (sec + (cyl * DSK_SECS)) * DSK_WDS;
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
(void)sim_fwrite (&dsk_buf[0], sizeof(uint64), (void)sim_fwrite (&dsk_buf[0], sizeof(uint64),
DSK_WDS, uptr->fileref); DSK_WDS, uptr->fileref);
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Write %d %d\n", ctlr, da, cyl); sim_debug(DEBUG_DETAIL, dptr, "DSK %d Write %d %d\n", ctlr, da, cyl);
@ -337,7 +336,7 @@ dsk_svc (UNIT *uptr)
if (sec > DSK_SECS) if (sec > DSK_SECS)
sec -= DSK_SECS; sec -= DSK_SECS;
da = (sec + (cyl * DSK_SECS)) * DSK_WDS; da = (sec + (cyl * DSK_SECS)) * DSK_WDS;
err = sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET); (void)sim_fseek(uptr->fileref, da * sizeof(uint64), SEEK_SET);
wc = sim_fread (&dsk_buf[0], sizeof(uint64), wc = sim_fread (&dsk_buf[0], sizeof(uint64),
DSK_WDS, uptr->fileref); DSK_WDS, uptr->fileref);
sim_debug(DEBUG_DETAIL, dptr, "DSK %d Read %d %d\n", ctlr, da, cyl); sim_debug(DEBUG_DETAIL, dptr, "DSK %d Read %d %d\n", ctlr, da, cyl);

View file

@ -1281,8 +1281,6 @@ dtc_flush (UNIT* uptr)
t_stat t_stat
dtc_detach (UNIT* uptr) dtc_detach (UNIT* uptr)
{ {
int32 u = uptr - dtc_dev.units;
if (!(uptr->flags & UNIT_ATT)) if (!(uptr->flags & UNIT_ATT))
return SCPE_OK; return SCPE_OK;
if (sim_is_active (uptr)) { if (sim_is_active (uptr)) {

424
PDP10/pdp6_ge.c Normal file
View file

@ -0,0 +1,424 @@
/* pdp6_ge.c: GE DATANET-760 with four consoles.
Copyright (c) 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.
This implements the MIT AI lab interface to a GE DATANET-760 with
four consoles. It consists of two somewhat independent IO bus
devices: 070 GTYI for keyboard input, and 750 GTYO for display
output. This file presents the two as a single GE device to SIMH
users.
*/
#include "kx10_defs.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_GE
#define NUM_DEVS_GE 0
#endif
#if NUM_DEVS_GE > 0
#define GTYI_DEVNUM 0070 /* GE console input. */
#define GTYO_DEVNUM 0750 /* GE console output. */
#define GE_CONSOLES 4
#define GTYI_PIA 00007 /* PI assignment. */
#define GTYI_DONE 00010 /* Input data ready. */
#define GTYI_STATUS (GTYI_PIA | GTYI_DONE)
#define GTYO_PIA 00007 /* PI assignment. */
#define GTYO_DONE 00100 /* Output data ready. */
#define GTYO_FROB 00200 /* Set done? */
#define GTYO_STATUS (GTYO_PIA | GTYO_DONE)
#define STATUS u3
#define DATA u4
#define PORT u5
#define LP u6
#define GE_SOH 001 /* Start of header/message. */
#define GE_STX 002 /* Start of text. */
#define GE_ETX 003 /* End of text. */
static t_stat gtyi_svc(UNIT *uptr);
static t_stat gtyo_svc(UNIT *uptr);
static t_stat gtyi_devio(uint32 dev, uint64 *data);
static t_stat gtyo_devio(uint32 dev, uint64 *data);
static t_stat ge_reset(DEVICE *dptr);
static t_stat ge_attach(UNIT *uptr, CONST char *ptr);
static t_stat ge_detach(UNIT *uptr);
static t_stat ge_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
static const char *ge_description(DEVICE *dptr);
static void gtyo_done(void);
static void gtyo_soh(char data);
static void gtyo_adr(char data);
static void gtyo_status(char data);
static void gtyo_stx(char data);
static void gtyo_text(char data);
static void gtyo_lp(char data);
static void (*gtyo_process)(char data) = gtyo_soh;
DIB gtyi_dib = { GTYI_DEVNUM, 1, &gtyi_devio, NULL };
DIB gtyo_dib = { GTYO_DEVNUM, 1, &gtyo_devio, NULL };
UNIT ge_unit[2] = {
{ UDATA(&gtyi_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 },
{ UDATA(&gtyo_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 },
};
#define gtyi_unit (&ge_unit[0])
#define gtyo_unit (&ge_unit[1])
static REG ge_reg[] = {
{ NULL }
};
static MTAB ge_mod[] = {
{ 0 }
};
#define DEBUG_TRC 0x0000400
static DEBTAB ge_debug[] = {
{"TRACE", DEBUG_TRC, "Routine trace"},
{"CMD", DEBUG_CMD, "Command Processing"},
{"CONO", DEBUG_CONO, "CONO instructions"},
{"CONI", DEBUG_CONI, "CONI instructions"},
{"DATAIO", DEBUG_DATAIO, "DATAI/O instructions"},
{"IRQ", DEBUG_IRQ, "Debug IRQ requests"},
{0},
};
DEVICE ge_dev = {
"GE", ge_unit, ge_reg, ge_mod,
2, 8, 18, 1, 8, 36,
NULL, NULL, &ge_reset,
NULL, &ge_attach, &ge_detach,
&gtyi_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX,
0, ge_debug,
NULL, NULL, NULL,
&ge_attach_help, NULL, &ge_description
};
DEVICE gtyo_dev = {
"GTYO", NULL, NULL, NULL,
0, 8, 18, 1, 8, 36,
NULL, NULL, NULL,
NULL, NULL, NULL,
&gtyo_dib, DEV_DIS | DEV_MUX,
0, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL
};
static TMLN ge_ldsc[GE_CONSOLES];
static TMXR ge_desc = { GE_CONSOLES, 0, 0, ge_ldsc };
static t_stat ge_reset(DEVICE *dptr)
{
sim_debug(DEBUG_TRC, dptr, "ge_reset()\n");
if (ge_dev.flags & DEV_DIS)
gtyo_dev.flags |= DEV_DIS;
else
gtyo_dev.flags &= ~DEV_DIS;
if (gtyi_unit->flags & UNIT_ATT) {
sim_activate(gtyi_unit, 10);
} else {
sim_cancel(gtyi_unit);
sim_cancel(gtyo_unit);
}
return SCPE_OK;
}
static t_stat ge_attach(UNIT *uptr, CONST char *cptr)
{
t_stat r;
if (!cptr || !*cptr)
return SCPE_ARG;
ge_desc.buffered = 1000;
r = tmxr_attach(&ge_desc, uptr, cptr);
if (r != SCPE_OK)
return r;
sim_debug(DEBUG_TRC, &ge_dev, "activate connection\n");
gtyi_unit->STATUS = 0;
gtyo_unit->STATUS = 0;
gtyo_process = gtyo_soh;
sim_activate(gtyi_unit, 10);
return SCPE_OK;
}
static t_stat ge_detach(UNIT *uptr)
{
t_stat r;
if (!(uptr->flags & UNIT_ATT))
return SCPE_OK;
sim_cancel(gtyi_unit);
sim_cancel(gtyo_unit);
r = tmxr_detach(&ge_desc, uptr);
uptr->filename = NULL;
return r;
}
static void gtyi_poll(UNIT *uptr)
{
int32 ch;
int i;
tmxr_poll_rx(&ge_desc);
for (i = 0; i < GE_CONSOLES; i++) {
if (!ge_ldsc[i].rcve)
continue;
if (!ge_ldsc[i].conn) {
ge_ldsc[i].rcve = 0;
tmxr_reset_ln(&ge_ldsc[i]);
sim_debug(DEBUG_CMD, &ge_dev, "Port %d connection lost\n", i);
continue;
}
ch = tmxr_getc_ln(&ge_ldsc[i]);
if (ch & TMXR_VALID) {
ch &= 0177;
sim_debug(DEBUG_CMD, &ge_dev, "Port %d got %03o\n", i, ch);
if (ch >= 0141 && ch <= 0172)
ch -= 0100;
else if (ch == 0140 || (ch >= 0173 && ch <= 0174)) {
sim_debug(DEBUG_CMD, &ge_dev, "Discard invalid character\n");
continue;
}
uptr->DATA = ch;
uptr->PORT = i;
uptr->STATUS |= GTYI_DONE;
if (uptr->STATUS & 7)
sim_debug(DEBUG_CMD, &ge_dev, "GTYI interrupt on channel %d\n", uptr->STATUS & 7);
set_interrupt(GTYI_DEVNUM, uptr->STATUS);
ge_ldsc[i].rcve = 0;
break;
}
}
}
static t_stat gtyi_svc(UNIT *uptr)
{
int32 n;
n = tmxr_poll_conn(&ge_desc);
if (n >= 0) {
sim_debug(DEBUG_CMD, &ge_dev, "got connection\n");
ge_ldsc[n].rcve = 1;
}
if ((uptr->STATUS & GTYI_DONE) == 0)
gtyi_poll(uptr);
sim_activate_after(uptr, 10000);
return SCPE_OK;
}
static t_stat gtyo_svc(UNIT *uptr)
{
switch (tmxr_putc_ln(&ge_ldsc[uptr->PORT], uptr->DATA)) {
case SCPE_OK:
sim_debug(DEBUG_CMD, &ge_dev, "Sent %03o to console %d\n",
uptr->DATA, uptr->PORT);
gtyo_done();
break;
case SCPE_LOST:
ge_ldsc[uptr->PORT].rcve = 0;
tmxr_reset_ln(&ge_ldsc[uptr->PORT]);
sim_debug(DEBUG_CMD, &ge_dev, "lost\n");
break;
case SCPE_STALL:
sim_debug(DEBUG_CMD, &ge_dev, "stall\n");
sim_clock_coschedule(uptr, 1000);
break;
default:
break;
}
tmxr_poll_tx(&ge_desc);
return SCPE_OK;
}
static t_stat ge_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
const char helpString[] =
/* The '*'s in the next line represent the standard text width of a help line */
/****************************************************************************/
" The %D device connects a secondary processor that is sharing memory with the.\n"
" primary.\n\n"
" The device must be attached to a receive port, this is done by using the\n"
" ATTACH command to specify the receive port number.\n"
"\n"
"+sim> ATTACH %U port\n"
"\n"
;
return scp_help(st, dptr, uptr, flag, helpString, cptr);
}
static const char *ge_description(DEVICE *dptr)
{
return "GE DATANET-760";
}
static void gtyo_done(void)
{
gtyo_unit->STATUS |= GTYO_DONE;
set_interrupt(GTYO_DEVNUM, gtyo_unit->STATUS);
if (gtyo_unit->STATUS & 7)
sim_debug(DEBUG_CMD, &ge_dev, "GTYO interrupt on channel %d\n", gtyo_unit->STATUS & 7);
}
static void gtyo_soh(char data) {
if (data == GE_SOH) {
gtyo_process = gtyo_adr;
gtyo_unit->LP = 0;
}
gtyo_done();
}
static void gtyo_adr(char data) {
switch(data) {
case 0140:
case 0150:
case 0160:
case 0170:
gtyo_unit->PORT = (data >> 3) & 3;
gtyo_process = gtyo_status;
break;
default:
gtyo_process = gtyo_soh;
break;
}
gtyo_done();
}
static void gtyo_status(char data) {
if (data == 0)
gtyo_process = gtyo_stx;
else
gtyo_process = gtyo_soh;
gtyo_done();
}
static void gtyo_stx(char data) {
if (data == GE_STX)
gtyo_process = gtyo_text;
gtyo_done();
}
static void gtyo_text(char data) {
if (data == GE_ETX) {
gtyo_process = gtyo_lp;
gtyo_done();
} else {
gtyo_unit->DATA = data;
sim_activate_after(gtyo_unit, 10000);
}
}
static void gtyo_lp(char data) {
if (gtyo_unit->LP != 0)
sim_debug(DEBUG_CMD, &ge_dev, "Checksum mismatch\n");
gtyo_process = gtyo_soh;
gtyo_done();
}
t_stat gtyi_devio(uint32 dev, uint64 *data)
{
UNIT *uptr = gtyi_unit;
switch(dev & 03) {
case CONO:
sim_debug(DEBUG_CONO, &ge_dev, "GTYI %012llo\n", *data);
uptr->STATUS &= ~GTYI_PIA;
uptr->STATUS |= *data & GTYI_PIA;
break;
case CONI:
*data = uptr->STATUS & GTYI_STATUS;
sim_debug(DEBUG_CONI, &ge_dev, "GTYI %012llo\n", *data);
break;
case DATAI:
*data = uptr->DATA | (uptr->PORT << 18);
sim_debug(DEBUG_DATAIO, &ge_dev, "GTYI %012llo\n", *data);
uptr->STATUS &= ~GTYI_DONE;
sim_debug(DEBUG_IRQ, &ge_dev, "Clear GTYI interrupt\n");
clr_interrupt(GTYI_DEVNUM);
ge_ldsc[uptr->PORT].rcve = 1;
sim_activate(gtyi_unit, 10);
break;
}
return SCPE_OK;
}
t_stat gtyo_devio(uint32 dev, uint64 *data)
{
UNIT *uptr = gtyo_unit;
int ch;
switch(dev & 03) {
case CONO:
sim_debug(DEBUG_CONO, &ge_dev, "GTYO %012llo\n", *data);
sim_debug(DEBUG_IRQ, &ge_dev, "Clear GTYO interrupt\n");
clr_interrupt(GTYO_DEVNUM);
uptr->STATUS &= ~GTYO_PIA;
uptr->STATUS |= *data & GTYO_PIA;
if (*data & GTYO_FROB)
gtyo_done();
break;
case CONI:
*data = uptr->STATUS & GTYO_STATUS;
sim_debug(DEBUG_CONI, &ge_dev, "GTYO %012llo\n", *data);
break;
case DATAO:
sim_debug(DEBUG_DATAIO, &ge_dev, "GTYO %012llo\n", *data);
if (uptr->STATUS & GTYO_DONE) {
sim_debug(DEBUG_IRQ, &ge_dev, "Clear GTYO interrupt\n");
clr_interrupt(GTYO_DEVNUM);
uptr->STATUS &= ~GTYO_DONE;
ch = *data & 0177;
ch ^= 0177;
ch = ((ch << 1) | (ch >> 6)) & 0177;
if (ch >= 040 && ch <= 0137)
sim_debug(DEBUG_DATAIO, &ge_dev, "Character %03o %c\n", ch, ch);
else
sim_debug(DEBUG_DATAIO, &ge_dev, "Character %03o\n", ch);
uptr->LP ^= ch;
sim_debug(DEBUG_DATAIO, &ge_dev, "LP %03o\n", uptr->LP);
gtyo_process(ch);
}
break;
}
return SCPE_OK;
}
#endif

View file

@ -211,6 +211,10 @@
RelativePath="..\PDP10\ka10_dkb.c" RelativePath="..\PDP10\ka10_dkb.c"
> >
</File> </File>
<File
RelativePath="..\PDP10\ka10_dd.c"
>
</File>
<File <File
RelativePath="..\PDP10\ka10_dpk.c" RelativePath="..\PDP10\ka10_dpk.c"
> >
@ -275,6 +279,10 @@
RelativePath="..\PDP10\kx10_dc.c" RelativePath="..\PDP10\kx10_dc.c"
> >
</File> </File>
<File
RelativePath="..\PDP10\kx10_ddc.c"
>
</File>
<File <File
RelativePath="..\PDP10\kx10_df.c" RelativePath="..\PDP10\kx10_df.c"
> >

View file

@ -215,6 +215,10 @@
RelativePath="..\PDP10\kx10_dc.c" RelativePath="..\PDP10\kx10_dc.c"
> >
</File> </File>
<File
RelativePath="..\PDP10\kx10_ddc.c"
>
</File>
<File <File
RelativePath="..\PDP10\kx10_df.c" RelativePath="..\PDP10\kx10_df.c"
> >
@ -279,6 +283,10 @@
RelativePath="..\PDP10\kx10_tu.c" RelativePath="..\PDP10\kx10_tu.c"
> >
</File> </File>
<File
RelativePath="..\PDP10\kx10_tym.c"
>
</File>
<File <File
RelativePath="..\..\windows-build\pthreads\pthread.c" RelativePath="..\..\windows-build\pthreads\pthread.c"
> >

View file

@ -215,6 +215,10 @@
RelativePath="..\PDP10\kx10_dpy.c" RelativePath="..\PDP10\kx10_dpy.c"
> >
</File> </File>
<File
RelativePath="..\PDP10\pdp6_ge.c"
>
</File>
<File <File
RelativePath="..\PDP10\kx10_lp.c" RelativePath="..\PDP10\kx10_lp.c"
> >

View file

@ -2048,7 +2048,8 @@ PDP6 = ${PDP6D}/kx10_cpu.c ${PDP6D}/kx10_sys.c ${PDP6D}/kx10_cty.c \
${PDP6D}/kx10_lp.c ${PDP6D}/kx10_pt.c ${PDP6D}/kx10_cr.c \ ${PDP6D}/kx10_lp.c ${PDP6D}/kx10_pt.c ${PDP6D}/kx10_cr.c \
${PDP6D}/kx10_cp.c ${PDP6D}/pdp6_dct.c ${PDP6D}/pdp6_dtc.c \ ${PDP6D}/kx10_cp.c ${PDP6D}/pdp6_dct.c ${PDP6D}/pdp6_dtc.c \
${PDP6D}/pdp6_mtc.c ${PDP6D}/pdp6_dsk.c ${PDP6D}/pdp6_dcs.c \ ${PDP6D}/pdp6_mtc.c ${PDP6D}/pdp6_dsk.c ${PDP6D}/pdp6_dcs.c \
${PDP6D}/kx10_dpy.c ${PDP6D}/pdp6_slave.c ${DISPLAYL} ${DISPLAY340} ${PDP6D}/kx10_dpy.c ${PDP6D}/pdp6_slave.c ${PDP6D}/pdp6_ge.c \
${DISPLAYL} ${DISPLAY340}
PDP6_OPT = -DPDP6=1 -DUSE_INT64 -I ${PDP6D} -DUSE_SIM_CARD ${DISPLAY_OPT} ${PDP6_DISPLAY_OPT} \ PDP6_OPT = -DPDP6=1 -DUSE_INT64 -I ${PDP6D} -DUSE_SIM_CARD ${DISPLAY_OPT} ${PDP6_DISPLAY_OPT} \
${AIO_CCDEFS} ${AIO_CCDEFS}
@ -2069,8 +2070,8 @@ KA10 = ${KA10D}/kx10_cpu.c ${KA10D}/kx10_sys.c ${KA10D}/kx10_df.c \
${KA10D}/pdp6_dtc.c ${KA10D}/pdp6_mtc.c ${KA10D}/pdp6_dsk.c \ ${KA10D}/pdp6_dtc.c ${KA10D}/pdp6_mtc.c ${KA10D}/pdp6_dsk.c \
${KA10D}/pdp6_dcs.c ${KA10D}/ka10_dpk.c ${KA10D}/kx10_dpy.c \ ${KA10D}/pdp6_dcs.c ${KA10D}/ka10_dpk.c ${KA10D}/kx10_dpy.c \
${KA10D}/ka10_ai.c ${KA10D}/ka10_iii.c ${KA10D}/kx10_disk.c \ ${KA10D}/ka10_ai.c ${KA10D}/ka10_iii.c ${KA10D}/kx10_disk.c \
${KA10D}/ka10_pclk.c ${KA10D}/ka10_tv.c \ ${KA10D}/ka10_pclk.c ${KA10D}/ka10_tv.c ${KA10D}/ka10_dd.c \
${DISPLAYL} ${DISPLAY340} ${DISPLAYIII} ${KA10D}/kx10_ddc.c ${DISPLAYL} ${DISPLAY340} ${DISPLAYIII}
KA10_OPT = -DKA=1 -DUSE_INT64 -I ${KA10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KA10_DISPLAY_OPT} KA10_OPT = -DKA=1 -DUSE_INT64 -I ${KA10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KA10_DISPLAY_OPT}
ifneq (${PANDA_LIGHTS},) ifneq (${PANDA_LIGHTS},)
# ONLY for Panda display. # ONLY for Panda display.
@ -2090,7 +2091,7 @@ KI10 = ${KI10D}/kx10_cpu.c ${KI10D}/kx10_sys.c ${KI10D}/kx10_df.c \
${KI10D}/kx10_dt.c ${KI10D}/kx10_dk.c ${KI10D}/kx10_cr.c \ ${KI10D}/kx10_dt.c ${KI10D}/kx10_dk.c ${KI10D}/kx10_cr.c \
${KI10D}/kx10_cp.c ${KI10D}/kx10_tu.c ${KI10D}/kx10_rs.c \ ${KI10D}/kx10_cp.c ${KI10D}/kx10_tu.c ${KI10D}/kx10_rs.c \
${KI10D}/kx10_imp.c ${KI10D}/kx10_dpy.c ${KI10D}/kx10_disk.c \ ${KI10D}/kx10_imp.c ${KI10D}/kx10_dpy.c ${KI10D}/kx10_disk.c \
${DISPLAYL} ${DISPLAY340} ${KI10D}/kx10_ddc.c ${KI10D}/kx10_tym.c ${DISPLAYL} ${DISPLAY340}
KI10_OPT = -DKI=1 -DUSE_INT64 -I ${KI10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KI10_DISPLAY_OPT} KI10_OPT = -DKI=1 -DUSE_INT64 -I ${KI10D} -DUSE_SIM_CARD ${NETWORK_OPT} ${DISPLAY_OPT} ${KI10_DISPLAY_OPT}
ifneq (${PANDA_LIGHTS},) ifneq (${PANDA_LIGHTS},)
# ONLY for Panda display. # ONLY for Panda display.