aboutsummaryrefslogtreecommitdiff
path: root/libpsn00b/psxapi/generate_stubs.py
diff options
context:
space:
mode:
authorJohn "Lameguy" Wilbert Villamor <lameguy64@gmail.com>2022-03-25 09:22:20 +0800
committerGitHub <noreply@github.com>2022-03-25 09:22:20 +0800
commit975e614b3c840e2f717adac1d1cb9cee4e5e561b (patch)
tree6584ce5b0dbe27a466c95c81fac61b0d90f627bd /libpsn00b/psxapi/generate_stubs.py
parent05d44488bd5587786f4bd0286fc0f555c79aa46a (diff)
parent45168ae43e29aa5930ee5a206475ae836078915f (diff)
downloadpsn00bsdk-975e614b3c840e2f717adac1d1cb9cee4e5e561b.tar.gz
Merge pull request #46 from spicyjpeg/psxmdec
Critical ldscript fixes, initial MDEC support and CI updates
Diffstat (limited to 'libpsn00b/psxapi/generate_stubs.py')
-rw-r--r--libpsn00b/psxapi/generate_stubs.py129
1 files changed, 129 insertions, 0 deletions
diff --git a/libpsn00b/psxapi/generate_stubs.py b/libpsn00b/psxapi/generate_stubs.py
new file mode 100644
index 0000000..9db60de
--- /dev/null
+++ b/libpsn00b/psxapi/generate_stubs.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+# PSn00bSDK BIOS stub generator
+# (C) 2022 spicyjpeg - MPL licensed
+
+import os, sys, json
+from argparse import ArgumentParser, FileType
+
+## Listing section generation
+
+SECTION_TEMPLATE = """## {title} ({count})
+
+{body}"""
+FUNCTION_TEMPLATE = """.section .text.{name}
+.global {name}
+.type {name}, @function
+{name}:
+ li $t2, 0x{address:02x}
+ jr $t2
+ li $t1, 0x{id:02x}
+
+"""
+SYSCALL_TEMPLATE = """.section .text.{name}
+.global {name}
+.type {name}, @function
+{name}:
+ li $a0, 0x{id:02x}
+ syscall 0
+ jr $ra
+ nop
+
+"""
+
+STUB_TYPES = {
+ "a": ( 0xa0, FUNCTION_TEMPLATE, "A0 table functions" ),
+ "b": ( 0xb0, FUNCTION_TEMPLATE, "B0 table functions" ),
+ "c": ( 0xc0, FUNCTION_TEMPLATE, "C0 table functions" ),
+ "syscall": ( 0x00, SYSCALL_TEMPLATE, "Syscalls" )
+}
+
+def generate_section(_type, entries):
+ address, template, title = STUB_TYPES[_type]
+ body = ""
+
+ for entry in entries:
+ if entry.get("comment", None):
+ body += f"# {entry['comment'].strip()}\n"
+
+ body += template.format(
+ name = entry["name"].strip(),
+ address = address,
+ id = entry["id"]
+ )
+
+ return SECTION_TEMPLATE.format(
+ title = title,
+ count = len(entries),
+ body = body
+ )
+
+## Main
+
+HEADER_TEMPLATE = """# PSn00bSDK BIOS API stubs
+# (C) 2022 spicyjpeg - MPL licensed
+
+# This file has been generated automatically. Each function is placed in its
+# own section to allow the linker to strip unused functions.
+
+.set noreorder
+
+"""
+
+def get_args():
+ parser = ArgumentParser(
+ description = "Generates MIPS assembly listings of BIOS API stubs."
+ )
+ parser.add_argument(
+ "json_list",
+ type = FileType("rt"),
+ help = "path to JSON list of stubs to generate"
+ )
+ parser.add_argument(
+ "-o", "--output",
+ type = str,
+ default = os.curdir,
+ help = "where to save generated files (current directory by default)",
+ metavar = "directory"
+ )
+
+ return parser.parse_args()
+
+def main():
+ args = get_args()
+
+ with args.json_list as _file:
+ all_entries = json.load(_file)
+
+ # { file: { type: [ entry, ... ], ... }, ... }
+ files = {}
+
+ # Sort all functions by the file they are going to be put in, and by the
+ # type within the file.
+ for entry in all_entries:
+ _type = entry["type"].strip().lower()
+ _file = entry["file"].strip()
+
+ if type(entry["id"]) is str:
+ entry["id"] = int(entry["id"], 0)
+
+ if _file not in files:
+ files[_file] = { _type: [] for _type in STUB_TYPES.keys() }
+
+ files[_file][_type].append(entry)
+
+ for path, types in files.items():
+ full_path = os.path.normpath(os.path.join(args.output, path))
+ listing = HEADER_TEMPLATE
+
+ for _type, entries in types.items():
+ if not entries:
+ continue
+
+ entries.sort(key = lambda entry: entry["id"])
+ listing += generate_section(_type, entries)
+
+ with open(full_path, "wt", newline = "\n") as _file:
+ _file.write(listing)
+
+if __name__ == "__main__":
+ main()