mirror of
https://github.com/pound-emu/ballistic.git
synced 2026-01-31 01:15:21 +01:00
decoder/tools: Made python script more user-friendly
- Added default values for input/output directories - Improve error handling for missing cli arguments Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
/*
|
||||
*GENERATED FILE - DO NOT EDIT
|
||||
*Generated with tools/generate_a64_table.py
|
||||
*/
|
||||
|
||||
/* Generated 2807 instructions */
|
||||
#include "decoder_table_gen.h"
|
||||
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/* Generated header file */
|
||||
/*
|
||||
*GENERATED FILE - DO NOT EDIT
|
||||
*Generated with tools/generate_a64_table.py
|
||||
*/
|
||||
|
||||
#include "decoder.h"
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
"""
|
||||
If you're in the same directory where this script is located you will be able
|
||||
to run it without passing any parameters:
|
||||
|
||||
$ python3 generate_a64_table.py
|
||||
Using default XML directory: ../spec/arm64_xml/
|
||||
Using default output directory: ../src/
|
||||
Found 2038 XML files
|
||||
Generated ARM decoder table header file -> ../src/decoder_table_gen.h
|
||||
Generated ARM decoder table source file -> ../src/decoder_table_gen.c
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
@@ -6,10 +18,21 @@ import xml.etree.ElementTree as ET
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
DEFAULT_XML_DIRECTORY_PATH = "../spec/arm64_xml"
|
||||
DEFAULT_GENERATED_TABLE_C_PATH = "../src/decoder_table_gen.c"
|
||||
DEFAULT_GENERATED_TABLE_H_PATH = "../src/decoder_table_gen.h"
|
||||
DEFAULT_DECODER_GENERATED_HEADER_NAME = "decoder_table_gen.h"
|
||||
DEFAULT_DECODER_GENERATED_SOURCE_NAME = "decoder_table_gen.c"
|
||||
DEFAULT_OUTPUT_DIRECTORY = "../src/"
|
||||
|
||||
DEFAULT_XML_DIRECTORY_PATH = "../spec/arm64_xml/"
|
||||
|
||||
DECODER_HEADER_NAME = "decoder.h"
|
||||
DECODER_ARM64_INSTRUCTIONS_SIZE_NAME = "BAL_DECODER_ARM64_INSTRUCTIONS_SIZE"
|
||||
DECODER_ARM64_GLOBAL_INSTRUCTIONS_ARRAY_NAME = "g_bal_decoder_arm64_instructions"
|
||||
DECODER_STRUCT_NAME = "bal_decoder_instruction_metadata_t"
|
||||
|
||||
GENERATED_FILE_WARNING = """/*
|
||||
*GENERATED FILE - DO NOT EDIT
|
||||
*Generated with tools/generate_a64_table.py
|
||||
*/"""
|
||||
|
||||
@dataclass
|
||||
class A64Instruction:
|
||||
@@ -28,7 +51,7 @@ def process_box(
|
||||
hibit = int(box.attrib.get("hibit"))
|
||||
# The width of this bitfield.
|
||||
width = int(box.attrib.get("width", "1"))
|
||||
except ValueError:
|
||||
except TypeError:
|
||||
return (current_mask, current_value)
|
||||
|
||||
if hibit >= 32:
|
||||
@@ -100,6 +123,7 @@ def parse_xml_file(filepath: str) -> List[A64Instruction]:
|
||||
|
||||
# Extract mask and value.
|
||||
for iclass in root.findall(".//iclass"):
|
||||
|
||||
# The diagram box contains the bit definitions.
|
||||
box_diagram = iclass.find("regdiagram")
|
||||
if box_diagram is None:
|
||||
@@ -169,29 +193,60 @@ def parse_xml_file(filepath: str) -> List[A64Instruction]:
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Generate ARM64 Decoder Tables")
|
||||
parser.add_argument("--directory")
|
||||
parser.add_argument("--output_header")
|
||||
parser.add_argument("--output_source")
|
||||
parser.add_argument("--xml-directory", help="Directory containing the ARM XML files")
|
||||
parser.add_argument("--output-directory", help="Directory to store the generated files")
|
||||
parser.add_argument("--output-header", help="Name of the generated header file")
|
||||
parser.add_argument("--output-source", help="Name of the generated source file")
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# CLI Arg Parsing
|
||||
# -------------------------------------------------------------------------
|
||||
args = parser.parse_args()
|
||||
|
||||
xml_directory: str = DEFAULT_XML_DIRECTORY_PATH
|
||||
if args.directory is not None:
|
||||
xml_directory = args.directory
|
||||
if args.xml_directory is not None:
|
||||
xml_directory = args.xml_directory
|
||||
else:
|
||||
print(
|
||||
f"XML directory not found, using default directory: {DEFAULT_XML_DIRECTORY_PATH}"
|
||||
)
|
||||
print(f"Using default XML directory: {DEFAULT_XML_DIRECTORY_PATH}")
|
||||
|
||||
if not os.path.exists(xml_directory):
|
||||
print(f"XML path not found at {xml_directory}", file=sys.stderr)
|
||||
print(f"XML directory does not exist: {xml_directory}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
output_directory: str = DEFAULT_OUTPUT_DIRECTORY
|
||||
if args.output_directory is not None:
|
||||
output_directory = args.output_directory
|
||||
else:
|
||||
print(f"Using default output directory: {DEFAULT_OUTPUT_DIRECTORY}")
|
||||
|
||||
if not os.path.exists(output_directory):
|
||||
print(f"Output directory does not exit: {output_directory}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
output_header_path: str = os.path.join(DEFAULT_OUTPUT_DIRECTORY + DEFAULT_DECODER_GENERATED_HEADER_NAME)
|
||||
output_source_path: str = os.path.join(DEFAULT_OUTPUT_DIRECTORY + DEFAULT_DECODER_GENERATED_SOURCE_NAME)
|
||||
if output_directory != DEFAULT_OUTPUT_DIRECTORY:
|
||||
output_header_path = os.path.join(output_directory + DEFAULT_DECODER_GENERATED_HEADER_NAME)
|
||||
output_source_path = os.path.join(output_directory + DEFAULT_DECODER_GENERATED_SOURCE_NAME)
|
||||
|
||||
if args.output_header is not None:
|
||||
output_header_path = os.path.join(output_directory + args.output_header)
|
||||
|
||||
if args.output_source is not None:
|
||||
output_source_path = os.path.join(output_directory + args.output_source)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Process XML Files
|
||||
# -------------------------------------------------------------------------
|
||||
all_instructions = []
|
||||
files = glob.glob(os.path.join(xml_directory, "*.xml"))
|
||||
if len(files) < 1:
|
||||
print(f"No XML files found in {xml_directory}")
|
||||
sys.exit(1)
|
||||
print(f"Found {len(files)} XML files")
|
||||
|
||||
files_to_ignore: List[str] = [xml_directory + "/onebigfile.xml"]
|
||||
files_to_ignore: List[str] = [os.path.join(xml_directory + "onebigfile.xml")]
|
||||
for f in files:
|
||||
# Skip index and shared pseudo-code files.
|
||||
if "index" in f or "shared" in f:
|
||||
@@ -205,38 +260,36 @@ if __name__ == "__main__":
|
||||
# Sort by priority
|
||||
all_instructions.sort(key=lambda x: x.priority, reverse=True)
|
||||
|
||||
# Generate Header
|
||||
out_file_header = DEFAULT_GENERATED_TABLE_H_PATH
|
||||
if args.output_header is not None:
|
||||
out_file_header = args.output_header
|
||||
|
||||
arm64_instructions_size_name: str = "BAL_DECODER_ARM64_INSTRUCTIONS_SIZE"
|
||||
arm64_global_instructions_array_name: str = "g_bal_decoder_arm64_instructions"
|
||||
|
||||
with open(out_file_header, "w") as f:
|
||||
f.write(f"/* Generated header file */\n")
|
||||
f.write(f'#include "decoder.h"\n')
|
||||
# -------------------------------------------------------------------------
|
||||
# Generate Header File
|
||||
# -------------------------------------------------------------------------
|
||||
with open(output_header_path, "w") as f:
|
||||
f.write(f"{GENERATED_FILE_WARNING}\n\n")
|
||||
f.write(f'#include "{DECODER_HEADER_NAME}"\n')
|
||||
f.write("#include <stdint.h>\n\n")
|
||||
f.write(f"#define {arm64_instructions_size_name} {len(all_instructions)}\n\n")
|
||||
f.write(f"#define {DECODER_ARM64_INSTRUCTIONS_SIZE_NAME} {len(all_instructions)}\n\n")
|
||||
f.write(
|
||||
f"extern const bal_decoder_instruction_metadata_t {arm64_global_instructions_array_name}[{arm64_instructions_size_name}];\n"
|
||||
f"extern const bal_decoder_instruction_metadata_t {DECODER_ARM64_GLOBAL_INSTRUCTIONS_ARRAY_NAME}[{DECODER_ARM64_INSTRUCTIONS_SIZE_NAME}];\n"
|
||||
)
|
||||
print(f"Generated ARM decoder table header file -> {out_file_header}")
|
||||
print(f"Generated ARM decoder table header file -> {output_header_path}")
|
||||
|
||||
# Generate Source
|
||||
out_file_source = DEFAULT_GENERATED_TABLE_C_PATH
|
||||
if args.output_source is not None:
|
||||
out_file_source = args.output_source
|
||||
# -------------------------------------------------------------------------
|
||||
# Generate Source File
|
||||
# -------------------------------------------------------------------------
|
||||
decoder_generated_header_name: str = DEFAULT_DECODER_GENERATED_HEADER_NAME
|
||||
if args.output_header is not None:
|
||||
decoder_generated_header_name = args.output_header
|
||||
|
||||
with open(out_file_source, "w") as f:
|
||||
with open(output_source_path, "w") as f:
|
||||
f.write(f"{GENERATED_FILE_WARNING}\n\n")
|
||||
f.write(f"/* Generated {len(all_instructions)} instructions */\n")
|
||||
f.write(f'#include "decoder_table_gen.h"\n\n')
|
||||
f.write(f'#include "{decoder_generated_header_name}"\n\n')
|
||||
f.write(
|
||||
f"const bal_decoder_instruction_metadata_t {arm64_global_instructions_array_name}[{arm64_instructions_size_name}] = {{\n"
|
||||
f"const bal_decoder_instruction_metadata_t {DECODER_ARM64_GLOBAL_INSTRUCTIONS_ARRAY_NAME}[{DECODER_ARM64_INSTRUCTIONS_SIZE_NAME}] = {{\n"
|
||||
)
|
||||
for inst in all_instructions:
|
||||
f.write(
|
||||
f' {{ "{inst.mnemonic}", 0x{inst.mask:08X}, 0x{inst.value:08X} }}, \n'
|
||||
)
|
||||
f.write("};")
|
||||
print(f"Generated ARM decoder table source file -> {out_file_source}")
|
||||
print(f"Generated ARM decoder table source file -> {output_source_path}")
|
||||
|
||||
Reference in New Issue
Block a user