Hexagon (target/hexagon) Use QEMU decodetree (16-bit instructions)
Section 10.3 of the Hexagon V73 Programmer's Reference Manual A duplex is encoded as a 32-bit instruction with bits [15:14] set to 00. The sub-instructions that comprise a duplex are encoded as 13-bit fields in the duplex. Create a decoder for each subinstruction class (a, l1, l2, s1, s2). Extend gen_trans_funcs.py to handle all instructions rather than filter by instruction class. There is a g_assert_not_reached() in decode_insns() in decode.c to verify we never try to use the old decoder on 16-bit instructions. Signed-off-by: Taylor Simpson <ltaylorsimpson@gmail.com> Reviewed-by: Brian Cain <bcain@quicinc.com> Message-Id: <20240115221443.365287-3-ltaylorsimpson@gmail.com> Signed-off-by: Brian Cain <bcain@quicinc.com>
This commit is contained in:
parent
1547a2d339
commit
f6c01009b5
@ -195,6 +195,7 @@ Step 1 is to run target/hexagon/gen_dectree_import.c to produce
|
||||
Step 2 is to import iset.py into target/hexagon/gen_decodetree.py to produce
|
||||
<BUILD_DIR>/target/hexagon/normal_decode_generated
|
||||
<BUILD_DIR>/target/hexagon/hvx_decode_generated
|
||||
<BUILD_DIR>/target/hexagon/subinsn_*_decode_generated
|
||||
Step 3 is to process the above files with QEMU's decodetree.py to produce
|
||||
<BUILD_DIR>/target/hexagon/decode_*_generated.c.inc
|
||||
Step 4 is to import iset.py into target/hexagon/gen_trans_funcs.py to produce
|
||||
|
@ -60,6 +60,7 @@ static int decode_mapped_reg_##NAME(DisasContext *ctx, int x) \
|
||||
}
|
||||
DECODE_MAPPED(R_16)
|
||||
DECODE_MAPPED(R_8)
|
||||
DECODE_MAPPED(R__8)
|
||||
|
||||
/* Helper function for decodetree_trans_funcs_generated.c.inc */
|
||||
static int shift_left(DisasContext *ctx, int x, int n, int immno)
|
||||
@ -77,6 +78,13 @@ static int shift_left(DisasContext *ctx, int x, int n, int immno)
|
||||
#include "decode_normal_generated.c.inc"
|
||||
#include "decode_hvx_generated.c.inc"
|
||||
|
||||
/* Include the generated decoder for 16 bit insn */
|
||||
#include "decode_subinsn_a_generated.c.inc"
|
||||
#include "decode_subinsn_l1_generated.c.inc"
|
||||
#include "decode_subinsn_l2_generated.c.inc"
|
||||
#include "decode_subinsn_s1_generated.c.inc"
|
||||
#include "decode_subinsn_s2_generated.c.inc"
|
||||
|
||||
/* Include the generated helpers for the decoder */
|
||||
#include "decodetree_trans_funcs_generated.c.inc"
|
||||
|
||||
@ -790,6 +798,63 @@ decode_insns_tablewalk(Insn *insn, const DectreeTable *table,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Section 10.3 of the Hexagon V73 Programmer's Reference Manual
|
||||
*
|
||||
* A duplex is encoded as a 32-bit instruction with bits [15:14] set to 00.
|
||||
* The sub-instructions that comprise a duplex are encoded as 13-bit fields
|
||||
* in the duplex.
|
||||
*
|
||||
* Per table 10-4, the 4-bit duplex iclass is encoded in bits 31:29, 13
|
||||
*/
|
||||
static uint32_t get_duplex_iclass(uint32_t encoding)
|
||||
{
|
||||
uint32_t iclass = extract32(encoding, 13, 1);
|
||||
iclass = deposit32(iclass, 1, 3, extract32(encoding, 29, 3));
|
||||
return iclass;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per table 10-5, the duplex ICLASS field values that specify the group of
|
||||
* each sub-instruction in a duplex
|
||||
*
|
||||
* This table points to the decode instruction for each entry in the table
|
||||
*/
|
||||
typedef bool (*subinsn_decode_func)(DisasContext *ctx, uint16_t insn);
|
||||
typedef struct {
|
||||
subinsn_decode_func decode_slot0_subinsn;
|
||||
subinsn_decode_func decode_slot1_subinsn;
|
||||
} subinsn_decode_groups;
|
||||
|
||||
static const subinsn_decode_groups decode_groups[16] = {
|
||||
[0x0] = { decode_subinsn_l1, decode_subinsn_l1 },
|
||||
[0x1] = { decode_subinsn_l2, decode_subinsn_l1 },
|
||||
[0x2] = { decode_subinsn_l2, decode_subinsn_l2 },
|
||||
[0x3] = { decode_subinsn_a, decode_subinsn_a },
|
||||
[0x4] = { decode_subinsn_l1, decode_subinsn_a },
|
||||
[0x5] = { decode_subinsn_l2, decode_subinsn_a },
|
||||
[0x6] = { decode_subinsn_s1, decode_subinsn_a },
|
||||
[0x7] = { decode_subinsn_s2, decode_subinsn_a },
|
||||
[0x8] = { decode_subinsn_s1, decode_subinsn_l1 },
|
||||
[0x9] = { decode_subinsn_s1, decode_subinsn_l2 },
|
||||
[0xa] = { decode_subinsn_s1, decode_subinsn_s1 },
|
||||
[0xb] = { decode_subinsn_s2, decode_subinsn_s1 },
|
||||
[0xc] = { decode_subinsn_s2, decode_subinsn_l1 },
|
||||
[0xd] = { decode_subinsn_s2, decode_subinsn_l2 },
|
||||
[0xe] = { decode_subinsn_s2, decode_subinsn_s2 },
|
||||
[0xf] = { NULL, NULL }, /* Reserved */
|
||||
};
|
||||
|
||||
static uint16_t get_slot0_subinsn(uint32_t encoding)
|
||||
{
|
||||
return extract32(encoding, 0, 13);
|
||||
}
|
||||
|
||||
static uint16_t get_slot1_subinsn(uint32_t encoding)
|
||||
{
|
||||
return extract32(encoding, 16, 13);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
|
||||
{
|
||||
@ -805,8 +870,28 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t encoding)
|
||||
table = &dectree_table_DECODE_ROOT_32;
|
||||
g_assert_not_reached();
|
||||
} else {
|
||||
uint32_t iclass = get_duplex_iclass(encoding);
|
||||
unsigned int slot0_subinsn = get_slot0_subinsn(encoding);
|
||||
unsigned int slot1_subinsn = get_slot1_subinsn(encoding);
|
||||
subinsn_decode_func decode_slot0_subinsn =
|
||||
decode_groups[iclass].decode_slot0_subinsn;
|
||||
subinsn_decode_func decode_slot1_subinsn =
|
||||
decode_groups[iclass].decode_slot1_subinsn;
|
||||
|
||||
/* The slot1 subinsn needs to be in the packet first */
|
||||
if (decode_slot1_subinsn(ctx, slot1_subinsn)) {
|
||||
insn->generate = opcode_genptr[insn->opcode];
|
||||
insn->iclass = iclass_bits(encoding);
|
||||
ctx->insn = ++insn;
|
||||
if (decode_slot0_subinsn(ctx, slot0_subinsn)) {
|
||||
insn->generate = opcode_genptr[insn->opcode];
|
||||
insn->iclass = iclass_bits(encoding);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
/* start with EE table - duplex instructions */
|
||||
table = &dectree_table_DECODE_ROOT_EE;
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return decode_insns_tablewalk(insn, table, encoding);
|
||||
}
|
||||
|
@ -96,8 +96,10 @@ def skip_tag(tag, class_to_decode):
|
||||
## A2_add ..................-.....---..... @A2_add
|
||||
##
|
||||
def gen_decodetree_file(f, class_to_decode):
|
||||
is_subinsn = class_to_decode.startswith("SUBINSN_")
|
||||
f.write(f"## DO NOT MODIFY - This file is generated by {sys.argv[0]}\n\n")
|
||||
f.write("%PP\t14:2\n\n")
|
||||
if not is_subinsn:
|
||||
f.write("%PP\t14:2\n\n")
|
||||
for tag in sorted(encs.keys(), key=iset.tags.index):
|
||||
if skip_tag(tag, class_to_decode):
|
||||
continue
|
||||
@ -108,6 +110,10 @@ def gen_decodetree_file(f, class_to_decode):
|
||||
f"## {tag}:\t{enc_str}\n"
|
||||
"##\n")
|
||||
|
||||
# The subinstructions come with a 13-bit encoding, but
|
||||
# decodetree.py needs 16 bits
|
||||
if is_subinsn:
|
||||
enc_str = "---" + enc_str
|
||||
|
||||
regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
|
||||
imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
|
||||
@ -174,7 +180,9 @@ def gen_decodetree_file(f, class_to_decode):
|
||||
imm_letter = "i" if imm_type.islower() else "I"
|
||||
f.write(f" {imm_type}{imm_letter}=%{tag}_{imm_type}{imm_letter}")
|
||||
|
||||
f.write(" %PP\n")
|
||||
if not is_subinsn:
|
||||
f.write(" %PP")
|
||||
f.write("\n")
|
||||
|
||||
# Replace the 0s and 1s with .
|
||||
enc_str = enc_str.replace("0", ".").replace("1", ".")
|
||||
|
@ -40,11 +40,6 @@ def ordered_unique(l):
|
||||
return sorted(set(l), key=l.index)
|
||||
|
||||
|
||||
def skip_tag(tag, classes):
|
||||
enc_class = iset.iset[tag]["enc_class"]
|
||||
return enc_class not in classes
|
||||
|
||||
|
||||
def code_fmt(txt):
|
||||
return textwrap.indent(textwrap.dedent(txt), " ")
|
||||
|
||||
@ -76,12 +71,9 @@ def mark_which_imm_extended(f, tag):
|
||||
## return true;
|
||||
## }
|
||||
##
|
||||
def gen_trans_funcs(f, classes):
|
||||
def gen_trans_funcs(f):
|
||||
f.write(f"/* DO NOT MODIFY - This file is generated by {sys.argv[0]} */\n\n")
|
||||
for tag in sorted(encs.keys(), key=iset.tags.index):
|
||||
if skip_tag(tag, classes):
|
||||
continue
|
||||
|
||||
regs = ordered_unique(regre.findall(iset.iset[tag]["syntax"]))
|
||||
imms = ordered_unique(immre.findall(iset.iset[tag]["syntax"]))
|
||||
|
||||
@ -129,4 +121,4 @@ def gen_trans_funcs(f, classes):
|
||||
if __name__ == "__main__":
|
||||
hex_common.read_semantics_file(sys.argv[1])
|
||||
with open(sys.argv[2], "w") as f:
|
||||
gen_trans_funcs(f, { "NORMAL", "EXT_mmvec" })
|
||||
gen_trans_funcs(f)
|
||||
|
@ -154,6 +154,51 @@ hvx_decode_generated = custom_target(
|
||||
)
|
||||
hexagon_ss.add(hvx_decode_generated)
|
||||
|
||||
subinsn_a_decode_generated = custom_target(
|
||||
'subinsn_a_decode_generated',
|
||||
output: 'subinsn_a_decode_generated',
|
||||
depends: [iset_py, semantics_generated],
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_A', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(subinsn_a_decode_generated)
|
||||
|
||||
subinsn_l1_decode_generated = custom_target(
|
||||
'subinsn_l1_decode_generated',
|
||||
output: 'subinsn_l1_decode_generated',
|
||||
depends: [iset_py, semantics_generated],
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L1', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(subinsn_l1_decode_generated)
|
||||
|
||||
subinsn_l2_decode_generated = custom_target(
|
||||
'subinsn_l2_decode_generated',
|
||||
output: 'subinsn_l2_decode_generated',
|
||||
depends: [iset_py, semantics_generated],
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_L2', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(subinsn_l2_decode_generated)
|
||||
|
||||
subinsn_s1_decode_generated = custom_target(
|
||||
'subinsn_s1_decode_generated',
|
||||
output: 'subinsn_s1_decode_generated',
|
||||
depends: [iset_py, semantics_generated],
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S1', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(subinsn_s1_decode_generated)
|
||||
|
||||
subinsn_s2_decode_generated = custom_target(
|
||||
'subinsn_s2_decode_generated',
|
||||
output: 'subinsn_s2_decode_generated',
|
||||
depends: [iset_py, semantics_generated],
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files('gen_decodetree.py'), semantics_generated, 'SUBINSN_S2', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(subinsn_s2_decode_generated)
|
||||
|
||||
#
|
||||
# Run the QEMU decodetree.py script to produce the instruction decoder
|
||||
#
|
||||
@ -176,6 +221,51 @@ decode_hvx_generated = custom_target(
|
||||
)
|
||||
hexagon_ss.add(decode_hvx_generated)
|
||||
|
||||
decode_subinsn_a_generated = custom_target(
|
||||
'decode_subinsn_a_generated.c.inc',
|
||||
output: 'decode_subinsn_a_generated.c.inc',
|
||||
input: subinsn_a_decode_generated,
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files(decodetree_py), subinsn_a_decode_generated, ['--static-decode=decode_subinsn_a', '--insnwidth=16'], '-o', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(decode_subinsn_a_generated)
|
||||
|
||||
decode_subinsn_l1_generated = custom_target(
|
||||
'decode_subinsn_l1_generated.c.inc',
|
||||
output: 'decode_subinsn_l1_generated.c.inc',
|
||||
input: subinsn_l1_decode_generated,
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files(decodetree_py), subinsn_l1_decode_generated, ['--static-decode=decode_subinsn_l1', '--insnwidth=16'], '-o', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(decode_subinsn_l1_generated)
|
||||
|
||||
decode_subinsn_l2_generated = custom_target(
|
||||
'decode_subinsn_l2_generated.c.inc',
|
||||
output: 'decode_subinsn_l2_generated.c.inc',
|
||||
input: subinsn_l2_decode_generated,
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files(decodetree_py), subinsn_l2_decode_generated, ['--static-decode=decode_subinsn_l2', '--insnwidth=16'], '-o', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(decode_subinsn_l2_generated)
|
||||
|
||||
decode_subinsn_s1_generated = custom_target(
|
||||
'decode_subinsn_s1_generated.c.inc',
|
||||
output: 'decode_subinsn_s1_generated.c.inc',
|
||||
input: subinsn_s1_decode_generated,
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files(decodetree_py), subinsn_s1_decode_generated, ['--static-decode=decode_subinsn_s1', '--insnwidth=16'], '-o', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(decode_subinsn_s1_generated)
|
||||
|
||||
decode_subinsn_s2_generated = custom_target(
|
||||
'decode_subinsn_s2_generated.c.inc',
|
||||
output: 'decode_subinsn_s2_generated.c.inc',
|
||||
input: subinsn_s2_decode_generated,
|
||||
env: {'PYTHONPATH': meson.current_build_dir()},
|
||||
command: [python, files(decodetree_py), subinsn_s2_decode_generated, ['--static-decode=decode_subinsn_s2', '--insnwidth=16'], '-o', '@OUTPUT@'],
|
||||
)
|
||||
hexagon_ss.add(decode_subinsn_s2_generated)
|
||||
|
||||
#
|
||||
# Generate the trans_* functions that the decoder will use
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user