/* ** encode DEC absolute loader format or XXDP binary to suit boot ROM ** in VT-11. Reverse engineered from ROM listing, as I had no documentation ** ** Copyright (C) John Holden 1998 ** University of Sydney */ #include #define EVER ;; char nibble_cnt; /* of nibble encoding */ char check_sum; /* input binary checksum */ char xxdp; /* input is XXDP binary */ char verify; /* verify checksums on binary */ FILE *inpfd; /* input file */ FILE *outfd; /* output file */ main(argc, argv) char *argv[]; { char *s; while(--argc) { s = *++argv; if(*s++ != '-') ferr("Expected '-' and an option"); switch(*s++) { case 'i': /* input filename (default stdin) */ if(argc < 2) ferr("No input file"); argc--; if((inpfd = fopen(*++argv, "r")) == NULL) ferr("Cannot open input file"); continue; case 'o': /* output filename (default stdout) */ if(argc < 2) ferr("No output file"); argc--; if((outfd = fopen(*++argv, "w")) == NULL) ferr("Cannot create output file"); continue; case 'x': /* input file is XXDP binary */ xxdp++; continue; case 'v': /* verify input file */ verify++; continue; default: ferr("Unknown option"); } } /* ** default to stdin/stdout if files ar not specified */ if(!inpfd) inpfd = stdin; if(!outfd) outfd = stdout; /* ** output leader */ leader(); /* ** if xxdp, skip the first two bytes */ if(xxdp) { getf(); getf(); } /* ** convert */ encode(); /* ** finish up */ outflush(); fclose(outfd); return 0; } /* ** read and verify absolute loader format data. Output encoded ** in VT-11 bootstrap format */ encode() { int chr; char last_block; int byte_count; int blocks = 0; int data_count = 0; int low_byte, high_byte; for(EVER) { /* ** skip leader until a start frame */ while((chr = getf()) != EOF && chr != 01) ; if(chr == EOF) { fprintf(stderr, "Warning: EOF without transfer or stop block\n"); fprintf(stderr, "Generating stop block\n"); outbyte(0); outbyte(0); outbyte(1); outbyte(0); outbyte(6); outbyte(0); outbyte(1); outbyte(0); outbyte(-8);outbyte(0); return; } check_sum = 1; blocks++; /* ** expect null frame after start frame */ if(getf() != 0) ferr("Expected null frame after start frame"); /* ** output the start of the block */ outbyte(0); outbyte(0); outbyte(1); outbyte(0); /* ** get byte count */ low_byte = getfout(); high_byte = getfout(); byte_count = (high_byte << 8) | low_byte; data_count += byte_count - 6; /* ** if the byte count is 6, then this is a transfer block ** and the last blobk of data */ last_block = ( byte_count == 6)? 1: 0; byte_count -= 4; /* correct for bytes read */ /* ** copy the data */ while(byte_count--) { if((chr = getfout()) == EOF) break; } /* ** and read the checksum. */ if(chr != EOF) { getfout(); if(check_sum & 0377) { if(verify) { fprintf(stderr, "Got checksum error (0%03o)", check_sum & 0377); where(); } else ferr("Checksum error"); } } /* ** if this was a transfer block or EOF, we're finished */ if(chr == EOF || last_block) { if(chr == EOF) fprintf(stderr, "Unexpected EOF\n"); if(verify) fprintf(stderr, "%d data blocks, %d data bytes\n", blocks, data_count); return; } } } /* ** read character (frame). Accumulate checksum */ getf() { int frame; frame = fgetc(inpfd); if(frame != EOF) { check_sum += frame; return frame & 0377; } else return EOF; } /* ** read frames as in 'getf', but output as well */ getfout() { int frame; frame = getf(); outbyte(frame); return frame; } /* ** output leading codes */ leader() { if(verify) return; fputc(0175, outfd); fputc('L', outfd); } /* ** output data byte */ outbyte(byte) char byte; { static unsigned char last_byte; if(verify) return; /* ** encode 8 bit byte in 6 bit nibble format */ switch(nibble_cnt++) { case 0: nibout(byte >> 2); break; case 1: nibout(((byte >> 4) & 017) | (last_byte << 4)); break; case 2: nibout((last_byte << 2) | ((byte >> 6) & 03)); nibout(byte); nibble_cnt = 0; break; } last_byte = byte; } /* ** flush remaining data with encoding */ outflush() { if(verify) return; while(nibble_cnt) outbyte((unsigned char)0); } /* ** output encoded nibble */ nibout(nibble) unsigned char nibble; { nibble &= 077; if(nibble >= ' ') fputc(nibble, outfd); else fputc(nibble | 0100, outfd); } /* ** handle fatal error */ ferr(text) char *text; { fprintf(stderr, text); where(); exit(1); } /* ** output character position */ where() { long position; if(inpfd && (position = ftell(inpfd)) != -1) fprintf(stderr, " at character position %ld\n", position); else fprintf(stderr, "\n"); }