diff --git a/tools/free_space.awk b/tools/free_space.awk deleted file mode 100755 index 1f2b04415..000000000 --- a/tools/free_space.awk +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/awk -f - -# Usage: tools/free_space.awk pokecrystal.map - -BEGIN { - total = free = 16384 * 128 -} -/^ SECTION: \$[0-7]/ { - free -= strtonum("0x" substr($3, 3)) -} -END { - printf "Free space: %d/%d (%.2f%%)\n", free, total, free * 100 / total -} diff --git a/tools/free_space.py b/tools/free_space.py new file mode 100644 index 000000000..4df8aec9d --- /dev/null +++ b/tools/free_space.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Usage: python3 free_space.py [BANK=none] [pokecrystal.map] + +Calculate the free space in the ROM or its individual banks. + +The BANK argument allows printing free space in one, all, or none of the ROM's banks. +Valid arguments are numbers (in decimal "42" or hexadecimal "0x2A"), "all" or "none". +If not specified, defaults to "none". +""" + +import sys + +from mapreader import MapReader + +def main(): + print_bank = 'none' + mapfile = 'pokecrystal.map' + + if len(sys.argv) >= 2 and sys.argv[1].startswith('BANK='): + print_bank = sys.argv[1].split('=', 1)[-1] + if len(sys.argv) >= 3: + mapfile = sys.argv[2] + elif len(sys.argv) >= 3 and sys.argv[2].startswith('BANK='): + print_bank = sys.argv[2].split('=', 1)[-1] + mapfile = sys.argv[1] + + if print_bank not in {'all', 'none'}: + try: + if print_bank.startswith('0x') or print_bank.startswith('0X'): + print_bank = int(print_bank[2:], 16) + else: + print_bank = int(print_bank) + except ValueError: + error = 'Error: invalid BANK: %s' % print_bank + if print_bank.isalnum(): + error += ' (did you mean: 0x%s?)' % print_bank + print(error, file=sys.stderr) + sys.exit(1) + + num_banks = 0x80 + bank_size = 0x4000 # bytes + total_size = num_banks * bank_size + + r = MapReader() + with open(mapfile, 'r', encoding='utf-8') as f: + l = f.readlines() + r.read_map_data(l) + + free_space = 0 + per_bank = [] + default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size} + for bank in range(num_banks): + bank_data = r.bank_data['ROM0 bank'] if bank == 0 else r.bank_data['ROMX bank'] + data = bank_data.get(bank, default_bank_data) + used = data['used'] + slack = data['slack'] + per_bank.append((used, slack)) + free_space += slack + + print('Free space: %d/%d (%.2f%%)' % (free_space, total_size, free_space * 100.0 / total_size)) + if print_bank != 'none': + print() + print('bank, used, free') + for bank in range(num_banks): + used, slack = per_bank[bank] + if print_bank in {'all', bank}: + print('$%02X, %d, %d' % (bank, used, slack)) + +if __name__ == '__main__': + main()