本教學課程的目標是:
- 瞭解二進位格式說明檔案的結構和語法。
- 瞭解二進位格式說明如何與 ISA 說明相符。
- 為 RiscV RV32I 部分指令撰寫二進位說明。
總覽
RiscV 二進位指令編碼
二進位指令編碼是將操作說明編碼的標準方式 透過微處理器執行這些檔案通常儲存在可執行檔中 通常使用 ELF 格式指示可以是固定寬度或可變動 寬度。
一般而言,指示會使用少量的編碼格式,每種格式都有。 ,根據編碼指示類型自訂。例如註冊 指令可能會使用一種格式,以最大化可用的運算碼 而應立即以其他方式取捨 可用的運算碼,可增加可編碼的立即大小。 分支版本和跳轉指示幾乎一律會使用可將 為了支援具有較大偏移量的分支版本。
我們要在 RiscV 中解碼的操作說明採用的指示格式 模擬工具如下:
註冊操作說明所用的 R-Type 格式:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| func7 | rs2 | rs1 | func3 | 日 | 運算程式碼 |
I-Type 格式,用於註冊中操作說明、載入指示和
jalr 指令,12 位元立即生效。
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|
| 12 | 5 | 3 | 5 | 7 |
| imm12 | rs1 | func3 | 日 | 運算程式碼 |
特殊的 I-Type 格式,用於能立即位移,5 位元 立即:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| func7 | uimm5 | rs1 | func3 | 日 | 運算程式碼 |
U-Type 格式,用於長方即時指示 (lui、auipc),20 位元
立即:
| 12 月 31 日 | 11..7 | 6..0 版 |
|---|---|---|
| 20 | 5 | 7 |
| uimm20 | 日 | 運算程式碼 |
B-Type 格式,用於條件分支版本,12 位元立即。
| 31 | 30.25 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..8 | 7 | 6..0 版 |
|---|---|---|---|---|---|---|---|
| 1 | 6 | 5 | 5 | 3 | 4 | 1 | 7 |
| 嗯 | 嗯 | rs2 | rs1 | func3 | 嗯 | 嗯 | 運算程式碼 |
J-Type 格式,用於 jal 指令,即時 20 位元。
| 31 | 2021 年 3 月 30 日 | 20 | 19:12 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 1 | 10 | 1 | 8 | 5 | 7 |
| 嗯 | 嗯 | 嗯 | 嗯 | 日 | 運算程式碼 |
S-Type 格式,儲存指示後可使用 12 位元格式。
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| 嗯 | rs2 | rs1 | func3 | 嗯 | 運算程式碼 |
如這些格式所示,所有指示的長度都是 32 位元,且 也就是每個格式的 7 位元是 opcode 欄位同時請注意 幾種格式的尺寸會立即相同,其位元的來源 指示分成不同的部分如畫面所示 就能表達出這一點
二進位編碼說明
指示的二進位編碼以二進位格式表示
(.bin_fmt) 說明檔案。它會說明
操作說明,以便系統擷取二進位格式指示
。產生的解碼器會判斷運算碼,並擷取
運算和即時欄位,以提供 ISA 所需的資訊
先前教學課程中所述的編碼式解碼器
在這個教學課程中,我們會針對子集,編寫二元編碼說明檔案 才能模擬 小型的「Hello World」計畫。如要進一步瞭解 RiscV ISA,請參閱 Risc-V 規格{.external}。
先開啟檔案:
riscv_bin_decoder/riscv32i.bin_fmt。
檔案內容分為幾個部分。
首先是 decoder 定義。
decoder RiscV32I {
// The namespace in which code will be generated.
namespace mpact::sim::codelab;
// The name (including any namespace qualifiers) of the opcode enum type.
opcode_enum = "OpcodeEnum";
// Include files specific to this decoder.
includes {
#include "riscv_isa_decoder/solution/riscv32i_decoder.h"
}
// Instruction groups for which to generate decode functions.
RiscVInst32;
};
解碼器定義會指定解碼器 RiscV32I 的名稱,以及
以及四項其他資訊第一個是 namespace,用來定義
要放置產生的程式碼所在的命名空間其次,
opcode_enum,可為產生的運算程式碼列舉類型命名
而是在產生的程式碼中參照第三
includes {} 會指定程式碼產生的所需檔案
編碼器與解碼器模型
在這個案例中,這是由 ISA 解碼器
請參閱上一堂教學課程
可在全域範圍的 includes {} 中指定其他 include 檔案
定義如果定義了多個解碼器,而且需要
加入一些相同檔案第四是指引名稱清單
來構成解碼器的產生指示群組在我們
結果只有一個:RiscVInst32
接下來是三種格式定義分別代表不同的指示 32 位元指示用字的格式 檔案中。
// The generic RiscV 32 bit instruction format.
format Inst32Format[32] {
fields:
unsigned bits[25];
unsigned opcode[7];
};
// RiscV 32 bit instruction format used by a number of instructions
// needing a 12 bit immediate, including CSR instructions.
format IType[32] : Inst32Format {
fields:
signed imm12[12];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
// RiscV instruction format used by fence instructions.
format Fence[32] : Inst32Format {
fields:
unsigned fm[4];
unsigned pred[4];
unsigned succ[4];
unsigned rs1[5];
unsigned func3[3];
unsigned rd[5];
unsigned opcode[7];
};
第一個是定義名為 Inst32Format 的 32 位元寬指示格式,其中包含
bits (寬 25 位元) 和 opcode (寬 7 位元)。每個欄位都是
unsigned:表示在擷取值時,會延伸零
並放在 C++ 整數類型中位元欄位寬度的總和必須
就會等於格式的寬度如果發生問題,這項工具會產生錯誤
。這個格式並不衍生其他格式,因此
視為頂層格式。
第二個則定義名為 IType 的 32 位元寬指示格式,衍生自
,由 Inst32Format 製作,並使這兩種格式相關。格式包含 5 個
欄位:imm12、rs1、func3、rd 和 opcode。imm12 欄位是
signed,這表示當值在
並放在 C++ 整數型別中請注意,IType.opcode 和
相同的帶正負號/無正負號屬性,且是指相同的指令文字位元
使用 Inst32Format.opcode。
第三種格式是僅供 fence 使用的自訂格式
指令:預先指定的指示,
因此您不需要擔心本教學課程中的問題
重點提示:以不同相關格式重複使用欄位名稱,只要欄位名稱 代表相同的位元且具有相同的正負號/未簽署屬性。
riscv32i.bin_fmt 的格式定義完成後,就會成為指令群組
定義老師群組中的所有指令都必須相同
並使用取自
頂層操作說明格式針對 ISA 提供操作說明的情況,
則每種長度都使用不同的指示群組此外,
如果目標 ISA 解碼需要仰賴執行模式 (例如 Arm 和 Thumb)
指令,每個模式都必須建立個別的指示群組。
bin_fmt 剖析器會為每個指令群組產生二進位解碼器。
instruction group RiscV32I[32] "OpcodeEnum" : Inst32Format {
fence : Fence : func3 == 0b000, opcode == 0b000'1111;
csrs : IType : func3 == 0b010, rs1 != 0, opcode == 0b111'0011;
csrw_nr : IType : func3 == 0b001, rd == 0, opcode == 0b111'0011;
csrs_nw : IType : func3 == 0b010, rs1 == 0, opcode == 0b111'0011;
};
指令群組會定義名稱 RiscV32I、寬度 [32]、
使用 "OpcodeEnum" 的 Ocode 列舉類型,以及基本指令
格式。運算碼列舉類型應與
格式獨立指示解碼器
編碼器和解碼器
每項操作說明編碼說明都包含 3 個部分:
- 運算碼名稱,必須與指示中使用的名稱相同 解碼器說明
- 運算程式碼所使用的指示格式。這種格式 用來滿足最後部分位元欄位的參照。
- 以半形逗號分隔的位元欄位限制條件清單:
==、!=、<、<=、>和>=都必須為運算程式碼才能成功比對 的說明文字
.bin_fmt 剖析器會使用所有這些資訊來建構具有以下功能的解碼器:
- 提供適合每個位元的擷取函式 (帶正負號/未簽署)
欄位。擷取器函式位於命名空間中
使用 Sake-case 版本的格式名稱命名舉例來說,
格式
IType的擷取器函式位於命名空間i_type中。 每個擷取器函式都會宣告為inline,採用最小uint_t表示格式寬度的 類型,然後傳回最窄的int_t(適用於未簽署的)、uint_t(適用於未簽署欄位) 類型,保存擷取的欄位 寬度。例如:
inline uint8_t ExtractOpcode(uint32_t value) {
return value & 0x7f;
}
- 每個指示群組的解碼函式。該函式會傳回類型
OpcodeEnum,並採用最窄的uint_t類型,該類型包含寬度的 指示群組格式
執行初始建構作業
將目錄變更為 riscv_bin_decoder,並使用
以下指令:
$ cd riscv_bin_decoder
$ bazel build :all
現在將目錄改回存放區根目錄,接著來看看
所產生的來源為此,請將目錄變更為
bazel-out/k8-fastbuild/bin/riscv_bin_decoder (假設您使用 x86 格式)
host - 如果是其他主機,k8-fastbuild 會是另一個字串)。
$ cd ..
$ cd bazel-out/k8-fastbuild/bin/riscv_bin_decoder
riscv32i_bin_decoder.hriscv32i_bin_decoder.cc
產生的標頭檔案 (.h)
開啟 riscv32i_bin_decoder.h。檔案的第一個部分包含標準檔案
樣板防護、包含檔案、命名空間宣告。然後
命名空間「internal」中有範本輔助函式。這個函式
用於擷取格式太長而無法容納 64 位元 C++ 的位元欄位
整數值。
#ifndef RISCV32I_BIN_DECODER_H
#define RISCV32I_BIN_DECODER_H
#include <iostream>
#include <cstdint>
#include "third_party/absl/functional/any_invocable.h"
#include "learning/brain/research/mpact/sim/codelab/riscv_isa_decoder/solution/riscv32i_decoder.h"
namespace mpact {
namespace sim {
namespace codelab {
namespace internal {
template <typename T>
static inline T ExtractBits(const uint8_t *data, int data_size,
int bit_index, int width) {
if (width == 0) return 0;
int byte_pos = bit_index >> 3;
int end_byte = (bit_index + width - 1) >> 3;
int start_bit = bit_index & 0x7;
// If it is only from one byte, extract and return.
if (byte_pos == end_byte) {
uint8_t mask = 0xff >> start_bit;
return (mask & data[byte_pos]) >> (8 - start_bit - width);
}
// Extract from the first byte.
T val = 0;
val = data[byte_pos++] & 0xff >> start_bit;
int remainder = width - (8 - start_bit);
while (remainder >= 8) {
val = (val << 8) | data[byte_pos++];
remainder -= 8;
}
// Extract any remaining bits.
if (remainder > 0) {
val <<= remainder;
int shift = 8 - remainder;
uint8_t mask = 0b1111'1111 << shift;
val |= (data[byte_pos] & mask) >> shift;
}
return val;
}
} // namespace internal
初始部分之後有三個命名空間
riscv32i.bin_fmt 檔案中 format 宣告的結構:
namespace fence {
...
} // namespace fence
namespace i_type {
...
} // namespace i_type
namespace inst32_format {
...
} // namespace inst32_format
在每個命名空間中,inline位元欄位擷取函式
每個位元欄位都會由該格式定義此外,基礎格式
從子系格式擷取重複函式
1) 欄位名稱只會出現在單一欄位名稱中,或是 2)
欄位名稱參照相同的類型欄位 (帶正負號/無正負號和位元位置)
都能提供不同的內容即可啟用描述相同值的位元欄位
要透過頂層格式命名空間中的函式擷取的位元。
i_type 命名空間中的函式如下所示:
namespace i_type {
inline uint8_t ExtractFunc3(uint32_t value) {
return (value >> 12) & 0x7;
}
inline int16_t ExtractImm12(uint32_t value) {
int16_t result = ( (value >> 20) & 0xfff) << 4;
result = result >> 4;
return result;
}
inline uint8_t ExtractOpcode(uint32_t value) {
return value & 0x7f;
}
inline uint8_t ExtractRd(uint32_t value) {
return (value >> 7) & 0x1f;
}
inline uint8_t ExtractRs1(uint32_t value) {
return (value >> 15) & 0x1f;
}
} // namespace i_type
最後,用於指示的解碼器函式的函式宣告
已宣告 RiscVInst32 群組。這個值需要 32 位元的未簽署值做為
並傳回 OpcodeEnum 列舉類別成員
不相符或 OpcodeEnum::kNone (沒有相符項目)。
OpcodeEnum DecodeRiscVInst32(uint32_t inst_word);
產生的來源檔案 (.cc)
現在開啟 riscv32i_bin_decoder.cc。檔案的第一個部分包含
#include 和命名空間宣告,然後是解碼器函式
宣告:
#include "riscv32i_bin_decoder.h"
namespace mpact {
namespace sim {
namespace codelab {
OpcodeEnum DecodeRiscVInst32None(uint32_t);
OpcodeEnum DecodeRiscVInst32_0(uint32_t inst_word);
OpcodeEnum DecodeRiscVInst32_0_3(uint32_t inst_word);
OpcodeEnum DecodeRiscVInst32_0_3c(uint32_t inst_word);
OpcodeEnum DecodeRiscVInst32_0_5c(uint32_t inst_word);
DecodeRiscVInst32None 用於空白解碼動作,例如:
傳回 OpcodeEnum::kNone。其他三個函式會構成
產生的解碼器整體解碼器會以階層方式運作。一組
是為了區分指令文字中的位元數
或一組指示群組。元件
以連續線來說位元數量會決定對照表的大小
會填入第二層解碼器函式您將在
的區段:
absl::AnyInvocable<OpcodeEnum(uint32_t)> parse_group_RiscVInst32_0[kParseGroupRiscVInst32_0_Size] = {
&DecodeRiscVInst32None, &DecodeRiscVInst32None,
&DecodeRiscVInst32None, &DecodeRiscVInst32_0_3,
&DecodeRiscVInst32None, &DecodeRiscVInst32None,
...
&DecodeRiscVInst32None, &DecodeRiscVInst32None,
&DecodeRiscVInst32None, &DecodeRiscVInst32None,
&DecodeRiscVInst32_0_3c, &DecodeRiscVInst32None,
...
};
最後,解碼器函式的定義如下:
OpcodeEnum DecodeRiscVInst32None(uint32_t) {
return OpcodeEnum::kNone;
}
OpcodeEnum DecodeRiscVInst32_0(uint32_t inst_word) {
if ((inst_word & 0x4003) != 0x3) return OpcodeEnum::kNone;
uint32_t index;
index = (inst_word >> 2) & 0x1f;
index |= (inst_word >> 7) & 0x60;
return parse_group_RiscVInst32_0[index](inst_word);
}
OpcodeEnum DecodeRiscVInst32_0_3(uint32_t inst_word) {
return OpcodeEnum::kFence;
}
OpcodeEnum DecodeRiscVInst32_0_3c(uint32_t inst_word) {
if ((inst_word & 0xf80) != 0x0) return OpcodeEnum::kNone;
return OpcodeEnum::kCsrwNr;
}
OpcodeEnum DecodeRiscVInst32_0_5c(uint32_t inst_word) {
uint32_t rs1_value = (inst_word >> 15) & 0x1f;
if (rs1_value != 0x0)
return OpcodeEnum::kCsrs;
if (rs1_value == 0x0)
return OpcodeEnum::kCsrsNw;
return OpcodeEnum::kNone;
}
OpcodeEnum DecodeRiscVInst32(uint32_t inst_word) {
OpcodeEnum opcode;
opcode = DecodeRiscVInst32_0(inst_word);
return opcode;
}
在本例中,如果只定義了 4 個指令,則 以及非常稀疏的對照表如 解碼器的結構將會改變 可能會增加
新增註冊註冊 ALU 操作說明
接下來,請在 riscv32i.bin_fmt 檔案中新增一些指示。
第一組操作說明是註冊 ALU 操作說明,例如
add、and 等。在 RiscV32 中,這些權限都會使用 R 型二進位檔指示
格式:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| func7 | rs2 | rs1 | func3 | 日 | 運算程式碼 |
首先,我們要新增格式。直接開啟
riscv32i.bin_fmt。在 Inst32Format 允許
新增名為 RType 的格式,該格式衍生自 Inst32Format。所有位元欄位
RType的價格為 unsigned。使用名稱、位元寬度和順序 (從左到右)
定義格式如果您需要提示
完整解決方案
請按這裡。
接下來,我們要新增指示。操作步驟如下:
add- 加入整數,and:位元和。or:位元或。sll- 將邏輯往左移。sltu- 設定小於或未簽署的字元。sub- 減去整數。xor- 位元 xor。
其編碼如下:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|---|---|---|
| 000,0000 | rs2 | rs1 | 000 | 日 | 011 0011 | add |
| 000,0000 | rs2 | rs1 | 111 | 日 | 011 0011 | 和 |
| 000,0000 | rs2 | rs1 | 110 | 日 | 011 0011 | 或 |
| 000,0000 | rs2 | rs1 | 001 | 日 | 011 0011 | 斯爾 |
| 000,0000 | rs2 | rs1 | 011 | 日 | 011 0011 | 史詩 |
| 010,0000 人 | rs2 | rs1 | 000 | 日 | 011 0011 | 替補球員 |
| 000,0000 | rs2 | rs1 | 100 | 日 | 011 0011 | Xor |
| func7 | func3 | 運算程式碼 |
請將這些指令定義放在
RiscVInst32 個指示群組。二進位字串的指定
0b 前置字元 (類似於十六進位數字的 0x)。為了方便起見
讀取二進位數字的長字串,您也可以插入單引號 ',
視需要調整數字分隔符
每項指令定義都會有三個限制,也就是
func7、func3和opcode。除了 sub 以外,func7 限制將
品牌:
func7 == 0b000'0000
func3 限制會因大多數操作說明而異。適用於 add和
sub,它是:
func3 == 0b000
以下每個操作說明的 opcode 限制都相同:
opcode == 0b011'0011
請記得以半形分號 ; 終止每一行。
已完成的解決方案是 請按這裡。
現在,繼續按照之前的方式建構專案,並開啟
riscv32i_bin_decoder.cc 檔案。您會看到其他解碼器函式
以便處理新的指令。大多數情況下
與先前產生的範本類似
DecodeRiscVInst32_0_c 用於 add/sub 解碼:
OpcodeEnum DecodeRiscVInst32_0_c(uint32_t inst_word) {
static constexpr OpcodeEnum opcodes[2] = {
OpcodeEnum::kAdd,
OpcodeEnum::kSub,
};
if ((inst_word & 0xbe000000) != 0x0) return OpcodeEnum::kNone;
uint32_t index;
index = (inst_word >> 30) & 0x1;
return opcodes[index];
}
這個函式會產生一個靜態解碼表,查詢值是 ,選取適當的索引。這麼做會新增 是指示解碼器階層的第二層 直接在表格中查詢,沒有進一步比較,系統會以這個方式內嵌 函式而非需要其他函式呼叫
立即新增 ALU 指示
下一組操作說明為 ALU 指示,使用 即時值,而不是其中一個暫存器。我們有三個群組 指令 (根據即時欄位):I-Type 立即指示 以及 12 位元立即簽署的特殊 I-Type 立即指示 以及 U-Type 會立即使用 20 位元無正負號的即時值。 格式如下:
I-Type 立即格式:
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|
| 12 | 5 | 3 | 5 | 7 |
| imm12 | rs1 | func3 | 日 | 運算程式碼 |
專用的 I-Type 立即格式:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| func7 | uimm5 | rs1 | func3 | 日 | 運算程式碼 |
U-Type 立即格式:
| 12 月 31 日 | 11..7 | 6..0 版 |
|---|---|---|
| 20 | 5 | 7 |
| uimm20 | 日 | 運算程式碼 |
riscv32i.bin_fmt 中已有 I-Type 格式,因此不需要
新增該格式
如果我們比較專門的 I-Type 格式和先前在
在上一個練習中,我們發現唯一的差別在於 rs2 欄位
已重新命名為 uimm5。與其新增特殊格式
R-Type 格式。我們無法新增另一個欄位,
但我們可以加入疊加層。「疊加層」是一組別名的別名
編碼中,還可以用來合併多個值的子序列
轉換為獨立的具名實體最終效果是產生的程式碼
現在,除了疊加層外, 檢視畫面也會加入擷取函式
是給欄位的看法在本範例中,rs2 和 uimm5 皆未簽署
並沒有太大的差別,而是明確指出欄位使用了該欄位
立即取得如要在 R-Type 格式中加入名為 uimm5 的疊加層,請在
在最後一個欄位後面:
overlays:
unsigned uimm5[5] = rs2;
我們需要新增的唯一新格式是 U-Type 格式。加上
格式,以下是使用該格式的兩個操作說明:auipc 和
lui。兩者會在使用前,先將 20 位元的直接值移往 12
,即可將其新增至暫存器 (auipc),或直接將電腦寫入暫存器中
(lui)。透過重疊,我們可提供原始的
將一些運算作業從指示執行轉為指導
解碼器。首先,根據表格中指定的欄位新增格式
。接著,我們可以加入下列疊加層:
overlays:
unsigned uimm32[32] = uimm20, 0b0000'0000'0000;
疊加層語法不僅可讓我們串連欄位,還能將常值參照 在本例中,我們將該變數與 12 個零串連 前 12 名。
需要新增的 I-Type 操作說明如下:
addi- 立即新增。andi- 位元和立即。ori:位元或立即。xori- 具有立即的位元 xor。
其編碼如下:
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode_name |
|---|---|---|---|---|---|
| imm12 | rs1 | 000 | 日 | 001 0011 | Addi |
| imm12 | rs1 | 111 | 日 | 001 0011 | 安迪 |
| imm12 | rs1 | 110 | 日 | 001 0011 | Ori |
| imm12 | rs1 | 100 | 日 | 001 0011 | Xori |
| func3 | 運算程式碼 |
我們需要新增的 R-Type (專屬 I-Type) 說明如下:
slli- 立即將左移邏輯列。srai- 立即將右算法調整。srli- 立即將右移邏輯運算。
其編碼如下:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|---|---|---|
| 000,0000 | uimm5 | rs1 | 001 | 日 | 001 0011 | Solli |
| 010,0000 人 | uimm5 | rs1 | 101 | 日 | 001 0011 | 斯拉伊 |
| 000,0000 | uimm5 | rs1 | 101 | 日 | 001 0011 | 斯里 |
| func7 | func3 | 運算程式碼 |
需要新增的 U-Type 操作說明如下:
auipc- 立即將上限新增至電腦。lui- 立即載入上方。
其編碼如下:
| 12 月 31 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|
| uimm20 | 日 | 001 0111 | auipc |
| uimm20 | 日 | 011 0111 | 盧伊 |
| 運算程式碼 |
請繼續進行變更,然後開始建構。檢查產生的輸出內容。只要 您可以先檢查 riscv32i.bin_fmt。
新增分支版本與跳轉連結的操作說明
下一組需要定義的指令是條件分支版本 說明、跳轉連結說明和快速連結註冊 指示
要新增的條件分支全都使用 B-Type 編碼。
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| imm7 | rs2 | rs1 | func3 | imm5 | 運算程式碼 |
雖然版面配置中的 B-Type 編碼與 R-Type 編碼相同,但
配合 RiscV 說明文件,選擇使用新的格式類型。
但您也可以新增疊加層,以便取得正確的分支版本
使用 R-Type 的 func7 和 rd 欄位,立即取代位移
編碼。
「BType」格式必須含有上述欄位,但「不」需要
而負責任的 AI 技術做法
有助於達成這項目標如您所見,立即分成兩個指示欄位。
此外,分支指示不算是將其視為
這兩個欄位的值而是將每個欄位進一步分區,然後是這些分區
會以不同順序串連最後,將該值往左移
以取得 16 位元對齊的位移。
用於形成直接形成指示詞中的位元序列為:31、
7、30..25、11..8。這對應下列子欄位參照,其中
索引或範圍會指定欄位中的位元,也就是從右到左編號,也就是
imm7[6] 是指 imm7 的 msb,imm5[0] 則是 lsb 的 lsb。
imm5。
imm7[6], imm5[0], imm7[5..0], imm5[4..1]
將位元操控部分設定為分支指示本身,有兩個
也有許多缺點首先,將語意函式的實作結果
二進位檔指示表示法中的詳細資料。其次,這樣做會增加執行階段
同時免除不必要的負擔答案是將疊加層加到 BType 格式,包括
結尾「0」所以務必要考量左移
overlays:
signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0;
請注意,疊加層已經簽署,因此會自動展開 所擷取的指令
跳連結 (立即) 指示使用 J-Type 編碼:
| 12 月 31 日 | 11..7 | 6..0 版 |
|---|---|---|
| 20 | 5 | 7 |
| imm20 | 日 | 運算程式碼 |
這個格式也容易新增,同樣地, 指導不如預期那麼簡單編碼器-解碼器架構 如下圖所示:31、19..12、20、30..21,最終為立即 目前移到左移 1,表示半文字對齊。解決方法是 依照左移 (21 位元為左側偏移) 調整格式:
overlays:
signed j_imm[21] = imm20[19, 7..0, 8, 18..9], 0b0;
如您所見,疊加層的語法支援在 欄位。此外,如果未使用欄位名稱,則 編號是指指令文字本身,因此上述指令也可以是 寫成:
signed j_imm[21] = [31, 19..12, 20, 30..21], 0b0;
最後,跳轉與連結 (註冊) 會使用以前的 I 型格式 像是剛才說過,即便 VM 正在運作 您還是能變更 VM 可用性政策
I-Type 立即格式:
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|
| 12 | 5 | 3 | 5 | 7 |
| imm12 | rs1 | func3 | 日 | 運算程式碼 |
這次不用變更格式。
需要新增的分支版本指示如下:
beq- 分支版本 (如果相等)。bge- 大於或等於分支版本。bgeu- 大於或等於未簽署的分支版本。blt- 所屬的分支版本,bltu- 分支版本 (如果小於未簽署文件)。bne- 否則為分支版本。
這些程式碼的編碼方式如下:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|---|---|---|
| imm7 | rs2 | rs1 | 000 | imm5 | 110 0011 | Beq |
| imm7 | rs2 | rs1 | 101 | imm5 | 110 0011 | Bge |
| imm7 | rs2 | rs1 | 111 | imm5 | 110 0011 | Bgeu |
| imm7 | rs2 | rs1 | 100 | imm5 | 110 0011 | blt |
| imm7 | rs2 | rs1 | 110 | imm5 | 110 0011 | bltu |
| imm7 | rs2 | rs1 | 001 | imm5 | 110 0011 | 胸部 |
| func3 | 運算程式碼 |
jal 指令的編碼方式如下:
| 12 月 31 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|
| imm20 | 日 | 110 1111 | Jal |
| 運算程式碼 |
jalr 指令的編碼方式如下:
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode_name |
|---|---|---|---|---|---|
| imm12 | rs1 | 000 | 日 | 110 0111 | jalr |
| func3 | 運算程式碼 |
請繼續進行變更,然後開始建構。檢查產生的輸出內容。只要 您可以先檢查 riscv32i.bin_fmt。
新增商店操作說明
商店指示使用 S-Type 編碼,與 B-Type 相同
分支指令所使用的編碼 (除了
可立即上手我們選擇加入 SType 格式,以便與 RiscV 保持一致
說明文件。
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 |
|---|---|---|---|---|---|
| 7 | 5 | 5 | 3 | 5 | 7 |
| imm7 | rs2 | rs1 | func3 | imm5 | 運算程式碼 |
使用 SType 格式時,最立即是直觀的
前向串連兩個直接欄位,因此疊加層規格
就是:
overlays:
signed s_imm[12] = imm7, imm5;
請注意,串連整個欄位時,不需要位元範圍指定碼。
商店指示的編碼方式如下:
| 2025 年 31 月 31 日 | 2020 年 24 月 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode 名稱 |
|---|---|---|---|---|---|---|
| imm7 | rs2 | rs1 | 000 | imm5 | 010 0011 | sb |
| imm7 | rs2 | rs1 | 001 | imm5 | 010 0011 | 淺睡 |
| imm7 | rs2 | rs1 | 010 | imm5 | 010 0011 | sw |
| func3 | 運算程式碼 |
請繼續進行變更,然後開始建構。檢查產生的輸出內容。只要 您可以先檢查 riscv32i.bin_fmt。
新增負載指示
載入指示使用 I-Type 格式。因此不需要在該處進行任何變更。
編碼方式如下:
| 2020 年 3 月 31 日 | 19:15 | 14 月 12 日 | 11..7 | 6..0 版 | opcode_name |
|---|---|---|---|---|---|
| imm12 | rs1 | 000 | 日 | 000 0011 | 英磅 |
| imm12 | rs1 | 100 | 日 | 000 0011 | 磅 |
| imm12 | rs1 | 001 | 日 | 000 0011 | 赫 |
| imm12 | rs1 | 101 | 日 | 000 0011 | lhu |
| imm12 | rs1 | 010 | 日 | 000 0011 | lw |
| func3 | 運算程式碼 |
請繼續進行變更,然後開始建構。檢查產生的輸出內容。只要 您可以先檢查 riscv32i.bin_fmt。
教學課程到此結束,希望對您有所幫助。