Hello World!

Linux Kernel, QEMU, RISC-V, and Computer Architecture

QEMU: 使用 Decodetree 新增 RISC-V 指令

⚠️ 本文所使用的 QEMU 版本為:v4.2.0 在之前的文章中 (Part 1., Part 2.) 我們提到了如何使用 Decodetree 來定義指令的 decoder。本篇文章就實際使用 Decodetree 來定義一個 QEMU RISC-V 目前尚未支援的指令 - B(itmanip) Extension 中的 pcnt 指令,並實做其行為。 pcnt 指令 pcnt 指令的定義如下: This instruction counts the number of 1 bits in a register. This operations is known as population count, popcount, sideways sum, bit summation, or Hamming weight. 其指令格式為: 1 2 3 | 1 0 9 8 7 6 5 | 4 3 2 1 0 | 9 8 7 6 5 | 4 3 2 | 1 0 9 8 7 | 6 5 4 3 2 1 0 | |===========================================================================| | 0110000 | 00010 | rs1 | 001 | rd | 0010011 | PCNT 安裝 toolchain 由於 B Extension 尚未正式定稿 (Draft),因此必須至 riscv-bitmanip repo 下載 toolchain,並依照該 repo 的指示安裝: ...

2020/02/16 · 6 分鐘 · 1156 字 · Frank Chang

QEMU Decodetree 語法介紹 (Part 2.)

⚠️ 本文所使用的 QEMU 版本為:v4.2.0 延續 Part 1. 一文,本文將繼續介紹 Decodetree 中的 Patterns 及 Pattern Groups 語法。 Patterns Pattern 實際定義了一個指令的 decode 方式。Decodetree 會根據 Patterns 的定義,來動態產生出對應的 switch-case decode 判斷式。 1 2 3 4 pat_def := identifier ( pat_elt )+ pat_elt := fixedbit_elt | field_elt | field_ref | args_ref | fmt_ref | const_elt fmt_ref := '@' identifier const_elt := identifier '=' number 其語法由使用者所定義的 identifier,隨後緊接著一個以上的 pat_elt。 ...

2020/02/01 · 8 分鐘 · 1664 字 · Frank Chang

QEMU Decodetree 語法介紹 (Part 1.)

⚠️ 本文所使用的 QEMU 版本為:v4.2.0 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 這種具有固定指令格式的 ISA1。 因為各欄位都在固定的位置,(如 RISC-V 的 opcode 都是固定在 bits[6..0] 的位置),各指令可重複使用的定義相較於其他的 ISA 來得多。 ...

2020/01/31 · 8 分鐘 · 1664 字 · Frank Chang

Linux Kernel: BUILD_BUG_ON_ZERO() / BUILD_BUG_ON_NULL()

之前在 trace Linux Kernel source codes 時發現了兩個很特別的 macros:BUILD_BUG_ON_ZERO() 和 BUILD_BUG_ON_NULL() (定義在:include/linux/kernel.h) 它們的定義如下: 1 2 3 4 5 6 /* Force a compilation error if condition is true, but also produce a result (of value 0 and type size_t), so the expression can be used e.g. in a structure initializer (or where-ever else comma expressions aren't permitted). */ #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) #define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) 其中 e 是我們所傳入的判斷式,若判斷式為 true,則會造成 compile error。如此我們便可透過這個 macro 來判斷是否某些錯誤/不應發生的情況 (判斷式) 是否會發生,若會發生則可在 compile-time 的時候就顯示錯誤訊息。 ...

2012/10/14 · 3 分鐘 · 488 字 · Frank Chang

Linux Kernel: ARRAY_SIZE()

通常我們在 C 語言中取得陣列的元數個數可以透過下列的方式來計算: 1 2 3 4 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) int arr[10]; int arr_size = ARRAY_SIZE(arr); 但如同 Jserv 大大在 這篇文章 中所提到:ARRAY_SIZE() 這樣的 macro 其實是陷阱重重… 因為 macro 本身沒辦法做型態檢查,只是單純的將值帶入並展開,而在 C 中我們常常會將指標和陣列混著使用。因此若是我們將指向該陣列的指標傳入,就會得到錯誤的計算結果。 如下面的程式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio.h> #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) int main(void) { int a[10]; int *a_ptr = a; printf("%d\n", ARRAY_SIZE(a)); printf("%d\n", ARRAY_SIZE(a_ptr)); return 0; } 若傳入陣列 a,則結果會正確顯示 size 大小為 10,但若傳入的是指向陣列 a 的指標 a_ptr,則因為指標的在 32 位元作業系統上大小為 4 bytes (4 / 4) 的結果則會變成 1,而並不是我們所要的答案 10。 ...

2012/10/13 · 3 分鐘 · 589 字 · Frank Chang