import sys import os from lexer import Lexer from parser import Parser from generator import generate, CTX from instruction_table import untabulate_instructions_sh4 from instruction_table import untabulate_instructions_sh2 from instruction_function_name import instruction_function_name from instruction_file_name import instruction_file_name from instruction_properties import has_delay_slot def is_instruction_descriptor(s): return all(c in {'0', '1', 'n', 'm', 'i', 'd'} for c in s) def parse_file(path): with open(path) as f: buf = f.read() lines = buf.split('\n', maxsplit=2) assert len(lines[0]) == 16 and is_instruction_descriptor(lines[0]), lines[0] if lines[1].startswith('Available only when'): buf = lines[2] else: if len(lines) >= 3: buf = '\n'.join([lines[1], lines[2]]) else: buf = lines[1] 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, variables, delay_slot, src_path): tokens = list(parse_file(src_path)) parser = Parser(tokens) ctx = CTX(identifiers=set()) yield from generate_function_declaration(instruction_name, function_name, variables) yield "{" output = [] while parser.tokens[parser.pos:]: stmt = parser.statement() src = "".join(generate(ctx, stmt)) 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"', '', ] header_output = [ '#pragma once', '', '#include "state.h"', '#include "memory_map.h"', '', ] sh2_instructions = set((ins.instruction, ins.operands) for ins in untabulate_instructions_sh2()) for ins in untabulate_instructions_sh4(): if (ins.instruction, ins.operands) not in sh2_instructions: continue _name = [ins.instruction, ins.operands] if ins.operands else [ins.instruction] instruction_name = " ".join(_name) function_name = instruction_function_name(ins) file_name = instruction_file_name(ins) src_path = os.path.join("sh4", file_name) delay_slot = "true" if has_delay_slot(ins) else "false" gen = generate_file(instruction_name, function_name, ins.variables, delay_slot, src_path) 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()