<aside> ⚠️ 本文所使用的 QEMU 版本為:v4.2.0

</aside>

QEMU 在 decode 指令的時候,需要呼叫各平台所定義的 instruction decoders 來解析指令。如在 ARM 平台下,就定義了:disas_arm_insn()disas_thumb_insn()disas_thumb2_insn() 等來分別負責 ARM 32-bits 指令、ARM Thumb 指令及 ARM Thumb2 指令的解析。

而 Decodetree 則是由 Bastian Koppelmann 於 2017 年在 porting RISC-V QEMU 的時候所提出來的機制 (詳見:討論串 1討論串 2)。主因是過往的 instruction decoders (如:ARM) 都是採用一大包的 switch-case 來做判斷。不僅難閱讀,也難以維護。

因此 Bastian Koppelmann 就提出了 Decodetree 的機制,開發者只需要透過 Decodetree 的語法定義各個指令的格式,便可交由 Decodetree 來動態生成對應包含 switch-case 的 instruction decoder .c 檔。

Decodetree 特別適合像 RISC-V 這種具有固定指令格式的 ISA [註1[]](https://www.notion.so/Decodetree-5eb0cb1f35ca4794bf3dfb8050cec81c#d9b5f36cf29a497aa764c3d0797085b9)。

Decodetree 其實是由 Python script (scripts/decodetree.py) 所撰寫的。其規格說明文件可以參考:docs/devel/decodetree.rst,裡面有詳細定義了其語法的格式。QEMU 在編譯時,會呼叫 Decodetree,根據各平台所定義的 decode 檔,動態生成對應的 decoder。

Decodetree 的語法共分為:FieldsArgument SetsFormatsPatternsPattern Groups 五部分。本文將介紹如何透過 Decodetree 的語法,來動態生成一個指令的 decoder。


Fields

Field 定義如何取出一指令中,各欄位 (e.g. rd, rs1, rs2, imm) 的值。

field_def     := '%' identifier ( unnamed_field )* ( !function=identifier )?
unnamed_field := number ':' ( 's' ) number

其語法由 % 開頭,隨後緊接著一個 identifier 及零個或多個 unamed_field,並可再加上可選的 !function