sh-dis/transform.py
Zack Buhman 8a300ba4c6 initial SH4 emulator implementation in C
This currently only implements the SH2 instructions.
2024-04-22 20:53:36 +08:00

119 lines
3.4 KiB
Python

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()