diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | tools/make_shim.c | 18 | ||||
-rw-r--r-- | tools/map2link.py | 183 |
3 files changed, 205 insertions, 4 deletions
@@ -59,6 +59,14 @@ clean: mostlyclean: rm -rf $(ROM) $(CORRECTEDROM) $(OBJS) $(OBJS:.o=.d) $(ROMS:.gb=.sym) $(ROMS:.gb=.map) +.PHONY: linkerscript +linkerscript: $(ROM:.gb=.link) + +%.link: %.map + $(PYTHON3) tools/map2link.py $< $@ + +%.map: %.gb; + $(CORRECTEDROM): %-correctheader.gb: %.gb cp $< $@ $(RGBFIX) -f hg -m 0x10 $@ diff --git a/tools/make_shim.c b/tools/make_shim.c index b5a7517..a025905 100644 --- a/tools/make_shim.c +++ b/tools/make_shim.c @@ -95,6 +95,8 @@ int main(int argc, char * argv[]) { } for (int arg_idx = optind; arg_idx < argc; arg_idx++) { + int last = -1; + int curr; eline[0] = 0; lineno = 0; fname = argv[arg_idx]; @@ -102,6 +104,7 @@ int main(int argc, char * argv[]) { if (file == NULL) RIP("Unable to open file"); while ((lineptr = fgets(line, sizeof(line), file)) != NULL) { + // Assume it's already sorted lineno++; unsigned short bank = 0; unsigned short pointer = 0; @@ -135,6 +138,7 @@ int main(int argc, char * argv[]) { bank = strtoul(lineptr, &end, 16); if (bank == 0 && end == lineptr) RIP("Unable to parse bank number"); + curr = (bank << 14) | (pointer & 0x3fff); // Main loop const char * section = NULL; @@ -157,10 +161,16 @@ int main(int argc, char * argv[]) { // Found section, but cannot shim it continue; - printf("SECTION \"Shim for %s\", %s[$%04X]", symbol, section, pointer); - if (bank) - printf(", BANK[$%04X]", bank); - printf("\n%s::\n\n", symbol); + if (curr != last) { + if (last != -1) + fputc('\n', stdout); + printf("SECTION \"Shim for %s\", %s[$%04X]", symbol, section, pointer); + if (bank) + printf(", BANK[$%04X]", bank); + printf("\n%s::\n", symbol); + last = curr; + } else + printf("%s::\n", symbol); fflush(stdout); } fclose(file); diff --git a/tools/map2link.py b/tools/map2link.py new file mode 100644 index 0000000..b24c82f --- /dev/null +++ b/tools/map2link.py @@ -0,0 +1,183 @@ +#!/bin/python3.6 + +import argparse +import re +import sys +from collections import OrderedDict + + +class MapFile: + LINETYPE_BLANK = -1 + LINETYPE_BANK = 0 + LINETYPE_SECTION = 1 + LINETYPE_SYMBOL = 2 + LINETYPE_SLACK = 3 + LINETYPE_EMPTY = 4 + + bank_types = ('ROM', 'VRAM', 'SRAM', 'WRAM', 'OAM', 'HRAM') + bank_starts = (0x4000, 0x8000, 0xa000, 0xd000, 0xfe00, 0xff80) + + class MapFileLine: + def __init__(self, linestr): + self.raw = linestr + + def __str__(self): + return self.raw + + class BlankLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + + class BankLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + match = re.search('#(\d+)', linestr, re.I) + if match is None: + self.bankno = 0 + else: + self.bankno = int(match.group(1)) + try: + self.banktype = MapFile.bank_types.index(linestr.split()[0].rstrip(':')) + except ValueError as e: + raise ValueError(f'Unrecognized bank type: {linestr.split()[0]}') from e + + @property + def name(self): + if self.banktype == 0: # ROM + if self.bankno == 0: + return 'ROM0' + else: + return f'ROMX ${self.bankno:02x}' + elif self.banktype == 3: # WRAM + if self.bankno == 0: + return 'WRAM0' + else: + return f'WRAMX ${self.bankno:02x}' + elif self.banktype < 3: + return f'{MapFile.bank_types[self.banktype]} {self.bankno:d}' + else: + return f'{MapFile.bank_types[self.banktype]}' + + @property + def start(self): + if self.bankno == 0: + if self.banktype == 0: + return 0x0000 + elif self.banktype == 3: + return 0xc000 + return MapFile.bank_starts[self.banktype] + + def __hash__(self): + return hash(self.name) + + class SectionLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + match = re.search(r'\$([0-9A-F]{4}) \(\$([0-9A-F]+) bytes\) \["(.+)"\]', linestr, re.I) + start, size, self.name = match.groups() + self.start = int(start, 16) + self.size = int(size, 16) + self.end = self.start + self.size + self.symbols = [] + + class SymbolLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + + class SlackLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + match = re.search(r'\$([0-9A-F]{4}) bytes', linestr, re.I) + self.slack = int(match.group(1), 16) + + class EmptyLine(MapFileLine): + def __init__(self, linestr): + super().__init__(linestr) + + line_classes = { + LINETYPE_BLANK: BlankLine, + LINETYPE_BANK: BankLine, + LINETYPE_SECTION: SectionLine, + LINETYPE_SYMBOL: SymbolLine, + LINETYPE_SLACK: SlackLine, + LINETYPE_EMPTY: EmptyLine + } + + def __init__(self, fname, *fpargs, **fpkwargs): + self.fname = fname + self.fp = None + self.fpargs = fpargs + self.fpkwargs = fpkwargs + + def open(self): + if self.fp is None or self.fp.closed: + self.fp = open(self.fname, *self.fpargs, **self.fpkwargs) + + def close(self): + if not self.fp.closed: + self.fp.close() + self.fp = None + + def __enter__(self): + self.open() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.fp.__exit__(exc_type, exc_val, exc_tb) + self.fp = None + + def __iter__(self): + if self.fp is None or self.fp.closed: + print('Warning: Cowardly refusing to read closed file', file=sys.stderr) + raise StopIteration + for line in self.fp: + linestr = line.strip('\n') + if linestr == '': + line_type = self.LINETYPE_BLANK + elif 'SECTION:' in linestr: + line_type = self.LINETYPE_SECTION + elif 'SLACK:' in linestr: + line_type = self.LINETYPE_SLACK + elif linestr == ' EMPTY': + line_type = self.LINETYPE_EMPTY + elif ' = ' in linestr: + line_type = self.LINETYPE_SYMBOL + else: + line_type = self.LINETYPE_BANK + yield self.line_classes[line_type](linestr) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('mapfile', type=MapFile) + parser.add_argument('linkfile', type=argparse.FileType('w')) + args = parser.parse_args() + + rom_map = OrderedDict() + cur_bank = None + + print('; Automatically generated by map2link.py', file=args.linkfile) + + with args.mapfile: + for line in args.mapfile: + if isinstance(line, MapFile.BankLine): + cur_bank = line + rom_map[cur_bank] = [] + elif isinstance(line, MapFile.SectionLine): + rom_map[cur_bank].append(line) + + for bank, sections in rom_map.items(): + if len(sections) == 0: + continue + sections.sort(key=lambda s: s.start) + print(bank.name, file=args.linkfile) + start = bank.start + for section in sections: + if section.start > start: + print(f'\torg ${section.start:04x}', file=args.linkfile) + print(f'\t"{section.name}" ; size: ${section.size:04x}', file=args.linkfile) + start = section.end + + +if __name__ == '__main__': + main() |