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:
parent
9515201238
commit
1cb2f3b96c
29 changed files with 7066 additions and 304 deletions
|
@ -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
756
PDP10/ka10_dd.c
Normal 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
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
134
PDP10/ka10_dd_font.h
Normal 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
763
PDP10/ka10_pipanel.c
Normal 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
|
|
@ -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
1188
PDP10/kl10_dn.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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 ++;
|
||||||
|
@ -11775,7 +11775,7 @@ fetch_opr:
|
||||||
MB = BR;
|
MB = BR;
|
||||||
if (Mem_write(pi_cycle, 0))
|
if (Mem_write(pi_cycle, 0))
|
||||||
goto last;
|
goto last;
|
||||||
MB = AR;
|
MB = AR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -13575,13 +13580,17 @@ static const char *pdp10_clock_precalibrate_commands[] = {
|
||||||
|
|
||||||
t_stat cpu_reset (DEVICE *dptr)
|
t_stat cpu_reset (DEVICE *dptr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
static int initialized = 0;
|
t_stat r = SCPE_OK;
|
||||||
|
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
402
PDP10/kx10_ddc.c
Normal 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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,8 +1146,8 @@ 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;
|
||||||
for (; len > 0; len--) {
|
for (; len > 0; len--) {
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
>yo_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)
|
||||||
|
|
|
@ -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
684
PDP10/kx10_tym.c
Normal 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
493
PDP10/pdp11_ddcmp.h
Normal 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_ */
|
|
@ -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);
|
||||||
|
|
|
@ -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
424
PDP10/pdp6_ge.c
Normal 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, >yi_devio, NULL };
|
||||||
|
DIB gtyo_dib = { GTYO_DEVNUM, 1, >yo_devio, NULL };
|
||||||
|
|
||||||
|
UNIT ge_unit[2] = {
|
||||||
|
{ UDATA(>yi_svc, UNIT_IDLE|UNIT_ATTABLE, 0), 1000 },
|
||||||
|
{ UDATA(>yo_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,
|
||||||
|
>yi_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,
|
||||||
|
>yo_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
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
|
@ -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"
|
||||||
>
|
>
|
||||||
|
|
9
makefile
9
makefile
|
@ -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.
|
||||||
|
|
Loading…
Add table
Reference in a new issue