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 generate_impl import parse_header from generate_impl import read_ins_source 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, discriminators): yield f"switch (code & {b16(mask)}) {{" for ins in instructions: yield f"case {b16(ins.code.code_bits)}: // {ins.instruction} {ins.operands}" yield "{" if (ins.instruction, ins.operands) in discriminators: (variable, value), = discriminators[(ins.instruction, ins.operands)] yield f"if (state->fpscr.bits.{variable} == {value}) {{" 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;" if (ins.instruction, ins.operands) in discriminators: yield "} else break;" yield "}" yield "}" def render_mask_switches(body_func, by_mask, discriminators): 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, discriminators) yield "return DECODE__UNDEFINED;" yield "}" def render_decode_and_execute(by_mask, discriminators): 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, discriminators) def render_decode_and_print(by_mask, discriminators): 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, discriminators) def header_execute(): yield '#include "decode_execute.h"' yield '#include "impl.h"' yield "" def header_print(): yield '#include ' yield "" yield '#include "decode_print.h"' yield "" s = set() def symmetric_available(a): return { 'Available only when SZ=0': 'Available only when PR=0', 'Available only when PR=0': 'Available only when SZ=0', 'Available only when PR=1 and SZ=0': 'Available only when PR=0 and SZ=1', 'Available only when PR=0 and SZ=1': 'Available only when PR=1 and SZ=0', }[a] def parse_available(a): return { 'Available only when PR=1 and SZ=0': {"pr": 1, "sz": 0}, 'Available only when SZ=0' : {"sz": 0}, 'Available only when PR=0' : {"pr": 0}, 'Available only when PR=0 and SZ=1': {"pr": 0, "sz": 1}, }[a] def main(): dup = set() by_instruction_operands = {} table = untabulate_instructions_sh4() for ins1 in table: buf = read_ins_source(ins1) _, available, _ = parse_header(buf) assert (ins1.instruction, ins1.operands) not in by_instruction_operands by_instruction_operands[(ins1.instruction, ins1.operands)] = (ins1, available) for ins2 in table: if ins1 is ins2: continue if ins1.code.code_bits & ins2.code.mask_bits == ins2.code.code_bits: assert (ins1.instruction, ins1.operands) != (ins2.instruction, ins2.operands) dup.add(frozenset([(ins1.instruction, ins1.operands), (ins2.instruction, ins2.operands)])) discriminators = {} for dup1, dup2 in dup: ins1, available1 = by_instruction_operands[dup1] ins2, available2 = by_instruction_operands[dup2] assert available1 is not None and available2 is not None, (dup1, dup2) av1 = parse_available(available1) av2 = parse_available(available2) assert symmetric_available(available1) != available2, (ins1, available1, ins2, available2) intersection = set(av1.keys()) & set(av2.keys()) av1 = tuple((k, v) for k, v in av1.items() if k in intersection) av2 = tuple((k, v) for k, v in av2.items() if k in intersection) assert av1 != av2 discriminators[(ins1.instruction, ins1.operands)] = av1 discriminators[(ins2.instruction, ins2.operands)] = av2 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, discriminators)) 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, discriminators)) with open(sys.argv[2], 'w') as f: f.write(out.getvalue()) if __name__ == "__main__": main()