From: Alan Cox Date: Wed, 31 Dec 2014 22:01:43 +0000 (+0000) Subject: binmunge, bihx: SDCC banking hacks X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=c093343e1a03ecfc39e0933f11cc9710170ef888;p=FUZIX.git binmunge, bihx: SDCC banking hacks These two tools are the first parts of the hacks to make SDCC generate banked binaries. It's not a full automatic banker but it's a first step. sdldz80 is modified to spit out a bihx format, which is a file that contains lines of the format XX:Intel IHX - Intel ihex from the : for bank XX :Intel IHX - Intel ihex for all the banks used Bxxxx - Inter bank relocation record Currently it is hard coded to understand the following segments CODE "bank 1" - banked code CODE2 "bank 2" - banked code CODE3 "bank 3" - banked code VIDEO "bank 3" - banked code FONT "bank 3" - data INITIALIZER common - data DATA common - data CONST common - data COMMONMEM common - code DISCARD "bank 3" - banked (discard) code calls are patched from CD xx xx to use RST8/16/24 xx xx according to the bank in question. References to banked objects that are made from data areas or are JP rather than call instructions are fixed up by changing the vector to point to a 4 byte stub for each problem case that is of the form RST xx xx RET. This generates more stubs than we really need right now. Most of them will go away if the system call table is moved into its own file and we add some kind of 'DATA2' segment. --- diff --git a/Kernel/tools/bihx.c b/Kernel/tools/bihx.c new file mode 100644 index 00000000..b94b18ae --- /dev/null +++ b/Kernel/tools/bihx.c @@ -0,0 +1,122 @@ +/* + * Banked ihx processor + * + * Split the ihx file into base and bank blocks + * Perform the patch ups on the file + * Write the stubs + */ + +#include +#include +#include +#include + +FILE *fseg[10]; +static char fbuf[64]; + +void open_fseg(int n) +{ + if (n == 0) + sprintf(fbuf, "common.ihx"); + else + sprintf(fbuf, "bank%d.ihx", n); + fseg[n] = fopen(fbuf, "w"); + if (fseg[n] == NULL) { + perror(fbuf); + exit(1); + } +} + +void put_seg(int n, char *bp) +{ + if (fseg[n] == NULL) + open_fseg(n); + fputs(bp, fseg[n]); +} + +void put_all_segs(char *bp) +{ + int i; + for (i = 0; i < 10; i++) { + if (fseg[i]) + fputs(bp, fseg[i]); + } +} + +void close_segs(void) +{ + int i; + for (i = 0; i < 10; i++) { + if (fseg[i]) + if(fclose(fseg[i])) + perror("fclose"); + } +} + +void bin_segs(void) +{ + int i; + system("makebin -s 65536 -p common.ihx >common.bin\n"); + for (i = 1; i < 10; i++) { + if (fseg[i]) { + snprintf(fbuf, 64, "makebin -s 65536 -p bank%d.ihx >bank%d.bin\n", + i, i); + system(fbuf); + } + } +} + +void save_patch_rule(FILE *fr, char *buf) +{ + fputs(buf, fr); +} + +void split_bihx(char *name) +{ + int n; + char buf[256]; + FILE *fp = fopen(name, "r"); + FILE *fr; + + if (fp == NULL) { + perror(name); + exit(1); + } + + fr = fopen("relocs.dat", "w"); + if (fr == NULL) { + perror("relocs.dat"); + exit(1); + } + + while(fgets(buf, 256, fp)) { + /* Leading hex means ihx data for this target */ + if (isdigit(*buf)) { + sscanf(buf, "%x", &n); + put_seg(n, buf + 2); + } else if (*buf == ':') /* ihx for all (end marker) */ + put_all_segs(buf); + else if (*buf == ';') + continue; + else if (*buf == 'B') + save_patch_rule(fr, buf); + else + fprintf(stderr, "%s: invalid bihx line.\n", name, buf); + } + fclose(fp); + fclose(fr); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + fprintf(stderr, "%s bihxfile\n", argv[0]); + exit(1); + } + split_bihx(argv[1]); + close_segs(); + bin_segs(); +} + + + \ No newline at end of file diff --git a/Kernel/tools/binmunge.c b/Kernel/tools/binmunge.c new file mode 100644 index 00000000..4a7d4e3e --- /dev/null +++ b/Kernel/tools/binmunge.c @@ -0,0 +1,244 @@ +/* + * Fix up the given binary block with the reloc data + * + * Patch RST lines into the relevant places, generate stub info + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NBANKS 4 + +unsigned char buf[NBANKS][65536]; +unsigned int size[NBANKS]; +FILE *fptr[NBANKS]; +int v; +static int nextfix = 0xFE00; /* FIXME */ +static int lastfix = 0x10000; + +struct stubmap { + struct stubmap *next; + int bank; + uint16_t addr; + uint16_t target; +}; + +struct stubmap *stubs; +static int stubct = 0; +static int stubdup = 0; + +unsigned int resize(int b) +{ + unsigned char *bp = buf[b] + 65535; + while(*bp == 0) + bp--; + bp++; + if (bp - buf[b] > size[b]) + return bp - buf[b]; + return size[b]; +} + +/* FIXME: */ +int stubmap(uint16_t v, int bank) +{ + struct stubmap *s = stubs; + struct stubmap **p = &stubs; + + while(s) { + if (s->bank == bank && s->addr == v) { + stubdup++; + return s->target; + } + p = &s->next; + s = *p; + } + s = malloc(sizeof(struct stubmap)); + if (s == NULL) { + fprintf(stderr, "Out of memory.\n"); + exit(1); + } + *p = s; + s->next = NULL; + s->bank = bank; + s->addr = v; + s->target = nextfix; + if (nextfix == lastfix) { + fprintf(stderr, "Out of fix space (%d stubs used).\n", stubct); + exit(1); + } + buf[0][nextfix++] = 0xC7 + 8 * bank; /* RST */ + buf[0][nextfix++] = v & 0xFF; /* Target */ + buf[0][nextfix++] = v >> 8; + buf[0][nextfix++] = 0xC9; /* RET */ + stubct++; + return s->target; +} + +void code_reloc(uint8_t sbank, uint16_t ptr, uint8_t dbank) +{ + int da; + if (ptr == 0) { + fprintf(stderr, "Nonsense zero based code relocation.\n"); + exit(1); + } + if (dbank == 0 || dbank >= NBANKS) { + fprintf(stderr, "Invalid bank %d\n", dbank); + exit(1); + } + switch(buf[sbank][ptr-1]) { + case 0xC3: /* JP - needs stub */ + if (v) + printf("Converting JP at %04x to RST/RET stub\n", ptr); + da = stubmap(buf[sbank][ptr] + (buf[sbank][ptr+1] << 8), dbank); + buf[sbank][ptr] = da & 0xFF; + buf[sbank][ptr+1] = da >> 8; + break; + case 0xCD: /* CALL */ + if (v) + printf("Converting CALL at %04x to RST\n", ptr); + buf[sbank][ptr-1] = 0xC7 + 8 * dbank; /* RST 8/16/24 */ + break; + case 0xC7: /* RST */ + case 0xCF: + case 0xD7: + case 0xDF: + fprintf(stderr, "File already processed!\n"); + exit(1); + default: + fprintf(stderr, "Bad relocation in code %04X: %02X\n", + ptr-1, buf[sbank][ptr-1]); + } +} + +void data_reloc(uint8_t sbank, uint16_t ptr, uint8_t dbank) +{ + int na; + uint16_t n; + + /* Get the target */ + n = buf[sbank][ptr] + (buf[sbank][ptr+1]<<8); + + if (v) + printf("Stubhooking %04x for data reference.\n", ptr); + /* Find the stub for it */ + na = stubmap(n, dbank); + if (na == -1) { + fprintf(stderr, "No stub match: stubs stale\n"); + exit(1); + } + /* Patch in the revised destination address */ + buf[sbank][ptr] = na & 255; + buf[sbank][ptr+1] = na >> 8; +} + +int stub_code(char *name) +{ + if(strncmp(name, "_CODE", 5) == 0) + return 1; + if(strcmp(name, "_VIDEO") == 0) + return 1; + if(strcmp(name, "_COMMONMEM") == 0) + return 1; + if(strcmp(name, "_DISCARD") == 0) + return 1; + /* Data */ + if(strcmp(name, "_INITIALIZER") == 0) + return 0; + if(strcmp(name, "_DATA") == 0) + return 0; + if(strcmp(name, "_FONT") == 0) + return 0; + if(strcmp(name , "_CONST") == 0) + return 0; + fprintf(stderr, "Unknown bank name %s\n", name); + exit(1); +} + +static void process_stub(char *p) +{ + int b1, b2, addr; + char name[65]; + if (sscanf(p, "%02x %04x %02x %64s", &b1, &addr, &b2, name) != 4) { + fprintf(stderr, "Invalid relocation link %s\n", p); + exit(1); + } + if (stub_code(name)) + code_reloc(b1, addr, b2); + else + data_reloc(b1, addr, b2); +} + + +int main(int argc, char *argv[]) +{ + FILE *r; + char in[256]; + char bin[64]; + int banks; + + if (argv[1] && strcmp(argv[1], "-v") == 0) + v = 1; + if (argc != 1 + v) { + fprintf(stderr, "%s -v\n", argv[0]); + exit(1); + } + + r = fopen("relocs.dat", "r"); + if (r == NULL) { + perror("relocs.dat"); + exit(1); + } + + for (banks = 0; banks < 4; banks ++) { + if (banks == 0) + strcpy(bin, "common.bin"); + else + sprintf(bin, "bank%d.bin", banks); + fptr[banks] = fopen(bin, "r+"); + if (fptr[banks] == NULL) { + if (errno != ENOENT) { + perror(bin); + exit(1); + } + } else { + size[banks] = fread(buf[banks], 1, 65536, fptr[banks]); + if (size[banks] < 1) { + perror(bin); + exit(1); + } + rewind(fptr[banks]); + } + } + + while(fgets(in, 256, r)) { + if (*in != 'B') { + fprintf(stderr, "Bad record: %s", in); + exit(1); + } + if (v) + printf("|%s", in); + process_stub(in + 1); + } + fclose(r); + + for (banks = 0; banks < 4; banks++) { + if (fptr[banks]) { + /* Just conceivably we might reloc a trailing zero byte and need to grow the + file */ + size[banks] = resize(banks); + if (fwrite(buf[banks], size[banks], 1, fptr[banks]) != 1) { + perror("fwrite"); + exit(1); + } + fclose(fptr[banks]); + } + } + printf("%d stub relocations using %d bytes, %d duplicates\n", + stubct, stubct * 4, stubdup); + exit(0); +}