1
0
mirror of https://github.com/open-simh/simh.git synced 2026-05-20 04:50:56 +00:00

PDP-11: RP-11: Fixing device register read / write consistency

1. Making sure that only expected values appear on the bus when
   registers are read by CPU;
2. Fix order of I/O cancellation in case of disk detachment with
   pending I/O;
3. Fix WLOA bug and make protection consistent with documentation;
4. Added more comments.
This commit is contained in:
Tony Lawrence
2025-11-16 18:05:45 -05:00
committed by rms47
parent f5a6fd869c
commit 8563ad07df

View File

@@ -34,19 +34,22 @@
#include "sim_disk.h"
/* const_assert() */
#define _Cx(a, b) a ## b
#define _Ax(x) _Cx(_assert, x)
#define _Sx(n) (((n) << 1) - 1)
#define const_assert(c) do { static const char _Ax(__LINE__)[-_Sx(!(c))] \
= {!(c)}; (void) _Ax(__LINE__); } while (0)
#ifndef NDEBUG
# define _Cx(a, b) a ## b
# define _Ax(x) _Cx(_assert, x)
# define _Sx(n) (((n) << 1) - 1)
# define const_assert(c) do { static const char _Ax(__LINE__)[-_Sx(!(c))] \
= {!(c)}; (void) _Ax(__LINE__); } while (0)
#else
# define const_assert(c) (void) 0
#endif
/* Constants */
#define RPCONTR uint16
#define RPWRDSZ 16
#define MAP_RDW(a,c,b) (Map_ReadW (a, (c) << 1, b) >> 1)
#define MAP_WRW(a,c,b) (Map_WriteW(a, (c) << 1, b) >> 1)
#define MAP_RDW(a,c,b) (Map_ReadW ((a), (c) << 1, (b)) >> 1)
#define MAP_WRW(a,c,b) (Map_WriteW((a), (c) << 1, (b)) >> 1)
/* RP02/RPR02 parameters; RP03 doubles # of cylinders (both total and spare) */
#define RP_NUMWD 256 /* words/sector */
@@ -93,7 +96,7 @@
/* 12 real UNIBUS registers, so 16 registers total: 32 addresses */
#define RP_IOLN 040
/* RP(R)02/RP03 particulars (all disks rotated at 2400rpm) */
/* RP(R)02/RP03(RP02P) particulars (all disks rotated at 2400rpm) */
static struct drv_typ {
const char* name; /* device type name */
int32 cyl; /* cylinders */
@@ -103,8 +106,8 @@ static struct drv_typ {
int32 seek_ave; /* average seek, 0.1ms */
int32 seek_max; /* maximal seek, 0.1ms */
} drv_tab[] = {
{ RP_RP02, RP_NUMCY, RP_NUMBL, RP_SPARE, 200, 500, 800 },
{ RP_RP03, RP_NUMCY*2, RP_NUMBL*2, RP_SPARE*2, 75, 290, 550 }
{ RP_RP02, RP_NUMCY, RP_NUMBL, RP_SPARE, 200, 500, 800 },
{ RP_RP03, RP_NUMCY*2, RP_NUMBL*2, RP_SPARE*2, 75, 290, 550 }
};
/* RPDS 776710, selected drive status, read-only except for the attention bits */
@@ -129,7 +132,7 @@ static BITFIELD rp_ds_bits[] = {
BIT(RDY),
ENDBITS
};
#define RPDS_REAL 0017400 /* bits stored */
#define RPDS_REAL 0017000 /* bits stored */
#define RPDS_DKER (RPDS_HNF | RPDS_INC) /* drive error */
#define RPER_DKER(x) ((x) & RPDS_DKER ? RPER_DRE : 0)/* DRE for RPER */
@@ -185,31 +188,32 @@ static const char* rp_funcs[] = {
};
static BITFIELD rp_cs_bits[] = {
/* CSR_GO */ /* the GO! bit */
BIT(GO),
BIT(GO), /* 0000001 */
#define RPCS_V_FUNC 1
#define RPCS_M_FUNC 7
#define RPCS_FUNC (RPCS_M_FUNC << RPCS_V_FUNC) /* function */
#define RPCS_RESET 0
#define RPCS_WRITE 1
#define RPCS_READ 2
#define RPCS_WCHK 3
#define RPCS_SEEK 4
#define RPCS_WR_NOSEEK 5
#define RPCS_HOME 6
#define RPCS_RD_NOSEEK 7
BITFNAM(FUNC,3,rp_funcs),
#define RPCS_FUNC (RPCS_M_FUNC << RPCS_V_FUNC) /* function: */
#define RPCS_RESET 0 /* Idle (Reset), i */
#define RPCS_WRITE 1 /* Write, x */
#define RPCS_READ 2 /* Read, x */
#define RPCS_WCHK 3 /* Write Check, x */
#define RPCS_SEEK 4 /* Seek, i */
#define RPCS_WR_NOSEEK 5 /* Write (No Seek), x */
#define RPCS_HOME 6 /* Home Seek, i */
#define RPCS_RD_NOSEEK 7 /* Read (No Seek), x */
BITFNAM(FUNC,3,rp_funcs), /* i: Initiate; x: Execute */
/* 0000016 */
#define RPCS_V_MEX 4
#define RPCS_M_MEX 3
#define RPCS_MEX (RPCS_M_MEX << RPCS_V_MEX) /* memory extension */
BITF(MEX,2),
BITF(MEX,2), /* 0000060 */
/* CSR_IE */ /* interrupt enable */
BIT(IE),
BIT(IE), /* 0000100 */
/* CSR_DONE */ /* controller ready */
BIT(DONE),
BIT(DONE), /* 0000200 */
#define RPCS_V_DRV 8
#define RPCS_M_DRV 7
#define RPCS_DRV (RPCS_M_DRV << RPCS_V_DRV) /* drive id */
BITFFMT(DRV,3,%u),
BITFFMT(DRV,3,%u),/*0003400 */
#define RPCS_HDR 0004000 /* header operation */
BIT(HDR),
#define RPCS_MODE 0010000 /* 0=PDP-11; 1=PDP-10/-15 or format */
@@ -219,7 +223,7 @@ static BITFIELD rp_cs_bits[] = {
#define RPCS_HERR 0040000 /* hard error */
BIT(HERR),
#define RPCS_ERR CSR_ERR /* error (hard or soft) */
BIT(ERR),
BIT(ERR), /* 0100000 */
#define RPCS_REAL 0037776 /* bits kept here */
#define RPCS_RW 0037576 /* read/write */
#define GET_FUNC(x) (((x) & RPCS_FUNC) >> RPCS_V_FUNC)
@@ -230,49 +234,48 @@ static BITFIELD rp_cs_bits[] = {
/* RPWC 776716, two's complement word count */
/* For PDP-11 must be even for data, and in multiples of 3 for format */
static BITFIELD rp_wc_bits[] = {
#define RPWC_IMP 0177777 /* implemented */
BITFFMT(WC,16,%u),
#define RPWC_IMP 0177777 /* implemented */
ENDBITS
};
/* RPBA 776720, bus address */
static BITFIELD rp_ba_bits[] = {
#define RPBA_IMP 0177776 /* implemented */
BITF(BA,16),
#define RPBA_IMP 0177776 /* implemented */
ENDBITS
};
/* RPCA 776722, cylinder address */
static BITFIELD rp_ca_bits[] = {
#define RPCA_IMP 0177777 /* implemented */
#define RPCA_RW 0000777 /* RP11: 0377 */
BITFFMT(CYL,9,%u),
#define RPCA_RW 0000777 /* RP11: 0377 */
ENDBITS
};
static BITFIELD rp_ca11_bits[] = { /* RP11 version */
#define RPCA_M_CYL 0000377
BITFFMT(CYL,8,%u),
#define RPCA_V_SUCA 8
#define RPCA_M_SUCA 0000377
#define RPCA_SUCA (RPCA_M_SUCA << RPCA_V_SUCA)
BITFFMT(SUCA,8,%u),
#define RPCA_SUCA (RPCA_M_CYL << RPCA_V_SUCA)
BITFFMT(SUCA,8,%u),/*177400*/
#define RPCA_IMP 0177777 /* implemented */
ENDBITS
};
/* RPDA 776724, disk address (track/sector) */
static BITFIELD rp_da_bits[] = {
#define RPDA_IMP 0017777 /* implemented */
#define RPDA_RW 0017417 /* bits here */
#define RPDA_M_SECT 017
#define RPDA_SECT RPDA_M_SECT /* sector */
BITFFMT(SECT,4,%u),
BITFFMT(SECT,4,%u),/*000017*/
#define RPDA_V_SOT 4
#define RPDA_SOT (RPDA_M_SECT << RPDA_V_SOT) /* current sect on track */
BITFFMT(SOT,4,%u),
BITFFMT(SOT,4,%u), /*000360*/
#define RPDA_V_TRACK 8
#define RPDA_M_TRACK 037
#define RPDA_TRACK (RPDA_M_TRACK << RPDA_V_TRACK) /* track */
BITFFMT(SURF,5,%u),
BITFFMT(SURF,5,%u),/*017400*/
#define RPDA_RW 0017417 /* read/write */
#define RPDA_IMP 0017777 /* implemented */
#define GET_SECT(x) ((x) & RPDA_SECT)
#define GET_TRACK(x) (((x) & RPDA_TRACK) >> RPDA_V_TRACK)
ENDBITS
@@ -286,8 +289,8 @@ static BITFIELD rp_da_bits[] = {
/* SUCA 776734 selected unit cylinder address, read-only */
static BITFIELD rp_suca_bits[] = {
#define SUCA_IMP 0000777 /* RP11: 0377 */
BITFFMT(CYL,9,%u), /* RP11: RPCA<15:08> */
#define SUCA_IMP 0000777 /* RP11: 0377 */
ENDBITS
};
@@ -296,19 +299,17 @@ static BITFIELD rp_suca_bits[] = {
/* Maintenance Write Lockout Address (LOA) (the switches on the maint. panel) */
static const char* offon[] = { "OFF", "ON" };
static BITFIELD rp_wloa_bits[] = {
#define RPWLOA_IMP 03777
#define RPWLOA_CYL 0377 /* cyls locked */
#define RPWLOA_CYL 0000377 /* cyls locked */
BITFFMT(CYL,8,%u),
#define RPWLOA_V_DRV 8
#define RPWLOA_M_DRV 7
#define RPWLOA_DRV (RPWLOA_M_DRV << RPWLOA_V_DRV) /* drives locked */
BITFFMT(DRV,3,%u),
#define GET_WLOACYL(x) (rr_dev.flags & DEV_RP11CE \
? (((x) & RPWLOA_CYL) << 1) | 1 /* x2 + 1 */ \
: ((x) & RPWLOA_CYL))
#define GET_WLOADRV(x) (((x) & RPWLOA_DRV) >> RPWLOA_V_DRV)
BITFFMT(DRV,3,%u),/*0003400*/
#define RPWLOA_IMP 0003777 /* implemented */
#define GET_WLOA(n, c) (((n) << RPWLOA_V_DRV) | \
(rr_dev.flags & DEV_RP11CE ? (c) >> 1 : (c)))
BITNCF(4),
#define RPWLOA_ON 0100000
#define RPWLOA_ON 0100000 /* sw on/off switch */
BITFNAM(PROTECT,1,offon),
ENDBITS
};
@@ -583,7 +584,7 @@ static t_stat rr_rd (int32 *data, int32 PA, int32 access)
rpds &= RPDS_ATTN; /* attention bits */
if (!(uptr->flags & UNIT_DIS)) { /* not disabled? */
rpds |= RPDS_ONLN;
if (GET_DTYPE(uptr->flags))
if (GET_DTYPE(uptr->flags)) /* RP03? */
rpds |= RPDS_RP03;
if (uptr->flags & UNIT_ATT) { /* attached? */
rpds |= uptr->STATUS & RPDS_REAL;
@@ -609,28 +610,29 @@ static t_stat rr_rd (int32 *data, int32 PA, int32 access)
break;
case 3: /* RPWC */
*data = rpwc;
*data = rpwc & RPWC_IMP;
break;
case 4: /* RPBA */
*data = rpba;
*data = rpba & RPBA_IMP;
break;
case 5: /* RPCA */
*data = rpca;
if (!(rr_dev.flags & DEV_RP11CE)) {
assert(!(suca & ~RPCA_M_SUCA));
*data |= suca << RPCA_V_SUCA;
bits = rp_ca11_bits;
}
const_assert(RPCA_M_CYL == (RPCA_RW >> 1));
if (!(rr_dev.flags & DEV_RP11CE)) { /* RP11? */
*data = (suca << RPCA_V_SUCA) | (rpca & RPCA_M_CYL);
bits = rp_ca11_bits; /* RP11 */
} else
*data = rpca & RPCA_RW;
break;
case 6: /* RPDA */
rpda &= RPDA_RW;
uptr = rr_dev.units + GET_DRIVE(rpcs);
if (uptr->flags & UNIT_ATT)
if (uptr->flags & UNIT_ATT) {
rpda &= ~RPDA_SOT;
rpda |= (rand() % RP_NUMSC) << RPDA_V_SOT; /* inject a random sect */
*data = rpda;
}
*data = rpda & RPDA_IMP;
break;
case 10: /* SUCA */
@@ -657,6 +659,7 @@ static t_stat rr_wr (int32 data, int32 PA, int32 access)
int32 n, oval = rn < 0 ? 0 : *rr_regs[rn].valp;
int16 func;
assert(rn < (int32)(sizeof(rr_regs)/sizeof(rr_regs[0])));
if (access == WRITEB && 2 <= rn && rn <= 6)
data = RR_DATOB(oval, data);
switch (rn) {
@@ -685,7 +688,7 @@ static t_stat rr_wr (int32 data, int32 PA, int32 access)
sim_debug(RRDEB_INT, &rr_dev, "rr_wr(CSR:CLR_INT)\n");
CLR_INT(RR); /* clr int request */
}
rpcs &= ~RPCS_RW;
rpcs &= ~(RPCS_RW | CSR_GO);
rpcs |= data & RPCS_RW;
n = GET_DRIVE(rpcs); /* get drive no */
if (n != GET_DRIVE(oval)) {
@@ -713,11 +716,12 @@ static t_stat rr_wr (int32 data, int32 PA, int32 access)
break;
case 5: /* RPCA */
const_assert(RPCA_M_CYL == (RPCA_RW >> 1));
const_assert((RPCA_RW >> 1) == RPCA_M_CYL);
rpca = data & (rr_dev.flags & DEV_RP11CE ? RPCA_RW : RPCA_M_CYL);
break;
case 6: /* RPDA */
rpda &= RPDA_IMP;
rpda &= ~RPDA_RW;
rpda |= data & RPDA_RW;
break;
@@ -792,7 +796,7 @@ static void rr_go (int16 func)
uptr = rr_dev.units + i; /* selected unit */
assert(uptr->action == rr_svc);
assert(uptr->SEEKING || !uptr->FUNC); /* SEEK underway or idle */
uptr->STATUS &= ~(RPDS_DKER | RPDS_WLK); /* clear drive errors */
uptr->STATUS &= ~RPDS_DKER; /* clear drive errors */
if (!(uptr->flags & UNIT_ATT)) { /* not attached? */
rr_set_done(RPER_PGE); /* unit offline */
@@ -821,30 +825,31 @@ static void rr_go (int16 func)
rd = func == RPCS_READ || func == RPCS_RD_NOSEEK || func == RPCS_WCHK;
wr = func == RPCS_WRITE || func == RPCS_WR_NOSEEK;
if (wr && (uptr->flags & UNIT_WPRT)) /* write and locked? */
rper |= RPER_WPV;
type = GET_DTYPE(uptr->flags); /* get drive type */
if (func == RPCS_HOME) {
cyl = 0;
head = 0;
} else if (func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK) {
cyl = uptr->CYL;
head = uptr->HEAD;
assert(head < RP_NUMSF && cyl < drv_tab[type].cyl);
} else {
cyl = rpca;
head = GET_TRACK(rpda);
if (cyl >= drv_tab[type].cyl) /* bad cyl? */
rper |= RPER_NXC;
if (head >= RP_NUMSF) /* bad head? */
rper |= RPER_NXT;
}
if (rd | wr) {
int32 sect = GET_SECT(rpda); /* get sect */
if (sect >= RP_NUMSC) /* sect out of range? */
rper |= RPER_NXS;
}
type = GET_DTYPE(uptr->flags); /* get drive type */
if (func == RPCS_HOME) {
head = 0;
cyl = 0;
} else if (func == RPCS_RD_NOSEEK || func == RPCS_WR_NOSEEK) {
head = uptr->HEAD;
cyl = uptr->CYL;
assert(uptr->CYL < drv_tab[type].cyl && uptr->HEAD < RP_NUMSF);
} else {
head = GET_TRACK(rpda);
cyl = rpca;
if (head >= RP_NUMSF) /* bad head? */
rper |= RPER_NXT;
if (cyl >= drv_tab[type].cyl) /* bad cyl? */
rper |= RPER_NXC;
}
if (wr && (uptr->flags & UNIT_WPRT)) /* write and locked? */
rper |= RPER_WPV;
if (rper) { /* any errors? */
rr_set_done(0); /* set done (w/errors) */
@@ -881,7 +886,7 @@ static void rr_go (int16 func)
* just prior to when the test clears it. Thus, the test is unable to
* confirm the interrupt for all remaining cylinders. ZRPB-E fixes both
* bugs by initializing INTFLG before firing up SEEK/AIE, and also by
* using the more correct "MOVB @#RPDS, @#RPDS", instead of BIC. */
* using a more correct "MOVB @#RPDS, @#RPDS", instead of the BIC. */
} else {
if (cyl != uptr->CYL || head != uptr->HEAD) {
assert(func != RPCS_RD_NOSEEK && func != RPCS_WR_NOSEEK);
@@ -889,7 +894,7 @@ static void rr_go (int16 func)
}
i += RP_ROT_12; /* I/O takes longer */
assert(i);
/* XXDP ZRPB-E / ZRPF-B have two data race conditions in Test 5 (data
/* XXDP ZRPF-B / ZRPB-E have two data race conditions in Test 5 (data
* reliability), which in ZRPB-E can be worked around with the following
* multiplier for all 15 steady patterns, but it does not help eliminate
* the second race in the last (random) pattern test, despite showing no
@@ -904,7 +909,7 @@ static void rr_go (int16 func)
assert(suca == uptr->CYL); /* actually */
uptr->FUNC = func; /* save new func */
uptr->HEAD = head; /* save head too */
uptr->CYL = cyl; /* put on cylinder */
uptr->CYL = cyl; /* put on cylinder */
suca += n >> 2; /* show motion */
return;
}
@@ -958,7 +963,7 @@ static t_stat rr_svc (UNIT *uptr)
assert(0 < func && func < sizeof(rp_funcs)/sizeof(rp_funcs[0]));
assert(!uptr->SEEKING && !(uptr->STATUS & RPDS_SEEK));
if (func == RPCS_HOME || func == RPCS_SEEK)
return SCPE_OK; /* all done */
return SCPE_OK; /* all done with seeks! */
assert(~(rpcs & CSR_DONE));
@@ -975,20 +980,17 @@ static t_stat rr_svc (UNIT *uptr)
n = (int32)(uptr - rr_dev.units); /* get drive no */
cyl = uptr->CYL;
if (wr /* write and ... */
&& (((wloa & RPWLOA_ON) &&
GET_WLOA(n, cyl) <= (wloa & RPWLOA_IMP)) /* DA write-protected? */
|| (uptr->flags & UNIT_WPRT))) { /* unit write-locked? */
rper |= RPER_WPV;
}
head = uptr->HEAD;
sect = GET_SECT(rpda); /* get sect */
if (sect >= RP_NUMSC) /* sect out of range? */
rper |= RPER_NXS;
head = uptr->HEAD;
cyl = uptr->CYL;
if (wr) {
if ((wloa & RPWLOA_ON) && !rper/*valid DA*/
&& (n <= GET_WLOADRV(wloa) || cyl <= GET_WLOACYL(wloa))) {
uptr->STATUS |= RPDS_WLK; /* DA write-locked */
rper |= RPER_WPV;
} else if (uptr->flags & UNIT_WPRT)
rper |= RPER_WPV; /* unit write-locked */
}
if (rper) { /* control in error? */
rr_set_done(0);
@@ -1011,14 +1013,14 @@ static t_stat rr_svc (UNIT *uptr)
else if ((!wr && wc != 3) || (wr && wc % 3)) /* DEC-11-HRPCA-C-D 3.8 */
rper |= RPER_PGE;
else if (wr)
n *= 3; /* 3 wds per sector */
else /* a typo in doc??? */
n = 3; /* can only read 3 wds */
n *= 3; /* 3 wds of HDR per sector */
else
n = 3; /* can only read 3 wds of HDR */
} else { /* no: regular R/W */
/* RP11 can actually handle the PDP-10/-15 (18b) mode on PDP-11 using 3
* words per transfer, combined as two 18b words in a disk sector (for
* the bit assignments in the triplet, see rr_svc() for format reading).
* However, a sector written in this mode is marked as such and cannot be
* words per transfer, combined as two 18b words on a disk sector (for
* bit assignments in the triplet, see below BR<35:0> in format reading).
* However, a sector written in 18b mode is marked as such and cannot be
* read back in the PDP-11 (16b) mode (but only in the 18b mode). Since
* the disk containers do not have sector format information, this mode
* cannot be supported (and for all intents and purposes it's not needed
@@ -1067,8 +1069,10 @@ static t_stat rr_svc (UNIT *uptr)
if (!wr) { /* read: */
if (rpcs & RPCS_HDR) { /* format? */
assert(wc <= 3);
/* Sector header is loaded in the 36-bit Buffer Register(BR):
17 0-bits, 9-bit cyl, 5-bit track, a spare bit, 4-bit sect */
17 0-bits, 9-bit cyl, 5-bit track, a spare bit, 4-bit sect;
which is then split into 3 PDP-11 (16b) words as following */
rpxb[0] = 0; /* BR<35:20> */
rpxb[1] = (cyl << 6) | (head << 1); /* BR<19:04> */
rpxb[2] = sect; /* BR<03:00> */
@@ -1082,7 +1086,7 @@ static t_stat rr_svc (UNIT *uptr)
sim_disk_data_trace(uptr, (uint8*) rpxb, da, n * sizeof(*rpxb), "rr_read",
RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS);
assert(done <= todo);
if (done >= todo)
if (done >= todo) /* NB: done == todo */
ioerr = 0; /* good stuff */
else if (ioerr)
wc = n; /* short, adj wd cnt */
@@ -1125,6 +1129,7 @@ static t_stat rr_svc (UNIT *uptr)
if (wc && !(rpcs & RPCS_HDR)) { /* regular write? */
DEVICE* dptr = find_dev_from_unit(uptr);
int32 m = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); /* clr to... */
assert(m <= RP_MAXFR);
memset(rpxb + wc, 0, (m - wc) * sizeof(*rpxb)); /* ...end of sect */
sim_disk_data_trace(uptr, (uint8*) rpxb, da, m * sizeof(*rpxb), "rr_write",
RRDEB_DAT & (dptr->dctrl | uptr->dctrl), RRDEB_OPS);
@@ -1145,7 +1150,7 @@ static t_stat rr_svc (UNIT *uptr)
ioerr = 0; /* good stuff */
} else {
ioerr = 0; /* good stuff */
done = wc / 3;
done = (wc + 2) / 3;
if (n)
rper |= RPER_NXM; /* NXM? set flg */
}
@@ -1284,7 +1289,7 @@ static t_stat rr_reset (DEVICE *dptr)
sim_debug(RRDEB_INT, dptr, "rr_reset(CLR_INT)\n");
CLR_INT(RR);
if (rpxb == NULL)
rpxb = (RPCONTR*) calloc(RP_MAXFR, sizeof (*rpxb));
rpxb = (RPCONTR*) calloc(RP_MAXFR, sizeof(*rpxb));
if (rpxb == NULL)
return SCPE_MEM;
return auto_config(NULL, 0);
@@ -1309,19 +1314,20 @@ static t_stat rr_attach (UNIT *uptr, CONST char *cptr)
static t_stat rr_detach (UNIT *uptr)
{
int16 func = uptr->FUNC;
int16 func;
sim_cancel(uptr);
func = uptr->FUNC;
rr_seek_done(uptr, 1/*cancel*/);
if (func) {
if (func) { /* anything unfinished? */
uptr->FUNC = 0; /* idle now */
sim_cancel(uptr);
if (func == RPCS_SEEK)
uptr->STATUS |= RPDS_INC; /* seek incomplete */
else if (func != RPCS_HOME) {
uptr->STATUS |= RPDS_HNF; /* sector not found */
rr_set_done(RPER_TE);
rr_set_done(RPER_TE); /* ...and timing error */
}
uptr->STATUS |= RPDS_UNSAFE; /* must reset before use */
}
uptr->STATUS |= RPDS_UNSAFE; /* must reset before use */
assert(!sim_is_active(uptr));
assert(!uptr->SEEKING);
uptr->action = rr_svc;
@@ -1396,7 +1402,7 @@ static t_stat rr_set_wloa (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
#define BOOT_ENTRY (BOOT_START + 002) /* entry */
#define BOOT_UNIT (BOOT_START + 010) /* unit number */
#define BOOT_CSR (BOOT_START + 014) /* CSR + 12 */
#define BOOT_LEN (sizeof (rr_boot_rom) / sizeof (rr_boot_rom[0]))
#define BOOT_LEN (sizeof(rr_boot_rom)/sizeof(rr_boot_rom[0]))
static const uint16 rr_boot_rom[] = {
/* EXPECTED M9312 REGISTER USE FOR BOOT PROMS (IN THE BOOTED SOFTWARE): *
@@ -1462,7 +1468,7 @@ static t_stat rr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const cha
"In default configuration " RP_RP11 " responds to the range 17776700 - 17776736\n"
"with the first 4 word locations not occupied by any device registers (and\n"
"so 17776710 is the first used location). Some operating systems want you\n"
"to specify the extended range (e.g. RSTS/E), but some -- the relevant range\n"
"to specify the extended range (e.g. RSTS), but some -- the relevant range\n"
"(17776710 - 17776736), yet some just want to know where the CSR is located\n"
"(17776714 by default), so they can auto-calculate the range on their own.\n\n"
"Disk drive parameters (all decimal):\n\n"
@@ -1481,13 +1487,23 @@ static t_stat rr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const cha
}
fputs("\n"
"The implementation does not include any maintenance registers or disk/sector\n"
"formatting operations yet supports the Write Lockout Address (LOA) register,\n"
"which can be set with a PROTECT command:\n\n"
" sim> set RR PROTECT=ON;0407\n\n"
"to turn the protection on (in this case, the entire units 0 and 1, and\n", st);
fprintf(st, "cylinders 0 thru 7%s in unit 2 will become write-locked).\n",
"formatting operations yet supports the Write Lockout Address (LOA) register.\n"
"It can be set with the PROTECT command using the keyword \"ON\" followed by a\n"
"value representing the number of continuously protected drives and cylinders:\n"
" bits <10:8> represent the highest protected unit number;\n"
" bits <07:0> encode the last protected cylinder on the unit number specified\n"
"above (all units preceding that unit become fully write-protected).\n"
"For example,\n\n"
" sim> set RR PROTECT=ON;0407\n\n", st);
fprintf(st,
"write-protects the entire drive unit 0 and cylinders 0 thru 7%s\n",
dptr->flags & DEV_RP11CE ? " x 2 + 1 = 15(10)" : "");
fputs(
"on drive unit 1. The value is accepted in either decimal, octal (if it starts\n"
"with 0), or hexadecimal (if it starts with 0x) notation (so \"0x107\" in the\n"
"above example effects the same setting). Alternatively, a deposit command\n"
"can be used, but it only allows native (octal) values:\n\n"
" sim> deposit RR WLOA 100407\n\n"
"The current setting can be obtained by examining the WLOA register in\n"
"the device (the sign bit not present in hardware controls the feature):\n\n"
" sim> examine RR WLOA\n"
@@ -1496,8 +1512,8 @@ static t_stat rr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const cha
" sim> set RR PROTECT=OFF\n"
" sim> examine RR WLOA\n"
" WLOA: 000407 PROTECT=OFF DRV=1 CYL=7\n\n"
"Note that it does not clear the address but turns the feature off. Also,\n"
"the WLOA register is unaffected by the device RESET.\n", st);
"Note that it does not clear the address but turns the feature off.\n"
"The WLOA register is unaffected by the device RESET.\n", st);
fprint_set_help (st, dptr);
fprint_show_help(st, dptr);
fprintf(st,
@@ -1549,5 +1565,5 @@ static t_stat rr_show_ctrl (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
}
#elif !defined(UC15)
#error "RP11/-C/-E can only be used in PDP-11 configuration"
# error "RP11/-C/-E can only be used in PDP-11 configuration"
#endif /*VM_PDP11 && !UC15*/