KA10: Release 3 of PDP10 simulators. KS10 support added.

Added KS10 support.
    CPU Redid instruction decode to improve performance
    Triple-I display cleanup.
    Normalized end of line to DOS/Unix.
    KL10 FE, Cleanup issues with TTY devices hanging simulator..
    Fixed errors in RH20 device.
    RP and TU drives more independent of RH controller.
This commit is contained in:
Richard Cornwell 2022-02-19 20:25:44 -05:00
parent 10c7e50f1c
commit 91aee9b39f
38 changed files with 15110 additions and 2218 deletions

View file

@ -54,7 +54,6 @@
t_stat dkb_devio(uint32 dev, uint64 *data); t_stat dkb_devio(uint32 dev, uint64 *data);
int dkb_keyboard (SIM_KEY_EVENT *kev); int dkb_keyboard (SIM_KEY_EVENT *kev);
t_stat dkb_svc(UNIT *uptr);
t_stat dkb_reset(DEVICE *dptr); t_stat dkb_reset(DEVICE *dptr);
t_stat dkb_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); t_stat dkb_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *dkb_description (DEVICE *dptr); const char *dkb_description (DEVICE *dptr);
@ -65,7 +64,7 @@ int dkb_kmod = 0;
DIB dkb_dib = { DKB_DEVNUM, 1, dkb_devio, NULL}; DIB dkb_dib = { DKB_DEVNUM, 1, dkb_devio, NULL};
UNIT dkb_unit[] = { UNIT dkb_unit[] = {
{UDATA (&dkb_svc, UNIT_IDLE, 0) }, {UDATA (NULL, UNIT_IDLE, 0) },
{ 0 } { 0 }
}; };
@ -417,11 +416,6 @@ int dkb_keyboard (SIM_KEY_EVENT *kev)
} }
t_stat dkb_svc( UNIT *uptr)
{
return SCPE_OK;
}
t_stat dkb_reset( DEVICE *dptr) t_stat dkb_reset( DEVICE *dptr)
{ {
if ((dkb_dev.flags & DEV_DIS) == 0) if ((dkb_dev.flags & DEV_DIS) == 0)

View file

@ -1,4 +1,4 @@
/* ka10_iii.c: Triple III display processor. /* ka10_iii.c: Triple-I display processor.
Copyright (c) 2019-2020, Richard Cornwell Copyright (c) 2019-2020, Richard Cornwell
@ -32,7 +32,6 @@
#if NUM_DEVS_III > 0 #if NUM_DEVS_III > 0
#include "display/display.h" #include "display/display.h"
#include "display/iii.h"
#define III_DEVNUM 0430 #define III_DEVNUM 0430
@ -98,6 +97,11 @@
#define CBRT_V 3 #define CBRT_V 3
#define CSIZE_V 0 #define CSIZE_V 0
#define MIN_X -512
#define MAX_X 512
#define MIN_Y -501
#define MAX_Y 522
/* /*
* Character map. * Character map.
* M(x,y) moves pointer to x,y. * M(x,y) moves pointer to x,y.
@ -380,7 +384,8 @@ t_stat iii_devio(uint32 dev, uint64 *data) {
uptr->STATUS |= DATA_FLG; uptr->STATUS |= DATA_FLG;
else { else {
iii_instr = *data; iii_instr = *data;
sim_activate(uptr, 10); /* Process instruction right away to ensure MAR is updated. */
iii_svc(iii_unit);
} }
sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAO %06o\n", dev, (uint32)*data); sim_debug(DEBUG_DATAIO, &iii_dev, "III %03o DATAO %06o\n", dev, (uint32)*data);
break; break;
@ -398,7 +403,7 @@ iii_svc (UNIT *uptr)
float ch_sz; float ch_sz;
if (uptr->CYCLE > 20) { if (uptr->CYCLE > 20) {
iii_cycle(300, 0); display_age(300, 0);
uptr->CYCLE = 0; uptr->CYCLE = 0;
} else { } else {
uptr->CYCLE++; uptr->CYCLE++;
@ -448,7 +453,7 @@ iii_svc (UNIT *uptr)
if (ch == '\t' || ch == 0) if (ch == '\t' || ch == 0)
continue; continue;
if (ch == '\r') { if (ch == '\r') {
ox = -512; ox = MIN_X;
continue; continue;
} }
if (ch == '\n') { if (ch == '\n') {
@ -493,7 +498,7 @@ iii_svc (UNIT *uptr)
nx, ny, sz, br); nx, ny, sz, br);
nx += ox; nx += ox;
ny += oy; ny += oy;
if (nx < -512 || nx > 512 || ny < -512 || ny > 512) if (nx < MIN_X || nx > MAX_X || ny < MIN_Y || ny > MAX_Y)
uptr->STATUS |= EDG_FBIT; uptr->STATUS |= EDG_FBIT;
i = (int)((iii_instr >> 18) & 3); i = (int)((iii_instr >> 18) & 3);
if ((i & 02) == 0 && (iii_sel & 04000) != 0) { /* Check if visible */ if ((i & 02) == 0 && (iii_sel & 04000) != 0) { /* Check if visible */
@ -516,7 +521,7 @@ iii_svc (UNIT *uptr)
/* Compute relative position. */ /* Compute relative position. */
nx += ox; nx += ox;
ny += oy; ny += oy;
if (nx < -512 || nx > 512 || ny < -512 || ny > 512) if (nx < MIN_X || nx > MAX_X || ny < MIN_Y || ny > MAX_Y)
uptr->STATUS |= EDG_FBIT; uptr->STATUS |= EDG_FBIT;
/* Check if visible */ /* Check if visible */
if ((iii_instr & 040) == 0 && (iii_sel & 04000) != 0) { if ((iii_instr & 040) == 0 && (iii_sel & 04000) != 0) {
@ -561,7 +566,7 @@ iii_svc (UNIT *uptr)
if ((iii_instr & 0100) == 0) { /* Relative mode */ if ((iii_instr & 0100) == 0) { /* Relative mode */
nx += ox; nx += ox;
ny += oy; ny += oy;
if (nx < -512 || nx > 512 || ny < -512 || ny > 512) if (nx < MIN_X || nx > MAX_X || ny < MIN_Y || ny > MAX_Y)
uptr->STATUS |= EDG_FBIT; uptr->STATUS |= EDG_FBIT;
} }
/* Check if visible */ /* Check if visible */
@ -637,7 +642,7 @@ t_stat iii_reset (DEVICE *dptr)
} else { } else {
display_reset(); display_reset();
dptr->units[0].POS = 0; dptr->units[0].POS = 0;
iii_init(dptr, 1); display_init(DIS_III, 1, dptr);
} }
return SCPE_OK; return SCPE_OK;
} }
@ -647,20 +652,20 @@ t_stat iii_reset (DEVICE *dptr)
static void static void
draw_point(int x, int y, int b, UNIT *uptr) draw_point(int x, int y, int b, UNIT *uptr)
{ {
if (x < -512 || x > 512 || y < -512 || y > 512) if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_X)
uptr->STATUS |= WRP_FBIT; uptr->STATUS |= WRP_FBIT;
iii_point(x, y, b); display_point(x - MIN_X, y - MIN_Y, b, 0);
} }
/* Draw a line between two points */ /* Draw a line between two points */
static void static void
draw_line(int x1, int y1, int x2, int y2, int b, UNIT *uptr) draw_line(int x1, int y1, int x2, int y2, int b, UNIT *uptr)
{ {
if (x1 < -512 || x1 > 512 || y1 < -512 || y1 > 512) if (x1 < MIN_X || x1 > MAX_X || y1 < MIN_Y || y1 > MAX_Y)
uptr->STATUS |= WRP_FBIT; uptr->STATUS |= WRP_FBIT;
if (x2 < -512 || x2 > 512 || y2 < -512 || y2 > 512) if (x2 < MIN_X || x2 > MAX_X || y2 < MIN_Y || y2 > MAX_Y)
uptr->STATUS |= WRP_FBIT; uptr->STATUS |= WRP_FBIT;
iii_draw_line(x1, y1, x2, y2, b); display_line(x1 - MIN_X, y1 - MIN_Y, x2 - MIN_X, y2 - MIN_Y, b);
} }
t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr) t_stat iii_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
@ -670,6 +675,6 @@ return SCPE_OK;
const char *iii_description (DEVICE *dptr) const char *iii_description (DEVICE *dptr)
{ {
return "Triple III Display"; return "Triple-I Display";
} }
#endif #endif

View file

@ -291,7 +291,7 @@ t_stat imx_set_channel (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
return r; return r;
if (*tptr != 0) { if (*tptr != 0) {
if (strcasecmp (tptr, "negate") != 0) if (MATCH_CMD (tptr, "NEGATE"))
return SCPE_ARG; return SCPE_ARG;
negate = 1; negate = 1;
} }

View file

@ -171,6 +171,9 @@ static t_stat mty_input_svc (UNIT *uptr)
tmxr_poll_rx (&mty_desc); tmxr_poll_rx (&mty_desc);
if (status & MTY_DONE)
return SCPE_OK;
for (i = 0; i < MTY_LINES; i++) { for (i = 0; i < MTY_LINES; i++) {
/* Round robin scan 32 lines. */ /* Round robin scan 32 lines. */
scan = (scan + 1) & 037; scan = (scan + 1) & 037;
@ -200,6 +203,9 @@ static t_stat mty_output_svc (UNIT *uptr)
int i, ch; int i, ch;
int32 txdone; int32 txdone;
if (status & MTY_DONE)
return SCPE_OK;
for (i = 0; i < MTY_LINES; i++) { for (i = 0; i < MTY_LINES; i++) {
/* Round robin scan 32 lines. */ /* Round robin scan 32 lines. */
scan = (scan + 1) & 037; scan = (scan + 1) & 037;
@ -232,9 +238,11 @@ static t_stat mty_output_svc (UNIT *uptr)
tmxr_poll_tx (&mty_desc); tmxr_poll_tx (&mty_desc);
if ((status & MTY_ODONE) == 0) {
/* SIMH will actually schedule this UNIT when output is due /* SIMH will actually schedule this UNIT when output is due
according to the line speed. */ according to the line speed. */
sim_activate_after (uptr, 1000000); sim_activate_after (uptr, 1000000);
}
return SCPE_OK; return SCPE_OK;
} }
@ -245,7 +253,7 @@ static t_stat mty_reset (DEVICE *dptr)
sim_debug(DEBUG_CMD, &mty_dev, "Reset\n"); sim_debug(DEBUG_CMD, &mty_dev, "Reset\n");
if (mty_unit->flags & UNIT_ATT) { if (mty_unit->flags & UNIT_ATT) {
sim_activate (mty_unit, tmxr_poll); sim_activate (&mty_unit[0], tmxr_poll);
sim_activate_after (&mty_unit[1], 100); sim_activate_after (&mty_unit[1], 100);
} else { } else {
sim_cancel (&mty_unit[0]); sim_cancel (&mty_unit[0]);

View file

@ -409,7 +409,7 @@ DEVICE pmp_dev = {
"PMP", pmp_unit, NULL, pmp_mod, "PMP", pmp_unit, NULL, pmp_mod,
NUM_UNITS_PMP, 8, 15, 1, 8, 8, NUM_UNITS_PMP, 8, 15, 1, 8, 8,
NULL, NULL, &pmp_reset, NULL, &pmp_attach, &pmp_detach, NULL, NULL, &pmp_reset, NULL, &pmp_attach, &pmp_detach,
&pmp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_DISK, 0, dev_debug, &pmp_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &pmp_help, NULL, NULL, &pmp_description NULL, NULL, &pmp_help, NULL, NULL, &pmp_description
}; };
@ -2212,8 +2212,8 @@ pmp_format(UNIT * uptr, int flag) {
uptr->CMD |= DK_ATTN; uptr->CMD |= DK_ATTN;
pmp_statusb |= REQ_CH; pmp_statusb |= REQ_CH;
sim_activate(uptr, 100); sim_activate(uptr, 100);
fputc('\n', stderr);
fputc('\r', stderr); fputc('\r', stderr);
fputc('\n', stderr);
return 0; return 0;
} else } else
return 1; return 1;
@ -2243,7 +2243,7 @@ pmp_attach(UNIT * uptr, CONST char *file)
return SCPE_OK; return SCPE_OK;
} }
sim_messagef(SCPE_OK, "Drive %03x=%d %d %02x %d\n\r", addr, sim_messagef(SCPE_OK, "Drive %03x=%d %d %02x %d\r\n", addr,
hdr.heads, hdr.tracksize, hdr.devtype, hdr.highcyl); hdr.heads, hdr.tracksize, hdr.devtype, hdr.highcyl);
for (i = 0; disk_type[i].name != 0; i++) { for (i = 0; disk_type[i].name != 0; i++) {
tsize = (uint32)((disk_type[i].bpt | 0x1ff) + 1); tsize = (uint32)((disk_type[i].bpt | 0x1ff) + 1);
@ -2251,7 +2251,7 @@ pmp_attach(UNIT * uptr, CONST char *file)
hdr.heads == disk_type[i].heads && hdr.highcyl == disk_type[i].cyl) { hdr.heads == disk_type[i].heads && hdr.highcyl == disk_type[i].cyl) {
if (GET_TYPE(uptr->flags) != i) { if (GET_TYPE(uptr->flags) != i) {
/* Ask if we should change */ /* Ask if we should change */
fprintf(stderr, "Wrong type %s\n\r", disk_type[i].name); fprintf(stderr, "Wrong type %s\r\n", disk_type[i].name);
if (!get_yn("Update dasd type? [N] ", FALSE)) { if (!get_yn("Update dasd type? [N] ", FALSE)) {
detach_unit(uptr); detach_unit(uptr);
return SCPE_FMT; return SCPE_FMT;
@ -2367,7 +2367,7 @@ pmp_set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
/* Update device entry */ /* Update device entry */
uptr->flags &= ~UNIT_ADDR(0xff); uptr->flags &= ~UNIT_ADDR(0xff);
uptr->flags |= UNIT_ADDR(newdev); uptr->flags |= UNIT_ADDR(newdev);
fprintf(stderr, "Set dev %x\n\r", GET_UADDR(uptr->flags)); fprintf(stderr, "Set dev %x\r\n", GET_UADDR(uptr->flags));
return r; return r;
} }

View file

@ -148,6 +148,11 @@ static int stk_modifiers (SIM_KEY_EVENT *kev)
static int stk_keys (SIM_KEY_EVENT *kev) static int stk_keys (SIM_KEY_EVENT *kev)
{ {
if (kev->state == SIM_KEYPRESS_UP && kev->key == SIM_KEY_F11) {
vid_set_fullscreen (!vid_is_fullscreen ());
return 1;
}
if (kev->state == SIM_KEYPRESS_UP) if (kev->state == SIM_KEYPRESS_UP)
return 0; return 0;

View file

@ -37,8 +37,12 @@
/* Rubin 10-11 pager. */ /* Rubin 10-11 pager. */
static uint64 ten11_pager[256]; static uint64 ten11_pager[256];
/* Physical address range of TEN11 moby. */
t_addr ten11_base = 03000000;
t_addr ten11_end = 04000000;
/* Physical address of 10-11 control page. */ /* Physical address of 10-11 control page. */
#define T11CPA 03776000 #define T11CPA 0776000 //Offset inside TEN11 moby.
/* Bits in a 10-11 page table entry. */ /* Bits in a 10-11 page table entry. */
#define T11VALID (0400000000000LL) #define T11VALID (0400000000000LL)
@ -64,6 +68,8 @@ static t_stat ten11_svc (UNIT *uptr);
static t_stat ten11_reset (DEVICE *dptr); static t_stat ten11_reset (DEVICE *dptr);
static t_stat ten11_attach (UNIT *uptr, CONST char *ptr); static t_stat ten11_attach (UNIT *uptr, CONST char *ptr);
static t_stat ten11_detach (UNIT *uptr); static t_stat ten11_detach (UNIT *uptr);
static t_stat ten11_set_base (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
static t_stat ten11_show_base (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); static t_stat ten11_attach_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
static const char *ten11_description (DEVICE *dptr); static const char *ten11_description (DEVICE *dptr);
@ -77,6 +83,8 @@ static REG ten11_reg[] = {
}; };
static MTAB ten11_mod[] = { static MTAB ten11_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "base address", "BASE",
&ten11_set_base, &ten11_show_base },
{ 0 } { 0 }
}; };
@ -290,6 +298,8 @@ int ten11_read (t_addr addr, uint64 *data)
int offset = addr & 01777; int offset = addr & 01777;
int word1, word2; int word1, word2;
addr &= RMASK; //Address offset inside moby.
if (addr >= T11CPA) { if (addr >= T11CPA) {
/* Accessing the control page. */ /* Accessing the control page. */
if (offset >= 0400) { if (offset >= 0400) {
@ -370,6 +380,8 @@ int ten11_write (t_addr addr, uint64 data)
{ {
int offset = addr & 01777; int offset = addr & 01777;
addr &= RMASK; //Address offset inside moby.
if (addr >= T11CPA) { if (addr >= T11CPA) {
/* Accessing the control page. */ /* Accessing the control page. */
if (offset >= 0400) { if (offset >= 0400) {
@ -413,4 +425,28 @@ int ten11_write (t_addr addr, uint64 data)
} }
return 0; return 0;
} }
static t_stat ten11_set_base (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r;
t_value x;
if (cptr == NULL || *cptr == 0)
return SCPE_ARG;
x = get_uint (cptr, 8, 03777777, &r);
if (r != SCPE_OK)
return SCPE_ARG;
ten11_base = (t_addr)(x&03777777);
/* The end of the TEN11 range is the start of the next moby. */
ten11_end = (ten11_base + 01000000) & LMASK;
return SCPE_OK;
}
static t_stat ten11_show_base (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf (st, "Base: %011o", ten11_base);
return SCPE_OK;
}
#endif #endif

130
PDP10/ka10_tv.c Normal file
View file

@ -0,0 +1,130 @@
/* ka10_tv.c: Stanford TV camera and Spacewar buttons.
Copyright (c) 2021, 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_video.h"
#if NUM_DEVS_TV > 0
#define TV_DEVNUM 0404
#define JOY_MAX_UNITS 5
#define JOY_MAX_AXES 4
#define JOY_MAX_BUTTONS 4
#define JOY_TRIG 5000
#define ROTATE_AXIS 0
#define THRUSTER_AXIS 1
#define TORPEDO_BUTTON 0
#define HYPER_BUTTON 1
/* CONI bits. */
#define TPBIT 001LL /* Fire torpedo. */
#define THRUBT 002LL /* Thruster. */
#define ROTRBT 004LL /* Rotate right. */
#define ROTLBT 010LL /* Rotate left. */
#define HYPRBT 014LL /* Hyperspace = right + left. */
static t_stat tv_devio(uint32 dev, uint64 *data);
static t_stat tv_reset (DEVICE *dptr);
static const char *tv_description (DEVICE *dptr);
static int joy_axes[JOY_MAX_UNITS][JOY_MAX_AXES];
static int joy_buttons[JOY_MAX_UNITS][JOY_MAX_BUTTONS];
DIB tv_dib = { TV_DEVNUM, 1, &tv_devio, NULL };
DEVICE tv_dev = {
"TV", NULL, NULL, NULL,
0, 8, 0, 1, 8, 36,
NULL, NULL, &tv_reset, NULL, NULL, NULL,
&tv_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &tv_description
};
static void tv_joy_motion(int which, int axis, int value)
{
if (which < JOY_MAX_UNITS && axis < JOY_MAX_AXES) {
joy_axes[which][axis] = value;
sim_debug (DEBUG_DETAIL, &tv_dev, "Joystick %d axid %d: value %d\n",
which, axis, value);
}
}
static void tv_joy_button(int which, int button, int state)
{
if (which < JOY_MAX_UNITS && button < JOY_MAX_BUTTONS) {
joy_buttons[which][button] = state;
sim_debug (DEBUG_DETAIL, &tv_dev, "Joystick %d button %d: state %d\n",
which, button, state);
}
}
static uint64 tv_buttons (void)
{
uint64 buttons = 2; /* Needed for unknown reason! */
int i;
for (i = 0; i < JOY_MAX_UNITS; i++) {
if (joy_axes[i][ROTATE_AXIS] > JOY_TRIG)
buttons ^= ROTRBT << (4 * i);
else if (joy_axes[i][ROTATE_AXIS] < -JOY_TRIG)
buttons ^= ROTLBT << (4 * i);
if (joy_axes[i][THRUSTER_AXIS] < -JOY_TRIG)
buttons ^= THRUBT << (4 * i);
if (joy_buttons[i][TORPEDO_BUTTON])
buttons ^= TPBIT << (4 * i);
if (joy_buttons[i][HYPER_BUTTON])
buttons ^= HYPRBT << (4 * i);
}
return buttons;
}
t_stat tv_devio(uint32 dev, uint64 *data)
{
switch(dev & 07) {
case CONI|4:
*data = tv_buttons ();
sim_debug (DEBUG_CONI, &tv_dev, "%07llo\n", *data);
break;
}
return SCPE_OK;
}
static t_stat tv_reset (DEVICE *dptr)
{
memset (joy_axes, 0, sizeof joy_axes);
memset (joy_buttons, 0, sizeof joy_buttons);
vid_register_gamepad_motion_callback (tv_joy_motion);
vid_register_gamepad_button_callback (tv_joy_button);
return SCPE_OK;
}
const char *tv_description (DEVICE *dptr)
{
return "Stanford TV camera and Spacewar buttons";
}
#endif

View file

@ -236,7 +236,7 @@ struct _dte_queue {
uint16 data[258]; /* Data packet */ uint16 data[258]; /* Data packet */
uint16 sdev; /* Secondary device code */ uint16 sdev; /* Secondary device code */
uint16 sz; /* Byte size */ uint16 sz; /* Byte size */
} dte_in[32], dte_out[32]; } dte_in[16], dte_out[16];
int32 dte_in_ptr; int32 dte_in_ptr;
int32 dte_in_cmd; int32 dte_in_cmd;
@ -589,7 +589,7 @@ t_stat dte_devio(uint32 dev, uint64 *data) {
if (res & DTE_CO11DB) { if (res & DTE_CO11DB) {
sim_debug(DEBUG_CONO, &dte_dev, "CTY Ring 11 DB\n"); sim_debug(DEBUG_CONO, &dte_dev, "CTY Ring 11 DB\n");
dte_unit[0].STATUS |= DTE_11DB; dte_unit[0].STATUS |= DTE_11DB;
sim_activate(&dte_unit[0], 200); sim_activate(&dte_unit[0], 100);
} }
if (dte_unit[0].STATUS & (DTE_10DB|DTE_11DN|DTE_10DN|DTE_11ER|DTE_10ER)) if (dte_unit[0].STATUS & (DTE_10DB|DTE_11DN|DTE_10DN|DTE_11ER|DTE_10ER))
set_interrupt(dev, dte_unit[0].STATUS); set_interrupt(dev, dte_unit[0].STATUS);
@ -660,6 +660,7 @@ void dte_second(UNIT *uptr) {
return; return;
} }
#endif #endif
/* Do it */ /* Do it */
sim_debug(DEBUG_DETAIL, &dte_dev, "CTY secondary %012llo\n", word); sim_debug(DEBUG_DETAIL, &dte_dev, "CTY secondary %012llo\n", word);
switch(word & SEC_CMDMSK) { switch(word & SEC_CMDMSK) {
@ -673,6 +674,7 @@ void dte_second(UNIT *uptr) {
if (ch != 0) { if (ch != 0) {
cty_out.buff[cty_out.in_ptr] = ch & 0x7f; cty_out.buff[cty_out.in_ptr] = ch & 0x7f;
inci(&cty_out); inci(&cty_out);
if (!sim_is_active(&dte_unit[1]))
sim_activate(&dte_unit[1], 200); sim_activate(&dte_unit[1], 200);
} }
M[SEC_DTCHR + base] = ch; M[SEC_DTCHR + base] = ch;
@ -683,6 +685,7 @@ void dte_second(UNIT *uptr) {
enter_pri: enter_pri:
if (Mem_examine_word(0, 0, &word)) if (Mem_examine_word(0, 0, &word))
break; break;
dte_proc_num = (word >> 24) & 037; dte_proc_num = (word >> 24) & 037;
dte_base = dte_proc_num + 1; dte_base = dte_proc_num + 1;
dte_off = dte_base + (word & 0177777); dte_off = dte_base + (word & 0177777);
@ -697,6 +700,7 @@ enter_pri:
M[SEC_DTCMD + base] = 0; M[SEC_DTCMD + base] = 0;
M[SEC_DTFLG + base] = FMASK; M[SEC_DTFLG + base] = FMASK;
uptr->STATUS &= ~DTE_11DB; uptr->STATUS &= ~DTE_11DB;
tty_reset(&tty_dev);
return; return;
case SEC_SETDDT: /* Read character from console */ case SEC_SETDDT: /* Read character from console */
@ -857,7 +861,7 @@ void dte_primary(UNIT *uptr) {
return; return;
/* Check if there is room for another packet */ /* Check if there is room for another packet */
if (((dte_in_ptr + 1) & 0x1f) == dte_in_cmd) { if (((dte_in_ptr + 1) & 0xf) == dte_in_cmd) {
/* If not reschedule ourselves */ /* If not reschedule ourselves */
sim_activate(uptr, 100); sim_activate(uptr, 100);
return; return;
@ -886,6 +890,7 @@ error:
sim_debug(DEBUG_DETAIL, &dte_dev, "DTE: error %012llo\n", word); sim_debug(DEBUG_DETAIL, &dte_dev, "DTE: error %012llo\n", word);
return; return;
} }
sim_debug(DEBUG_DETAIL, &dte_dev, "DTE: status word %012llo\n", word);
if ((word & PRI_CMT_QP) == 0) { if ((word & PRI_CMT_QP) == 0) {
goto error; goto error;
@ -895,7 +900,7 @@ error:
if ((word & PRI_CMT_IP) != 0) { if ((word & PRI_CMT_IP) != 0) {
/* Transfer from 10 */ /* Transfer from 10 */
if ((uptr->STATUS & DTE_IND) == 0) { if ((uptr->STATUS & DTE_IND) == 0) {
fprintf(stderr, "DTE out of sync\n\r"); fprintf(stderr, "DTE out of sync\r\n");
return; return;
} }
/* Get size of transfer */ /* Get size of transfer */
@ -920,7 +925,7 @@ error:
cnt--; cnt--;
} }
uptr->STATUS &= ~DTE_IND; uptr->STATUS &= ~DTE_IND;
dte_in_ptr = (dte_in_ptr + 1) & 0x1f; dte_in_ptr = (dte_in_ptr + 1) & 0xf;
} else { } else {
/* Transfer from 10 */ /* Transfer from 10 */
in->dptr = 0; in->dptr = 0;
@ -965,7 +970,7 @@ error:
if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_STS, &word)) if (Mem_deposit_word(0, dte_dt10_off + PRI_CMTW_STS, &word))
goto error; goto error;
} else { } else {
dte_in_ptr = (dte_in_ptr + 1) & 0x1f; dte_in_ptr = (dte_in_ptr + 1) & 0xf;
} }
} }
word &= ~PRI_CMT_TOT; word &= ~PRI_CMT_TOT;
@ -988,7 +993,7 @@ dte_function(UNIT *uptr)
/* Check if queue is empty */ /* Check if queue is empty */
while (dte_in_cmd != dte_in_ptr) { while (dte_in_cmd != dte_in_ptr) {
if (((dte_out_res + 1) & 0x1f) == dte_out_ptr) { if (((dte_out_res + 1) & 0xf) == dte_out_ptr) {
sim_debug(DEBUG_DATA, &dte_dev, "DTE: func out full %d %d\n", sim_debug(DEBUG_DATA, &dte_dev, "DTE: func out full %d %d\n",
dte_out_res, dte_out_ptr); dte_out_res, dte_out_ptr);
return; return;
@ -1016,10 +1021,15 @@ dte_function(UNIT *uptr)
break; break;
case PRI_EM2TI: /* Replay to initial message. */ case PRI_EM2TI: /* Replay to initial message. */
case PRI_EMLBE: /* Acknowledge line */
/* Should never get these */ /* Should never get these */
break; break;
case PRI_EMLBE: /* Acknowledge line */
data1[0] = 0;
if (dte_queue(PRI_EMLBE, dev, 1, data1) == 0)
return;
break;
case PRI_EMHDR: /* Here is date and time */ case PRI_EMHDR: /* Here is date and time */
/* Ignore this function */ /* Ignore this function */
break; break;
@ -1109,8 +1119,10 @@ cty:
data1[0] = 0; data1[0] = 0;
if (cmd->sz > 8) if (cmd->sz > 8)
cmd->dcnt += cmd->dcnt; cmd->dcnt += cmd->dcnt;
while (cmd->dptr < cmd->dcnt) { while (cmd->dptr < cmd->dcnt) {
ch = (int32)(cmd->data[cmd->dptr >> 1]); ch = (int32)(cmd->data[cmd->dptr >> 1]);
sim_debug(DEBUG_DATA, &dte_dev,"CTY data %o\n", ch);
if ((cmd->dptr & 1) == 0) if ((cmd->dptr & 1) == 0)
ch >>= 8; ch >>= 8;
ch &= 0177; ch &= 0177;
@ -1127,6 +1139,7 @@ cty:
if (cmd->dptr != cmd->dcnt) if (cmd->dptr != cmd->dcnt)
return; return;
} }
break; break;
case PRI_EMSNA: /* Send all (ttys) */ case PRI_EMSNA: /* Send all (ttys) */
@ -1398,7 +1411,7 @@ cty:
} }
/* Mark command as finished */ /* Mark command as finished */
cmd->cnt = 0; cmd->cnt = 0;
dte_in_cmd = (dte_in_cmd + 1) & 0x1F; dte_in_cmd = (dte_in_cmd + 1) & 0xf;
} }
} }
@ -1482,7 +1495,7 @@ void dte_transfer(UNIT *uptr) {
} }
} }
out->cnt = 0; out->cnt = 0;
dte_out_ptr = (dte_out_ptr + 1) & 0x1f; dte_out_ptr = (dte_out_ptr + 1) & 0xf;
done: done:
uptr->STATUS |= DTE_10DN; uptr->STATUS |= DTE_10DN;
set_interrupt(DTE_DEVNUM, uptr->STATUS); set_interrupt(DTE_DEVNUM, uptr->STATUS);
@ -1623,7 +1636,7 @@ dte_input()
/* While we have room for one more packet, /* While we have room for one more packet,
* grab as much input as we can */ * grab as much input as we can */
for (ln = 0; ln < tty_desc.lines && for (ln = 0; ln < tty_desc.lines &&
((dte_out_res + 1) & 0x1f) != dte_out_ptr; ln++) { ((dte_out_res + 1) & 0xf) != dte_out_ptr; ln++) {
struct _buffer *itty = &tty_in[ln]; struct _buffer *itty = &tty_in[ln];
while (not_empty(itty)) { while (not_empty(itty)) {
ch = itty->buff[itty->out_ptr]; ch = itty->buff[itty->out_ptr];
@ -1671,7 +1684,7 @@ dte_queue(int func, int dev, int dcnt, uint16 *data)
struct _dte_queue *out; struct _dte_queue *out;
/* Check if room in queue for this packet. */ /* Check if room in queue for this packet. */
if (((dte_out_res + 1) & 0x1f) == dte_out_ptr) { if (((dte_out_res + 1) & 0xf) == dte_out_ptr) {
sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d out full\n", dte_out_res, dte_out_ptr); sim_debug(DEBUG_DATA, &dte_dev, "DTE: %d %d out full\n", dte_out_res, dte_out_ptr);
return 0; return 0;
} }
@ -1688,7 +1701,7 @@ dte_queue(int func, int dev, int dcnt, uint16 *data)
*dp++ = *data++; *dp++ = *data++;
} }
/* Advance pointer to next function */ /* Advance pointer to next function */
dte_out_res = (dte_out_res + 1) & 0x1f; dte_out_res = (dte_out_res + 1) & 0xf;
return 1; return 1;
} }
@ -1965,7 +1978,7 @@ lp20_printline(UNIT *uptr, int nl) {
int trim = 0; int trim = 0;
/* Trim off trailing blanks */ /* Trim off trailing blanks */
while (uptr->COL >= 0 && lp20_buffer[uptr->COL - 1] == ' ') { while (uptr->COL > 0 && lp20_buffer[uptr->COL - 1] == ' ') {
uptr->COL--; uptr->COL--;
trim = 1; trim = 1;
} }
@ -2197,15 +2210,11 @@ lp20_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr) const char *cptr)
{ {
fprintf (st, "Line Printer (LPT)\n\n"); fprintf (st, "Line Printer (LP20)\n\n");
fprintf (st, "The line printer (LPT) writes data to a disk file. The POS register specifies\n"); fprintf (st, "The line printer (LP20) writes data to a disk file.\n");
fprintf (st, "the number of the next data item to be written. Thus, by changing POS, the\n");
fprintf (st, "user can backspace or advance the printer.\n");
fprintf (st, "The Line printer can be configured to any number of lines per page with the:\n"); fprintf (st, "The Line printer can be configured to any number of lines per page with the:\n");
fprintf (st, " sim> SET %s0 LINESPERPAGE=n\n\n", dptr->name); fprintf (st, " sim> SET %s LINESPERPAGE=n\n\n", dptr->name);
fprintf (st, "The default is 66 lines per page.\n\n"); fprintf (st, "The default is 66 lines per page.\n\n");
fprintf (st, "The device address of the Line printer can be changed\n");
fprintf (st, " sim> SET %s0 DEV=n\n\n", dptr->name);
fprint_set_help (st, dptr); fprint_set_help (st, dptr);
fprint_show_help (st, dptr); fprint_show_help (st, dptr);
fprint_reg_help (st, dptr); fprint_reg_help (st, dptr);
@ -2274,16 +2283,15 @@ t_stat ttyo_svc (UNIT *uptr)
t_stat r; t_stat r;
int32 ln; int32 ln;
TMLN *lp; TMLN *lp;
int f;
if ((tty_unit[0].flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */ sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
for (ln = 0; ln < tty_desc.lines; ln++) { for (ln = 0; ln < tty_desc.lines; ln++) {
struct _buffer *optr = &tty_out[ln]; struct _buffer *optr = &tty_out[ln];
lp = &tty_ldsc[ln]; lp = &tty_ldsc[ln];
if (lp->conn == 0) { if (lp->conn == 0 || (tty_unit[0].flags & UNIT_ATT) == 0) {
if (not_empty(optr)) { if (not_empty(optr)) {
optr->out_ptr = optr->in_ptr = 0; optr->out_ptr = optr->in_ptr = 0;
tty_done[ln] = 1; tty_done[ln] = 1;
@ -2292,7 +2300,8 @@ t_stat ttyo_svc (UNIT *uptr)
} }
if (empty(optr)) if (empty(optr))
continue; continue;
while (not_empty(optr)) { f = 1;
while (f && not_empty(optr)) {
int32 ch = optr->buff[optr->out_ptr]; int32 ch = optr->buff[optr->out_ptr];
ch = sim_tt_outcvt(ch, TT_GET_MODE (tty_unit[0].flags) | TTUF_KSR); ch = sim_tt_outcvt(ch, TT_GET_MODE (tty_unit[0].flags) | TTUF_KSR);
sim_debug(DEBUG_DATA, &tty_dev, "TTY: %d output %o\n", ln, ch); sim_debug(DEBUG_DATA, &tty_dev, "TTY: %d output %o\n", ln, ch);
@ -2301,12 +2310,17 @@ t_stat ttyo_svc (UNIT *uptr)
inco(optr); inco(optr);
else if (r == SCPE_LOST) { else if (r == SCPE_LOST) {
optr->out_ptr = optr->in_ptr = 0; optr->out_ptr = optr->in_ptr = 0;
continue; f = 0;
} else } else if (r == SCPE_STALL) {
continue; f = 0;
} else {
break;
} }
}
if (empty(optr)) {
tty_done[ln] = 1; tty_done[ln] = 1;
} }
}
return SCPE_OK; return SCPE_OK;
} }
@ -2314,6 +2328,12 @@ t_stat ttyo_svc (UNIT *uptr)
t_stat tty_reset (DEVICE *dptr) t_stat tty_reset (DEVICE *dptr)
{ {
int i;
for (i = 0; i < tty_desc.lines; i++) {
tty_done[i] = 0;
tty_out[i].out_ptr = tty_out[i].in_ptr = 0;
tty_in[i].out_ptr = tty_in[i].in_ptr = 0;
}
return SCPE_OK; return SCPE_OK;
} }

View file

@ -874,7 +874,7 @@ void nia_load_ptt()
nia_error(EBSERR); nia_error(EBSERR);
return; return;
} }
sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %012llo %012llo\n\r", sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %012llo %012llo\n",
n, word1, word2); n, word1, word2);
if (word1 & SMASK) { if (word1 & SMASK) {
uint16 type; uint16 type;
@ -887,7 +887,7 @@ void nia_load_ptt()
addr++; addr++;
} }
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %04x %010o\n\r", sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load ptt%d: %04x %010o\n",
n, nia_data.ptt_proto[i], nia_data.ptt_head[i]); n, nia_data.ptt_proto[i], nia_data.ptt_head[i]);
nia_data.ptt_n = n; nia_data.ptt_n = n;
} }
@ -925,7 +925,7 @@ void nia_load_mcast()
} }
for(i = 0; i< n; i++) { for(i = 0; i< n; i++) {
eth_mac_fmt(&nia_data.macs[i], buffer); eth_mac_fmt(&nia_data.macs[i], buffer);
sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load mcast%d: %s\n\r",i,buffer); sim_debug(DEBUG_DETAIL, &nia_dev, "NIA load mcast%d: %s\n",i,buffer);
} }
nia_data.macs_n = n - 2; nia_data.macs_n = n - 2;
if (nia_recv_uptr->flags & UNIT_ATT) if (nia_recv_uptr->flags & UNIT_ATT)

562
PDP10/ks10_ch11.c Normal file
View file

@ -0,0 +1,562 @@
/* ks10_ch11.c: CH11 Chaosnet interface.
------------------------------------------------------------------------------
Copyright (c) 2022, Richard Cornwell, original by Lars Brinkhoff.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHOR 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 the author shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
------------------------------------------------------------------------------
*/
#include "kx10_defs.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_CH11
#define NUM_DEVS_CH11 0
#endif
#if (NUM_DEVS_CH11 > 0)
/* CSR 076410 */
#define CSR_BSY 0000001 /* Xmit busy RO */
#define CSR_LUP 0000002 /* Loop back R/W */
#define CSR_SPY 0000004 /* Receive msgs from any destination R/W */
#define CSR_RCL 0000010 /* Clear receiver WO */
#define CSR_REN 0000020 /* Receiver int enable R/W */
#define CSR_TEN 0000040 /* Transmitter int enable R/W */
#define CSR_TAB 0000100 /* Transmit abort by conflict RO */
#define CSR_TDN 0000200 /* Transmit Done */
#define CSR_TCL 0000400 /* Clear transmitter WO */
#define CSR_LOS 0017000 /* Lost count RO */
#define CSR_RST 0020000 /* I/O Reset WO */
#define CSR_ERR 0040000 /* CRC Error RO */
#define CSR_RDN 0100000 /* Receive done */
/* MY # 764142 Host number RO */
/* WBF 764142 Write bufffer WO */
/* RBF 764144 Read buffer RO */
/* RBC 764146 Receive bit counter RO */
/* XMT 764152 Read initiates transmission */
#define CHUDP_HEADER 4
#define IOLN_CH 020
#define DBG_TRC 0x0001
#define DBG_REG 0x0002
#define DBG_PKT 0x0004
#define DBG_DAT 0x0008
#define DBG_INT 0x0010
#define DBG_ERR 0x0020
int ch11_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int ch11_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
uint16 ch11_checksum (const uint8 *p, int count);
void ch11_validate (const uint8 *p, int count);
t_stat ch11_transmit (struct pdp_dib *dibp);
void ch11_receive (struct pdp_dib *dibp);
void ch11_clear (struct pdp_dib *dibp);
t_stat ch11_svc(UNIT *);
t_stat ch11_reset (DEVICE *);
t_stat ch11_attach (UNIT *, CONST char *);
t_stat ch11_detach (UNIT *);
t_stat ch11_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
t_stat ch11_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
t_stat ch11_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
t_stat ch11_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
t_stat ch11_help (FILE *, DEVICE *, UNIT *, int32, const char *);
t_stat ch11_help_attach (FILE *, DEVICE *, UNIT *, int32, const char *);
const char *ch11_description (DEVICE *);
static char peer[256];
static int address;
static uint16 ch11_csr;
static int rx_count;
static int tx_count;
static uint8 rx_buffer[512+100];
static uint8 tx_buffer[512+100];
TMLN ch11_lines[1] = { {0} };
TMXR ch11_tmxr = { 1, NULL, 0, ch11_lines};
UNIT ch11_unit[] = {
{UDATA (&ch11_svc, UNIT_IDLE|UNIT_ATTABLE, 0) },
};
REG ch11_reg[] = {
{ ORDATA(CSR, ch11_csr, 16)},
{ GRDATAD(RXCNT, rx_count, 16, 16, 0, "Receive word count"), REG_FIT|REG_RO},
{ GRDATAD(TXCNT, tx_count, 16, 16, 0, "Transmit word count"), REG_FIT|REG_RO},
{ BRDATAD(RXBUF, rx_buffer, 16, 8, sizeof rx_buffer, "Receive packet buffer"), REG_FIT},
{ BRDATAD(TXBUF, tx_buffer, 16, 8, sizeof tx_buffer, "Transmit packet buffer"), REG_FIT},
{ BRDATAD(PEER, peer, 16, 8, sizeof peer, "Network peer"), REG_HRO},
{ GRDATAD(NODE, address, 16, 16, 0, "Node address"), REG_HRO},
{ NULL } };
MTAB ch11_mod[] = {
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
NULL, "Sets vect of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
NULL, "Sets br of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of CH11" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "PEER", "PEER",
&ch11_set_peer, &ch11_show_peer, NULL, "Remote host name and port" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "NODE", "NODE",
&ch11_set_node, &ch11_show_node, NULL, "Chaosnet node address" },
{ 0 },
};
DIB ch11_dib = { 0764140, 017, 0270, 6, 3, &ch11_read, &ch11_write, NULL, 0, 0 };
DEBTAB ch11_debug[] = {
{ "DETAIL", DEBUG_DETAIL,"I/O operations"},
{ "TRC", DBG_TRC, "Detailed trace" },
{ "REG", DBG_REG, "Hardware registers" },
{ "PKT", DBG_PKT, "Packets" },
{ "DAT", DBG_DAT, "Packet data" },
{ "INT", DBG_INT, "Interrupts" },
{ "ERR", DBG_ERR, "Error conditions" },
{ 0 }
};
DEVICE ch11_dev = {
"CH", ch11_unit, ch11_reg, ch11_mod,
1, 8, 16, 1, 8, 16,
NULL, NULL, &ch11_reset,
NULL, &ch11_attach, &ch11_detach,
&ch11_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_MUX,
0, ch11_debug, NULL, NULL, &ch11_help, &ch11_help_attach, NULL,
&ch11_description
};
int
ch11_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
int i;
addr &= dibp->uba_mask;
sim_debug(DEBUG_DETAIL, dptr, "CH11 write %06o %06o %o\n",
addr, data, access);
switch (addr & 016) {
case 000: /* CSR */
if (data & CSR_RST) {
sim_debug (DBG_REG, &ch11_dev, "Reset\n");
ch11_clear (dibp);
}
ch11_csr &= ~(CSR_REN|CSR_TEN|CSR_SPY);
ch11_csr |= data & (CSR_REN|CSR_TEN|CSR_SPY);
if (data & CSR_RCL) {
sim_debug (DBG_REG, &ch11_dev, "Clear RX\n");
ch11_csr &= ~CSR_RDN;
rx_count = 0;
ch11_lines[0].rcve = TRUE;
uba_clr_irq(dibp, dibp->uba_vect);
}
if (data & CSR_TCL) {
sim_debug (DBG_REG, &ch11_dev, "Clear TX\n");
tx_count = 0;
ch11_csr |= CSR_TDN;
if (ch11_csr & CSR_TEN)
uba_set_irq(dibp, dibp->uba_vect);
}
break;
case 002: /* Write buffer */
ch11_csr &= ~CSR_TDN;
if (tx_count < 512) {
i = CHUDP_HEADER + tx_count;
tx_buffer[i] = (data >> 8) & 0xff;
tx_buffer[i+1] = data & 0xff;
tx_count+=2;
sim_debug (DBG_DAT, &ch11_dev, "Write buffer word %d:%02x %02x %06o %06o\n",
tx_count, tx_buffer[i], tx_buffer[i+1], data, ch11_csr);
} else {
sim_debug (DBG_ERR, &ch11_dev, "Write buffer overflow\n");
}
break;
case 004: /* Read buffer */
case 006: /* Bit count */
case 012: /* Start transmission */
case 010: /* Empty */
case 014: /* Empty */
case 016: /* Empty */
break;
}
return 0;
}
int
ch11_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
int i;
addr &= dibp->uba_mask;
*data = 0;
switch (addr & 016) {
case 000: /* CSR */
*data = ch11_csr;
break;
case 002: /* Host number */
*data = address;
break;
case 004: /* Read buffer */
if (rx_count == 0) {
*data = 0;
sim_debug (DBG_ERR, &ch11_dev, "Read empty buffer\n");
} else {
i = 512-rx_count;
ch11_csr &= ~CSR_RDN;
uba_clr_irq(dibp, dibp->uba_vect);
*data = ((uint64)(rx_buffer[i]) & 0xff) << 8;
*data |= ((uint64)(rx_buffer[i+1]) & 0xff);
rx_count-=2;
sim_debug (DBG_DAT, &ch11_dev, "Read buffer word %d:%02x %02x %06o %06o\n",
rx_count, rx_buffer[i], rx_buffer[i+1], *data, ch11_csr);
}
break;
case 006: /* Bit count */
*data = ((512 - rx_count) - 1) & 07777;
break;
case 012: /* Start transmission */
sim_debug (DBG_REG, &ch11_dev, "XMIT TX\n");
ch11_transmit(dibp);
break;
case 010: /* Empty */
case 014: /* Empty */
case 016: /* Empty */
break;
}
sim_debug(DEBUG_DETAIL, dptr, "CH11 read %06o %06o %o\n",
addr, *data, access);
return 0;
}
uint16
ch11_checksum (const uint8 *p, int count)
{
int32 sum = 0;
while (count > 1) {
sum += (p[0]<<8) | p[1];
p += 2;
count -= 2;
}
if ( count > 0)
sum += p[0];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return (~sum) & 0xffff;
}
void
ch11_validate (const uint8 *p, int count)
{
uint16 chksum;
int size;
sim_debug (DBG_TRC, &ch11_dev, "Packet opcode: %02x\n", p[0]);
sim_debug (DBG_TRC, &ch11_dev, "MBZ: %02x\n", p[1]);
sim_debug (DBG_TRC, &ch11_dev, "Forwarding count: %02x\n", p[2] >> 4);
size = ((p[2] & 0xF) << 8) + p[3];
sim_debug (DBG_TRC, &ch11_dev, "Packet size: %03x\n", size);
sim_debug (DBG_TRC, &ch11_dev, "Destination address: %o\n", (p[4] << 8) + p[5]);
sim_debug (DBG_TRC, &ch11_dev, "Destination index: %02x\n", (p[6] << 8) + p[7]);
sim_debug (DBG_TRC, &ch11_dev, "Source address: %o\n", (p[8] << 8) + p[9]);
sim_debug (DBG_TRC, &ch11_dev, "Source index: %02x\n", (p[10] << 8) + p[11]);
sim_debug (DBG_TRC, &ch11_dev, "Packet number: %02x\n", (p[12] << 8) + p[13]);
sim_debug (DBG_TRC, &ch11_dev, "Acknowledgement: %02x\n", (p[14] << 8) + p[15]);
if (p[1] != 0)
sim_debug (DBG_ERR, &ch11_dev, "Bad packet\n");
chksum = ch11_checksum (p, count);
if (chksum != 0) {
sim_debug (DBG_ERR, &ch11_dev, "Checksum error: %04x\n", chksum);
ch11_csr |= CSR_ERR;
} else
sim_debug (DBG_TRC, &ch11_dev, "Checksum: %05o\n", chksum);
}
t_stat
ch11_transmit (struct pdp_dib *dibp)
{
size_t len;
t_stat r;
int i = CHUDP_HEADER + tx_count;
uint16 chk;
if (tx_count > (512 - CHUDP_HEADER)) {
sim_debug (DBG_PKT, &ch11_dev, "Pack size failed, %d bytes.\n", (int)tx_count);
ch11_csr |= CSR_ERR;
return SCPE_INCOMP;
}
tx_buffer[i] = tx_buffer[8+CHUDP_HEADER];
tx_buffer[i+1] = tx_buffer[9+CHUDP_HEADER];
tx_count += 2;
chk = ch11_checksum(tx_buffer + CHUDP_HEADER, tx_count);
tx_buffer[i+2] = (chk >> 8) & 0xff;
tx_buffer[i+3] = chk & 0xff;
tx_count += 2;
tmxr_poll_tx (&ch11_tmxr);
len = CHUDP_HEADER + (size_t)tx_count;
r = tmxr_put_packet_ln (&ch11_lines[0], (const uint8 *)&tx_buffer, len);
if (r == SCPE_OK) {
sim_debug (DBG_PKT, &ch11_dev, "Sent UDP packet, %d bytes.\n", (int)len);
tmxr_poll_tx (&ch11_tmxr);
} else {
sim_debug (DBG_ERR, &ch11_dev, "Sending UDP failed: %d.\n", r);
ch11_csr |= CSR_TAB;
}
tx_count = 0;
return SCPE_OK;
}
void
ch11_receive (struct pdp_dib *dibp)
{
size_t count;
const uint8 *p;
uint16 dest;
tmxr_poll_rx (&ch11_tmxr);
if (tmxr_get_packet_ln (&ch11_lines[0], &p, &count) != SCPE_OK) {
sim_debug (DBG_ERR, &ch11_dev, "TMXR error receiving packet\n");
return;
}
if (p == NULL)
return;
dest = ((p[4+CHUDP_HEADER] & 0xff) << 8) + (p[5+CHUDP_HEADER] & 0xff);
sim_debug (DBG_PKT, &ch11_dev, "Received UDP packet, %d bytes for: %o\n", (int)count, dest);
/* Check if packet for us. */
if (dest != address && dest != 0 && (ch11_csr & CSR_SPY) == 0)
return;
if ((CSR_RDN & ch11_csr) == 0) {
count = (count + 1) & 0776;
memcpy (rx_buffer + (512 - count), p, count);
rx_count = count;
sim_debug (DBG_TRC, &ch11_dev, "Rx count, %d\n", rx_count);
ch11_validate (p + CHUDP_HEADER, count - CHUDP_HEADER);
ch11_csr |= CSR_RDN;
if (ch11_csr & CSR_REN) {
sim_debug (DBG_INT, &ch11_dev, "RX Interrupt\n");
uba_set_irq(dibp, dibp->uba_vect);
}
ch11_lines[0].rcve = FALSE;
sim_debug (DBG_TRC, &ch11_dev, "Rx off\n");
} else {
sim_debug (DBG_ERR, &ch11_dev, "Lost packet\n");
if ((ch11_csr & CSR_LOS) != CSR_LOS)
ch11_csr = (ch11_csr & ~CSR_LOS) | (CSR_LOS & (ch11_csr + 01000));
}
}
void
ch11_clear (struct pdp_dib *dibp)
{
ch11_csr = CSR_TDN;
rx_count = 0;
tx_count = 0;
tx_buffer[0] = 1; /* CHUDP header */
tx_buffer[1] = 1;
tx_buffer[2] = 0;
tx_buffer[3] = 0;
ch11_lines[0].rcve = TRUE;
uba_clr_irq(dibp, dibp->uba_vect);
}
t_stat
ch11_svc(UNIT *uptr)
{
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
sim_clock_coschedule (uptr, 1000);
(void)tmxr_poll_conn (&ch11_tmxr);
if (ch11_lines[0].conn) {
ch11_receive (dibp);
}
if (tx_count == 0) {
ch11_csr |= CSR_TDN;
if (ch11_csr & CSR_TEN) {
sim_debug (DBG_INT, &ch11_dev, "RX Interrupt\n");
uba_set_irq(dibp, dibp->uba_vect);
}
}
return SCPE_OK;
}
t_stat ch11_attach (UNIT *uptr, CONST char *cptr)
{
char linkinfo[256];
t_stat r;
ch11_dev.dctrl |= 0xF77F0000;
if (address == -1)
return sim_messagef (SCPE_2FARG, "Must set Chaosnet NODE address first \"SET CH NODE=val\"\n");
if (peer[0] == '\0')
return sim_messagef (SCPE_2FARG, "Must set Chaosnet PEER \"SET CH PEER=host:port\"\n");
snprintf (linkinfo, sizeof(linkinfo), "Buffer=%d,UDP,%s,PACKET,Connect=%.*s,Line=0",
(int)sizeof tx_buffer, cptr, (int)(sizeof(linkinfo) - (45 + strlen(cptr))), peer);
r = tmxr_attach (&ch11_tmxr, uptr, linkinfo);
if (r != SCPE_OK) {
sim_debug (DBG_ERR, &ch11_dev, "TMXR error opening master\n");
return sim_messagef (r, "Error Opening: %s\n", peer);
}
uptr->filename = (char *)realloc (uptr->filename, 1 + strlen (cptr));
strcpy (uptr->filename, cptr);
sim_activate (uptr, 1000);
return SCPE_OK;
}
t_stat ch11_detach (UNIT *uptr)
{
sim_cancel (uptr);
tmxr_detach (&ch11_tmxr, uptr);
return SCPE_OK;
}
t_stat ch11_reset (DEVICE *dptr)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
ch11_clear (dibp);
if (ch11_unit[0].flags & UNIT_ATT)
sim_activate (&ch11_unit[0], 100);
return SCPE_OK;
}
t_stat ch11_show_peer (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
fprintf (st, "peer=%s", peer[0] ? peer : "unspecified");
return SCPE_OK;
}
t_stat ch11_set_peer (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
{
char host[256], port[256];
if ((cptr == NULL) || (*cptr == 0))
return SCPE_ARG;
if (uptr->flags & UNIT_ATT)
return SCPE_ALATT;
if (sim_parse_addr (cptr, host, sizeof host, NULL, port, sizeof port, NULL, NULL))
return SCPE_ARG;
if (host[0] == '\0')
return SCPE_ARG;
strncpy (peer, cptr, sizeof(peer) - 1);
return SCPE_OK;
}
t_stat ch11_show_node (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
{
if (address == -1)
fprintf (st, "node=unspecified");
else
fprintf (st, "node=%o", address);
return SCPE_OK;
}
t_stat ch11_set_node (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
{
t_stat r;
int x;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_ARG;
if (uptr->flags & UNIT_ATT)
return SCPE_ALATT;
x = (int)get_uint (cptr, 8, 0177777, &r);
if (r != SCPE_OK)
return SCPE_ARG;
address = x;
return SCPE_OK;
}
const char *ch11_description (DEVICE *dptr)
{
return "CH11 Chaosnet interface";
}
t_stat ch11_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "CH11 Chaosnet interface\n\n");
fprintf (st, "It's a network interface for MIT's Chaosnet. Options allow\n");
fprintf (st, "control of the node address and network peer. The node address must\n");
fprintf (st, "be a 16-bit octal number.\n");
fprint_set_help (st, dptr);
fprintf (st, "\nConfigured options and controller state can be displayed with:\n");
fprint_show_help (st, dptr);
fprintf (st, "\nThe CH11 simulation will encapsulate Chaosnet packets in UDP or TCP.\n");
fprintf (st, "To access the network, the simulated Chaosnet interface must be attached\n");
fprintf (st, "to a network peer.\n\n");
ch11_help_attach (st, dptr, uptr, flag, cptr);
fprintf (st, "Software that runs on SIMH that supports this device include:\n");
fprintf (st, " - ITS, the PDP-10 Incompatible Timesharing System\n");
fprintf (st, "Outside SIMH, there's KLH10 and Lisp machine simulators. Various\n");
fprintf (st, "encapsulating transport mechanisms exist: UDP, IP, Ethernet.\n\n");
fprintf (st, "Documentation:\n");
fprintf (st, "https://lm-3.github.io/amber.html#Hardware-Programming-Documentation\n\n");
return SCPE_OK;
}
t_stat ch11_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "To configure CH11, first set the local Chaosnet node address, and\n");
fprintf (st, "the peer:\n\n");
fprintf (st, " sim> SET CH NODE=<octal address>\n");
fprintf (st, " sim> SET CH PEER=<remote host>:<remote port>\n\n");
fprintf (st, "Then, attach a local port. By default UDP is used:\n\n");
fprintf (st, " sim> ATTACH CH <local port>\n\n");
fprintf (st, "If TCP is desired, add \"TCP\":\n\n");
fprintf (st, " sim> ATTACH CH <local port>,TCP\n\n");
return SCPE_OK;
}
#endif

282
PDP10/ks10_cty.c Normal file
View file

@ -0,0 +1,282 @@
/* ks10_cty.c: KS-10 front end (console terminal) simulator
Copyright (c) 2021, 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 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
*/
#include "kx10_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#include <ctype.h>
#if KS
#define UNIT_DUMMY (1 << UNIT_V_UF)
#define STATUS 031
#define CTY_IN 032
#define CTY_OUT 033
#define KLINK_IN 034
#define KLINK_OUT 035
#define BOOT_ADDR 036
#define BOOT_DRIVE 037
#define MAG_FMT 040
#define KA_FAIL 0000000000001LL /* Keep Alive failed to change */
#define FORCE_RELOAD 0000000000002LL /* Force reload */
#define PWR_FAIL1 0000000000004LL /* Power failure */
#define BOOT_SW 0000000000010LL /* Boot switch */
#define KEEP_ALIVE 0000000177400LL /* Keep alive */
#define TRAPS_ENB 0000040000000LL /* Traps enabled */
#define ONE_MS 0000100000000LL /* 1ms enabled */
#define CACHE_ENB 0000200000000LL /* Cache enable */
#define DP_PAR_ENB 0000400000000LL /* DP parity error enable */
#define CRAM_PAR_ENB 0001000000000LL /* CRAM parity error enable */
#define PAR_ENB 0002000000000LL /* Parity error detect enable */
#define KLINK_ENB 0004000000000LL /* Klink active */
#define EX_KEEP_ALV 0010000000000LL /* Examine Keep Alive */
#define RELOAD 0020000000000LL /* Reload */
#define CTY_CHAR 0000000000400LL /* Character pending */
#define KLINK_CHAR 0000000000400LL /* Character pending */
#define KLINK_ACT 0000000001000LL /* KLINK ACTIVE */
#define KLINK_HANG 0000000001400LL /* KLINK HANGUP */
extern int32 tmxr_poll;
t_stat ctyi_svc (UNIT *uptr);
t_stat ctyo_svc (UNIT *uptr);
t_stat ctyrtc_srv(UNIT * uptr);
t_stat cty_reset (DEVICE *dptr);
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *cty_description (DEVICE *dptr);
uint64 keep_alive = 0;
int keep_num = 0;
extern DEVICE *rh_boot_dev;
extern int rh_boot_unit;
static int32 rtc_tps = 1;
MTAB cty_mod[] = {
{ UNIT_DUMMY, 0, NULL, "STOP", &cty_stop_os },
{ TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode },
{ TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode },
{ TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode },
{ TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode },
{ 0 }
};
UNIT cty_unit[] = {
{ UDATA (&ctyo_svc, TT_MODE_7B, 0), 20000},
{ UDATA (&ctyi_svc, TT_MODE_7B|UNIT_DIS, 0), 4000 },
{ UDATA (&ctyrtc_srv, UNIT_IDLE|UNIT_DIS, 0), 1000 }
};
REG cty_reg[] = {
{HRDATAD(WRU, sim_int_char, 8, "interrupt character") },
{ 0 },
};
DEVICE cty_dev = {
"CTY", cty_unit, cty_reg, cty_mod,
3, 10, 31, 1, 8, 8,
NULL, NULL, &cty_reset,
NULL, NULL, NULL, NULL, DEV_DEBUG, 0, dev_debug,
NULL, NULL, &cty_help, NULL, NULL, &cty_description
};
void
cty_wakeup()
{
sim_debug(DEBUG_EXP, &cty_dev, "CTY wakeup\n");
sim_activate(&cty_unit[0], cty_unit[0].wait);
}
/* Check for input from CTY and put on queue. */
t_stat ctyi_svc (UNIT *uptr)
{
uint64 buffer;
int32 ch;
sim_clock_coschedule (uptr, tmxr_poll * 3);
if (Mem_read_word(CTY_IN, &buffer, 0))
return SCPE_OK;
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Read %012llo\n", buffer);
if (buffer & CTY_CHAR)
return SCPE_OK;
ch = sim_poll_kbd ();
if (ch & SCPE_KFLAG) {
ch = 0177 & sim_tt_inpcvt(ch, TT_GET_MODE (cty_unit[0].flags));
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY char %o '%c'\n", ch,
((ch > 040 && ch < 0177)? ch: '.'));
buffer = (uint64)(ch) | CTY_CHAR;
if (Mem_write_word(CTY_IN, &buffer, 0) == 0) {
cty_interrupt();
} else {
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write failed %o '%c'\n", ch,
((ch > 040 && ch < 0177)? ch: '.'));
}
}
return SCPE_OK;
}
/* Handle output of characters to CTY. Started whenever there is output pending */
t_stat ctyo_svc (UNIT *uptr)
{
uint64 buffer;
/* Check if any input pending? */
if (Mem_read_word(CTY_OUT, &buffer, 0))
return SCPE_OK;
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY Write %012llo\n", buffer);
if (buffer & CTY_CHAR) {
int32 ch;
ch = buffer & 0377;
ch = sim_tt_outcvt ( ch, TT_GET_MODE (uptr->flags));
if (sim_putchar_s(ch) != SCPE_OK) {
sim_activate(uptr, 2000);
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write %o '%c'\n", ch,
((ch > 040 && ch < 0177)? ch: '.'));
buffer = 0;
if (Mem_write_word(CTY_OUT, &buffer, 0) == 0) {
cty_interrupt();
} else {
sim_debug(DEBUG_DETAIL, &cty_dev, "CTY write failed %o '%c'\n", ch,
((ch > 040 && ch < 0177)? ch: '.'));
}
}
if (Mem_read_word(KLINK_OUT, &buffer, 0))
return SCPE_OK;
if (buffer != 0) {
buffer = 0;
if (Mem_write_word(CTY_OUT, &buffer, 0) == 0) {
cty_interrupt();
}
}
return SCPE_OK;
}
/* Handle FE timer interrupts. And keepalive counts */
t_stat
ctyrtc_srv(UNIT * uptr)
{
uint64 buffer;
sim_activate_after(uptr, 1000000/rtc_tps);
if (Mem_read_word(STATUS, &buffer, 0))
return SCPE_OK;
if (buffer & ONE_MS) {
fprintf(stderr, "1MS\n\r");
}
if (buffer & RELOAD && rh_boot_dev != NULL) {
reset_all(1); /* Reset everybody */
if (rh_boot_dev->boot(rh_boot_unit, rh_boot_dev) != SCPE_OK)
return SCPE_STOP;
}
/* Check if clock requested */
if (buffer & EX_KEEP_ALV) {
if (keep_alive != (buffer & KEEP_ALIVE)) {
keep_alive = buffer;
keep_num = 0;
} else {
if (++keep_num >= 15) {
keep_num = 0;
buffer &= ~0377LL;
buffer |= 1;
cty_execute(071);
M[STATUS] = buffer;
M[CTY_IN] = 0;
M[CTY_OUT] = 0;
M[KLINK_IN] = 0;
M[KLINK_OUT] = 0;
}
}
}
return SCPE_OK;
}
t_stat cty_reset (DEVICE *dptr)
{
sim_activate(&cty_unit[1], cty_unit[1].wait);
sim_activate(&cty_unit[2], cty_unit[2].wait);
M[STATUS] = 0;
M[CTY_IN] = 0;
M[CTY_OUT] = 0;
M[KLINK_IN] = 0;
M[KLINK_OUT] = 0;
M[CTY_SWITCH] = 0;
return SCPE_OK;
}
t_stat tty_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
cty_unit[0].flags = (cty_unit[0].flags & ~TT_MODE) | val;
return SCPE_OK;
}
/* Stop operating system */
t_stat cty_stop_os (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
M[CTY_SWITCH] = 1; /* tell OS to stop */
return SCPE_OK;
}
t_stat cty_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "To stop the cpu use the command:\n\n");
fprintf (st, " sim> SET CTY STOP\n\n");
fprintf (st, "This will write a 1 to location %03o, causing TOPS10 to stop\n\n", CTY_SWITCH);
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
fprintf (st, " mode input characters output characters\n\n");
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
fprintf (st, " to upper case, high-order bit cleared,\n");
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
fprintf (st, " non-printing characters suppressed\n");
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
fprintf (st, " 8B no changes no changes\n\n");
fprintf (st, "The default mode is 7P. In addition, each line can be configured to\n");
fprintf (st, "behave as though it was attached to a dataset, or hardwired to a terminal:\n\n");
fprint_reg_help (st, &cty_dev);
return SCPE_OK;
}
const char *cty_description (DEVICE *dptr)
{
return "Console TTY Line";
}
#endif

1604
PDP10/ks10_dup.c Normal file

File diff suppressed because it is too large Load diff

64
PDP10/ks10_dup.h Normal file
View file

@ -0,0 +1,64 @@
/* ks10_dup.h: PDP-11 DUP11 bit synchronous shared device packet interface interface
Copyright (c) 2013, Mark Pizzolato
Modified for KA10 simulator by Richard Cornwell, 2022
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.
dup DUP11 Unibus/DPV11 Qbus bit synchronous interface
This module describes the interfaces exposed by the dup device for use by
a packet delivery devices (i.e. KMC11).
31-May-13 MP Initial implementation
*/
#ifndef PDP11_DUP_H_
#define PDP11_DUP_H_ 0
typedef void (*PACKET_DATA_AVAILABLE_CALLBACK)(int32 dup, int len);
typedef void (*PACKET_TRANSMIT_COMPLETE_CALLBACK)(int32 dup, int status);
typedef void (*MODEM_CHANGE_CALLBACK)(int32 dup);
int32 dup_get_DSR (int32 dup);
int32 dup_get_DCD (int32 dup);
int32 dup_get_CTS (int32 dup);
int32 dup_get_RING (int32 dup);
int32 dup_get_RCVEN (int32 dup);
t_stat dup_set_DTR (int32 dup, t_bool state);
t_stat dup_set_RTS (int32 dup, t_bool state);
t_stat dup_set_W3_option (int32 dup, t_bool state);
t_stat dup_set_W5_option (int32 dup, t_bool state);
t_stat dup_set_W6_option (int32 dup, t_bool state);
t_stat dup_set_RCVEN (int32 dup, t_bool state);
t_stat dup_setup_dup (int32 dup, t_bool enable, t_bool protocol_DDCMP, t_bool crc_inhibit, t_bool halfduplex, uint8 station);
t_stat dup_reset_dup (int32 dup);
int32 dup_csr_to_linenum (int32 CSRPA);
void dup_set_callback_mode (int32 dup, PACKET_DATA_AVAILABLE_CALLBACK receive, PACKET_TRANSMIT_COMPLETE_CALLBACK transmit, MODEM_CHANGE_CALLBACK modem);
t_bool dup_put_msg_bytes (int32 dup, uint8 *bytes, size_t len, t_bool start, t_bool end);
t_stat dup_get_packet (int32 dup, const uint8 **pbuf, uint16 *psize);
#endif /* PDP11_DUP_H_ */

667
PDP10/ks10_dz.c Normal file
View file

@ -0,0 +1,667 @@
/* ks10_dz.c: PDP-10 DZ11 communication server simulator
Copyright (c) 2021, 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 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.
*/
#include "kx10_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_DZ
#define NUM_DEVS_DZ 0
#endif
#if (NUM_DEVS_DZ > 0)
#define DZ11_LINES (8 * NUM_DEVS_DZ)
/* 0 CSR */
#define MAINT 0000010 /* Maintance mode */
#define CLR 0000020
#define MSE 0000040
#define RIE 0000100
#define RDONE 0000200
#define TLINE 0003400
#define TLINE_V 8
#define SAE 0010000
#define SA 0020000
#define TIE 0040000
#define TRDY 0100000
/* 2 RBUF */
#define RBUF 0000377
#define RXLINE 0003400
#define RXLINE_V 8
#define PAR_ERR 0010000
#define FRM_ERR 0020000
#define OVRN 0040000
#define VALID 0100000
/* 2 LPR */
#define LINE 0000007
#define CHAR_LEN 0000030
#define STOP 0000040
#define PAR_ENB 0000100
#define ODD_PAR 0000200
#define FREQ 0007400
#define RXON 0010000
/* 4 TCR */
#define LINE_ENB 0000001
#define DTR 0000400
/* 6 MSR */
#define RO 0000001
#define CO 0000400
/* 6 TDR */
#define TBUF 0000377
#define BRK 0000400
struct _buffer {
int in_ptr; /* Insert pointer */
int out_ptr; /* Remove pointer */
uint16 buff[64]; /* Buffer */
int len; /* Length */
};
#define full(q) ((((q)->in_ptr + 1) & 0x3f) == (q)->out_ptr)
#define empty(q) ((q)->in_ptr == (q)->out_ptr)
#define not_empty(q) ((q)->in_ptr != (q)->out_ptr)
#define inco(q) (q)->out_ptr = ((q)->out_ptr + 1) & 0x3f
#define inci(q) (q)->in_ptr = ((q)->in_ptr + 1) & 0x3f
#define LINE_EN 01
#define DTR_FLAG 02
uint16 dz_csr[NUM_DEVS_DZ];
uint16 dz_xmit[DZ11_LINES];
uint8 dz_flags[DZ11_LINES];
uint8 dz_ring[NUM_DEVS_DZ];
struct _buffer dz_recv[NUM_DEVS_DZ];
TMLN dz_ldsc[DZ11_LINES] = { 0 }; /* Line descriptors */
TMXR dz_desc = { DZ11_LINES, 0, 0, dz_ldsc };
extern int32 tmxr_poll;
int dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
t_stat dz_svc (UNIT *uptr);
t_stat dz_reset (DEVICE *dptr);
void dz_checkirq(struct pdp_dib *dibp);
uint16 dz_vect(struct pdp_dib *dibp);
t_stat dz_set_modem (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dz_show_modem (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat dz_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dz_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dz_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat dz_attach (UNIT *uptr, CONST char *cptr);
t_stat dz_detach (UNIT *uptr);
t_stat dz_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *dz_description (DEVICE *dptr);
DIB dz_dib = { 0760000, 077, 0340, 5, 3, &dz_read, &dz_write, 0, 0, 0 };
UNIT dz_unit = {
UDATA (&dz_svc, TT_MODE_7B+UNIT_IDLE+UNIT_DISABLE+UNIT_ATTABLE, 0), KBD_POLL_WAIT
};
REG dz_reg[] = {
{ DRDATA (TIME, dz_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL }
};
MTAB dz_mod[] = {
{ TT_MODE, TT_MODE_KSR, "KSR", "KSR", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of DZ11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
NULL, "Sets vect of DZ11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
NULL, "Sets br of DZ11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of DZ11" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dz_desc, "Disconnect a specific line" },
{ UNIT_ATT, UNIT_ATT, "SUMMARY", NULL,
NULL, &tmxr_show_summ, (void *) &dz_desc, "Display a summary of line states" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &tmxr_show_cstat, (void *) &dz_desc, "Display current connections" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &tmxr_show_cstat, (void *) &dz_desc, "Display multiplexer statistics" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "LINES", "LINES=n",
&dz_setnl, &tmxr_show_lines, (void *) &dz_desc, "Set number of lines" },
{ MTAB_XTD|MTAB_VDV|MTAB_NC, 0, NULL, "LOG=n=file",
&dz_set_log, NULL, (void *)&dz_desc },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "NOLOG",
&dz_set_nolog, NULL, (void *)&dz_desc, "Disable logging on designated line" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "LOG", NULL,
NULL, &dz_show_log, (void *)&dz_desc, "Display logging for all lines" },
{ 0 }
};
DEVICE dz_dev = {
"DZ", &dz_unit, dz_reg, dz_mod,
1, 10, 31, 1, 8, 8,
&tmxr_ex, &tmxr_dep, &dz_reset,
NULL, &dz_attach, &dz_detach,
&dz_dib, DEV_MUX | DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &dz_help, NULL, NULL, &dz_description
};
int
dz_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
int base;
uint16 temp;
int ln;
TMLN *lp;
int i;
if ((dptr->flags & DEV_DIS) != 0)
return 1;
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
addr &= dibp->uba_mask;
if (addr < 010 || addr > 047)
return 1;
base = ((addr & 070) - 010) >> 3;
if (((base + 1) * 8) > dz_desc.lines)
return 1;
sim_debug(DEBUG_DETAIL, dptr, "DZ%o write %06o %06o %o\n", base,
addr, data, access);
switch (addr & 06) {
case 0:
if (access == BYTE) {
temp = dz_csr[base];
if (addr & 1)
data = data | (temp & 0377);
else
data = (temp & 0177400) | data;
}
if (data & CLR) {
dz_csr[base] = 0;
dz_recv[base].in_ptr = dz_recv[base].out_ptr = 0;
dz_recv[base].len = 0;
/* Set up the current status */
ln = base << 3;
for (i = 0; i < 8; i++) {
dz_flags[ln + i] &= ~LINE_EN;
}
return 0;
}
dz_csr[base] &= ~(TIE|SAE|RIE|MSE|CLR|MAINT);
dz_csr[base] |= data & (TIE|SAE|RIE|MSE|MAINT);
if (((dz_csr[base] & (RDONE|RIE)) == (RDONE|RIE)) ||
(dz_csr[base] & (SA|SAE)) == (SA|SAE))
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
else
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
if ((dz_csr[base] & (TRDY|TIE)) == (TRDY|TIE))
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * base));
else
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
case 2:
ln = (data & 07) + (base << 3);
dz_ldsc[ln].rcve = (data & RXON) != 0;
break;
case 4:
temp = 0;
ln = base << 3;
/* Set up the current status */
for (i = 0; i < 8; i++) {
if (dz_flags[ln + i] & LINE_EN)
temp |= LINE_ENB << i;
if (dz_flags[ln + i] & DTR_FLAG)
temp |= DTR << i;
dz_flags[ln + i] = 0;
}
if (access == BYTE) {
if (addr & 1)
data = data | (temp & 0377);
else
data = (temp & 0177400) | data;
}
dz_csr[base] &= ~(TRDY);
for (i = 0; i < 8; i++) {
lp = &dz_ldsc[ln + i];
if ((data & (LINE_ENB << i)) != 0)
dz_flags[ln + i] |= LINE_EN;
if ((data & (DTR << i)) != 0)
dz_flags[ln + i] |= DTR_FLAG;
if (dz_flags[ln + i] & DTR_FLAG)
tmxr_set_get_modem_bits(lp, TMXR_MDM_OUTGOING, 0, NULL);
else
tmxr_set_get_modem_bits(lp, 0, TMXR_MDM_OUTGOING, NULL);
sim_debug(DEBUG_EXP, dptr, "DZ%o sstatus %07o %o %o\n", base, data, i, dz_flags[ln+i]);
}
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
case 6:
if (access == BYTE && (addr & 1) != 0) {
break;
}
if ((dz_csr[base] & TRDY) == 0)
break;
ln = ((dz_csr[base] & TLINE) >> TLINE_V) + (base << 3);
lp = &dz_ldsc[ln];
if ((dz_flags[ln] & LINE_EN) != 0 && lp->conn) {
int32 ch = data & 0377;
t_stat r;
ch = sim_tt_outcvt(ch, TT_GET_MODE (dz_unit.flags) | TTUF_KSR);
/* Try and send character */
r = tmxr_putc_ln(lp, ch);
/* If character did not send, queue it */
if (r == SCPE_STALL)
dz_xmit[ln] = TRDY | ch;
}
dz_csr[base] &= ~TRDY;
uba_clr_irq(dibp, dibp->uba_vect + 4 + (010 * base));
break;
}
dz_checkirq(dibp);
return 0;
}
int
dz_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
int base;
uint16 temp;
int ln;
TMLN *lp;
int i;
if ((dptr->flags & DEV_DIS) != 0)
return 1;
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
addr &= dibp->uba_mask;
if (addr < 010 || addr > 047)
return 1;
base = ((addr & 070) - 010) >> 3;
if (((base + 1) * 8) > dz_desc.lines)
return 1;
switch (addr & 06) {
case 0:
*data = dz_csr[base];
break;
case 2:
*data = 0;
if ((dz_csr[base] & MSE) == 0)
return 0;
dz_csr[base] &= ~(SA|RDONE);
uba_clr_irq(dibp, dibp->uba_vect + (010 * base));
if (!empty(&dz_recv[base])) {
*data = dz_recv[base].buff[dz_recv[base].out_ptr];
inco(&dz_recv[base]);
dz_recv[base].len = 0;
}
if (!empty(&dz_recv[base])) {
dz_csr[base] |= RDONE;
if (dz_csr[base] & RIE) {
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
}
}
break;
case 4:
temp = 0;
base <<= 3;
/* Set up the current status */
for (ln = 0; ln < 8; ln++) {
if (dz_flags[base + ln] & LINE_EN)
temp |= LINE_ENB << ln;
if (dz_flags[base + ln] & DTR_FLAG)
temp |= DTR << ln;
}
*data = temp;
break;
case 6:
temp = (uint16)dz_ring[base];
ln = base << 3;
for (i = 0; i < 8; i++) {
lp = &dz_ldsc[ln + i];
if (lp->conn)
temp |= CO << i;
}
dz_ring[base] = 0;
*data = temp;
break;
}
sim_debug(DEBUG_DETAIL, dptr, "DZ%o read %06o %06o %o\n", base,
addr, *data, access);
return 0;
}
/* Unit service */
t_stat dz_svc (UNIT *uptr)
{
int32 ln;
int base;
uint16 temp;
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
TMLN *lp;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
ln = tmxr_poll_conn (&dz_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb*/
dz_ring[(ln & 030) >> 3] |= (1 << (ln & 7));
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line connect %d\n", ln);
dz_xmit[ln] = 0;
}
tmxr_poll_tx(&dz_desc);
tmxr_poll_rx(&dz_desc);
for (ln = 0; ln < dz_desc.lines; ln++) {
lp = &dz_ldsc[ln];
base = (ln >> 3) & 03;
if (dz_xmit[ln] != 0) {
/* Try and send character */
t_stat r = tmxr_putc_ln(lp, dz_xmit[ln] & 0377);
/* If character did not send, queue it */
if (r == SCPE_OK)
dz_xmit[ln] = 0;
}
/* If silo full, skip to next */
while (!full(&dz_recv[base])) {
int32 ch = tmxr_getc_ln(lp);
if ((ch & TMXR_VALID) != 0) {
if (ch & SCPE_BREAK) { /* break? */
temp = FRM_ERR;
} else {
ch = sim_tt_inpcvt (ch, TT_GET_MODE(dz_unit.flags) | TTUF_KSR);
temp = VALID | ((ln & 07) << RXLINE_V) | (uint16)(ch & RBUF);
}
dz_recv[base].buff[dz_recv[base].in_ptr] = temp;
inci(&dz_recv[base]);
dz_recv[base].len++;
dz_csr[base] |= RDONE;
if (dz_csr[base] & RIE)
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
if (dz_recv[base].len > 16) {
dz_csr[base] |= SA;
if (dz_csr[base] & SAE) {
uba_set_irq(dibp, dibp->uba_vect + (010 * base));
}
}
sim_debug(DEBUG_DETAIL, dptr, "TTY recieve %d: %o\n", ln, ch);
} else
break;
}
}
dz_checkirq(dibp);
sim_clock_coschedule(uptr, tmxr_poll); /* continue poll */
return SCPE_OK;
}
/* Check if a device has an IRQ event ready */
void
dz_checkirq(struct pdp_dib *dibp)
{
int i;
int ln;
int stop;
TMLN *lp;
int irq = 0;
for (i = 0; i < NUM_DEVS_DZ; i++) {
if ((dz_csr[i] & MSE) == 0)
continue;
ln = ((dz_csr[i] & TLINE) >> TLINE_V) + (i << 3);
stop = ln;
if ((dz_csr[i] & TRDY) == 0) {
/* See if there is another line ready */
do {
ln = (ln & 070) | ((ln + 1) & 07);
lp = &dz_ldsc[ln];
/* Connected and empty xmit_buffer */
if ((dz_flags[ln] & LINE_EN) != 0 && dz_xmit[ln] == 0) {
sim_debug(DEBUG_DETAIL, &dz_dev, "DZ line ready %o\n", ln);
dz_csr[i] &= ~(TRDY|TLINE);
dz_csr[i] |= TRDY | ((ln & 07) << TLINE_V);
if (dz_csr[i] & TIE) {
uba_set_irq(dibp, dibp->uba_vect + 4 + (010 * i));
}
break;
}
} while (ln != stop);
}
}
}
/* Reset routine */
t_stat
dz_reset (DEVICE *dptr)
{
int i;
if (dz_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&dz_unit, tmxr_poll); /* activate */
else
sim_cancel (&dz_unit); /* else stop */
for (i = 0; i < NUM_DEVS_DZ; i++) {
dz_csr[i] = 0;
dz_recv[i].in_ptr = dz_recv[i].out_ptr = 0;
dz_recv[i].len = 0;
dz_ring[i] = 0;
dz_xmit[i] = 0;
}
for (i = 0; i < DZ11_LINES; i++) {
dz_flags[i] = 0;
}
return SCPE_OK;
}
/* SET LINES processor */
t_stat
dz_setnl (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
newln = (int32) get_uint (cptr, 10, DZ11_LINES, &r);
if ((r != SCPE_OK) || (newln == dz_desc.lines))
return r;
if ((newln == 0) || (newln > DZ11_LINES) || (newln % 8) != 0)
return SCPE_ARG;
if (newln < dz_desc.lines) {
for (i = newln - 1, t = 0; i < dz_desc.lines; i++)
t = t | dz_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln - 1; i < dz_desc.lines; i++) {
if (dz_ldsc[i].conn) {
tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_send_buffered_data (&dz_ldsc[i]);
}
tmxr_detach_ln (&dz_ldsc[i]); /* completely reset line */
}
}
if (dz_desc.lines < newln)
memset (dz_ldsc + dz_desc.lines, 0, sizeof(*dz_ldsc)*(newln-dz_desc.lines));
dz_desc.lines = newln;
return dz_reset (&dz_dev); /* setup lines and auto config */
}
/* SET LOG processor */
t_stat
dz_set_log (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r;
char gbuf[CBUFSIZE];
int32 ln;
if (cptr == NULL)
return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, '=');
if ((cptr == NULL) || (*cptr == 0) || (gbuf[0] == 0))
return SCPE_ARG;
ln = (int32) get_uint (gbuf, 10, dz_desc.lines, &r);
if ((r != SCPE_OK) || (ln > dz_desc.lines))
return SCPE_ARG;
return tmxr_set_log (NULL, ln, cptr, desc);
}
/* SET NOLOG processor */
t_stat
dz_set_nolog (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_stat r;
int32 ln;
if (cptr == NULL)
return SCPE_ARG;
ln = (int32) get_uint (cptr, 10, dz_desc.lines, &r);
if ((r != SCPE_OK) || (ln > dz_desc.lines))
return SCPE_ARG;
return tmxr_set_nolog (NULL, ln, NULL, desc);
}
/* SHOW LOG processor */
t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 i;
for (i = 0; i < dz_desc.lines; i++) {
fprintf (st, "line %d: ", i);
tmxr_show_log (st, NULL, i, desc);
fprintf (st, "\n");
}
return SCPE_OK;
}
/* Attach routine */
t_stat
dz_attach (UNIT *uptr, CONST char *cptr)
{
t_stat reason;
reason = tmxr_attach (&dz_desc, uptr, cptr);
if (reason != SCPE_OK)
return reason;
sim_activate (uptr, tmxr_poll);
return SCPE_OK;
}
/* Detach routine */
t_stat
dz_detach (UNIT *uptr)
{
int32 i;
t_stat reason;
reason = tmxr_detach (&dz_desc, uptr);
for (i = 0; i < dz_desc.lines; i++)
dz_ldsc[i].rcve = 0;
sim_cancel (uptr);
return reason;
}
t_stat dz_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "DZ11 Terminal Interfaces\n\n");
fprintf (st, "Each DZ11 supports 8 serial lines. Up to 32 can be configured\n");
fprintf (st, " sim> SET DZ LINES=n set number of additional lines to n [8-32]\n\n");
fprintf (st, "Lines must be set in multiples of 8.\n");
fprintf (st, "The ATTACH command specifies the port to be used:\n\n");
tmxr_attach_help (st, dptr, uptr, flag, cptr);
fprintf (st, "The additional terminals can be set to one of four modes: UC, 7P, 7B, or 8B.\n\n");
fprintf (st, " mode input characters output characters\n\n");
fprintf (st, " UC lower case converted lower case converted to upper case,\n");
fprintf (st, " to upper case, high-order bit cleared,\n");
fprintf (st, " high-order bit cleared non-printing characters suppressed\n");
fprintf (st, " 7P high-order bit cleared high-order bit cleared,\n");
fprintf (st, " non-printing characters suppressed\n");
fprintf (st, " 7B high-order bit cleared high-order bit cleared\n");
fprintf (st, " 8B no changes no changes\n\n");
fprintf (st, "The default mode is 7P.\n");
fprintf (st, "Finally, each line supports output logging. The SET DZn LOG command enables\n");
fprintf (st, "logging on a line:\n\n");
fprintf (st, " sim> SET DZn LOG=filename log output of line n to filename\n\n");
fprintf (st, "The SET DZn NOLOG command disables logging and closes the open log file,\n");
fprintf (st, "if any.\n\n");
fprintf (st, "Once DZ is attached and the simulator is running, the terminals listen for\n");
fprintf (st, "connections on the specified port. They assume that the incoming connections\n");
fprintf (st, "are Telnet connections. The connections remain open until disconnected either\n");
fprintf (st, "by the Telnet client, a SET DZ DISCONNECT command, or a DETACH DC command.\n\n");
fprintf (st, "Other special commands:\n\n");
fprintf (st, " sim> SHOW DZ CONNECTIONS show current connections\n");
fprintf (st, " sim> SHOW DZ STATISTICS show statistics for active connections\n");
fprintf (st, " sim> SET DZn DISCONNECT disconnects the specified line.\n\n");
fprintf (st, "The DZ11 is a unibus device, various parameters can be changed on these devices\n");
fprintf (st, "\n The address of the device can be set with: \n");
fprintf (st, " sim> SET DZ ADDR=octal default address= 760000\n");
fprintf (st, "\n The interrupt vector can be set with: \n");
fprintf (st, " sim> SET DZ VECT=octal default 340\n");
fprintf (st, "\n The interrupt level can be set with: \n");
fprintf (st, " sim> SET DZ BR=# # should be between 4 and 7.\n");
fprintf (st, "\n The unibus addaptor that the DZ is on can be set with:\n");
fprintf (st, " sim> SET DZ CTL=# # can be either 1 or 3\n");
fprint_reg_help (st, &dz_dev);
fprintf (st, "\nThe additional terminals do not support save and restore. All open connections\n");
fprintf (st, "are lost when the simulator shuts down or DZ is detached.\n");
return SCPE_OK;
}
const char *dz_description (DEVICE *dptr)
{
return "DZ11 asynchronous line interface";
}
#endif

3080
PDP10/ks10_kmc.c Normal file

File diff suppressed because it is too large Load diff

896
PDP10/ks10_lp.c Normal file
View file

@ -0,0 +1,896 @@
/* ks10_lp.c: PDP-10 LP20 printer.
Copyright (c) 2021, 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 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.
*/
#include "kx10_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_LP20
#define NUM_DEVS_LP20 0
#endif
#if (NUM_DEVS_LP20 > 0)
#define UNIT_V_CT (UNIT_V_UF + 0)
#define UNIT_UC (1 << UNIT_V_CT)
#define UNIT_CT (1 << UNIT_V_CT)
#define UNIT_V_VFU (UNIT_V_CT + 1)
#define UNIT_OPT (1 << UNIT_V_VFU)
#define LINE u6
/* LPCSRA (765400) */
#define CS1_GO 0000001 /* Go command */
#define CS1_PAR 0000002 /* Enable Parity interrupt */
#define CS1_V_FNC 2 /* Function shift */
#define CS1_M_FNC 03 /* Function mask */
#define FNC_PRINT 0 /* Print */
#define FNC_TEST 1 /* Test */
#define FNC_DVU 2 /* Load DAVFU */
#define FNC_RAM 3 /* Load translation RAM */
#define CS1_UBA 0000060 /* Upper Unibus address */
#define CS1_IE 0000100 /* Interrupt enable */
#define CS1_DONE 0000200 /* Done flag */
#define CS1_INIT 0000400 /* Init */
#define CS1_ECLR 0001000 /* Clear errors */
#define CS1_DHOLD 0002000 /* Delimiter hold */
#define CS1_ONL 0004000 /* Online */
#define CS1_DVON 0010000 /* DAVFU online */
#define CS1_UND 0020000 /* Undefined Character */
#define CS1_PZERO 0040000 /* Page counter zero */
#define CS1_ERR 0100000 /* Errors */
#define CS1_MOD (CS1_DHOLD|CS1_IE|(CS1_M_FNC << CS1_V_FNC)|CS1_PAR|CS1_GO)
/* LPCSRB (765402) */
#define CS2_GOE 0000001 /* Go error */
#define CS2_DTE 0000002 /* DEM timing error */
#define CS2_MTE 0000004 /* MSYN error */
#define CS2_RPE 0000010 /* RAM parity error */
#define CS2_MPE 0000020 /* Memory parity error */
#define CS2_LPE 0000040 /* LPT parity error */
#define CS2_DVOF 0000100 /* DAVFU not ready */
#define CS2_OFFL 0000200 /* Offline */
#define CS2_TEST 0003400 /* Test mode */
#define CS2_OVFU 0004000 /* Optical VFU */
#define CS2_PBIT 0010000 /* data parity bit */
#define CS2_NRDY 0020000 /* Printer error */
#define CS2_LA180 0040000 /* LA180 printer */
#define CS2_VLD 0100000 /* Valid data */
#define CS2_ECLR (CS2_GOE|CS2_DTE|CS2_MTE|CS2_RPE|CS2_LPE)
#define CS2_ERR (CS2_ECLR|CS2_OFFL|CS2_DVOF)
/* LPBA (765404) */
/* Unibus address */
/* LPBC (765406) */
/* byte count */
/* LPPAGC (765410) */
/* Page count */
/* LPRDAT (765412) */
/* RAM Data register */
/* LPCOLC/LPCBUF (765414) */
/* Column counter / Character buffer */
/* LPCSUM/LPPDAT (765416) */
/* Checksum / Printer data */
#define EOFFLG 001 /* Tops 20 wants EOF */
#define HDSFLG 002 /* Tell Tops 20 The current device status */
#define ACKFLG 004 /* Post an acknowwledge message */
#define INTFLG 010 /* Send interrupt */
#define DELFLG 020 /* Previous character was delimiter */
#define MARGIN 6
int lp20_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int lp20_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
void lp20_printline(UNIT *uptr, int nl);
void lp20_output(UNIT *uptr, uint8 c);
void lp20_update_chkirq (UNIT *uptr, int done, int irq);
void lp20_update_ready(UNIT *uptr, uint16 setrdy, uint16 clrrdy);
t_stat lp20_svc (UNIT *uptr);
t_stat lp20_init (UNIT *uptr);
t_stat lp20_reset (DEVICE *dptr);
t_stat lp20_attach (UNIT *uptr, CONST char *cptr);
t_stat lp20_detach (UNIT *uptr);
t_stat lp20_setlpp(UNIT *, int32, CONST char *, void *);
t_stat lp20_getlpp(FILE *, UNIT *, int32, CONST void *);
t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *lp20_description (DEVICE *dptr);
char lp20_buffer[134 * 3];
uint16 lp20_cs1;
uint16 lp20_cs2;
uint16 lp20_pagcnt;
uint32 lp20_ba;
uint16 lp20_wcnt;
uint8 lp20_col;
uint8 lp20_chksum;
uint8 lp20_buf;
uint8 lp20_data;
int lp20_odd = 0;
int lp20_duvfa_state = 0;
int lp20_index = 0;
#define LP20_RAM_RAP 010000 /* RAM Parity */
#define LP20_RAM_INT 04000 /* Interrrupt bit */
#define LP20_RAM_DEL 02000 /* Delimiter bit */
#define LP20_RAM_TRN 01000 /* Translation bite */
#define LP20_RAM_PI 00400 /* Paper Instruction */
#define LP20_RAM_CHR 00377 /* Character translation */
uint16 lp20_vfu[256];
uint16 lp20_ram[256];
uint16 lp20_dvfu[] = { /* Default VFU */
/* 66 line page with 6 line margin */
00377, /* Line 0 8 7 6 5 4 3 2 1 */
00220, /* Line 1 8 5 */
00224, /* Line 2 8 5 3 */
00230, /* Line 3 8 5 4 */
00224, /* Line 4 8 5 3 */
00220, /* Line 5 8 5 */
00234, /* Line 6 8 5 4 3 */
00220, /* Line 7 8 5 */
00224, /* Line 8 8 5 3 */
00230, /* Line 9 8 5 4 */
00264, /* Line 10 8 6 5 3 */
00220, /* Line 11 8 5 */
00234, /* Line 12 8 5 4 3 */
00220, /* Line 13 8 5 */
00224, /* Line 14 8 5 3 */
00230, /* Line 15 8 5 4 */
00224, /* Line 16 8 5 3 */
00220, /* Line 17 8 5 */
00234, /* Line 18 8 5 4 3 */
00220, /* Line 19 8 5 */
00364, /* Line 20 8 7 6 5 3 */
00230, /* Line 21 8 5 4 */
00224, /* Line 22 8 5 3 */
00220, /* Line 23 8 5 */
00234, /* Line 24 8 5 4 3 */
00220, /* Line 25 8 5 */
00224, /* Line 26 8 5 3 */
00230, /* Line 27 8 5 4 */
00224, /* Line 28 8 5 3 */
00220, /* Line 29 8 5 */
00276, /* Line 30 8 6 5 4 3 2 */
00220, /* Line 31 8 5 */
00224, /* Line 32 8 5 3 */
00230, /* Line 33 8 5 4 */
00224, /* Line 34 8 5 3 */
00220, /* Line 35 8 5 */
00234, /* Line 36 8 5 4 3 */
00220, /* Line 37 8 5 */
00224, /* Line 38 8 5 3 */
00230, /* Line 39 8 5 4 */
00364, /* Line 40 8 7 6 5 3 */
00220, /* Line 41 8 5 */
00234, /* Line 42 8 5 4 3 */
00220, /* Line 43 8 5 */
00224, /* Line 44 8 5 3 */
00230, /* Line 45 8 5 4 */
00224, /* Line 46 8 5 3 */
00220, /* Line 47 8 5 */
00234, /* Line 48 8 5 4 3 */
00220, /* Line 49 8 5 */
00264, /* Line 50 8 6 5 3 */
00230, /* Line 51 8 5 4 */
00224, /* Line 52 8 5 3 */
00220, /* Line 53 8 5 */
00234, /* Line 54 8 5 4 3 */
00220, /* Line 55 8 5 */
00224, /* Line 56 8 5 3 */
00230, /* Line 57 8 5 4 */
00224, /* Line 58 8 5 3 */
00220, /* Line 59 8 5 */
00020, /* Line 60 5 */
00020, /* Line 61 5 */
00020, /* Line 62 5 */
00020, /* Line 63 5 */
00020, /* Line 64 5 */
04020, /* Line 65 12 5 */
010000, /* End of form */
};
/* LPT data structures
lp20_dev LPT device descriptor
lp20_unit LPT unit descriptor
lp20_reg LPT register list
*/
DIB lp20_dib = { 0775400, 017, 0754, 5, 3, &lp20_read, &lp20_write, NULL, 0, 0 };
UNIT lp20_unit = {
UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 66), 100
};
REG lp20_reg[] = {
{BRDATA(BUFFER, lp20_buffer, 16, 8, sizeof(lp20_buffer)), REG_HRO},
{BRDATA(VFU, lp20_vfu, 16, 16, (sizeof(lp20_vfu)/sizeof(uint16))), REG_HRO},
{BRDATA(RAM, lp20_ram, 16, 16, (sizeof(lp20_ram)/sizeof(uint16))), REG_HRO},
{ORDATA(CS1, lp20_cs1, 16)},
{ORDATA(CS2, lp20_cs2, 16)},
{ORDATA(PAGCNT, lp20_pagcnt, 12)},
{ORDATA(BA, lp20_ba, 18)},
{ORDATA(BC, lp20_wcnt, 16)},
{ORDATA(COL, lp20_col, 8)},
{ORDATA(CHKSUM, lp20_chksum, 8)},
{ORDATA(BUF, lp20_buf, 8)},
{ NULL }
};
MTAB lp20_mod[] = {
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of LP20" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
NULL, "Sets vect of LP20" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
NULL, "Sets br of LP20" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of LP20" },
{UNIT_CT, 0, "Lower case", "LC", NULL},
{UNIT_CT, UNIT_UC, "Upper case", "UC", NULL},
{UNIT_OPT, 0, "Normal VFU", "NORMAL", NULL},
{UNIT_OPT, UNIT_OPT, "Optical VFU", "OPTICAL", NULL},
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LINESPERPAGE", "LINESPERPAGE",
&lp20_setlpp, &lp20_getlpp, NULL, "Number of lines per page"},
{ 0 }
};
DEVICE lp20_dev = {
"LP20", &lp20_unit, lp20_reg, lp20_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lp20_reset,
NULL, &lp20_attach, &lp20_detach,
&lp20_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &lp20_help, NULL, NULL, &lp20_description
};
int
lp20_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
uint16 temp;
addr &= dibp->uba_mask;
sim_debug(DEBUG_DETAIL, dptr, "LP20 write %06o %06o %o\n",
addr, data, access);
switch (addr & 016) {
case 000: /* LPCSA */
if (access == BYTE) {
if (addr & 1)
data = data | (lp20_cs1 & 0377);
else
data = (lp20_cs1 & 0177400) | data;
}
lp20_ba = ((data & CS1_UBA) << 9) | (lp20_ba & 0177777);
if (data & CS1_INIT) {
/* Reset controller */
lp20_init (&lp20_unit);
}
if (data & CS1_ECLR) {
/* Clear errors */
lp20_cs2 &= ~(CS2_ECLR);
lp20_cs1 &= ~(CS1_GO);
lp20_cs1 |= CS1_DONE;
}
if (data & CS1_GO) {
if ((lp20_cs1 & CS1_GO) == 0) {
lp20_chksum = 0;
lp20_odd = 0;
lp20_duvfa_state = 0;
lp20_index = 0;
sim_activate(&lp20_unit, 100);
lp20_cs1 |= CS1_GO;
}
} else {
lp20_cs1 &= ~CS1_GO;
sim_cancel(&lp20_unit);
}
lp20_cs1 &= ~(CS1_MOD);
lp20_cs1 |= data & CS1_MOD;
if (lp20_duvfa_state && ((lp20_cs1 >> CS1_V_FNC) & CS1_M_FNC) != FNC_DVU) {
lp20_update_ready(&lp20_unit, 0, CS1_DVON);
lp20_duvfa_state = 0;
}
break;
case 002: /* LPCSB */
if (access == BYTE) {
if (addr & 1) {
lp20_cs2 &= ~(CS2_TEST);
lp20_cs2 |= data & CS2_TEST;
} else {
lp20_cs2 &= ~(CS2_GOE);
lp20_cs2 |= data & CS2_GOE;
}
} else {
lp20_cs2 &= ~(CS2_TEST|CS2_GOE);
lp20_cs2 |= data & (CS2_TEST|CS2_GOE);
}
break;
case 004: /* LPBA */
lp20_ba = (lp20_ba & 060000) | (data & 0177777);
break;
case 006: /* LPBC */
lp20_wcnt = (data & 0177777);
lp20_cs1 &= ~CS1_DONE;
break;
case 010: /* LPPAGC */
if (access == BYTE) {
if (addr & 1)
data = data | (lp20_pagcnt & 0377);
else
data = (lp20_pagcnt & 0177400) | data;
}
lp20_pagcnt = (data & 0177777);
lp20_cs1 &= ~CS1_PZERO;
break;
case 012: /* LPRDAT */
break;
case 014: /* LPCOL/LPCBUF */
if (access == BYTE) {
if (addr & 1)
lp20_col = (data >> 8) & 0377;
else
lp20_buf = data & 0377;
} else {
lp20_buf = data & 0377;
lp20_col = (data >> 8) & 0377;
}
break;
case 016: /* LPCSUM/LPPDAT */
if (access == BYTE) {
temp = lp20_ram[(int)lp20_buf];
if (addr & 1)
data = data | (temp & 0377);
else
data = (temp & 0177400) | data;
}
lp20_ram[(int)lp20_buf] = data & 07777;
break;
}
lp20_update_chkirq(&lp20_unit, 0, 0);
return 0;
}
int
lp20_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
uint16 temp;
int par;
addr &= dibp->uba_mask;
switch (addr & 016) {
case 000: /* LPCSA */
*data = lp20_cs1;
*data &= ~CS1_UBA;
*data |= (lp20_ba >> 9) & CS1_UBA;
if ((lp20_cs2 & CS2_ERR) != 0)
*data |= CS1_ERR;
break;
case 002: /* LPCSB */
*data = lp20_cs2;
break;
case 004: /* LPBA */
*data = lp20_ba & 0177777;
break;
case 006: /* LPBC */
*data = lp20_wcnt;
break;
case 010: /* LPPAGC */
*data = lp20_pagcnt;
break;
case 012: /* LPRDAT */
temp = lp20_ram[(int)lp20_buf] & 07777;
par = (temp >> 8) ^ (temp >> 4) ^ temp;
par = (par >> 2) ^ par;
par ^= par >> 1;
if ((par & 1) != 0)
temp |= LP20_RAM_RAP;
break;
case 014: /* LPCOL/LPCBUF */
*data = ((uint16)lp20_col) << 8;
*data |= (uint16)lp20_buf;
break;
case 016: /* LPCSUM/LPPDAT */
*data = ((uint16)lp20_chksum) << 8;
*data |= (uint16)lp20_data;
break;
}
sim_debug(DEBUG_DETAIL, dptr, "LP20 read %06o %06o %o\n",
addr, *data, access);
return 0;
}
void
lp20_printline(UNIT *uptr, int nl) {
int trim = 0;
/* Trim off trailing blanks */
while (lp20_col != 0 && lp20_buffer[lp20_col - 1] == ' ') {
lp20_col--;
trim = 1;
}
lp20_buffer[lp20_col] = '\0';
sim_debug(DEBUG_DETAIL, &lp20_dev, "LP output %d %d [%s]\n", lp20_col, nl,
lp20_buffer);
/* Stick a carraige return and linefeed as needed */
if (lp20_col != 0 || trim)
lp20_buffer[lp20_col++] = '\r';
if (nl != 0) {
lp20_buffer[lp20_col++] = '\n';
uptr->LINE++;
}
if (nl > 0 && lp20_vfu[uptr->LINE] == 010000) {
lp20_buffer[lp20_col++] = '\f';
uptr->LINE = 0;
lp20_pagcnt = (lp20_pagcnt - 1) & 07777;
if (lp20_pagcnt == 0)
lp20_cs1 |= CS1_PZERO;
} else if (nl < 0 && uptr->LINE >= (int32)uptr->capac) {
uptr->LINE = 0;
lp20_pagcnt = (lp20_pagcnt - 1) & 07777;
if (lp20_pagcnt == 0)
lp20_cs1 |= CS1_PZERO;
}
sim_fwrite(&lp20_buffer, 1, lp20_col, uptr->fileref);
uptr->pos += lp20_col;
lp20_col = 0;
return;
}
/* Unit service */
void
lp20_output(UNIT *uptr, uint8 c) {
if (c == 0)
return;
lp20_data = c & 0377;
if (lp20_col == 132)
lp20_printline(uptr, 1);
/* Map lower to upper case if uppercase only */
if ((uptr->flags & UNIT_UC) && (c & 0140) == 0140)
c &= 0137;
if (c >= 040 && c < 0177) { /* If printable */
lp20_buffer[lp20_col++] = c;
return;
}
if (c == 012) { /* Line feed? */
lp20_printline(uptr, 1);
} else if (c == 014) { /* Form feed, advance to top of form */
if (lp20_col != 0)
lp20_printline(uptr, 1);
sim_fwrite("\f", 1, 1, uptr->fileref);
uptr->pos += 1;
lp20_col = 0;
uptr->LINE = 0;
} else if (c == 015) { /* Carrage return */
lp20_col = 0;
}
if (c == 011) { /* Tab */
lp20_buffer[lp20_col++] = ' ';
while ((lp20_col & 07) != 0)
lp20_buffer[lp20_col++] = ' ';
}
return;
}
/*
* Check if interrupt should be sent.
* Done set CS1_DONE.
* Irq set interrupt
*/
void
lp20_update_chkirq (UNIT *uptr, int done, int irq)
{
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
if (done)
lp20_cs1 |= CS1_DONE;
if (uptr->flags & UNIT_ATT) {
lp20_cs1 |= CS1_ONL;
lp20_cs2 &= ~(CS2_OFFL|CS2_NRDY);
} else {
lp20_cs1 &= ~(CS1_ONL|CS1_DONE);
lp20_cs2 |= CS2_NRDY|CS2_OFFL;
}
if ((lp20_cs1 & CS1_IE) && (irq || (lp20_cs1 & CS1_DONE)))
uba_set_irq(dibp, dibp->uba_vect);
else
uba_clr_irq(dibp, dibp->uba_vect);
}
/*
* Update ready status of printer.
*/
void
lp20_update_ready(UNIT *uptr, uint16 setrdy, uint16 clrrdy)
{
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
uint16 new_cs1 = (lp20_cs1 | setrdy) & ~clrrdy;
if ((new_cs1 ^ lp20_cs1) & (CS1_ONL|CS1_DVON) && !sim_is_active(uptr)) {
if (new_cs1 & CS1_IE)
uba_set_irq(dibp, dibp->uba_vect);
}
if (new_cs1 & CS1_DVON)
lp20_cs2 &= ~CS2_DVOF;
if (new_cs1 & CS1_ONL)
lp20_cs2 &= ~CS2_OFFL;
else
lp20_cs2 |= CS2_OFFL;
lp20_cs1 = new_cs1;
}
t_stat
lp20_svc (UNIT *uptr)
{
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
char ch;
int fnc = (lp20_cs1 >> CS1_V_FNC) & CS1_M_FNC;
uint16 ram_ch;
uint8 data;
if (fnc == FNC_PRINT && (uptr->flags & UNIT_ATT) == 0) {
lp20_cs1 |= CS1_ERR;
/* Set error */
lp20_cs1 &= ~CS1_GO;
lp20_update_chkirq (uptr, 0, 1);
return SCPE_OK;
}
if (uba_read_npr_byte(lp20_ba, dibp->uba_ctl, &data) == 0) {
lp20_cs2 |= CS2_MTE;
lp20_cs1 &= ~CS1_GO;
lp20_update_chkirq (uptr, 0, 1);
sim_debug(DEBUG_DETAIL, &lp20_dev, "LP npr failed\n");
return SCPE_OK;
}
lp20_buf = data;
lp20_ba = (lp20_ba + 1) & 0777777;
lp20_wcnt = (lp20_wcnt + 1) & 07777;
if (lp20_wcnt == 0) {
lp20_cs1 &= ~CS1_GO;
}
lp20_chksum += lp20_buf;
sim_debug(DEBUG_DETAIL, &lp20_dev, "LP npr %08o %06o %03o %d\n", lp20_ba, lp20_wcnt,
lp20_buf, fnc);
switch(fnc) {
case FNC_PRINT:
ram_ch = lp20_ram[(int)lp20_buf];
/* If previous was delimiter or translation do it */
if (lp20_cs1 & CS1_DHOLD || (ram_ch &(LP20_RAM_DEL|LP20_RAM_TRN)) != 0) {
ch = ram_ch & LP20_RAM_CHR;
lp20_cs1 &= ~CS1_DHOLD;
if (ram_ch & LP20_RAM_DEL)
lp20_cs1 |= CS1_DHOLD;
}
/* Flag if interrupt set */
if (ram_ch & LP20_RAM_INT) {
lp20_cs1 &= ~CS1_GO;
lp20_cs1 |= CS1_UND;
}
/* Check if translate flag set */
if (ram_ch & LP20_RAM_TRN) {
lp20_buf = (uint8)(ram_ch & 0377);
}
/* Check if paper motion */
if (ram_ch & LP20_RAM_PI) {
int lines = 0; /* Number of new lines to output */
/* Print any buffered line */
if (lp20_col != 0)
lp20_printline(uptr, 1);
sim_debug(DEBUG_DETAIL, &lp20_dev, "LP Page Index %02x %04x\n",
lp20_buf, ram_ch);
if ((ram_ch & 020) == 0) { /* Find channel mark in output */
while ((lp20_vfu[uptr->LINE] & (1 << (ram_ch & 017))) == 0) {
sim_debug(DEBUG_DETAIL, &lp20_dev,
"LP skip chan %04x %04x %d\n",
lp20_vfu[uptr->LINE], ram_ch, uptr->LINE);
if (lp20_vfu[uptr->LINE] & 010000) { /* Hit bottom of form */
sim_fwrite("\014", 1, 1, uptr->fileref);
uptr->pos++;
lines = 0;
uptr->LINE = 0;
lp20_pagcnt = (lp20_pagcnt - 1) & 07777;
if (lp20_pagcnt == 0)
lp20_cs1 |= CS1_PZERO;
break;
}
lines++;
uptr->LINE++;
}
} else {
while ((ram_ch & 017) != 0) {
sim_debug(DEBUG_DETAIL, &lp20_dev,
"LP skip line %04x %04x %d\n",
lp20_vfu[uptr->LINE], ram_ch, uptr->LINE);
if (lp20_vfu[uptr->LINE] & 010000) { /* Hit bottom of form */
sim_fwrite("\014", 1, 1, uptr->fileref);
uptr->pos++;
lines = 0;
uptr->LINE = 0;
lp20_pagcnt = (lp20_pagcnt - 1) & 07777;
if (lp20_pagcnt == 0)
lp20_cs1 |= CS1_PZERO;
}
lines++;
uptr->LINE++;
ram_ch--;
}
}
for(;lines > 0; lines--) {
sim_fwrite("\r\n", 1, 2, uptr->fileref);
uptr->pos+=2;
}
} else if (lp20_buf != 0) {
sim_debug(DEBUG_DETAIL, &lp20_dev, "LP print %03o '%c' %04o\n",
lp20_buf, lp20_buf, ram_ch);
lp20_output(uptr, lp20_buf);
}
if (lp20_cs1 & CS1_GO)
sim_activate(uptr, 600);
else
lp20_update_chkirq (uptr, lp20_wcnt == 0, 1);
return SCPE_OK;
case FNC_TEST:
break;
case FNC_DVU:
if ((uptr->flags & UNIT_OPT) != 0) {
lp20_output(uptr, lp20_buf);
break;
}
if (lp20_buf >= 0354 && lp20_buf <= 0356) { /* Start of DVU load */
lp20_duvfa_state = 1;
lp20_index = 0;
lp20_odd = 0;
lp20_cs2 &= ~CS2_DVOF;
} else if (lp20_buf == 0357) { /* Stop DVU load */
lp20_duvfa_state = 0;
lp20_vfu[lp20_index] = 010000;
if (lp20_odd || lp20_index < 12) {
lp20_cs1 &= ~CS1_DVON;
} else {
lp20_cs1 |= CS1_DVON;
}
} else if (lp20_duvfa_state) {
if (lp20_odd) {
lp20_vfu[lp20_index] = (lp20_vfu[lp20_index] & 077) | ((lp20_buf & 077) << 6);
sim_debug(DEBUG_DETAIL, &lp20_dev,
"LP load DFU %d %04x\n", lp20_index, lp20_vfu[lp20_index]);
lp20_index++;
} else {
lp20_vfu[lp20_index] = (lp20_vfu[lp20_index] & 0007700) | (lp20_buf & 077);
}
lp20_odd = !lp20_odd;
}
break;
case FNC_RAM:
if (lp20_odd) {
lp20_ram[lp20_index] = (lp20_ram[lp20_index] & 0377) | ((lp20_buf & 017) << 8);
lp20_index++;
} else {
lp20_ram[lp20_index] = (lp20_ram[lp20_index] & 07400) | (lp20_buf & 0377);
}
lp20_odd = !lp20_odd;
break;
}
if (lp20_cs1 & CS1_GO) {
sim_activate(uptr, 10);
} else {
lp20_update_chkirq (uptr, 1, 1);
}
return SCPE_OK;
}
/* Init routine */
t_stat lp20_init (UNIT *uptr)
{
lp20_cs1 = (lp20_cs1 & CS1_DVON) | CS1_DONE;
lp20_cs2 = lp20_cs2 & (CS2_OFFL|CS2_DVOF);
lp20_col = 0;
lp20_ba = 0;
lp20_wcnt = 0;
lp20_chksum = 0;
sim_cancel (uptr); /* deactivate unit */
lp20_update_chkirq (uptr, 1, 0);
return SCPE_OK;
}
/* Reset routine */
t_stat lp20_reset (DEVICE *dptr)
{
UNIT *uptr = &lp20_unit;
int i;
int par;
lp20_col = 0;
uptr->LINE = 0;
lp20_cs1 = 0;
lp20_cs2 = CS2_OFFL|CS2_DVOF;
lp20_ba = 0;
lp20_wcnt = 0;
/* Clear RAM & VFU */
for (i = 0; i < 256; i++) {
lp20_ram[i] = 0;
lp20_vfu[i] = 0;
}
if ((uptr->flags & UNIT_OPT) != 0) {
/* Load default VFU into VFU */
memcpy(&lp20_vfu, lp20_dvfu, sizeof(lp20_dvfu));
lp20_cs2 |= CS2_OVFU;
lp20_cs2 &= CS2_DVOF;
lp20_cs1 |= CS1_DVON;
}
lp20_ram[012] = LP20_RAM_TRN|LP20_RAM_PI|7; /* Line feed, print line, space one line */
lp20_ram[013] = LP20_RAM_TRN|LP20_RAM_PI|6; /* Vertical tab, Skip mod 20 */
lp20_ram[014] = LP20_RAM_TRN|LP20_RAM_PI|0; /* Form feed, skip to top of page */
lp20_ram[015] = LP20_RAM_TRN|LP20_RAM_PI|020; /* Carrage return */
lp20_ram[020] = LP20_RAM_TRN|LP20_RAM_PI|1; /* Skip half page */
lp20_ram[021] = LP20_RAM_TRN|LP20_RAM_PI|2; /* Skip even lines */
lp20_ram[022] = LP20_RAM_TRN|LP20_RAM_PI|3; /* Skip triple lines */
lp20_ram[023] = LP20_RAM_TRN|LP20_RAM_PI|4; /* Skip one line */
lp20_ram[024] = LP20_RAM_TRN|LP20_RAM_PI|5;
/* Set parity of default RAM */
for (i = 0; i < 256; i++) {
lp20_ram[i] &= ~(LP20_RAM_RAP);
par = (lp20_ram[i] >> 8) ^ (lp20_ram[i] >> 4) ^ (lp20_ram[i]);
par = (par >> 2) ^ par;
par ^= par >> 1;
if ((par & 1) == 0)
lp20_ram[i] |= LP20_RAM_RAP;
}
sim_cancel (uptr); /* deactivate unit */
if (uptr->flags & UNIT_ATT) {
lp20_update_ready(uptr, CS1_ONL, 0);
lp20_update_chkirq (uptr, 1, 0);
}
return SCPE_OK;
}
/* Attach routine */
t_stat lp20_attach (UNIT *uptr, CONST char *cptr)
{
t_stat r;
sim_switches |= SWMASK ('A'); /* Position to EOF */
r = attach_unit (uptr, cptr);
if (r == SCPE_OK) {
lp20_update_ready(uptr, CS1_ONL, 0);
lp20_update_chkirq (uptr, 1, 1);
}
return r;
}
/* Detach routine */
t_stat lp20_detach (UNIT *uptr)
{
sim_cancel (uptr); /* deactivate unit */
lp20_update_ready(uptr, 0, CS1_ONL);
lp20_update_chkirq (uptr, 1, 1);
return detach_unit (uptr);
}
/*
* Line printer routines
*/
t_stat
lp20_setlpp(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
t_value i;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
i = get_uint (cptr, 10, 100, &r);
if (r != SCPE_OK)
return SCPE_ARG;
uptr->capac = (t_addr)i;
uptr->LINE = 0;
return SCPE_OK;
}
t_stat
lp20_getlpp(FILE *st, UNIT *uptr, int32 v, CONST void *desc)
{
if (uptr == NULL)
return SCPE_IERR;
fprintf(st, "linesperpage=%d", uptr->capac);
return SCPE_OK;
}
t_stat lp20_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr)
{
fprintf (st, "Line Printer (LPT)\n\n");
fprintf (st, "The line printer (LPT) writes data to a disk file. \n");
fprintf (st, "The Line printer can be configured to any number of lines per page with the:\n");
fprintf (st, " sim> SET %s LINESPERPAGE=n\n\n", dptr->name);
fprintf (st, "The default is 66 lines per page.\n\n");
fprintf (st, "The LP20 is a unibus device, various parameters can be changed on these devices\n");
fprintf (st, "\n The address of the device can be set with: \n");
fprintf (st, " sim> SET LP20 ADDR=octal default address= 775400\n");
fprintf (st, "\n The interrupt vector can be set with: \n");
fprintf (st, " sim> SET LP20 VECT=octal default 754\n");
fprintf (st, "\n The interrupt level can be set with: \n");
fprintf (st, " sim> SET LP20 BR=# # should be between 4 and 7.\n");
fprintf (st, "\n The unibus addaptor that the DZ is on can be set with:\n");
fprintf (st, " sim> SET LP20 CTL=# # can be either 1 or 3\n");
fprint_set_help (st, dptr);
fprint_show_help (st, dptr);
fprint_reg_help (st, dptr);
return SCPE_OK;
}
const char *lp20_description (DEVICE *dptr)
{
return "LP20 line printer" ;
}
#endif

137
PDP10/ks10_tcu.c Normal file
View file

@ -0,0 +1,137 @@
/* ks10_tcu.c: PDP-10
Copyright (c) 2021, 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 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.
*/
#include "kx10_defs.h"
#include "sim_sock.h"
#include "sim_tmxr.h"
#ifndef NUM_DEVS_TCU
#define NUM_DEVS_TCU 0
#endif
#if (NUM_DEVS_TCU > 0)
#define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */
#define UNIT_Y2K (1u << UNIT_V_Y2K)
int tcu_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int tcu_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
t_stat tcu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr);
const char *tcu_description (DEVICE *dptr);
DIB tcu_dib = { 0760770, 07, 0, 0, 3, &tcu_read, &tcu_write, NULL, 0, 0 };
UNIT tcu_unit = {UDATA (NULL, UNIT_IDLE+UNIT_DISABLE, 0)};
MTAB tcu_mod[] = {
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of TCU" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of TCU" },
{ UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },
{ UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },
{ 0 }
};
DEVICE tcu_dev = {
"TIM", &tcu_unit, NULL, tcu_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, NULL, NULL, NULL, NULL,
&tcu_dib, DEV_DISABLE | DEV_DEBUG, 0, dev_debug,
NULL, NULL, &tcu_help, NULL, NULL, &tcu_description
};
/* Time can't be set in device */
int
tcu_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
{
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
return 0;
}
/* Read current time of day */
int
tcu_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
time_t curtim;
struct tm *tptr;
if ((dptr->units[0].flags & UNIT_DIS) != 0)
return 1;
/* Get time */
curtim = sim_get_time (NULL);
tptr = localtime (&curtim);
if (tptr == NULL)
return 0;
if ((tptr->tm_year > 99) && !(dptr->units[0].flags & UNIT_Y2K))
tptr->tm_year = 99; /* Y2K prob? */
switch (addr & 06) {
case 0: /* year/month/day */
*data = (((tptr->tm_year) & 0177) << 9) |
(((tptr->tm_mon + 1) & 017) << 5) |
((tptr->tm_mday) & 037);
break;
case 2: /* hour/minute */
*data = (((tptr->tm_hour) & 037) << 8) |
((tptr->tm_min) & 077);
break;
case 4: /* second */
*data = (tptr->tm_sec) & 077;
break;
case 6: /* status */
*data = 0200;
break;
}
sim_debug(DEBUG_DETAIL, dptr, "TCU read %06o %06o %o\n",
addr, *data, access);
return 0;
}
t_stat tcu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
return SCPE_OK;
}
const char *tcu_description (DEVICE *dptr)
{
return "TCU150 Time of day clock";
}
#endif

586
PDP10/ks10_uba.c Normal file
View file

@ -0,0 +1,586 @@
/* ks10_uba.c: KS10 Unibus interface
Copyright (c) 2021, 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 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.
*/
#include "kx10_defs.h"
/* UBA Map as stored */
#define PAGE_MASK 000003777000 /* Page mask bits, bits 25-36 on load */
#define MAP_RPV 000400000000 /* Ram parity valid bit */
#define MAP_VALID 001000000000 /* Page valid */
#define MAP_FME 002000000000 /* Fast Mode enable */
#define MAP_EN16 004000000000 /* Disable upper 2 bits UBA */
#define MAP_RPW 010000000000 /* For Read Pause Write */
#define MAP_RAMP 020000000000 /* Parity error in RAM */
/* UBA Stats register */
#define UBST_PIL 000000000007 /* Low level PIA */
#define UBST_PIH 000000000070 /* High level PIA */
#define UBST_INIT 000000000100 /* Initialize UBA */
#define UBST_DXFR 000000000200 /* Disable transfer on uncorrectable */
#define UBST_PWRL 000000001000 /* Power low */
#define UBST_INTL 000000002000 /* Interrupt on Br5 or Br4 */
#define UBST_INTH 000000004000 /* INterrupt on Br7 or Br6 */
#define UBST_NED 000000040000 /* Non-existant device */
#define UBST_PAR 000000100000 /* Parity error */
#define UBST_BAD 000000200000 /* Bad mem transfer */
#define UBST_TIM 000000400000 /* UBA Timout */
#define VECT_L 0x10
#define VECT_H 0x20
#define VECT_CTR 0x0F
uint32 uba_map[2][64];
uint32 uba_status[2];
int uba_device[16] = { -1, 0, -1, 1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 };
int uba_irq_ctlr[128];
int
uba_read(t_addr addr, int ctl, uint64 *data, int access)
{
DEVICE *dptr;
int i;
int ubm = uba_device[ctl];
if (ctl == 0 && addr == 0100000) {
*data = 0;
return 0;
}
if (ubm == -1) {
sim_debug(DEBUG_EXP, &cpu_dev, "No UBA adaptor %02o %08o\n", ctl, addr);
return 1;
}
/* Check if in UBA map */
if ((addr & 0777600) == 0763000) {
if ((addr & 0100) == 0) {
*data = (uint64)uba_map[ubm][addr & 077];
return 0;
} else if ((addr & 077) == 0) {
int pih, pil;
int irqf = 0;
*data = (uint64)uba_status[ubm];
pih = 0200 >> ((uba_status[ubm] >> 3) & 07);
pil = 0200 >> (uba_status[ubm] & 07);
for (i = 0; i < 128; i++) {
if ((uba_irq_ctlr[i] & VECT_CTR) == ctl)
irqf |= uba_irq_ctlr[i];
}
*data |= (irqf & (VECT_L|VECT_H)) << 6;
return 0;
} else if ((addr & 077) == 1) {
*data = 0;
return 0;
}
*data = 0;
uba_status[ubm] |= UBST_TIM | UBST_NED;
return 1;
}
/* Look for device */
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
if (ctl == dibp->uba_ctl &&
dibp->uba_addr == (addr & (~dibp->uba_mask))) {
uint16 buf;
int r = dibp->rd_io(dptr, addr, &buf, access);
if (r)
break;
if (access == BYTE) {
if ((addr & 1) != 0)
buf >>= 8;
buf &= 0377;
}
*data = (uint64)buf;
return r;
}
}
sim_debug(DEBUG_EXP, &cpu_dev, "No UBA device %02o %08o\n", ctl, addr);
*data = 0;
uba_status[ubm] |= UBST_TIM | UBST_NED;
return 1;
}
int
uba_write(t_addr addr, int ctl, uint64 data, int access)
{
DEVICE *dptr;
int i;
int ubm = uba_device[ctl];
if (ctl == 0 && addr == 0100000) {
return 1;
}
if (ubm == -1) {
sim_debug(DEBUG_EXP, &cpu_dev, "No UBA adaptor %02o %08o %012llo\n", ctl, addr, data);
return 1;
}
sim_debug(DEBUG_EXP, &cpu_dev, "UBA device write %02o %08o %012llo %d\n", ctl, addr, data, access);
if (access == BYTE) {
if ((addr & 1) != 0)
data = (data & 0377) << 8;
else
data = (data & 0377);
}
/* Check if in UBA map */
if ((addr & 0777400) == 0763000) {
if ((addr & 0100) == 0) {
uint32 map = (uint32)(data & 03777) << 9;
map |= (uint32)(data & 0740000) << 13;
uba_map[ubm][addr & 077] = map;
sim_debug(DEBUG_EXP, &cpu_dev, "Wr MAP %02o %012llo %06o\n",
addr & 077, data, map);
return 0;
} else if ((addr & 077) == 0) {
uba_status[ubm] &= (uint32)(074000 ^ data) | 0746000;
if (data & 0100) {
uba_status[ubm] = 0;
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
if (ctl == dibp->uba_ctl && dptr->reset != NULL)
(void)(dptr->reset)(dptr);
}
}
for (i = 0; i < 128; i++) {
if ((uba_irq_ctlr[i] & VECT_CTR) == ctl) {
uba_irq_ctlr[i] = 0;
clr_interrupt(i << 2);
}
}
uba_status[ubm] |= (uint32)(0277 & data);
return 0;
} else if ((addr & 077) == 1) {
return 0;
}
uba_status[ubm] |= UBST_TIM | UBST_NED;
return 1;
}
/* Look for device */
for(i = 0; (dptr = sim_devices[i]) != NULL; i++) {
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
continue;
if (ctl == dibp->uba_ctl && dibp->uba_addr == (addr & (~dibp->uba_mask))) {
uint16 buf = (uint16)(data & 0177777);
int r = dibp->wr_io(dptr, addr, buf, access);
sim_debug(DEBUG_EXP, &cpu_dev, "UBA device write %02o %08o %012llo %06o\n", ctl, addr, data, buf);
if (r)
break;
return r;
}
}
sim_debug(DEBUG_EXP, &cpu_dev, "No UBA device write %02o %08o %012llo\n", ctl, addr, data);
uba_status[ubm] |= UBST_TIM | UBST_NED;
return 1;
}
int
uba_read_npr(t_addr addr, uint16 ctl, uint64 *data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
*data = M[addr];
return 1;
}
int
uba_write_npr(t_addr addr, uint16 ctl, uint64 data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
t_addr oaddr = addr;
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
sim_debug(DEBUG_DATA, &cpu_dev, "Wr NPR %08o %08o %012llo\n", oaddr, addr, data);
M[addr] = data;
return 1;
}
int
uba_read_npr_byte(t_addr addr, uint16 ctl, uint8 *data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
t_addr oaddr = addr;
uint64 wd;
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
wd = M[addr];
sim_debug(DEBUG_DATA, &kmc_dev, "RD NPR B %08o %08o %012llo ", oaddr, addr, wd);
if ((oaddr & 02) == 0)
wd >>= 18;
if ((oaddr & 01))
wd >>= 8;
sim_debug(DEBUG_DATA, &kmc_dev, "%03llo\n", wd & 0377);
*data = (uint8)(wd & 0377);
return 1;
}
int
uba_write_npr_byte(t_addr addr, uint16 ctl, uint8 data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
t_addr oaddr = addr;
uint64 wd;
uint64 msk;
uint64 buf;
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
msk = 0377;
buf = (uint64)(data & msk);
wd = M[addr];
sim_debug(DEBUG_DATA, &kmc_dev, "WR NPR B %08o %08o %012llo ", oaddr, addr, wd);
if ((oaddr & 02) == 0) {
buf <<= 18;
msk <<= 18;
}
if ((oaddr & 01)) {
buf <<= 8;
msk <<= 8;
}
wd &= ~msk;
wd |= buf;
M[addr] = wd;
sim_debug(DEBUG_DATA, &kmc_dev, "%012llo\n", wd);
return 1;
}
int
uba_read_npr_word(t_addr addr, uint16 ctl, uint16 *data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
t_addr oaddr = addr;
uint64 wd;
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
wd = M[addr];
sim_debug(DEBUG_EXP, &cpu_dev, "RD NPR W %08o %08o %012llo m=%o\n", oaddr, addr, wd, map);
if ((oaddr & 02) == 0)
wd >>= 18;
*data = (uint16)(wd & 0177777);
return 1;
}
int
uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data)
{
int ubm = uba_device[ctl];
uint32 map = uba_map[ubm][(077) & (addr >> 11)];
t_addr oaddr = addr;
uint64 wd;
uint64 msk;
uint64 buf;
if ((addr & 0400000) != 0)
return 0;
if ((map & MAP_VALID) == 0)
return 0;
addr = (map & PAGE_MASK) | (addr >> 2) & 0777;
msk = 0177777;
buf = (uint64)(data & msk);
wd = M[addr];
sim_debug(DEBUG_EXP, &cpu_dev, "WR NPR W %08o %08o %012llo m=%o\n", oaddr, addr, wd, map);
if ((oaddr & 02) == 0) {
buf <<= 18;
msk <<= 18;
}
wd &= ~msk;
wd |= buf;
M[addr] = wd;
return 1;
}
void
uba_set_irq(DIB *dibp, int vect)
{
int ubm = uba_device[dibp->uba_ctl];
int pi;
int flg;
if (ubm < 0)
return;
/* Figure out what channel device should IRQ on */
if (dibp->uba_br > 5) {
pi = uba_status[ubm] >> 3;
flg = VECT_H;
} else {
pi = uba_status[ubm];
flg = VECT_L;
}
sim_debug(DEBUG_IRQ, &cpu_dev, "set uba irq %06o %03o %o pi=%o\n",
dibp->uba_addr, vect, dibp->uba_br, pi);
/* Save in device temp the irq value */
set_interrupt(vect, pi);
uba_irq_ctlr[vect >> 2] = flg | dibp->uba_ctl;
}
void
uba_clr_irq(DIB *idev, int vect)
{
int ubm = uba_device[idev->uba_ctl];
if (ubm < 0)
return;
sim_debug(DEBUG_IRQ, &cpu_dev, "clr uba irq %06o %03o %o\n",
idev->uba_addr, vect, idev->uba_br);
clr_interrupt(vect);
uba_irq_ctlr[vect >> 2] = 0;
}
void
uba_reset()
{
int i;
/* Clear the Unibus map */
for (i = 0; i < 64; i++) {
uba_map[0][i] = 0;
uba_map[1][i] = 0;
}
uba_status[0] = 0;
uba_status[1] = 0;
for (i = 0; i < 128; i++)
uba_irq_ctlr[i] = 0;
}
t_addr
uba_get_vect(t_addr addr, int lvl, int dev)
{
uint64 buffer;
int ubm;
ubm = uba_irq_ctlr[dev];
if (ubm != 0) {
/* Fetch vector base */
ubm &= VECT_CTR;
if (Mem_read_word(0100 | ubm, &buffer, 1))
return addr;
/* Compute unibus vector */
addr = (buffer + dev) & RMASK;
sim_debug(DEBUG_IRQ, &cpu_dev, "get_vect d=%03o l=%03o ir=%02o v=%012llo\n",
dev << 2, lvl, uba_irq_ctlr[dev], buffer);
uba_irq_ctlr[dev] = 0;
}
return addr;
}
void
uba_set_parity(uint16 ctl)
{
int ubm = uba_device[ctl];
if (ubm >= 0)
uba_status[ubm] |= UBST_PAR;
}
t_stat
uba_set_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value newaddr;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
newaddr = get_uint (cptr, 18, 0777777, &r);
if (r != SCPE_OK)
return r;
dibp->uba_addr = (uint32)(newaddr & RMASK);
return SCPE_OK;
}
t_stat
uba_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr = find_dev_from_unit(uptr);
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
fprintf(st, "addr=%07o", dibp->uba_addr);
return SCPE_OK;
}
t_stat
uba_set_br(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value br;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
br = get_uint (cptr, 3, 07, &r);
if (r != SCPE_OK)
return r;
if (br < 4 || br > 7)
return SCPE_ARG;
dibp->uba_br = (uint16)br;
return SCPE_OK;
}
t_stat
uba_show_br (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr = find_dev_from_unit(uptr);
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
fprintf(st, "br=%o", dibp->uba_br);
return SCPE_OK;
}
t_stat
uba_set_vect(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value vect;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
vect = get_uint (cptr, 8, 0377, &r);
if (r != SCPE_OK)
return r;
dibp->uba_vect = (uint16)vect;
return SCPE_OK;
}
t_stat
uba_show_vect (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr = find_dev_from_unit(uptr);
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
fprintf(st, "vect=%03o", dibp->uba_vect);
return SCPE_OK;
}
t_stat
uba_set_ctl(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value ctl;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
ctl = get_uint (cptr, 4, 017, &r);
if (r != SCPE_OK)
return r;
if (ctl != 1 && ctl != 3)
return SCPE_ARG;
dibp->uba_ctl = (uint16)ctl;
return SCPE_OK;
}
t_stat
uba_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr = find_dev_from_unit(uptr);
DIB *dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
fprintf(st, "uba%o", dibp->uba_ctl);
return SCPE_OK;
}

File diff suppressed because it is too large Load diff

View file

@ -50,11 +50,15 @@
#define KL 0 #define KL 0
#endif #endif
#ifndef KS
#define KS 0
#endif
#if KL #if KL
#define EPT440 0 /* Force KL10 to use as 440 section address */ #define EPT440 0 /* Force KL10 to use as 440 section address */
#endif #endif
#if (PDP6 + KA + KI + KL) != 1 #if (PDP6 + KA + KI + KL + KS) != 1
#error "Please define only one type of CPU" #error "Please define only one type of CPU"
#endif #endif
@ -82,6 +86,11 @@
#define KL_ITS KL #define KL_ITS KL
#endif #endif
/* Support for ITS on KS */
#ifndef KS_ITS
#define KS_ITS KS
#endif
#ifndef PDP6_DEV /* Include PDP6 devices */ #ifndef PDP6_DEV /* Include PDP6 devices */
#define PDP6_DEV PDP6|WAITS #define PDP6_DEV PDP6|WAITS
#endif #endif
@ -195,6 +204,30 @@ extern DEBTAB crd_debug[];
#define FPMMASK 00000000000077777777777LL #define FPMMASK 00000000000077777777777LL
#define FPRBIT2 00000000000100000000000LL #define FPRBIT2 00000000000100000000000LL
#define FPRBIT1 00000000000200000000000LL #define FPRBIT1 00000000000200000000000LL
#if KS
#define IOCTL 00000017000000LL
#endif
/* IRQ Flags in APR */
#if KL
#define SWP_DONE 0000020 /* Cache sweep done */
#define PFAIL 0000040 /* Power failure */
#define ADDR_PAR 0000100 /* Address Parity error */
#define CACHE_DIR 0000200 /* Cache Parity error */
#define MB_PAR 0000400 /* Memory parity error */
#define INOUT_FAIL 0001000 /* Fault during IRQ */
#define NXM_MEM 0002000 /* Non-existent memory */
#define SBUS_ERR 0004000 /* SBus Error */
#endif
#if KS
#define CON_IRQ 0000020 /* Interrupt from Console */
#define INT_DONE 0000040 /* Interval timer complete */
#define COR_MEM 0000100 /* Corrected memory error */
#define MB_ERR 0000200 /* Uncorrectable memory error */
#define NXM_MEM 0000400 /* No memory */
#define PFAIL 0001000 /* Power Failure */
#define FLAG_24 0004000 /* Spare */
#endif
#define CM(x) (FMASK ^ (x)) #define CM(x) (FMASK ^ (x))
#define CCM(x) ((CMASK ^ (x)) & CMASK) #define CCM(x) ((CMASK ^ (x)) & CMASK)
@ -231,12 +264,16 @@ extern DEBTAB crd_debug[];
#define NODIV 000001 /* 000040 */ #define NODIV 000001 /* 000040 */
#define FLTUND 000002 /* 000100 */ #define FLTUND 000002 /* 000100 */
#endif #endif
#if KI|KL #if KI|KL|KS
#define TRP1 000004 /* 000200 */ #define TRP1 000004 /* 000200 */
#define TRP2 000010 /* 000400 */ #define TRP2 000010 /* 000400 */
#define ADRFLT 000020 /* 001000 */ #define ADRFLT 000020 /* 001000 */
#if KI | KL
#define PUBLIC 000040 /* 002000 */ #define PUBLIC 000040 /* 002000 */
#else #else
#define PUBLIC 000000 /* 000000 */
#endif
#else
#define TRP1 000000 #define TRP1 000000
#define TRP2 000000 #define TRP2 000000
#define ADRFLT 000000 #define ADRFLT 000000
@ -261,7 +298,7 @@ extern DEBTAB crd_debug[];
#if KI|KL #if KI|KL
#define PRV_PUB 020000 /* Overflow in excutive mode */ #define PRV_PUB 020000 /* Overflow in excutive mode */
#else #else
#define PRV_PUB 000000 /* Not on KA or PDP6 */ #define PRV_PUB 000000 /* Not on KA, KS or PDP6 */
#endif #endif
#ifdef ITS #ifdef ITS
#ifdef PURE #ifdef PURE
@ -280,13 +317,13 @@ extern DEBTAB crd_debug[];
#if KI_22BIT|KI #if KI_22BIT|KI
#define MAXMEMSIZE 4096 * 1024 #define MAXMEMSIZE 4096 * 1024
#else #elif PDP6
#if PDP6
#define MAXMEMSIZE 256 * 1024 #define MAXMEMSIZE 256 * 1024
#elif KS
#define MAXMEMSIZE 1024 * 1024
#else #else
#define MAXMEMSIZE 1024 * 1024 #define MAXMEMSIZE 1024 * 1024
#endif #endif
#endif
#define MEMSIZE (cpu_unit[0].capac) #define MEMSIZE (cpu_unit[0].capac)
#define ICWA 0000000000776 #define ICWA 0000000000776
@ -323,6 +360,10 @@ extern DEBTAB crd_debug[];
#define DEF_SERIAL 1025 /* Default DEC test machine */ #define DEF_SERIAL 1025 /* Default DEC test machine */
#endif #endif
#if KS
#define DEF_SERIAL 4097 /* Default DEC test machine */
#endif
#if BBN #if BBN
#define BBN_PAGE 0000017777777LL #define BBN_PAGE 0000017777777LL
#define BBN_TRPPG 0000017000000LL #define BBN_TRPPG 0000017000000LL
@ -339,7 +380,7 @@ extern DEBTAB crd_debug[];
#define BBN_MERGE 0161740000000LL #define BBN_MERGE 0161740000000LL
#endif #endif
#if KL #if KL|KS
/* KL10 TLB paging bits */ /* KL10 TLB paging bits */
#define KL_PAG_A 0400000 /* Access */ #define KL_PAG_A 0400000 /* Access */
#define KL_PAG_P 0200000 /* Public */ #define KL_PAG_P 0200000 /* Public */
@ -367,7 +408,11 @@ extern DEBTAB crd_debug[];
#define UNIT_KL10B (1 << UNIT_V_PAGE) #define UNIT_KL10B (1 << UNIT_V_PAGE)
#define UNIT_TWOSEG (0) #define UNIT_TWOSEG (0)
#else #else
#if KA
#define UNIT_TWOSEG (1 << UNIT_V_PAGE) #define UNIT_TWOSEG (1 << UNIT_V_PAGE)
#else
#define UNIT_TWOSEG (0)
#endif
#endif #endif
#define UNIT_ITSPAGE (2 << UNIT_V_PAGE) #define UNIT_ITSPAGE (2 << UNIT_V_PAGE)
#define UNIT_BBNPAGE (4 << UNIT_V_PAGE) #define UNIT_BBNPAGE (4 << UNIT_V_PAGE)
@ -415,6 +460,10 @@ extern void restore_pi_hold();
extern void set_pi_hold(); extern void set_pi_hold();
extern UNIT cpu_unit[]; extern UNIT cpu_unit[];
extern UNIT ten11_unit[]; extern UNIT ten11_unit[];
#if KS
extern DEVICE lp20_dev;
extern DEVICE ch11_dev;
#endif
#if KL #if KL
extern DEVICE dte_dev; extern DEVICE dte_dev;
extern DEVICE lp20_dev; extern DEVICE lp20_dev;
@ -462,15 +511,104 @@ extern DEVICE dkb_dev;
extern DEVICE auxcpu_dev; extern DEVICE auxcpu_dev;
extern DEVICE slave_dev; extern DEVICE slave_dev;
extern DEVICE dpk_dev; extern DEVICE dpk_dev;
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;
extern DEVICE dsk_dev; extern DEVICE dsk_dev;
extern DEVICE dcs_dev; extern DEVICE dcs_dev;
extern DEVICE dz_dev;
extern DEVICE kmc_dev;
extern DEVICE dup_dev;
extern DEVICE tcu_dev;
#if KS
struct rh_if {
int (*dev_write)(DEVICE *dptr, struct rh_if *rh, int reg, uint32 data);
int (*dev_read)(DEVICE *dptr, struct rh_if *rh, int reg, uint32 *data);
void (*dev_reset)(DEVICE *dptr);
struct pdp_dib *dib; /* Pointer back to DIB */
int drive; /* Last drive selected */
t_uint64 buf; /* Data buffer */
uint32 status; /* Status word */
uint16 cs1; /* Control register 1 */
uint16 cs2; /* Control register 1 */
uint16 error; /* Controller Error register */
uint32 wcr; /* Current word count */
uint32 cda; /* Current bus address */
uint16 dba; /* Input data buffer */
uint16 dbb; /* Output data buffer*/
int rae; /* Access register error */
int attn; /* Attention bits */
int xfer_drive; /* Current transfering drive */
uint16 regs[16]; /* Space for TM03 formater */
};
/* Device context block */
struct pdp_dib {
uint32 uba_addr; /* device address, includes adaptor */
uint32 uba_mask; /* Compare mask */
uint16 uba_vect; /* Floating IRQ vector */
uint16 uba_br; /* Unibus IRQ level */
uint16 uba_ctl; /* Unibus controller number */
t_stat (*rd_io)(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
t_stat (*wr_io)(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
uint16 (*irqv)(struct pdp_dib *dibp);
uint8 uba_irq_pend; /* Device has pending */
struct rh_if *rh11_if;
};
typedef struct pdp_dib DIB;
void cty_wakeup();
void cty_interrupt();
void cty_execute(int addr);
t_stat cty_reset (DEVICE *dptr);
#define WORD 0
#define BYTE 1
int uba_read(t_addr addr, int ctl, uint64 *data, int access);
int uba_write(t_addr addr, int ctl, uint64 data, int access);
int uba_read_npr(t_addr addr, uint16 ctl, uint64 *data);
int uba_write_npr(t_addr addr, uint16 ctl, uint64 data);
int uba_read_npr_byte(t_addr addr, uint16 ctl, uint8 *data);
int uba_write_npr_byte(t_addr addr, uint16 ctl, uint8 data);
int uba_read_npr_word(t_addr addr, uint16 ctl, uint16 *data);
int uba_write_npr_word(t_addr addr, uint16 ctl, uint16 data);
void uba_set_irq(DIB *dibp, int vect);
void uba_clr_irq(DIB *dibp, int vect);
t_addr uba_get_vect(t_addr addr, int lvl, int dev);
void uba_set_parity(uint16 ctl);
uint16 uba_rh_vect(struct pdp_dib *dibp);
int uba_rh_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
int uba_rh_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
void uba_reset();
t_stat uba_set_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat uba_show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat uba_set_br(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat uba_show_br (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat uba_set_vect(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat uba_show_vect (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat uba_set_ctl(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat uba_show_ctl (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
void rh_reset(DEVICE *dptr, struct rh_if *rh);
void rh_setup(struct rh_if *rh, uint32 addr);
void rh_setattn(struct rh_if *rh, int unit);
void rh_error(struct rh_if *rh);
int rh_blkend(struct rh_if *rh);
void rh_setirq(struct rh_if *rh);
void rh_writecw(struct rh_if *rh, int nxm);
void rh_finish_op(struct rh_if *rh, int flags);
int rh_read(struct rh_if *rh);
int rh_write(struct rh_if *rh);
#else
extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data); extern t_stat (*dev_tab[128])(uint32 dev, t_uint64 *data);
#define VEC_DEVMAX 8 /* max device vec */ #define VEC_DEVMAX 8 /* max device vec */
@ -512,6 +650,7 @@ struct rh_if {
int rae; /* Access register error */ int rae; /* Access register error */
int attn; /* Attention bits */ int attn; /* Attention bits */
int xfer_drive; /* Current transfering drive */ int xfer_drive; /* Current transfering drive */
uint16 regs[16]; /* Space for TM03 formater */
}; };
/* Device context block */ /* Device context block */
@ -551,6 +690,7 @@ t_stat rh_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat rh_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat rh_show_type (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat rh_devio(uint32 dev, t_uint64 *data); t_stat rh_devio(uint32 dev, t_uint64 *data);
t_addr rh_devirq(uint32 dev, t_addr addr); t_addr rh_devirq(uint32 dev, t_addr addr);
void rh_reset(DEVICE *dptr, struct rh_if *rh);
#if KL #if KL
void rh20_setup(struct rh_if *rhc); void rh20_setup(struct rh_if *rhc);
#endif #endif
@ -565,23 +705,18 @@ int rh_read(struct rh_if *rh);
int rh_write(struct rh_if *rh); int rh_write(struct rh_if *rh);
int ten11_read (t_addr addr, t_uint64 *data);
int ten11_write (t_addr addr, t_uint64 data);
/* Console lights. */ /* Console lights. */
extern void ka10_lights_init (void); extern void ka10_lights_init (void);
extern void ka10_lights_main (t_uint64); extern void ka10_lights_main (t_uint64);
extern void ka10_lights_set_aux (int); extern void ka10_lights_set_aux (int);
extern void ka10_lights_clear_aux (int); extern void ka10_lights_clear_aux (int);
#endif
/* I/O system parameters */ /* I/O system parameters */
#if !(PDP6 | KS)
#define NUM_DEVS_LP 1 #define NUM_DEVS_LP 1
#if KL #endif
#define NUM_DEVS_PT 0 #if !(KL | KS)
#define NUM_DEVS_CR 0
#define NUM_DEVS_CP 0
#else
#define NUM_DEVS_PT 1 #define NUM_DEVS_PT 1
#define NUM_DEVS_CR 1 #define NUM_DEVS_CR 1
#define NUM_DEVS_CP 1 #define NUM_DEVS_CP 1
@ -597,34 +732,48 @@ extern void ka10_lights_clear_aux (int);
#define NUM_DEVS_DCS 1 #define NUM_DEVS_DCS 1
#define NUM_DEVS_SLAVE PDP6 #define NUM_DEVS_SLAVE PDP6
#endif #endif
#if !PDP6 #if !(PDP6 | KS)
#define NUM_DEVS_DC 1 #define NUM_DEVS_DC 1
#define NUM_DEVS_MT 1 #define NUM_DEVS_MT 1
#endif
#if KL #if KL
#define NUM_DEVS_RC 0
#define NUM_DEVS_DT 0
#define NUM_DEVS_DK 0
#define NUM_DEVS_DP 0
#define NUM_DEVS_LP20 1 #define NUM_DEVS_LP20 1
#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
#else #define NUM_DEVS_DN 0
#elif KS
#define NUM_DEVS_LP20 1
#define NUM_DEVS_DZ 4
#define NUM_DEVS_TCU 1
#define NUM_DEVS_DUP 2
#define NUM_DEVS_KMC 2
#if KS_ITS
#define NUM_DEVS_IMP KS_ITS
#define NUM_DEVS_CH11 KS_ITS
#endif
#endif
#if KA | KI
#define NUM_DEVS_RC 1 #define NUM_DEVS_RC 1
#define NUM_DEVS_DT 1 #define NUM_DEVS_DT 1
#define NUM_DEVS_DK 1 #define NUM_DEVS_DK 1
#define NUM_DEVS_DP 2 #define NUM_DEVS_DP 2
#define NUM_DEVS_LP20 0
#define NUM_DEVS_TTY 0
#define NUM_DEVS_NIA 0
#endif #endif
#if KS
#define NUM_DEVS_RP 1
#elif KA | KI | KL
#define NUM_DEVS_RP 4 #define NUM_DEVS_RP 4
#define NUM_DEVS_RS 1 #define NUM_DEVS_RS 1
#endif
#if !(PDP6)
#define NUM_DEVS_TU 1 #define NUM_DEVS_TU 1
#endif
#if KA
#define NUM_DEVS_PMP WAITS #define NUM_DEVS_PMP WAITS
#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_PD ITS | KL_ITS #define NUM_DEVS_TV (WAITS * USE_DISPLAY)
#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
#define NUM_DEVS_STK ITS #define NUM_DEVS_STK ITS
@ -632,11 +781,16 @@ extern void ka10_lights_clear_aux (int);
#define NUM_DEVS_MTY ITS #define NUM_DEVS_MTY ITS
#define NUM_DEVS_TEN11 ITS #define NUM_DEVS_TEN11 ITS
#define NUM_DEVS_AUXCPU ITS #define NUM_DEVS_AUXCPU ITS
#define NUM_DEVS_IMP 1 #define NUM_DEVS_IMP ITS
#define NUM_DEVS_CH10 ITS | KL_ITS #define NUM_DEVS_CH10 ITS
#define NUM_DEVS_DPK ITS #define NUM_DEVS_DPK ITS
#define NUM_DEVS_AI ITS #define NUM_DEVS_AI ITS
#endif #endif
#if KL_ITS
#define NUM_DEVS_PD KL_ITS
#define NUM_DEVS_IMP KL_ITS
#define NUM_DEVS_CH10 KL_ITS
#endif
#if MAGIC_SWITCH && !KA && !ITS #if MAGIC_SWITCH && !KA && !ITS
#error "Magic switch only valid on KA10 with ITS mods" #error "Magic switch only valid on KA10 with ITS mods"
#endif #endif
@ -645,12 +799,20 @@ extern void ka10_lights_clear_aux (int);
extern t_bool sim_idle_enab; extern t_bool sim_idle_enab;
#if !KS
extern struct rh_dev rh[]; extern struct rh_dev rh[];
#endif
extern t_uint64 M[MAXMEMSIZE]; extern t_uint64 M[MAXMEMSIZE];
extern t_uint64 FM[]; extern t_uint64 FM[];
extern uint32 PC; extern uint32 PC;
extern uint32 FLAGS; extern uint32 FLAGS;
#if NUM_DEVS_TEN11
int ten11_read (t_addr addr, t_uint64 *data);
int ten11_write (t_addr addr, t_uint64 data);
extern t_addr ten11_base;
extern t_addr ten11_end;
#endif
#if NUM_DEVS_AUXCPU #if NUM_DEVS_AUXCPU
extern t_addr auxcpu_base; extern t_addr auxcpu_base;
int auxcpu_read (t_addr addr, uint64 *); int auxcpu_read (t_addr addr, uint64 *);

View file

@ -24,7 +24,7 @@
/* Flags in the unit flags word */ /* Flags in the unit flags word */
#define UNIT_V_FMT (UNIT_V_UF + 8) #define UNIT_V_FMT (UNIT_V_UF + 7)
#define UNIT_M_FMT 7 #define UNIT_M_FMT 7
#define GET_FMT(x) (((x) >> UNIT_V_FMT) & UNIT_M_FMT) #define GET_FMT(x) (((x) >> UNIT_V_FMT) & UNIT_M_FMT)
#define SET_FMT(x) (((x) & UNIT_M_FMT) << UNIT_V_FMT) #define SET_FMT(x) (((x) & UNIT_M_FMT) << UNIT_V_FMT)

View file

@ -717,7 +717,7 @@ t_stat dp_svc (UNIT *uptr)
CLR_BUF(uptr); CLR_BUF(uptr);
} }
if (r) if (r)
sim_activate(uptr, 40); sim_activate(uptr, 25);
else { else {
uptr->STATUS &= ~(SRC_DONE|END_CYL|BUSY); uptr->STATUS &= ~(SRC_DONE|END_CYL|BUSY);
uptr->UFLAGS |= DONE; uptr->UFLAGS |= DONE;

View file

@ -109,6 +109,7 @@
#include "kx10_defs.h" #include "kx10_defs.h"
#include "sim_video.h" #include "sim_video.h"
#include <math.h>
#ifndef NUM_DEVS_DPY #ifndef NUM_DEVS_DPY
#define NUM_DEVS_DPY 0 #define NUM_DEVS_DPY 0
@ -120,6 +121,8 @@
#define DPY_DEVNUM 0130 #define DPY_DEVNUM 0130
#define FULLSCREEN (1 << (UNIT_V_UF))
#define RRZ(W) ((W) & RMASK) #define RRZ(W) ((W) & RMASK)
#define XWD(L,R) ((((uint64)(L))<<18)|((uint64)(R))) #define XWD(L,R) ((((uint64)(L))<<18)|((uint64)(R)))
@ -187,12 +190,20 @@ UNIT dpy_unit[] = {
#define UPTR(UNIT) (dpy_unit+(UNIT)) #define UPTR(UNIT) (dpy_unit+(UNIT))
MTAB dpy_mod[] = {
{ FULLSCREEN, FULLSCREEN, "FULLSCREEN", "FULLSCREEN", NULL, NULL, NULL,
"Display in fullscreen"},
{ FULLSCREEN, 0, NULL, "WINDOW", NULL, NULL, NULL,
"Display in window"},
{ 0 }
};
DEVICE dpy_dev = { DEVICE dpy_dev = {
"DPY", dpy_unit, NULL, NULL, "DPY", dpy_unit, NULL, dpy_mod,
NUM_DEVS_DPY, 0, 0, 0, 0, 0, NUM_DEVS_DPY, 0, 0, 0, 0, 0,
NULL, NULL, dpy_reset, NULL, NULL, dpy_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
&dpy_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_DISPLAY, 0, NULL, &dpy_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_DISPLAY, 0, dev_debug,
NULL, NULL, NULL, NULL, NULL, &dpy_description NULL, NULL, NULL, NULL, NULL, &dpy_description
}; };
@ -348,10 +359,21 @@ static void dpy_joy_motion(int which, int axis, int value)
static void dpy_joy_button(int which, int button, int state) static void dpy_joy_button(int which, int button, int state)
{ {
if (which < JOY_MAX_UNITS && button < JOY_MAX_BUTTONS) { if (which < JOY_MAX_UNITS && button < JOY_MAX_BUTTONS) {
joy_buttons[which * JOY_MAX_UNITS + button] = state; joy_buttons[which * JOY_MAX_BUTTONS + button] = state;
} }
} }
static int dpy_keyboard (SIM_KEY_EVENT *ev)
{
sim_debug(DEBUG_DATA, &dpy_dev, "Key %d %s\n",
ev->key, ev->state == SIM_KEYPRESS_DOWN ? "down" : "up");
if (ev->state == SIM_KEYPRESS_UP && ev->key == SIM_KEY_F11) {
vid_set_fullscreen (!vid_is_fullscreen ());
return 1;
}
return 0;
}
/* Reset routine */ /* Reset routine */
t_stat dpy_reset (DEVICE *dptr) t_stat dpy_reset (DEVICE *dptr)
@ -359,8 +381,15 @@ t_stat dpy_reset (DEVICE *dptr)
if (dptr->flags & DEV_DIS) { if (dptr->flags & DEV_DIS) {
display_close(dptr); display_close(dptr);
} else { } else {
#if ITS
if (stk_dev.flags & DEV_DIS) {
sim_debug(DEBUG_DETAIL, &dpy_dev, "Grabbing keyboard\n");
vid_display_kb_event_process = dpy_keyboard;
}
#endif
display_reset(); display_reset();
ty340_reset(dptr); ty340_reset(dptr);
vid_set_fullscreen (dpy_unit[0].flags & FULLSCREEN);
vid_register_gamepad_motion_callback (dpy_joy_motion); vid_register_gamepad_motion_callback (dpy_joy_motion);
vid_register_gamepad_button_callback (dpy_joy_button); vid_register_gamepad_button_callback (dpy_joy_button);
} }
@ -427,37 +456,63 @@ cpu_set_switches(unsigned long w1, unsigned long w2) {
#if NUM_DEVS_WCNSLS > 0 #if NUM_DEVS_WCNSLS > 0
#define WCNSLS_DEVNUM 0420 #define WCNSLS_DEVNUM 0420
#define UNIT_JOY (1 << DEV_V_UF) #define UNIT_JOY (1 << DEV_V_UF) /* Use USB gaming devices. */
#define UNIT_CSCOPE (1 << (DEV_V_UF+1)) /* Enable color scope. */
t_stat wcnsls_devio(uint32 dev, uint64 *data); t_stat wcnsls_devio(uint32 dev, uint64 *data);
t_stat wcnsls_svc (UNIT *uptr);
t_stat wcnsls_reset (DEVICE *dptr);
const char *wcnsls_description (DEVICE *dptr); const char *wcnsls_description (DEVICE *dptr);
static uint64 dev420_cono = 0;
static uint8 cscope_r = 0;
static uint8 cscope_g = 0;
static uint8 cscope_b = 0;
static VID_DISPLAY *cscope_display = NULL;
static uint32 fade[512 * 512];
static uint32 dot[7 * 7];
DIB wcnsls_dib[] = { DIB wcnsls_dib[] = {
{ WCNSLS_DEVNUM, 1, &wcnsls_devio, NULL }}; { WCNSLS_DEVNUM, 1, &wcnsls_devio, NULL }};
MTAB wcnsls_mod[] = { MTAB wcnsls_mod[] = {
{ UNIT_JOY, UNIT_JOY, "JOYSTICK", "JOYSTICK", NULL, NULL, NULL, { UNIT_JOY, UNIT_JOY, "JOYSTICK", "JOYSTICK", NULL, NULL, NULL,
"Use USB joysticks"}, "Use USB joysticks"},
{ UNIT_CSCOPE, UNIT_CSCOPE, "CSCOPE", "CSCOPE", NULL, NULL, NULL,
"Enable color scope"},
{ 0 } { 0 }
}; };
UNIT wcnsls_unit[] = { UNIT wcnsls_unit[] = {
{ UDATA (NULL, UNIT_IDLE, 0) }}; { UDATA (wcnsls_svc, UNIT_IDLE, 0) }};
REG wcnsls_reg[] = {
{ORDATA(CONO, dev420_cono, 18)},
{0}
};
DEVICE wcnsls_dev = { DEVICE wcnsls_dev = {
"WCNSLS", wcnsls_unit, NULL, wcnsls_mod, "WCNSLS", wcnsls_unit, wcnsls_reg, wcnsls_mod,
NUM_DEVS_WCNSLS, 0, 0, 0, 0, 0, NUM_DEVS_WCNSLS, 0, 0, 0, 0, 0,
NULL, NULL, wcnsls_reset,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, &wcnsls_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, dev_debug,
&wcnsls_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, NULL,
NULL, NULL, NULL, NULL, NULL, &wcnsls_description NULL, NULL, NULL, NULL, NULL, &wcnsls_description
}; };
const char *wcnsls_description (DEVICE *dptr) const char *wcnsls_description (DEVICE *dptr)
{ {
return "MIT Spacewar Consoles"; return "MIT Spacewar Consoles, and DEC color scope";
} }
/* Device 420 CONO bits. */
#define CONO_BLUE 0000020 /* Color scope blue enable */
#define CONO_SPCWAR 0000040 /* Spacewar consoles */
#define CONO_GREEN 0002000 /* Color scope green enable */
#define CONO_RANDOM 0004000 /* Random switches */
#define CONO_RED 0200000 /* Color scope red enable */
#define CONO_KNIGHT 0400000 /* Switches in TK's office */
/* /*
* map 32-bit "spacewar_switches" value to what PDP-6/10 game expects * map 32-bit "spacewar_switches" value to what PDP-6/10 game expects
* (four 9-bit bytes) * (four 9-bit bytes)
@ -485,6 +540,37 @@ const char *wcnsls_description (DEVICE *dptr)
#define BUT2 (JOY_MAX_BUTTONS*2) #define BUT2 (JOY_MAX_BUTTONS*2)
#define BUT3 (JOY_MAX_BUTTONS*3) #define BUT3 (JOY_MAX_BUTTONS*3)
static void
cscope_init (void)
{
int i;
fade[0] = vid_map_rgba_window (cscope_display, 0, 0, 0, 240);
for (i = 1; i < 512 * 512; i++)
fade[i] = fade[0];
}
static void
cscope_plot(int x, int y)
{
int i, j;
for (i = 0; i < 7; i++) {
for (j = 0; j < 7; j++) {
int dx = i - 3, dy = j - 3;
int r2 = dx*dx + dy*dy;
double focus = 0.2;
double intensity = 0xFF/15.0;
double alpha = 0xFF*exp(-focus*r2);
dot[i + 7*j] = vid_map_rgba_window (cscope_display,
(uint8)(intensity*(cscope_r << 4)),
(uint8)(intensity*(cscope_g << 4)),
(uint8)(intensity*(cscope_b << 4)),
(uint8)alpha);
}
}
vid_draw_window (cscope_display, x - 3, 511 - y - 3, 7, 7, dot);
}
static uint64 joystick_switches (void) static uint64 joystick_switches (void)
{ {
uint64 switches = 0777777777777LL; uint64 switches = 0777777777777LL;
@ -562,18 +648,67 @@ static uint64 keyboard_switches (void)
return switches; return switches;
} }
t_stat wcnsls_svc (UNIT *uptr)
{
vid_refresh_window (cscope_display);
vid_draw_window (cscope_display, 0, 0, 512, 512, fade);
sim_activate_after (uptr, 33333);
return SCPE_OK;
}
t_stat
wcnsls_reset (DEVICE *dptr)
{
t_stat r;
if (sim_switches & SWMASK('P') || dptr->flags & DEV_DIS ||
(wcnsls_unit->flags & UNIT_CSCOPE) == 0) {
sim_cancel (wcnsls_unit);
if (cscope_display != NULL)
vid_close_window (cscope_display);
cscope_display = NULL;
} else if (cscope_display == NULL) {
r = vid_open_window (&cscope_display, dptr, "Color scope", 512, 512, 0);
if (r != SCPE_OK)
return r;
/* Allow time for window to open and data structures to settle. */
sim_os_sleep (1);
r = vid_set_alpha_mode (cscope_display, SIM_ALPHA_BLEND);
if (r != SCPE_OK)
return r;
sim_activate_abs (wcnsls_unit, 0);
cscope_init ();
}
return SCPE_OK;
}
t_stat wcnsls_devio(uint32 dev, uint64 *data) { t_stat wcnsls_devio(uint32 dev, uint64 *data) {
switch (dev & 3) { switch (dev & 3) {
case CONO: case CONO:
/* CONO WCNSLS,40 ;enable spacewar consoles */ /* CONO WCNSLS,40 ;enable spacewar consoles */
sim_debug (DEBUG_CONO, &wcnsls_dev, "%06llo\n", *data);
dev420_cono = *data;
if (dev420_cono & CONO_RED)
cscope_r = (dev420_cono >> 12) & 017;
if (dev420_cono & CONO_GREEN)
cscope_g = (dev420_cono >> 6) & 017;
if (dev420_cono & CONO_BLUE)
cscope_b = dev420_cono & 017;
break;
case DATAO:
sim_debug (DEBUG_DATAIO, &wcnsls_dev, "DATAO %012llo\n", *data);
if (wcnsls_unit->flags & UNIT_CSCOPE)
cscope_plot((*data >> 9) & 0777, *data & 0777);
break; break;
case DATAI: case DATAI:
if (dev420_cono & CONO_SPCWAR) {
if (wcnsls_unit->flags & UNIT_JOY) { if (wcnsls_unit->flags & UNIT_JOY) {
*data = joystick_switches (); *data = joystick_switches ();
} else { } else {
*data = keyboard_switches (); *data = keyboard_switches ();
} }
}
sim_debug(DEBUG_DATAIO, &wcnsls_dev, "WCNSLS %03o DATI %012llo PC=%06o\n", sim_debug(DEBUG_DATAIO, &wcnsls_dev, "WCNSLS %03o DATI %012llo PC=%06o\n",
dev, *data, PC); dev, *data, PC);

View file

@ -1233,7 +1233,6 @@ void dt_flush (UNIT* uptr)
uint32 ba, k, *fbuf; uint32 ba, k, *fbuf;
if (uptr->WRITTEN && uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ if (uptr->WRITTEN && uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
sim_printf ("%s: writing buffer to file: %s\n", sim_uname (uptr), uptr->filename);
rewind (uptr->fileref); /* start of file */ rewind (uptr->fileref); /* start of file */
fbuf = (uint32 *) uptr->filebuf; /* file buffer */ fbuf = (uint32 *) uptr->filebuf; /* file buffer */
if (uptr->flags & UNIT_8FMT) { /* 12b? */ if (uptr->flags & UNIT_8FMT) { /* 12b? */
@ -1285,8 +1284,10 @@ t_stat dt_detach (UNIT* uptr)
sim_cancel (uptr); sim_cancel (uptr);
uptr->CMD = uptr->pos = 0; uptr->CMD = uptr->pos = 0;
} }
if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) /* any data? */ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */
dt_flush(uptr); /* end if hwmark */ sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u);
dt_flush(uptr);
} /* end if hwmark */
free (uptr->filebuf); /* release buf */ free (uptr->filebuf); /* release buf */
uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */
uptr->filebuf = NULL; /* clear buf ptr */ uptr->filebuf = NULL; /* clear buf ptr */

View file

@ -44,6 +44,59 @@
#define TYPE_BBN 1 /* BBN style interface TENEX */ #define TYPE_BBN 1 /* BBN style interface TENEX */
#define TYPE_WAITS 2 /* IMP connected to waits system. */ #define TYPE_WAITS 2 /* IMP connected to waits system. */
#define TYPE_UNI 0 /* Unibus byte order */
#define TYPE_SIMP 1 /* PDP10 string byte order */
#if KS
/* IMP11 interface */
/* CSR values */
#define CSR_GO 0000001 /* Go transfer */
#define CSR_RST 0000002 /* Reset interface */
#define CSR_UBA 0000060 /* Unibus upper address */
#define CSR_IE 0000100 /* Interrupt enable */
#define CSR_RDY 0000200 /* Device ready */
#define CSR_MRE 0001000 /* Master error */
#define CSR_NXM 0040000 /* Non existant memory */
#define CSR_ERR 0100000 /* Error present */
/* Input CSR 0767600 */
#define CSR_HRC 0000004 /* Host Ready Relay Control */
#define CSR_SE 0000010 /* Store enable */
#define CSR_IBF 0000400 /* Input Buffer full */
#define CSR_INR 0002000 /* IMP not ready */
#define CSR_HR 0004000 /* Host Ready */
#define CSR_EOM 0020000 /* End of Message */
/* Input data buffer 0767602 */
/* Input Bus Address 0767604 */
/* Input Word Count 0767606 */
/* Output CSR 07676010 */
#define CSR_ELB 0000004 /* Send EOM indication to IMP */
#define CSR_BB 0000010 /* Bus Back */
#define CSR_OBE 0000400 /* OUtput Buffer Empty */
#define CSR_WC0 0020000 /* Output Word Count 0 */
/* Output data buffer 0767612 */
/* Output Bus Address 0767614 */
/* Output Word Count 0767616 */
/* Bits in STATUS */
#define IMPID 010 /* Input done. */
#define IMPIB 040 /* Input busy. */
#define IMPOD 0100 /* Output done. */
#define IMPOB 0400 /* Output busy. */
#define IMPERR 01000 /* IMP error. */
#define IMPR 02000 /* IMP ready. */
#define IMPIC 04000 /* IMP interrupt condition. */
#define IMPHER 010000 /* Host error. */
#define IMPHR 020000 /* Host ready. */
#define IMPIHE 040000 /* Inhibit interrupt on host error. */
#define IMPLW 0100000 /* Last IMP word. */
#else
/* ITS IMP Bits */ /* ITS IMP Bits */
/* CONI */ /* CONI */
@ -123,6 +176,7 @@
/* CONI timeout. If no CONI instruction is executed for 3-5 seconds, /* CONI timeout. If no CONI instruction is executed for 3-5 seconds,
the interface will raise the host error signal. */ the interface will raise the host error signal. */
#define CONI_TIMEOUT 3000000 #define CONI_TIMEOUT 3000000
#endif
#define STATUS u3 #define STATUS u3
#define OPOS u4 /* Output bit position */ #define OPOS u4 /* Output bit position */
@ -435,8 +489,14 @@ static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff};
static CONST in_addr_T broadcast_ipaddr = {0xffffffff}; static CONST in_addr_T broadcast_ipaddr = {0xffffffff};
#if KS
int imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access);
int imp_rd(DEVICE *dptr, t_addr addr, uint16 *data, int32 access);
uint16 imp_vect(struct pdp_dib *dibp);
#else
t_stat imp_devio(uint32 dev, uint64 *data); t_stat imp_devio(uint32 dev, uint64 *data);
t_addr imp_devirq(uint32 dev, t_addr addr); t_addr imp_devirq(uint32 dev, t_addr addr);
#endif
t_stat imp_srv(UNIT *); t_stat imp_srv(UNIT *);
t_stat imp_eth_srv(UNIT *); t_stat imp_eth_srv(UNIT *);
t_stat imp_tim_srv(UNIT *); t_stat imp_tim_srv(UNIT *);
@ -480,15 +540,30 @@ const char *imp_description (DEVICE *dptr);
static char *ipv4_inet_ntoa(struct in_addr ip); static char *ipv4_inet_ntoa(struct in_addr ip);
static int ipv4_inet_aton(const char *str, struct in_addr *inp); static int ipv4_inet_aton(const char *str, struct in_addr *inp);
#if KS
uint16 imp_icsr;
uint16 imp_idb;
uint32 imp_iba;
uint16 imp_iwcnt;
uint16 imp_ocsr;
uint16 imp_odb;
uint32 imp_oba;
uint16 imp_owcnt;
#endif
int imp_mpx_lvl = 0; int imp_mpx_lvl = 0;
double last_coni; double last_coni;
UNIT imp_unit[] = { UNIT imp_unit[] = {
{UDATA(imp_srv, UNIT_IDLE+UNIT_ATTABLE+UNIT_DHCP, 0)}, /* 0 */ {UDATA(imp_srv, UNIT_IDLE+UNIT_ATTABLE+UNIT_DHCP, 0)}, /* 0 */
{UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ {UDATA(imp_eth_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 1 */
{UDATA(imp_tim_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 0 */ {UDATA(imp_tim_srv, UNIT_IDLE+UNIT_DIS, 0)}, /* 2 */
}; };
#if KS
DIB imp_dib = {0767600, 017, 0250, 6, 3, &imp_rd, &imp_wr, 0, 0, 0};
#else
DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio, DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio,
#if KL #if KL
&imp_devirq, &imp_devirq,
@ -496,6 +571,7 @@ DIB imp_dib = {IMP_DEVNUM, 1, &imp_devio,
NULL NULL
#endif #endif
}; };
#endif
MTAB imp_mod[] = { MTAB imp_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx",
@ -516,16 +592,33 @@ MTAB imp_mod[] = {
"Use DHCP to set IP address"}, "Use DHCP to set IP address"},
{ MTAB_XTD|MTAB_VDV, 0, "DHCPIP", NULL, { MTAB_XTD|MTAB_VDV, 0, "DHCPIP", NULL,
NULL, &imp_show_dhcpip, NULL, "DHCP info" }, NULL, &imp_show_dhcpip, NULL, "DHCP info" },
#if KS
{ UNIT_DTYPE, (TYPE_UNI << UNIT_V_DTYPE), "UNI", "UNI", NULL, NULL, NULL,
"Standard Unibus transfers"},
{ UNIT_DTYPE, (TYPE_SIMP << UNIT_V_DTYPE), "SIMP", "SIMP", NULL, NULL, NULL,
"PDP10 byte order transfers"},
#else
{ UNIT_DTYPE, (TYPE_MIT << UNIT_V_DTYPE), "MIT", "MIT", NULL, NULL, NULL, { UNIT_DTYPE, (TYPE_MIT << UNIT_V_DTYPE), "MIT", "MIT", NULL, NULL, NULL,
"ITS/MIT style interface"}, "ITS/MIT style interface"},
{ UNIT_DTYPE, (TYPE_BBN << UNIT_V_DTYPE), "BBN", "BBN", NULL, NULL, NULL, { UNIT_DTYPE, (TYPE_BBN << UNIT_V_DTYPE), "BBN", "BBN", NULL, NULL, NULL,
"Tenex/BBN style interface"}, "Tenex/BBN style interface"},
{ UNIT_DTYPE, (TYPE_WAITS << UNIT_V_DTYPE), "WAITS", "WAITS", NULL, NULL, NULL, { UNIT_DTYPE, (TYPE_WAITS << UNIT_V_DTYPE), "WAITS", "WAITS", NULL, NULL, NULL,
"WAITS style interface"}, "WAITS style interface"},
#endif
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ARP", NULL, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ARP", NULL,
NULL, &imp_show_arp, NULL, "ARP IP address->MAC address table" }, NULL, &imp_show_arp, NULL, "ARP IP address->MAC address table" },
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "ARP=ddd.ddd.ddd.ddd=XX:XX:XX:XX:XX:XX", { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, NULL, "ARP=ddd.ddd.ddd.ddd=XX:XX:XX:XX:XX:XX",
&imp_set_arp, NULL, NULL, "Create a static ARP Entry" }, &imp_set_arp, NULL, NULL, "Create a static ARP Entry" },
#if KS
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
NULL, "Sets vect of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
NULL, "Sets br of CH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of CH11" },
#endif
{ 0 } { 0 }
}; };
@ -570,6 +663,180 @@ DEVICE imp_dev = {
#define IMP_ICHN 0000070 #define IMP_ICHN 0000070
#define IMP_ECHN 0000700 #define IMP_ECHN 0000700
#if KS
static void check_interrupts (UNIT *uptr)
{
DEVICE *dptr = &imp_dev;
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
if ((uptr->STATUS & IMPID) != 0 && imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
}
int
imp_wr(DEVICE *dptr, t_addr addr, uint16 data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
UNIT *uptr = imp_unit;
addr &= dibp->uba_mask;
sim_debug(DEBUG_DETAIL, dptr, "IMP11 write %06o %06o %o\n",
addr, data, access);
switch (addr & 016) {
case 000: /* Input CSR */
if (access == BYTE) {
if (addr & 1)
data = data | (imp_icsr & 0377);
else
data = (imp_icsr & 0177400) | data;
}
if (data & CSR_RST) {
imp_icsr = CSR_INR|CSR_RDY;
imp_iba = 0;
imp_iwcnt = 0;
uba_clr_irq(dibp, dibp->uba_vect);
}
data &= (CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_HRC|CSR_SE);
imp_icsr &= ~(CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_HRC|CSR_SE|CSR_ERR
|CSR_NXM|CSR_MRE);
imp_icsr |= data;
if (data & CSR_HRC) {
imp_icsr |= CSR_HR;
} else {
imp_icsr &= ~CSR_HR;
imp_icsr |= CSR_INR;
}
if (data & CSR_GO) {
imp_icsr &= ~CSR_RDY;
uptr->STATUS &= ~(IMPID|IMPLW);
uba_clr_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, dptr, "IMP11 icsr %06o\n", imp_icsr);
break;
case 002: /* Input Data Buffer */
if (access == BYTE) {
if (addr & 1)
data = data | (imp_idb & 0377);
else
data = (imp_idb & 0177400) | data;
}
imp_idb = data;
break;
case 004: /* Input Bus Address */
imp_iba = (data & 0177777);
imp_icsr &= ~(CSR_ERR);
break;
case 006: /* Input Word Count */
imp_iwcnt = (data & 0177777);
break;
case 010: /* Output CSR */
if (access == BYTE) {
if (addr & 1)
data = data | (imp_ocsr & 0377);
else
data = (imp_ocsr & 0177400) | data;
}
if (data & CSR_RST) {
imp_ocsr |= CSR_RDY;
imp_oba = 0;
imp_owcnt = 0;
uba_clr_irq(dibp, dibp->uba_vect + 4);
}
data &= (CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_BB|CSR_ELB);
imp_ocsr &= ~(CSR_GO|CSR_RST|CSR_UBA|CSR_IE|CSR_BB|CSR_ELB|CSR_ERR
|CSR_NXM|CSR_MRE);
imp_ocsr |= data;
if (data & CSR_GO) {
imp_ocsr &= ~CSR_RDY;
uptr->STATUS &= ~(IMPOD);
uba_clr_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, dptr, "IMP11 ocsr %06o\n", imp_ocsr);
break;
case 012: /* Output Data Buffer */
if (access == BYTE) {
if (addr & 1)
data = data | (imp_odb & 0377);
else
data = (imp_odb & 0177400) | data;
}
imp_odb = data;
break;
case 014: /* Output Bus Address */
imp_oba = (data & 0177777);
imp_ocsr &= ~(CSR_ERR);
break;
case 016: /* Output Word Count */
imp_owcnt = (data & 0177777);
break;
}
if (imp_ocsr & CSR_GO || imp_icsr & CSR_GO)
sim_activate(uptr, 100);
return 0;
}
int
imp_rd(DEVICE *dptr, t_addr addr, uint16 *data, int32 access)
{
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
UNIT *uptr = imp_unit;
addr &= dibp->uba_mask;
switch (addr & 016) {
case 000: /* Input CSR */
*data = imp_icsr;
if ((uptr->STATUS & (IMPID)) != 0)
*data |= CSR_IBF;
if ((uptr->STATUS & (IMPLW)) != 0)
*data |= CSR_EOM;
break;
case 002: /* Input Data Buffer */
*data = imp_idb;
break;
case 004: /* Input Bus Address */
*data = imp_iba;
break;
case 006: /* Input Word Count */
*data = imp_iwcnt;
break;
case 010: /* Output CSR */
*data = imp_ocsr;
if ((uptr->STATUS & (IMPOD)) != 0)
*data |= CSR_OBE;
break;
case 012: /* Output Data Buffer */
*data = imp_odb;
break;
case 014: /* Output Bus Address */
*data = imp_oba;
break;
case 016: /* Output Word Count */
*data = imp_owcnt;
break;
}
sim_debug(DEBUG_DETAIL, dptr, "IMP11 read %06o %06o %o\n",
addr, *data, access);
return 0;
}
#else
static void check_interrupts (UNIT *uptr) static void check_interrupts (UNIT *uptr)
{ {
clr_interrupt (DEVNUM); clr_interrupt (DEVNUM);
@ -740,9 +1007,171 @@ imp_devirq(uint32 dev, t_addr addr) {
return addr; return addr;
} }
#endif #endif
#endif
t_stat imp_srv(UNIT * uptr) t_stat imp_srv(UNIT * uptr)
{ {
#if KS
DEVICE *dptr = find_dev_from_unit (uptr);
struct pdp_dib *dibp = (DIB *)dptr->ctxt;
t_addr pa;
uint64 wd64;
uint16 wd;
if (imp_ocsr & CSR_GO && imp_data.sendq == NULL) {
pa = ((imp_ocsr & CSR_UBA) << 12) | imp_oba;
switch (GET_DTYPE(uptr->flags)) {
case TYPE_UNI:
if (uba_read_npr_word(pa, dibp->uba_ctl, &wd) == 0) {
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
imp_data.sbuffer[uptr->OPOS >> 3] = (wd & 0377);
uptr->OPOS += 8;
imp_data.sbuffer[uptr->OPOS >> 3] = ((wd >> 8) & 0377);
uptr->OPOS += 8;
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP send %04x %07o %06o %06o\n",
wd, pa, imp_owcnt, imp_ocsr);
break;
case TYPE_SIMP:
if (uba_read_npr(pa, dibp->uba_ctl, &wd64) == 0) {
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
imp_data.sbuffer[uptr->OPOS >> 3] = (wd64 >> 28) & 0377;
uptr->OPOS += 8;
imp_data.sbuffer[uptr->OPOS >> 3] = (wd64 >> 20) & 0377;
uptr->OPOS += 8;
imp_data.sbuffer[uptr->OPOS >> 3] = (wd64 >> 12) & 0377;
uptr->OPOS += 8;
imp_data.sbuffer[uptr->OPOS >> 3] = (wd64 >> 4) & 0377;
uptr->OPOS += 8;
imp_oba += 2;
imp_owcnt++;
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP send %08llx %07o %06o %06o\n",
(wd64 >> 4), pa, imp_owcnt, imp_ocsr);
break;
}
imp_oba += 2;
imp_owcnt++;
if (imp_oba == 0) {
imp_ocsr |= CSR_ERR;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP oba overflow\n");
return SCPE_OK;
}
if (imp_owcnt == 0) {
imp_ocsr |= CSR_RDY;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPOD;
if (imp_ocsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect + 4);
}
if (imp_ocsr & CSR_ELB) {
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP send\n");
imp_send_packet (&imp_data, uptr->OPOS >> 3);
memset(imp_data.sbuffer, 0, ETH_FRAME_SIZE);
uptr->OPOS = 0;
}
}
}
if (uptr->STATUS & IMPIB && imp_icsr & CSR_GO) {
pa = ((imp_icsr & CSR_UBA) << 12) | imp_iba;
if (imp_iba == 0) {
imp_icsr |= CSR_ERR;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP oba overflow\n");
return SCPE_OK;
}
switch (GET_DTYPE(uptr->flags)) {
case TYPE_UNI:
wd = imp_data.rbuffer[uptr->IPOS >> 3] << 8;
uptr->IPOS += 8;
wd |= imp_data.rbuffer[uptr->IPOS >> 3];
uptr->IPOS += 8;
if (uba_write_npr_word(pa, dibp->uba_ctl, wd) == 0) {
imp_icsr |= CSR_NXM;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP in npr failed\n");
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP rec %04x %07o %06o %06o\n",
wd, pa, imp_owcnt, imp_ocsr);
break;
case TYPE_SIMP:
wd64 = (uint64)imp_data.rbuffer[uptr->IPOS >> 3] << 28;
uptr->IPOS += 8;
wd64 |= (uint64)imp_data.rbuffer[uptr->IPOS >> 3] << 20;
uptr->IPOS += 8;
wd64 |= (uint64)imp_data.rbuffer[uptr->IPOS >> 3] << 12;
uptr->IPOS += 8;
wd64 |= (uint64)imp_data.rbuffer[uptr->IPOS >> 3] << 4;
uptr->IPOS += 8;
if (uba_write_npr(pa, dibp->uba_ctl, wd64) == 0) {
imp_ocsr |= CSR_NXM;
imp_ocsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP out npr failed\n");
return SCPE_OK;
}
imp_iba += 2;
imp_iwcnt++;
sim_debug(DEBUG_DETAIL, &imp_dev, "IMP rec %08llx %07o %06o %06o\n",
(wd64 >> 4), pa, imp_owcnt, imp_ocsr);
break;
}
imp_iba += 2;
imp_iwcnt++;
if (uptr->IPOS > uptr->ILEN) {
imp_icsr |= CSR_EOM|CSR_RDY;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID|IMPLW;
uptr->STATUS &= ~IMPIB;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
uptr->ILEN = 0;
}
if (imp_iwcnt == 0) {
imp_icsr |= CSR_RDY;
imp_icsr &= ~CSR_GO;
uptr->STATUS |= IMPID;
if (imp_icsr & CSR_IE) {
uba_set_irq(dibp, dibp->uba_vect);
}
}
}
if (imp_ocsr & CSR_GO || imp_icsr & CSR_GO)
sim_activate(uptr, 100);
#else
int i; int i;
int l; int l;
@ -782,6 +1211,7 @@ t_stat imp_srv(UNIT * uptr)
uptr->STATUS |= IMPID; uptr->STATUS |= IMPID;
check_interrupts (uptr); check_interrupts (uptr);
} }
#endif
if (uptr->ILEN == 0 && (uptr->STATUS & (IMPIB|IMPID)) == 0) if (uptr->ILEN == 0 && (uptr->STATUS & (IMPIB|IMPID)) == 0)
imp_packet_in(&imp_data); imp_packet_in(&imp_data);
return SCPE_OK; return SCPE_OK;
@ -879,11 +1309,16 @@ t_stat imp_eth_srv(UNIT * uptr)
imp_data.init_state); imp_data.init_state);
if (imp_unit[0].ILEN == 0) { if (imp_unit[0].ILEN == 0) {
/* Queue up a nop packet */ /* Queue up a nop packet */
imp_data.rbuffer[0] = 0x4; #if KS
#if 0
imp_data.rbuffer[0] = 0xf; imp_data.rbuffer[0] = 0xf;
imp_data.rbuffer[3] = 4; imp_data.rbuffer[3] = 4;
#else
imp_data.rbuffer[0] = 0x4;
#endif #endif
imp_data.rbuffer[1] = (ntohl(imp_data.ip) >> 24) & 0xff;
imp_data.rbuffer[5] = (ntohl(imp_data.ip) >> 16) & 0xff;
imp_data.rbuffer[6] = (ntohl(imp_data.ip) >> 8) & 0xff;
imp_data.rbuffer[7] = ntohl(imp_data.ip) & 0xff;
imp_unit[0].STATUS |= IMPIB; imp_unit[0].STATUS |= IMPIB;
imp_unit[0].IPOS = 0; imp_unit[0].IPOS = 0;
imp_unit[0].ILEN = 12*8; imp_unit[0].ILEN = 12*8;
@ -938,6 +1373,9 @@ t_stat imp_tim_srv(UNIT * uptr)
imp_dhcp_timer(&imp_data); imp_dhcp_timer(&imp_data);
imp_arp_age(&imp_data); imp_arp_age(&imp_data);
#if KS
imp_icsr &= ~CSR_HR;
#endif
return SCPE_OK; return SCPE_OK;
} }
@ -996,12 +1434,20 @@ imp_packet_in(struct imp_device *imp)
memset(&imp->rbuffer[0], 0, 256); memset(&imp->rbuffer[0], 0, 256);
imp->rbuffer[0] = 0xf; imp->rbuffer[0] = 0xf;
imp->rbuffer[3] = 0; imp->rbuffer[3] = 0;
#if KS
imp->rbuffer[1] = (ntohl(ip_hdr->ip_src) >> 24) & 0xff;
imp->rbuffer[5] = (ntohl(ip_hdr->ip_src) >> 16) & 0xff; imp->rbuffer[5] = (ntohl(ip_hdr->ip_src) >> 16) & 0xff;
imp->rbuffer[6] = (ntohl(ip_hdr->ip_src) >> 8) & 0xff;
imp->rbuffer[7] = ntohl(ip_hdr->ip_src) & 0xff;
#else
imp->rbuffer[7] = 14; imp->rbuffer[7] = 14;
#endif
imp->rbuffer[8] = 0233; imp->rbuffer[8] = 0233;
#if !KS
imp->rbuffer[18] = 0; imp->rbuffer[18] = 0;
imp->rbuffer[19] = 0x80; imp->rbuffer[19] = 0x80;
imp->rbuffer[21] = 0x30; imp->rbuffer[21] = 0x30;
#endif
/* Copy message over */ /* Copy message over */
pad = 12 + (imp->padding / 8); pad = 12 + (imp->padding / 8);
@ -1144,6 +1590,12 @@ imp_packet_in(struct imp_device *imp)
imp_unit[0].STATUS |= IMPIB; imp_unit[0].STATUS |= IMPIB;
imp_unit[0].IPOS = 0; imp_unit[0].IPOS = 0;
imp_unit[0].ILEN = n*8; imp_unit[0].ILEN = n*8;
imp->rbuffer[1] = (ntohl(ip_hdr->ip_src) >> 24) & 0xff;
imp->rbuffer[5] = (ntohl(ip_hdr->ip_src) >> 16) & 0xff;
imp->rbuffer[6] = (ntohl(ip_hdr->ip_src) >> 8) & 0xff;
imp->rbuffer[7] = ntohl(ip_hdr->ip_src) & 0xff;
imp->rbuffer[10] = (n >> 8) & 0xff;
imp->rbuffer[11] = n & 0xff;
} }
if (!sim_is_active(&imp_unit[0])) if (!sim_is_active(&imp_unit[0]))
sim_activate(&imp_unit[0], 100); sim_activate(&imp_unit[0], 100);
@ -1187,10 +1639,11 @@ imp_send_packet (struct imp_device *imp, int len)
break; break;
} }
sim_debug(DEBUG_DETAIL, &imp_dev, sim_debug(DEBUG_DETAIL, &imp_dev,
"IMP packet Type=%d ht=%d dh=%d imp=%d lk=%d %d st=%d Len=%d\n", "IMP packet H=%x Type=%d ht=%d dh=%d imp=%d lk=%d %d st=%d Len=%d mt=%d\n",
imp->sbuffer[0],
imp->sbuffer[3], imp->sbuffer[4], imp->sbuffer[5], imp->sbuffer[3], imp->sbuffer[4], imp->sbuffer[5],
(imp->sbuffer[6] * 256) + imp->sbuffer[7], (imp->sbuffer[6] * 256) + imp->sbuffer[7],
lk, imp->sbuffer[9] >> 4, st, n); lk, imp->sbuffer[9] >> 4, st, n, mt);
switch(mt) { switch(mt) {
case 0: /* Regular packet */ case 0: /* Regular packet */
switch(st) { switch(st) {
@ -1205,6 +1658,15 @@ imp_send_packet (struct imp_device *imp, int len)
imp_packet_out(imp, &write_buffer); imp_packet_out(imp, &write_buffer);
} }
break; break;
case 4: /* Nop */
if (imp->init_state < 3)
imp->init_state++;
imp->padding = 0;
sim_debug(DEBUG_DETAIL, &imp_dev,
"IMP recieve Nop %d padding= %d\n",
imp->init_state, imp->padding);
sim_activate(uptr, tmxr_poll); /* Start reciever task */
break;
case 2: /* Getting ready */ case 2: /* Getting ready */
case 3: /* Uncontrolled */ case 3: /* Uncontrolled */
default: default:
@ -1214,7 +1676,6 @@ imp_send_packet (struct imp_device *imp, int len)
case 1: /* Error */ case 1: /* Error */
break; break;
case 2: /* Host going down */ case 2: /* Host going down */
fprintf(stderr, "IMP: Host shutdown\n\r");
break; break;
case 4: /* Nop */ case 4: /* Nop */
if (imp->init_state < 3) if (imp->init_state < 3)
@ -2027,7 +2488,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer)
ip_checksum((uint8 *)&sum, (uint8 *)ip_hdr, hl); ip_checksum((uint8 *)&sum, (uint8 *)ip_hdr, hl);
if (sum != 0) { if (sum != 0) {
sim_printf("IP checksum error %x\n\r", sum); sim_printf("IP checksum error %x\r\n", sum);
return; return;
} }
ip_checksum((uint8 *)(&sum), (uint8 *)(upkt), ntohs(upkt->len)); ip_checksum((uint8 *)(&sum), (uint8 *)(upkt), ntohs(upkt->len));
@ -2038,7 +2499,7 @@ imp_do_dhcp_client(struct imp_device *imp, ETH_PACK *read_buffer)
udp_hdr.hlen = upkt->len; udp_hdr.hlen = upkt->len;
checksumadjust((uint8 *)&sum, 0, 0, (uint8 *)(&udp_hdr), sizeof(udp_hdr)); checksumadjust((uint8 *)&sum, 0, 0, (uint8 *)(&udp_hdr), sizeof(udp_hdr));
if (sum != 0) { if (sum != 0) {
sim_printf("UDP checksum error %x\n\r", sum); sim_printf("UDP checksum error %x\r\n", sum);
return; return;
} }
@ -2647,6 +3108,10 @@ t_stat imp_reset (DEVICE *dptr)
imp_data.freeq = p; imp_data.freeq = p;
imp_data.init_state = 0; imp_data.init_state = 0;
last_coni = sim_gtime(); last_coni = sim_gtime();
#if KS
imp_icsr = CSR_RDY;
imp_ocsr = CSR_RDY;
#endif
if (imp_unit[0].flags & UNIT_ATT) if (imp_unit[0].flags & UNIT_ATT)
sim_activate_after(&imp_unit[2], 1000000); /* Start Timer service */ sim_activate_after(&imp_unit[2], 1000000); /* Start Timer service */
return SCPE_OK; return SCPE_OK;
@ -2659,6 +3124,7 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
char* tptr; char* tptr;
char buf[32]; char buf[32];
#if !KS
/* Set to correct device number */ /* Set to correct device number */
switch(GET_DTYPE(imp_unit[0].flags)) { switch(GET_DTYPE(imp_unit[0].flags)) {
case TYPE_MIT: case TYPE_MIT:
@ -2669,6 +3135,7 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
imp_dib.dev_num = WA_IMP_DEVNUM; imp_dib.dev_num = WA_IMP_DEVNUM;
break; break;
} }
#endif
if (!(uptr->flags & UNIT_DHCP) && imp_data.ip == 0) if (!(uptr->flags & UNIT_DHCP) && imp_data.ip == 0)
return sim_messagef (SCPE_NOATT, "%s: An IP Address must be specified when DHCP is disabled\n", return sim_messagef (SCPE_NOATT, "%s: An IP Address must be specified when DHCP is disabled\n",
imp_dev.name); imp_dev.name);

View file

@ -178,10 +178,8 @@ UNIT mt_unit[] = {
DIB mt_dib = {MT_DEVNUM, 2, &mt_devio, NULL}; DIB mt_dib = {MT_DEVNUM, 2, &mt_devio, NULL};
MTAB mt_mod[] = { MTAB mt_mod[] = {
{ MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED", {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
&set_writelock, &show_writelock, NULL, "Write ring in place" }, {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
{ MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED",
&set_writelock, NULL, NULL, "no Write ring in place" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, MTDF_TYPEB, "TYPE", "TYPE", &mt_set_mta, &mt_show_mta}, {MTAB_XTD|MTAB_VDV|MTAB_VALR, MTDF_TYPEB, "TYPE", "TYPE", &mt_set_mta, &mt_show_mta},
{MTUF_7TRK, 0, "9T", "9T", NULL, NULL}, {MTUF_7TRK, 0, "9T", "9T", NULL, NULL},
{MTUF_7TRK, MTUF_7TRK, "7T", "7T", NULL, NULL}, {MTUF_7TRK, MTUF_7TRK, "7T", "7T", NULL, NULL},
@ -297,7 +295,7 @@ t_stat mt_devio(uint32 dev, uint64 *data) {
break; break;
case WRITE: case WRITE:
if ((uptr->flags & MTUF_WRP) != 0) { if ((uptr->flags & MTUF_WLK) != 0) {
mt_status |= IDLE_UNIT|ILL_OPR|EOF_FLAG; mt_status |= IDLE_UNIT|ILL_OPR|EOF_FLAG;
break; break;
} }
@ -372,7 +370,7 @@ t_stat mt_devio(uint32 dev, uint64 *data) {
res |= SEVEN_CHAN; res |= SEVEN_CHAN;
if ((uptr->flags & UNIT_ATT) != 0 && (uptr->CNTRL & MT_MOTION) == 0) if ((uptr->flags & UNIT_ATT) != 0 && (uptr->CNTRL & MT_MOTION) == 0)
res |= IDLE_UNIT; res |= IDLE_UNIT;
if ((uptr->flags & MTUF_WRP) != 0) if ((uptr->flags & MTUF_WLK) != 0)
res |= WRITE_LOCK; res |= WRITE_LOCK;
if (sim_tape_bot(uptr)) if (sim_tape_bot(uptr))
res |= BOT_FLAG; res |= BOT_FLAG;
@ -534,8 +532,8 @@ t_stat mt_error(UNIT * uptr, t_stat r, DEVICE * dptr)
/* Handle processing of tape requests. */ /* Handle processing of tape requests. */
t_stat mt_srv(UNIT * uptr) t_stat mt_srv(UNIT * uptr)
{ {
DEVICE *dptr = find_dev_from_unit(uptr); DEVICE *dptr = uptr->dptr;
int unit = (uptr - dptr->units) & 7; int unit;
int cmd = (uptr->CNTRL & FUNCTION) >> 9; int cmd = (uptr->CNTRL & FUNCTION) >> 9;
t_mtrlnt reclen; t_mtrlnt reclen;
t_stat r = SCPE_ARG; /* Force error if not set */ t_stat r = SCPE_ARG; /* Force error if not set */
@ -559,6 +557,10 @@ t_stat mt_srv(UNIT * uptr)
cc_max = (4 + ((uptr->CNTRL & CORE_DUMP) != 0)); cc_max = (4 + ((uptr->CNTRL & CORE_DUMP) != 0));
} }
if (dptr == NULL)
dptr = find_dev_from_unit(uptr);
unit = (uptr - dptr->units) & 7;
switch(cmd) { switch(cmd) {
case NOP_IDLE: case NOP_IDLE:
sim_debug(DEBUG_DETAIL, dptr, "MT%o Idle\n", unit); sim_debug(DEBUG_DETAIL, dptr, "MT%o Idle\n", unit);
@ -802,7 +804,7 @@ t_stat mt_srv(UNIT * uptr)
break; break;
case WTM: case WTM:
if ((uptr->flags & MTUF_WRP) != 0) if ((uptr->flags & MTUF_WLK) != 0)
return mt_error(uptr, MTSE_WRP, dptr); return mt_error(uptr, MTSE_WRP, dptr);
if (uptr->CPOS == 0) { if (uptr->CPOS == 0) {
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG); mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG);
@ -821,7 +823,7 @@ t_stat mt_srv(UNIT * uptr)
break; break;
case ERG: case ERG:
if ((uptr->flags & MTUF_WRP) != 0) if ((uptr->flags & MTUF_WLK) != 0)
return mt_error(uptr, MTSE_WRP, dptr); return mt_error(uptr, MTSE_WRP, dptr);
uptr->CNTRL &= ~MT_MOTION; uptr->CNTRL &= ~MT_MOTION;
mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG); mt_status &= ~(IDLE_UNIT|BOT_FLAG|EOT_FLAG);

View file

@ -130,7 +130,7 @@ t_stat ptp_devio(uint32 dev, uint64 *data) {
if (cpu_unit[0].flags & UNIT_WAITS) if (cpu_unit[0].flags & UNIT_WAITS)
*data |= 0200; *data |= 0200;
#endif #endif
sim_debug(DEBUG_CONI, &ptp_dev, "PP: CONI %012llo\n\r", *data); sim_debug(DEBUG_CONI, &ptp_dev, "PP: CONI %012llo\n", *data);
break; break;
case CONO: case CONO:
@ -144,7 +144,7 @@ t_stat ptp_devio(uint32 dev, uint64 *data) {
} }
if (uptr->STATUS & DONE_FLG) if (uptr->STATUS & DONE_FLG)
set_interrupt(dev, uptr->STATUS); set_interrupt(dev, uptr->STATUS);
sim_debug(DEBUG_CONO, &ptp_dev, "PP: CONO %012llo\n\r", *data); sim_debug(DEBUG_CONO, &ptp_dev, "PP: CONO %012llo\n", *data);
break; break;
case DATAO: case DATAO:
@ -159,7 +159,7 @@ t_stat ptp_devio(uint32 dev, uint64 *data) {
clr_interrupt(dev); clr_interrupt(dev);
sim_activate (&ptp_unit, ptp_unit.wait); sim_activate (&ptp_unit, ptp_unit.wait);
} }
sim_debug(DEBUG_DATAIO, &ptp_dev, "PP: DATAO %012llo\n\r", *data); sim_debug(DEBUG_DATAIO, &ptp_dev, "PP: DATAO %012llo\n", *data);
break; break;
case DATAI: case DATAI:
*data = 0; *data = 0;
@ -181,12 +181,12 @@ t_stat ptp_svc (UNIT *uptr)
return SCPE_OK; return SCPE_OK;
} }
fputc (uptr->CHR, uptr->fileref); /* print char */ fputc (uptr->CHR, uptr->fileref); /* print char */
uptr->pos = ftell (uptr->fileref);
if (ferror (uptr->fileref)) { /* error? */ if (ferror (uptr->fileref)) { /* error? */
perror ("PTP I/O error"); perror ("PTP I/O error");
clearerr (uptr->fileref); clearerr (uptr->fileref);
return SCPE_IOERR; return SCPE_IOERR;
} }
uptr->pos = uptr->pos + 1;
return SCPE_OK; return SCPE_OK;
} }
@ -230,7 +230,7 @@ t_stat ptr_devio(uint32 dev, uint64 *data) {
switch(dev & 3) { switch(dev & 3) {
case CONI: case CONI:
*data = uptr->STATUS; *data = uptr->STATUS;
sim_debug(DEBUG_CONI, &ptr_dev, "PT: CONI %012llo\n\r", *data); sim_debug(DEBUG_CONI, &ptr_dev, "PT: CONI %012llo\n", *data);
break; break;
case CONO: case CONO:
@ -245,7 +245,7 @@ t_stat ptr_devio(uint32 dev, uint64 *data) {
} }
if (uptr->STATUS & DONE_FLG) if (uptr->STATUS & DONE_FLG)
set_interrupt(dev, uptr->STATUS); set_interrupt(dev, uptr->STATUS);
sim_debug(DEBUG_CONO, &ptr_dev, "PT: CONO %012llo\n\r", *data); sim_debug(DEBUG_CONO, &ptr_dev, "PT: CONO %012llo\n", *data);
break; break;
case DATAI: case DATAI:
@ -257,7 +257,7 @@ t_stat ptr_devio(uint32 dev, uint64 *data) {
sim_activate (&ptr_unit, ptr_unit.wait); sim_activate (&ptr_unit, ptr_unit.wait);
} }
uptr->STATUS |= BUSY_FLG; uptr->STATUS |= BUSY_FLG;
sim_debug(DEBUG_DATAIO, &ptr_dev, "PT: DATAI %012llo\n\r", *data); sim_debug(DEBUG_DATAIO, &ptr_dev, "PT: DATAI %012llo\n", *data);
break; break;
case DATAO: case DATAO:
break; break;

View file

@ -24,7 +24,66 @@
#include "kx10_defs.h" #include "kx10_defs.h"
#if KS
#define CS1_GO 1 /* go */
#define CS1_V_FNC 1 /* function pos */
#define CS1_M_FNC 037 /* function mask */
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
#define CS1_IE 0000100 /* Enable interrupts */
#define CS1_RDY 0000200 /* Drive ready */
#define CS1_UBA 0001400 /* High order UBA bits */
#define CS1_PSEL 0002000 /* */
#define CS1_DVA 0004000 /* drive avail */
#define CS1_MCPE 0020000 /* */
#define CS1_TRE 0040000 /* Set if CS2 0177400 */
#define CS1_SC 0100000 /* Set if TRE or ATTN */
#define CS2_V_UNIT 0 /* unit pos */
#define CS2_M_UNIT 07 /* unit mask */
#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT)
#define CS2_UAI 0000010 /* addr inhibit */
#define CS2_PAT 0000020 /* parity test NI */
#define CS2_CLR 0000040 /* controller clear */
#define CS2_IR 0000100 /* input ready */
#define CS2_OR 0000200 /* output ready */
#define CS2_MDPE 0000400 /* Mbus par err NI */
#define CS2_MXF 0001000 /* missed xfer NI */
#define CS2_PGE 0002000 /* program err */
#define CS2_NEM 0004000 /* nx mem err */
#define CS2_NED 0010000 /* nx drive err */
#define CS2_PE 0020000 /* parity err NI */
#define CS2_WCE 0040000 /* write check err */
#define CS2_DLT 0100000 /* data late NI */
/* Controller error bits, saved in error register */
#define ER1_ILF 0000001 /* illegal func */
#define ER1_ILR 0000002 /* illegal register */
#define ER1_RMR 0000004 /* reg mod refused */
#define ER1_PAR 0000010 /* parity err */
/* Map addresses into RH registers */
int rh_map[] = { 0, /* 776700 */
-1, /* 776702 */
-1, /* 776704 */
05, /* 776706 */
-1, /* 776710 */
01, /* 776712 */
02, /* 776714 */
04, /* 776716 */
07, /* 776720 */
-1, /* 776722 */
03, /* 776724 */
06, /* 776726 */
010, /* 776730 */
011, /* 776732 */
012, /* 776734 */
013, /* 776736 */
014, /* 776740 */
015, /* 776742 */
016, /* 776744 */
017 /* 776746 */
};
#else
/* CONI Flags */ /* CONI Flags */
#define IADR_ATTN 0000000000040LL /* Interrupt on attention */ #define IADR_ATTN 0000000000040LL /* Interrupt on attention */
#define IARD_RAE 0000000000100LL /* Interrupt on register access error */ #define IARD_RAE 0000000000100LL /* Interrupt on register access error */
@ -103,6 +162,19 @@
#define IRQ_VECT 0000000000777LL /* Interupt vector */ #define IRQ_VECT 0000000000777LL /* Interupt vector */
#define IRQ_KI10 0000002000000LL #define IRQ_KI10 0000002000000LL
#define IRQ_KA10 0000001000000LL #define IRQ_KA10 0000001000000LL
/* RH20 channel status flags */
#define RH20_MEM_PAR 00200000000000LL /* Memory parity error */
#define RH20_NADR_PAR 00100000000000LL /* Address parity error */
#define RH20_NOT_WC0 00040000000000LL /* Word count not zero */
#define RH20_NXM_ERR 00020000000000LL /* Non existent memory */
#define RH20_LAST_ERR 00000400000000LL /* Last transfer error */
#define RH20_ERROR 00000200000000LL /* RH20 error */
#define RH20_LONG_STS 00000100000000LL /* Did not reach wc */
#define RH20_SHRT_STS 00000040000000LL /* WC reached zero */
#define RH20_OVER 00000020000000LL /* Overrun error */
#endif
#define FNC_XFER 024 /* >=? data xfr */ #define FNC_XFER 024 /* >=? data xfr */
/* Status register settings */ /* Status register settings */
@ -118,17 +190,234 @@
#define DS_ERR 0040000 /* error */ #define DS_ERR 0040000 /* error */
#define DS_ATA 0100000 /* attention active */ #define DS_ATA 0100000 /* attention active */
/* RH20 channel status flags */ #if KS
#define RH20_MEM_PAR 00200000000000LL /* Memory parity error */
#define RH20_NADR_PAR 00100000000000LL /* Address parity error */
#define RH20_NOT_WC0 00040000000000LL /* Word count not zero */
#define RH20_NXM_ERR 00020000000000LL /* Non existent memory */
#define RH20_LAST_ERR 00000400000000LL /* Last transfer error */
#define RH20_ERROR 00000200000000LL /* RH20 error */
#define RH20_LONG_STS 00000100000000LL /* Did not reach wc */
#define RH20_SHRT_STS 00000040000000LL /* WC reached zero */
#define RH20_OVER 00000020000000LL /* Overrun error */
DEVICE *rh_boot_dev = NULL;
int rh_boot_unit = 0;
int
uba_rh_write(DEVICE *dptr, t_addr addr, uint16 data, int32 access) {
int r = 0;
struct pdp_dib *dibp = (DIB *) dptr->ctxt;
struct rh_if *rhc;
int reg;
uint32 temp;
if (dibp == NULL)
return 1;
rhc = dibp->rh11_if;
/* Check for parity error during access */
if (rhc->cs2 & CS2_PAT) {
uba_set_parity(dibp->uba_ctl);
rhc->error |= ER1_PAR;
}
addr &= dibp->uba_mask;
reg = rh_map[addr >> 1];
switch(addr & 076) {
case 000: /* CS1 */
if (access == BYTE) {
if (addr & 1) {
rhc->dev_read(dptr, rhc, 0, &temp);
data = data | (rhc->cs1 & 0300) | (temp & 076);
} else {
data = data | (rhc->cs1 & CS1_UBA);
}
}
rhc->cs1 &= ~(CS1_IE);
rhc->cs1 |= data & (CS1_IE);
if ((rhc->status & BUSY) == 0)
rhc->cda = ((data << 8) & 0600000) | (rhc->cda & 0177777);
if ((data & CS1_GO) != 0 || (rhc->cs1 & CS1_IE) == 0)
uba_clr_irq(rhc->dib, rhc->dib->uba_vect);
if ((data & CS1_GO) != 0 && (rhc->status & BUSY) != 0 && GET_FNC(data) >= FNC_XFER) {
rhc->cs2 |= CS2_PGE;
break;
}
r = rhc->dev_write(dptr, rhc, 0, data);
/* Check if we had a go with a data transfer command */
if (r == 0 && (data & CS1_GO) != 0 && GET_FNC(data) >= FNC_XFER) {
rhc->cs2 = ((CS2_UAI|CS2_OR|CS2_IR|CS2_PAT|CS2_UNIT) & rhc->cs2);
rhc->xfer_drive = rhc->drive;
rhc->status |= BUSY;
}
break;
case 002: /* RPWC - 176702 - word count */ /* 1 */
if (access == BYTE) {
if (addr & 1)
data = data | (rhc->wcr & 0377);
else
data = (rhc->wcr & 0177400) | data;
}
rhc->wcr = data;
break;
case 004: /* RPBA - 176704 - base address */ /* 2 */
if (access == BYTE) {
if (addr & 1)
data = data | (rhc->cda & 0377);
else
data = (rhc->cda & 0177400) | data;
}
rhc->cda = (rhc->cda & 0600000) | (data & 0177776);
break;
case 010: /* RPCS2 - 176710 - Control and Status register 2 */ /* 4 */
if (access == BYTE) {
if (addr & 1)
data = data | (rhc->cs2 & 0377);
else
data = (rhc->cs2 & 0177400) | data;
}
if (data & CS2_CLR) {
rh_reset(dptr, rhc);
if (rhc->dev_reset != NULL)
rhc->dev_reset(dptr);
else
dptr->reset(dptr);
rhc->cs2 |= CS2_CLR; /* Hack for tops 10 7.04 */
break;
}
/* Don't allow UAI to be set just after reset */
if (rhc->cs2 & CS2_CLR) {
data &= ~CS2_UAI;
rhc->cs2 &= ~CS2_CLR;
}
rhc->cs2 &= ~(CS2_PE|CS2_MXF|CS2_PAT|CS2_UNIT);
if ((rhc->status & BUSY) == 0) {
rhc->cs2 &= ~(CS2_UAI);
if( data & CS2_UAI)
sim_debug(DEBUG_DETAIL, dptr, "RH%o set no UAI %06o\n", rhc->drive, PC);
rhc->cs2 |= CS2_UAI & data;
}
rhc->cs2 |= (CS2_PE|CS2_MXF|CS2_PAT|CS2_UNIT) & data;
rhc->cs2 |= CS2_IR;
rhc->drive = rhc->cs2 & CS2_UNIT;
/* Try reading the command register */
r = rhc->dev_read(dptr, rhc, 0, &temp);
if (r < 0)
rhc->cs2 |= CS2_NED;
break;
case 022: /* RPDB - 176722 - data buffer */ /* 11 */
if ((rhc->cs2 & CS2_IR) == 0) {
rhc->cs2 |= CS2_DLT;
break;
}
rhc->dba = rhc->dbb;
rhc->dbb = data;
if (rhc->cs2 & CS2_IR)
rhc->dba = rhc->dbb;
rhc->cs2 |= CS2_OR;
rhc->cs2 &= ~CS2_IR;
break;
case 014: /* RPER1 - 176714 - error status 1 */ /* 6 */
rhc->error = data;
/* Fall through */
default:
if (access == BYTE) {
rhc->dev_read(dptr, rhc, reg, &temp);
if (addr & 1)
data = data | (temp & 0377);
else
data = (temp & 0177400) | data;
}
r = rhc->dev_write(dptr, rhc, reg, data);
}
if (r < 0) {
rhc->cs2 |= CS2_NED;
r = 0;
}
sim_debug(DEBUG_DETAIL, dptr, "RH%o write %06o %06o %o\n", rhc->drive,
addr, data, access);
return r;
}
int
uba_rh_read(DEVICE *dptr, t_addr addr, uint16 *data, int32 access) {
int r = 1;
struct pdp_dib *dibp = (DIB *) dptr->ctxt;
struct rh_if *rhc;
int reg;
uint32 temp = 0;
if (dibp == NULL)
return 1;
rhc = dibp->rh11_if;
addr &= dibp->uba_mask;
reg = rh_map[addr >> 1];
if (reg >= 0) {
r = rhc->dev_read(dptr, rhc, reg, &temp);
if (r < 0) {
rhc->cs2 |= CS2_NED;
return 0;
}
}
switch(addr & 076) {
case 000: /* RPC - 176700 - control */
temp |= (uint16)(rhc->cs1 & (CS1_IE));
temp |= (rhc->cda & 0600000) >> 8;
if ((rhc->status & BUSY) == 0)
temp |= CS1_RDY;
if (rhc->cs2 & (CS2_MDPE|CS2_MXF|CS2_PGE|CS2_NEM|CS2_NED|CS2_PE|CS2_WCE|CS2_DLT))
temp |= CS1_TRE;
if (rhc->attn || (temp & CS1_TRE) != 0)
temp |= CS1_SC;
r = 0;
break;
case 002: /* RPWC - 176702 - word count */
temp = rhc->wcr;
r = 0;
break;
case 004: /* RPBA - 176704 - base address */
temp = (uint16)(rhc->cda & 0177776);
r = 0;
break;
case 010: /* RPCS2 - 176710 - control/status 2 */
temp = rhc->cs2 & ~CS2_CLR;
r = 0;
break;
case 014: /* RPER1 - 176714 - error status 1 */
temp |= rhc->error;
r = 0;
break;
case 022: /* RPDB - 176722 - data buffer */
r = 0;
if ((rhc->cs2 & CS2_OR) == 0) {
rhc->cs2 |= CS2_DLT;
break;
}
temp = rhc->dba;
rhc->dba = rhc->dbb;
rhc->cs2 &= ~CS2_OR;
rhc->cs2 |= CS2_IR;
break;
default:
break;
}
*data = temp;
sim_debug(DEBUG_DETAIL, dptr, "RH%o read %o %d %06o %06o %06o\n", rhc->drive, r, reg,
addr, temp, PC);
/* Check for parity error during access */
if (rhc->cs2 & CS2_PAT) {
uba_set_parity(dibp->uba_ctl);
rhc->error |= ER1_PAR;
}
return r;
}
uint16
uba_rh_vect(struct pdp_dib *dibp)
{
return dibp->uba_vect;
}
#else
/* 0-37 mass bus register. /* 0-37 mass bus register.
70 SBAR, block address. 70 SBAR, block address.
71 STCR, neg block count, func 71 STCR, neg block count, func
@ -446,14 +735,16 @@ t_stat rh_devio(uint32 dev, uint64 *data) {
dptr->name, dev, *data, rhc->drive, PC, rhc->status); dptr->name, dev, *data, rhc->drive, PC, rhc->status);
return SCPE_OK; return SCPE_OK;
} }
rhc->drive = (int)(*data >> 18) & 07;
/* Check if access error */ /* Check if access error */
if (rhc->rae & (1 << rhc->drive)) if (rhc->rae & (1 << rhc->drive))
return SCPE_OK; return SCPE_OK;
/* Start command */ /* Start command */
rh_setup(rhc, (uint32)(*data >> 6));
rhc->xfer_drive = (int)(*data >> 18) & 07;
if (rhc->dev_write(dptr, rhc, 0, (uint32)(*data & 077))) { if (rhc->dev_write(dptr, rhc, 0, (uint32)(*data & 077))) {
rhc->status |= CR_DRE; rhc->status |= CR_DRE;
} else {
rh_setup(rhc, (uint32)(*data >> 6));
rhc->xfer_drive = rhc->drive;
} }
sim_debug(DEBUG_DATAIO, dptr, sim_debug(DEBUG_DATAIO, dptr,
"%s %03o command %012llo, %d PC=%06o %06o\n", "%s %03o command %012llo, %d PC=%06o %06o\n",
@ -506,23 +797,51 @@ rh_devirq(uint32 dev, t_addr addr) {
else if (rhc->imode == 2) /* RH20 style */ else if (rhc->imode == 2) /* RH20 style */
addr = rhc->ivect; addr = rhc->ivect;
} else { } else {
sim_printf("Unable to find device %03o\n\r", dev); sim_printf("Unable to find device %03o\r\n", dev);
} }
return addr; return addr;
} }
#endif
/* Reset the RH to a known clear condiguration */
void rh_reset(DEVICE *dptr, struct rh_if *rhc)
{
rhc->status = 0;
rhc->attn = 0;
rhc->rae = 0;
rhc->wcr = 0;
rhc->cda = 0;
rhc->drive = 0;
// rhc->xfer_drive = -1;
#if KS
rhc->dib = (DIB *)dptr->ctxt;
rhc->cs1 = 0;
rhc->cs2 = CS2_IR;
rhc->dba = 0;
rhc->dbb = 0;
rhc->error = 0;
#endif
}
/* Set the attention flag for a unit */ /* Set the attention flag for a unit */
void rh_setattn(struct rh_if *rhc, int unit) void rh_setattn(struct rh_if *rhc, int unit)
{ {
rhc->attn |= 1<<unit; rhc->attn |= 1<<unit;
#if KS
if ((rhc->status & BUSY) == 0 && (rhc->cs1 & CS1_IE) != 0)
uba_set_irq(rhc->dib, rhc->dib->uba_vect);
#else
if ((rhc->status & BUSY) == 0 && (rhc->status & IADR_ATTN) != 0) if ((rhc->status & BUSY) == 0 && (rhc->status & IADR_ATTN) != 0)
set_interrupt(rhc->devnum, rhc->status); set_interrupt(rhc->devnum, rhc->status);
#endif
} }
void rh_error(struct rh_if *rhc) void rh_error(struct rh_if *rhc)
{ {
#if !KS
if (rhc->imode == 2) if (rhc->imode == 2)
rhc->status |= RH20_DR_EXC; rhc->status |= RH20_DR_EXC;
#endif
} }
/* Decrement block count for RH20, nop for RH10 */ /* Decrement block count for RH20, nop for RH10 */
@ -543,11 +862,17 @@ int rh_blkend(struct rh_if *rhc)
/* Set an IRQ for a DF10 device */ /* Set an IRQ for a DF10 device */
void rh_setirq(struct rh_if *rhc) { void rh_setirq(struct rh_if *rhc) {
rhc->status |= PI_ENABLE; rhc->status |= PI_ENABLE;
#if KS
if ((rhc->status & BUSY) == 0 && (rhc->cs1 & CS1_IE) != 0)
uba_set_irq(rhc->dib, rhc->dib->uba_vect);
#else
set_interrupt(rhc->devnum, rhc->status); set_interrupt(rhc->devnum, rhc->status);
#endif
} }
/* Generate the DF10 complete word */ /* Generate the DF10 complete word */
void rh_writecw(struct rh_if *rhc, int nxm) { void rh_writecw(struct rh_if *rhc, int nxm) {
#if !KS
uint64 wrd1; uint64 wrd1;
#if KL #if KL
if (rhc->imode == 2) { if (rhc->imode == 2) {
@ -598,14 +923,16 @@ void rh_writecw(struct rh_if *rhc, int nxm) {
rhc->cda++; rhc->cda++;
wrd1 = ((uint64)(rhc->ccw & WMASK) << CSHIFT) | ((uint64)(rhc->cda) & AMASK); wrd1 = ((uint64)(rhc->ccw & WMASK) << CSHIFT) | ((uint64)(rhc->cda) & AMASK);
(void)Mem_write_word(rhc->cia|1, &wrd1, 0); (void)Mem_write_word(rhc->cia|1, &wrd1, 0);
#endif
} }
/* Finish off a DF10 transfer */ /* Finish off a DF10 transfer */
void rh_finish_op(struct rh_if *rhc, int nxm) { void rh_finish_op(struct rh_if *rhc, int nxm) {
#if KL #if KL
rhc->status &= ~(CC_CHAN_ACT);
if (rhc->imode != 2) if (rhc->imode != 2)
#endif #endif
rhc->status &= ~BUSY; rhc->status &= ~(BUSY);
rh_writecw(rhc, nxm); rh_writecw(rhc, nxm);
rh_setirq(rhc); rh_setirq(rhc);
#if KL #if KL
@ -621,7 +948,9 @@ void rh_finish_op(struct rh_if *rhc, int nxm) {
void rh20_setup(struct rh_if *rhc) void rh20_setup(struct rh_if *rhc)
{ {
DEVICE *dptr = NULL; DEVICE *dptr = NULL;
uint32 data;
int reg; int reg;
int drv;
for (reg = 0; rh[reg].dev_num != 0; reg++) { for (reg = 0; rh[reg].dev_num != 0; reg++) {
if (rh[reg].rh == rhc) { if (rh[reg].rh == rhc) {
@ -631,15 +960,24 @@ void rh20_setup(struct rh_if *rhc)
} }
if (dptr == 0) if (dptr == 0)
return; return;
rhc->pbar = rhc->sbar; /* Check to see if drive currently doing something */
drv = rhc->drive;
rhc->drive = (rhc->stcr >> 18) & 07;
if (rhc->dev_read != NULL) {
(void)rhc->dev_read(dptr, rhc, 0, &data);
if (data & 1) {
rhc->drive = drv;
return;
}
}
rhc->ptcr = rhc->stcr; rhc->ptcr = rhc->stcr;
/* Read drive status */ rhc->pbar = rhc->sbar;
rhc->drive = (rhc->ptcr >> 18) & 07; rhc->drive = (rhc->ptcr >> 18) & 07;
/* Read drive status */
rhc->status &= ~(RH20_DATA_OVR|RH20_CHAN_RDY|RH20_DR_RESP|RH20_CHAN_ERR|RH20_SHRT_WC|\ rhc->status &= ~(RH20_DATA_OVR|RH20_CHAN_RDY|RH20_DR_RESP|RH20_CHAN_ERR|RH20_SHRT_WC|\
RH20_LONG_WC|RH20_DR_EXC|RH20_SCR_FULL|PI_ENABLE|RH20_XEND); RH20_LONG_WC|RH20_DR_EXC|RH20_SCR_FULL|PI_ENABLE|RH20_XEND);
rhc->status |= RH20_PCR_FULL; rhc->status |= RH20_PCR_FULL;
if (rhc->status & RH20_SBAR) { if (rhc->status & RH20_SBAR) {
rhc->drive = (rhc->pbar >> 18) & 07;
if (rhc->dev_write != NULL) if (rhc->dev_write != NULL)
(void)rhc->dev_write(dptr, rhc, 5, (rhc->pbar & 0177777)); (void)rhc->dev_write(dptr, rhc, 5, (rhc->pbar & 0177777));
rhc->status &= ~RH20_SBAR; rhc->status &= ~RH20_SBAR;
@ -649,28 +987,33 @@ void rh20_setup(struct rh_if *rhc)
rhc->wcr = 0; rhc->wcr = 0;
} }
/* Hold block count in cia */ /* Hold block count in cia */
rhc->drive = (rhc->ptcr >> 18) & 07;
rhc->cia = (rhc->ptcr >> 6) & 01777; rhc->cia = (rhc->ptcr >> 6) & 01777;
if (rhc->dev_write != NULL) if (rhc->dev_write != NULL)
(void)rhc->dev_write(dptr, rhc, 0, (rhc->ptcr & 077)); (void)rhc->dev_write(dptr, rhc, 0, (rhc->ptcr & 077));
rhc->cop = 0; rhc->cop = 0;
rhc->wcr = 0; rhc->wcr = 0;
rhc->xfer_drive = rhc->drive;
rhc->status &= ~RH20_CHAN_RDY; rhc->status &= ~RH20_CHAN_RDY;
rhc->status |= BUSY;
rhc->drive = drv;
} }
#endif #endif
/* Setup for a DF10 transfer */ /* Setup for a DF10 transfer */
void rh_setup(struct rh_if *rhc, uint32 addr) void rh_setup(struct rh_if *rhc, uint32 addr)
{ {
#if !KS
rhc->cia = addr & ICWA; rhc->cia = addr & ICWA;
rhc->ccw = rhc->cia; rhc->ccw = rhc->cia;
rhc->wcr = 0; rhc->wcr = 0;
#endif
rhc->status |= BUSY; rhc->status |= BUSY;
} }
/* Fetch the next IO control word */ /* Fetch the next IO control word */
int rh_fetch(struct rh_if *rhc) { int rh_fetch(struct rh_if *rhc) {
#if !KS
uint64 data; uint64 data;
int reg; int reg;
DEVICE *dptr = NULL; DEVICE *dptr = NULL;
@ -727,12 +1070,30 @@ int rh_fetch(struct rh_if *rhc) {
rhc->wcr = (uint32)((data >> CSHIFT) & WMASK); rhc->wcr = (uint32)((data >> CSHIFT) & WMASK);
rhc->cda = (uint32)(data & AMASK); rhc->cda = (uint32)(data & AMASK);
rhc->ccw = (uint32)((rhc->ccw + 1) & AMASK); rhc->ccw = (uint32)((rhc->ccw + 1) & AMASK);
#endif
return 1; return 1;
} }
/* Read next word */ /* Read next word */
int rh_read(struct rh_if *rhc) { int rh_read(struct rh_if *rhc) {
#if KS
if ((rhc->status & BUSY) == 0)
return 0;
if (uba_read_npr(rhc->cda, rhc->dib->uba_ctl, &rhc->buf) == 0) {
rhc->cs2 |= CS2_NEM;
rhc->status &= ~BUSY;
return 0;
}
if ((rhc->cs2 & CS2_UAI) == 0)
rhc->cda += 4;
rhc->wcr = (rhc->wcr + 2) & 0177777;
if (rhc->wcr == 0) {
rhc->status &= ~BUSY;
return 0;
}
#else
uint64 data; uint64 data;
if (rhc->wcr == 0) { if (rhc->wcr == 0) {
if (!rh_fetch(rhc)) if (!rh_fetch(rhc))
return 0; return 0;
@ -774,11 +1135,28 @@ int rh_read(struct rh_if *rhc) {
if (rhc->wcr == 0) { if (rhc->wcr == 0) {
return rh_fetch(rhc); return rh_fetch(rhc);
} }
#endif
return 1; return 1;
} }
/* Write next word */ /* Write next word */
int rh_write(struct rh_if *rhc) { int rh_write(struct rh_if *rhc) {
#if KS
if ((rhc->status & BUSY) == 0)
return 0;
if (uba_write_npr(rhc->cda, rhc->dib->uba_ctl, rhc->buf) == 0) {
rhc->cs2 |= CS2_NEM;
rhc->status &= ~BUSY;
return 0;
}
if ((rhc->cs2 & CS2_UAI) == 0)
rhc->cda += 4;
rhc->wcr = (rhc->wcr + 2) & 0177777;
if (rhc->wcr == 0) {
rhc->status &= ~BUSY;
return 0;
}
#else
if (rhc->wcr == 0) { if (rhc->wcr == 0) {
if (!rh_fetch(rhc)) if (!rh_fetch(rhc))
return 0; return 0;
@ -817,6 +1195,7 @@ int rh_write(struct rh_if *rhc) {
if (rhc->wcr == 0) { if (rhc->wcr == 0) {
return rh_fetch(rhc); return rh_fetch(rhc);
} }
#endif
return 1; return 1;
} }

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,9 @@
sim_load binary loader sim_load binary loader
*/ */
#if KS
char sim_name[] = "KS-10";
#endif
#if KL #if KL
char sim_name[] = "KL-10"; char sim_name[] = "KL-10";
#endif #endif
@ -62,7 +65,7 @@ int32 sim_emax = 1;
DEVICE *sim_devices[] = { DEVICE *sim_devices[] = {
&cpu_dev, &cpu_dev,
#if PDP6 | KA | KI #if PDP6 | KA | KI | KS
&cty_dev, &cty_dev,
#endif #endif
#if KL #if KL
@ -171,6 +174,9 @@ DEVICE *sim_devices[] = {
#if (NUM_DEVS_III > 0) #if (NUM_DEVS_III > 0)
&iii_dev, &iii_dev,
#endif #endif
#if (NUM_DEVS_TV > 0)
&tv_dev,
#endif
#if NUM_DEVS_IMP > 0 #if NUM_DEVS_IMP > 0
&imp_dev, &imp_dev,
#endif #endif
@ -180,6 +186,9 @@ DEVICE *sim_devices[] = {
#if NUM_DEVS_CH10 > 0 #if NUM_DEVS_CH10 > 0
&ch10_dev, &ch10_dev,
#endif #endif
#if NUM_DEVS_CH11 > 0
&ch11_dev,
#endif
#if NUM_DEVS_IMX > 0 #if NUM_DEVS_IMX > 0
&imx_dev, &imx_dev,
#endif #endif
@ -211,6 +220,21 @@ DEVICE *sim_devices[] = {
#endif #endif
#if NUM_DEVS_AI > 0 #if NUM_DEVS_AI > 0
&ai_dev, &ai_dev,
#endif
#if NUM_DEVS_DZ > 0
&dz_dev,
#endif
#if NUM_DEVS_TCU > 0
&tcu_dev,
#endif
#if NUM_DEVS_KMC > 0
&kmc_dev,
#endif
#if NUM_DEVS_DUP > 0
&dup_dev,
#endif
#if NUM_DEVS_DN > 0
&dn_dev,
#endif #endif
NULL NULL
}; };
@ -279,14 +303,12 @@ t_stat load_dmp (FILE *fileref)
uint64 data; uint64 data;
uint32 high = 0; uint32 high = 0;
while (fgets((char *)buffer, 80, fileref) != 0) { while (fgets(&buffer[0], 80, fileref) != 0) {
p = (char *)buffer;
while (*p >= '0' && *p <= '7') {
data = 0; data = 0;
while (*p >= '0' && *p <= '7') { p = &buffer[0];
if (*p >= '0' && *p <= '7') {
for (; *p >= '0' && *p <= '7'; p++)
data = (data << 3) + *p - '0'; data = (data << 3) + *p - '0';
p++;
}
if (addr == 0135 && data != 0) if (addr == 0135 && data != 0)
high = (uint32)(data & RMASK); high = (uint32)(data & RMASK);
if (high != 0 && high == addr) { if (high != 0 && high == addr) {
@ -294,8 +316,6 @@ t_stat load_dmp (FILE *fileref)
high = 0; high = 0;
} }
M[addr++] = data; M[addr++] = data;
if (*p == ' ' || *p == '\t')
p++;
} }
} }
return SCPE_OK; return SCPE_OK;
@ -585,7 +605,7 @@ t_stat load_sav (FILE *fileref, int ftype)
wc = (int32)(data >> 18); wc = (int32)(data >> 18);
pa = (uint32) (data & RMASK); pa = (uint32) (data & RMASK);
if (wc == (OP_JRST << 9)) { if (wc == (OP_JRST << 9)) {
printf("Start addr=%06o\n", pa); sim_printf("Start addr=%06o\n", pa);
PC = pa; PC = pa;
return SCPE_OK; return SCPE_OK;
} }
@ -769,6 +789,8 @@ t_stat load_exb (FILE *fileref, int ftype)
return SCPE_FMT; return SCPE_FMT;
addr |= byt << 24; addr |= byt << 24;
/* Empty record gives start address */ /* Empty record gives start address */
if (addr > MEMSIZE)
return SCPE_FMT;
if (wc == 0) { if (wc == 0) {
PC = addr; PC = addr;
return SCPE_OK; return SCPE_OK;
@ -784,6 +806,8 @@ t_stat load_exb (FILE *fileref, int ftype)
case 2: word |= ((uint64)byt) << 16; break; case 2: word |= ((uint64)byt) << 16; break;
case 3: word |= ((uint64)byt) << 24; break; case 3: word |= ((uint64)byt) << 24; break;
case 4: word |= ((uint64)(byt & 017)) << 32; case 4: word |= ((uint64)(byt & 017)) << 32;
if (addr > MEMSIZE)
return SCPE_FMT;
M[addr++] = word; M[addr++] = word;
pos = -1; pos = -1;
break; break;
@ -902,7 +926,7 @@ static const char *opcode[] = {
"SETSTS", "STATO", "STATUS", "GETSTS", "INBUF", "OUTBUF", "INPUT", "OUTPUT", "SETSTS", "STATO", "STATUS", "GETSTS", "INBUF", "OUTBUF", "INPUT", "OUTPUT",
"CLOSE", "RELEAS", "MTAPE", "UGETF", "USETI", "USETO", "LOOKUP", "ENTER", "CLOSE", "RELEAS", "MTAPE", "UGETF", "USETI", "USETO", "LOOKUP", "ENTER",
#if KL #if KL | KS
"UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ", "UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ",
"DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV", "DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV",
#else #else
@ -961,6 +985,19 @@ static const char *opcode[] = {
"TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON", "TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON",
"TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON", "TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON",
#if KS
"APRID", "CLRSCH", "RDUBR", "CLRPT",
"WRUBR", "WREBR", "RDEBR",
"RDSPB", "RDCSB", "RDPUR", "RDCSTM",
"RDTIME", "RDINT", "RDHSB", "SPM",
"WRSPB", "WRCSB", "WRPUR", "WRCSTM",
"WRTIME", "WRINT", "WRHSB", "LPMR",
"UMOVE", "UMOVEM",
"TIOE", "TION", "RDIO", "WRIO",
"BSIO", "BCIO",
"TIOEB", "TIONB", "RDIOB", "WRIOB",
"BSIOB", "BCIOB",
#endif
"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */ "BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */
"CONO", "CONI", "CONSZ", "CONSO", "CONO", "CONI", "CONSZ", "CONSO",
@ -1095,9 +1132,21 @@ static const t_int64 opc_val[] = {
0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC, 0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC,
0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC, 0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC,
#if KS
0700000000000+I_OP, 0701000000000+I_OP, 0701040000000+I_OP, 0701100000000+I_OP,
0701140000000+I_OP, 0701200000000+I_OP, 0701240000000+I_OP,
0702000000000+I_OP, 0702040000000+I_OP, 0702100000000+I_OP, 0702140000000+I_OP,
0702200000000+I_OP, 0702240000000+I_OP, 0702300000000+I_OP, 0702340000000+I_OP,
0702400000000+I_OP, 0702440000000+I_OP, 0702500000000+I_OP, 0702540000000+I_OP,
0702600000000+I_OP, 0702640000000+I_OP, 0702700000000+I_OP, 0702740000000+I_OP,
0704000000000+I_AC, 0705000000000+I_AC,
0710000000000+I_AC, 0711000000000+I_AC, 0712000000000+I_AC, 0713000000000+I_AC,
0714000000000+I_AC, 0715000000000+I_AC,
0720000000000+I_AC, 0721000000000+I_AC, 0722000000000+I_AC, 0723000000000+I_AC,
0724000000000+I_AC, 0725000000000+I_AC,
#endif
0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO, 0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO,
0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO, 0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO,
-1 -1
}; };

View file

@ -41,7 +41,6 @@
#define TU_UNIT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE #define TU_UNIT UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE
#define CMD u3 #define CMD u3
/* u3 low */
/* TUC - 00 - control */ /* TUC - 00 - control */
#define CS1_GO 1 /* go */ #define CS1_GO 1 /* go */
@ -64,15 +63,12 @@
#define FNC_READ 034 /* read */ #define FNC_READ 034 /* read */
#define FNC_READREV 037 /* read reverse */ #define FNC_READREV 037 /* read reverse */
#define CS1_DVA 0004000 /* drive avail NI */ #define CS1_DVA 0004000 /* drive avail NI */
#define CS1_TRE 0040000 /* Set if errors */
#define CS1_SC 0100000 /* Set if TRE or ATTN */
#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) #define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC)
#define CS_TM 001000 /* Tape mark sensed */
#define CS_MOTION 002000 /* Tape moving */
#define CS_PIP 004000 /* Tape Position command */
#define CS_ATA 010000 /* Tape signals attention */
#define CS_CHANGE 020000 /* Status changed */
#define STATUS u5 #define TUDS 01
/* u5 low */ #define STATUS u4 /* Attentions status for device */
/* TUDS - 01 - drive status */ /* TUDS - 01 - drive status */
#define DS_SLA 0000001 /* Drive has become ready */ #define DS_SLA 0000001 /* Drive has become ready */
@ -92,7 +88,7 @@
#define DS_ERR 0040000 /* error */ #define DS_ERR 0040000 /* error */
#define DS_ATA 0100000 /* attention active */ #define DS_ATA 0100000 /* attention active */
/* u5 high */ #define TUER1 02
/* TUER1 - 02 - error status 1 */ /* TUER1 - 02 - error status 1 */
#define ER1_ILF 0000001 /* illegal func */ #define ER1_ILF 0000001 /* illegal func */
@ -112,20 +108,27 @@
#define ER1_UNS 0040000 /* drive unsafe */ #define ER1_UNS 0040000 /* drive unsafe */
#define ER1_DCK 0100000 /* data check NI */ #define ER1_DCK 0100000 /* data check NI */
#define TUMR 03
/* TUMR - 03 - maintenace register */ /* TUMR - 03 - maintenace register */
#define TUAS 04
/* TUAS - 04 - attention summary */ /* TUAS - 04 - attention summary */
#define AS_U0 0000001 /* unit 0 flag */ #define AS_U0 0000001 /* unit 0 flag */
#define TUDC 05
/* TUDC - 05 - frame count */ /* TUDC - 05 - frame count */
#define TUDT 06
/* TUDT - 06 - drive type */ /* TUDT - 06 - drive type */
#define TULA 07
/* TULA - 07 - Check Character */ /* TULA - 07 - Check Character */
#define TUSN 010
/* TUSN - 10 - serial number */ /* TUSN - 10 - serial number */
#define TUTC 011
/* TUTC - 11 - Tape control register */ /* TUTC - 11 - Tape control register */
#define TC_SS 0000007 /* Slave select mask */ #define TC_SS 0000007 /* Slave select mask */
#define TC_EVPAR 0000010 /* Even parity */ #define TC_EVPAR 0000010 /* Even parity */
@ -153,12 +156,10 @@
/* TUER3 - 15 - error status 3 - more unsafe conditions - unimplemented */ /* TUER3 - 15 - error status 3 - more unsafe conditions - unimplemented */
#define CPOS u4 #define CPOS u5
#define DATAPTR u6 #define DATAPTR u6
uint8 tu_buf[NUM_DEVS_TU][TU_NUMFR]; uint8 tu_buf[NUM_DEVS_TU][TU_NUMFR];
uint16 tu_frame[NUM_DEVS_TU];
uint16 tu_tcr[NUM_DEVS_TU];
static uint64 tu_boot_buffer; static uint64 tu_boot_buffer;
int tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data); int tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data);
@ -173,6 +174,10 @@ t_stat tu_detach(UNIT *);
t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, t_stat tu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
const char *cptr); const char *cptr);
const char *tu_description (DEVICE *dptr); const char *tu_description (DEVICE *dptr);
#if KS
extern DEVICE *rh_boot_dev;
extern int rh_boot_unit;
#endif
UNIT tu_unit[] = { UNIT tu_unit[] = {
@ -187,6 +192,15 @@ UNIT tu_unit[] = {
{ UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) }, { UDATA (&tu_srv, TU_UNIT+CNTRL_RH(0), 0) },
}; };
#if KS
struct rh_if tu_rh[NUM_DEVS_TU] = {
{ &tu_write, &tu_read},
};
DIB tu_dib[NUM_DEVS_TU] = {
{0772440, 037, 0224, 6, 3, &uba_rh_read, &uba_rh_write, 0, 0, &tu_rh[0]},
};
#else
struct rh_if tu_rh[NUM_DEVS_TU] = { struct rh_if tu_rh[NUM_DEVS_TU] = {
{ &tu_write, &tu_read} { &tu_write, &tu_read}
}; };
@ -194,6 +208,7 @@ struct rh_if tu_rh[NUM_DEVS_TU] = {
DIB tu_dib[] = { DIB tu_dib[] = {
{RH10_DEV, 1, &rh_devio, &rh_devirq, &tu_rh[0]} {RH10_DEV, 1, &rh_devio, &rh_devirq, &tu_rh[0]}
}; };
#endif
MTAB tu_mod[] = { MTAB tu_mod[] = {
#if KL #if KL
@ -202,35 +217,45 @@ MTAB tu_mod[] = {
{MTAB_XTD|MTAB_VDV, TYPE_RH20, "RH20", "RH20", &rh_set_type, &rh_show_type, {MTAB_XTD|MTAB_VDV, TYPE_RH20, "RH20", "RH20", &rh_set_type, &rh_show_type,
NULL, "Sets controller to RH20"}, NULL, "Sets controller to RH20"},
#endif #endif
{ MTAB_XTD|MTAB_VUN, 0, "write enabled", "WRITEENABLED", {MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL},
&set_writelock, &show_writelock, NULL, "Write ring in place" }, {MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL},
{ MTAB_XTD|MTAB_VUN, 1, NULL, "LOCKED",
&set_writelock, NULL, NULL, "no Write ring in place" },
{MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", {MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
&sim_tape_set_fmt, &sim_tape_show_fmt, NULL}, &sim_tape_set_fmt, &sim_tape_show_fmt, NULL},
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LENGTH", "LENGTH", {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "LENGTH", "LENGTH",
&sim_tape_set_capac, &sim_tape_show_capac, NULL}, &sim_tape_set_capac, &sim_tape_show_capac, NULL},
{MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DENSITY", "DENSITY", {MTAB_XTD|MTAB_VUN|MTAB_VALR, 0, "DENSITY", "DENSITY",
&sim_tape_set_dens, &sim_tape_show_dens, NULL}, &sim_tape_set_dens, &sim_tape_show_dens, NULL},
#if KS
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "addr", "addr", &uba_set_addr, uba_show_addr,
NULL, "Sets address of RH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "vect", "vect", &uba_set_vect, uba_show_vect,
NULL, "Sets vect of RH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "br", "br", &uba_set_br, uba_show_br,
NULL, "Sets br of RH11" },
{MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "ctl", "ctl", &uba_set_ctl, uba_show_ctl,
NULL, "Sets uba of RH11" },
#endif
{0} {0}
}; };
REG tua_reg[] = { REG tua_reg[] = {
#if !KS
{ORDATA(IVECT, tu_rh[0].ivect, 18)}, {ORDATA(IVECT, tu_rh[0].ivect, 18)},
{FLDATA(IMODE, tu_rh[0].imode, 0)}, {FLDATA(IMODE, tu_rh[0].imode, 0)},
{ORDATA(FRAME, tu_frame[0], 16)},
{ORDATA(TCR, tu_tcr[0], 16)},
{ORDATA(XFER, tu_rh[0].xfer_drive, 3), REG_HRO}, {ORDATA(XFER, tu_rh[0].xfer_drive, 3), REG_HRO},
{ORDATA(DRIVE, tu_rh[0].drive, 3), REG_HRO},
{ORDATA(REG, tu_rh[0].reg, 6), REG_RO}, {ORDATA(REG, tu_rh[0].reg, 6), REG_RO},
{ORDATA(CIA, tu_rh[0].cia, 18)},
{ORDATA(CCW, tu_rh[0].ccw, 18)},
{ORDATA(DEVNUM, tu_rh[0].devnum, 9), REG_HRO},
#endif
{ORDATA(FRAME, tu_rh[0].regs[TUDC], 16)},
{ORDATA(TCR, tu_rh[0].regs[TUTC], 16)},
{ORDATA(DRIVE, tu_rh[0].drive, 3), REG_HRO},
{ORDATA(RAE, tu_rh[0].rae, 8), REG_RO}, {ORDATA(RAE, tu_rh[0].rae, 8), REG_RO},
{ORDATA(ATTN, tu_rh[0].attn, 8), REG_RO}, {ORDATA(ATTN, tu_rh[0].attn, 8), REG_RO},
{ORDATA(STATUS, tu_rh[0].status, 18), REG_RO}, {ORDATA(STATUS, tu_rh[0].status, 18), REG_RO},
{ORDATA(CIA, tu_rh[0].cia, 18)},
{ORDATA(CCW, tu_rh[0].ccw, 18)},
{ORDATA(WCR, tu_rh[0].wcr, 18)}, {ORDATA(WCR, tu_rh[0].wcr, 18)},
{ORDATA(CDA, tu_rh[0].cda, 18)}, {ORDATA(CDA, tu_rh[0].cda, 18)},
{ORDATA(DEVNUM, tu_rh[0].devnum, 9), REG_HRO},
{ORDATA(BUF, tu_rh[0].buf, 36), REG_HRO}, {ORDATA(BUF, tu_rh[0].buf, 36), REG_HRO},
{BRDATA(BUFF, tu_buf[0], 16, 8, TU_NUMFR), REG_HRO}, {BRDATA(BUFF, tu_buf[0], 16, 8, TU_NUMFR), REG_HRO},
{0} {0}
@ -252,15 +277,16 @@ DEVICE *tu_devs[] = {
int int
tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) { tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
int ctlr = GET_CNTRL_RH(dptr->units[0].flags); int ctlr = GET_CNTRL_RH(dptr->units[0].flags);
int unit = tu_tcr[ctlr] & 07; uint16 *regs = &rhc->regs[0];
int unit = regs[TUTC] & 07;
UNIT *uptr = &dptr->units[unit]; UNIT *uptr = &dptr->units[unit];
int i; int i;
if (rhc->drive != 0 && reg != 04) /* Only one unit at 0 */ if (rhc->drive != 0 && reg != 04) /* Only one unit at 0 */
return 1; return -1;
if (uptr->CMD & CS1_GO) { if ((uptr->CMD & CS1_GO) != 0 || (uptr->STATUS & DS_PIP) != 0) {
uptr->STATUS |= (ER1_RMR); regs[TUER1] |= ER1_RMR;
return 0; return 0;
} }
@ -268,8 +294,25 @@ tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
case 000: /* control */ case 000: /* control */
sim_debug(DEBUG_DETAIL, dptr, "%s%o %d Status=%06o\n", sim_debug(DEBUG_DETAIL, dptr, "%s%o %d Status=%06o\n",
dptr->name, unit, ctlr, uptr->STATUS); dptr->name, unit, ctlr, uptr->STATUS);
if ((data & 01) != 0 && (uptr->flags & UNIT_ATT) != 0) {
uptr->CMD = data & 076; uptr->CMD = data & 076;
if ((data & 01) == 0) {
sim_debug(DEBUG_DETAIL, &tua_dev, "TU%o no go %06o\n", unit, data);
return 0; /* No, nop */
}
if ((uptr->flags & UNIT_ATT) == 0) {
if (GET_FNC(data) == FNC_DCLR) {
uptr->STATUS = 0;
rhc->attn = 0;
for (i = 0; i < NUM_UNITS_TU; i++) {
if (dptr->units[i].STATUS & DS_ATA)
rhc->attn = 1;
}
}
sim_debug(DEBUG_DETAIL, &tua_dev, "TU%o unattached %06o\n", unit, data);
return 0; /* No, nop */
}
switch (GET_FNC(data)) { switch (GET_FNC(data)) {
case FNC_NOP: case FNC_NOP:
break; break;
@ -277,15 +320,15 @@ tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
case FNC_PRESET: /* read-in preset */ case FNC_PRESET: /* read-in preset */
case FNC_READ: /* read */ case FNC_READ: /* read */
case FNC_READREV: /* read w/ headers */ case FNC_READREV: /* read w/ headers */
tu_frame[ctlr] = 0; regs[TUDC] = 0;
tu_tcr[ctlr] |= TC_FCS; regs[TUTC] |= TC_FCS;
/* Fall through */ /* Fall through */
case FNC_WRITE: /* write */ case FNC_WRITE: /* write */
case FNC_SPACEF: /* Space forward */ case FNC_SPACEF: /* Space forward */
case FNC_SPACEB: /* Space backward */ case FNC_SPACEB: /* Space backward */
if ((tu_tcr[ctlr] & TC_FCS) == 0) { if ((regs[TUTC] & TC_FCS) == 0) {
uptr->STATUS |= ER1_NEF; regs[TUER1] |= ER1_NEF;
break; break;
} }
/* Fall through */ /* Fall through */
@ -296,10 +339,13 @@ tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
case FNC_REWIND: /* rewind */ case FNC_REWIND: /* rewind */
case FNC_UNLOAD: /* unload */ case FNC_UNLOAD: /* unload */
case FNC_WCHKREV: /* write w/ headers */ case FNC_WCHKREV: /* write w/ headers */
uptr->CMD |= CS_PIP|CS1_GO; uptr->CMD |= CS1_GO;
uptr->STATUS = DS_PIP;
regs[TUTC] |= TC_ACCL;
regs[TUER1] = 0;
rhc->attn = 0; rhc->attn = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < NUM_UNITS_TU; i++) {
if (dptr->units[i].CMD & CS_ATA) if (dptr->units[i].STATUS & DS_ATA)
rhc->attn = 1; rhc->attn = 1;
} }
CLR_BUF(uptr); CLR_BUF(uptr);
@ -308,53 +354,62 @@ tu_write(DEVICE *dptr, struct rh_if *rhc, int reg, uint32 data) {
break; break;
case FNC_DCLR: /* drive clear */ case FNC_DCLR: /* drive clear */
uptr->CMD &= ~(CS_ATA|CS1_GO|CS_TM); uptr->CMD &= ~(CS1_GO);
uptr->STATUS = 0; uptr->STATUS = 0;
regs[TUER1] = 0;
regs[TUTC] &= ~TC_FCS;
rhc->status &= ~PI_ENABLE; rhc->status &= ~PI_ENABLE;
rhc->attn = 0; rhc->attn = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < NUM_UNITS_TU; i++) {
if (dptr->units[i].CMD & CS_ATA) if (dptr->units[i].STATUS & DS_ATA)
rhc->attn = 1; rhc->attn = 1;
} }
break; break;
default: default:
uptr->STATUS |= (ER1_ILF); regs[TUER1] |= ER1_ILF;
uptr->CMD |= CS_ATA; uptr->STATUS = DS_ATA;
rhc->attn = 1; rhc->attn = 1;
rh_setattn(rhc, 0);
} }
sim_debug(DEBUG_DETAIL, dptr, "%s%o AStatus=%06o\n", dptr->name, unit, sim_debug(DEBUG_DETAIL, dptr, "%s%o AStatus=%06o\n", dptr->name, unit,
uptr->CMD); uptr->CMD);
}
return 0; return 0;
case 001: /* status */ case 001: /* status */
break; break;
case 002: /* error register 1 */ case 002: /* error register 1 */
uptr->STATUS &= ~0177777; regs[TUER1] = data;
uptr->STATUS |= data;
break; break;
case 003: /* maintenance */ case 003: /* maintenance */
regs[TUMR] = data;
fprintf(stderr, "TU MR=%06o\r\n", data);
break; break;
case 004: /* atten summary */ case 004: /* atten summary */
rhc->attn = 0; rhc->attn = 0;
if (data & 1) { if (data & 1) {
for (i = 0; i < 8; i++) for (i = 0; i < NUM_UNITS_TU; i++)
dptr->units[i].CMD &= ~CS_ATA; dptr->units[i].STATUS &= ~DS_ATA;
} }
break; break;
case 005: /* frame count */ case 005: /* frame count */
tu_frame[ctlr] = data & 0177777; regs[TUDC] = data;
tu_tcr[ctlr] |= TC_FCS; regs[TUTC] |= TC_FCS;
break; break;
case 006: /* drive type */ case 006: /* drive type */
case 007: /* look ahead */ case 007: /* look ahead */
case 010: /* look ahead */
break;
case 011: /* tape control register */ case 011: /* tape control register */
tu_tcr[ctlr] = data & 0177777 ; regs[TUTC] = data;
break; break;
default: default:
uptr->STATUS |= ER1_ILR; #if KS
uptr->CMD |= CS_ATA; return 1;
#else
regs[TUER1] |= ER1_ILR;
uptr->STATUS = DS_ATA;
rhc->attn = 1; rhc->attn = 1;
rhc->rae = 1; rhc->rae = 1;
#endif
} }
return 0; return 0;
} }
@ -362,77 +417,76 @@ 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); int ctlr = GET_CNTRL_RH(dptr->units[0].flags);
int unit = tu_tcr[ctlr] & 07; uint16 *regs = &rhc->regs[0];
int unit = regs[TUTC] & 07;
UNIT *uptr = &dptr->units[unit]; UNIT *uptr = &dptr->units[unit];
uint32 temp = 0; uint32 temp = 0;
int i; int i;
if (rhc->drive != 0 && reg != 4) /* Only one unit at 0 */ if (rhc->drive != 0 && reg != 4) /* Only one unit at 0 */
return 1; return -1;
switch(reg) { switch(reg) {
case 000: /* control */ case 000: /* control */
temp = uptr->CMD & 076; temp = uptr->CMD & 077;
temp |= CS1_DVA; temp |= CS1_DVA;
if (uptr->CMD & CS1_GO)
temp |= CS1_GO;
break; break;
case 001: /* status */ case 001: /* status */
temp = DS_DPR; temp = DS_DPR | uptr->STATUS;
if (uptr->CMD & CS_ATA) if (regs[TUER1] != 0)
temp |= DS_ATA;
if (uptr->CMD & CS_CHANGE)
temp |= DS_SSC;
if ((uptr->STATUS & 0177777) != 0)
temp |= DS_ERR; temp |= DS_ERR;
if ((uptr->flags & UNIT_ATT) != 0) { if ((uptr->flags & UNIT_ATT) != 0) {
temp |= DS_MOL; temp |= DS_MOL;
if (uptr->CMD & CS_TM) if ((regs[TUTC] & TC_DENS) == TC_1600)
temp |= DS_TM; temp |= DS_PES;
if (uptr->flags & MTUF_WRP) if (uptr->flags & MTUF_WLK)
temp |= DS_WRL; temp |= DS_WRL;
if ((uptr->CMD & (CS_MOTION|CS_PIP|CS1_GO)) == 0) if ((uptr->CMD & (CS1_GO)) == 0 && (uptr->STATUS & (DS_PIP)) == 0)
temp |= DS_DRY; temp |= DS_DRY;
if (sim_tape_bot(uptr)) if (sim_tape_bot(uptr))
temp |= DS_BOT; temp |= DS_BOT;
if (sim_tape_eot(uptr)) if (sim_tape_eot(uptr))
temp |= DS_EOT; temp |= DS_EOT;
if ((uptr->CMD & CS_MOTION) == 0) if ((uptr->CMD & CS1_GO) == 0)
temp |= DS_SDWN; temp |= DS_SDWN;
if (uptr->CMD & CS_PIP)
temp |= DS_PIP;
} }
break; break;
case 002: /* error register 1 */ case 002: /* error register 1 */
temp = uptr->STATUS & 0177777; temp = regs[TUER1];
break; break;
case 004: /* atten summary */ case 004: /* atten summary */
for (i = 0; i < 8; i++) { for (i = 0; i < NUM_UNITS_TU; i++) {
if (dptr->units[i].CMD & CS_ATA) if (dptr->units[i].STATUS & DS_ATA)
temp |= 1; temp |= 1;
} }
break; break;
case 005: /* frame count */ case 005: /* frame count */
temp = tu_frame[ctlr]; temp = regs[TUDC];
break; break;
case 006: /* drive type */ case 006: /* drive type */
if ((uptr->flags & UNIT_DIS) == 0) if ((uptr->flags & UNIT_DIS) == 0)
temp = 042054; temp = 0142054;
break;
case 011: /* tape control register */
temp = tu_tcr[ctlr];
break; break;
case 010: /* serial no */ case 010: /* serial no */
temp = 020 + (unit + 1); temp = 020 + (unit + 1);
break; break;
case 011: /* tape control register */
temp = regs[TUTC];
break;
case 003: /* maintenance */ case 003: /* maintenance */
temp = regs[TUMR];
break;
case 007: /* look ahead */ case 007: /* look ahead */
break; break;
default: default:
uptr->STATUS |= (ER1_ILR); #if KS
uptr->CMD |= CS_ATA; return 1;
#else
regs[TUER1] |= ER1_ILR;
uptr->STATUS |= DS_ATA;
rhc->attn = 1; rhc->attn = 1;
rhc->rae = 1; rhc->rae = 1;
#endif
} }
*data = temp; *data = temp;
return 0; return 0;
@ -445,18 +499,19 @@ void tu_error(UNIT * uptr, t_stat r)
int ctlr = GET_CNTRL_RH(uptr->flags); int ctlr = GET_CNTRL_RH(uptr->flags);
DEVICE *dptr = tu_devs[ctlr]; DEVICE *dptr = tu_devs[ctlr];
struct rh_if *rhc = &tu_rh[ctlr]; struct rh_if *rhc = &tu_rh[ctlr];
uint16 *regs = &rhc->regs[0];
switch (r) { switch (r) {
case MTSE_OK: /* no error */ case MTSE_OK: /* no error */
break; break;
case MTSE_TMK: /* tape mark */ case MTSE_TMK: /* tape mark */
uptr->CMD |= CS_TM; uptr->STATUS |= DS_TM;
break; break;
case MTSE_WRP: /* write protected */ case MTSE_WRP: /* write protected */
uptr->STATUS |= (ER1_NEF); regs[TUER1] |= ER1_NEF;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
break; break;
case MTSE_UNATT: /* unattached */ case MTSE_UNATT: /* unattached */
@ -466,26 +521,27 @@ void tu_error(UNIT * uptr, t_stat r)
case MTSE_IOERR: /* IO error */ case MTSE_IOERR: /* IO error */
case MTSE_FMT: /* invalid format */ case MTSE_FMT: /* invalid format */
uptr->STATUS |= (ER1_PEF); regs[TUER1] |= ER1_PEF;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
break; break;
case MTSE_RECE: /* error in record */ case MTSE_RECE: /* error in record */
uptr->STATUS |= (ER1_DPAR); regs[TUER1] |= ER1_DPAR;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
break; break;
case MTSE_INVRL: /* invalid rec lnt */ case MTSE_INVRL: /* invalid rec lnt */
uptr->STATUS |= (ER1_FCE); regs[TUER1] |= ER1_FCE;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
break; break;
} }
if (uptr->CMD & CS_ATA) if (uptr->STATUS & DS_ATA)
rh_setattn(rhc, 0); rh_setattn(rhc, 0);
if (GET_FNC(uptr->CMD) >= FNC_XFER && uptr->CMD & (CS_ATA | CS_TM)) if (GET_FNC(uptr->CMD) >= FNC_XFER && uptr->STATUS & (DS_ATA | DS_TM))
rh_error(rhc); rh_error(rhc);
uptr->CMD &= ~(CS_MOTION|CS_PIP|CS1_GO); uptr->CMD &= ~(CS1_GO);
uptr->STATUS &= ~(DS_PIP);
sim_debug(DEBUG_EXP, dptr, "Setting status %d\n", r); sim_debug(DEBUG_EXP, dptr, "Setting status %d\n", r);
} }
@ -495,6 +551,7 @@ t_stat tu_srv(UNIT * uptr)
int ctlr = GET_CNTRL_RH(uptr->flags); int ctlr = GET_CNTRL_RH(uptr->flags);
int unit; int unit;
struct rh_if *rhc; struct rh_if *rhc;
uint16 *regs;
DEVICE *dptr; DEVICE *dptr;
t_stat r; t_stat r;
t_mtrlnt reclen; t_mtrlnt reclen;
@ -505,8 +562,10 @@ t_stat tu_srv(UNIT * uptr)
/* Find dptr, and df10 */ /* Find dptr, and df10 */
dptr = tu_devs[ctlr]; dptr = tu_devs[ctlr];
rhc = &tu_rh[ctlr]; rhc = &tu_rh[ctlr];
regs = &rhc->regs[0];
unit = uptr - dptr->units; unit = uptr - dptr->units;
cc_max = (4 + ((tu_tcr[ctlr] & TC_FMTSEL) == 0)); cc_max = (4 + ((regs[TUTC] & TC_FMTSEL) == 0));
regs[TUTC] &= ~TC_ACCL;
if ((uptr->flags & UNIT_ATT) == 0) { if ((uptr->flags & UNIT_ATT) == 0) {
tu_error(uptr, MTSE_UNATT); /* attached? */ tu_error(uptr, MTSE_UNATT); /* attached? */
rh_setirq(rhc); rh_setirq(rhc);
@ -522,38 +581,35 @@ t_stat tu_srv(UNIT * uptr)
case FNC_REWIND: case FNC_REWIND:
sim_debug(DEBUG_DETAIL, dptr, "%s%o rewind\n", dptr->name, unit); sim_debug(DEBUG_DETAIL, dptr, "%s%o rewind\n", dptr->name, unit);
if (uptr->CMD & CS1_GO) { if (uptr->STATUS & CS1_GO) {
sim_activate(uptr,40000); sim_activate(uptr,40000);
uptr->CMD |= CS_MOTION;
uptr->CMD &= ~(CS1_GO); uptr->CMD &= ~(CS1_GO);
} else { } else {
uptr->CMD &= ~(CS_MOTION|CS_PIP); sim_debug(DEBUG_DETAIL, dptr, "%s%o rewind done\n", dptr->name, unit);
uptr->CMD |= CS_CHANGE|CS_ATA; uptr->STATUS |= DS_SSC|DS_ATA;
rh_setattn(rhc, 0); tu_error(uptr, sim_tape_rewind(uptr));
(void)sim_tape_rewind(uptr);
} }
return SCPE_OK; return SCPE_OK;
case FNC_UNLOAD: case FNC_UNLOAD:
sim_debug(DEBUG_DETAIL, dptr, "%s%o unload\n", dptr->name, unit); sim_debug(DEBUG_DETAIL, dptr, "%s%o unload\n", dptr->name, unit);
uptr->CMD |= CS_CHANGE|CS_ATA; uptr->STATUS |= DS_SSC|DS_ATA;
tu_error(uptr, sim_tape_detach(uptr)); tu_error(uptr, sim_tape_detach(uptr));
return SCPE_OK; return SCPE_OK;
case FNC_WCHKREV: case FNC_WCHKREV:
case FNC_READREV: case FNC_READREV:
if (BUF_EMPTY(uptr)) { if (BUF_EMPTY(uptr)) {
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
if ((r = sim_tape_rdrecr(uptr, &tu_buf[ctlr][0], &reclen, if ((r = sim_tape_rdrecr(uptr, &tu_buf[ctlr][0], &reclen,
TU_NUMFR)) != MTSE_OK) { TU_NUMFR)) != MTSE_OK) {
sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r);
if (r == MTSE_BOT) if (r == MTSE_BOT)
uptr->STATUS |= ER1_NEF; regs[TUER1] |= ER1_NEF;
tu_error(uptr, r); tu_error(uptr, r);
rh_finish_op(rhc, 0); rh_finish_op(rhc, 0);
} else { } else {
sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d\n", dptr->name, unit, reclen); sim_debug(DEBUG_DETAIL, dptr, "%s%o read %d\n", dptr->name, unit, reclen);
uptr->CMD |= CS_MOTION;
uptr->hwmark = reclen; uptr->hwmark = reclen;
uptr->DATAPTR = uptr->hwmark-1; uptr->DATAPTR = uptr->hwmark-1;
uptr->CPOS = cc_max; uptr->CPOS = cc_max;
@ -563,7 +619,9 @@ t_stat tu_srv(UNIT * uptr)
return SCPE_OK; return SCPE_OK;
} }
if (uptr->DATAPTR >= 0) { if (uptr->DATAPTR >= 0) {
tu_frame[ctlr]++; regs[TUDC]++;
if (regs[TUDC] == 0)
regs[TUTC] &= ~TC_FCS;
cc = (8 * (3 - uptr->CPOS)) + 4; cc = (8 * (3 - uptr->CPOS)) + 4;
ch = tu_buf[ctlr][uptr->DATAPTR]; ch = tu_buf[ctlr][uptr->DATAPTR];
if (cc < 0) if (cc < 0)
@ -596,13 +654,12 @@ t_stat tu_srv(UNIT * uptr)
case FNC_WCHK: case FNC_WCHK:
case FNC_READ: case FNC_READ:
if (BUF_EMPTY(uptr)) { if (BUF_EMPTY(uptr)) {
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
uptr->CMD |= CS_MOTION;
if ((r = sim_tape_rdrecf(uptr, &tu_buf[ctlr][0], &reclen, if ((r = sim_tape_rdrecf(uptr, &tu_buf[ctlr][0], &reclen,
TU_NUMFR)) != MTSE_OK) { TU_NUMFR)) != MTSE_OK) {
sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r); sim_debug(DEBUG_DETAIL, dptr, "%s%o read error %d\n", dptr->name, unit, r);
if (r == MTSE_TMK) if (r == MTSE_TMK)
uptr->STATUS |= ER1_FCE; regs[TUER1] |= ER1_FCE;
tu_error(uptr, r); tu_error(uptr, r);
rh_finish_op(rhc, 0); rh_finish_op(rhc, 0);
} else { } else {
@ -616,7 +673,9 @@ t_stat tu_srv(UNIT * uptr)
return SCPE_OK; return SCPE_OK;
} }
if ((uint32)uptr->DATAPTR < uptr->hwmark) { if ((uint32)uptr->DATAPTR < uptr->hwmark) {
tu_frame[ctlr]++; regs[TUDC]++;
if (regs[TUDC] == 0)
regs[TUTC] &= ~TC_FCS;
cc = (8 * (3 - uptr->CPOS)) + 4; cc = (8 * (3 - uptr->CPOS)) + 4;
ch = tu_buf[ctlr][uptr->DATAPTR]; ch = tu_buf[ctlr][uptr->DATAPTR];
if (cc < 0) if (cc < 0)
@ -644,8 +703,8 @@ t_stat tu_srv(UNIT * uptr)
dptr->name, unit, rhc->buf); dptr->name, unit, rhc->buf);
rh_write(rhc); rh_write(rhc);
} }
if (tu_frame[ctlr] != 0) if (regs[TUDC] != 0)
uptr->STATUS |= ER1_FCE; regs[TUER1] |= ER1_FCE;
tu_error(uptr, MTSE_OK); tu_error(uptr, MTSE_OK);
(void)rh_blkend(rhc); (void)rh_blkend(rhc);
rh_finish_op(rhc, 0); rh_finish_op(rhc, 0);
@ -655,31 +714,29 @@ t_stat tu_srv(UNIT * uptr)
case FNC_WRITE: case FNC_WRITE:
if (BUF_EMPTY(uptr)) { if (BUF_EMPTY(uptr)) {
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
if (tu_frame[ctlr] == 0) { if (regs[TUDC] == 0) {
uptr->STATUS |= ER1_NEF; regs[TUER1] |= ER1_NEF;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
rhc->attn = 1; rhc->attn = 1;
tu_error(uptr, MTSE_OK); tu_error(uptr, MTSE_OK);
rh_finish_op(rhc, 0); rh_finish_op(rhc, 0);
return SCPE_OK; return SCPE_OK;
} }
if ((uptr->flags & MTUF_WRP) != 0) { if ((uptr->flags & MTUF_WLK) != 0) {
tu_error(uptr, MTSE_WRP); tu_error(uptr, MTSE_WRP);
rh_finish_op(rhc, 0); rh_finish_op(rhc, 0);
return SCPE_OK; return SCPE_OK;
} }
uptr->CMD |= CS_MOTION;
sim_debug(DEBUG_EXP, dptr, "%s%o Init write\n", dptr->name, unit); sim_debug(DEBUG_EXP, dptr, "%s%o Init write\n", dptr->name, unit);
uptr->hwmark = 0; uptr->hwmark = 0;
uptr->CPOS = 0; uptr->CPOS = 0;
uptr->DATAPTR = 0; uptr->DATAPTR = 0;
rhc->buf = 0; rhc->buf = 0;
} }
if (tu_frame[ctlr] != 0 && uptr->CPOS == 0 && rh_read(rhc) == 0) if (regs[TUDC] != 0 && uptr->CPOS == 0 && rh_read(rhc) == 0)
uptr->CPOS |= 010; uptr->CPOS |= 010;
if ((uptr->CMD & CS_MOTION) != 0) {
if (uptr->CPOS == 0) if (uptr->CPOS == 0)
sim_debug(DEBUG_DATA, dptr, "%s%o write %012llo\n", sim_debug(DEBUG_DATA, dptr, "%s%o write %012llo\n",
dptr->name, unit, rhc->buf); dptr->name, unit, rhc->buf);
@ -696,11 +753,10 @@ t_stat tu_srv(UNIT * uptr)
if ((uptr->CPOS & 7) == cc_max) { if ((uptr->CPOS & 7) == cc_max) {
uptr->CPOS &= 010; uptr->CPOS &= 010;
} }
tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1); regs[TUDC]++;
if (tu_frame[ctlr] == 0) { if (regs[TUDC] == 0) {
uptr->CPOS = 010; uptr->CPOS = 010;
tu_tcr[ctlr] &= ~(TC_FCS); regs[TUTC] &= ~(TC_FCS);
}
} }
if (uptr->CPOS == 010) { if (uptr->CPOS == 010) {
/* Write out the block */ /* Write out the block */
@ -718,9 +774,9 @@ t_stat tu_srv(UNIT * uptr)
break; break;
case FNC_WTM: case FNC_WTM:
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
if ((uptr->flags & MTUF_WRP) != 0) { if ((uptr->flags & MTUF_WLK) != 0) {
tu_error(uptr, MTSE_WRP); tu_error(uptr, MTSE_WRP);
} else { } else {
tu_error(uptr, sim_tape_wrtmk(uptr)); tu_error(uptr, sim_tape_wrtmk(uptr));
@ -729,9 +785,10 @@ t_stat tu_srv(UNIT * uptr)
return SCPE_OK; return SCPE_OK;
case FNC_ERASE: case FNC_ERASE:
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
if ((uptr->flags & MTUF_WRP) != 0) { sim_tape_sprecf(uptr, &reclen);
if ((uptr->flags & MTUF_WLK) != 0) {
tu_error(uptr, MTSE_WRP); tu_error(uptr, MTSE_WRP);
} else { } else {
tu_error(uptr, sim_tape_wrgap(uptr, 35)); tu_error(uptr, sim_tape_wrgap(uptr, 35));
@ -741,47 +798,42 @@ t_stat tu_srv(UNIT * uptr)
case FNC_SPACEF: case FNC_SPACEF:
case FNC_SPACEB: case FNC_SPACEB:
sim_debug(DEBUG_DETAIL, dptr, "%s%o space %o\n", dptr->name, unit, GET_FNC(uptr->CMD)); sim_debug(DEBUG_DETAIL, dptr, "%s%o space %06o %o\n", dptr->name, unit, regs[TUDC], GET_FNC(uptr->CMD));
uptr->CMD &= ~CS_PIP; uptr->STATUS &= ~DS_PIP;
if (tu_frame[ctlr] == 0) {
uptr->STATUS |= ER1_NEF;
uptr->CMD |= CS_ATA;
tu_error(uptr, MTSE_OK);
return SCPE_OK;
}
uptr->CMD |= CS_MOTION;
/* Always skip at least one record */ /* Always skip at least one record */
if (GET_FNC(uptr->CMD) == FNC_SPACEF) if (GET_FNC(uptr->CMD) == FNC_SPACEF)
r = sim_tape_sprecf(uptr, &reclen); r = sim_tape_sprecf(uptr, &reclen);
else else
r = sim_tape_sprecr(uptr, &reclen); r = sim_tape_sprecr(uptr, &reclen);
tu_frame[ctlr] = 0177777 & (tu_frame[ctlr] + 1); regs[TUDC]++;
if (regs[TUDC] == 0)
regs[TUTC] &= ~TC_FCS;
switch (r) { switch (r) {
case MTSE_OK: /* no error */ case MTSE_OK: /* no error */
break; break;
case MTSE_BOT: /* beginning of tape */ case MTSE_BOT: /* beginning of tape */
uptr->STATUS |= ER1_NEF; regs[TUER1] |= ER1_NEF;
/* Fall Through */ /* Fall Through */
case MTSE_TMK: /* tape mark */ case MTSE_TMK: /* tape mark */
case MTSE_EOM: /* end of medium */ case MTSE_EOM: /* end of medium */
if (tu_frame[ctlr] != 0) if (regs[TUDC] != 0)
uptr->STATUS |= ER1_FCE; regs[TUER1] |= ER1_FCE;
else uptr->STATUS |= DS_ATA;
tu_tcr[ctlr] &= ~(TC_FCS);
uptr->CMD |= CS_ATA;
/* Stop motion if we recieve any of these */ /* Stop motion if we recieve any of these */
tu_error(uptr, r); tu_error(uptr, r);
sim_debug(DEBUG_DETAIL, dptr, "%s%o space finish %06o %o\n", dptr->name, unit, regs[TUDC], GET_FNC(uptr->CMD));
return SCPE_OK; return SCPE_OK;
} }
if (tu_frame[ctlr] == 0) { if (regs[TUDC] == 0) {
uptr->CMD |= CS_ATA; uptr->STATUS |= DS_ATA;
tu_error(uptr, MTSE_OK); tu_error(uptr, MTSE_OK);
sim_debug(DEBUG_DETAIL, dptr, "%s%o space finish1 %06o %o\n", dptr->name, unit, regs[TUDC], GET_FNC(uptr->CMD));
return SCPE_OK; return SCPE_OK;
} else { } else {
tu_tcr[ctlr] &= ~(TC_FCS);
sim_activate(uptr, reclen * 100); sim_activate(uptr, reclen * 100);
sim_debug(DEBUG_DETAIL, dptr, "%s%o space cont %06o %o\n", dptr->name, unit, regs[TUDC], GET_FNC(uptr->CMD));
} }
return SCPE_OK; return SCPE_OK;
} }
@ -795,11 +847,12 @@ t_stat tu_srv(UNIT * uptr)
t_stat t_stat
tu_reset(DEVICE * dptr) tu_reset(DEVICE * dptr)
{ {
int ctlr; struct rh_if *rhc = &tu_rh[0];
for (ctlr = 0; ctlr < NUM_DEVS_TU; ctlr++) { uint16 *regs = &rhc->regs[0];
tu_rh[ctlr].attn = 0;
tu_rh[ctlr].rae = 0; rh_reset(dptr, &tu_rh[0]);
} regs[TUER1] = 0;
regs[TUTC] = TC_1600;
return SCPE_OK; return SCPE_OK;
} }
@ -823,6 +876,9 @@ t_stat
tu_boot(int32 unit_num, DEVICE * dptr) tu_boot(int32 unit_num, DEVICE * dptr)
{ {
UNIT *uptr = &dptr->units[unit_num]; UNIT *uptr = &dptr->units[unit_num];
int ctlr = GET_CNTRL_RH(uptr->flags);
struct rh_if *rhc = &tu_rh[ctlr];
uint16 *regs = &rhc->regs[0];
t_mtrlnt reclen; t_mtrlnt reclen;
t_stat r; t_stat r;
uint32 addr; uint32 addr;
@ -834,6 +890,36 @@ tu_boot(int32 unit_num, DEVICE * dptr)
r = sim_tape_rewind(uptr); r = sim_tape_rewind(uptr);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
uptr->CMD = 0;
#if KS
/* Skip first file, which is micro code */
while (r == MTSE_OK)
r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR);
if (r != MTSE_TMK)
return r;
/* Next read in the boot block */
r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR);
if (r != MTSE_OK)
return r;
uptr->DATAPTR = 0;
uptr->hwmark = reclen;
wc = reclen;
addr = 01000;
while (uptr->DATAPTR < wc) {
tu_read_word(uptr);
M[addr] = tu_boot_buffer;
addr ++;
}
regs[TUTC] |= unit_num;
M[036] = rhc->dib->uba_addr | (rhc->dib->uba_ctl << 18);
M[037] = 0;
M[040] = regs[TUTC];
PC = 01000;
rh_boot_dev = dptr;
rh_boot_unit = unit_num;
#else
r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR); r = sim_tape_rdrecf(uptr, &tu_buf[0][0], &reclen, TU_NUMFR);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
@ -865,6 +951,8 @@ tu_boot(int32 unit_num, DEVICE * dptr)
M[addr] = tu_boot_buffer; M[addr] = tu_boot_buffer;
PC = tu_boot_buffer & RMASK; PC = tu_boot_buffer & RMASK;
regs[TUTC] |= unit_num;
#endif
return SCPE_OK; return SCPE_OK;
} }
@ -879,7 +967,7 @@ tu_attach(UNIT * uptr, CONST char *file)
uptr->STATUS = 0; uptr->STATUS = 0;
r = sim_tape_attach_ex(uptr, file, 0, 0); r = sim_tape_attach_ex(uptr, file, 0, 0);
if (r == SCPE_OK && (sim_switches & SIM_SW_REST) == 0) { if (r == SCPE_OK && (sim_switches & SIM_SW_REST) == 0) {
uptr->CMD = CS_ATA|CS_CHANGE; uptr->STATUS = DS_ATA|DS_SSC;
rh_setattn(rhc, 0); rh_setattn(rhc, 0);
} }
return r; return r;
@ -891,9 +979,7 @@ tu_detach(UNIT * uptr)
int ctlr = GET_CNTRL_RH(uptr->flags); int ctlr = GET_CNTRL_RH(uptr->flags);
struct rh_if *rhc = &tu_rh[ctlr]; struct rh_if *rhc = &tu_rh[ctlr];
/* Find df10 */ uptr->STATUS = DS_ATA|DS_SSC;
uptr->STATUS = 0;
uptr->CMD = CS_ATA|CS_CHANGE;
rh_setattn(rhc, 0); rh_setattn(rhc, 0);
return sim_tape_detach(uptr); return sim_tape_detach(uptr);
} }
@ -910,6 +996,17 @@ fprint_show_help (st, dptr);
fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n"); fprintf (st, "\nThe type options can be used only when a unit is not attached to a file.\n");
fprintf (st, "The TU device supports the BOOT command.\n"); fprintf (st, "The TU device supports the BOOT command.\n");
sim_tape_attach_help (st, dptr, uptr, flag, cptr); sim_tape_attach_help (st, dptr, uptr, flag, cptr);
#if KS
fprintf (st, "The RH11 is a unibus device, various parameters can be changed on these devices\n");
fprintf (st, "\n The address of the device can be set with: \n");
fprintf (st, " sim> SET TUA ADDR=octal default address= 772440\n");
fprintf (st, "\n The interrupt vector can be set with: \n");
fprintf (st, " sim> SET TUA VECT=octal default 224\n");
fprintf (st, "\n The interrupt level can be set with: \n");
fprintf (st, " sim> SET TUA BR=# # should be between 4 and 7.\n");
fprintf (st, "\n The unibus addaptor that the DZ is on can be set with:\n");
fprintf (st, " sim> SET TUA CTL=# # can be either 1 or 3\n");
#endif
fprint_reg_help (st, dptr); fprint_reg_help (st, dptr);
return SCPE_OK; return SCPE_OK;
} }

View file

@ -118,7 +118,7 @@ dct_devio(uint32 dev, uint64 *data) {
clr_interrupt(dev); clr_interrupt(dev);
if (uptr->STATUS & DB_RQ) { if (uptr->STATUS & DB_RQ) {
*data = dct_buf[u]; *data = dct_buf[u];
uptr->STATUS &= ~(DB_RQ); uptr->STATUS &= ~(NUM_CHARS|DB_RQ);
uptr->STATUS |= DB_MV; uptr->STATUS |= DB_MV;
sim_activate(uptr, 10); sim_activate(uptr, 10);
} }
@ -132,7 +132,7 @@ dct_devio(uint32 dev, uint64 *data) {
dev, *data, u, PC); dev, *data, u, PC);
if (uptr->STATUS & DB_RQ) { if (uptr->STATUS & DB_RQ) {
dct_buf[u] = *data; dct_buf[u] = *data;
uptr->STATUS &= ~(DB_RQ); uptr->STATUS &= ~(NUM_CHARS|DB_RQ);
uptr->STATUS |= DB_MV; uptr->STATUS |= DB_MV;
sim_activate(uptr, 10); sim_activate(uptr, 10);
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
doc/ks10_doc.doc Normal file

Binary file not shown.

Binary file not shown.