blob: 66cdc61b20775d21101e534e6708df45cb24edda [file] [log] [blame] [raw]
/* pdp11_io_lib.c: Unibus/Qbus common support routines
Copyright (c) 1993-2017, Robert M Supnik
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.
*/
#if defined (VM_PDP10) /* PDP10 version */
#include "pdp10_defs.h"
#elif defined (VM_VAX) /* VAX version */
#include "vax_defs.h"
#else /* PDP-11 version */
#include "pdp11_defs.h"
#endif
#include "sim_sock.h"
#include "sim_tmxr.h"
#include "sim_ether.h"
extern int32 int_vec[IPL_HLVL][32];
#if !defined(VEC_SET)
#define VEC_SET 0
#endif
#if (VEC_SET != 0)
extern int32 int_vec_set[IPL_HLVL][32]; /* bits to set in vector */
#endif
extern int32 (*int_ack[IPL_HLVL][32])(void);
extern t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md);
extern t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md);
extern t_stat build_dib_tab (void);
static DIB *iodibp[IOPAGESIZE >> 1];
static void build_vector_tab (void);
#if !defined(UNIMEMSIZE)
#define UNIMEMSIZE 001000000 /* 2**18 */
#endif
#define AUTO_MAXC 32 /* Maximum number of controllers */
#define AUTO_CSRBASE 0010
#define AUTO_CSRMAX 04000
#define AUTO_VECBASE 0300
/* Enable/disable autoconfiguration */
t_stat set_autocon (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (cptr != NULL)
return SCPE_ARG;
autcon_enb = val;
return auto_config (NULL, 0);
}
/* Show autoconfiguration status */
t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
fprintf (st, "autoconfiguration ");
fprintf (st, autcon_enb? "enabled": "disabled");
return SCPE_OK;
}
/* Change device address */
t_stat set_addr (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newba;
t_stat r;
if (cptr == NULL)
return SCPE_ARG;
if ((val == 0) || (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;
newba = (uint32) get_uint (cptr, DEV_RDX, IOPAGEBASE+IOPAGEMASK, &r); /* get new */
if (r != SCPE_OK)
return r;
if ((newba <= IOPAGEBASE) || /* > IO page base? */
(newba % ((uint32) val))) /* check modulus */
return SCPE_ARG;
dibp->ba = newba; /* store */
autcon_enb = 0; /* autoconfig off */
return SCPE_OK;
}
/* Show device address */
t_stat show_addr (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 radix = DEV_RDX;
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) || (dibp->ba <= IOPAGEBASE))
return SCPE_IERR;
if (sim_switches & SWMASK ('H'))
radix = 16;
if (sim_switches & SWMASK ('O'))
radix = 8;
fprintf (st, "address=");
fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT);
if (radix != DEV_RDX) {
fprintf (st, "(");
fprint_val (st, (t_value) dibp->ba, radix, 32, PV_LEFT);
fprintf (st, ")");
}
if (dibp->lnt > 1) {
fprintf (st, "-");
fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT);
if (radix != DEV_RDX) {
fprintf (st, "(");
fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, radix, 32, PV_LEFT);
fprintf (st, ")");
}
}
if (dibp->ba < IOPAGEBASE + AUTO_CSRBASE + AUTO_CSRMAX)
fprintf (st, "*");
return SCPE_OK;
}
/* Set address floating */
t_stat set_addr_flt (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
if (cptr != NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
return SCPE_IERR;
return auto_config (NULL, 0); /* autoconfigure */
}
/* Change device vector */
t_stat set_vec (UNIT *uptr, int32 arg, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 newvec;
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;
newvec = (uint32) get_uint (cptr, DEV_RDX, 01000, &r);
if ((r != SCPE_OK) ||
((newvec + (dibp->vnum * 4)) >= 01000) || /* total too big? */
(newvec & ((dibp->vnum > 1)? 07: 03))) /* properly aligned value? */
return SCPE_ARG;
dibp->vec = newvec;
autcon_enb = 0; /* autoconfig off */
return SCPE_OK;
}
/* Show device vector */
t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
uint32 vec, numvec, br_lvl, radix = DEV_RDX;
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;
if (sim_switches & SWMASK ('H'))
radix = 16;
if (sim_switches & SWMASK ('O'))
radix = 8;
vec = dibp->vec;
if (arg)
numvec = arg;
else
numvec = dibp->vnum;
if (vec == 0)
fprintf (st, "no vector");
else {
#if (VEC_SET != 0)
vec |= (int_vec_set[dibp->vloc / 32][dibp->vloc % 32] & ~3);
vec &= (int_vec_set[dibp->vloc / 32][dibp->vloc % 32] | 0x1FF);
#endif
fprintf (st, "vector=");
fprint_val (st, (t_value) vec, DEV_RDX, 16, PV_LEFT);
if (radix != DEV_RDX) {
fprintf (st, "(");
fprint_val (st, (t_value) vec, radix, 16, PV_LEFT);
fprintf (st, ")");
}
if (numvec > 1) {
fprintf (st, "-");
fprint_val (st, (t_value) vec + (4 * (numvec - 1)), DEV_RDX, 16, PV_LEFT);
if (radix != DEV_RDX) {
fprintf (st, "(");
fprint_val (st, (t_value) vec + (4 * (numvec - 1)), radix, 16, PV_LEFT);
fprintf (st, ")");
}
}
}
if (vec >= ((VEC_SET | AUTO_VECBASE) & ~3))
fprintf (st, "*");
br_lvl = dibp->vloc / 32;
if (br_lvl < 4) /* VAXen do 0-3, others 4-7 */
br_lvl = br_lvl + 4;
fprintf (st, ", BR%d", br_lvl);
return SCPE_OK;
}
/* Show vector for terminal multiplexor */
t_stat show_vec_mux (FILE *st, UNIT *uptr, int32 arg, CONST void *desc)
{
const TMXR *mp = (const TMXR *) desc;
if ((mp == NULL) || (arg == 0))
return SCPE_IERR;
return show_vec (st, uptr, ((mp->lines * 2) / arg), desc);
}
/* Init Unibus tables */
void init_ubus_tab (void)
{
size_t i, j;
build_vector_tab ();
for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */
for (j = 0; j < 32; j++) {
int_vec[i][j] = 0;
int_ack[i][j] = NULL;
}
}
for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */
iodispR[i] = NULL;
iodispW[i] = NULL;
iodibp[i] = NULL;
}
return;
}
/* Build Unibus tables */
t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp)
{
int32 i, idx, vec, hivec, ilvl, ibit;
DEVICE *cdptr;
size_t j;
const char *cdname;
if ((dptr == NULL) || (dibp == NULL)) /* validate args */
return SCPE_IERR;
if (dibp->vnum > VEC_DEVMAX)
return SCPE_IERR;
vec = dibp->vec;
ilvl = dibp->vloc / 32;
ibit = dibp->vloc % 32;
#if (VEC_SET != 0)
if (vec)
vec |= (int_vec_set[ilvl][ibit] & ~3);
#endif
/* hivec & cdhivec are first vector AFTER device */
hivec = vec + (dibp->vnum * 4 * (dibp->ulnt? dibp->lnt/dibp->ulnt:
(dptr->numunits? dptr->numunits: 1)));
/* Check for vector conflict with any other enabled device.
* Skip vector checks if device (currently) doesn't have a vector assigned.
* Also skip if power-up reset to allow for auto-configure.
*/
if (vec && !(sim_switches & SWMASK ('P'))) {
for (j = 0; vec && (cdptr = sim_devices[j]) != NULL; j++) {
DIB *cdibp = (DIB *)(cdptr->ctxt);
int32 cdvec, cdhivec;
if (!cdibp || (cdptr->flags & DEV_DIS)) {
continue;
}
cdvec = cdibp->vec;
ilvl = cdibp->vloc / 32;
ibit = cdibp->vloc % 32;
#if (VEC_SET != 0)
if (cdvec)
cdvec |= (int_vec_set[ilvl][ibit] & ~3);
#endif
cdhivec = cdvec + (cdibp->vnum * 4 *
(cdibp->ulnt? cdibp->lnt/cdibp->ulnt:
(cdptr->numunits? cdptr->numunits: 1)));
if (cdptr == dptr || !cdvec || !dibp->vnum) {
continue;
}
if (hivec <= cdvec || vec >= cdhivec) {
continue;
}
cdname = cdptr? sim_dname(cdptr): NULL;
if (!cdname) {
cdname = "CPU";
}
return sim_messagef (SCPE_STOP, (DEV_RDX == 16) ?
"Device %s interrupt vector conflict with %s at 0x%X\n" :
"Device %s interrupt vector conflict with %s at 0%o\n",
sim_dname (dptr), cdname, (int)dibp->vec);
}
}
/* Interrupt slot assignment and conflict check. */
for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */
idx = dibp->vloc + i; /* vector index */
vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */
ilvl = idx / 32;
ibit = idx % 32;
#if (VEC_SET != 0)
if (vec)
vec |= (int_vec_set[ilvl][ibit] & ~3);
#endif
if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */
(int_ack[ilvl][ibit] != dibp->ack[i])) ||
(int_vec[ilvl][ibit] && vec &&
(int_vec[ilvl][ibit] != vec))) {
return sim_messagef (SCPE_STOP, "Device %s interrupt slot conflict at %d\n",
sim_dname (dptr), idx);
}
if (dibp->ack[i])
int_ack[ilvl][ibit] = dibp->ack[i];
else {
if (vec)
int_vec[ilvl][ibit] = vec;
}
}
/* Register I/O space address and check for conflicts */
for (i = 0; i < (int32) dibp->lnt; i = i + 2) { /* create entries */
idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */
if ((iodispR[idx] && dibp->rd && /* conflict? */
(iodispR[idx] != dibp->rd)) ||
(iodispW[idx] && dibp->wr &&
(iodispW[idx] != dibp->wr))) {
for (j = 0; (cdptr = sim_devices[j]) != NULL; j++) { /* Find conflicting device */
DIB *cdibp = (DIB *)(cdptr->ctxt);
if ((cdptr->flags & DEV_DIS) || !cdibp || cdibp == dibp) {
continue;
}
if ((iodispR[idx] && dibp->rd &&
(iodispR[idx] != dibp->rd) &&
(cdibp->rd == iodispR[idx])) ||
(iodispW[idx] && dibp->wr &&
(iodispW[idx] != dibp->wr) &&
(cdibp->wr == iodispW[idx]))) {
break;
}
}
cdname = cdptr? sim_dname(cdptr): NULL;
if (!cdname) {
cdname = "CPU";
}
return sim_messagef (SCPE_STOP, (DEV_RDX == 16) ?
"Device %s address conflict with %s at 0x%X\n" :
"Device %s address conflict with %s at 0%o\n",
sim_dname (dptr), cdname, (int)dibp->ba);
}
if (dibp->rd) /* set rd dispatch */
iodispR[idx] = dibp->rd;
if (dibp->wr) /* set wr dispatch */
iodispW[idx] = dibp->wr;
iodibp[idx] = dibp; /* remember DIB */
}
return SCPE_OK;
}
/* Show IO space */
t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
uint32 i, j;
DEVICE *dptr;
DIB *dibp;
uint32 maxaddr, maxname, maxdev;
int32 maxvec, vecwid;
int32 brbase = 0;
char valbuf[40];
#if defined DEV_RDX && DEV_RDX == 16
#define VEC_FMT "X"
#else
#define VEC_FMT "o"
#endif
if (build_dib_tab ()) /* build IO page */
return SCPE_OK;
maxaddr = 0;
maxvec = 0;
maxname = 0;
maxdev = 1;
#if defined (VM_VAX)
brbase = 4;
#endif
for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
size_t l;
if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
dibp = iodibp[i]; /* DIB for block */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
if (((DIB*) sim_devices[j]->ctxt) == dibp) {
dptr = sim_devices[j]; /* locate device */
break;
} /* end if */
} /* end for j */
if ((dibp->ba+ dibp->lnt - 1) > maxaddr)
maxaddr = dibp->ba+ dibp->lnt - 1;
if (dibp->vec > maxvec)
maxvec = dibp->vec;
l = strlen (dptr? sim_dname (dptr): "CPU");
if (l>maxname)
maxname = (int32)l;
j = (dibp->ulnt? dibp->lnt/dibp->ulnt:
(dptr? dptr->numunits: 1));
if (j > maxdev)
maxdev = j;
} /* end if */
} /* end for i */
maxaddr = fprint_val (NULL, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT);
sprintf (valbuf, "%03" VEC_FMT, maxvec);
vecwid = maxvec = (int32) strlen (valbuf);
if (vecwid < 3)
vecwid = 3;
sprintf (valbuf, "%u", maxdev);
maxdev = (uint32)strlen (valbuf);
j = strlen ("Address");
i = (maxaddr*2)+3+1;
if (i <= j)
i = 0;
else
i -= j;
maxaddr = i+j;
fprintf (st, "%*.*sAddress%*.*s", i/2, i/2, " ", (i/2)+i%2, (i/2)+i%2, " ");
j = strlen ("Vector");
i = ((maxvec*2)+1+1);
if (i <= j)
i = 0;
else
i -= j;
maxvec = i+j;
fprintf (st, " %*.*sVector%*.*s", i/2, i/2, " ", (i/2)+i%2, (i/2)+i%2, " ");
fprintf (st, " BR %*.*s# Device\n", (maxdev -1), (maxdev-1), " ");
for (i = 0; i < maxaddr; i++)
fputc ('-', st);
fprintf (st, " ");
for (i = 0; i < (uint32)maxvec; i++)
fputc ('-', st);
fprintf (st, " -- ");
for (i=0; i < maxdev; i++) {
fputc ('-', st);
}
fputc (' ', st);
i = strlen ("Device");
if (maxname < i)
maxname = i;
for (i = 0; i < maxname; i++)
fputc ('-', st);
fputc ('\n', st);
for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */
if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */
dibp = iodibp[i]; /* DIB for block */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
if (((DIB*) sim_devices[j]->ctxt) == dibp) {
dptr = sim_devices[j]; /* locate device */
break;
} /* end if */
} /* end for j */
fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT);
fprintf (st, " - ");
fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT);
fprintf (st, "%c ", /* print block entry */
(dibp->ba < IOPAGEBASE + AUTO_CSRBASE + AUTO_CSRMAX)? '*': ' ');
if (dibp->vec == 0)
fprintf (st, "%*s", ((vecwid*2)+1+1), " ");
else {
fprintf (st, "%0*" VEC_FMT, vecwid, dibp->vec);
if (dibp->vnum > 1)
fprintf (st, "-%0*" VEC_FMT, vecwid, dibp->vec + (4 *
(dibp->ulnt? dibp->lnt/dibp->ulnt:
(dptr? dptr->numunits: 1)) * dibp->vnum) - 4);
else
fprintf (st, " %*s", vecwid, " ");
fprintf (st, "%1s", (dibp->vnum >= AUTO_VECBASE)? "*": " ");
}
if (dibp->vnum || dibp->vloc)
fprintf (st, " %2u", brbase + dibp->vloc/32);
else
fprintf (st, " ");
fprintf (st, " %*u %s\n", maxdev, (dibp->ulnt? dibp->lnt/dibp->ulnt:
(dptr? dptr->numunits: 1)),
dptr? sim_dname (dptr): "CPU");
} /* end if */
} /* end for i */
return SCPE_OK;
#undef VEC_FMT
}
/* Autoconfiguration
The table reflects the MicroVAX 3900 microcode, with one field
addition:
a valid flag marking the end of the list when the value is -1
The table has been reviewed, extended and updated to reflect the
contents of the auto configure table in VMS sysgen (V5.5-2)
A minus number of vectors indicates a field that should be
calculated but not placed in the DIB (RQ, TQ dynamic vectors)
An amod value of 0 indicates that all addresses are FIXED
An vmod value of 0 indicates that all vectors are FIXED */
typedef struct {
const char *dnam[AUTO_MAXC];
int32 valid;
int32 numv;
uint32 amod;
uint32 vmod;
uint32 fixa[AUTO_MAXC];
uint32 fixv[AUTO_MAXC];
} AUTO_CON;
AUTO_CON auto_tab[] = {/*c #v am vm fxa fxv */
{ { "QBA" }, 1, 0, 0, 0,
{017500} }, /* doorbell - fx CSR, no VEC */
{ { "MCTL" }, 1, 0, 0, 0,
{012100} }, /* MSV11-P/MSV11-Q - fx CSR, no VEC */
{ { "KE" }, 1, 0, 0, 0,
{017300} }, /* KE11-A - fx CSR, no VEC */
{ { "KG" }, 1, 0, 0, 0,
{010700} }, /* KG11-A - fx CSR, no VEC */
{ { "RHA" }, 1, 1, 0, 0,
{016700}, {0254} }, /* RH11/RH70 - fx CSR, fx VEC */
{ { "RHB" }, 1, 1, 0, 0,
{012440}, {0224} }, /* RH11/RH70 - fx CSR, fx VEC */
{ { "RHC" }, 1, 1, 0, 0,
{012040}, {0204} }, /* RH11/RH70 - fx CSR, fx VEC */
{ { "CLK" }, 1, 1, 0, 0,
{017546}, {0100} }, /* KW11L - fx CSR, fx VEC */
{ { "PCLK" }, 1, 1, 0, 0,
{012540}, {0104} }, /* KW11P - fx CSR, fx VEC */
{ { "PTR" }, 1, 1, 0, 0,
{017550}, {0070} }, /* PC11 reader - fx CSR, fx VEC */
{ { "PTP" }, 1, 1, 0, 0,
{017554}, {0074} }, /* PC11 punch - fx CSR, fx VEC */
{ { "RK" }, 1, 1, 0, 0,
{017400}, {0220} }, /* RK11 - fx CSR, fx VEC */
{ { "TM" }, 1, 1, 0, 0,
{012520}, {0224} }, /* TM11 - fx CSR, fx VEC */
{ { "RC" }, 1, 1, 0, 0,
{017440}, {0210} }, /* RC11 - fx CSR, fx VEC */
{ { "RF" }, 1, 1, 0, 0,
{017460}, {0204} }, /* RF11 - fx CSR, fx VEC */
{ { "CR" }, 1, 1, 0, 0,
{017160}, {0230} }, /* CR11 - fx CSR, fx VEC */
{ { "HK" }, 1, 1, 0, 0,
{017440}, {0210} }, /* RK611 - fx CSR, fx VEC */
{ { "LPT" }, 1, 1, 0, 0,
{017514, 004004, 004014, 004024, 004034},
{0200, 0170, 0174, 0270, 0274} }, /* LP11 - fx CSR, fx VEC */
{ { "RB" }, 1, 1, 0, 0,
{015606}, {0250} }, /* RB730 - fx CSR, fx VEC */
{ { "RL" }, 1, 1, 0, 0,
{014400}, {0160} }, /* RL11 - fx CSR, fx VEC */
{ { "RL" }, 1, 1, 0, 0,
{014400}, {0160} }, /* RL11 - fx CSR, fx VEC */
{ { "DCI" }, 1, 2, 0, 8,
{014000, 014010, 014020, 014030,
014040, 014050, 014060, 014070,
014100, 014110, 014120, 014130,
014140, 014150, 014160, 014170,
014200, 014210, 014220, 014230,
014240, 014250, 014260, 014270,
014300, 014310, 014320, 014330,
014340, 014350, 014360, 014370} }, /* DC11 - fx CSRs */
{ { NULL }, 1, 1, 0, 4,
{015200, 015210, 015220, 015230,
015240, 015250, 015260, 015270,
015300, 015310, 015320, 015330,
015340, 015350, 015360, 015370} }, /* DN11 - fx CSRs */
{ { NULL }, 1, 1, 0, 4,
{010500, 010510, 010520, 010530,
010540, 010550, 010560, 010570,
010600, 010610, 010620, 010630,
010640, 010650, 010660, 010670} }, /* DM11B - fx CSRs */
{ { NULL }, 1, 2, 0, 8,
{007600, 007570, 007560, 007550,
007540, 007530, 007520, 007510,
007500, 007470, 007460, 007450,
007440, 007430, 007420, 007410} }, /* DR11C - fx CSRs */
{ { NULL }, 1, 1, 0, 8,
{012600, 012604, 012610, 012614,
012620, 012624, 012620, 012624} }, /* PR611 - fx CSRs */
{ { NULL }, 1, 1, 0, 8,
{017420, 017422, 017424, 017426,
017430, 017432, 017434, 017436} }, /* DT11 - fx CSRs */
{ { NULL }, 1, 2, 0, 8,
{016200, 016240} }, /* DX11 */
{ { "TDC", "DLI" }, 1, 2, 0, 8,
{016500, 016510, 016520, 016530,
016540, 016550, 016560, 016570,
016600, 016610, 016620, 016630,
016740, 016750, 016760, 016770} }, /* KL11/DL11/DLV11/TU58 - fx CSRs */
{ { NULL }, 1, 2, 0, 8, { 0 } }, /* DLV11J - fx CSRs */
{ { NULL }, 1, 2, 8, 8 }, /* DJ11 */
{ { NULL }, 1, 2, 16, 8 }, /* DH11 */
{ { "VT" }, 1, 4, 0, 8,
{012000, 012010, 012020, 012030} }, /* VT11/GT40 - fx CSRs */
{ { "VS60" }, 1, 4, 0, 8,
{012000} }, /* VS60/GT48 - fx CSRs */
{ { NULL }, 1, 2, 0, 8,
{010400} }, /* LPS11 */
{ { NULL }, 1, 2, 8, 8 }, /* DQ11 */
{ { NULL }, 1, 2, 0, 8,
{012400} }, /* KW11W */
{ { NULL }, 1, 2, 8, 8 }, /* DU11 */
{ { "DUP" }, 1, 2, 8, 8 }, /* DUP11 */
{ { NULL }, 1, 3, 0, 8,
{015000, 015040, 015100, 015140, }}, /* DV11 */
{ { NULL }, 1, 2, 8, 8 }, /* LK11A */
{ { "DMC" },
1, 2, 8, 8 }, /* DMC11 */
{ { "DZ" }, 1, 2, 8, 8 }, /* DZ11 */
{ { "KDP" }, 1, 2, 8, 8 }, /* KMC11 */
{ { NULL }, 1, 2, 8, 8 }, /* LPP11 */
{ { NULL }, 1, 2, 8, 8 }, /* VMV21 */
{ { NULL }, 1, 2, 16, 8 }, /* VMV31 */
{ { NULL }, 1, 2, 8, 8 }, /* DWR70 */
{ { "RL", "RLB"}, 1, 1, 8, 4,
{014400}, {0160} }, /* RL11 */
{ { "TS", "TSB", "TSC", "TSD"},
1, 1, 0, 4, /* TS11 */
{012520, 012524, 012530, 012534},
{0224} },
{ { NULL }, 1, 2, 16, 8,
{010460} }, /* LPA11K */
{ { NULL }, 1, 2, 8, 8 }, /* KW11C */
{ { NULL }, 1, 1, 8, 8 }, /* reserved */
{ { "RX", "RY" }, 1, 1, 8, 4,
{017170} , {0264} }, /* RX11/RX211 */
{ { NULL }, 1, 1, 8, 4 }, /* DR11W */
{ { NULL }, 1, 1, 8, 4,
{012410, 012410}, {0124} }, /* DR11B - fx CSRs,vec */
{ { "DMP" }, 1, 2, 8, 8 }, /* DMP11 */
{ { "DPV" }, 1, 2, 8, 8 }, /* DPV11 */
{ { NULL }, 1, 2, 8, 8 }, /* ISB11 */
{ { NULL }, 1, 2, 16, 8 }, /* DMV11 */
{ { "XU", "XUB" }, 1, 1, 8, 4,
{014510}, {0120} }, /* DEUNA */
{ { "XQ", "XQB" }, 1, -1, 0, 4,
{014440, 014460, 014520, 014540}, {0120} }, /* DEQNA */
{ { "RQ", "RQB", "RQC", "RQD" },
1, -1, 4, 4, /* RQDX3 */
{012150}, {0154} },
{ { NULL }, 1, 8, 32, 4 }, /* DMF32 */
{ { NULL }, 1, 3, 16, 8 }, /* KMS11 */
{ { NULL }, 1, 2, 0, 8,
{004200, 004240, 004300, 004340} }, /* PLC11 */
{ { NULL }, 1, 1, 16, 4 }, /* VS100 */
{ { "TQ", "TQB" }, 1, -1, 4, 4,
{014500}, {0260} }, /* TQK50 */
{ { NULL }, 1, 2, 16, 8 }, /* KMV11 */
{ { NULL }, 1, 2, 0, 8,
{004400, 004440, 004500, 004540} }, /* KTC32 */
{ { NULL }, 1, 2, 0, 8,
{004100} }, /* IEQ11 */
{ { "VH" }, 1, 2, 16, 8 }, /* DHU11/DHQ11 */
{ { NULL }, 1, 6, 32, 4 }, /* DMZ32 */
{ { NULL }, 1, 6, 32, 4 }, /* CP132 */
{ { "TC" }, 1, 1, 0, 0,
{017340}, {0214} }, /* TC11 */
{ { "TA" }, 1, 1, 0, 0,
{017500}, {0260} }, /* TA11 */
{ { "QVSS" }, 1, 2, 64, 8,
{017200} }, /* QVSS - fx CSR */
{ { NULL }, 1, 1, 8, 4 }, /* VS31 */
{ { NULL }, 1, 1, 0, 4,
{016200} }, /* LNV11 - fx CSR */
{ { NULL }, 1, 1, 16, 4 }, /* LNV21/QPSS */
{ { NULL }, 1, 1, 8, 4,
{012570} }, /* QTA - fx CSR */
{ { NULL }, 1, 1, 8, 4 }, /* DSV11 */
{ { NULL }, 1, 2, 8, 8 }, /* CSAM */
{ { NULL }, 1, 2, 8, 8 }, /* ADV11C */
{ { NULL }, 1, 0, 8, 8,
{010440} }, /* AAV11/AAV11C */
{ { NULL }, 1, 2, 8, 8,
{016400}, {0140} }, /* AXV11C - fx CSR,vec */
{ { NULL }, 1, 2, 4, 8,
{010420} }, /* KWV11C - fx CSR */
{ { NULL }, 1, 2, 8, 8,
{016410} }, /* ADV11D - fx CSR */
{ { NULL }, 1, 2, 8, 8,
{016420} }, /* AAV11D - fx CSR */
{ { "QDSS" }, 1, 3, 0, 16,
{017400, 017402, 017404, 017406,
017410, 017412, 017414, 017416} }, /* VCB02 - QDSS - fx CSR */
{ { NULL }, 1, 16, 0, 4,
{004160, 004140, 004120} }, /* DRV11J - fx CSR */
{ { NULL }, 1, 2, 16, 8 }, /* DRQ3B */
{ { NULL }, 1, 1, 8, 4 }, /* VSV24 */
{ { NULL }, 1, 1, 8, 4 }, /* VSV21 */
{ { NULL }, 1, 1, 8, 4 }, /* IBQ01 */
{ { NULL }, 1, 1, 8, 8 }, /* IDV11A */
{ { NULL }, 1, 0, 8, 8 }, /* IDV11B */
{ { NULL }, 1, 0, 8, 8 }, /* IDV11C */
{ { NULL }, 1, 1, 8, 8 }, /* IDV11D */
{ { NULL }, 1, 2, 8, 8 }, /* IAV11A */
{ { NULL }, 1, 0, 8, 8 }, /* IAV11B */
{ { NULL }, 1, 2, 8, 8 }, /* MIRA */
{ { NULL }, 1, 2, 16, 8 }, /* IEQ11 */
{ { NULL }, 1, 2, 32, 8 }, /* ADQ32 */
{ { NULL }, 1, 2, 8, 8 }, /* DTC04, DECvoice */
{ { NULL }, 1, 1, 32, 4 }, /* DESNA */
{ { NULL }, 1, 2, 4, 8 }, /* IGQ11 */
{ { NULL }, 1, 2, 32, 8 }, /* KMV1F */
{ { NULL }, 1, 1, 8, 4 }, /* DIV32 */
{ { NULL }, 1, 2, 4, 8 }, /* DTCN5, DECvoice */
{ { NULL }, 1, 2, 4, 8 }, /* DTC05, DECvoice */
{ { NULL }, 1, 2, 8, 8 }, /* KWV32 (DSV11) */
{ { NULL }, 1, 1, 64, 4 }, /* QZA */
{ { NULL }, -1 } /* end table */
};
#if !defined(DEV_NEXUS)
#if defined(DEV_MBUS)
#define DEV_NEXUS DEV_MBUS
#else
#define DEV_NEXUS 0
#endif
#endif
#define MAX(a,b) (((a)>(b))? (a) : (b))
static void build_vector_tab (void)
{
int32 ilvl, ibit;
static t_bool done = FALSE;
AUTO_CON *autp;
DEVICE *dptr;
DIB *dibp;
uint32 j, k;
if (done)
return;
/* Locate all Unibus/Qbus devices and make sure vector masks are set */
for (j = 0; (dptr = sim_devices[j]) != NULL; j++) {
if ((dptr->flags & (DEV_UBUS | DEV_QBUS)) == 0)
continue;
for (autp = auto_tab; autp->valid >= 0; autp++) {
for (k=0; autp->dnam[k]; k++) {
if (!strcmp(dptr->name, autp->dnam[k])) {
dibp = (DIB *)dptr->ctxt;
ilvl = dibp->vloc / 32;
ibit = dibp->vloc % 32;
#if (VEC_SET != 0)
if (1) {
int v;
for (v=0; v<MAX(dibp->vnum, 1); v++)
int_vec_set[ilvl][ibit+v] = VEC_SET;
}
#endif
break;
}
}
}
}
done = TRUE;
}
t_stat auto_config (const char *name, int32 nctrl)
{
uint32 csr = IOPAGEBASE + AUTO_CSRBASE;
uint32 vec = AUTO_VECBASE;
int32 ilvl, ibit, numc;
AUTO_CON *autp;
DEVICE *dptr;
DIB *dibp;
uint32 j, k, jena, vmask, amask;
if (autcon_enb == 0) /* enabled? */
return SCPE_OK;
if (name) { /* updating? */
dptr = find_dev (name);
if (dptr == NULL)
return SCPE_ARG;
dibp = (DIB *) dptr->ctxt; /* get DIB */
if ((nctrl < 0) || (dibp == NULL))
return SCPE_ARG;
dibp->numc = nctrl;
}
for (autp = auto_tab; autp->valid >= 0; autp++) { /* loop thru table */
if (autp->amod) { /* floating csr? */
amask = autp->amod - 1;
csr = (csr + amask) & ~amask; /* align csr */
}
for (j = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) {
if (autp->dnam[j] == NULL) /* no device? */
break;
dptr = find_dev (autp->dnam[j]); /* find ctrl */
if ((dptr == NULL) || /* enabled, not (nexus or unibus or qbus)? */
(dptr->flags & DEV_DIS) ||
(dptr->flags & DEV_NEXUS) ||
!(dptr->flags & (DEV_UBUS | DEV_QBUS | DEV_Q18)) )
continue;
/* Sanity check that enabled devices can work on the current bus */
if (!((UNIBUS && (dptr->flags & (DEV_UBUS | DEV_Q18))) ||
((!UNIBUS) && ((dptr->flags & DEV_QBUS) ||
((dptr->flags & DEV_Q18) && (MEMSIZE <= UNIMEMSIZE)))))) {
dptr->flags |= DEV_DIS;
if (sim_switches & SWMASK ('P'))
continue;
return sim_messagef (SCPE_NOFNC, "%s device not compatible with system bus\n", sim_dname(dptr));
}
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp == NULL) /* not there??? */
return SCPE_IERR;
numc = dibp->numc ? dibp->numc : 1;
ilvl = dibp->vloc / 32;
ibit = dibp->vloc % 32;
/* Identify how many devices earlier in the device list are
enabled and use that info to determine fixed address assignments */
for (k=jena=0; k<j; k++) {
DEVICE *kdptr = find_dev (autp->dnam[k]);
if (kdptr && (!(kdptr->flags & DEV_DIS)))
jena += ((DIB *)kdptr->ctxt)->numc ? ((DIB *)kdptr->ctxt)->numc : 1;
}
if (autp->fixa[jena]) /* fixed csr avail? */
dibp->ba = IOPAGEBASE + autp->fixa[jena]; /* use it */
else { /* no fixed left */
dibp->ba = csr; /* set CSR */
csr += (numc * autp->amod); /* next CSR */
} /* end else */
if (autp->numv) { /* vec needed? */
if (autp->fixv[jena]) { /* fixed vec avail? */
if (autp->numv > 0)
dibp->vec = autp->fixv[jena]; /* use it */
}
else { /* no fixed left */
uint32 numv = abs (autp->numv); /* get num vec */
vmask = autp->vmod - 1;
vec = (vec + vmask) & ~vmask; /* align vector */
if (autp->numv > 0)
dibp->vec = vec; /* set vector */
vec += (numc * numv * 4);
} /* end else */
} /* end vec needed */
} /* end for j */
if (autp->amod) /* flt CSR? gap */
csr = csr + 2;
} /* end for i */
return SCPE_OK;
}
/* Factory bad block table creation routine
This routine writes a DEC standard 144 compliant bad block table on the
last track of the specified unit as described in:
EL-00144_B_DEC_STD_144_Disk_Standard_for_Recording_and_Handling_Bad_Sectors_Nov76.pdf
The bad block table consists of 10 repetitions of the same table,
formatted as follows:
words 0-1 pack id number
words 2-3 cylinder/sector/surface specifications
:
words n-n+1 end of table (-1,-1)
Inputs:
uptr = pointer to unit
sec = number of sectors per surface
wds = number of words per sector
Outputs:
sta = status code
*/
#include "sim_disk.h"
t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
{
return sim_disk_pdp11_bad_block (uptr, sec, wds);
}