Some SH4 floating point instructions have ambiguous encodings that depend on the state of FPSCR bits. Exhaustively, these are: FMOV XDm,DRn (sz 1) FMOV FRm,FRn (sz 0) FMOV DRm,@(R0,Rn) (sz 1) FMOV.S FRm,@(R0,Rn) (sz 0) FCMP/EQ DRm,DRn (pr 1) FCMP/EQ FRm,FRn (pr 0) FMOV @Rm+,XDn (sz 1) FMOV.S @Rm+,FRn (sz 0) FMOV XDm,@(R0,Rn) (sz 1) FMOV.S FRm,@(R0,Rn) (sz 0) FMUL DRm,DRn (pr 1) FMUL FRm,FRn (pr 0) FMOV.S @Rm+,FRn (sz 0) FMOV @Rm+,DRn (sz 1) FLOAT FPUL,DRn (pr 1) FLOAT FPUL,FRn (pr 0) FNEG DRn (pr 1) FNEG FRn (pr 0) FTRC DRm,FPUL (pr 1) FTRC FRm,FPUL (pr 0) FMOV.S @(R0,Rm),FRn (sz 0) FMOV @(R0,Rm),DRn (sz 1) FMOV.S @Rm,FRn (sz 0) FMOV @Rm,DRn (sz 1) FMOV XDm,XDn (sz 1) FMOV FRm,FRn (sz 0) FABS FRn (pr 0) FABS DRn (pr 1) FMOV.S FRm,@Rn (sz 0) FMOV DRm,@Rn (sz 1) FSUB DRm,DRn (pr 1) FSUB FRm,FRn (pr 0) FDIV DRm,DRn (pr 1) FDIV FRm,FRn (pr 0) FCMP/GT DRm,DRn (pr 1) FCMP/GT FRm,FRn (pr 0) FMOV DRm,DRn (sz 1) FMOV FRm,FRn (sz 0) FMOV.S FRm,@-Rn (sz 0) FMOV DRm,@-Rn (sz 1) FADD DRm,DRn (pr 1) FADD FRm,FRn (pr 0) FMOV.S FRm,@Rn (sz 0) FMOV XDm,@Rn (sz 1) FMOV.S @(R0,Rm),FRn (sz 0) FMOV @(R0,Rm),XDn (sz 1) FMOV DRm,XDn (sz 1) FMOV FRm,FRn (sz 0) FMOV XDm,@-Rn (sz 1) FMOV.S FRm,@-Rn (sz 0) FSQRT DRn (pr 1) FSQRT FRn (pr 0) FMOV.S @Rm,FRn (sz 0) FMOV @Rm,XDn (sz 1) This commit automatically calculates which FPU instructions require FPSCR-discrimination, and automatically inserts the appropriate conditional logic in the instruction decoder.
129 lines
3.7 KiB
Python
129 lines
3.7 KiB
Python
import sys
|
|
import os
|
|
|
|
from lexer import Lexer
|
|
from parser import Parser
|
|
from ast_to_c_source import generate
|
|
from ast_transformers import transform_statements
|
|
|
|
from instruction_table import untabulate_instructions_sh4
|
|
from instruction_table import untabulate_instructions_sh2
|
|
from instruction_table import unparse_instruction_code
|
|
from instruction_function_name import instruction_function_name
|
|
from instruction_file_name import instruction_file_name
|
|
from instruction_properties import has_delay_slot
|
|
|
|
from disabled_instructions import disabled_instructions
|
|
|
|
def is_instruction_descriptor(s):
|
|
return all(c in {'0', '1', 'n', 'm', 'i', 'd'} for c in s)
|
|
|
|
def parse_header(buf):
|
|
lines = buf.split('\n')
|
|
code, available, *rest = lines
|
|
assert len(code) == 16 and is_instruction_descriptor(lines[0]), lines[0]
|
|
if not available.startswith('Available only when'):
|
|
return code, None, '\n'.join([available, *rest])
|
|
else:
|
|
return code, available, '\n'.join(rest)
|
|
|
|
def read_ins_source(ins):
|
|
file_name = instruction_file_name(ins)
|
|
src_path = os.path.join("sh4", file_name)
|
|
with open(src_path) as f:
|
|
return f.read()
|
|
|
|
def parse_tokens(buf):
|
|
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, ins, delay_slot):
|
|
buf = read_ins_source(ins)
|
|
code, _available, source = parse_header(buf)
|
|
assert code == unparse_instruction_code(ins), (code, unparse_instruction_code(ins))
|
|
|
|
tokens = list(parse_tokens(source))
|
|
parser = Parser(tokens)
|
|
statements = []
|
|
while parser.tokens[parser.pos:]:
|
|
statements.append(parser.statement())
|
|
|
|
statements = transform_statements(statements)
|
|
|
|
yield from generate_function_declaration(instruction_name, function_name, ins.variables)
|
|
yield "{"
|
|
output = []
|
|
for statement in statements:
|
|
src = "".join(generate(statement))
|
|
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"',
|
|
'#include "fpu.h"',
|
|
'',
|
|
]
|
|
|
|
header_output = [
|
|
'#pragma once',
|
|
'',
|
|
'#include "state.h"',
|
|
'#include "memory_map.h"',
|
|
'',
|
|
]
|
|
|
|
for ins in untabulate_instructions_sh4():
|
|
if ins.instruction in disabled_instructions:
|
|
continue
|
|
|
|
_name = [ins.instruction, ins.operands] if ins.operands else [ins.instruction]
|
|
instruction_name = " ".join(_name)
|
|
function_name = instruction_function_name(ins)
|
|
delay_slot = "true" if has_delay_slot(ins) else "false"
|
|
gen = generate_file(instruction_name, function_name, ins, delay_slot)
|
|
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()
|