mirror of
https://github.com/simh/simh.git
synced 2026-04-17 16:44:15 +00:00
TAPE: Add support for erasing tape marks and Coverity Fixes (Dave Bryan)
This commit is contained in:
504
sim_tape.c
504
sim_tape.c
@@ -1,6 +1,6 @@
|
|||||||
/* sim_tape.c: simulator tape support library
|
/* sim_tape.c: simulator tape support library
|
||||||
|
|
||||||
Copyright (c) 1993-2016, Robert M Supnik
|
Copyright (c) 1993-2017, 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"),
|
||||||
@@ -26,6 +26,8 @@
|
|||||||
Ultimately, this will be a place to hide processing of various tape formats,
|
Ultimately, this will be a place to hide processing of various tape formats,
|
||||||
as well as OS-specific direct hardware access.
|
as well as OS-specific direct hardware access.
|
||||||
|
|
||||||
|
03-May-17 JDB Added support for erasing tape marks to sim_tape_errec[fr]
|
||||||
|
02-May-17 JDB Added error checks to sim_fseek calls
|
||||||
18-Jul-16 JDB Added sim_tape_errecf, sim_tape_errecr functions
|
18-Jul-16 JDB Added sim_tape_errecf, sim_tape_errecr functions
|
||||||
12-Oct-15 JDB Fixed bug in sim_tape_rdlntf if gap buffer read ends at EOM
|
12-Oct-15 JDB Fixed bug in sim_tape_rdlntf if gap buffer read ends at EOM
|
||||||
15-Dec-14 JDB Changed sim_tape_set_dens to check validity of density change
|
15-Dec-14 JDB Changed sim_tape_set_dens to check validity of density change
|
||||||
@@ -188,7 +190,7 @@ sim_tape_rewind (uptr);
|
|||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read record length forward (internal routine)
|
/* Read record length forward (internal routine).
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
uptr = pointer to tape unit
|
uptr = pointer to tape unit
|
||||||
@@ -239,6 +241,7 @@ return SCPE_OK;
|
|||||||
|
|
||||||
See the notes at "tape_erase_fwd" regarding the erase gap implementation.
|
See the notes at "tape_erase_fwd" regarding the erase gap implementation.
|
||||||
|
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. For programming convenience, erase gap processing is performed for both
|
1. For programming convenience, erase gap processing is performed for both
|
||||||
@@ -251,7 +254,11 @@ return SCPE_OK;
|
|||||||
indicator. Subsequent passes only occur if an erase gap is present, so
|
indicator. Subsequent passes only occur if an erase gap is present, so
|
||||||
a non-zero return indicates an EOF was seen while reading through a gap.
|
a non-zero return indicates an EOF was seen while reading through a gap.
|
||||||
|
|
||||||
3. The dynamic start/stop test of the HP 3000 magnetic tape diagnostic
|
3. The "runaway_counter" cannot decrement to zero (or below) in the presence
|
||||||
|
of an error that terminates the gap-search loop. Therefore, the test
|
||||||
|
after the loop exit need not check for error status.
|
||||||
|
|
||||||
|
4. The dynamic start/stop test of the HP 3000 magnetic tape diagnostic
|
||||||
heavily exercises the erase gap scanning code. Sample test execution
|
heavily exercises the erase gap scanning code. Sample test execution
|
||||||
times for various buffer sizes on a 2 GHz host platform are:
|
times for various buffer sizes on a 2 GHz host platform are:
|
||||||
|
|
||||||
@@ -265,7 +272,7 @@ return SCPE_OK;
|
|||||||
512 186
|
512 186
|
||||||
1024 171
|
1024 171
|
||||||
|
|
||||||
4. Because an erase gap may precede the logical end-of-medium, represented
|
5. Because an erase gap may precede the logical end-of-medium, represented
|
||||||
either by the physical end-of-file or by an EOM marker, the "position not
|
either by the physical end-of-file or by an EOM marker, the "position not
|
||||||
updated" flag is set only if the tape is positioned at the EOM when the
|
updated" flag is set only if the tape is positioned at the EOM when the
|
||||||
routine is entered. If at least one gap marker precedes the EOM, then
|
routine is entered. If at least one gap marker precedes the EOM, then
|
||||||
@@ -273,25 +280,29 @@ return SCPE_OK;
|
|||||||
sequence will work correctly in both cases.
|
sequence will work correctly in both cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
|
static t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
|
||||||
{
|
{
|
||||||
uint8 c;
|
uint8 c;
|
||||||
t_bool all_eof;
|
t_bool all_eof;
|
||||||
uint32 f = MT_GET_FMT (uptr);
|
uint32 f = MT_GET_FMT (uptr);
|
||||||
t_mtrlnt sbc;
|
t_mtrlnt sbc;
|
||||||
t_tpclnt tpcbc;
|
t_tpclnt tpcbc;
|
||||||
t_mtrlnt buffer [256]; /* local tape buffer */
|
t_mtrlnt buffer [256]; /* local tape buffer */
|
||||||
uint32 bufcntr, bufcap; /* buffer counter and capacity */
|
uint32 bufcntr, bufcap; /* buffer counter and capacity */
|
||||||
int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */
|
int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */
|
||||||
|
t_stat status = SCPE_OK;
|
||||||
|
|
||||||
MT_CLR_PNU (uptr); /* clear the position-not-updated flag */
|
MT_CLR_PNU (uptr); /* clear the position-not-updated flag */
|
||||||
|
|
||||||
if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */
|
if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */
|
||||||
return MTSE_UNATT; /* then quit with an error */
|
return MTSE_UNATT; /* then quit with an error */
|
||||||
|
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set the initial tape position */
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the initial tape position; if it fails */
|
||||||
|
MT_SET_PNU (uptr); /* then set position not updated */
|
||||||
|
status = sim_tape_ioerr (uptr); /* and quit with I/O error status */
|
||||||
|
}
|
||||||
|
|
||||||
switch (f) { /* the read method depends on the tape format */
|
else switch (f) { /* otherwise the read method depends on the tape format */
|
||||||
|
|
||||||
case MTUF_F_STD:
|
case MTUF_F_STD:
|
||||||
case MTUF_F_E11:
|
case MTUF_F_E11:
|
||||||
@@ -301,6 +312,7 @@ switch (f) { /* the read method depen
|
|||||||
sizeof_gap = 0; /* then disable runaway detection */
|
sizeof_gap = 0; /* then disable runaway detection */
|
||||||
runaway_counter = INT_MAX; /* to allow gaps of any size */
|
runaway_counter = INT_MAX; /* to allow gaps of any size */
|
||||||
}
|
}
|
||||||
|
|
||||||
else /* otherwise */
|
else /* otherwise */
|
||||||
sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */
|
sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */
|
||||||
|
|
||||||
@@ -309,11 +321,13 @@ switch (f) { /* the read method depen
|
|||||||
|
|
||||||
do { /* loop until a record, gap, or error is seen */
|
do { /* loop until a record, gap, or error is seen */
|
||||||
if (bufcntr == bufcap) { /* if the buffer is empty then refill it */
|
if (bufcntr == bufcap) { /* if the buffer is empty then refill it */
|
||||||
if (feof (uptr->fileref)) /* if we hit the EOF while reading a gap */
|
if (feof (uptr->fileref)) { /* if we hit the EOF while reading a gap */
|
||||||
if (sizeof_gap > 0) /* then if detection is enabled */
|
if (sizeof_gap > 0) /* then if detection is enabled */
|
||||||
return MTSE_RUNAWAY; /* then report a tape runaway */
|
status = MTSE_RUNAWAY; /* then report a tape runaway */
|
||||||
else /* otherwise report the physical EOF */
|
else /* otherwise report the physical EOF */
|
||||||
return MTSE_EOM; /* as the end-of-medium */
|
status = MTSE_EOM; /* as the end-of-medium */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else if (bufcap == 0) /* otherwise if this is the initial read */
|
else if (bufcap == 0) /* otherwise if this is the initial read */
|
||||||
bufcap = 1; /* then start with just one marker */
|
bufcap = 1; /* then start with just one marker */
|
||||||
@@ -331,21 +345,25 @@ switch (f) { /* the read method depen
|
|||||||
if (bufcntr == 0) /* then if this is the initial read */
|
if (bufcntr == 0) /* then if this is the initial read */
|
||||||
MT_SET_PNU (uptr); /* then set position not updated */
|
MT_SET_PNU (uptr); /* then set position not updated */
|
||||||
|
|
||||||
return sim_tape_ioerr (uptr); /* report the error and quit */
|
status = sim_tape_ioerr (uptr); /* report the error and quit */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (bufcap == 0 /* otherwise if positioned at the physical EOF */
|
else if (bufcap == 0 /* otherwise if positioned at the physical EOF */
|
||||||
|| buffer [0] == MTR_EOM) /* or at the logical EOM */
|
|| buffer [0] == MTR_EOM) /* or at the logical EOM */
|
||||||
if (bufcntr == 0) { /* then if this is the initial read */
|
if (bufcntr == 0) { /* then if this is the initial read */
|
||||||
MT_SET_PNU (uptr); /* then set position not updated */
|
MT_SET_PNU (uptr); /* then set position not updated */
|
||||||
return MTSE_EOM; /* and report the end-of-medium and quit */
|
status = MTSE_EOM; /* and report the end-of-medium and quit */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (sizeof_gap > 0) /* otherwise if detection is enabled */
|
else { /* otherwise some gap has already been skipped */
|
||||||
return MTSE_RUNAWAY; /* then report a tape runaway */
|
if (sizeof_gap > 0) /* so if detection is enabled */
|
||||||
|
status = MTSE_RUNAWAY; /* then report a tape runaway */
|
||||||
else /* otherwise report the physical EOF */
|
else /* otherwise report the physical EOF */
|
||||||
return MTSE_EOM; /* as the end-of-medium */
|
status = MTSE_EOM; /* as the end-of-medium */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else /* otherwise reset the index */
|
else /* otherwise reset the index */
|
||||||
bufcntr = 0; /* to the start of the buffer */
|
bufcntr = 0; /* to the start of the buffer */
|
||||||
@@ -353,94 +371,115 @@ switch (f) { /* the read method depen
|
|||||||
|
|
||||||
*bc = buffer [bufcntr++]; /* store the metadata marker value */
|
*bc = buffer [bufcntr++]; /* store the metadata marker value */
|
||||||
|
|
||||||
if (*bc == MTR_EOM) /* if an end-of-medium marker is seen */
|
if (*bc == MTR_EOM) { /* if an end-of-medium marker is seen */
|
||||||
if (sizeof_gap > 0) /* then if detection is enabled */
|
if (sizeof_gap > 0) /* then if detection is enabled */
|
||||||
return MTSE_RUNAWAY; /* then report a tape runaway */
|
status = MTSE_RUNAWAY; /* then report a tape runaway */
|
||||||
else /* otherwise report the physical EOF */
|
else /* otherwise report the physical EOF */
|
||||||
return MTSE_EOM; /* as the end-of-medium */
|
status = MTSE_EOM; /* as the end-of-medium */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* space over the marker */
|
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* space over the marker */
|
||||||
|
|
||||||
if (*bc == MTR_TMK) /* if the value is a tape mark */
|
if (*bc == MTR_TMK) { /* if the value is a tape mark */
|
||||||
return MTSE_TMK; /* then quit with tape mark status */
|
status = MTSE_TMK; /* then quit with tape mark status */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else if (*bc == MTR_GAP) /* otherwise if the value is a full gap */
|
else if (*bc == MTR_GAP) /* otherwise if the value is a full gap */
|
||||||
runaway_counter -= sizeof_gap; /* then decrement the gap counter */
|
runaway_counter -= sizeof_gap; /* then decrement the gap counter */
|
||||||
|
|
||||||
else if (*bc == MTR_FHGAP) { /* otherwise if the value if a half gap */
|
else if (*bc == MTR_FHGAP) { /* otherwise if the value if a half gap */
|
||||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2; /* then back up */
|
uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2; /* then back up and resync */
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* to resync */
|
|
||||||
bufcntr = bufcap; /* mark the buffer as invalid to force a read */
|
|
||||||
|
|
||||||
*bc = MTR_GAP; /* reset the marker */
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* set the tape position; if it fails */
|
||||||
runaway_counter -= sizeof_gap / 2; /* and decrement the gap counter */
|
status = sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufcntr = bufcap; /* mark the buffer as invalid to force a read */
|
||||||
|
|
||||||
|
*bc = MTR_GAP; /* reset the marker */
|
||||||
|
runaway_counter -= sizeof_gap / 2; /* and decrement the gap counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
else { /* otherwise it's a record marker */
|
else { /* otherwise it's a record marker */
|
||||||
if (bufcntr < bufcap) /* if the position is within the buffer */
|
if (bufcntr < bufcap /* if the position is within the buffer */
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* then seek to the data area */
|
&& sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* then seek to the data area; if it fails */
|
||||||
|
status = sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
sbc = MTR_L (*bc); /* extract the record length */
|
sbc = MTR_L (*bc); /* extract the record length */
|
||||||
uptr->pos = uptr->pos + sizeof (t_mtrlnt) /* position to the start */
|
uptr->pos = uptr->pos + sizeof (t_mtrlnt) /* position to the start */
|
||||||
+ (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */
|
+ (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */
|
while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */
|
||||||
|
|
||||||
if (runaway_counter <= 0) /* if a tape runaway occurred */
|
if (runaway_counter <= 0) /* if a tape runaway occurred */
|
||||||
return MTSE_RUNAWAY; /* then report it */
|
status = MTSE_RUNAWAY; /* then report it */
|
||||||
|
|
||||||
break; /* otherwise the operation succeeded */
|
break; /* otherwise the operation succeeded */
|
||||||
|
|
||||||
case MTUF_F_TPC:
|
case MTUF_F_TPC:
|
||||||
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
||||||
*bc = tpcbc; /* save rec lnt */
|
*bc = tpcbc; /* save rec lnt */
|
||||||
|
|
||||||
if (ferror (uptr->fileref)) { /* error? */
|
if (ferror (uptr->fileref)) { /* error? */
|
||||||
MT_SET_PNU (uptr); /* pos not upd */
|
MT_SET_PNU (uptr); /* pos not upd */
|
||||||
return sim_tape_ioerr (uptr);
|
status = sim_tape_ioerr (uptr);
|
||||||
}
|
}
|
||||||
if (feof (uptr->fileref)) { /* eof? */
|
else if (feof (uptr->fileref)) { /* eof? */
|
||||||
MT_SET_PNU (uptr); /* pos not upd */
|
MT_SET_PNU (uptr); /* pos not upd */
|
||||||
return MTSE_EOM;
|
status = MTSE_EOM;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */
|
||||||
|
if (tpcbc == TPC_TMK) /* tape mark? */
|
||||||
|
status = MTSE_TMK;
|
||||||
|
else
|
||||||
|
uptr->pos = uptr->pos + ((tpcbc + 1) & ~1); /* spc over record */
|
||||||
}
|
}
|
||||||
uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */
|
|
||||||
if (tpcbc == TPC_TMK) /* tape mark? */
|
|
||||||
return MTSE_TMK;
|
|
||||||
uptr->pos = uptr->pos + ((tpcbc + 1) & ~1); /* spc over record */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MTUF_F_P7B:
|
case MTUF_F_P7B:
|
||||||
for (sbc = 0, all_eof = 1; ; sbc++) { /* loop thru record */
|
for (sbc = 0, all_eof = 1; ; sbc++) { /* loop thru record */
|
||||||
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
||||||
|
|
||||||
if (ferror (uptr->fileref)) { /* error? */
|
if (ferror (uptr->fileref)) { /* error? */
|
||||||
MT_SET_PNU (uptr); /* pos not upd */
|
MT_SET_PNU (uptr); /* pos not upd */
|
||||||
return sim_tape_ioerr (uptr);
|
status = sim_tape_ioerr (uptr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (feof (uptr->fileref)) { /* eof? */
|
else if (feof (uptr->fileref)) { /* eof? */
|
||||||
if (sbc == 0) /* no data? eom */
|
if (sbc == 0) /* no data? eom */
|
||||||
return MTSE_EOM;
|
status = MTSE_EOM;
|
||||||
break; /* treat like eor */
|
break; /* treat like eor */
|
||||||
}
|
}
|
||||||
if ((sbc != 0) && (c & P7B_SOR)) /* next record? */
|
else if ((sbc != 0) && (c & P7B_SOR)) /* next record? */
|
||||||
break;
|
break;
|
||||||
if ((c & P7B_DPAR) != P7B_EOF)
|
else if ((c & P7B_DPAR) != P7B_EOF)
|
||||||
all_eof = 0;
|
all_eof = 0;
|
||||||
}
|
}
|
||||||
*bc = sbc; /* save rec lnt */
|
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
if (status == SCPE_OK) {
|
||||||
uptr->pos = uptr->pos + sbc; /* spc over record */
|
*bc = sbc; /* save rec lnt */
|
||||||
if (all_eof) /* tape mark? */
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
||||||
return MTSE_TMK;
|
uptr->pos = uptr->pos + sbc; /* spc over record */
|
||||||
|
if (all_eof) /* tape mark? */
|
||||||
|
status = MTSE_TMK;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MTSE_FMT;
|
status = MTSE_FMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MTSE_OK;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read record length reverse (internal routine)
|
/* Read record length reverse (internal routine).
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
uptr = pointer to tape unit
|
uptr = pointer to tape unit
|
||||||
@@ -465,21 +504,32 @@ return MTSE_OK;
|
|||||||
giving the reason that the operation did not succeed and the tape position is
|
giving the reason that the operation did not succeed and the tape position is
|
||||||
as indicated above.
|
as indicated above.
|
||||||
|
|
||||||
See the notes at "sim_tape_rdlntf" and "tape_erase_fwd" regarding tape
|
|
||||||
runaway and the erase gap implementation, respectively.
|
Implementation notes:
|
||||||
|
|
||||||
|
1. The "sim_fread" call cannot return 0 in the absence of an error
|
||||||
|
condition. The preceding "sim_tape_bot" test ensures that "pos" >= 4, so
|
||||||
|
"sim_fseek" will back up at least that far, so "sim_fread" will read at
|
||||||
|
least one element. If the call returns zero, an error must have
|
||||||
|
occurred, so the "ferror" call must succeed.
|
||||||
|
|
||||||
|
2. See the notes at "sim_tape_rdlntf" and "tape_erase_fwd" regarding tape
|
||||||
|
runaway and the erase gap implementation, respectively.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
|
static t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
|
||||||
{
|
{
|
||||||
uint8 c;
|
uint8 c;
|
||||||
t_bool all_eof;
|
t_bool all_eof;
|
||||||
uint32 f = MT_GET_FMT (uptr);
|
uint32 f = MT_GET_FMT (uptr);
|
||||||
t_addr ppos;
|
t_addr ppos;
|
||||||
t_mtrlnt sbc;
|
t_mtrlnt sbc;
|
||||||
t_tpclnt tpcbc;
|
t_tpclnt tpcbc;
|
||||||
t_mtrlnt buffer [256]; /* local tape buffer */
|
t_mtrlnt buffer [256]; /* local tape buffer */
|
||||||
uint32 bufcntr, bufcap; /* buffer counter and capacity */
|
uint32 bufcntr, bufcap; /* buffer counter and capacity */
|
||||||
int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */
|
int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */
|
||||||
|
t_stat status = SCPE_OK;
|
||||||
|
|
||||||
MT_CLR_PNU (uptr); /* clear the position-not-updated flag */
|
MT_CLR_PNU (uptr); /* clear the position-not-updated flag */
|
||||||
|
|
||||||
@@ -487,13 +537,13 @@ if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not at
|
|||||||
return MTSE_UNATT; /* then quit with an error */
|
return MTSE_UNATT; /* then quit with an error */
|
||||||
|
|
||||||
if (sim_tape_bot (uptr)) /* if the unit is positioned at the BOT */
|
if (sim_tape_bot (uptr)) /* if the unit is positioned at the BOT */
|
||||||
return MTSE_BOT; /* then reading backward is not possible */
|
status = MTSE_BOT; /* then reading backward is not possible */
|
||||||
|
|
||||||
switch (f) { /* the read method depends on the tape format */
|
else switch (f) { /* otherwise the read method depends on the tape format */
|
||||||
|
|
||||||
case MTUF_F_STD:
|
case MTUF_F_STD:
|
||||||
case MTUF_F_E11:
|
case MTUF_F_E11:
|
||||||
runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set largest legal gap size in bytes */
|
runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set the largest legal gap size in bytes */
|
||||||
|
|
||||||
if (runaway_counter == 0) { /* if tape density has not been not set */
|
if (runaway_counter == 0) { /* if tape density has not been not set */
|
||||||
sizeof_gap = 0; /* then disable runaway detection */
|
sizeof_gap = 0; /* then disable runaway detection */
|
||||||
@@ -504,40 +554,50 @@ switch (f) { /* the read method depen
|
|||||||
sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */
|
sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */
|
||||||
|
|
||||||
bufcntr = 0; /* force an initial read */
|
bufcntr = 0; /* force an initial read */
|
||||||
bufcap = 1; /* but of just one metadata marker */
|
bufcap = 0; /* but of just one metadata marker */
|
||||||
|
|
||||||
do { /* loop until a record, gap, or error seen */
|
do { /* loop until a record, gap, or error is seen */
|
||||||
if (bufcntr == 0) { /* if the buffer is empty then refill it */
|
if (bufcntr == 0) { /* if the buffer is empty then refill it */
|
||||||
if (sim_tape_bot (uptr)) /* if the search has backed into the BOT */
|
if (sim_tape_bot (uptr)) { /* if the search has backed into the BOT */
|
||||||
return MTSE_BOT; /* then quit with an error */
|
status = MTSE_BOT; /* then quit with an error */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else if (uptr->pos < sizeof (buffer)) /* if less than a full buffer remains */
|
else if (bufcap == 0) /* otherwise if this is the initial read */
|
||||||
|
bufcap = 1; /* then start with just one marker */
|
||||||
|
|
||||||
|
else if (uptr->pos < sizeof (buffer)) /* otherwise if less than a full buffer remains */
|
||||||
bufcap = (uint32) uptr->pos /* then reduce the capacity accordingly */
|
bufcap = (uint32) uptr->pos /* then reduce the capacity accordingly */
|
||||||
/ sizeof (t_mtrlnt);
|
/ sizeof (t_mtrlnt);
|
||||||
|
|
||||||
sim_fseek (uptr->fileref, /* seek back to the location */
|
|
||||||
uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */
|
|
||||||
SEEK_SET); /* of the buffer */
|
|
||||||
|
|
||||||
bufcntr = sim_fread (buffer, sizeof (t_mtrlnt), /* fill the buffer */
|
|
||||||
bufcap, uptr->fileref); /* with tape metadata */
|
|
||||||
|
|
||||||
if (ferror (uptr->fileref)) { /* if a file I/O error occurred */
|
|
||||||
MT_SET_PNU (uptr); /* then set position not updated */
|
|
||||||
return sim_tape_ioerr (uptr); /* report the error and quit */
|
|
||||||
}
|
|
||||||
|
|
||||||
else /* otherwise reset the capacity */
|
else /* otherwise reset the capacity */
|
||||||
bufcap = sizeof (buffer) /* to the full size of the buffer */
|
bufcap = sizeof (buffer) /* to the full size of the buffer */
|
||||||
/ sizeof (buffer [0]);
|
/ sizeof (buffer [0]);
|
||||||
|
|
||||||
|
if (sim_fseek (uptr->fileref, /* seek back to the location */
|
||||||
|
uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */
|
||||||
|
SEEK_SET)) { /* of the buffer; if it fails */
|
||||||
|
status = sim_tape_ioerr (uptr); /* and fail with I/O error status */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bufcntr = sim_fread (buffer, sizeof (t_mtrlnt), /* fill the buffer */
|
||||||
|
bufcap, uptr->fileref); /* with tape metadata */
|
||||||
|
|
||||||
|
if (ferror (uptr->fileref)) { /* if a file I/O error occurred */
|
||||||
|
status = sim_tape_ioerr (uptr); /* then report the error and quit */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*bc = buffer [--bufcntr]; /* store the metadata marker value */
|
*bc = buffer [--bufcntr]; /* store the metadata marker value */
|
||||||
|
|
||||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* backspace over the marker */
|
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* backspace over the marker */
|
||||||
|
|
||||||
if (*bc == MTR_TMK) /* if the marker is a tape mark */
|
if (*bc == MTR_TMK) { /* if the marker is a tape mark */
|
||||||
return MTSE_TMK; /* then quit with tape mark status */
|
status = MTSE_TMK; /* then quit with tape mark status */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
else if (*bc == MTR_GAP) /* otherwise if the marker is a full gap */
|
else if (*bc == MTR_GAP) /* otherwise if the marker is a full gap */
|
||||||
runaway_counter -= sizeof_gap; /* then decrement the gap counter */
|
runaway_counter -= sizeof_gap; /* then decrement the gap counter */
|
||||||
@@ -555,14 +615,19 @@ switch (f) { /* the read method depen
|
|||||||
sbc = MTR_L (*bc); /* extract the record length */
|
sbc = MTR_L (*bc); /* extract the record length */
|
||||||
uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */
|
uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */
|
||||||
- (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */
|
- (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */
|
||||||
sim_fseek (uptr->fileref, /* seek to the data area */
|
|
||||||
uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
|
if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */
|
||||||
|
uptr->pos + sizeof (t_mtrlnt), /* then return with I/O error status */
|
||||||
|
SEEK_SET)) {
|
||||||
|
status = sim_tape_ioerr (uptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */
|
while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */
|
||||||
|
|
||||||
if (runaway_counter <= 0) /* if a tape runaway occurred */
|
if (runaway_counter <= 0) /* if a tape runaway occurred */
|
||||||
return MTSE_RUNAWAY; /* then report it */
|
status = MTSE_RUNAWAY; /* then report it */
|
||||||
|
|
||||||
break; /* otherwise the operation succeeded */
|
break; /* otherwise the operation succeeded */
|
||||||
|
|
||||||
@@ -571,41 +636,55 @@ switch (f) { /* the read method depen
|
|||||||
sim_fseek (uptr->fileref, ppos, SEEK_SET); /* position */
|
sim_fseek (uptr->fileref, ppos, SEEK_SET); /* position */
|
||||||
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
||||||
*bc = tpcbc; /* save rec lnt */
|
*bc = tpcbc; /* save rec lnt */
|
||||||
|
|
||||||
if (ferror (uptr->fileref)) /* error? */
|
if (ferror (uptr->fileref)) /* error? */
|
||||||
return sim_tape_ioerr (uptr);
|
status = sim_tape_ioerr (uptr);
|
||||||
if (feof (uptr->fileref)) /* eof? */
|
else if (feof (uptr->fileref)) /* eof? */
|
||||||
return MTSE_EOM;
|
status = MTSE_EOM;
|
||||||
uptr->pos = ppos; /* spc over record */
|
else {
|
||||||
if (*bc == MTR_TMK) /* tape mark? */
|
uptr->pos = ppos; /* spc over record */
|
||||||
return MTSE_TMK;
|
if (*bc == MTR_TMK) /* tape mark? */
|
||||||
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
|
status = MTSE_TMK;
|
||||||
|
else
|
||||||
|
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MTUF_F_P7B:
|
case MTUF_F_P7B:
|
||||||
for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
|
for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) {
|
||||||
sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
|
sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
|
||||||
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
||||||
if (ferror (uptr->fileref)) /* error? */
|
|
||||||
return sim_tape_ioerr (uptr);
|
if (ferror (uptr->fileref)) { /* error? */
|
||||||
if (feof (uptr->fileref)) /* eof? */
|
status = sim_tape_ioerr (uptr);
|
||||||
return MTSE_EOM;
|
|
||||||
if ((c & P7B_DPAR) != P7B_EOF)
|
|
||||||
all_eof = 0;
|
|
||||||
if (c & P7B_SOR) /* start of record? */
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else if (feof (uptr->fileref)) { /* eof? */
|
||||||
|
status = MTSE_EOM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((c & P7B_DPAR) != P7B_EOF)
|
||||||
|
all_eof = 0;
|
||||||
|
if (c & P7B_SOR) /* start of record? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == SCPE_OK) {
|
||||||
|
uptr->pos = uptr->pos - sbc; /* update position */
|
||||||
|
*bc = sbc; /* save rec lnt */
|
||||||
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
||||||
|
if (all_eof) /* tape mark? */
|
||||||
|
status = MTSE_TMK;
|
||||||
}
|
}
|
||||||
uptr->pos = uptr->pos - sbc; /* update position */
|
|
||||||
*bc = sbc; /* save rec lnt */
|
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
|
||||||
if (all_eof) /* tape mark? */
|
|
||||||
return MTSE_TMK;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MTSE_FMT;
|
status = MTSE_FMT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return MTSE_OK;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read record forward
|
/* Read record forward
|
||||||
@@ -824,6 +903,12 @@ return result;
|
|||||||
write error unchanged, PNU set
|
write error unchanged, PNU set
|
||||||
gap written updated
|
gap written updated
|
||||||
|
|
||||||
|
If the requested byte count equals the metadatum size, then the routine
|
||||||
|
succeeds only if it can overlay a single metadatum (i.e., a tape mark, an
|
||||||
|
end-of-medium marker, or an existing erase gap marker); otherwise, the file
|
||||||
|
position is not altered, PNU is set, and MTSE_INVRL (invalid record length)
|
||||||
|
status is returned.
|
||||||
|
|
||||||
An erase gap is represented in the tape image file by a special metadata
|
An erase gap is represented in the tape image file by a special metadata
|
||||||
value repeated throughout the gap. The value is chosen so that it is still
|
value repeated throughout the gap. The value is chosen so that it is still
|
||||||
recognizable even if it has been "cut in half" by a subsequent data overwrite
|
recognizable even if it has been "cut in half" by a subsequent data overwrite
|
||||||
@@ -888,7 +973,8 @@ return result;
|
|||||||
a gap of the requested size. If the format does not, then no action will be
|
a gap of the requested size. If the format does not, then no action will be
|
||||||
taken, and MTSE_OK status will be returned. This allows a device simulator
|
taken, and MTSE_OK status will be returned. This allows a device simulator
|
||||||
that supports writing erase gaps to use the same code without worrying about
|
that supports writing erase gaps to use the same code without worrying about
|
||||||
the tape format currently selected by the user.
|
the tape format currently selected by the user. A request for an erase gap
|
||||||
|
of zero length also succeeds with no action taken.
|
||||||
|
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
@@ -898,11 +984,12 @@ return result;
|
|||||||
|
|
||||||
static t_stat tape_erase_fwd (UNIT *uptr, t_mtrlnt gap_size)
|
static t_stat tape_erase_fwd (UNIT *uptr, t_mtrlnt gap_size)
|
||||||
{
|
{
|
||||||
t_stat st;
|
size_t xfer;
|
||||||
|
t_stat st;
|
||||||
t_mtrlnt meta, sbc, new_len, rec_size;
|
t_mtrlnt meta, sbc, new_len, rec_size;
|
||||||
uint32 file_size, marker_count;
|
uint32 file_size, marker_count;
|
||||||
int32 gap_needed = (int32) gap_size; /* the gap remaining to be allocated from the tape */
|
int32 gap_needed = (int32) gap_size; /* the gap remaining to be allocated from the tape */
|
||||||
uint32 gap_alloc = 0; /* the gap currently allocated from the tape */
|
uint32 gap_alloc = 0; /* the gap currently allocated from the tape */
|
||||||
const t_addr gap_pos = uptr->pos; /* the file position where the gap will start */
|
const t_addr gap_pos = uptr->pos; /* the file position where the gap will start */
|
||||||
const uint32 format = MT_GET_FMT (uptr); /* the tape format */
|
const uint32 format = MT_GET_FMT (uptr); /* the tape format */
|
||||||
const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
||||||
@@ -916,25 +1003,30 @@ if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not at
|
|||||||
else if (sim_tape_wrp (uptr)) /* otherwise if the unit is write protected */
|
else if (sim_tape_wrp (uptr)) /* otherwise if the unit is write protected */
|
||||||
return MTSE_WRP; /* then we cannot write */
|
return MTSE_WRP; /* then we cannot write */
|
||||||
|
|
||||||
else if (format != MTUF_F_STD) /* if erase gaps aren't supported by the format */
|
else if (gap_size == 0 || format != MTUF_F_STD) /* otherwise if zero length or gaps aren't supported */
|
||||||
return MTSE_OK; /* then take no action */
|
return MTSE_OK; /* then take no action */
|
||||||
|
|
||||||
file_size = sim_fsize (uptr->fileref); /* get file size */
|
file_size = sim_fsize (uptr->fileref); /* get the file size */
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */
|
|
||||||
|
|
||||||
/* Read tape records and allocate to gap until amount required is consumed.
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) { /* position the tape; if it fails */
|
||||||
|
MT_SET_PNU (uptr); /* then set position not updated */
|
||||||
|
return sim_tape_ioerr (uptr); /* and quit with I/O error status */
|
||||||
|
}
|
||||||
|
|
||||||
Read next metadatum from tape:
|
/* Read tape records and allocate them to the gap until the amount required is
|
||||||
|
consumed.
|
||||||
|
|
||||||
|
Read the next metadatum from tape:
|
||||||
- EOF or EOM: allocate remainder of bytes needed.
|
- EOF or EOM: allocate remainder of bytes needed.
|
||||||
- TMK or GAP: allocate sizeof(metadatum) bytes.
|
- TMK or GAP: allocate sizeof(metadatum) bytes.
|
||||||
- Reverse GAP: allocate sizeof(metadatum) / 2 bytes.
|
- Reverse GAP: allocate sizeof(metadatum) / 2 bytes.
|
||||||
- Data record: see below.
|
- Data record: see below.
|
||||||
|
|
||||||
Loop until bytes needed = 0.
|
Loop until the bytes needed = 0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sim_fread (&meta, meta_size, 1, uptr->fileref); /* read metadatum */
|
xfer = sim_fread (&meta, meta_size, 1, uptr->fileref); /* read a metadatum */
|
||||||
|
|
||||||
if (ferror (uptr->fileref)) { /* read error? */
|
if (ferror (uptr->fileref)) { /* read error? */
|
||||||
uptr->pos = gap_pos; /* restore original position */
|
uptr->pos = gap_pos; /* restore original position */
|
||||||
@@ -942,8 +1034,14 @@ do {
|
|||||||
return sim_tape_ioerr (uptr); /* translate error */
|
return sim_tape_ioerr (uptr); /* translate error */
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else if (xfer != 1 && feof (uptr->fileref) == 0) { /* otherwise if a partial metadatum was read */
|
||||||
uptr->pos = uptr->pos + meta_size; /* move tape over datum */
|
uptr->pos = gap_pos; /* then restore the original position */
|
||||||
|
MT_SET_PNU (uptr); /* set the position-not-updated flag */
|
||||||
|
return MTSE_INVRL; /* and return an invalid record length error */
|
||||||
|
}
|
||||||
|
|
||||||
|
else /* otherwise we had a good read */
|
||||||
|
uptr->pos = uptr->pos + meta_size; /* so move the tape over the datum */
|
||||||
|
|
||||||
if (feof (uptr->fileref) || (meta == MTR_EOM)) { /* at eof or eom? */
|
if (feof (uptr->fileref) || (meta == MTR_EOM)) { /* at eof or eom? */
|
||||||
gap_alloc = gap_alloc + gap_needed; /* allocate remainder */
|
gap_alloc = gap_alloc + gap_needed; /* allocate remainder */
|
||||||
@@ -955,17 +1053,25 @@ do {
|
|||||||
gap_needed = gap_needed - meta_size; /* reduce requirement */
|
gap_needed = gap_needed - meta_size; /* reduce requirement */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (gap_size == meta_size) { /* otherwise if the request is for a single metadatum */
|
||||||
|
uptr->pos = gap_pos; /* then restore the original position */
|
||||||
|
MT_SET_PNU (uptr); /* set the position-not-updated flag */
|
||||||
|
return MTSE_INVRL; /* and return an invalid record length error */
|
||||||
|
}
|
||||||
|
|
||||||
else if (meta == MTR_FHGAP) { /* half gap? */
|
else if (meta == MTR_FHGAP) { /* half gap? */
|
||||||
uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */
|
uptr->pos = uptr->pos - meta_size / 2; /* backup to resync */
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */
|
|
||||||
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */
|
||||||
|
return sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
|
|
||||||
gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */
|
gap_alloc = gap_alloc + meta_size / 2; /* allocate marker space */
|
||||||
gap_needed = gap_needed - meta_size / 2; /* reduce requirement */
|
gap_needed = gap_needed - meta_size / 2; /* reduce requirement */
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (uptr->pos +
|
else if (uptr->pos + MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */
|
||||||
MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */
|
gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */
|
||||||
gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */
|
gap_needed = 0; /* allocate remainder */
|
||||||
gap_needed = 0; /* allocate remainder */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate a data record:
|
/* Allocate a data record:
|
||||||
@@ -974,13 +1080,17 @@ do {
|
|||||||
allocate entire record to gap, else allocate needed amount and
|
allocate entire record to gap, else allocate needed amount and
|
||||||
truncate data record to reflect remainder.
|
truncate data record to reflect remainder.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else { /* data record */
|
else { /* data record */
|
||||||
sbc = MTR_L (meta); /* get record data length */
|
sbc = MTR_L (meta); /* get record data length */
|
||||||
rec_size = ((sbc + 1) & ~1) + meta_size * 2; /* overall size in bytes */
|
rec_size = ((sbc + 1) & ~1) + meta_size * 2; /* overall size in bytes */
|
||||||
|
|
||||||
if (rec_size < gap_needed + min_rec_size) { /* rec too small? */
|
if (rec_size < gap_needed + min_rec_size) { /* rec too small? */
|
||||||
uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */
|
uptr->pos = uptr->pos - meta_size + rec_size; /* position past record */
|
||||||
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* move tape */
|
|
||||||
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */
|
||||||
|
return sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
|
|
||||||
gap_alloc = gap_alloc + rec_size; /* allocate record */
|
gap_alloc = gap_alloc + rec_size; /* allocate record */
|
||||||
gap_needed = gap_needed - rec_size; /* reduce requirement */
|
gap_needed = gap_needed - rec_size; /* reduce requirement */
|
||||||
}
|
}
|
||||||
@@ -1008,7 +1118,7 @@ do {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (gap_needed > 0);
|
while (gap_needed > 0); /* loop until all of the gap has been allocated */
|
||||||
|
|
||||||
uptr->pos = gap_pos; /* reposition to gap start */
|
uptr->pos = gap_pos; /* reposition to gap start */
|
||||||
|
|
||||||
@@ -1054,15 +1164,26 @@ return MTSE_OK;
|
|||||||
write error unchanged, PNU set
|
write error unchanged, PNU set
|
||||||
gap written updated
|
gap written updated
|
||||||
|
|
||||||
|
If the requested byte count equals the metadatum size, then the routine
|
||||||
|
succeeds only if it can overlay a single metadatum (i.e., a tape mark or an
|
||||||
|
existing erase gap marker); otherwise, the file position is not altered, and
|
||||||
|
MTSE_INVRL (invalid record length) status is returned.
|
||||||
|
|
||||||
|
|
||||||
Implementation notes:
|
Implementation notes:
|
||||||
|
|
||||||
1. Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format.
|
1. Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format.
|
||||||
|
|
||||||
2. Erasing in the reverse direction currently succeeds only if the gap
|
2. Erasing a record in the reverse direction currently succeeds only if the
|
||||||
requested occupies the same space as the record located immediately
|
gap requested occupies the same space as the record located immediately
|
||||||
before the current file position. This limitation may be lifted in a
|
before the current file position. This limitation may be lifted in a
|
||||||
future update.
|
future update.
|
||||||
|
|
||||||
|
3. The "sim_fread" call cannot return 0 in the absence of an error
|
||||||
|
condition. The preceding "sim_tape_bot" test ensures that "pos" >= 4, so
|
||||||
|
"sim_fseek" will back up at least that far, so "sim_fread" will read at
|
||||||
|
least one element. If the call returns zero, an error must have
|
||||||
|
occurred, so the "ferror" call must succeed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size)
|
static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size)
|
||||||
@@ -1070,38 +1191,83 @@ static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size)
|
|||||||
const uint32 format = MT_GET_FMT (uptr); /* the tape format */
|
const uint32 format = MT_GET_FMT (uptr); /* the tape format */
|
||||||
const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
const uint32 meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
||||||
t_stat status;
|
t_stat status;
|
||||||
t_mtrlnt rec_size;
|
t_mtrlnt rec_size, metadatum;
|
||||||
t_addr gap_pos;
|
t_addr gap_pos;
|
||||||
|
size_t xfer;
|
||||||
|
|
||||||
MT_CLR_PNU (uptr);
|
MT_CLR_PNU (uptr); /* clear the position-not-updated flag */
|
||||||
|
|
||||||
if (sim_tape_wrp (uptr)) /* if the unit is write protected */
|
if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */
|
||||||
|
return MTSE_UNATT; /* then we cannot proceed */
|
||||||
|
|
||||||
|
else if (sim_tape_wrp (uptr)) /* otherwise if the unit is write protected */
|
||||||
return MTSE_WRP; /* then we cannot write */
|
return MTSE_WRP; /* then we cannot write */
|
||||||
|
|
||||||
else if (format != MTUF_F_STD) /* otherwise if erase gaps aren't supported by the format */
|
else if (gap_size == 0 || format != MTUF_F_STD) /* otherwise if the gap length is zero or unsupported */
|
||||||
return MTSE_OK; /* then take no action */
|
return MTSE_OK; /* then take no action */
|
||||||
|
|
||||||
gap_pos = uptr->pos; /* save the starting position */
|
gap_pos = uptr->pos; /* save the starting position */
|
||||||
|
|
||||||
status = sim_tape_rdlntr (uptr, &rec_size); /* get the length of the preceding record */
|
if (gap_size == meta_size) { /* if the request is for a single metadatum */
|
||||||
|
if (sim_tape_bot (uptr)) /* then if the unit is positioned at the BOT */
|
||||||
|
return MTSE_BOT; /* then erasing backward is not possible */
|
||||||
|
else /* otherwise */
|
||||||
|
uptr->pos -= meta_size; /* back up the file pointer */
|
||||||
|
|
||||||
if (status == MTSE_OK /* if the read succeeded */
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* position the tape; if it fails */
|
||||||
&& gap_size == rec_size + 2 * meta_size) { /* and the gap will exactly overlay the record */
|
return sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
gap_pos = uptr->pos; /* then save the gap start position */
|
|
||||||
|
|
||||||
status = tape_erase_fwd (uptr, gap_size); /* erase the record */
|
sim_fread (&metadatum, meta_size, 1, uptr->fileref); /* read a metadatum */
|
||||||
|
|
||||||
if (status == MTSE_OK) /* if the gap write succeeded */
|
if (ferror (uptr->fileref)) /* if a file I/O error occurred */
|
||||||
uptr->pos = gap_pos; /* the reposition back to the start of the gap */
|
return sim_tape_ioerr (uptr); /* then report the error and quit */
|
||||||
|
|
||||||
|
else if (metadatum == MTR_TMK) /* otherwise if a tape mark is present */
|
||||||
|
if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* then reposition the tape; if it fails */
|
||||||
|
return sim_tape_ioerr (uptr); /* then quit with I/O error status */
|
||||||
|
|
||||||
|
else { /* otherwise */
|
||||||
|
metadatum = MTR_GAP; /* replace it with an erase gap marker */
|
||||||
|
|
||||||
|
xfer = sim_fwrite (&metadatum, meta_size, /* write the gap marker */
|
||||||
|
1, uptr->fileref);
|
||||||
|
|
||||||
|
if (ferror (uptr->fileref) || xfer == 0) /* if a file I/O error occurred */
|
||||||
|
return sim_tape_ioerr (uptr); /* report the error and quit */
|
||||||
|
else /* otherwise the write succeeded */
|
||||||
|
status = MTSE_OK; /* so return success */
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (metadatum == MTR_GAP) /* otherwise if a gap already exists */
|
||||||
|
status = MTSE_OK; /* then take no additional action */
|
||||||
|
|
||||||
|
else { /* otherwise a data record is present */
|
||||||
|
uptr->pos = gap_pos; /* so restore the starting position */
|
||||||
|
return MTSE_INVRL; /* and fail with invalid record length status */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else { /* otherwise the read failed or is the wrong size */
|
else { /* otherwise it's an erase record request */
|
||||||
uptr->pos = gap_pos; /* so restore the starting position */
|
status = sim_tape_rdlntr (uptr, &rec_size); /* so get the length of the preceding record */
|
||||||
|
|
||||||
if (status != MTSE_OK) /* if the record was not found */
|
if (status == MTSE_OK /* if the read succeeded */
|
||||||
return status; /* then return the failure reason */
|
&& gap_size == rec_size + 2 * meta_size) { /* and the gap will exactly overlay the record */
|
||||||
else /* otherwise the record is the wrong size */
|
gap_pos = uptr->pos; /* then save the gap start position */
|
||||||
return MTSE_INVRL; /* so report an invalid record length */
|
|
||||||
|
status = tape_erase_fwd (uptr, gap_size); /* erase the record */
|
||||||
|
|
||||||
|
if (status == MTSE_OK) /* if the gap write succeeded */
|
||||||
|
uptr->pos = gap_pos; /* the reposition back to the start of the gap */
|
||||||
|
}
|
||||||
|
|
||||||
|
else { /* otherwise the read failed or is the wrong size */
|
||||||
|
uptr->pos = gap_pos; /* so restore the starting position */
|
||||||
|
|
||||||
|
if (status != MTSE_OK) /* if the record was not found */
|
||||||
|
return status; /* then return the failure reason */
|
||||||
|
else /* otherwise the record is the wrong size */
|
||||||
|
return MTSE_INVRL; /* so report an invalid record length */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status; /* return the status of the erase operation */
|
return status; /* return the status of the erase operation */
|
||||||
@@ -1115,10 +1281,10 @@ return status; /* return the status of
|
|||||||
sim_tape_set_dens call; if it has not, then no action is taken, and
|
sim_tape_set_dens call; if it has not, then no action is taken, and
|
||||||
MTSE_IOERR is returned.
|
MTSE_IOERR is returned.
|
||||||
|
|
||||||
If the tape format currently selected does not support erase gaps, the call
|
If the requested gap length is zero, or the tape format currently selected
|
||||||
succeeds with no action taken. This allows a device simulator that supports
|
does not support erase gaps, the call succeeds with no action taken. This
|
||||||
writing erase gaps to use the same code without worrying about the tape
|
allows a device simulator that supports writing erase gaps to use the same
|
||||||
format currently selected by the user.
|
code without worrying about the tape format currently selected by the user.
|
||||||
|
|
||||||
Because SIMH tape images do not carry physical parameters (e.g., recording
|
Because SIMH tape images do not carry physical parameters (e.g., recording
|
||||||
density), overwriting a tape image file containing a gap is problematic if
|
density), overwriting a tape image file containing a gap is problematic if
|
||||||
@@ -1149,6 +1315,11 @@ else /* otherwise */
|
|||||||
metadata. This function may be used to erase a record of length "n" in place
|
metadata. This function may be used to erase a record of length "n" in place
|
||||||
by requesting a gap of length "n". After erasure, the tape will be
|
by requesting a gap of length "n". After erasure, the tape will be
|
||||||
positioned at the end of the gap.
|
positioned at the end of the gap.
|
||||||
|
|
||||||
|
If a length of 0 is specified, then the metadatum marker at the current tape
|
||||||
|
position will be erased. If the tape is not positioned at a metadatum
|
||||||
|
marker, the routine fails with MTSE_INVRL, and the tape position is
|
||||||
|
unchanged.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_tape_errecf (UNIT *uptr, t_mtrlnt bc)
|
t_stat sim_tape_errecf (UNIT *uptr, t_mtrlnt bc)
|
||||||
@@ -1156,7 +1327,10 @@ t_stat sim_tape_errecf (UNIT *uptr, t_mtrlnt bc)
|
|||||||
const t_mtrlnt meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
const t_mtrlnt meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
||||||
const t_mtrlnt gap_size = bc + 2 * meta_size; /* the requested gap size in bytes */
|
const t_mtrlnt gap_size = bc + 2 * meta_size; /* the requested gap size in bytes */
|
||||||
|
|
||||||
return tape_erase_fwd (uptr, gap_size); /* erase the requested gap */
|
if (bc == 0) /* if a zero-length erase is requested */
|
||||||
|
return tape_erase_fwd (uptr, meta_size); /* then erase a metadatum marker */
|
||||||
|
else /* otherwise */
|
||||||
|
return tape_erase_fwd (uptr, gap_size); /* erase the requested gap */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Erase a record reverse.
|
/* Erase a record reverse.
|
||||||
@@ -1168,6 +1342,11 @@ return tape_erase_fwd (uptr, gap_size); /* erase the requested g
|
|||||||
metadata. This function may be used to erase a record of length "n" in place
|
metadata. This function may be used to erase a record of length "n" in place
|
||||||
by requesting a gap of length "n". After erasure, the tape will be
|
by requesting a gap of length "n". After erasure, the tape will be
|
||||||
positioned at the start of the gap.
|
positioned at the start of the gap.
|
||||||
|
|
||||||
|
If a length of 0 is specified, then the metadatum marker preceding the
|
||||||
|
current tape position will be erased. If the tape is not positioned after a
|
||||||
|
metadatum marker, the routine fails with MTSE_INVRL, and the tape position is
|
||||||
|
unchanged.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
t_stat sim_tape_errecr (UNIT *uptr, t_mtrlnt bc)
|
t_stat sim_tape_errecr (UNIT *uptr, t_mtrlnt bc)
|
||||||
@@ -1175,7 +1354,10 @@ t_stat sim_tape_errecr (UNIT *uptr, t_mtrlnt bc)
|
|||||||
const t_mtrlnt meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
const t_mtrlnt meta_size = sizeof (t_mtrlnt); /* the number of bytes per metadatum */
|
||||||
const t_mtrlnt gap_size = bc + 2 * meta_size; /* the requested gap size in bytes */
|
const t_mtrlnt gap_size = bc + 2 * meta_size; /* the requested gap size in bytes */
|
||||||
|
|
||||||
return tape_erase_rev (uptr, gap_size); /* erase the requested gap */
|
if (bc == 0) /* if a zero-length erase is requested */
|
||||||
|
return tape_erase_rev (uptr, meta_size); /* then erase a metadatum marker */
|
||||||
|
else /* otherwise */
|
||||||
|
return tape_erase_rev (uptr, gap_size); /* erase the requested gap */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Space record forward */
|
/* Space record forward */
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/* sim_tape.h: simulator tape support library definitions
|
/* sim_tape.h: simulator tape support library definitions
|
||||||
|
|
||||||
Copyright (c) 1993-2016, Robert M Supnik
|
Copyright (c) 1993-2016, Robert M Supnik
|
||||||
|
Copyright (c) 2017 J. David Bryan
|
||||||
|
|
||||||
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"),
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
used in advertising or otherwise to promote the sale, use or other dealings
|
used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
in this Software without prior written authorization from Robert M Supnik.
|
in this Software without prior written authorization from Robert M Supnik.
|
||||||
|
|
||||||
|
22-Apr-17 JDB Added MTSE_LEOT value for 4.x compatibility
|
||||||
18-Jul-16 JDB Added sim_tape_errecf, sim_tape_errecr functions
|
18-Jul-16 JDB Added sim_tape_errecf, sim_tape_errecr functions
|
||||||
15-Dec-14 JDB Added tape density validity flags
|
15-Dec-14 JDB Added tape density validity flags
|
||||||
04-Nov-14 JDB Added tape density flags
|
04-Nov-14 JDB Added tape density flags
|
||||||
@@ -126,7 +128,8 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */
|
|||||||
#define MTSE_EOM 7 /* end of medium */
|
#define MTSE_EOM 7 /* end of medium */
|
||||||
#define MTSE_RECE 8 /* error in record */
|
#define MTSE_RECE 8 /* error in record */
|
||||||
#define MTSE_WRP 9 /* write protected */
|
#define MTSE_WRP 9 /* write protected */
|
||||||
#define MTSE_RUNAWAY 10 /* tape runaway */
|
#define MTSE_LEOT 10 /* Logical End Of Tape (4.x) */
|
||||||
|
#define MTSE_RUNAWAY 11 /* tape runaway */
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user