/* cmp_tape.c: Compare two PDP-8 paper tapes. This compares the memory contents from loading the tapes into memory. Main is by David Gesswein djg@pdp8online.com The rest of the code taken from SIMH which is Copyright (c) 1993-2011, 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. RIM loader format consists of alternating pairs of addresses and 12-bit words. It can only operate in field 0 and is not checksummed. */ #include #include #include #include "sim_defs.h" #define MEMSIZE 32768 /* max memory size */ int16 M[MEMSIZE]; int16 M2[MEMSIZE]; #define T_NONE 0 #define T_RIM 1 #define T_BIN 2 /* Macro to get the number of elements in an array. */ #define DIM(a) (sizeof(a)/sizeof(a[0])) char *match_ext (char *fnam, char *ext) { char *pptr, *fptr, *eptr; if ((fnam == NULL) || (ext == NULL)) /* bad arguments? */ return NULL; pptr = strrchr (fnam, '.'); /* find last . */ if (pptr) { /* any? */ for (fptr = pptr + 1, eptr = ext; /* match characters */ #if defined (VMS) /* VMS: stop at ; or null */ (*fptr != 0) && (*fptr != ';'); #else *fptr != 0; /* others: stop at null */ #endif fptr++, eptr++) { if (toupper (*fptr) != toupper (*eptr)) return NULL; } if (*eptr != 0) /* ext exhausted? */ return NULL; } return pptr; } t_stat sim_load_rim (FILE *fi) { int32 origin, hi, lo, wd; origin = 0200; do { /* skip leader */ if ((hi = getc (fi)) == EOF) return SCPE_FMT; } while ((hi == 0) || (hi >= 0200)); do { /* data block */ if ((lo = getc (fi)) == EOF) return SCPE_FMT; wd = (hi << 6) | lo; if (wd > 07777) origin = wd & 07777; else M[origin++ & 07777] = wd; if ((hi = getc (fi)) == EOF) return SCPE_FMT; } while (hi < 0200); /* until trailer */ return SCPE_OK; } /* BIN loader format consists of a string of 12-bit words (made up from 7-bit characters) between leader and trailer (200). The last word on tape is the checksum. A word with the "link" bit set is a new origin; a character > 0200 indicates a change of field. */ int32 sim_bin_getc (FILE *fi, uint32 *newf) { int32 c, rubout; rubout = 0; /* clear toggle */ while ((c = getc (fi)) != EOF) { /* read char */ if (rubout) /* toggle set? */ rubout = 0; /* clr, skip */ else if (c == 0377) /* rubout? */ rubout = 1; /* set, skip */ else if (c > 0200) /* channel 8 set? */ *newf = (c & 070) << 9; /* change field */ else return c; /* otherwise ok */ } return EOF; } t_stat sim_load_bin (FILE *fi) { int32 hi, lo, wd, csum, t; uint32 field, newf, origin; int32 sections_read = 0; for (;;) { csum = origin = field = newf = 0; /* init, field setting can be first after leader */ do { /* skip leader */ if ((hi = sim_bin_getc (fi, &newf)) == EOF) { if (sections_read != 0) { return SCPE_OK; } else return SCPE_FMT; } } while ((hi == 0) || (hi >= 0200)); for (;;) { /* data blocks */ if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */ return SCPE_FMT; wd = (hi << 6) | lo; /* form word */ t = hi; /* save for csum */ if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */ return SCPE_FMT; if (hi == 0200) { /* end of tape? */ if ((csum - wd) & 07777) { /* valid csum? */ if (sections_read > 1) printf ("%d sections sucessfully read\n\r", sections_read); return SCPE_CSUM; } sections_read++; break; //return SCPE_OK; } csum = csum + t + lo; /* add to csum */ if (wd > 07777) /* chan 7 set? */ origin = wd & 07777; /* new origin */ else { /* no, data */ if ((field | origin) >= MEMSIZE) return SCPE_NXM; M[field | origin] = wd; //printf("Writing %04o to %d %04o\n\r",wd, field, origin); origin = (origin + 1) & 07777; } field = newf; /* update field */ } } return SCPE_IERR; } /* Binary loader Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. */ t_stat sim_load (char *fname, int type) { FILE *fileref; t_stat rc; fileref = fopen(fname, "rb"); if (fileref == NULL) { fprintf(stderr, "Unable to open file %s: %s\n", fname, strerror(errno)); exit(1); } if ((type == T_RIM) || /* RIM format? */ (match_ext (fname, "RIM") && type != T_BIN)) rc = sim_load_rim (fileref); else rc = sim_load_bin (fileref); /* no, BIN */ fclose(fileref); return rc; } int main( int argc, char *argv[] ) { int ix, jx; int type; char *pathname[2]; int num_pathname = 0; int diff = 0; int num_nonzero = 0; type = T_NONE; for( ix = 1; ix < argc; ix++ ) { if( argv[ix][0] == '-' ) { for( jx = 1; argv[ix][jx] != 0; jx++ ) { switch( argv[ix][jx] ) { case 'r': type = T_RIM; break; case 'b': type = T_BIN; break; default: fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] ); case 'h': fprintf( stderr, "Usage: [flags] file1 file2 (compare paper tape files)\n" ); fprintf( stderr, " -b -- bin format\n" ); fprintf( stderr, " -r -- rim format\n" ); fprintf( stderr, " -h -- show this help\n" ); fflush( stderr ); exit( -1 ); } } } else { if( num_pathname >= DIM(pathname) ) { fprintf( stderr, "%s: too many input files\n", argv[0] ); exit( -1 ); } pathname[num_pathname++] = &argv[ix][0]; } } if (num_pathname != DIM(pathname)) { fprintf( stderr, "%s: too few input files\n", argv[0] ); exit( -1 ); } if (sim_load (pathname[0], type) != SCPE_OK) { fprintf( stderr, "Error reading %s\n", pathname[0]); exit( -1 ); } memcpy(M2, M, sizeof(M2)); memset(M,0,sizeof(M)); if (sim_load (pathname[1], type) != SCPE_OK) { fprintf( stderr, "Error reading %s\n", pathname[1]); exit( -1 ); } for (ix = 0; ix < MEMSIZE; ix++) { if (M2[ix] != M[ix]) { printf("%05o %04o %04o\n", ix, M2[ix], M[ix]); diff++; } if (M[ix] || M2[ix]) { num_nonzero++; } } if (diff == 0) { printf("Files %s & %s match ", pathname[0], pathname[1]); } else { printf("Files %s & %s differ %d locations ", pathname[0], pathname[1], diff); } printf("%d non zero words\n", num_nonzero); if (diff == 0) { return 0; } else { return 1; } }