/* ---------------------- * P C V D U M P V 1.00 * ---------------------- * Displays .PCV (PCVIC system snapshot) files & checks them for validity. * Versions supported: 1.0 * * Copyright (C) 16 jan 1998 by B.W. van Schooten. * * This program is freely useable, and freely modifiable as long as it is * made clear that the original program has been modified. */ #define USAGE \ "\n"\ "Usage: PCVDUMP sourcefile targetfile\n"\ "\n"\ "The source file must be a PCV (Vic-20) system snapshot.\n"\ "Header information will be printed to stdout. The contents of the memory\n"\ "space will be decompressed and written to the targetfile. Diagnostic\n"\ "messages are written to stderr.\n"\ "\n" #include #include #define ERROR_NONE 0 #define ERROR_EOF 1 #define ERROR_TOOLONG 2 char *decompressmsg[] = { "Done.\n", "\nERROR: EOF found when data was expected.\n", "\nERROR: Data runs past expected end address.\n" }; int decompress (long, FILE *, FILE *); /* Usage: error=decompress(size, inputfile, outputfile) * Decompresses Byterun-compressed data from inputfile, writing the result * to outputfile. * * Byterun is a simple compression method, based on replacing a row of * bytes which have the same value by a count and a value byte. It is used * for example in ILBM images. * * This routine also updates the checksum as the data is read. */ void interpretrsb100 (FILE *,int); /* Shows information of register state block (rsb) as it is found in * version 1.00. File pointer should point to start of rsb. * File pointer is left undefined. */ void addtochecksum (unsigned char); /* Calculates new checksum according to given byte. Checksum is stored in * GLOBAL variable checksum. */ void closedown (int); /* Closes any open files and exits with supplied exit code */ const char *headerstr="PCVIC system snapshot"; #define HEADERSTRLEN 22 /* length includes zero terminator */ long checksum; FILE *inp, *outp; void main(int argc,char **argv) { int n,m; /* loop counters */ unsigned char c1,c2; /* temp. input characters */ int rsbsize; /* size field of register state block */ long rsbstart; /* file pointer to start of reg.state block */ int decompresserror; /* error returned by decompress procedure */ unsigned int checksumread; /* value of checksum as read from file */ int version; /* PCV version, ex. 100=1.00, 110=1.10 */ inp=NULL; outp=NULL; checksum=0x7ffb; fprintf(stderr,"PCVDUMP 1.00, (C) 16 jan 1998 by B.W. van Schooten\n"); if (argc!=3) { fprintf(stderr,USAGE); closedown(EXIT_SUCCESS); } /* * OPEN FILES */ inp=fopen(argv[1],"rb"); if (!inp) { fprintf(stderr,"ERROR: Cannot open file %s.\n",argv[1]); closedown(EXIT_FAILURE); } outp=fopen(argv[2],"wb"); if (!outp) { fprintf(stderr,"ERROR: Cannot write file %s.\n",argv[2]); closedown(EXIT_FAILURE); } /* * MATCH HEADER */ n=0; while (1) { c1=(unsigned char)fgetc(inp); if (feof(inp)) { fprintf(stderr,"ERROR: EOF in header.\n"); closedown(EXIT_FAILURE); } if (c1!=headerstr[n]) break; n++; if (n==HEADERSTRLEN) break; } if (n!=HEADERSTRLEN) { fprintf(stderr,"ERROR: Header does not match.\n"); closedown(EXIT_FAILURE); } /* * GET VERSION NUMBER */ c1=(unsigned char)fgetc(inp); addtochecksum(c1); c2=(unsigned char)fgetc(inp); addtochecksum(c2); if (feof(inp)) { fprintf(stderr,"ERROR: EOF in version number.\n"); closedown(EXIT_FAILURE); } if (c1>=100) { fprintf(stderr,"ERROR: minor version out of valid range.\n"); closedown(EXIT_FAILURE); } version=c1+100*c2; printf("SnapshotVersion=%d.%02d\n",(int)c2,(int)c1); /* * GET SIZE OF REGISTER STATE BLOCK */ c1=(unsigned char)fgetc(inp); addtochecksum(c1); c2=(unsigned char)fgetc(inp); addtochecksum(c2); if (feof(inp)) { fprintf(stderr,"ERROR: EOF in register state block size.\n"); closedown(EXIT_FAILURE); } rsbsize=(int)c1 + 256*(int)c2; printf("RSBSize=%u\n",rsbsize); if (rsbsize>32767) { fprintf(stderr,"ERROR: Register state block size more than 32767.\n"); closedown(EXIT_FAILURE); } rsbstart = ftell(inp); /* * CHECKSUM OVER REGISTER STATE BLOCK */ for (n=0; n128) { /* 129..255: duplicate byte n times */ databyte=(unsigned char)fgetc(inp); addtochecksum(databyte); if (feof(inp)) return (ERROR_EOF); for (n=0; n<257-leaderbyte; n++) { fputc(databyte, outp); runningtotal++; } } /* 128: ignore byte */ if (runningtotal==bytes) return(ERROR_NONE); if (runningtotal>bytes) return(ERROR_TOOLONG); } } void interpretrsb100(FILE *inp, int rsbsize) { unsigned char c1,c2; unsigned int value; if (rsbsize!=35) { fprintf(stderr,"WARNING: Register state block size should be 35.\n"); } c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); value=c1+256*c2; printf("X=$%04X\n",value); if (c2!=0) fprintf(stderr,"WARNING: Hi byte must be 0.\n"); c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); value=c1+256*c2; printf("Y=$%04X\n",value); if (c2!=0) fprintf(stderr,"WARNING: Hi byte must be 0.\n"); c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); value=c1+256*c2; printf("S=$%04X\n",value); if (c2!=1) fprintf(stderr,"WARNING: Hi byte must be 1.\n"); c1=(unsigned char)fgetc(inp); printf("OLDSCANCOUNT=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("AUXFLAGS=%02X\n",c1); if (c1 & 0xc3) fprintf(stderr,"WARNING: Bit 0,1,6,7 should all be 0.\n"); if (!(c1 & 0x20)) fprintf(stderr,"WARNING: Bit 5 should always be 1.\n"); c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); value=c1+256*c2; printf("SCANLINE=$%02X\n",value); if (value>32767) fprintf(stderr,"WARNING: Value should not exceed 32767.\n"); c1=(unsigned char)fgetc(inp); printf("IFR1=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("IER1=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("IFR2=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("IER2=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("PERIP1B=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("LATCH1B=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("PERIP1A=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("LATCH1A=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("PERIP2B=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("LATCH2B=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("PERIP2A=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("LATCH2A=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("TIMERSTATUS=$%02X\n",c1); if (c1 & 0xf0) fprintf(stderr,"WARNING: high four bits should be zero.\n"); c1=(unsigned char)fgetc(inp); printf("V1T2LATCHL=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("V2T2LATCHL=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("V1T2TIMERL=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("V2T2TIMERL=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("NMIFLANK=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("MEMCONFIG=$%02X\n",c1); if (c1 & 0xd0) fprintf(stderr,"WARNING: Bit 7,6 and 3 should all be zero.\n"); c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); value=c1+256*c2; printf("PC=$%04X\n",value); c1=(unsigned char)fgetc(inp); c2=(unsigned char)fgetc(inp); printf("MAINFLAGS=$%02X(H) $%02X(L)\n",c2,c1); if (c2 & 0xbe) fprintf(stderr, "WARNING: Bit 7,5,4,3,2,1 of high byte should be zero.\n"); c1=(unsigned char)fgetc(inp); printf("A=$%02X\n",c1); c1=(unsigned char)fgetc(inp); printf("SCANCOUNT=$%02X\n",c1); } void addtochecksum(unsigned char nextbyte) { long tmp1,tmp2, carryout; tmp1=checksum; tmp2=(long)nextbyte; /* * ROL W[checksum],1 */ tmp1 <<= 1; carryout = (tmp1 & 0x10000); if (carryout) tmp1 |= 1; tmp1 &= 0xffff; /* * CBW */ if (tmp2 >= 128) tmp2 |= 0xff00; /* * ADD [checksum],AX */ tmp1 += tmp2; tmp1 &= 0xffff; checksum=tmp1; /* printf("C%x ",(int) checksum);*/ } void closedown(int exitcode) { if (inp) fclose(inp); if (outp) fclose(outp); exit(exitcode); }