diff options
Diffstat (limited to 'mkreloc.c')
-rw-r--r-- | mkreloc.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/mkreloc.c b/mkreloc.c new file mode 100644 index 0000000..35c6cd7 --- /dev/null +++ b/mkreloc.c @@ -0,0 +1,298 @@ +/* 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 <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> + +#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; +} + |