mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-09-09 09:51:34 -07:00
dump_sections - tool to dump a skeleton asm file
This commit is contained in:
parent
9a29def250
commit
eb6cb9812d
14
extras/dump_sections
Executable file
14
extras/dump_sections
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# This wraps dump_sections.py so that other python scripts can import the
|
||||
# functions. If dump_sections.py was instead called dump_sections, then other
|
||||
# python source code would be unable to use the functions via import
|
||||
# statements.
|
||||
|
||||
# figure out the path to this script
|
||||
cwd="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
# construct the path to dump_sections.py
|
||||
secpath=$cwd/dump_sections.py
|
||||
|
||||
# run dump_sections.py
|
||||
$secpath $1
|
130
extras/dump_sections.py
Executable file
130
extras/dump_sections.py
Executable file
@ -0,0 +1,130 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Use this tool to dump an asm file for a new source code or disassembly project.
|
||||
|
||||
usage:
|
||||
|
||||
from dump_sections import dump_sections
|
||||
|
||||
output = dump_sections("../../butt.gbc")
|
||||
|
||||
file_handler = open("main.asm", "w")
|
||||
file_handler.write(output)
|
||||
file_handler.close()
|
||||
|
||||
You can also use this script from the shell, where it will look for
|
||||
"baserom.gbc" in the current working path or whatever file path you pass in the
|
||||
first positional argument.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
def upper_hex(input):
|
||||
"""
|
||||
Converts the input to an uppercase hex string.
|
||||
"""
|
||||
if input in [0, "0"]:
|
||||
return "0"
|
||||
elif input <= 0xF:
|
||||
return ("%.x" % (input)).upper()
|
||||
else:
|
||||
return ("%.2x" % (input)).upper()
|
||||
|
||||
def format_bank_number(address, bank_size=0x4000):
|
||||
"""
|
||||
Returns a str of the hex number of the bank based on the address.
|
||||
"""
|
||||
return upper_hex(address / bank_size)
|
||||
|
||||
def calculate_bank_quantity(path, bank_size=0x4000):
|
||||
"""
|
||||
Returns the number of 0x4000 banks in the file at path.
|
||||
"""
|
||||
return float(os.lstat(path).st_size) / bank_size
|
||||
|
||||
def dump_section(bank_number, separator="\n\n"):
|
||||
"""
|
||||
Returns a str of a section header for the asm file.
|
||||
"""
|
||||
output = "SECTION \""
|
||||
if bank_number in [0, "0"]:
|
||||
output += "bank0\",HOME"
|
||||
else:
|
||||
output += "bank"
|
||||
output += bank_number
|
||||
output += "\",DATA,BANK[$"
|
||||
output += bank_number
|
||||
output += "]"
|
||||
output += separator
|
||||
return output
|
||||
|
||||
def dump_incbin_for_section(address, bank_size=0x4000, baserom="baserom.gbc", separator="\n\n"):
|
||||
"""
|
||||
Returns a str for an INCBIN line for an entire section.
|
||||
"""
|
||||
output = "INCBIN \""
|
||||
output += baserom
|
||||
output += "\",$"
|
||||
output += upper_hex(address)
|
||||
output += ",$"
|
||||
output += upper_hex(bank_size)
|
||||
output += separator
|
||||
return output
|
||||
|
||||
def dump_sections(path, bank_size=0x4000, initial_bank=0, last_bank=None, separator="\n\n"):
|
||||
"""
|
||||
Returns a str of assembly source code. The source code delineates each
|
||||
SECTION and includes bytes from the file specified by baserom.
|
||||
"""
|
||||
if not last_bank:
|
||||
last_bank = calculate_bank_quantity(path, bank_size=bank_size)
|
||||
|
||||
if last_bank < initial_bank:
|
||||
raise Exception("last_bank must be greater than or equal to initial_bank")
|
||||
|
||||
baserom_name = os.path.basename(path)
|
||||
|
||||
output = ""
|
||||
|
||||
banks = range(initial_bank, last_bank)
|
||||
|
||||
for bank_number in banks:
|
||||
address = bank_number * bank_size
|
||||
|
||||
# get a formatted hex number of the bank based on the address
|
||||
formatted_bank_number = format_bank_number(address, bank_size=bank_size)
|
||||
|
||||
# SECTION
|
||||
output += dump_section(formatted_bank_number, separator=separator)
|
||||
|
||||
# INCBIN a range of bytes from the ROM
|
||||
output += dump_incbin_for_section(address, bank_size=bank_size, baserom=baserom_name, separator=separator)
|
||||
|
||||
# clean up newlines at the end of the output
|
||||
if output[-2:] == "\n\n":
|
||||
output = output[:-2]
|
||||
output += "\n"
|
||||
|
||||
return output
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("rompath", nargs="?", metavar="rompath", type=str)
|
||||
args = parser.parse_args()
|
||||
|
||||
# default to "baserom.gbc" in the current working directory
|
||||
baserom = "baserom.gbc"
|
||||
|
||||
# but let the user override the default
|
||||
if args.rompath:
|
||||
baserom = args.rompath
|
||||
|
||||
# generate some asm
|
||||
output = dump_sections(baserom)
|
||||
|
||||
# dump everything to stdout
|
||||
sys.stdout.write(output)
|
||||
|
74
extras/test_dump_sections.py
Normal file
74
extras/test_dump_sections.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest
|
||||
|
||||
# check for things we need in unittest
|
||||
if not hasattr(unittest.TestCase, 'setUpClass'):
|
||||
sys.stderr.write("The unittest2 module or Python 2.7 is required to run this script.")
|
||||
sys.exit(1)
|
||||
|
||||
from dump_sections import (
|
||||
upper_hex,
|
||||
format_bank_number,
|
||||
calculate_bank_quantity,
|
||||
dump_section,
|
||||
dump_incbin_for_section,
|
||||
)
|
||||
|
||||
class TestDumpSections(unittest.TestCase):
|
||||
def test_upper_hex(self):
|
||||
number = 0x52
|
||||
self.assertEquals(number, int("0x" + upper_hex(number), 16))
|
||||
|
||||
number = 0x1
|
||||
self.assertEquals(number, int("0x" + upper_hex(number), 16))
|
||||
|
||||
number = 0x0
|
||||
self.assertEquals(number, int("0x" + upper_hex(number), 16))
|
||||
|
||||
number = 0xAA
|
||||
self.assertEquals(number, int("0x" + upper_hex(number), 16))
|
||||
|
||||
number = 0xFFFFAAA0000
|
||||
self.assertEquals(number, int("0x" + upper_hex(number), 16))
|
||||
|
||||
def test_format_bank_number(self):
|
||||
address = 0x0
|
||||
self.assertEquals("0", format_bank_number(address))
|
||||
|
||||
address = 0x4000
|
||||
self.assertEquals("1", format_bank_number(address))
|
||||
|
||||
address = 0x1FC000
|
||||
self.assertEquals("7F", format_bank_number(address))
|
||||
|
||||
def test_dump_section(self):
|
||||
self.assertIn("SECTION", dump_section(str(0)))
|
||||
self.assertIn("HOME", dump_section(str(0)))
|
||||
self.assertNotIn("HOME", dump_section(str(1)))
|
||||
self.assertIn("DATA", dump_section(str(2)))
|
||||
self.assertIn("BANK", dump_section(str(40)))
|
||||
self.assertNotIn("BANK", dump_section(str(0)))
|
||||
|
||||
def test_dump_incbin_for_section(self):
|
||||
self.assertIn("INCBIN", dump_incbin_for_section(0))
|
||||
|
||||
def test_dump_incbin_for_section_separator(self):
|
||||
separator = "\n\n"
|
||||
self.assertIn(separator, dump_incbin_for_section(0, separator=separator))
|
||||
|
||||
separator = "\t\t" # dumb
|
||||
self.assertIn(separator, dump_incbin_for_section(0, separator=separator))
|
||||
|
||||
def test_dump_incbin_for_section_default(self):
|
||||
rom = "baserom.gbc"
|
||||
self.assertIn(rom, dump_incbin_for_section(0))
|
||||
|
||||
rom = "baserom"
|
||||
self.assertIn(rom, dump_incbin_for_section(0x4000))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Loading…
Reference in New Issue
Block a user