【指令仿真】DecodeTree语法
DecodeTree的详细格式,当manual,编程的时候查看:
0、常用符号描述
以target/riscv/insn16.decode为例子
Decodetree Field:field_offset / Immediates_offset【%】
Decodetree Argument Sets:insn_argument_sets_format【&】
Decodetree Format: insn_format【@】
Decodetree Pattern:基于format的组合实现
1、Decodetree Field:field_offset / Immediates_offset【%】
1.0、参数提取
field_def := '%' identifier ( unnamed_field )* ( !function=identifier )?
unnamed_field := number ':' ( 's' ) number eg: %rd 7:5 => insn[11:7]
- identifier 可由开发者自定,如:rd、imm… 等
- unamed_field 定义了该字段的所在比特/位域,s 字符来标明在取出该字段后,是否需要做符号扩展
- !function 定义在截取出该字段的值后,所会再调用的 function
1.1 数字提取&符号扩展
以%imm_c为例子,发现其首bit处为s1,有些地方带bit处带s,有些不带s
其中带s是sextract的缩写,需要进行符号扩展
extract 和 sextract 是用于位提取操作的指令,二者的主要区别在于是否进行符号扩展
# Immediates:
%imm_ci 12:s1 2:5
%nzuimm_ciw 7:4 11:2 5:1 6:1 !function=ex_shift_2
%uimm_cl_q 10:1 5:2 11:2 !function=ex_shift_4
%uimm_cl_d 5:2 10:3 !function=ex_shift_3
%uimm_cl_w 5:1 10:3 6:1 !function=ex_shift_2
1.2 !function符号
从@cl_q找到rs1是带!function符号的,找到其解析部分可以看到函数需要处理其包含位
# Formats 16:
@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
@cl_q ... . ..... ..... .. &i imm=%uimm_cl_q rs1=%rs1_3 rd=%rs2_3
@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
# Fields:
%rd 7:5
%rs1_3 7:3 !function=ex_rvc_register
%rs2_3 2:3 !function=ex_rvc_register
%rs2_5 2:5
%r1s 7:3 !function=ex_sreg_register
%r2s 2:3 !function=ex_sreg_register
# ./qemu/build/libqemu-riscv32-softmmu.fa.p/decode-insn16.c.inc
static void decode_insn16_extract_cl_q(DisasContext *ctx, arg_i *a, uint16_t insn)
{
a->rd = ex_rvc_register(ctx, extract32(insn, 2, 3));
a->rs1 = ex_rvc_register(ctx, extract32(insn, 7, 3));
a->imm = ex_shift_4(ctx, deposit32(deposit32(extract32(insn, 11, 2), 2, 30, extract32(insn, 5, 2)), 4, 28, extract32(insn, 10, 1)));
}
1.3、官方用例
以 RISC-V 的 U-type 指令为例:
31 12 11 7 6 0
+----------------------------------+--------------------+------+
| imm[31:12] | rd |opcode| U-type
+----------------------------------+--------------------+------+
可以声明为:
%rd 7:5
%imm_u 12:s20 !function=ex_shift_12
最后会生成如下的代码:
static void decode_insn32_extract_u(DisasContext *ctx, arg_u *a, uint32_t insn)
{
a->imm = ex_shift_12(ctx, sextract32(insn, 12, 20)); // 是由 insn[31:12] 所取得并做符号扩展,且会再调用 ex_shift_12() 来左移 12 个 bits
a->rd = extract32(insn, 7, 5); // 由 insn[11:7] 所取得
2、Decodetree Argument Sets:insn_argument_sets_format【&】
2.1、指令格式
args_def := '&' identifier ( args_elt )+ ( !extern )?
args_elt := identifier
- identifier 可由开发者自定义,如:regs、loadstore… 等
- !extern 则表示是否在其他地方已经由其他的 decoder 定义过。如果有该字段,就不会再次生成对应的 argument set struct
# U-type 指令格式示例
&u imm rd
# 生成如下代码
typedef struct {
int imm;
int rd;
} arg_u;
2.2、代码例子
# Argument sets imported from insn32.decode:
&empty !extern
&r rd rs1 rs2 !extern
&i imm rs1 rd !extern
&s imm rs1 rs2 !extern
&j imm rd !extern
&b imm rs2 rs1 !extern
&u imm rd !extern
&shift shamt rs1 rd !extern
&r2 rd rs1 !extern
&r2_s rs1 rs2 !extern
&lx_i imm rs1
&lx_imm imm
3、Decodetree Format: insn_format【@】
根据参数提取、指令格式,构建初指令的类型
Format 定义了指令的格式 (如 RISC-V 中的 R、I、S、B、U、J-type),并会生成对应的 decode function。
fmt_def := '@' identifier ( fmt_elt )+ fmt_elt := fixedbit_elt | field_elt | field_ref | args_ref fixedbit_elt := [01.-]+ field_elt := identifier ':' 's'? number field_ref := '%' identifier | identifier '=' '%' identifier args_ref := '&' identifier
3.1、例如@cl_q指令,
1、参照type-i类型的指令格式,
2、参数提取参照以下定义 imm=%uimm_cl_q rs1=%rs1_3 rd=%rs2_3
# Formats 16:
@cr .... ..... ..... .. &r rs2=%rs2_5 rs1=%rd %rd
@ci ... . ..... ..... .. &i imm=%imm_ci rs1=%rd %rd
@cl_q ... . ..... ..... .. &i imm=%uimm_cl_q rs1=%rs1_3 rd=%rs2_3
@cl_d ... ... ... .. ... .. &i imm=%uimm_cl_d rs1=%rs1_3 rd=%rs2_3
@cl_w ... ... ... .. ... .. &i imm=%uimm_cl_w rs1=%rs1_3 rd=%rs2_3
@cs_2 ... ... ... .. ... .. &r rs2=%rs2_3 rs1=%rs1_3 rd=%rs1_3
3.2、官方样例
以 RISC-V I-type 指令为例:
31 20 19 15 14 12 11 7 6 0
+--------------+--------+----------+--------------------+------+
| imm[11:0] | rs1 | funct3 | rd |opcode| I-type
+--------------+--------+----------+--------------------+------+
# Fields:
%rs1 15:5
%rd 7:5
# immediates:
%imm_i 20:s12
# Argment sets:
&i imm rs1 rd
# Format
@i ........ ........ ........ ........ &i imm=%imm_i %rs1 %rd
此范例会生成以下的 decode function:
typedef struct {
int imm;
int rd;
int rs1;
} arg_i;
static void decode_insn32extract_i(DisasContext *ctx, arg_i *a, uint32_t insn)
{
a->imm = sextract32(insn, 20, 12);
a->rs1 = extract32(insn, 15, 5);
a->rd = extract32(insn, 7, 5);
}
4、pattern
4.1 pattern配合trans_进行使用;
c_li是addi指令的一种特殊形式
# *** RV32/64C Standard Extension (Quadrant 1) ***
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
{
illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
addi 011 . 00010 ..... 01 @c_addi16sp
lui 011 . ..... ..... 01 @c_lui
}
# ./qemu/target/riscv/insn_trans/trans_rvi.c.inc
static bool trans_addi(DisasContext *ctx, arg_addi *a)
{
return gen_arith_imm_fn(ctx, a, EXT_NONE, tcg_gen_addi_tl, gen_addi2_i128);
}
4.2 对比c.li与c.addi的格式
c.li【x[rd] = sext(imm)】
c.addi【x[rd] = x[rd] + sext(imm)】
c.li中第二个寄存器为x0,x0在riscv的架构中恒为0
5、 pattern group
# *** RV32/64C Standard Extension (Quadrant 1) ***
addi 000 . ..... ..... 01 @ci
addi 010 . ..... ..... 01 @c_li
{
illegal 011 0 ----- 00000 01 # c.addi16sp and c.lui, RES nzimm=0
addi 011 . 00010 ..... 01 @c_addi16sp
lui 011 . ..... ..... 01 @c_lui
}
注意illegal的限制:
限制nzimm=0,因为当imm=0时,没意义
对于c.addi16sp,当imm=0时,没意义
对于c.lui,当rd=x2时,变成了c.addi16sp,所以要限制非法;当imm=0时,没意义
riscv指令仿真
