Previously, ast transformations were performed informally as ad-hoc modifications to the generated C source code. In this commit, the same transformations are performed by rewriting the ast prior to code generation time. The most significant new transformer is transform_assignment_list. This transforms assignments such as: a, b, c = f(b, c, d) To: a = f(&b, &c, d) The former syntax is used frequently in the manual's description of FPU-related instructions.
110 lines
3.6 KiB
Python
110 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
|
|
|
|
from disabled_instructions import disabled_instructions
|
|
|
|
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 = []
|
|
|
|
for ins in untabulate_instructions_sh4():
|
|
if ins.instruction in disabled_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()
|