1
0
mirror of https://github.com/simh/simh.git synced 2026-05-01 05:48:35 +00:00

PDP11, PDP10 & VAXen: Fix TS11, RH11/TM02-3, TU45 for proper BOT handling

A user observed that the TS11 would not run XXDP+, even though it ran
fine with the PDP11 operating systems, VMS, and XXDP V2.  I traced this
back to a conceptual error in the implementation of some magtapes,
specifically the TS11, RH11/TM02-3, and the PDP10 TU45.

The issues is that beginning of tape, and being positioned in front of
the first record, are not necessarily the same. Following BOT, tape
drives record a ID burst If high density and an inter-record gap before
the first record. When the first record is read backwards or backspaced
over, the tape ends up at position 0 but should not show BOT.  Most
simulated tape drives did this correctly, but a few used sim_tape_bot()
as a shortcut for BOT, and it's simply not correct.

BOT should be set at ATTACH, by a successful rewind, and by any reverse
operation when the tape is positioned in front of the first record.

BOT should be cleared by any successful movement operation, except
rewind.
This commit is contained in:
Bob Supnik
2023-11-07 09:06:27 -10:00
committed by Mark Pizzolato
parent 67ec597696
commit 4c63340ba9
3 changed files with 120 additions and 67 deletions

View File

@@ -1,6 +1,6 @@
/* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator
Copyright (c) 1993-2022, Robert M Supnik Copyright (c) 1993-2023, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@@ -25,6 +25,7 @@
tu RH11/TM03/TU45 magtape tu RH11/TM03/TU45 magtape
06-Nov-23 RMS Fixed BOT logic
26-Mar-22 RMS Added extra case points for new MTSE definitions 26-Mar-22 RMS Added extra case points for new MTSE definitions
07-Sep-20 RMS Fixed || -> | in macro (Mark Pizzolato) 07-Sep-20 RMS Fixed || -> | in macro (Mark Pizzolato)
12-Jan-18 RMS Fixed missing () in logical test (Mark Pizzolato) 12-Jan-18 RMS Fixed missing () in logical test (Mark Pizzolato)
@@ -94,6 +95,10 @@
level sensitive. level sensitive.
- The DONE interrupt, once set, is not disabled if IE is cleared, - The DONE interrupt, once set, is not disabled if IE is cleared,
but the SC interrupt is. but the SC interrupt is.
BOT is not the same as POS == 0. BOT is set after rewinding or after
a reverse operation from before the first record. It is cleared by
any successful motion operation.
*/ */
#include "pdp10_defs.h" #include "pdp10_defs.h"
@@ -183,7 +188,7 @@
*/ */
#define FS_SAT 0000001 /* slave attention */ #define FS_SAT 0000001 /* slave attention */
#define FS_BOT 0000002 /* ^beginning of tape */ #define FS_BOT 0000002 /* +beginning of tape */
#define FS_TMK 0000004 /* end of file */ #define FS_TMK 0000004 /* end of file */
#define FS_ID 0000010 /* ID burst detected */ #define FS_ID 0000010 /* ID burst detected */
#define FS_SLOW 0000020 /* slowing down NI */ #define FS_SLOW 0000020 /* slowing down NI */
@@ -191,7 +196,7 @@
#define FS_SSC 0000100 /* slave stat change */ #define FS_SSC 0000100 /* slave stat change */
#define FS_RDY 0000200 /* ^formatter ready */ #define FS_RDY 0000200 /* ^formatter ready */
#define FS_FPR 0000400 /* formatter present */ #define FS_FPR 0000400 /* formatter present */
#define FS_EOT 0002000 /* +end of tape */ #define FS_EOT 0002000 /* ^end of tape */
#define FS_WRL 0004000 /* ^write locked */ #define FS_WRL 0004000 /* ^write locked */
#define FS_MOL 0010000 /* ^medium online */ #define FS_MOL 0010000 /* ^medium online */
#define FS_PIP 0020000 /* +pos in progress */ #define FS_PIP 0020000 /* +pos in progress */
@@ -675,7 +680,7 @@ switch (fnc) { /* case on function */
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING))
sim_cancel (uptr); /* stop motion, not on-line delay */ sim_cancel (uptr); /* stop motion, not on-line delay */
uptr->USTAT = 0; uptr->USTAT &= FS_BOT; /* fall through */
/* fall through */ /* fall through */
case FNC_NOP: case FNC_NOP:
tucs1 = tucs1 & ~CS1_GO; /* no operation */ tucs1 = tucs1 & ~CS1_GO; /* no operation */
@@ -687,8 +692,10 @@ switch (fnc) { /* case on function */
break; break;
} }
tutc = TC_RIP; /* density = 800 */ tutc = TC_RIP; /* density = 800 */
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ if (tu_unit[0].flags & UNIT_ATT) { /* attached? */
tu_unit[0].USTAT = 0; sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
tu_unit[0].USTAT = FS_BOT;
}
tucs1 = tucs1 & ~CS1_GO; tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK; tufs = tufs & ~FS_TMK;
return; return;
@@ -733,7 +740,7 @@ switch (fnc) { /* case on function */
set_tuer (ER_UNS); set_tuer (ER_UNS);
break; break;
} }
if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { if ((uptr->USTAT & FS_BOT) || ((tutc & TC_FCS) == 0)) {
set_tuer (ER_NXF); set_tuer (ER_NXF);
break; break;
} }
@@ -761,7 +768,7 @@ switch (fnc) { /* case on function */
case FNC_WCHKR: /* wchk = read */ case FNC_WCHKR: /* wchk = read */
case FNC_READR: /* read rev */ case FNC_READR: /* read rev */
if (tufs & FS_BOT) { /* beginning of tape? */ if (uptr->USTAT & FS_BOT) { /* beginning of tape? */
set_tuer (ER_NXF); set_tuer (ER_NXF);
break; break;
} }
@@ -835,7 +842,9 @@ if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) {
if (uptr->USTAT & FS_REW) { /* rewind or unload? */ if (uptr->USTAT & FS_REW) { /* rewind or unload? */
sim_tape_rewind (uptr); /* rewind tape */ sim_tape_rewind (uptr); /* rewind tape */
uptr->USTAT = 0; /* clear status */ if (uptr->flags & UNIT_ATT) /* attached? */
uptr->USTAT = FS_BOT; /* set BOT */
else uptr->USTAT = 0; /* clear status */
tufs = tufs | FS_ATA | FS_SSC; tufs = tufs | FS_ATA | FS_SSC;
update_tucs (CS1_SC, drv); /* update status */ update_tucs (CS1_SC, drv); /* update status */
return SCPE_OK; return SCPE_OK;
@@ -1041,21 +1050,17 @@ if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */
tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */
if (GET_FMTR (tucs2) == 0) { /* formatter present? */ if (GET_FMTR (tucs2) == 0) { /* formatter present? */
tufs = (tufs & ~FS_DYN) | FS_FPR; tufs = (tufs & ~FS_DYN) | FS_FPR;
if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line timer running? */ if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* delayed on-line timer running? */
act = 0; /* Not a tape motion op */ act = 0; /* not a tape motion op */
else { else {
if (tu_unit[drv].flags & UNIT_ATT) { if (tu_unit[drv].flags & UNIT_ATT) {
tufs = tufs | FS_MOL | tu_unit[drv].USTAT; tufs = tufs | FS_MOL | (tu_unit[drv].USTAT & 0177777);
if (tu_unit[drv].UDENS == TC_1600) if (tu_unit[drv].UDENS == TC_1600)
tufs = tufs | FS_PE; tufs = tufs | FS_PE;
if (sim_tape_wrp (&tu_unit[drv])) if (sim_tape_wrp (&tu_unit[drv]))
tufs = tufs | FS_WRL; tufs = tufs | FS_WRL;
if (!act) { if (!act && sim_tape_eot (&tu_unit[drv]))
if (sim_tape_bot (&tu_unit[drv]))
tufs = tufs | FS_BOT;
if (sim_tape_eot (&tu_unit[drv]))
tufs = tufs | FS_EOT; tufs = tufs | FS_EOT;
}
} }
} }
if (tuer) if (tuer)
@@ -1138,6 +1143,7 @@ switch (st) {
break; break;
case MTSE_BOT: /* reverse into BOT */ case MTSE_BOT: /* reverse into BOT */
uptr->USTAT = FS_BOT; /* set BOT */
break; break;
case MTSE_WRP: /* write protect */ case MTSE_WRP: /* write protect */
@@ -1178,7 +1184,9 @@ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */
if (!sim_is_active(uptr) ) if (!sim_is_active(uptr) )
sim_activate_after(uptr, SPINUPDLY); sim_activate_after(uptr, SPINUPDLY);
} }
uptr->USTAT = 0; if ((uptr->flags & UNIT_ATT) && sim_tape_bot (uptr))
uptr->USTAT = FS_BOT;
else uptr->USTAT = 0;
} }
if (xbuf == NULL) if (xbuf == NULL)
xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8));
@@ -1197,7 +1205,7 @@ t_stat r;
r = sim_tape_attach (uptr, cptr); r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
uptr->USTAT = 0; /* clear unit status */ uptr->USTAT = FS_BOT; /* set BOT */
uptr->UDENS = UD_UNK; /* unknown density */ uptr->UDENS = UD_UNK; /* unknown density */
/* Delay setting MOL since we may have just detached a previous file. /* Delay setting MOL since we may have just detached a previous file.
* In that case, the OS must see MOL clear, so that it will know that the * In that case, the OS must see MOL clear, so that it will know that the
@@ -1243,7 +1251,7 @@ return sim_tape_detach (uptr);
} }
/* Device bootstrap */ /* Device bootstrap */
/* Note that the dec and ITS boot code is word for word identical, /* Note that the DEC and ITS boot code is word for word identical,
* except for the IO instructions. The ITS instructions encode the * except for the IO instructions. The ITS instructions encode the
* UBA number. No attempt is made to allow UBA selection under ITS, * UBA number. No attempt is made to allow UBA selection under ITS,
* though it should work with the DEC rom. * though it should work with the DEC rom.

View File

@@ -1,6 +1,6 @@
/* pdp11_ts.c: TS11/TSV05 magnetic tape simulator /* pdp11_ts.c: TS11/TSV05 magnetic tape simulator
Copyright (c) 1993-2022, Robert M Supnik Copyright (c) 1993-2023, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@@ -25,6 +25,8 @@
ts TS11/TSV05 magtape ts TS11/TSV05 magtape
29-Oct-23 RMS Implemented distinction between BOT and POS==0
INIT command is a NOP
26-Mar-22 RMS Added extra case points for new MTSE definitions 26-Mar-22 RMS Added extra case points for new MTSE definitions
27-Oct-14 RMS Fixed bug in read forward with byte swap 27-Oct-14 RMS Fixed bug in read forward with byte swap
23-Oct-13 RMS Revised for new boot setup routine 23-Oct-13 RMS Revised for new boot setup routine
@@ -87,6 +89,25 @@
- PDP-11 Unibus 22b systems - the TS11 behaves as an 18b Unibus - PDP-11 Unibus 22b systems - the TS11 behaves as an 18b Unibus
peripheral and must go through the I/O map peripheral and must go through the I/O map
- VAX Q22 systems - the TS11 must go through the I/O map - VAX Q22 systems - the TS11 must go through the I/O map
The TS11 must distinguish between true beginning of tape (BOT) -
positioned at the tape marker - and positioned before the first
record (POS == 0). BOT is set under the following circumstances:
- Mount (ATTACH)
- Rewind
- Backward operation, !BOT && POS==0. This sets RIB (rewind into
BOT) and is an error
It is cleared by any successful forward operation.
Therefore, reverse operations (except rewind) have three states:
- !BOT, POS != 0. BOT unchanaged.
- !BOT, POS == 0. Set BOT and RIB; error.
- BOT. Set function reject.
Rewind always moves the tape to BOT, even if it is already at BOT.
*/ */
#if defined (VM_PDP10) /* PDP10 version */ #if defined (VM_PDP10) /* PDP10 version */
@@ -275,11 +296,12 @@ int32 tsdbx = 0; /* data buf ext */
int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */ int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */
int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */ int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */
int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */ int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */
int32 ts_bot = 0; /* at BOT */
int32 ts_ownc = 0; /* tape owns cmd */ int32 ts_ownc = 0; /* tape owns cmd */
int32 ts_ownm = 0; /* tape owns msg */ int32 ts_ownm = 0; /* tape owns msg */
int32 ts_qatn = 0; /* queued attn */ int32 ts_qatn = 0; /* queued attn */
int32 ts_bcmd = 0; /* boot cmd */ int32 ts_bcmd = 0; /* boot cmd */
int32 ts_time = 2000; /* record latency */ int32 ts_time = 10; /* record latency */
static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */ static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */
t_stat ts_rd (int32 *data, int32 PA, int32 access); t_stat ts_rd (int32 *data, int32 PA, int32 access);
@@ -293,6 +315,7 @@ int32 ts_updtssr (int32 t);
int32 ts_updxs0 (int32 t); int32 ts_updxs0 (int32 t);
void ts_cmpendcmd (int32 s0, int32 s1); void ts_cmpendcmd (int32 s0, int32 s1);
void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); void ts_endcmd (int32 ssf, int32 xs0f, int32 msg);
void ts_set_mot (int32 bot);
int32 ts_map_status (t_stat st); int32 ts_map_status (t_stat st);
t_stat ts_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); t_stat ts_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
const char *ts_description (DEVICE *dptr); const char *ts_description (DEVICE *dptr);
@@ -335,6 +358,7 @@ REG ts_reg[] = {
{ GRDATAD (WOPT, wchopt, DEV_RDX, 16, 0, "write char packet options") }, { GRDATAD (WOPT, wchopt, DEV_RDX, 16, 0, "write char packet options") },
{ GRDATAD (WXOPT, wchxopt, DEV_RDX, 16, 0, "write char packet extended options") }, { GRDATAD (WXOPT, wchxopt, DEV_RDX, 16, 0, "write char packet extended options") },
{ FLDATAD (INT, IREQ (TS), INT_V_TS, "interrupt pending") }, { FLDATAD (INT, IREQ (TS), INT_V_TS, "interrupt pending") },
{ FLDATAD (BOT, ts_bot, 0, "beginning of tape") },
{ FLDATAD (ATTN, ts_qatn, 0, "attention message pending") }, { FLDATAD (ATTN, ts_qatn, 0, "attention message pending") },
{ FLDATAD (BOOT, ts_bcmd, 0, "boot request pending") }, { FLDATAD (BOOT, ts_bcmd, 0, "boot request pending") },
{ FLDATAD (OWNC, ts_ownc, 0, "if set, tape owns command buffer") }, { FLDATAD (OWNC, ts_ownc, 0, "if set, tape owns command buffer") },
@@ -401,6 +425,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */
case 0: /* TSBA */ case 0: /* TSBA */
*data = tsba & DMASK; /* low 16b of ba */ *data = tsba & DMASK; /* low 16b of ba */
break; break;
case 1: /* TSSR */ case 1: /* TSSR */
*data = tssr = ts_updtssr (tssr); /* update tssr */ *data = tssr = ts_updtssr (tssr); /* update tssr */
break; break;
@@ -433,7 +458,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */
CLR_INT (TS); /* clr int req */ CLR_INT (TS); /* clr int req */
t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */ t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */
tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */ tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */
if (t) { /* nxm? */ if (t != 0) { /* nxm? */
ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL);
return SCPE_OK; return SCPE_OK;
} }
@@ -478,11 +503,11 @@ switch (st) {
break; break;
case MTSE_TMK: case MTSE_TMK:
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
return (XTC (XS0_TMK | XS0_RLS, TC2)); return (XTC (XS0_TMK | XS0_RLS, TC2));
case MTSE_RECE: /* record in error */ case MTSE_RECE: /* record in error */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
case MTSE_INVRL: /* invalid rec lnt */ case MTSE_INVRL: /* invalid rec lnt */
case MTSE_IOERR: /* IO error */ case MTSE_IOERR: /* IO error */
default: /* unknown error */ default: /* unknown error */
@@ -497,6 +522,7 @@ switch (st) {
case MTSE_BOT: /* reverse into BOT */ case MTSE_BOT: /* reverse into BOT */
msgxs3 = msgxs3 | XS3_RIB; /* set status */ msgxs3 = msgxs3 | XS3_RIB; /* set status */
ts_bot = 1; /* set BOT */
return (XTC (XS0_BOT | XS0_RLS, TC2)); /* tape alert */ return (XTC (XS0_BOT | XS0_RLS, TC2)); /* tape alert */
case MTSE_WRP: /* write protect */ case MTSE_WRP: /* write protect */
@@ -518,7 +544,7 @@ do {
msgrfc = fc; msgrfc = fc;
if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */ if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */
return ts_map_status (st); /* map status */ return ts_map_status (st); /* map status */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
} while (fc != 0); } while (fc != 0);
return 0; return 0;
} }
@@ -536,7 +562,7 @@ do {
st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */
if (st == MTSE_TMK) { /* tape mark? */ if (st == MTSE_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr count */ msgrfc = (msgrfc - 1) & DMASK; /* decr count */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */
return (XTC ((msgrfc? XS0_RLS: 0) | return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2)); XS0_TMK | XS0_LET, TC2));
@@ -545,7 +571,7 @@ do {
else if (st != MTSE_OK) else if (st != MTSE_OK)
return ts_map_status (st); return ts_map_status (st);
else tmkprv = FALSE; /* not a tmk */ else tmkprv = FALSE; /* not a tmk */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
} while (msgrfc != 0); } while (msgrfc != 0);
return 0; return 0;
} }
@@ -561,7 +587,7 @@ do {
msgrfc = fc; msgrfc = fc;
if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */ if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */
return ts_map_status (st); /* map status */ return ts_map_status (st); /* map status */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
} while (fc != 0); } while (fc != 0);
return 0; return 0;
} }
@@ -577,7 +603,7 @@ do {
st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */ st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */
if (st == MTSE_TMK) { /* tape mark? */ if (st == MTSE_TMK) { /* tape mark? */
msgrfc = (msgrfc - 1) & DMASK; /* decr count */ msgrfc = (msgrfc - 1) & DMASK; /* decr count */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */
return (XTC ((msgrfc? XS0_RLS: 0) | return (XTC ((msgrfc? XS0_RLS: 0) |
XS0_TMK | XS0_LET, TC2)); XS0_TMK | XS0_LET, TC2));
@@ -586,7 +612,7 @@ do {
else if (st != MTSE_OK) else if (st != MTSE_OK)
return ts_map_status (st); return ts_map_status (st);
else tmkprv = FALSE; /* not a tmk */ else tmkprv = FALSE; /* not a tmk */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
} while (msgrfc != 0); } while (msgrfc != 0);
return 0; return 0;
} }
@@ -605,7 +631,7 @@ if (fc == 0) /* byte count */
fc = 0200000; fc = 0200000;
tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */
wbc = (tbc > fc)? fc: tbc; /* cap buf size */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
if (cmdhdr & CMD_SWP) { /* swapped? */ if (cmdhdr & CMD_SWP) { /* swapped? */
for (i = 0; i < wbc; i++) { /* copy buffer */ for (i = 0; i < wbc; i++) { /* copy buffer */
wa = tsba ^ 1; /* apply OPP */ wa = tsba ^ 1; /* apply OPP */
@@ -620,7 +646,7 @@ if (cmdhdr & CMD_SWP) { /* swapped? */
else { else {
t = Map_WriteB (tsba, wbc, tsxb); /* store record */ t = Map_WriteB (tsba, wbc, tsxb); /* store record */
tsba = tsba + (wbc - t); /* update tsba */ tsba = tsba + (wbc - t); /* update tsba */
if (t) { /* nxm? */ if (t != 0) { /* nxm? */
tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */
return (XTC (XS0_RLS, TC4)); return (XTC (XS0_RLS, TC4));
} }
@@ -647,7 +673,7 @@ if (fc == 0) /* byte count */
fc = 0200000; fc = 0200000;
tsba = ((cmdadh << 16) | cmdadl) + fc; /* buf addr */ tsba = ((cmdadh << 16) | cmdadl) + fc; /* buf addr */
wbc = (tbc > fc)? fc: tbc; /* cap buf size */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
for (i = wbc; i > 0; i--) { /* copy buffer */ for (i = wbc; i > 0; i--) { /* copy buffer */
tsba = tsba - 1; tsba = tsba - 1;
wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */
@@ -687,14 +713,14 @@ if (cmdhdr & CMD_SWP) { /* swapped? */
else { else {
t = Map_ReadB (tsba, fc, tsxb); /* fetch record */ t = Map_ReadB (tsba, fc, tsxb); /* fetch record */
tsba = tsba + (fc - t); /* update tsba */ tsba = tsba + (fc - t); /* update tsba */
if (t) { /* nxm? */ if (t != 0) { /* nxm? */
tssr = ts_updtssr (tssr | TSSR_NXM); tssr = ts_updtssr (tssr | TSSR_NXM);
return TC5; return TC5;
} }
} }
if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */
return ts_map_status (st); /* return status */ return ts_map_status (st); /* return status */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
msgrfc = 0; msgrfc = 0;
if (sim_tape_eot (&ts_unit)) /* EOT on write? */ if (sim_tape_eot (&ts_unit)) /* EOT on write? */
return XTC (XS0_EOT, TC2); return XTC (XS0_EOT, TC2);
@@ -707,7 +733,7 @@ t_stat st;
if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */
return ts_map_status (st); /* return status */ return ts_map_status (st); /* return status */
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ ts_set_mot (0); /* tape has moved, !BOT */
if (sim_tape_eot (&ts_unit)) /* EOT on write? */ if (sim_tape_eot (&ts_unit)) /* EOT on write? */
return XTC (XS0_EOT, TC2); return XTC (XS0_EOT, TC2);
return XTC (XS0_TMK, TC0); return XTC (XS0_TMK, TC0);
@@ -738,7 +764,7 @@ static const char *fnc_name[CMD_N_FNC] = {
"30", "31", "32", "33", "34", "35", "36", "37" "30", "31", "32", "33", "34", "35", "36", "37"
}; };
if (ts_bcmd) { /* boot? */ if (ts_bcmd != 0) { /* boot? */
ts_bcmd = 0; /* clear flag */ ts_bcmd = 0; /* clear flag */
sim_tape_rewind (uptr); /* rewind */ sim_tape_rewind (uptr); /* rewind */
if (uptr->flags & UNIT_ATT) { /* attached? */ if (uptr->flags & UNIT_ATT) { /* attached? */
@@ -750,6 +776,7 @@ if (ts_bcmd) { /* boot? */
else tssr = ts_updtssr (tssr | TSSR_SSR | TC3); else tssr = ts_updtssr (tssr | TSSR_SSR | TC3);
if (cmdhdr & CMD_IE) if (cmdhdr & CMD_IE)
SET_INT (TS); SET_INT (TS);
ts_bot = 0; /* unatt or !BOT */
return SCPE_OK; return SCPE_OK;
} }
@@ -792,7 +819,7 @@ if ((fnc_flg[fnc] & FLG_WR) && /* write? */
} }
if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */
((fnc == FNC_POS) && (mod & 1))) && /* space rev */ ((fnc == FNC_POS) && (mod & 1))) && /* space rev */
sim_tape_bot (uptr)) { /* BOT? */ (ts_bot != 0)) { /* BOT? */
ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL);
return SCPE_OK; return SCPE_OK;
} }
@@ -805,9 +832,6 @@ st0 = st1 = 0;
switch (fnc) { /* case on func */ switch (fnc) { /* case on func */
case FNC_INIT: /* init */ case FNC_INIT: /* init */
if (!sim_tape_bot (uptr)) /* set if tape moves */
msgxs0 = msgxs0 | XS0_MOT;
sim_tape_rewind (uptr); /* rewind */
case FNC_WSSM: /* write mem */ case FNC_WSSM: /* write mem */
case FNC_GSTA: /* get status */ case FNC_GSTA: /* get status */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */
@@ -822,7 +846,7 @@ switch (fnc) { /* case on func */
bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1; bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1;
t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */ t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */
tsba = tsba + (bc - t); /* inc tsba */ tsba = tsba + (bc - t); /* inc tsba */
if (t) { /* nxm? */ if (t != 0) { /* nxm? */
ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0);
return SCPE_OK; return SCPE_OK;
} }
@@ -844,11 +868,12 @@ switch (fnc) { /* case on func */
tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */ tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */
if (wchopt & WCH_ERI) if (wchopt & WCH_ERI)
SET_INT (TS); SET_INT (TS);
ts_ownc = 0; ts_ownm = 1; /* keep msg */ ts_ownc = 0;
ts_ownm = 1; /* keep msg */
break; break;
case 01: /* rewind and unload */ case 01: /* rewind and unload */
if (!sim_tape_bot (uptr)) /* if tape moves */ if (ts_bot == 0) /* if tape moves */
msgxs0 = msgxs0 | XS0_MOT; msgxs0 = msgxs0 | XS0_MOT;
sim_tape_detach (uptr); /* unload */ sim_tape_detach (uptr); /* unload */
ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND);
@@ -863,9 +888,8 @@ switch (fnc) { /* case on func */
return SCPE_OK; return SCPE_OK;
case 04: /* rewind */ case 04: /* rewind */
if (!sim_tape_bot (uptr)) /* if tape moves */
msgxs0 = msgxs0 | XS0_MOT;
sim_tape_rewind (uptr); sim_tape_rewind (uptr);
ts_set_mot (1); /* always moves, BOT */
ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND); ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND);
break; break;
} }
@@ -960,9 +984,8 @@ switch (fnc) { /* case on func */
break; break;
case 04: /* rewind */ case 04: /* rewind */
if (!sim_tape_bot (uptr)) /* if tape moves */
msgxs0 = msgxs0 | XS0_MOT;
sim_tape_rewind (uptr); sim_tape_rewind (uptr);
ts_set_mot (1); /* always moves, BOT */
break; break;
} }
ts_cmpendcmd (st0, 0); ts_cmpendcmd (st0, 0);
@@ -983,6 +1006,13 @@ else t = t | TSSR_OFL;
return (t & ~TSSR_MBZ); return (t & ~TSSR_MBZ);
} }
void ts_set_mot (int32 bot)
{
msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */
ts_bot = bot; /* set BOT state */
return;
}
int32 ts_updxs0 (int32 t) int32 ts_updxs0 (int32 t)
{ {
t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET; t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET;
@@ -990,7 +1020,7 @@ if (ts_unit.flags & UNIT_ATT) {
t = t | XS0_ONL; t = t | XS0_ONL;
if (sim_tape_wrp (&ts_unit)) if (sim_tape_wrp (&ts_unit))
t = t | XS0_WLK; t = t | XS0_WLK;
if (sim_tape_bot (&ts_unit)) if (ts_bot != 0)
t = (t | XS0_BOT) & ~XS0_EOT; t = (t | XS0_BOT) & ~XS0_EOT;
if (sim_tape_eot (&ts_unit)) if (sim_tape_eot (&ts_unit))
t = (t | XS0_EOT) & ~XS0_BOT; t = (t | XS0_EOT) & ~XS0_BOT;
@@ -1056,6 +1086,9 @@ t_stat ts_reset (DEVICE *dptr)
int32 i; int32 i;
sim_tape_rewind (&ts_unit); sim_tape_rewind (&ts_unit);
if ((ts_unit.flags & UNIT_ATT) != 0)
ts_bot = 1;
else ts_bot = 0;
tsba = tsdbx = 0; tsba = tsdbx = 0;
ts_ownc = ts_ownm = 0; ts_ownc = ts_ownm = 0;
ts_bcmd = 0; ts_bcmd = 0;
@@ -1085,6 +1118,7 @@ t_stat r;
r = sim_tape_attach_ex (uptr, cptr, DBG_TAP, 0); /* attach unit */ r = sim_tape_attach_ex (uptr, cptr, DBG_TAP, 0); /* attach unit */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
ts_bot = 1; /* at BOT */
tssr = tssr & ~TSSR_OFL; /* clr offline */ tssr = tssr & ~TSSR_OFL; /* clr offline */
if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */
return r; return r;
@@ -1108,6 +1142,7 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */
r = sim_tape_detach (uptr); /* detach unit */ r = sim_tape_detach (uptr); /* detach unit */
if (r != SCPE_OK) if (r != SCPE_OK)
return r; /* error? */ return r; /* error? */
ts_bot = 0;
tssr = tssr | TSSR_OFL; /* set offline */ tssr = tssr | TSSR_OFL; /* set offline */
if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */
return r; return r;

View File

@@ -1,6 +1,6 @@
/* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller /* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller
Copyright (c) 1993-2017, Robert M Supnik Copyright (c) 1993-2023, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"), copy of this software and associated documentation files (the "Software"),
@@ -25,6 +25,7 @@
tu TM02/TM03 magtape tu TM02/TM03 magtape
06-Nov-23 RMS Fixed BOT logic
28-Dec-17 RMS Read tape mark must set Massbus EXC 28-Dec-17 RMS Read tape mark must set Massbus EXC
13-Mar-17 RMS Annotated fall through in switch 13-Mar-17 RMS Annotated fall through in switch
23-Oct-13 RMS Revised for new boot setup routine 23-Oct-13 RMS Revised for new boot setup routine
@@ -53,6 +54,10 @@
If the byte count is odd, the record is padded with an extra byte If the byte count is odd, the record is padded with an extra byte
of junk. File marks are represented by a single record length of 0. of junk. File marks are represented by a single record length of 0.
End of tape is two consecutive end of file marks. End of tape is two consecutive end of file marks.
BOT is not the same as POS == 0. BOT is set after rewinding or after
a reverse operation from before the first record. It is cleared by
any successful motion operation.
*/ */
#if defined (VM_PDP10) #if defined (VM_PDP10)
@@ -117,11 +122,12 @@
/* TUFS - formatter status - offset 1 /* TUFS - formatter status - offset 1
+ indicates kept in drive status + indicates kept in drive status
^ indicates calculated on the fly ^ indicates calculated on the fly
Rewinding is a pseudo-status flag and never appears in TUFS
*/ */
#define FS_OF 1 #define FS_OF 1
#define FS_SAT 0000001 /* slave attention */ #define FS_SAT 0000001 /* slave attention */
#define FS_BOT 0000002 /* ^beginning of tape */ #define FS_BOT 0000002 /* +beginning of tape */
#define FS_TMK 0000004 /* end of file */ #define FS_TMK 0000004 /* end of file */
#define FS_ID 0000010 /* ID burst detected */ #define FS_ID 0000010 /* ID burst detected */
#define FS_SLOW 0000020 /* slowing down NI */ #define FS_SLOW 0000020 /* slowing down NI */
@@ -129,7 +135,7 @@
#define FS_SSC 0000100 /* slave stat change */ #define FS_SSC 0000100 /* slave stat change */
#define FS_RDY 0000200 /* ^formatter ready */ #define FS_RDY 0000200 /* ^formatter ready */
#define FS_FPR 0000400 /* formatter present */ #define FS_FPR 0000400 /* formatter present */
#define FS_EOT 0002000 /* +end of tape */ #define FS_EOT 0002000 /* ^end of tape */
#define FS_WRL 0004000 /* ^write locked */ #define FS_WRL 0004000 /* ^write locked */
#define FS_MOL 0010000 /* ^medium online */ #define FS_MOL 0010000 /* ^medium online */
#define FS_PIP 0020000 /* +pos in progress */ #define FS_PIP 0020000 /* +pos in progress */
@@ -502,7 +508,7 @@ switch (fnc) { /* case on function */
tutc = tutc & ~TC_FCS; /* clear fc status */ tutc = tutc & ~TC_FCS; /* clear fc status */
tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR);
sim_cancel (uptr); /* reset drive */ sim_cancel (uptr); /* reset drive */
uptr->USTAT = 0; uptr->USTAT &= FS_BOT; /* fall through */
/* fall through */ /* fall through */
case FNC_NOP: case FNC_NOP:
tucs1 = tucs1 & ~CS1_GO; /* no operation */ tucs1 = tucs1 & ~CS1_GO; /* no operation */
@@ -510,8 +516,10 @@ switch (fnc) { /* case on function */
case FNC_RIP: /* read-in preset */ case FNC_RIP: /* read-in preset */
tutc = TC_RIP; /* set tutc */ tutc = TC_RIP; /* set tutc */
sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ if (tu_unit[0].flags & UNIT_ATT) { /* unit 0 attached? */
tu_unit[0].USTAT = 0; sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */
tu_unit[0].USTAT = FS_BOT;
}
tucs1 = tucs1 & ~CS1_GO; tucs1 = tucs1 & ~CS1_GO;
tufs = tufs & ~FS_TMK; tufs = tufs & ~FS_TMK;
return SCPE_OK; return SCPE_OK;
@@ -556,7 +564,7 @@ switch (fnc) { /* case on function */
tu_set_er (ER_UNS); tu_set_er (ER_UNS);
break; break;
} }
if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { if ((uptr->USTAT & FS_BOT) || ((tutc & TC_FCS) == 0)) {
tu_set_er (ER_NXF); tu_set_er (ER_NXF);
break; break;
} }
@@ -565,7 +573,7 @@ switch (fnc) { /* case on function */
case FNC_WCHKR: /* wchk = read */ case FNC_WCHKR: /* wchk = read */
case FNC_READR: /* read rev */ case FNC_READR: /* read rev */
if (tufs & FS_BOT) { /* beginning of tape? */ if (uptr->USTAT & FS_BOT) { /* beginning of tape? */
tu_set_er (ER_NXF); tu_set_er (ER_NXF);
break; break;
} }
@@ -636,7 +644,9 @@ t_stat st, r = SCPE_OK;
drv = (int32) (uptr - tu_dev.units); /* get drive # */ drv = (int32) (uptr - tu_dev.units); /* get drive # */
if (uptr->USTAT & FS_REW) { /* rewind or unload? */ if (uptr->USTAT & FS_REW) { /* rewind or unload? */
sim_tape_rewind (uptr); /* rewind tape */ sim_tape_rewind (uptr); /* rewind tape */
uptr->USTAT = 0; /* clear status */ if (uptr->flags & UNIT_ATT) /* standard rewind? */
uptr->USTAT = FS_BOT; /* set BOT */
else uptr->USTAT = 0; /* clear status */
tu_update_fs (FS_ATA | FS_SSC, drv); tu_update_fs (FS_ATA | FS_SSC, drv);
return SCPE_OK; return SCPE_OK;
} }
@@ -835,17 +845,13 @@ int32 act = sim_activate_time (&tu_unit[drv]);
tufs = (tufs & ~FS_DYN) | FS_FPR | flg; tufs = (tufs & ~FS_DYN) | FS_FPR | flg;
if (tu_unit[drv].flags & UNIT_ATT) { if (tu_unit[drv].flags & UNIT_ATT) {
tufs = tufs | FS_MOL | tu_unit[drv].USTAT; tufs = tufs | FS_MOL | (tu_unit[drv].USTAT & 0177777);
if (tu_unit[drv].UDENS == TC_1600) if (tu_unit[drv].UDENS == TC_1600)
tufs = tufs | FS_PE; tufs = tufs | FS_PE;
if (sim_tape_wrp (&tu_unit[drv])) if (sim_tape_wrp (&tu_unit[drv]))
tufs = tufs | FS_WRL; tufs = tufs | FS_WRL;
if (!act) { if (!act && sim_tape_eot (&tu_unit[drv]))
if (sim_tape_bot (&tu_unit[drv]))
tufs = tufs | FS_BOT;
if (sim_tape_eot (&tu_unit[drv]))
tufs = tufs | FS_EOT; tufs = tufs | FS_EOT;
}
} }
if (tuer) if (tuer)
tufs = tufs | FS_ERR; tufs = tufs | FS_ERR;
@@ -904,6 +910,7 @@ switch (st) {
break; break;
case MTSE_BOT: /* reverse into BOT */ case MTSE_BOT: /* reverse into BOT */
tu_unit[drv].USTAT = FS_BOT; /* set BOT */
return SCPE_OK; return SCPE_OK;
case MTSE_WRP: /* write protect */ case MTSE_WRP: /* write protect */
@@ -938,7 +945,10 @@ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */
uptr = tu_dev.units + u; uptr = tu_dev.units + u;
sim_tape_reset (uptr); /* clear pos flag */ sim_tape_reset (uptr); /* clear pos flag */
sim_cancel (uptr); /* cancel activity */ sim_cancel (uptr); /* cancel activity */
uptr->USTAT = 0; if ((uptr->flags & UNIT_ATT) && /* if attached */
sim_tape_bot (uptr)) /* and BOT */
uptr->USTAT = FS_BOT; /* set BOT */
else uptr->USTAT = 0;
} }
if (xbuf == NULL) if (xbuf == NULL)
xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8));
@@ -961,7 +971,7 @@ t_stat r;
r = sim_tape_attach (uptr, cptr); r = sim_tape_attach (uptr, cptr);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
uptr->USTAT = 0; /* clear unit status */ uptr->USTAT = FS_BOT; /* set BOT */
uptr->UDENS = UD_UNK; /* unknown density */ uptr->UDENS = UD_UNK; /* unknown density */
flg = FS_ATA | FS_SSC; /* set attention */ flg = FS_ATA | FS_SSC; /* set attention */
if (GET_DRV (tutc) == drv) /* sel drv? set SAT */ if (GET_DRV (tutc) == drv) /* sel drv? set SAT */