【指令仿真】DecodeTree语法

DecodeTree的详细格式,当manual,编程的时候查看:

  1. 汉化文档: Decodetree - Learning QEMU Docs
  2. 全英官方: Decodetree Specification — QEMU documentation

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时,没意义

QEMU指令仿真 文章被收录于专栏

riscv指令仿真

全部评论

相关推荐

2025-12-28 16:32
重庆邮电大学 Java
程序员花海:1.技能放最后,来面试默认你都会,技能没啥用 2.实习写的看起来没啥含金量,多读读部门文档,包装下 接LLM这个没含金量 也不要用重构这种 不会给实习生做的 3.抽奖这个还是Demo项目,实际在公司里面要考虑策略,满减,触发点,触发规则 库存 之类的,不是这个项目这么简单 4.教育背景提前,格式为 教育背景 实习 项目 技能 自我评价
简历被挂麻了,求建议
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务