type
status
date
slug
summary
tags
category
icon
password
本文所使用的 QEMU 版本為:
v4.2.0
Patterns
Pattern
實際定義了一個指令的 decode 方式。Decodetree 會根據 Patterns
的定義,來動態產生出對應的 switch-case
decode 判斷式。其語法由使用者所定義的
identifier
,隨後緊接著一個以上的 pat_elt
。identifier
可由開發者自訂,如:addl_r
、addli
... 等。
pat_elt
則可以採用以下不同的語法:fixedbit_elt
與在Format
中fixedbit_elt
的定義相同。field_elt
與在Format
中field_elt
的定義相同。field_ref
與在Format
中field_ref
的定義相同。args_ref
與在Format
中args_ref
的定義相同。fmt_ref
直接參考一個被定義過的Format
。const_elt
可以直接指定某一個argument
的值。
由於
Pattern
實際定義了一個指令的 decode 方式,因此 所有的 bits 及 arguments (如果有參考 args_ref
的話) 都必須明確的被定義,如果在搭配了所有的 pat_elt
後還有未定義的 bits 或是 arguments 的話,Decodetree 便會報錯。此外,
Pattern
所產生出來的 decoder,最後還會呼叫對應的 translator function
。translator function
需開發者自行定義。
Examples
定義了
addl_i
這個指令的 Pattern
,其中:- insn[31:26] 為
010000
。
- insn[11:5] 為
0000000
。
- 參考了
@opi
這個Format
。
- 由於
Pattern
的 所有 bits 都必須明確的被定義,因此@opi
必須包含其餘insn[25:12]
及insn[4:0]
的格式定義,否則 Decodetree 便會報錯。
最後
addl_i
的 decoder 還會呼叫 trans_addl_i()
這個 translator function
。首先是 RISC-V 的
lui
及 auipc
指令:
會產生以下
lui
及 auipc
的 decoder:回顧到目前為止所介紹的:
Argument Sets
:&u
這個argument set
包含了imm
及rd
這兩個arguments
。
Fields
:imm
及rd
分別位在 insn[31:12] 及 insn[11:7],且imm
為sign-extended
。最後在擷取出imm
的值後,還會呼叫ex_shift_12()
。
Formats
:@u
定義了 RISC-VU-type
指令的格式- 參考了
&u
這個Argument Set
,因此 decode function 會傳入arg_u
作為參數。 - insn[31:12] 參考了
imm_u
這個Field
(並重新命名為imm
) - insn[11:7] 參考了
rd
這個Field
。
Patterns
:lui
的opcode
(insn[6:0]) 為0010111
,也就是0x17
,在產生出來的switch-case
中可以看到其對應的case
。lui
的 decoder 最後呼叫了trans_lui()
,並傳入DisasContext
及經由decode_insn32_extract_u()
所解析出來的arg_u
。auipc
的opcode
(insn[6:0]) 為0110111
,也就是0x37
,在產生出來的switch-case
中可以看到其對應的case
。auipc
的 decoder 最後呼叫了trans_auipc()
,並傳入DisasContext
及經由decode_insn32_extract_u()
所解析出來的arg_u
。- P.S. 這邊由於 Decodetree 發現
lui
及auipc
可以共用decode_insn32_extract_u()
,因此將其提到了switch-case
之外。 Pattern
定義了opcode
(insn[6:0])。Format
參考了imm
(insn[31:12]) 及rd
(insn[11:7])。
我們另外可以發現,
Pattern
+ Format
把所有的 32-bits 都給了明確的定義:如果有任何未明確定義的 bits 的話,Decodetree 便會報錯,例如如果我們將
lui
的 opcode
最高 2 個 bits (insn[6:5]) 由 01
改成 ..
:Decodetree 在解析時,便會報錯:
Decodetree 提醒我們,insn[6:5] (
0x00000060
) 尚未給出明確定義,並會顯示出其錯誤的行數。trans_lui()
和 trans_auipc()
被定義在 target/riscv/insn_trans/trans_rvi.inc.c
:可以看到
trans_*()
負責實際指令的 business logics 及產生對應的 TCG codes
。如同先前所介紹,
Patterns
的 pat_elt
也可以採用 field_elt
語法,如 RISC-V 的 fence
指令:- insn[27:24] 為
pred
。
- insn[23:20] 為
succ
。
- insn[14:12] 固定為
000
。
- insn[6:0] 為
opcode
(0001111
)。
- 沒有參考任何的
Format
。
- 剩下的 insn[31:28]、insn[19:15]、insn[11:7] 被宣告為
-
,因此就算沒有被明確定義也沒有關係。
所生成
fence
的 decoder 如下:值得注意的是,雖然這次我們沒有參考任何的
Argument Set
,但 Decodetree 還是替我們生成了一個包含 pred
和 succ
的 arg_decode_insn320
。trans_fence()
同樣是被定義在 trans_rvi.inc.c
:Pattern Groups
Pattern Groups
由一個以上的 Patterns
所組成,其主要差別是不同 Patterns
之間的 bits 可以 overlap。當同組中有多個 Patterns
時,會依據該組中各 Pattern
的宣告順序依序判斷目前的指令是否符合其定義。除此之外,當符合的 Pattern
其 trans_*()
回傳值為 false
時,也會被視為 不相符,而繼續判斷該組中的下一個 Pattern
。因此 Pattern Groups
非常適合將多個相似格式的指令給組成同一個 Pattern Group
。原文說明如下:
Unlike ungrouped patterns, grouped patterns are allowed to overlap.
Conflicts are resolved by selecting the patterns in order. If all
of the
fixedbits
for a pattern match, its translate function will
be called. If the translate function returns false
, then subsequent
patterns within the group will be matched.各
Pattern Group
以 {
開頭,並以 }
結尾,且允許 nested pattern groups
的存在,其他語法皆與 Pattern
相同。Examples
會產生以下的 decoder:
當指令的值符合
nop
及 copy
這個內層 Pattern Group
時,會先判斷該指令是否符合 nop
指令的定義,且 trans_nop()
的回傳值為 true
。否則的話,就會繼續判斷是否符合同組中的 copy
指令。若都不符,就會再判斷是否符合外層 Pattern Group
的 or
指令。若仍不符,才會回傳 false
表示 decode 失敗。與單純使用
Pattern
最大不同的是,當一 Pattern
的 trans_*()
回傳值為 false
時,不會直接回傳 false
(代表 decode 失敗),而是會接續著判斷後續的 Patterns
是否相符。RISC-V Compressed-Extension 中的
c.ebreak
、c.jalr
、及 c.add
指令,由於這三個指令的格式非常相似,因此非常適合使用 Pattern Group
來定義:
RISC-V spec. 中定義:
C.EBREAK
shares the opcode
with the C.ADD
instruction, but with rd
and rs2
both zero
, thus can also use the CR
format.C.JALR
is only valid when rs1≠x0
; the code point with rs1=x0
corresponds to the C.EBREAK
instruction.C.ADD
is only valid when rs2≠x0
; the code points with rs2=x0
correspond to the C.JALR
and C.EBREAK
instructions. The code points with rs2̸=x0
and rd=x0
are HINTs
.c.ebreak
、c.jalr
、c.add
三個指令:- insn[15:13]、insn[12]、insn[1:0] 的值皆相同。
- 當 insn[11:7] 且 insn[6:2] 的值皆為
0
(rs1=0
且rs2=0
) 時為c.ebreak
指令。
- 當只有 insn[11:7] 的值為
0
(rs1=0
且rs2≠0
) 時為c.jalr
指令。
- 否則為
c.add
指令 (rs1≠x0
且rs2≠0
)。
所生成的 decoder 如下:
當指令格式符合
c.ebreak
、c.jalr
、c.add
的 Pattern Group
時,會依序判斷該指令是否符合 c.ebreak
、c.jalr
、c.add
的定義以及其對應的 trans_*()
。另外值得一提的是,在
c_jalr
Format
和 jalr
Pattern
中有分別指定其 imm
及 rd
的值為 0
,所生成的 codes 也會分別在對應的地方將該值設為 0
(見 codes 註解說明)。以上就是 Decodetree 的語法說明。透過 Decodetree,我們不用再像以前以樣寫一大包的
switch-case
來 decode 指令。將不同類型的指令寫至不同的 decode 檔,不僅方便維護,閱讀起來也更為容易。