sh-dis/generate_impl.py
Zack Buhman 3209054b8f decode: implement PR- and SZ- instruction decode discrimination
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.
2024-04-26 18:51:01 +08:00

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