sh-dis/generate_decoder.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

109 lines
3.6 KiB
Python

import sys
from collections import defaultdict
from instruction_table import untabulate_instructions_sh4
from instruction_table import untabulate_instructions_sh2
from instruction_function_name import instruction_function_name
from generate import renderer
def b16(n):
bits = []
for i in range(16):
bits.append((n >> i) & 1)
return '0b' + ''.join(map(str, reversed(bits)))
def format_variables(ins):
s = ins.operands
for i, name in enumerate(ins.variables):
if 'disp' in s and name == 'd':
name = 'disp'
if 'imm' in s and name == 'i':
name = 'imm'
if 'label' in s and name == 'd':
name = 'label'
s = s.replace(name, "%d")
return s
def render_print(ins):
variable_args = ", " + ", ".join(ins.variables) if ins.variables else ""
operands = format_variables(ins)
if operands:
yield f'snprintf(operand_buf, size, "{operands}"{variable_args});'
else:
yield "operand_buf[0] = 0;";
yield f'*instruction_buf = "{ins.instruction}";'
def render_execute(ins):
function_name = instruction_function_name(ins)
variable_args = ", " + ", ".join(ins.variables) if ins.variables else ""
yield f"{function_name}(state, map{variable_args});"
def render_mask_switch(body_func, mask, instructions):
yield f"switch (code & {b16(mask)}) {{"
for ins in instructions:
yield f"case {b16(ins.code.code_bits)}: // {ins.instruction} {ins.operands}"
yield "{"
for variable in ins.variables:
operand_var = ins.code.operands[variable]
yield f"uint32_t {variable} = (code >> {operand_var.lsb}) & ((1 << {operand_var.length}) - 1);"
yield from body_func(ins)
yield f"return DECODE__DEFINED;"
yield "}"
yield "}"
def render_mask_switches(body_func, by_mask):
yield "{"
for mask, instructions in by_mask.items():
instructions = sorted(instructions, key=lambda i: i.code.code_bits)
yield from render_mask_switch(body_func, mask, instructions)
yield "return DECODE__UNDEFINED;"
yield "}"
def render_decode_and_execute(by_mask):
yield f"enum decode_status decode_and_execute_instruction(struct architectural_state * state, struct memory_map * map, uint16_t code)"
yield from render_mask_switches(render_execute, by_mask)
def render_decode_and_print(by_mask):
yield f"enum decode_status decode_and_print_instruction(struct architectural_state * state, struct memory_map * map, uint16_t code, char const ** instruction_buf, char * operand_buf, uint32_t size)"
yield from render_mask_switches(render_print, by_mask)
def header_execute():
yield '#include "decode_execute.h"'
yield '#include "impl.h"'
yield ""
def header_print():
yield '#include <stdio.h>'
yield ""
yield '#include "decode_print.h"'
yield ""
def main():
by_mask = defaultdict(list)
masks = []
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
if ins.code.mask_bits not in masks:
masks.append(ins.code.mask_bits)
by_mask[ins.code.mask_bits].append(ins)
render, out = renderer()
render(header_execute())
render(render_decode_and_execute(by_mask))
with open(sys.argv[1], 'w') as f:
f.write(out.getvalue())
render, out = renderer()
render(header_print())
render(render_decode_and_print(by_mask))
with open(sys.argv[2], 'w') as f:
f.write(out.getvalue())
if __name__ == "__main__":
main()