diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Makefile | 3 | ||||
| -rw-r--r-- | tools/disasm_coverage.py | 41 | ||||
| -rw-r--r-- | tools/make_shim.c | 179 | ||||
| -rw-r--r-- | tools/scan_includes.py | 82 | ||||
| -rw-r--r-- | tools/tests/charmap.asm | 4 |
5 files changed, 114 insertions, 195 deletions
diff --git a/tools/Makefile b/tools/Makefile index c591d9c..6c49ccb 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -4,8 +4,7 @@ CFLAGS := -O3 -std=c99 -Wall -Wextra tools := \ pkmncompress \ - gfx \ - make_shim + gfx all: $(tools) diff --git a/tools/disasm_coverage.py b/tools/disasm_coverage.py index 39d1960..9fcd61e 100644 --- a/tools/disasm_coverage.py +++ b/tools/disasm_coverage.py @@ -10,13 +10,13 @@ import png from mapreader import MapReader from colorsys import hls_to_rgb -if __name__ == "__main__": +if __name__ == '__main__': # argument parser ap = argparse.ArgumentParser() - ap.add_argument("-o", dest="filename", default="coverage.png") - ap.add_argument("-s", dest="statsname", default="coverage.log") - ap.add_argument("-m", dest="mapfile", required=True) - ap.add_argument("-b", dest="num_banks", required=True, type=lambda x: int(x, 0)) + ap.add_argument('-r', dest='romname') + ap.add_argument('-o', dest='filename', default='coverage.png') + ap.add_argument('-m', dest='mapfile', required=True) + ap.add_argument('-b', dest='num_banks', required=True, type=lambda x: int(x, 0)) args = ap.parse_args() bank_mask = 0x3FFF @@ -24,6 +24,7 @@ if __name__ == "__main__": width = 256 # pixels per row bpp = 8 # bytes per pixel + romname = args.romname rom_size = args.num_banks * bank_size # bytes height = (args.num_banks * bank_size + (width * bpp - 1)) // (width * bpp) # pixels rows_per_bank = bank_size // (width * bpp) @@ -34,17 +35,37 @@ if __name__ == "__main__": l = f.readlines() except UnicodeDecodeError: # Python 3 seems to choke on the file's encoding, but the `encoding` keyword only works on Py3 - with open(args.mapfile, 'r', encoding= "utf-8") as f: + with open(args.mapfile, 'r', encoding= 'utf-8') as f: l = f.readlines() r.read_map_data(l) - hit_data = [[0] * width for _ in range(height)] default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size} + filler = [0x00, 0xFF] + + if (romname is not None): + with open(romname, 'rb') as f: + for rb in range(0, args.num_banks): + data = r.bank_data['ROM Bank'].get(rb, default_bank_data) + bank = f.read(bank_size) + if (bank[bank_size - 1] in filler): + fill = bank[bank_size - 1] + for i in reversed(range(-1, bank_size - 1)): + if (i < 0 or bank[i] != fill): + break + # i is now pointing to first different byte + beg = i + 1 + (0 if rb == 0 else bank_size) + end = bank_size + (0 if rb == 0 else bank_size) + data['sections'].append({'beg': beg, 'end': end, 'name': 'Section_Trailing_Fill', 'symbols': []}) + + hit_data = [[0] * width for _ in range(height)] for bank in range(args.num_banks): data = r.bank_data['ROM Bank'].get(bank, default_bank_data) for s in data['sections']: beg = (s['beg'] & bank_mask) + bank * bank_size - end = (s['end'] & bank_mask) + bank * bank_size + end = ((s['end'] -1) & bank_mask) + bank * bank_size # end is exclusive + # skip zero-sized entries + if (s['beg'] == s['end']): + continue y_beg = beg // (width * bpp) x_beg = (beg % (width * bpp)) // bpp y_end = end // (width * bpp) @@ -63,10 +84,6 @@ if __name__ == "__main__": for x in range(x_line_beg, x_line_end + 1): hit_data[y][x] += bpp - with open(args.statsname, 'w') as stats: - # TODO: write stats - pass - png_data = [] for i, row in enumerate(hit_data): bank = i // rows_per_bank diff --git a/tools/make_shim.c b/tools/make_shim.c deleted file mode 100644 index a025905..0000000 --- a/tools/make_shim.c +++ /dev/null @@ -1,179 +0,0 @@ -#include <stdio.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -struct Section { - unsigned short end; - bool invalid; - char * name; - bool banked; -}; - -typedef struct Section section_t; - -// These functions are like strspn and strcspn, but from the right of the string rather than the left. -size_t strrspn(const char *s1, const char *s2) { - const char * _s1 = s1; - const char * _s2; - - while (*_s1++); - _s1--; - while (_s1 > s1) { - for (_s2 = s2; *_s2; _s2++) { - if (_s1[-1] == *_s2) { - break; - } - } - if (*_s2 == 0) - break; - _s1--; - } - - return _s1 - s1; -} - -size_t strrcspn(const char *s1, const char *s2) { - const char * _s1 = s1; - const char * _s2; - - while (*_s1++); - _s1--; - while (_s1 > s1) { - for (_s2 = s2; *_s2; _s2++) { - if (_s1[-1] == *_s2) - break; - } - if (*_s2) - break; - _s1--; - } - - return _s1 - s1; -} - -#define RIP(errmsg) { \ - fprintf(stderr, "%s:%d:%s: %s\n", fname, lineno, eline, errmsg); \ - if (file) fclose(file); \ - return 1; \ -} - -int main(int argc, char * argv[]) { - int ch; - char line[16*1024]; - char eline[16*1024]; - char *lineptr = NULL; - char *fname; - int lineno; - - section_t section_list[] = { - {0x4000, false, "ROM0", false}, - {0x8000, false, "ROMX", true}, - {0xA000, false, "VRAM", true}, - {0xC000, false, "SRAM", true}, - {0xD000, false, "WRAM0", false}, - {0xE000, false, "WRAMX", true}, - {0xFE00, true, "Echo RAM", false}, - {0xFEA0, false, "OAM", false}, - {0xFF80, true, "FEXX / IO", false}, - {0xFFFF, false, "HRAM", false}, - {} - }; - - while ((ch = getopt(argc, argv, "wdt")) != -1) { - switch (ch) { - case 'w': - case 'd': - section_list[4].end = 0xE000; - break; - case 't': - section_list[0].end = 0x8000; - break; - } - } - - for (int arg_idx = optind; arg_idx < argc; arg_idx++) { - int last = -1; - int curr; - eline[0] = 0; - lineno = 0; - fname = argv[arg_idx]; - FILE * file = fopen(fname, "r"); - 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; - char * symbol = NULL; - char * end; - char * addr_p; - strcpy(eline, line); // Unmodified copy for tracebacks - *strrchr(eline, '\n') = 0; - - // line = line.split(";")[0].strip() - lineptr += strspn(lineptr, " \t\n"); - end = strchr(lineptr, ';'); - if (end) *end = 0; - lineptr[strrspn(lineptr, " \t\n")] = 0; - if (!*lineptr) - continue; - - // Get the bank, address, and symbol - end = lineptr + strcspn(lineptr, " \t\n"); - symbol = end + strspn(end, " \t\n"); - if (!*symbol) - RIP("Declaration not in \"bank:addr Name\" format"); - *end = 0; - addr_p = strchr(lineptr, ':'); - if (!addr_p) - RIP("Pointer not in bank:addr format"); - *addr_p++ = 0; - pointer = strtoul(addr_p, &end, 16); - if (pointer == 0 && end == addr_p) - RIP("Unable to parse symbol address"); - 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; - section_t * section_type; - - for (section_type = section_list; section_type->end; section_type++) { - if (pointer < section_type->end) { - if (section_type->invalid) { - fprintf(stderr, "Warning: cannot shim '%s' in section type '%s'\n", symbol, section_type->name); - } else { - section = section_type->name; - if (!section_type->banked) - bank = 0; - } - break; - } - } - - if (section == NULL) - // Found section, but cannot shim it - continue; - - 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); - } - return 0; -} diff --git a/tools/scan_includes.py b/tools/scan_includes.py new file mode 100644 index 0000000..34e1f09 --- /dev/null +++ b/tools/scan_includes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Get all the dependencies of RGBDS assembly files recursively, +and output them using Make dependency syntax. +""" + +# Script adapted from the Telefang disassembly / fan translation project. + +from __future__ import print_function +from __future__ import unicode_literals + +import argparse +import os +import re +import sys +if sys.version_info[0] < 3: + from codecs import open + +INCLUDE_RE = re.compile(r"^(?:[a-zA-Z0-9_.]+:?:?)?\s*(INC(?:LUDE|BIN))", re.IGNORECASE) + +def dependencies_in(asm_file_paths, build_dirs=[]): + asm_file_paths = list(asm_file_paths) + dependencies = {} + + for path in asm_file_paths: + if path not in dependencies: + asm_dependencies, bin_dependencies = shallow_dependencies_of(path, build_dirs) + dependencies[path] = asm_dependencies | bin_dependencies + asm_file_paths += asm_dependencies + + return dependencies + +def shallow_dependencies_of(asm_file_path, build_dirs=[]): + asm_dependencies = set() + bin_dependencies = set() + + with open(asm_file_path, 'r', encoding='utf-8') as f: + for line in f: + m = INCLUDE_RE.match(line) + if m is None: + continue + + keyword = m.group(1).upper() + line = line.split(';', 1)[0] + # RGBDS treats absolute(-looking) paths as relative, + # so leading slashes should be stripped. + path = line[line.index('"') + 1:line.rindex('"')].lstrip('/') + if keyword == 'INCLUDE': + asm_dependencies.add(path) + else: + if os.path.isfile(path) or not build_dirs: + bin_dependencies.add(path) + else: + bin_dependencies.update(os.path.join(d, path) for d in build_dirs) + + return asm_dependencies, bin_dependencies + +def main(argv): + script_name = os.path.basename(__file__) + parser = argparse.ArgumentParser(prog=script_name, add_help=False) + parser.add_argument('-h', '--help', action='help', help="Show this help and exit.") + parser.add_argument('-b', metavar="build directories", action='append', default=[], + help="Build directory to generate dependencies for " + "if files don't exist at the exact path specified. " + "Multiple build directories may be specified.") + parser.add_argument('files', metavar='file', nargs='+', + help="An assembly file to generate dependencies for.") + + args = parser.parse_args(argv) + + for path, dependencies in dependencies_in(args.files, args.b).items(): + # It seems that if A depends on B which depends on C, and + # C is modified, Make needs you to change the modification + # time of B too. That's the reason for the "@touch $@". + # This does mean mtimes on .asm files are updated when building, + # but the alternative opens up a whole can of problems. + if dependencies: + print("{}: {}\n\t@touch $@".format(path, ' '.join(dependencies))) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/tools/tests/charmap.asm b/tools/tests/charmap.asm index 228bb6b..70e228c 100644 --- a/tools/tests/charmap.asm +++ b/tools/tests/charmap.asm @@ -101,7 +101,7 @@ charmap "<RIVAL>", $53 ; wRivalName charmap "#", $54 ; "POKé" charmap "<CONT>", $55 - charmap "<……>", $56 ; "……" + charmap "<⋯⋯>", $56 ; "⋯⋯" charmap "<DONE>", $57 charmap "<PROMPT>", $58 charmap "<TARGET>", $59 @@ -137,7 +137,7 @@ charmap "『", $72 charmap "』", $73 charmap "・", $74 - charmap "…", $75 + charmap "⋯", $75 charmap "ぁ", $76 charmap "ぇ", $77 |
