The source set has been extensively overhauled. For correct viewing, set Visual C++ or Emacs to have tab stops every 4 characters. 1. New Features 1.1 3.5-0 1.1.1 All Ethernet devices - Added Windows user-defined adapter names (from Timothe Litt) 1.1.2 Interdata, SDS, HP, PDP-8, PDP-18b terminal multiplexors - Added support for SET <unit>n DISCONNECT 1.1.3 VAX - Added latent QDSS support - Revised autoconfigure to handle QDSS 1.1.4 PDP-11 - Revised autoconfigure to handle more cases 1.2 3.5-1 No new features 1.3 3.5-2 1.3.1 All ASCII terminals - Most ASCII terminal emulators have supported 7-bit and 8-bit operation; where required, they have also supported an upper- case only or KSR-emulation mode. This release adds a new mode, 7P, for 7-bit printing characters. In 7P mode, non-printing characters in the range 0-31 (decimal), and 127 (decimal), are automatically suppressed. This prevents printing of fill characters under Windows. The printable character set for ASCII code values 0-31 can be changed with the SET CONSOLE PCHAR command. Code value 127 (DELETE) is always suppressed. 1.3.2 VAX-11/780 - First release. The VAX-11/780 has successfully run VMS V7.2. The commercial instructions and compatability mode have not been extensively tested. The Ethernet controller is not working yet and is disabled. 2. Bugs Fixed 2.1 3.5-0 2.1.1 SCP and libraries - Trim trailing spaces on all input (for example, attach file names) - Fixed sim_sock spurious SIGPIPE error in Unix/Linux - Fixed sim_tape misallocation of TPC map array for 64b simulators 2.1.2 1401 - Fixed bug, CPU reset was clearing SSB through SSG 2.1.3 PDP-11 - Fixed bug in VH vector display routine - Fixed XU runt packet processing (found by Tim Chapman) 2.1.4 Interdata - Fixed bug in SHOW PAS CONN/STATS - Fixed potential integer overflow exception in divide 2.1.5 SDS - Fixed bug in SHOW MUX CONN/STATS 2.1.6 HP - Fixed bug in SHOW MUX CONN/STATS 2.1.7 PDP-8 - Fixed bug in SHOW TTIX CONN/STATS - Fixed bug in SET/SHOW TTOXn LOG 2.1.8 PDP-18b - Fixed bug in SHOW TTIX CONN/STATS - Fixed bug in SET/SHOW TTOXn LOG 2.1.9 Nova, Eclipse - Fixed potential integer overflow exception in divide 2.2 3.5-1 2.2.1 1401 - Changed character encodings to be compatible with Pierce 709X simulator - Added mode for old/new character encodings 2.2.2 1620 - Changed character encodings to be compatible with Pierce 709X simulator 2.2.3 PDP-10 - Changed MOVNI to eliminate GCC warning 2.2.4 VAX - Fixed bug in structure definitions with 32b compilation options - Fixed bug in autoconfiguration table 2.2.5 PDP-11 - Fixed bug in autoconfiguration table 2.3 3.5-2 2.3.1 PDP-10 - RP: fixed drive clear not to clear disk address 2.3.2 PDP-11 (VAX, VAX-11/780, for shared peripherals) - HK: fixed overlap seek interaction with drive select, drive clear, etc - RQ, TM, TQ, TS, TU: widened address display to 64b when USE_ADDR64 option selected - TU: changed default adapter from TM02 to TM03 (required by VMS) - RP: fixed drive clear not to clear disk address - RP, TU: fixed device enable/disable to enabled/disable Massbus adapter as well - XQ: fixed register access alignment bug (found by Doug Carman) 2.3.3 PDP-8 - RL: fixed IOT 61 decoding bug (found by David Gesswein) - DF, DT, RF: fixed register access alignment bug (found by Doug Carman) 2.3.4 VAX - Fixed CVTfi to trap on integer overflow if PSW<iv> is set - Fixed breakpoint detection when USE_ADDR64 option selected
647 lines
22 KiB
C
647 lines
22 KiB
C
/* sim_tape.c: simulator tape support library
|
|
|
|
Copyright (c) 1993-2006, Robert M Supnik
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Robert M Supnik shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Robert M Supnik.
|
|
|
|
Ultimately, this will be a place to hide processing of various tape formats,
|
|
as well as OS-specific direct hardware access.
|
|
|
|
23-Jan-05 RMS Fixed bug in write forward (found by Dave Bryan)
|
|
17-Dec-05 RMS Added write support for Paul Pierce 7b format
|
|
16-Aug-05 RMS Fixed C++ declaration and cast problems
|
|
02-May-05 RMS Added support for Pierce 7b format
|
|
28-Jul-04 RMS Fixed bug in writing error records (found by Dave Bryan)
|
|
RMS Fixed incorrect error codes (found by Dave Bryan)
|
|
05-Jan-04 RMS Revised for file I/O library
|
|
25-Apr-03 RMS Added extended file support
|
|
28-Mar-03 RMS Added E11 and TPC format support
|
|
|
|
Public routines:
|
|
|
|
sim_tape_attach attach tape unit
|
|
sim_tape_detach detach tape unit
|
|
sim_tape_rdrecf read tape record forward
|
|
sim_tape_rdrecr read tape record reverse
|
|
sim_tape_wrrecf write tape record forward
|
|
sim_tape_sprecf space tape record forward
|
|
sim_tape_sprecr space tape record reverse
|
|
sim_tape_wrtmk write tape mark
|
|
sim_tape_wrtmk_7t write tape mark, 7 track with parity
|
|
sim_tape_wreom erase remainder of tape
|
|
sim_tape_rewind rewind
|
|
sim_tape_reset reset unit
|
|
sim_tape_bot TRUE if at beginning of tape
|
|
sim_tape_eot TRUE if at or beyond end of tape
|
|
sim_tape_wrp TRUE if write protected
|
|
sim_tape_set_fmt set tape format
|
|
sim_tape_show_fmt show tape format
|
|
*/
|
|
|
|
#include "sim_defs.h"
|
|
#include "sim_tape.h"
|
|
|
|
struct sim_tape_fmt {
|
|
char *name; /* name */
|
|
int32 uflags; /* unit flags */
|
|
t_addr bot; /* bot test */
|
|
};
|
|
|
|
static struct sim_tape_fmt fmts[MTUF_N_FMT] = {
|
|
{ "SIMH", 0, sizeof (t_mtrlnt) - 1 },
|
|
{ "E11", 0, sizeof (t_mtrlnt) - 1 },
|
|
{ "TPC", UNIT_RO, sizeof (t_tpclnt) - 1 },
|
|
{ "P7B", 0, 0 },
|
|
/* { "TPF", UNIT_RO, 0 }, */
|
|
{ NULL, 0, 0 }
|
|
};
|
|
|
|
extern int32 sim_switches;
|
|
|
|
t_stat sim_tape_ioerr (UNIT *uptr);
|
|
t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat);
|
|
uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map);
|
|
t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map);
|
|
|
|
/* Attach tape unit */
|
|
|
|
t_stat sim_tape_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
uint32 objc;
|
|
char gbuf[CBUFSIZE];
|
|
t_stat r;
|
|
|
|
if (sim_switches & SWMASK ('F')) { /* format spec? */
|
|
cptr = get_glyph (cptr, gbuf, 0); /* get spec */
|
|
if (*cptr == 0) return SCPE_2FARG; /* must be more */
|
|
if (sim_tape_set_fmt (uptr, 0, gbuf, NULL) != SCPE_OK)
|
|
return SCPE_ARG;
|
|
}
|
|
r = attach_unit (uptr, cptr); /* attach unit */
|
|
if (r != SCPE_OK) return r; /* error? */
|
|
switch (MT_GET_FMT (uptr)) { /* case on format */
|
|
|
|
case MTUF_F_TPC: /* TPC */
|
|
objc = sim_tape_tpc_map (uptr, NULL); /* get # objects */
|
|
if (objc == 0) { /* tape empty? */
|
|
sim_tape_detach (uptr);
|
|
return SCPE_FMT; /* yes, complain */
|
|
}
|
|
uptr->filebuf = calloc (objc + 1, sizeof (t_addr));
|
|
if (uptr->filebuf == NULL) { /* map allocated? */
|
|
sim_tape_detach (uptr);
|
|
return SCPE_MEM; /* no, complain */
|
|
}
|
|
uptr->hwmark = objc + 1; /* save map size */
|
|
sim_tape_tpc_map (uptr, (t_addr *) uptr->filebuf); /* fill map */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
sim_tape_rewind (uptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Detach tape unit */
|
|
|
|
t_stat sim_tape_detach (UNIT *uptr)
|
|
{
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_stat r;
|
|
|
|
r = detach_unit (uptr); /* detach unit */
|
|
if (r != SCPE_OK) return r;
|
|
switch (f) { /* case on format */
|
|
|
|
case MTUF_F_TPC: /* TPC */
|
|
if (uptr->filebuf) free (uptr->filebuf); /* free map */
|
|
uptr->filebuf = NULL;
|
|
uptr->hwmark = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
sim_tape_rewind (uptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Read record length forward (internal routine)
|
|
|
|
Inputs:
|
|
uptr = pointer to tape unit
|
|
bc = pointer to returned record length
|
|
Outputs:
|
|
status = operation status
|
|
|
|
exit condition position
|
|
|
|
unit unattached unchanged
|
|
read error unchanged, PNU set
|
|
end of file/medium unchanged, PNU set
|
|
tape mark updated
|
|
data record updated, sim_fread will read record forward
|
|
*/
|
|
|
|
t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc)
|
|
{
|
|
uint8 c;
|
|
t_bool all_eof;
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_mtrlnt sbc;
|
|
t_tpclnt tpcbc;
|
|
|
|
MT_CLR_PNU (uptr);
|
|
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */
|
|
switch (f) { /* switch on fmt */
|
|
|
|
case MTUF_F_STD: case MTUF_F_E11:
|
|
sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */
|
|
sbc = MTR_L (*bc); /* save rec lnt */
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr); /* pos not upd */
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */
|
|
MT_SET_PNU (uptr); /* pos not upd */
|
|
return MTSE_EOM;
|
|
}
|
|
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */
|
|
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
|
uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */
|
|
((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc);
|
|
break;
|
|
|
|
case MTUF_F_TPC:
|
|
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
|
*bc = tpcbc; /* save rec lnt */
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr); /* pos not upd */
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
if (feof (uptr->fileref)) { /* eof? */
|
|
MT_SET_PNU (uptr); /* pos not upd */
|
|
return MTSE_EOM;
|
|
}
|
|
uptr->pos = uptr->pos + sizeof (t_tpclnt); /* spc over reclnt */
|
|
if (tpcbc == TPC_TMK) return MTSE_TMK; /* tape mark? */
|
|
uptr->pos = uptr->pos + ((tpcbc + 1) & ~1); /* spc over record */
|
|
break;
|
|
|
|
case MTUF_F_P7B:
|
|
for (sbc = 0, all_eof = 1; ; sbc++) { /* loop thru record */
|
|
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr); /* pos not upd */
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
if (feof (uptr->fileref)) { /* eof? */
|
|
if (sbc == 0) return MTSE_EOM; /* no data? eom */
|
|
break; /* treat like eor */
|
|
}
|
|
if ((sbc != 0) && (c & P7B_SOR)) break; /* next record? */
|
|
if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0;
|
|
}
|
|
*bc = sbc; /* save rec lnt */
|
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
|
uptr->pos = uptr->pos + sbc; /* spc over record */
|
|
if (all_eof) return MTSE_TMK; /* tape mark? */
|
|
break;
|
|
|
|
default:
|
|
return MTSE_FMT;
|
|
}
|
|
|
|
return MTSE_OK;
|
|
}
|
|
|
|
/* Read record length reverse (internal routine)
|
|
|
|
Inputs:
|
|
uptr = pointer to tape unit
|
|
bc = pointer to returned record length
|
|
Outputs:
|
|
status = operation status
|
|
|
|
exit condition position
|
|
|
|
unit unattached unchanged
|
|
beginning of tape unchanged
|
|
read error unchanged
|
|
end of file unchanged
|
|
end of medium updated
|
|
tape mark updated
|
|
data record updated, sim_fread will read record forward
|
|
*/
|
|
|
|
t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc)
|
|
{
|
|
uint8 c;
|
|
t_bool all_eof;
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_addr ppos;
|
|
t_mtrlnt sbc;
|
|
t_tpclnt tpcbc;
|
|
|
|
MT_CLR_PNU (uptr);
|
|
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
|
if (sim_tape_bot (uptr)) return MTSE_BOT; /* at BOT? */
|
|
switch (f) { /* switch on fmt */
|
|
|
|
case MTUF_F_STD: case MTUF_F_E11:
|
|
sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET);
|
|
sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */
|
|
sbc = MTR_L (*bc);
|
|
if (ferror (uptr->fileref)) /* error? */
|
|
return sim_tape_ioerr (uptr);
|
|
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
|
uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */
|
|
if (*bc == MTR_EOM) return MTSE_EOM; /* eom? */
|
|
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
|
uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */
|
|
((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc);
|
|
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET);
|
|
break;
|
|
|
|
case MTUF_F_TPC:
|
|
ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */
|
|
sim_fseek (uptr->fileref, ppos, SEEK_SET); /* position */
|
|
sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref);
|
|
*bc = tpcbc; /* save rec lnt */
|
|
if (ferror (uptr->fileref)) /* error? */
|
|
return sim_tape_ioerr (uptr);
|
|
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
|
uptr->pos = ppos; /* spc over record */
|
|
if (*bc == MTR_TMK) return MTSE_TMK; /* tape mark? */
|
|
sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET);
|
|
break;
|
|
|
|
case MTUF_F_P7B:
|
|
for (sbc = 1, all_eof = 1; ; sbc++) { /* loop thru record */
|
|
sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET);
|
|
sim_fread (&c, sizeof (uint8), 1, uptr->fileref);
|
|
if (ferror (uptr->fileref)) /* error? */
|
|
return sim_tape_ioerr (uptr);
|
|
if (feof (uptr->fileref)) return MTSE_EOM; /* eof? */
|
|
if ((c & P7B_DPAR) != P7B_EOF) all_eof = 0;
|
|
if (c & P7B_SOR) break; /* start of record? */
|
|
}
|
|
uptr->pos = uptr->pos - sbc; /* update position */
|
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */
|
|
if (all_eof) return MTSE_TMK; /* tape mark? */
|
|
break;
|
|
|
|
default:
|
|
return MTSE_FMT;
|
|
}
|
|
|
|
return MTSE_OK;
|
|
}
|
|
|
|
/* Read record forward
|
|
|
|
Inputs:
|
|
uptr = pointer to tape unit
|
|
buf = pointer to buffer
|
|
bc = pointer to returned record length
|
|
max = maximum record size
|
|
Outputs:
|
|
status = operation status
|
|
|
|
exit condition position
|
|
|
|
unit unattached unchanged
|
|
read error unchanged, PNU set
|
|
end of file/medium unchanged, PNU set
|
|
invalid record unchanged, PNU set
|
|
tape mark updated
|
|
data record updated
|
|
data record error updated
|
|
*/
|
|
|
|
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
|
|
{
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_mtrlnt i, tbc, rbc;
|
|
t_addr opos;
|
|
t_stat st;
|
|
|
|
opos = uptr->pos; /* old position */
|
|
if (st = sim_tape_rdlntf (uptr, &tbc)) return st; /* read rec lnt */
|
|
*bc = rbc = MTR_L (tbc); /* strip error flag */
|
|
if (rbc > max) { /* rec out of range? */
|
|
MT_SET_PNU (uptr);
|
|
uptr->pos = opos;
|
|
return MTSE_INVRL;
|
|
}
|
|
i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr);
|
|
uptr->pos = opos;
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
for ( ; i < rbc; i++) buf[i] = 0; /* fill with 0's */
|
|
if (f == MTUF_F_P7B) buf[0] = buf[0] & P7B_DPAR; /* p7b? strip SOR */
|
|
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
|
|
}
|
|
|
|
/* Read record reverse
|
|
|
|
Inputs:
|
|
uptr = pointer to tape unit
|
|
buf = pointer to buffer
|
|
bc = pointer to returned record length
|
|
max = maximum record size
|
|
Outputs:
|
|
status = operation status
|
|
|
|
exit condition position
|
|
|
|
unit unattached unchanged
|
|
read error unchanged
|
|
end of file unchanged
|
|
end of medium updated
|
|
invalid record unchanged
|
|
tape mark updated
|
|
data record updated
|
|
data record error updated
|
|
*/
|
|
|
|
t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max)
|
|
{
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_mtrlnt i, rbc, tbc;
|
|
t_stat st;
|
|
|
|
if (st = sim_tape_rdlntr (uptr, &tbc)) return st; /* read rec lnt */
|
|
*bc = rbc = MTR_L (tbc); /* strip error flag */
|
|
if (rbc > max) return MTSE_INVRL; /* rec out of range? */
|
|
i = sim_fread (buf, sizeof (uint8), rbc, uptr->fileref); /* read record */
|
|
if (ferror (uptr->fileref)) /* error? */
|
|
return sim_tape_ioerr (uptr);
|
|
for ( ; i < rbc; i++) buf[i] = 0; /* fill with 0's */
|
|
if (f == MTUF_F_P7B) buf[0] = buf[0] & P7B_DPAR; /* p7b? strip SOR */
|
|
return (MTR_F (tbc)? MTSE_RECE: MTSE_OK);
|
|
}
|
|
|
|
/* Write record forward
|
|
|
|
Inputs:
|
|
uptr = pointer to tape unit
|
|
buf = pointer to buffer
|
|
bc = record length
|
|
Outputs:
|
|
status = operation status
|
|
|
|
exit condition position
|
|
|
|
unit unattached unchanged
|
|
write protect unchanged
|
|
write error unchanged, PNU set
|
|
data record updated
|
|
*/
|
|
|
|
t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc)
|
|
{
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
t_mtrlnt sbc;
|
|
|
|
MT_CLR_PNU (uptr);
|
|
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
|
if (sim_tape_wrp (uptr)) return MTSE_WRP; /* write prot? */
|
|
sbc = MTR_L (bc);
|
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */
|
|
switch (f) { /* case on format */
|
|
|
|
case MTUF_F_STD: /* standard */
|
|
sbc = MTR_L ((bc + 1) & ~1); /* pad odd length */
|
|
case MTUF_F_E11: /* E11 */
|
|
sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
|
|
sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
|
|
sim_fwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref);
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr);
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
uptr->pos = uptr->pos + sbc + (2 * sizeof (t_mtrlnt)); /* move tape */
|
|
break;
|
|
|
|
case MTUF_F_P7B: /* Pierce 7B */
|
|
buf[0] = buf[0] | P7B_SOR; /* mark start of rec */
|
|
sim_fwrite (buf, sizeof (uint8), sbc, uptr->fileref);
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr);
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
uptr->pos = uptr->pos + sbc; /* move tape */
|
|
break;
|
|
}
|
|
|
|
return MTSE_OK;
|
|
}
|
|
|
|
/* Write metadata forward (internal routine) */
|
|
|
|
t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat)
|
|
{
|
|
MT_CLR_PNU (uptr);
|
|
if ((uptr->flags & UNIT_ATT) == 0) return MTSE_UNATT; /* not attached? */
|
|
if (sim_tape_wrp (uptr)) return MTSE_WRP; /* write prot? */
|
|
sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */
|
|
sim_fwrite (&dat, sizeof (t_mtrlnt), 1, uptr->fileref);
|
|
if (ferror (uptr->fileref)) { /* error? */
|
|
MT_SET_PNU (uptr);
|
|
return sim_tape_ioerr (uptr);
|
|
}
|
|
uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* move tape */
|
|
return MTSE_OK;
|
|
}
|
|
|
|
/* Write tape mark */
|
|
|
|
t_stat sim_tape_wrtmk (UNIT *uptr)
|
|
{
|
|
if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */
|
|
uint8 buf= P7B_EOF; /* eof mark */
|
|
return sim_tape_wrrecf (uptr, &buf, 1); /* write char */
|
|
}
|
|
return sim_tape_wrdata (uptr, MTR_TMK);
|
|
}
|
|
|
|
/* Write end of medium */
|
|
|
|
t_stat sim_tape_wreom (UNIT *uptr)
|
|
{
|
|
if (MT_GET_FMT (uptr) == MTUF_F_P7B) return MTSE_FMT; /* cant do P7B */
|
|
return sim_tape_wrdata (uptr, MTR_EOM);
|
|
}
|
|
|
|
/* Space record forward */
|
|
|
|
t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc)
|
|
{
|
|
t_stat st;
|
|
|
|
st = sim_tape_rdlntf (uptr, bc); /* get record length */
|
|
*bc = MTR_L (*bc);
|
|
return st;
|
|
}
|
|
|
|
/* Space record reverse */
|
|
|
|
t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc)
|
|
{
|
|
t_stat st;
|
|
|
|
if (MT_TST_PNU (uptr)) {
|
|
MT_CLR_PNU (uptr);
|
|
*bc = 0;
|
|
return MTSE_OK;
|
|
}
|
|
st = sim_tape_rdlntr (uptr, bc); /* get record length */
|
|
*bc = MTR_L (*bc);
|
|
return st;
|
|
}
|
|
|
|
/* Rewind tape */
|
|
|
|
t_stat sim_tape_rewind (UNIT *uptr)
|
|
{
|
|
uptr->pos = 0;
|
|
MT_CLR_PNU (uptr);
|
|
return MTSE_OK;
|
|
}
|
|
|
|
/* Reset tape */
|
|
|
|
t_stat sim_tape_reset (UNIT *uptr)
|
|
{
|
|
MT_CLR_PNU (uptr);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Test for BOT */
|
|
|
|
t_bool sim_tape_bot (UNIT *uptr)
|
|
{
|
|
uint32 f = MT_GET_FMT (uptr);
|
|
|
|
return (uptr->pos <= fmts[f].bot)? TRUE: FALSE;
|
|
}
|
|
|
|
/* Test for end of tape */
|
|
|
|
t_bool sim_tape_eot (UNIT *uptr, t_addr cap)
|
|
{
|
|
return (uptr->pos > cap)? TRUE: FALSE;
|
|
}
|
|
|
|
/* Test for write protect */
|
|
|
|
t_bool sim_tape_wrp (UNIT *uptr)
|
|
{
|
|
return (uptr->flags & MTUF_WRP)? TRUE: FALSE;
|
|
}
|
|
|
|
/* Process I/O error */
|
|
|
|
t_stat sim_tape_ioerr (UNIT *uptr)
|
|
{
|
|
perror ("Magtape library I/O error");
|
|
clearerr (uptr->fileref);
|
|
return MTSE_IOERR;
|
|
}
|
|
|
|
/* Set tape format */
|
|
|
|
t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc)
|
|
{
|
|
int32 f;
|
|
|
|
if (uptr == NULL) return SCPE_IERR;
|
|
if (cptr == NULL) return SCPE_ARG;
|
|
for (f = 0; f < MTUF_N_FMT; f++) {
|
|
if (fmts[f].name && (strcmp (cptr, fmts[f].name) == 0)) {
|
|
uptr->flags = (uptr->flags & ~MTUF_FMT) |
|
|
(f << MTUF_V_FMT) | fmts[f].uflags;
|
|
return SCPE_OK;
|
|
}
|
|
}
|
|
return SCPE_ARG;
|
|
}
|
|
|
|
/* Show tape format */
|
|
|
|
t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc)
|
|
{
|
|
int32 f = MT_GET_FMT (uptr);
|
|
|
|
if (fmts[f].name) fprintf (st, "%s format", fmts[f].name);
|
|
else fprintf (st, "invalid format");
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Map a TPC format tape image */
|
|
|
|
uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map)
|
|
{
|
|
t_addr tpos;
|
|
t_tpclnt bc;
|
|
uint32 i, objc;
|
|
|
|
if ((uptr == NULL) || (uptr->fileref == NULL)) return 0;
|
|
for (objc = 0, tpos = 0;; ) {
|
|
sim_fseek (uptr->fileref, tpos, SEEK_SET);
|
|
i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref);
|
|
if (i == 0) break;
|
|
if (map) map[objc] = tpos;
|
|
objc++;
|
|
tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt);
|
|
}
|
|
if (map) map[objc] = tpos;
|
|
return objc;
|
|
}
|
|
|
|
/* Find the preceding record in a TPC file */
|
|
|
|
t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map)
|
|
{
|
|
uint32 lo, hi, p;
|
|
|
|
|
|
if (map == NULL) return 0;
|
|
lo = 0;
|
|
hi = uptr->hwmark - 1;
|
|
do {
|
|
p = (lo + hi) >> 1;
|
|
if (uptr->pos == map[p])
|
|
return ((p == 0)? map[p]: map[p - 1]);
|
|
else if (uptr->pos < map[p]) hi = p - 1;
|
|
else lo = p + 1;
|
|
}
|
|
while (lo <= hi);
|
|
return ((p == 0)? map[p]: map[p - 1]);
|
|
}
|