import sys import os from lexer import Lexer from parser import Parser from ast_to_c_source import generate from ast_transformers import transform_statements from instruction_table import untabulate_instructions_sh4 from instruction_table import untabulate_instructions_sh2 from instruction_table import unparse_instruction_code from instruction_function_name import instruction_function_name from instruction_file_name import instruction_file_name from instruction_properties import has_delay_slot from disabled_instructions import disabled_instructions def is_instruction_descriptor(s): return all(c in {'0', '1', 'n', 'm', 'i', 'd'} for c in s) def parse_header(buf): lines = buf.split('\n') code, available, *rest = lines assert len(code) == 16 and is_instruction_descriptor(lines[0]), lines[0] if not available.startswith('Available only when'): return code, None, '\n'.join([available, *rest]) else: return code, available, '\n'.join(rest) def read_ins_source(ins): file_name = instruction_file_name(ins) src_path = os.path.join("sh4", file_name) with open(src_path) as f: return f.read() def parse_tokens(buf): lexer = Lexer(buf) while True: try: token = lexer.next_token() except IndexError: break yield token def generate_function_declaration(instruction_name, function_name, variables): args = ", ".join([ "struct architectural_state * state", "struct memory_map * map", *[ f"const uint32_t {x}" for x in variables ] ]) yield f"/* {instruction_name} */" yield f"void {function_name}({args})" def generate_file(instruction_name, function_name, ins, delay_slot): buf = read_ins_source(ins) code, _available, source = parse_header(buf) assert code == unparse_instruction_code(ins), (code, unparse_instruction_code(ins)) tokens = list(parse_tokens(source)) parser = Parser(tokens) statements = [] while parser.tokens[parser.pos:]: statements.append(parser.statement()) statements = transform_statements(statements) yield from generate_function_declaration(instruction_name, function_name, ins.variables) yield "{" output = [] for statement in statements: src = "".join(generate(statement)) output.append(src) for line in "".join(output).rstrip().split('\n'): yield f" {line}" yield "" yield f" state->is_delay_slot = {delay_slot};" yield "}" yield "" yield "" def main(): output = [ '#include "impl.h"', '#include "operations.h"', '#include "exception.h"', '#include "state_helpers.h"', '#include "fpu.h"', '', ] header_output = [ '#pragma once', '', '#include "state.h"', '#include "memory_map.h"', '', ] for ins in untabulate_instructions_sh4(): if ins.instruction in disabled_instructions: continue _name = [ins.instruction, ins.operands] if ins.operands else [ins.instruction] instruction_name = " ".join(_name) function_name = instruction_function_name(ins) delay_slot = "true" if has_delay_slot(ins) else "false" gen = generate_file(instruction_name, function_name, ins, delay_slot) output.extend(gen) gen = generate_function_declaration(instruction_name, function_name, ins.variables) lgen = list(gen) lgen[-1] += ';' header_output.extend(lgen) with open(sys.argv[1], "w") as f: f.write("\n".join(output)) with open(sys.argv[2], "w") as f: f.write("\n".join(header_output)) if __name__ == '__main__': main()