diff --git a/display/ng.c b/display/ng.c index 5ffde51..53914d2 100644 --- a/display/ng.c +++ b/display/ng.c @@ -37,10 +37,16 @@ static void *ng_dptr; static int ng_dbit; +#if defined(__cplusplus) +extern "C" { +#endif #define DEVICE void extern void _sim_debug_device (unsigned int dbits, DEVICE* dptr, const char* fmt, ...); #define DEBUGF(...) _sim_debug_device (ng_dbit, ng_dptr, ## __VA_ARGS__) +#if defined(__cplusplus) +} +#endif int ng_type = 0; int ng_scale = PIX_SCALE; diff --git a/scp.c b/scp.c index d8eafe2..f798f79 100644 --- a/scp.c +++ b/scp.c @@ -2240,7 +2240,7 @@ static const char simh_help[] = " Specifies a true (false {NOT}) condition if the file exists.\n" "5File Comparison Expressions\n" " Files can have their contents compared with:\n\n" - "++-D {NOT} \"\" == \"\" \n\n" + "++-F {NOT} \"\" == \"\" \n\n" " Specifies a true (false {NOT}) condition if the indicated files\n" " have the same contents.\n\n" /***************** 80 character line width template *************************/ @@ -2637,7 +2637,7 @@ else if (*argv[0]) { /* sim name arg? */ if (SCPE_BARE_STATUS(stat) == SCPE_OPENERR) /* didn't exist/can't open? */ stat = SCPE_OK; -if (sim_switches & SWMASK ('T')) /* Command Line -T switch */ +if (sim_switches & SWMASK ('T')) /* Command Line -T switch */ stat = sim_library_unit_tests (); /* run library unit tests */ if (SCPE_BARE_STATUS(stat) != SCPE_EXIT) @@ -4260,7 +4260,6 @@ for (i=1; ireset != NULL) { reason = dptr->reset (dptr); if (reason != SCPE_OK) @@ -6879,6 +6880,7 @@ return attach_unit (uptr, (CONST char *)cptr); /* no, std routine */ t_stat attach_unit (UNIT *uptr, CONST char *cptr) { DEVICE *dptr; +t_bool open_rw = FALSE; if (!(uptr->flags & UNIT_ATTABLE)) /* not attachable? */ return SCPE_NOATT; @@ -6932,6 +6934,8 @@ else { sim_messagef (SCPE_OK, "%s: creating new file\n", sim_dname (dptr)); } } /* end if null */ + else + open_rw = TRUE; } /* end else */ } if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ @@ -6947,6 +6951,12 @@ if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ } uptr->flags = uptr->flags | UNIT_ATT; uptr->pos = 0; +if (open_rw && /* open for write in append mode? */ + (sim_switches & SWMASK ('A')) && + (uptr->flags & UNIT_SEQ) && + (!(uptr->flags & UNIT_MUSTBUF)) && + (0 == sim_fseek (uptr->fileref, 0, SEEK_END))) + uptr->pos = (t_addr)sim_ftell (uptr->fileref); /* Position at end of file */ return SCPE_OK; } @@ -12894,6 +12904,11 @@ if (sim_deb && ((dptr->dctrl | (uptr ? uptr->dctrl : 0)) & reason)) { ebcdicbuf[eidx++] = '.'; } } + for (; sidx<16; ++sidx) { + strbuf[soff+sidx] = ' '; + if (eidx) + ebcdicbuf[eidx++] = ' '; + } outbuf[oidx] = '\0'; strbuf[soff+sidx] = '\0'; ebcdicbuf[eidx] = '\0'; @@ -14515,6 +14530,23 @@ delete_Stack (postfix); return cptr; } +/* + * To avoid Coverity complaints about the use of rand() we define the function locally + */ + +static uint32 sim_rand_seed; + +void sim_srand (unsigned int seed) +{ +sim_rand_seed = (uint32)seed; +} + +int sim_rand () +{ +sim_rand_seed = sim_rand_seed * 214013 + 2531011; +return (sim_rand_seed >> 16) & RAND_MAX; +} + /* * Compiled in unit tests for the various device oriented library * modules: sim_card, sim_disk, sim_tape, sim_ether, sim_tmxr, etc. @@ -14524,11 +14556,18 @@ static t_stat sim_library_unit_tests (void) { int i; DEVICE *dptr; +int32 saved_switches = sim_switches & ~SWMASK ('T'); t_stat stat = SCPE_OK; +if (sim_switches & SWMASK ('D')) { + sim_switches &= ~(SWMASK ('D') | SWMASK ('R') | SWMASK ('F') | SWMASK ('T')); + sim_set_debon (0, "STDOUT"); + sim_switches = saved_switches; + } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { t_stat tstat = SCPE_OK; + sim_switches = saved_switches; switch (DEV_TYPE(dptr)) { #if defined(USE_SIM_CARD) case DEV_CARD: diff --git a/scp.h b/scp.h index 0a2a7ed..24e6124 100644 --- a/scp.h +++ b/scp.h @@ -231,6 +231,12 @@ size_t sim_strlcpy (char *dst, const char *src, size_t size); #ifndef strcasecmp #define strcasecmp(str1, str2) sim_strcasecmp ((str1), (str2)) #endif +void sim_srand (unsigned int seed); +int sim_rand (void); +#ifdef RAND_MAX +#undef RAND_MAX +#endif +#define RAND_MAX 32767 CONST char *get_sim_opt (int32 opt, CONST char *cptr, t_stat *st); CONST char *get_sim_sw (CONST char *cptr); const char *put_switches (char *buf, size_t bufsize, uint32 sw); @@ -297,6 +303,7 @@ t_stat sim_exp_show (FILE *st, CONST EXPECT *exp, const char *match); t_stat sim_exp_showall (FILE *st, const EXPECT *exp); t_stat sim_exp_check (EXPECT *exp, uint8 data); CONST char *match_ext (CONST char *fnam, const char *ext); +int sim_cmp_string (const char *s1, const char *s2); t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr); diff --git a/sim_console.c b/sim_console.c index d482fa4..a406035 100644 --- a/sim_console.c +++ b/sim_console.c @@ -2242,6 +2242,21 @@ else return SCPE_OK; } +/* Set debug switches */ + +int32 sim_set_deb_switches (int32 switches) +{ +int32 old_deb_switches = sim_deb_switches; + +sim_deb_switches = switches & + (SWMASK ('R') | SWMASK ('P') | + SWMASK ('T') | SWMASK ('A') | + SWMASK ('F') | SWMASK ('N') | + SWMASK ('B') | SWMASK ('E') | + SWMASK ('D') ); /* save debug switches */ +return old_deb_switches; +} + /* Set debug routine */ t_stat sim_set_debon (int32 flag, CONST char *cptr) @@ -2267,11 +2282,8 @@ r = sim_open_logfile (gbuf, FALSE, &sim_deb, &sim_deb_ref); if (r != SCPE_OK) return r; -sim_deb_switches = sim_switches & - (SWMASK ('R') | SWMASK ('P') | - SWMASK ('T') | SWMASK ('A') | - SWMASK ('F') | SWMASK ('N') | - SWMASK ('B')); /* save debug switches */ +sim_set_deb_switches (sim_switches); + if (sim_deb_switches & SWMASK ('R')) { struct tm loc_tm, gmt_tm; time_t time_t_now; diff --git a/sim_console.h b/sim_console.h index 361870b..6f27d99 100644 --- a/sim_console.h +++ b/sim_console.h @@ -81,6 +81,7 @@ t_stat sim_set_serial (int32 flag, CONST char *cptr); t_stat sim_set_noserial (int32 flag, CONST char *cptr); t_stat sim_set_logon (int32 flag, CONST char *cptr); t_stat sim_set_logoff (int32 flag, CONST char *cptr); +int32 sim_set_deb_switches (int32 switches); t_stat sim_set_debon (int32 flag, CONST char *cptr); t_stat sim_set_cons_debug (int32 flg, CONST char *cptr); t_stat sim_set_cons_buff (int32 flg, CONST char *cptr); diff --git a/sim_defs.h b/sim_defs.h index 81e6dbe..ce77bf7 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -650,7 +650,8 @@ struct UNIT { #define UNIT_NO_FIO 0000004 /* fileref is NOT a FILE * */ #define UNIT_DISK_CHK 0000010 /* disk data debug checking (sim_disk) */ #define UNIT_TMR_UNIT 0000020 /* Unit registered as a calibrated timer */ -#define UNIT_V_DF_TAPE 6 /* Bit offset for Tape Density reservation */ +#define UNIT_TAPE_MRK 0000040 /* Tape Unit AWS Tapemark */ +#define UNIT_V_DF_TAPE 7 /* Bit offset for Tape Density reservation */ #define UNIT_S_DF_TAPE 3 /* Bits Reserved for Tape Density */ struct BITFIELD { diff --git a/sim_fio.c b/sim_fio.c index a134200..44eecaf 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -41,7 +41,7 @@ sim_finit - initialize package sim_fopen - open file sim_fread - endian independent read (formerly fxread) - sim_write - endian independent write (formerly fxwrite) + sim_fwrite - endian independent write (formerly fxwrite) sim_fseek - conditionally extended (>32b) seek ( sim_fseeko - extended seek (>32b if available) sim_fsize - get file size @@ -205,9 +205,11 @@ t_offset pos, sz; if (fp == NULL) return 0; pos = sim_ftell (fp); -sim_fseeko (fp, 0, SEEK_END); +if (sim_fseeko (fp, 0, SEEK_END)) + return 0; sz = sim_ftell (fp); -sim_fseeko (fp, pos, SEEK_SET); +if (sim_fseeko (fp, pos, SEEK_SET)) + return 0; return sz; } diff --git a/sim_tape.c b/sim_tape.c index 0e94fc2..47108ce 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -104,13 +104,15 @@ struct sim_tape_fmt { const char *name; /* name */ int32 uflags; /* unit flags */ t_addr bot; /* bot test */ + t_addr eom_remnant; /* potentially unprocessed data */ }; 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 }, + { "SIMH", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt)}, + { "E11", 0, sizeof (t_mtrlnt) - 1, sizeof (t_mtrlnt) }, + { "TPC", UNIT_RO, sizeof (t_tpclnt) - 1, sizeof (t_tpclnt) }, + { "P7B", 0, 0, 0 }, + { "AWS", 0, 0, 0 }, /* { "TPF", UNIT_RO, 0 }, */ { NULL, 0, 0 } }; @@ -128,15 +130,14 @@ static const uint32 bpi [] = { /* tape density table, i static t_stat sim_tape_ioerr (UNIT *uptr); static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat); +static t_stat sim_tape_aws_wrdata (UNIT *uptr, uint8 *buf, t_mtrlnt bc); static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize); -static t_stat sim_tape_simh_check (UNIT *uptr); -static t_stat sim_tape_e11_check (UNIT *uptr); +static t_stat sim_tape_scan_tape (UNIT *uptr); static t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map); static void sim_tape_data_trace (UNIT *uptr, const uint8 *data, size_t len, const char* txt, int detail, uint32 reason); static t_stat tape_erase_fwd (UNIT *uptr, t_mtrlnt gap_size); static t_stat tape_erase_rev (UNIT *uptr, t_mtrlnt gap_size); - struct tape_context { DEVICE *dptr; /* Device for unit (access to debug flags) */ uint32 dbit; /* debugging bit for trace */ @@ -458,7 +459,7 @@ DEVICE *dptr; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; -return sim_tape_attach_ex (uptr, cptr, ((dptr->flags & DEV_DEBUG) || (dptr->debflags)) ? 0xFFFFFFFF : 0, 0); +return sim_tape_attach_ex (uptr, cptr, ((dptr->flags & DEV_DEBUG) || (dptr->debflags)) ? MTSE_DBG_API : 0, 0); } t_stat sim_tape_attach_ex (UNIT *uptr, const char *cptr, uint32 dbit, int completion_delay) @@ -469,6 +470,9 @@ DEVICE *dptr; char gbuf[CBUFSIZE]; t_stat r; t_bool auto_format = FALSE; +t_bool had_debug = (sim_deb != NULL); +uint32 starting_dctrl = uptr->dctrl; +int32 saved_switches = sim_switches; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; @@ -486,32 +490,33 @@ if (MT_GET_FMT (uptr) == MTUF_F_TPC) r = attach_unit (uptr, (CONST char *)cptr); /* attach unit */ if (r != SCPE_OK) /* error? */ return sim_messagef (r, "Can't open tape image: %s\n", cptr); + +if ((sim_switches & SWMASK ('D')) && !had_debug) { + sim_switches |= SWMASK ('E'); + sim_switches &= ~(SWMASK ('D') | SWMASK ('R') | SWMASK ('F')); + sim_set_debon (0, "STDOUT"); + sim_switches = saved_switches; + } +if (sim_switches & SWMASK ('D')) + uptr->dctrl = MTSE_DBG_STR | MTSE_DBG_DAT; + +uptr->tape_ctx = ctx = (struct tape_context *)calloc(1, sizeof(struct tape_context)); +ctx->dptr = dptr; /* save DEVICE pointer */ +ctx->dbit = dbit; /* save debug bit */ +ctx->auto_format = auto_format; /* save that we auto selected format */ + switch (MT_GET_FMT (uptr)) { /* case on format */ - case MTUF_F_STD: /* SIMH */ - if (SCPE_OK != sim_tape_simh_check (uptr)) { - sim_tape_detach (uptr); - return SCPE_FMT; /* yes, complain */ - } - break; - - case MTUF_F_E11: /* E11 */ - if (SCPE_OK != sim_tape_e11_check (uptr)) { - sim_tape_detach (uptr); - return SCPE_FMT; /* yes, complain */ - } - break; - case MTUF_F_TPC: /* TPC */ objc = sim_tape_tpc_map (uptr, NULL, 0); /* get # objects */ if (objc == 0) { /* tape empty? */ sim_tape_detach (uptr); - return SCPE_FMT; /* yes, complain */ + r = 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 */ + r = SCPE_MEM; /* no, complain */ } uptr->hwmark = objc + 1; /* save map size */ sim_tape_tpc_map (uptr, (t_addr *) uptr->filebuf, objc);/* fill map */ @@ -521,19 +526,22 @@ switch (MT_GET_FMT (uptr)) { /* case on format */ break; } -uptr->tape_ctx = ctx = (struct tape_context *)calloc(1, sizeof(struct tape_context)); -ctx->dptr = dptr; /* save DEVICE pointer */ -ctx->dbit = dbit; /* save debug bit */ -ctx->auto_format = auto_format; /* save that we auto selected format */ +if (r == SCPE_OK) { + sim_tape_scan_tape (uptr); -sim_tape_rewind (uptr); + sim_tape_rewind (uptr); #if defined (SIM_ASYNCH_IO) -sim_tape_set_async (uptr, completion_delay); + sim_tape_set_async (uptr, completion_delay); #endif -uptr->io_flush = _sim_tape_io_flush; + uptr->io_flush = _sim_tape_io_flush; + } -return SCPE_OK; +if ((sim_switches & SWMASK ('D')) && !had_debug) + sim_set_deboff (0, ""); +if (sim_switches & SWMASK ('D')) + uptr->dctrl = starting_dctrl; +return r; } /* Detach tape unit */ @@ -560,6 +568,7 @@ if (ctx) sim_tape_clr_async (uptr); +MT_CLR_INMRK (uptr); /* Not within an AWS tapemark */ r = detach_unit (uptr); /* detach unit */ if (r != SCPE_OK) return r; @@ -607,6 +616,10 @@ fprintf (st, " -E Must Exist (if not specified an attempt to create fprintf (st, " virtual tape will be attempted).\n"); fprintf (st, " -F Open the indicated tape container in a specific format (default\n"); fprintf (st, " is SIMH, alternatives are E11, TPC and P7B)\n"); +fprintf (st, " -V Display some summary information about the record structure\n"); +fprintf (st, " contained in the tape structure.\n"); +fprintf (st, " -D Causes the internal tape structure information to be displayed\n"); +fprintf (st, " while the tape image is scanned.\n"); return SCPE_OK; } @@ -616,7 +629,7 @@ struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; if (ctx == NULL) return; -if (sim_deb && (ctx->dptr->dctrl & reason)) +if (sim_deb && ((uptr->dctrl | ctx->dptr->dctrl) & reason)) sim_data_trace(ctx->dptr, uptr, (detail ? data : NULL), "", len, txt, reason); } @@ -717,6 +730,8 @@ t_bool all_eof; uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; t_tpclnt tpcbc; +t_awshdr awshdr; +size_t rdcnt; t_mtrlnt buffer [256]; /* local tape buffer */ uint32 bufcntr, bufcap; /* buffer counter and capacity */ int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */ @@ -860,16 +875,20 @@ else switch (f) { /* otherwise the read me MT_SET_PNU (uptr); /* pos not upd */ status = sim_tape_ioerr (uptr); } - else if (feof (uptr->fileref)) { /* eof? */ - MT_SET_PNU (uptr); /* pos not upd */ - 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 */ + if ((feof (uptr->fileref)) || /* eof? */ + ((tpcbc == TPC_EOM) && + (sim_fsize (uptr->fileref) == (uint32)sim_ftell (uptr->fileref)))) { + MT_SET_PNU (uptr); /* pos not upd */ + 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 */ + } } break; @@ -895,13 +914,42 @@ else switch (f) { /* otherwise the read me if (status == MTSE_OK) { *bc = sbc; /* save rec lnt */ - sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ + (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ uptr->pos = uptr->pos + sbc; /* spc over record */ if (all_eof) /* tape mark? */ status = MTSE_TMK; } break; + case MTUF_F_AWS: + MT_CLR_INMRK (uptr); /* Not within an AWS tapemark */ + memset (&awshdr, 0, sizeof (awshdr)); + rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); + *bc = awshdr.nxtlen; /* save rec lnt */ + + if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + status = sim_tape_ioerr (uptr); + break; + } + if ((feof (uptr->fileref)) || /* eof? */ + (rdcnt < 3)) { + MT_SET_PNU (uptr); /* pos not upd */ + status = MTSE_EOM; + break; + } + uptr->pos = uptr->pos + sizeof (t_awshdr); /* spc over AWS header */ + if (awshdr.rectyp == AWS_TMK) /* tape mark? */ + status = MTSE_TMK; + else + if (awshdr.rectyp == AWS_REC) /* tape data record */ + uptr->pos = uptr->pos + awshdr.nxtlen; /* spc over record */ + else { + MT_SET_PNU (uptr); /* pos not upd */ + status = MTSE_INVRL; + } + break; + default: status = MTSE_FMT; } @@ -919,7 +967,7 @@ if (ctx == NULL) /* if not properly attac status = sim_tape_rdlntf (uptr, bc); /* read the record length */ -sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); +sim_debug_unit (MTSE_DBG_STR, uptr, "rd_lntf: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); return status; } @@ -970,6 +1018,8 @@ uint32 f = MT_GET_FMT (uptr); t_addr ppos; t_mtrlnt sbc; t_tpclnt tpcbc; +t_awshdr awshdr; +size_t rdcnt; t_mtrlnt buffer [256]; /* local tape buffer */ uint32 bufcntr, bufcap; /* buffer counter and capacity */ int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */ @@ -1077,8 +1127,8 @@ else switch (f) { /* otherwise the read me 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); + (void)sim_fseek (uptr->fileref, ppos, SEEK_SET);/* position */ + (void)sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); *bc = tpcbc; /* save rec lnt */ if (ferror (uptr->fileref)) /* error? */ @@ -1090,14 +1140,14 @@ else switch (f) { /* otherwise the read me if (*bc == MTR_TMK) /* tape mark? */ status = MTSE_TMK; else - sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); + (void)sim_fseek (uptr->fileref, uptr->pos + sizeof (t_tpclnt), SEEK_SET); } break; case MTUF_F_P7B: for (sbc = 1, all_eof = 1; (t_addr) sbc <= uptr->pos ; sbc++) { - sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET); - sim_fread (&c, sizeof (uint8), 1, uptr->fileref); + (void)sim_fseek (uptr->fileref, uptr->pos - sbc, SEEK_SET); + (void)sim_fread (&c, sizeof (uint8), 1, uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ status = sim_tape_ioerr (uptr); @@ -1118,12 +1168,65 @@ else switch (f) { /* otherwise the read me if (status == MTSE_OK) { uptr->pos = uptr->pos - sbc; /* update position */ *bc = sbc; /* save rec lnt */ - sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for read */ + (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* for next read */ if (all_eof) /* tape mark? */ status = MTSE_TMK; } break; + case MTUF_F_AWS: + sbc = 0; + while ((sbc == 0) && (status == MTSE_OK)) { + if (sim_tape_bot (uptr)) { /* if we start at BOT */ + status = MTSE_BOT; /* then we're done */ + break; + } + (void)sim_fseek (uptr->fileref, uptr->pos, SEEK_SET);/* position */ + memset (&awshdr, 0, sizeof (awshdr)); + rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); + *bc = awshdr.prelen; /* save rec lnt */ + + if (ferror (uptr->fileref)) { /* error? */ + status = sim_tape_ioerr (uptr); + break; + } + if (feof (uptr->fileref)) { /* eof? */ + status = MTSE_EOM; + if ((uptr->pos > sizeof (t_awshdr)) && + (uptr->pos >= sim_fsize (uptr->fileref))) + uptr->pos -= sizeof (t_awshdr); + break; + } + if ((rdcnt != 3) || + ((awshdr.rectyp != AWS_REC) && + (awshdr.rectyp != AWS_TMK))) { + status = MTSE_INVRL; + break; + } + sbc = *bc; /* extract the record length */ + if (MT_TST_INMRK (uptr)) /* already in a tapemark? */ + awshdr.rectyp = AWS_REC; + MT_CLR_INMRK (uptr); /* No longer in a tapemark */ + if ((awshdr.rectyp != AWS_TMK) || + (awshdr.prelen == 0)) { + uptr->pos -= sizeof (t_awshdr); /* position to the start of the record */ + uptr->pos -= awshdr.prelen; /* Including the data length */ + + if (sim_fseek (uptr->fileref, /* seek to the start of the data area; if it fails */ + uptr->pos + sizeof (t_awshdr), + SEEK_SET)) { + status = sim_tape_ioerr (uptr); /* then return with I/O error status */ + break; + } + } + if (awshdr.rectyp == AWS_TMK) { /* tape mark? */ + status = MTSE_TMK; + if (awshdr.prelen != 0) + MT_SET_INMRK (uptr); /* Flag processing a tapemark header */ + } + } + break; + default: status = MTSE_FMT; } @@ -1141,7 +1244,7 @@ if (ctx == NULL) /* if not properly attac status = sim_tape_rdlntr (uptr, bc); /* read the record length */ -sim_debug (MTSE_DBG_STR, ctx->dptr, "rd_lnt: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); +sim_debug_unit (MTSE_DBG_STR, uptr, "rd_lntr: st: %d, lnt: %d, pos: %" T_ADDR_FMT "u\n", status, *bc, uptr->pos); return status; } @@ -1199,7 +1302,7 @@ for ( ; i < rbc; i++) /* fill with 0's */ buf[i] = 0; if (f == MTUF_F_P7B) /* p7b? strip SOR */ buf[0] = buf[0] & P7B_DPAR; -sim_tape_data_trace(uptr, buf, rbc, "Record Read", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR); +sim_tape_data_trace(uptr, buf, rbc, "Record Read", (uptr->dctrl | ctx->dptr->dctrl) & MTSE_DBG_DAT, MTSE_DBG_STR); return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); } @@ -1259,7 +1362,7 @@ for ( ; i < rbc; i++) /* fill with 0's */ buf[i] = 0; if (f == MTUF_F_P7B) /* p7b? strip SOR */ buf[0] = buf[0] & P7B_DPAR; -sim_tape_data_trace(uptr, buf, rbc, "Record Read Reverse", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR); +sim_tape_data_trace(uptr, buf, rbc, "Record Read Reverse", (uptr->dctrl | ctx->dptr->dctrl) & MTSE_DBG_DAT, MTSE_DBG_STR); return (MTR_F (tbc)? MTSE_RECE: MTSE_OK); } @@ -1294,12 +1397,13 @@ t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc) struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; +t_stat status = MTSE_OK; if (ctx == NULL) /* if not properly attached? */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ sim_debug_unit (ctx->dbit, uptr, "sim_tape_wrrecf(unit=%d, buf=%p, bc=%d)\n", (int)(uptr-ctx->dptr->units), buf, bc); -sim_tape_data_trace(uptr, buf, bc, "Record Write", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR); +sim_tape_data_trace(uptr, buf, bc, "Record Write", (uptr->dctrl | ctx->dptr->dctrl) & MTSE_DBG_DAT, MTSE_DBG_STR); MT_CLR_PNU (uptr); sbc = MTR_L (bc); if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ @@ -1308,7 +1412,8 @@ if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; if (sbc == 0) /* nothing to do? */ return MTSE_OK; -sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ + return MTSE_IOERR; switch (f) { /* case on format */ case MTUF_F_STD: /* standard */ @@ -1335,8 +1440,13 @@ switch (f) { /* case on format */ } uptr->pos = uptr->pos + sbc; /* move tape */ break; + case MTUF_F_AWS: /* AWS */ + status = sim_tape_aws_wrdata (uptr, buf, bc); + if (status != MTSE_OK) + return status; + break; } -sim_tape_data_trace(uptr, buf, sbc, "Record Written", ctx->dptr->dctrl & MTSE_DBG_DAT, MTSE_DBG_STR); +sim_tape_data_trace(uptr, buf, sbc, "Record Written", (uptr->dctrl | ctx->dptr->dctrl) & MTSE_DBG_DAT, MTSE_DBG_STR); return MTSE_OK; } @@ -1349,6 +1459,48 @@ AIO_CALL(TOP_WREC, buf, 0, NULL, 0, bc, 0, 0, NULL, callback); return r; } +/* Write AWS metadata (and possibly data) forward (internal routine) */ + +static t_stat sim_tape_aws_wrdata (UNIT *uptr, uint8 *buf, t_mtrlnt bc) +{ +t_awshdr awshdr; +size_t rdcnt; +t_bool replacing_record; + +memset (&awshdr, 0, sizeof (t_awshdr)); +if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ + return MTSE_IOERR; +rdcnt = sim_fread (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); +if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + return sim_tape_ioerr (uptr); + } +if ((!sim_tape_bot (uptr)) && + (((feof (uptr->fileref)) && (rdcnt < 3)) || /* eof? */ + ((awshdr.rectyp != AWS_REC) && (awshdr.rectyp != AWS_TMK)))) { + MT_SET_PNU (uptr); /* pos not upd */ + return MTSE_INVRL; + } +if (sim_fseek (uptr->fileref, uptr->pos, SEEK_SET)) /* set pos */ + return MTSE_IOERR; +replacing_record = (awshdr.nxtlen == (t_awslnt)bc) && (awshdr.rectyp == (bc ? AWS_REC : AWS_TMK)); +awshdr.nxtlen = (t_awslnt)bc; +awshdr.rectyp = (bc) ? AWS_REC : AWS_TMK; +sim_fwrite (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); +if (bc) + sim_fwrite (buf, sizeof (uint8), bc, uptr->fileref); +uptr->pos += sizeof (awshdr) + bc; +if ((!replacing_record) | (bc == 0)) { + awshdr.prelen = bc; + awshdr.nxtlen = 0; + awshdr.rectyp = AWS_TMK; + sim_fwrite (&awshdr, sizeof (t_awslnt), 3, uptr->fileref); + if (!replacing_record) + sim_set_fsize (uptr->fileref, uptr->pos + sizeof (awshdr)); + } +return MTSE_OK; +} + /* Write metadata forward (internal routine) */ static t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat) @@ -1362,13 +1514,13 @@ if (ctx == NULL) /* if not properly attac return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ if (sim_tape_wrp (uptr)) /* write prot? */ return MTSE_WRP; -sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +(void)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); } -sim_debug (MTSE_DBG_STR, ctx->dptr, "wr_lnt: lnt: %d, pos: %" T_ADDR_FMT "u\n", dat, uptr->pos); +sim_debug_unit (MTSE_DBG_STR, uptr, "wr_lnt: lnt: %d, pos: %" T_ADDR_FMT "u\n", dat, uptr->pos); uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* move tape */ return MTSE_OK; } @@ -1386,6 +1538,8 @@ if (MT_GET_FMT (uptr) == MTUF_F_P7B) { /* P7B? */ uint8 buf = P7B_EOF; /* eof mark */ return sim_tape_wrrecf (uptr, &buf, 1); /* write char */ } +if (MT_GET_FMT (uptr) == MTUF_F_AWS) /* AWS? */ + return sim_tape_aws_wrdata (uptr, NULL, 0); return sim_tape_wrdata (uptr, MTR_TMK); } @@ -1408,12 +1562,19 @@ struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; if (ctx == NULL) /* if not properly attached? */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ sim_debug_unit (ctx->dbit, uptr, "sim_tape_wreom(unit=%d)\n", (int)(uptr-ctx->dptr->units)); +if (sim_tape_wrp (uptr)) /* write prot? */ + return MTSE_WRP; if (MT_GET_FMT (uptr) == MTUF_F_P7B) /* cant do P7B */ return MTSE_FMT; - -result = sim_tape_wrdata (uptr, MTR_EOM); /* write the EOM marker */ - -uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* restore original tape position */ +if (MT_GET_FMT (uptr) == MTUF_F_AWS) { + sim_tape_aws_wrdata (uptr, NULL, 0); + sim_set_fsize (uptr->fileref, uptr->pos); + result = MTSE_OK; + } +else { + result = sim_tape_wrdata (uptr, MTR_EOM); /* write the EOM marker */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* restore original tape position */ + } MT_SET_PNU (uptr); /* indicate that position was not updated */ return result; @@ -1438,9 +1599,7 @@ t_stat r; if (ctx == NULL) /* if not properly attached? */ return sim_messagef (SCPE_IERR, "Bad Attach\n"); /* that's a problem */ sim_debug_unit (ctx->dbit, uptr, "sim_tape_wreomrw(unit=%d)\n", (int)(uptr-ctx->dptr->units)); -if (MT_GET_FMT (uptr) == MTUF_F_P7B) /* cant do P7B */ - return MTSE_FMT; -r = sim_tape_wrdata (uptr, MTR_EOM); +r = sim_tape_wreom (uptr); if (r == MTSE_OK) r = sim_tape_rewind (uptr); return r; @@ -1785,7 +1944,7 @@ if (gap_size == meta_size) { /* if the request is for 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 */ - sim_fread (&metadatum, meta_size, 1, uptr->fileref); /* read a metadatum */ + (void)sim_fread (&metadatum, meta_size, 1, uptr->fileref);/* read a metadatum */ if (ferror (uptr->fileref)) /* if a file I/O error occurred */ return sim_tape_ioerr (uptr); /* then report the error and quit */ @@ -2468,7 +2627,7 @@ return (uptr->capac && (uptr->pos >= uptr->capac))? TRUE: FALSE; t_bool sim_tape_wrp (UNIT *uptr) { -return ((uptr->flags & MTUF_WRP) || (MT_GET_FMT (uptr) == MTUF_F_TPC))? TRUE: FALSE; +return ((uptr->flags & MTUF_WRP) || (uptr->flags & UNIT_RO) || (MT_GET_FMT (uptr) == MTUF_F_TPC))? TRUE: FALSE; } /* Process I/O error */ @@ -2520,7 +2679,7 @@ static uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map, uint32 mapsize) { t_addr tpos, leot; t_addr tape_size; -t_tpclnt bc, last_bc = 0xFFFF; +t_tpclnt bc, last_bc = TPC_EOM; uint32 had_double_tape_mark = 0; size_t i; uint32 objc, sizec; @@ -2533,9 +2692,9 @@ if ((uptr == NULL) || (uptr->fileref == NULL)) countmap = (uint32 *)calloc (65536, sizeof(*countmap)); recbuf = (uint8 *)malloc (65536); tape_size = (t_addr)sim_fsize (uptr->fileref); -sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size); +sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: tape_size: %" T_ADDR_FMT "u\n", tape_size); for (objc = 0, sizec = 0, tpos = 0;; ) { - sim_fseek (uptr->fileref, tpos, SEEK_SET); + (void)sim_fseek (uptr->fileref, tpos, SEEK_SET); i = sim_fread (&bc, sizeof (t_tpclnt), 1, uptr->fileref); if (i == 0) /* past or at eof? */ break; @@ -2545,14 +2704,14 @@ for (objc = 0, sizec = 0, tpos = 0;; ) { if (map && (objc < mapsize)) map[objc] = tpos; if (bc) { - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: %d byte count at pos: %" T_ADDR_FMT "u\n", bc, tpos); - if (sim_deb && (dptr->dctrl & MTSE_DBG_STR)) { - sim_fread (recbuf, 1, bc, uptr->fileref); - sim_data_trace(dptr, uptr, ((dptr->dctrl & MTSE_DBG_DAT) ? recbuf : NULL), "", bc, "Data Record", MTSE_DBG_STR); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: %d byte count at pos: %" T_ADDR_FMT "u\n", bc, tpos); + if (map && sim_deb && (dptr->dctrl & MTSE_DBG_STR)) { + (void)sim_fread (recbuf, 1, bc, uptr->fileref); + sim_data_trace(dptr, uptr, (((uptr->dctrl | dptr->dctrl) & MTSE_DBG_DAT) ? recbuf : NULL), "", bc, "Data Record", MTSE_DBG_STR); } } else - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: tape mark at pos: %" T_ADDR_FMT "u\n", tpos); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: tape mark at pos: %" T_ADDR_FMT "u\n", tpos); objc++; tpos = tpos + ((bc + 1) & ~1) + sizeof (t_tpclnt); if ((bc == 0) && (last_bc == 0)) { /* double tape mark? */ @@ -2561,56 +2720,201 @@ for (objc = 0, sizec = 0, tpos = 0;; ) { } last_bc = bc; } -sim_debug (MTSE_DBG_STR, dptr, "tpc_map: objc: %u, different record sizes: %u\n", objc, sizec); +sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: objc: %u, different record sizes: %u\n", objc, sizec); for (i=0; i<65535; i++) { if (countmap[i]) { if (i == 0) - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u tape marks\n", countmap[i]); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: summary - %u tape marks\n", countmap[i]); else - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: summary - %u %d byte record%s\n", countmap[i], (int)i, (countmap[i] > 1) ? "s" : ""); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: summary - %u %d byte record%s\n", countmap[i], (int)i, (countmap[i] > 1) ? "s" : ""); } } -if (((last_bc != 0xffff) && +if (((last_bc != TPC_EOM) && (tpos > tape_size) && (!had_double_tape_mark)) || (!had_double_tape_mark) || ((objc == countmap[0]) && (countmap[0] != 2))) { /* Unreasonable format? */ - if (last_bc != 0xffff) - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR unexpected EOT byte count: %d\n", last_bc); + if (last_bc != TPC_EOM) + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: ERROR unexpected EOT byte count: %d\n", last_bc); if (tpos > tape_size) - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR next record position %" T_ADDR_FMT "u beyond EOT: %" T_ADDR_FMT "u\n", tpos, tape_size); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: ERROR next record position %" T_ADDR_FMT "u beyond EOT: %" T_ADDR_FMT "u\n", tpos, tape_size); if (objc == countmap[0]) - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: ERROR tape cnly contains tape marks\n"); + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: ERROR tape cnly contains tape marks\n"); free (countmap); free (recbuf); return 0; } -if ((last_bc != 0xffff) && (tpos > tape_size)) { - sim_debug (MTSE_DBG_STR, dptr, "tpc_map: WARNING unexpected EOT byte count: %d, double tape mark before %" T_ADDR_FMT "u provides logical EOT\n", last_bc, leot); +if ((last_bc != TPC_EOM) && (tpos > tape_size)) { + sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: WARNING unexpected EOT byte count: %d, double tape mark before %" T_ADDR_FMT "u provides logical EOT\n", last_bc, leot); objc = had_double_tape_mark; tpos = leot; } if (map) map[objc] = tpos; -sim_debug (MTSE_DBG_STR, dptr, "tpc_map: OK objc: %d\n", objc); +sim_debug_unit (MTSE_DBG_STR, uptr, "tpc_map: OK objc: %d\n", objc); free (countmap); free (recbuf); return objc; } -/* Check the basic structure of a SIMH format tape image */ - -static t_stat sim_tape_simh_check (UNIT *uptr) +static +const char *sim_tape_error_text (t_stat stat) { -return SCPE_OK; +const char *mtse_errors[] = { + "no error", + "tape mark", + "unattached", + "IO error", + "invalid rec lnt", + "invalid format", + "beginning of tape", + "end of medium", + "error in record", + "write protected", + "Logical End Of Tape", + "tape runaway" + }; +static char msgbuf[64]; + +if (stat <= MTSE_MAX_ERR) + return mtse_errors[stat]; +sprintf(msgbuf, "Error %d", stat); +return msgbuf; } -/* Check the basic structure of a E11 format tape image */ - -static t_stat sim_tape_e11_check (UNIT *uptr) +static t_stat sim_tape_scan_tape (UNIT *uptr) { +t_addr saved_pos = uptr->pos; +uint32 record_in_file = 0; +uint32 data_total = 0; +uint32 tapemark_total = 0; +uint32 tapemark_seen = 0; +uint32 record_total = 0; +uint32 unique_record_sizes = 0; +t_stat r = SCPE_OK; +uint8 *buf = NULL; +uint32 *rec_sizes = NULL; +t_mtrlnt bc; +t_mtrlnt max = MTR_MAXLEN; +t_bool prior_was_tapemark = FALSE; + +if (!(uptr->flags & UNIT_ATT)) + return SCPE_UNATT; +buf = (uint8 *)malloc (max); +if (buf == NULL) + return SCPE_MEM; +rec_sizes = (uint32 *)calloc (max + 1, sizeof (*rec_sizes)); +if (rec_sizes == NULL) { + free (buf); + return SCPE_MEM; + } +r = sim_tape_rewind (uptr); +while (r == SCPE_OK) { + r = sim_tape_rdrecf (uptr, buf, &bc, max); + switch (r) { + case MTSE_OK: /* no error */ + ++record_total; + data_total += bc; + if (rec_sizes[bc] == 0) + ++unique_record_sizes; + ++rec_sizes[bc]; + r = SCPE_OK; + prior_was_tapemark = FALSE; + break; + case MTSE_TMK: /* tape mark */ + ++tapemark_total; + if (prior_was_tapemark) + r = MTSE_LEOT; + else + r = SCPE_OK; + prior_was_tapemark = TRUE; + break; + case MTSE_INVRL: /* invalid rec lnt */ + case MTSE_FMT: /* invalid format */ + case MTSE_BOT: /* beginning of tape */ + case MTSE_RECE: /* error in record */ + case MTSE_WRP: /* write protected */ + case MTSE_LEOT: /* Logical End Of Tape */ + case MTSE_RUNAWAY: /* tape runaway */ + default: + break; + case MTSE_EOM: /* end of medium */ + break; + } + } +if (((r != MTSE_EOM) && (r != MTSE_LEOT)) || (sim_switches & SWMASK ('V')) || + ((uint32)(sim_fsize_ex (uptr->fileref) - (t_offset)uptr->pos) > fmts[MT_GET_FMT (uptr)].eom_remnant) || + (unique_record_sizes > 2 * tapemark_seen)) { + uint32 remaining_data = (uint32)(sim_fsize_ex (uptr->fileref) - (t_offset)uptr->pos); + + sim_printf ("Tape Image '%s' scanned as %s format.\n", uptr->filename, fmts[MT_GET_FMT (uptr)].name); + if (r != MTSE_EOM) + sim_printf ("After processing "); + else + sim_printf ("contains "); + sim_printf ("%u bytes of tape data (%u records, %u tapemarks)\n", + data_total, record_total, tapemark_total); + if (record_total > 0) { + sim_printf ("Comprising:\n"); + for (bc = 0; bc <= max; bc++) { + if (rec_sizes[bc]) + sim_printf ("%8u %u byte records\n", rec_sizes[bc], (uint32)bc); + } + } + if ((r != MTSE_EOM) && (r != MTSE_LEOT)) + sim_printf ("Read Tape Record Returned Unexpected Status: %s\n", sim_tape_error_text (r)); + if (remaining_data > fmts[MT_GET_FMT (uptr)].eom_remnant) + sim_printf ("%u bytes of unexamined data remain in the tape image file\n", remaining_data); + } +/* Try again reading backwards */ +r = SCPE_OK; +tapemark_seen = tapemark_total; +while (r == SCPE_OK) { + r = sim_tape_rdrecr (uptr, buf, &bc, max); + switch (r) { + case MTSE_OK: /* no error */ + --record_total; + data_total -= bc; + if (bc > max) + bc = max; + --rec_sizes[bc]; + r = SCPE_OK; + break; + case MTSE_TMK: /* tape mark */ + --tapemark_total; + r = SCPE_OK; + break; + case MTSE_BOT: /* beginning of tape */ + break; + case MTSE_INVRL: /* invalid rec lnt */ + case MTSE_FMT: /* invalid format */ + case MTSE_RECE: /* error in record */ + case MTSE_WRP: /* write protected */ + case MTSE_LEOT: /* Logical End Of Tape */ + case MTSE_RUNAWAY: /* tape runaway */ + default: + break; + case MTSE_EOM: /* end of medium */ + r = SCPE_OK; + break; + } + } + +if ((record_total != 0) || + (tapemark_total != 0) || + (data_total != 0)) + sim_printf ("Reverse read of the tape data is inconsistent with the forward read.\n"); + +if (unique_record_sizes > 2 * tapemark_seen) { + sim_printf ("An unreasonable number of record sizes(%u) vs tape marks (%u) have been found\n", unique_record_sizes, tapemark_total); + sim_printf ("The tape format (%s) might not be correct for the '%s' tape image\n", fmts[MT_GET_FMT (uptr)].name, uptr->filename); + } + +free (buf); +free (rec_sizes); +uptr->pos = saved_pos; return SCPE_OK; } @@ -2752,7 +3056,245 @@ else { /* otherwise get the den return SCPE_OK; } -t_stat sim_tape_test (DEVICE *dptr) +static DEBTAB tape_debug[] = { + {"TRACE", MTSE_DBG_API, "API Trace"}, + {"DATA", MTSE_DBG_DAT, "Tape Data"}, + {"POS", MTSE_DBG_POS, "Positioning Activities"}, + {"STR", MTSE_DBG_STR, "Tape Structure"}, + {0} +}; + +t_stat sim_tape_add_debug (DEVICE *dptr) { +if (DEV_TYPE(dptr) != DEV_TAPE) + return SCPE_OK; +return sim_add_debug_flags (dptr, tape_debug); +} + +static t_bool p7b_parity_inited = FALSE; +static uint8 p7b_odd_parity[64]; +static uint8 p7b_even_parity[64]; + +static t_stat create_tape_files (UNIT *uptr, const char *filename, int files, int records, int max_size) +{ +FILE *fSIMH = NULL; +FILE *fE11 = NULL; +FILE *fTPC = NULL; +FILE *fP7B = NULL; +FILE *fAWS = NULL; +int i, j, k; +t_tpclnt tpclnt; +t_mtrlnt mtrlnt; +t_awslnt awslnt; +t_awslnt awslnt_last = 0; +t_awslnt awsrec_typ = AWS_REC; +char name[256]; +t_stat stat = SCPE_OPENERR; +uint8 *buf = NULL; +t_stat aws_stat; +int32 saved_switches = sim_switches; + +srand (0); /* All devices use the same random sequence for file data */ +if (max_size == 0) + max_size = 65535; +if (!p7b_parity_inited) { + for (i=0; i < 64; i++) { + int bit_count = 0; + + for (j=0; j<6; j++) { + if (i & (1 << j)) + ++bit_count; + } + p7b_odd_parity[i] = i | ((~bit_count & 1) << 6); + p7b_even_parity[i] = i | ((bit_count & 1) << 6); + } + p7b_parity_inited = TRUE; + } +buf = (uint8 *)malloc (65536); +if (buf == NULL) + return SCPE_MEM; +sprintf (name, "%s.simh", filename); +fSIMH = fopen (name, "wb"); +if (fSIMH == NULL) + goto Done_Files; +sprintf (name, "%s.e11", filename); +fE11 = fopen (name, "wb"); +if (fE11 == NULL) + goto Done_Files; +sprintf (name, "%s.tpc", filename); +fTPC = fopen (name, "wb"); +if (fTPC == NULL) + goto Done_Files; +sprintf (name, "%s.p7b", filename); +fP7B = fopen (name, "wb"); +if (fP7B == NULL) + goto Done_Files; +sprintf (name, "%s.aws", filename); +fAWS = fopen (name, "wb"); +if (fAWS == NULL) + goto Done_Files; +sprintf (name, "aws %s.aws.tape", filename); +(void)remove (name); +sim_switches = SWMASK ('F') | (sim_switches & SWMASK ('D')) | SWMASK ('N'); +if (sim_switches & SWMASK ('D')) + uptr->dctrl = MTSE_DBG_STR | MTSE_DBG_DAT; +aws_stat = sim_tape_attach_ex (uptr, name, (saved_switches & SWMASK ('D')) ? MTSE_DBG_STR | MTSE_DBG_DAT: 0, 0); +sim_switches = saved_switches; +stat = SCPE_OK; +for (i=0; i + +t_stat sim_tape_test (DEVICE *dptr) +{ +int32 saved_switches = sim_switches; +SIM_TEST_INIT; + +sim_printf ("\nTesting %s device sim_tape APIs\n", sim_uname(dptr->units)); + +SIM_TEST(remove_tape_files (dptr->units, "TapeTestFile1")); + +SIM_TEST(create_tape_files (dptr->units, "TapeTestFile1", 2, 4, 4096)); + +sim_switches = saved_switches; +SIM_TEST(process_tape_file (dptr->units, "TapeTestFile1", "aws")); + +sim_switches = saved_switches; +SIM_TEST(process_tape_file (dptr->units, "TapeTestFile1", "p7b")); + +sim_switches = saved_switches; +SIM_TEST(process_tape_file (dptr->units, "TapeTestFile1", "tpc")); + +sim_switches = saved_switches; +SIM_TEST(process_tape_file (dptr->units, "TapeTestFile1", "e11")); + +sim_switches = saved_switches; +SIM_TEST(process_tape_file (dptr->units, "TapeTestFile1", "simh")); + +SIM_TEST(remove_tape_files (dptr->units, "TapeTestFile1")); + return SCPE_OK; } diff --git a/sim_tape.h b/sim_tape.h index e90cd18..26abba6 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -63,6 +63,10 @@ typedef uint32 t_mtrlnt; /* magtape rec lnt */ typedef uint16 t_tpclnt; /* magtape rec lnt */ +#define TPC_TMK 0x0000 /* tape mark */ +#define TPC_EOM 0xFFFF /* end of medium */ + + /* P7B tape format */ #define P7B_SOR 0x80 /* start of record */ @@ -71,7 +75,15 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define P7B_DPAR (P7B_PAR|P7B_DATA) /* data and parity */ #define P7B_EOF 0x0F /* eof character */ -#define TPC_TMK 0x0000 /* tape mark */ +/* AWS tape format */ +typedef uint16 t_awslnt; /* magtape rec lnt */ +typedef struct { + t_awslnt nxtlen; + t_awslnt prelen; + t_awslnt rectyp; +#define AWS_TMK 0x0040 +#define AWS_REC 0x00A0 + } t_awshdr; /* Unit flags */ @@ -85,7 +97,7 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define MTUF_F_E11 1 /* E11 format */ #define MTUF_F_TPC 2 /* TPC format */ #define MTUF_F_P7B 3 /* P7B format */ -#define MUTF_F_TDF 4 /* TDF format */ +#define MTUF_F_AWS 4 /* AWS format */ #define MTUF_V_UF (MTUF_V_FMT + MTUF_W_FMT) #define MTUF_PNU (1u << MTUF_V_PNU) #define MTUF_WLK (1u << MTUF_V_WLK) @@ -96,11 +108,14 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define MT_F_E11 (MTUF_F_E11 << MTUF_V_FMT) #define MT_F_TPC (MTUF_F_TPC << MTUF_V_FMT) #define MT_F_P7B (MTUF_F_P7B << MTUF_V_FMT) -#define MT_F_TDF (MTUF_F_TDF << MTUF_V_FMT) +#define MT_F_AWS (MTUF_F_AWS << MTUF_V_FMT) #define MT_SET_PNU(u) (u)->flags = (u)->flags | MTUF_PNU #define MT_CLR_PNU(u) (u)->flags = (u)->flags & ~MTUF_PNU #define MT_TST_PNU(u) ((u)->flags & MTUF_PNU) +#define MT_SET_INMRK(u) (u)->dynflags = (u)->dynflags | UNIT_TAPE_MRK +#define MT_CLR_INMRK(u) (u)->dynflags = (u)->dynflags & ~UNIT_TAPE_MRK +#define MT_TST_INMRK(u) ((u)->dynflags & UNIT_TAPE_MRK) #define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT) /* sim_tape_position Position Flags */ @@ -146,11 +161,13 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define MTSE_WRP 9 /* write protected */ #define MTSE_LEOT 10 /* Logical End Of Tape */ #define MTSE_RUNAWAY 11 /* tape runaway */ +#define MTSE_MAX_ERR 11 typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status); /* Tape Internal Debug flags */ +#define MTSE_DBG_API 0x10000000 /* API Trace */ #define MTSE_DBG_DAT 0x20000000 /* Debug Data */ #define MTSE_DBG_POS 0x40000000 /* Debug Positioning activities */ #define MTSE_DBG_STR 0x80000000 /* Debug Tape Structure */ @@ -210,6 +227,7 @@ t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, CONST void *desc); t_stat sim_tape_set_asynch (UNIT *uptr, int latency); t_stat sim_tape_clr_asynch (UNIT *uptr); t_stat sim_tape_test (DEVICE *dptr); +t_stat sim_tape_add_debug (DEVICE *dptr); #ifdef __cplusplus } diff --git a/sim_tmxr.c b/sim_tmxr.c index 19ec6a4..51125db 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -3913,7 +3913,7 @@ static DEBTAB tmxr_debug[] = { t_stat tmxr_add_debug (DEVICE *dptr) { -if (!(dptr->flags & DEV_MUX)) +if (DEV_TYPE(dptr) != DEV_MUX) return SCPE_OK; return sim_add_debug_flags (dptr, tmxr_debug); }