summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/Makefile3
-rw-r--r--tools/disasm_coverage.py41
-rw-r--r--tools/make_shim.c179
-rw-r--r--tools/scan_includes.py82
-rw-r--r--tools/tests/charmap.asm4
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