/* this can be compiled for either POSIX or Atari 8-bit. it's got some weird constructs because sizeof(int) is 16 bits on the Atari. also, I've avoided printf() to keep the .xex size down. */ #include #include #include #include #define u8 uint8_t #define u16 uint16_t #ifdef __ATARI__ #define low_infile "D:LO.XEX" #define hi_infile "D:HI.XEX" #define reloc_file "D:RELOC.XEX" #define out_file "D:AUTORUN.SYS" #else #define low_infile "lo.xex" #define hi_infile "hi.xex" #define reloc_file "reloc.xex" #define out_file "autorun.sys" #endif #define MAX_SIZE 18880U #define TBL_SIZE 2360 u8 bitmap[TBL_SIZE]; u16 bitmap_idx = 0; void errexit(void) { #ifdef __ATARI__ fputs("Press Return to exit.", stdout); getc(stdin); #endif exit(1); } void errfile(const char *fn) { fputs(fn, stderr); fputc(':', stderr); fputc(' ', stderr); } void invalid_xex(const char *fn) { errfile(fn); fputs("not a valid XEX file.\n", stderr); errexit(); } void err_trunc(const char *fn) { errfile(fn); fputs("truncated.\n", stderr); errexit(); } void bad_diff(const char *fn) { errfile(fn); fputs("not $100 above.\n", stderr); errexit(); } void bad_length(const char *fn) { errfile(fn); fputs("length mismatch.\n", stderr); errexit(); } void too_long(const char *fn) { errfile(fn); fputs("code segment too long.\n", stderr); errexit(); } void bad_byte(const char *fn) { errfile(fn); fputs("bytes differ by other than 0 or 1.\n", stderr); errexit(); } void invalid_seg(const char *fn) { errfile(fn); fputs("only one code segment allowed.\n", stderr); errexit(); } u16 read_word(const char *fh, FILE *f) { u16 word; int c; c = fgetc(f); if(c < 0) err_trunc(fh); word = (u8)c; c = fgetc(f); if(c < 0) err_trunc(fh); word |= ((u8)c) << 8; return word; } int read_header(FILE *f, u16 *s, u16 *e) { u16 a; int c; c = fgetc(f); if(c < 0) return 0; a = (u8)c; c = fgetc(f); if(c < 0) return 0; a |= ((u8)c) << 8; if(a == 0xffff) { c = fgetc(f); if(c < 0) return 0; a = (u8)c; c = fgetc(f); if(c < 0) return 0; a |= ((u8)c) << 8; } *s = a; c = fgetc(f); if(c < 0) return 0; a = (u8)c; c = fgetc(f); if(c < 0) return 0; a |= ((u8)c) << 8; *e = a; return 1; } void write_word(FILE *f, u16 word) { fputc(word & 0xff, f); fputc(word >> 8, f); } void add_bit(u8 bit) { static u16 pos = 0; u8 i; bitmap_idx = pos / 8; i = 7 - (pos % 8); bitmap[bitmap_idx] |= (bit * (1 << i)); pos++; } void append_bitmap(FILE *f) { fwrite(bitmap, bitmap_idx + 1, 1, f); } void read_run_init(const char *fn, FILE *f, u16 *run, u16 *init) { u16 s, e; *run = *init = 0; while(read_header(f, &s, &e)) { if(s == 0x02e0) { if(e == 0x02e1) { *run = read_word(fn, f); } else if(e == 0x02e3) { *run = read_word(fn, f); *init = read_word(fn, f); } else { invalid_seg(fn); } } else if(s == 0x02e2 && e == 0x02e3) { *init = read_word(fn, f); } else { invalid_seg(fn); } } } FILE *open_file(const char *fn, const char *mode) { FILE *fh = fopen(fn, mode); if(!fh) { errfile(fn); perror(fn); errexit(); } return fh; } FILE *open_input(const char *fn) { return open_file(fn, "rb"); } FILE *open_output(const char *fn) { return open_file(fn, "wb"); } int main(int, char **) { int c; u8 a, b; u16 hi_start, hi_end, lo_start, lo_end, lo_len; u16 run_addr = 0, init_addr = 0; FILE *lo, *hi, *rel, *out; #if 0 /* if we were actually printing anything... */ #ifdef __ATARI__ *((char *)0x2be) = 0x40; /* enable caps lock */ putchar(0x9c); /* delete line (cursor to left margin) */ #endif #endif /* open and check the two .xex input files */ lo = open_input(low_infile); hi = open_input(hi_infile); if(!read_header(lo, &lo_start, &lo_end)) { invalid_xex(low_infile); } if(!read_header(hi, &hi_start, &hi_end)) { invalid_xex(hi_infile); } if(hi_start != (lo_start + 0x100)) bad_diff(hi_infile); lo_len = lo_end - lo_start + 1; if(lo_len != (hi_end - hi_start + 1)) bad_length(hi_infile); if(lo_len >= MAX_SIZE) too_long(hi_infile); out = open_output(out_file); write_word(out, 0xffffU); write_word(out, lo_start); write_word(out, lo_end); /* read segment data, create bitmap */ while(lo_len--) { c = fgetc(lo); if(c < 0) err_trunc(low_infile); a = (u8)c; fputc(a, out); c = fgetc(hi); if(c < 0) err_trunc(hi_infile); b = (u8)c; if(a == b) { add_bit(0); } else if(a == (b - 1)) { add_bit(1); } else { bad_byte(hi_infile); } } fclose(hi); read_run_init(low_infile, lo, &run_addr, &init_addr); /* append the relocator */ rel = open_input(reloc_file); read_header(rel, &hi_start, &hi_end); write_word(out, 0xffffU); write_word(out, hi_start); write_word(out, hi_end + bitmap_idx + 1 + 8); while((c = fgetc(rel)) >= 0) { fputc(c & 0xff, out); } fclose(rel); /* append the address table */ write_word(out, lo_start); write_word(out, lo_end); write_word(out, run_addr); write_word(out, init_addr); /* append the bitmap */ append_bitmap(out); /* append the init address */ // write_word(out, 0xffffU); write_word(out, 0x2e2); write_word(out, 0x2e3); write_word(out, 0x71c0); fclose(out); return 0; }