aboutsummaryrefslogtreecommitdiff
path: root/mkreloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mkreloc.c')
-rw-r--r--mkreloc.c298
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;
+}
+