วัตถุประสงค์ของบทแนะนำนี้ได้แก่
- เรียนรู้โครงสร้างและไวยากรณ์ของไฟล์คำอธิบายรูปแบบไบนารี
- เรียนรู้ว่าคำอธิบายรูปแบบไบนารีตรงกับคำอธิบาย ISA อย่างไร
- เขียนคำอธิบายไบนารีสำหรับชุดย่อยของคำสั่ง RiscV RV32I
ภาพรวม
การเข้ารหัสคำสั่งไบนารีของ RiscV
การเข้ารหัสการสอนแบบไบนารีเป็นวิธีมาตรฐานในการเข้ารหัสคำสั่งสำหรับ ในไมโครโปรเซสเซอร์ ซึ่งปกติแล้วจะจัดเก็บอยู่ในไฟล์ปฏิบัติการ มักอยู่ในรูปแบบ ELF วิธีการอาจเป็นความกว้างคงที่หรือแปรผันก็ได้ ความกว้าง
โดยทั่วไป วิธีการจะใช้รูปแบบการเข้ารหัสกลุ่มเล็กๆ โดยแต่ละรูปแบบ ที่ปรับแต่งสำหรับประเภทคำสั่งที่เข้ารหัส ตัวอย่างเช่น ลงทะเบียน-ลงทะเบียน อาจใช้รูปแบบเดียวที่จะเพิ่มจำนวน opcode ที่ใช้ได้ คำแนะนำในการลงทะเบียนทันที ให้ใช้วิธีอื่นที่ลดจำนวน รหัส opcode ที่ใช้ได้สำหรับการเพิ่มขนาดของทันทีที่สามารถเข้ารหัส วิธีการกำหนดสาขาและการข้ามมักจะใช้รูปแบบที่เพิ่มขนาดให้ใหญ่สุด ทันทีเพื่อรองรับสาขาที่มีการชดเชยที่มากขึ้น
รูปแบบการสอนที่ใช้โดยคำสั่งที่เราต้องการถอดรหัสใน RiscV เครื่องมือจำลองมีดังต่อไปนี้
รูปแบบ R-Type ที่ใช้สำหรับคำแนะนำในการลงทะเบียน:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | rs2 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ I-Type ที่ใช้สำหรับคำแนะนำในการลงทะเบียน คำแนะนำในการโหลด และ
คำสั่ง jalr
ทันที 12 บิต
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ I-Type เฉพาะทาง ใช้สำหรับกะการทำงานพร้อมคำสั่งได้ทันที 5 บิต ทันที:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ U-Type ใช้สำหรับคำสั่งแบบยาวทันที (lui
, auipc
) 20 บิต
ทันที:
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
uimm20 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ B-Type ที่ใช้สำหรับ Branch แบบมีเงื่อนไข 12 บิตทันที
31 | 30..25 | 24..20 | 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 | 30..21 | 20 | 19..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
1 | 10 | 1 | 8 | 5 | 7 |
หนู | หนู | หนู | หนู | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ S-Type ที่ใช้สำหรับวิธีการของร้านค้า ใช้กับการตั้งค่า 12 บิตทันที
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
หนู | rs2 | rs1 | func3 | หนู | รหัสดำเนินการ |
จากรูปแบบเหล่านี้ คุณจะเห็นคำแนะนำเหล่านี้ทั้งหมดมีความยาว 32 บิต 7 บิตต่ำๆ ในแต่ละรูปแบบคือฟิลด์ opcode โปรดทราบด้วยว่า รูปแบบหลายๆ รูปแบบมีขนาดเท่ากันในทันที โดยบิตของรูปแบบจะมาจาก ส่วนต่างๆ ของการสอน จะเห็นได้ว่าเครื่องมือถอดรหัสแบบไบนารี รูปแบบที่กำหนด สามารถแสดงสิ่งนี้ได้
คำอธิบายการเข้ารหัสแบบไบนารี
การเข้ารหัสแบบไบนารีของคำสั่งจะแสดงในรูปแบบไบนารี
(.bin_fmt
) ไฟล์คำอธิบาย โดยจะอธิบายการเข้ารหัสแบบไบนารีของ
ใน ISA เพื่อถอดรหัสคำสั่งในรูปแบบไบนารี
ที่สร้างขึ้น ตัวถอดรหัสที่สร้างขึ้นจะกำหนด opcode และแยกค่าของ
ตัวถูกดำเนินการและฟิลด์ที่ทันท่วงที เพื่อให้ข้อมูลที่จำเป็นสำหรับ ISA
โปรแกรมถอดรหัสแบบไม่ต้องพึ่งการเข้ารหัสซึ่งอธิบายไว้ในบทแนะนำก่อนหน้านี้
ในบทแนะนำนี้ เราจะเขียนไฟล์คำอธิบายการเข้ารหัสแบบไบนารีสำหรับกลุ่มย่อย คำสั่งของ RiscV32I ที่จำเป็นต่อการจำลองคำสั่งที่ใช้ใน "สวัสดีโลก" ขนาดเล็ก ของโปรแกรม สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ 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
และ
ข้อมูลเพิ่มเติมอีก 4 ประเภท รายการแรกคือ namespace
ซึ่งกำหนด
เนมสเปซที่จะวางโค้ดที่สร้างขึ้น อย่างที่สอง ฟิลด์
opcode_enum
ซึ่งเป็นชื่อของประเภทการระบุ opcode ที่สร้างขึ้น
โดยตัวถอดรหัส ISA ควรมีการอ้างอิงภายในโค้ดที่สร้างขึ้น ข้อ 3
includes {}
ระบุไฟล์ที่จำเป็นสำหรับโค้ดที่สร้างขึ้นสำหรับ
ตัวถอดรหัสนี้
ในกรณีของเรา นี่คือไฟล์ที่ตัวถอดรหัส ISA สร้างขึ้นจาก
บทแนะนำก่อนหน้า
ระบุไฟล์ที่รวมเพิ่มเติมได้ใน includes {}
ที่มีขอบเขตรวมทั้งหมด
ของเรา วิธีนี้มีประโยชน์หากมีการกำหนดตัวถอดรหัสไว้หลายตัวและทุกตัวต้องการ
ให้รวมไฟล์เดียวกันบางไฟล์ไว้ด้วย รายการที่ 4 เป็นรายการคำสั่ง
กลุ่มที่ประกอบขึ้นเป็นคำสั่งสำหรับสร้างตัวถอดรหัส ใน
แต่มีแค่ RiscVInst32
เท่านั้น
ต่อไปคือคำจำกัดความรูปแบบ 3 รูปแบบ คำแนะนำเหล่านี้ไม่เหมือนกัน รูปแบบสำหรับคำที่เป็นคำแนะนำแบบ 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];
};
รายการแรกกำหนดรูปแบบการสอนแบบกว้าง 32 บิตชื่อ Inst32Format
ซึ่งมี
2 ฟิลด์: bits
(กว้าง 25 บิต) และ opcode
(กว้าง 7 บิต) แต่ละช่อง
unsigned
ซึ่งหมายความว่าค่าจะขยายเป็น 0 เมื่อแยกค่าออกมา
และวางไว้ในประเภทจำนวนเต็ม C++ ผลรวมของความกว้างบิตฟิลด์ต้อง
เท่ากับความกว้างของรูปแบบ เครื่องมือจะสร้างข้อผิดพลาดหากมี
ความเห็นไม่ตรงกัน รูปแบบนี้ไม่ได้มาจากรูปแบบอื่นๆ ดังนั้นจึงเป็น
ถือเป็นรูปแบบระดับบนสุด
รายการที่ 2 กำหนดรูปแบบคำสั่งแบบกว้าง 32 บิตชื่อ IType
ที่มาจาก
จาก Inst32Format
ทำให้ 2 รูปแบบนี้เกี่ยวข้องกัน รูปแบบมี 5
ฟิลด์: imm12
, rs1
, func3
, rd
และ opcode
ช่อง imm12
คือ
signed
ซึ่งหมายความว่าค่าจะมีเครื่องหมายขยายออกเมื่อค่าเป็น
ดึงข้อมูลและวางไว้ในประเภทจำนวนเต็ม C++ โปรดทราบว่า IType.opcode
ทั้งคู่มี
แอตทริบิวต์ที่มีลายเซ็น/ไม่มีการรับรองเดียวกัน และอ้างถึงบิตของ Word ในวิธีเดียวกัน
ด้วยชื่อ Inst32Format.opcode
รูปแบบที่ 3 คือรูปแบบที่กำหนดเองซึ่งใช้โดย 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]
, ชื่อของ
ประเภทการระบุ opcode ที่จะใช้ "OpcodeEnum"
และคำแนะนำพื้นฐาน
ประเภทการระบุ opcode ควรเป็นประเภทเดียวกันกับที่สร้างโดย
ตัวถอดรหัสคำสั่งอิสระในรูปแบบที่ครอบคลุมในบทแนะนำเกี่ยวกับ ISA
ตัวถอดรหัส
คำอธิบายการเข้ารหัสวิธีการแต่ละรายการประกอบด้วย 3 ส่วนดังนี้
- ชื่อรหัสการดำเนินการ ซึ่งต้องเป็นชื่อเดียวกับที่ใช้ในวิธีการ คำอธิบายตัวถอดรหัสเพื่อให้เครื่องมือทั้งสอง ทำงานร่วมกัน
- รูปแบบคำสั่งที่ใช้สำหรับรหัสการดำเนินการ นี่คือรูปแบบที่ ที่ใช้เพื่อตอบสนองการอ้างอิงไปยังบิตฟิลด์ในส่วนสุดท้าย
- รายการค่าจำกัดฟิลด์บิตที่คั่นด้วยคอมมา,
==
,!=
,<
,<=
,>
และ>=
ทั้งหมดนั้นต้องเป็นจริงเพื่อให้ opcode ถึงจะจับคู่ ข้อความคำสั่ง
โปรแกรมแยกวิเคราะห์ .bin_fmt
จะใช้ข้อมูลทั้งหมดนี้ในการสร้างตัวถอดรหัสที่มีลักษณะดังนี้
- มีฟังก์ชันการดึงข้อมูล (มีลายเซ็น/ไม่ลงนาม) ตามความเหมาะสมสำหรับแต่ละบิต
ในทุกรูปแบบ ฟังก์ชันเครื่องมือแยกข้อมูลจะอยู่ในเนมสเปซ
ตั้งชื่อตามชื่อรูปแบบเวอร์ชัน Snake-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.h
riscv32i_bin_decoder.cc
ไฟล์ส่วนหัวที่สร้างขึ้น (.h)
เปิด riscv32i_bin_decoder.h
ส่วนแรกของไฟล์มีมาตรฐาน
Boilerplate Guard รวมถึงการประกาศเนมสเปซ ต่อจากนั้น
มีฟังก์ชันตัวช่วยแบบเทมเพลตในเนมสเปซ internal
ฟังก์ชันนี้
ใช้ในการดึงฟิลด์บิตจากรูปแบบที่ยาวเกินไปสำหรับ C++ 64 บิต
จำนวนเต็ม
#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
ถัดจากส่วนแรกจะมีชุดเนมสเปซ 3 รายการ แต่ละรายการสำหรับ
ของการประกาศ format
รายการในไฟล์ riscv32i.bin_fmt
:
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
ฟังก์ชันอีก 3 รายการประกอบด้วย
ตัวถอดรหัสที่สร้างขึ้น ตัวถอดรหัสโดยรวมจะทำงานตามลำดับชั้น ชุด
ของบิตในคำแนะนำ จะได้รับการคำนวณเพื่อแยกความแตกต่างระหว่าง
แสดงเป็นกลุ่มของคำสั่งที่ระดับบนสุด องค์ประกอบเหล่านี้ไม่จำเป็นต้อง
ต่อเนื่องกัน จำนวนบิตจะกำหนดขนาดของตารางตรวจสอบ
สร้างขึ้นด้วยฟังก์ชันตัวถอดรหัสระดับที่ 2 เราจะเห็นกันในอีก
ของไฟล์
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
รูปแบบ:
31..25 | 24..20 | 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.
การเข้ารหัสมีดังนี้
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | ชื่อ opcode |
---|---|---|---|---|---|---|
000,0000 | rs2 | rs1 | 000 | ปุ่มเลือก | 011 0011 | เพิ่ม |
000,0000 | rs2 | rs1 | 111 | ปุ่มเลือก | 011 0011 | และ |
000,0000 | rs2 | rs1 | 110 | ปุ่มเลือก | 011 0011 | หรือ |
000,0000 | rs2 | rs1 | 001 | ปุ่มเลือก | 011 0011 | Sll |
000,0000 | rs2 | rs1 | 011 | ปุ่มเลือก | 011 0011 | Sltu |
010 0000 | rs2 | rs1 | 000 | ปุ่มเลือก | 011 0011 | สำรอง |
000,0000 | rs2 | rs1 | 100 | ปุ่มเลือก | 011 0011 | Xor |
func7 | func3 | รหัสดำเนินการ |
เพิ่มคำจำกัดความคำสั่งเหล่านี้ก่อนคำสั่งอื่นๆ ใน
กลุ่มวิธีการ RiscVInst32
สตริงไบนารีจะถูกระบุด้วยเครื่องหมายนำหน้า
คำนำหน้า 0b
(คล้ายกับ 0x
สำหรับเลขฐานสิบหก) เพื่อให้คุณสามารถ
อ่านสตริงยาวของเลขฐานสอง คุณสามารถแทรกเครื่องหมายคำพูดเดี่ยว '
เป็น
ตัวคั่นหลักที่คุณเห็นพอดี
คำจำกัดความแต่ละคำสั่งจะมีข้อจำกัด 3 ประการ ได้แก่
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];
}
ในฟังก์ชันนี้ ระบบจะสร้างตารางถอดรหัสแบบคงที่ และค่าการค้นหาคือ ดึงข้อมูลจากคำที่แนะนำเพื่อเลือกดัชนีที่เหมาะสม ซึ่งจะเพิ่ม ชั้นที่ 2 ในลำดับชั้นตัวถอดรหัสคำสั่ง แต่เนื่องจาก opcode สามารถ ก็ดูได้โดยตรงในตาราง โดยไม่มีการเปรียบเทียบเพิ่มเติม ในบรรทัดนี้ ใหม่ แทนที่จะเป็นการเรียกใช้ฟังก์ชันอื่น
เพิ่มคำสั่ง ALU ทันที
วิธีการชุดถัดไปที่เราจะเพิ่มคือคำสั่ง ALU ที่ใช้องค์ประกอบ แทนการจดทะเบียนอย่างใดอย่างหนึ่ง ซึ่งจะมีอยู่ 3 กลุ่ม คำสั่ง (ขึ้นอยู่กับฟิลด์ที่อยู่ติดกัน): คำสั่ง I-Type แบบทันที ด้วยการลงชื่อ 12 บิตทันที คำสั่ง I-Type เฉพาะในทันที สำหรับกะ และ U-Type ทันที โดยมีค่าทันทีแบบไม่ลงชื่อแบบ 20 บิต รูปแบบมีดังนี้
รูปแบบ I-Type ทันที:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ I-Type เฉพาะทันที:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
รูปแบบ U-Type ทันทีมีดังนี้
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
uimm20 | ปุ่มเลือก | รหัสดำเนินการ |
มีรูปแบบ I-Type อยู่แล้วใน riscv32i.bin_fmt
จึงไม่มีความจำเป็น
ให้เพิ่มรูปแบบนั้น
หากเราเปรียบเทียบรูปแบบ I-Type แบบพิเศษกับรูปแบบ R-Type ที่เรากำหนดไว้
ในแบบฝึกหัดก่อนหน้า เราจะเห็นความแตกต่างเพียงอย่างเดียวคือช่อง rs2
เปลี่ยนชื่อเป็น uimm5
แทนที่จะเพิ่มรูปแบบใหม่ทั้งหมด เราสามารถเสริม
R-Type เราไม่สามารถเพิ่มช่องอีก เพราะเป็นการเพิ่มความกว้างของ
รูปแบบนั้น แต่เราสามารถเพิ่มโฆษณาซ้อนทับ โฆษณาซ้อนทับเป็นชื่อแทนของชุด
บิตในรูปแบบนี้ และสามารถใช้เพื่อรวมหลายลำดับย่อยของ
เป็นเอนทิตีที่มีชื่อแยกต่างหาก ผลข้างเคียงคือโค้ดที่สร้างขึ้น
จะมีฟังก์ชันการแยกสำหรับการวางซ้อนด้วย นอกเหนือจาก
เหล่านั้นโดยตรง ในกรณีนี้ เมื่อทั้ง rs2
และ uimm5
ยกเลิกการลงนาม
ไม่มีความแตกต่างมากนัก เพียงแค่บอกให้ทราบว่าใช้ฟิลด์นี้
โดยทันที หากต้องการเพิ่มการวางซ้อนชื่อ uimm5
ลงในรูปแบบ R-Type ให้เพิ่มพารามิเตอร์
ต่อท้ายฟิลด์สุดท้าย:
overlays:
unsigned uimm5[5] = rs2;
รูปแบบใหม่เดียวที่เราต้องเพิ่มคือรูปแบบ U-Type ก่อนที่เราจะเพิ่มส่วน
เราจะมาพิจารณาคำสั่ง 2 รายการที่ใช้รูปแบบนั้น นั่นคือ auipc
และ
lui
การตั้งค่าทั้ง 2 อย่างนี้จะเปลี่ยนค่า 20 บิตที่เปลี่ยนทันทีให้เหลือ 12 ก่อนที่จะใช้งาน
เพื่อเพิ่ม PC ลงในเครื่อง (auipc
) หรือเขียนลงในเครื่องลงทะเบียนโดยตรง
(lui
) การใช้การวางซ้อนเราสามารถทำให้
เปลี่ยนการคำนวณเล็กน้อยจากการดำเนินการสอนไปเป็นการสอน
ถอดรหัส ก่อนอื่นให้เพิ่มรูปแบบตามช่องที่ระบุไว้ในตาราง
ที่ด้านบน จากนั้นเราสามารถเพิ่มการวางซ้อนต่อไปนี้
overlays:
unsigned uimm32[32] = uimm20, 0b0000'0000'0000;
ไวยากรณ์การวางซ้อนอนุญาตให้เราเชื่อมต่อ ไม่เพียงแต่ช่อง แต่รวมถึงลิเทอรัลเป็น ในกรณีนี้จะต่อเลขศูนย์ 12 ตัวเข้าด้วยกัน แล้วเลื่อนไปทางซ้าย ภายในวันที่ 12
คำสั่ง I-Type ที่เราต้องเพิ่ม ได้แก่
addi
- เพิ่มทันทีandi
- Bitwise และทันทีori
- Bitwise หรือในทันทีxori
- Bitwise xor แบบทันที
การเข้ารหัสมีดังนี้
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | ปุ่มเลือก | 001 0011 | แอดดิ |
imm12 | rs1 | 111 | ปุ่มเลือก | 001 0011 | Andi |
imm12 | rs1 | 110 | ปุ่มเลือก | 001 0011 | Ori |
imm12 | rs1 | 100 | ปุ่มเลือก | 001 0011 | โซรี |
func3 | รหัสดำเนินการ |
คำสั่งประเภท R (ประเภท I-Type เฉพาะทาง) ที่เราต้องเพิ่ม ได้แก่
slli
- เลื่อนไปทางซ้ายอย่างสมเหตุสมผลทันทีsrai
- เลื่อนเลขคณิตด้านขวาทันทีsrli
- เลื่อนไปทางขวาโดยใช้ตรรกะทันที
การเข้ารหัสมีดังนี้
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | ชื่อ opcode |
---|---|---|---|---|---|---|
000,0000 | uimm5 | rs1 | 001 | ปุ่มเลือก | 001 0011 | SLli |
010 0000 | uimm5 | rs1 | 101 | ปุ่มเลือก | 001 0011 | Srai |
000,0000 | uimm5 | rs1 | 101 | ปุ่มเลือก | 001 0011 | Srli |
func7 | func3 | รหัสดำเนินการ |
คำสั่ง U-Type ที่เราต้องเพิ่ม ได้แก่
auipc
- เพิ่มส่วนบนทันทีลงใน PClui
- โหลดด้านบนทันที
การเข้ารหัสมีดังนี้
31..12 | 11..7 | 6..0 | ชื่อ opcode |
---|---|---|---|
uimm20 | ปุ่มเลือก | 001 0111 | auipc |
uimm20 | ปุ่มเลือก | 011 0111 | Lui |
รหัสดำเนินการ |
ทำการเปลี่ยนแปลง แล้วสร้างได้เลย ตรวจสอบเอาต์พุตที่สร้างขึ้น เพียงแค่ ก่อนหน้านี้ คุณสามารถตรวจสอบงานกับ riscv32i.bin_fmt
เพิ่มวิธีการ Branch และข้ามลิงก์
คำสั่งชุดถัดไปที่ต้องกำหนดคือสาขาแบบมีเงื่อนไข คำสั่ง วิธีการข้ามและลิงก์ และการลงทะเบียนการข้ามลิงก์ วิธีการ
สาขาแบบมีเงื่อนไขที่เราเพิ่มทั้งหมดจะใช้การเข้ารหัส B-Type
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm7 | rs2 | rs1 | func3 | imm5 | รหัสดำเนินการ |
แม้ว่าการเข้ารหัส B-Type จะมีเลย์เอาต์เหมือนกับการเข้ารหัสประเภท R
เลือกใช้ประเภทรูปแบบใหม่เพื่อให้สอดคล้องกับเอกสารประกอบของ RiscV
แต่คุณอาจเพิ่มการวางซ้อนเพื่อรับ Branch ที่เหมาะสมก็ได้
การแทนที่ทันที โดยใช้ฟิลด์ func7
และ rd
ของประเภท R
การเข้ารหัส
จำเป็นต้องเพิ่มรูปแบบ BType
ในช่องดังที่ระบุข้างต้น แต่ไม่จำเป็น
เพียงพอ คุณจะเห็นว่า "ทันที" แบ่งออกเป็นช่องคำแนะนำ 2 ช่อง
ยิ่งไปกว่านั้น คำสั่งสำหรับ Branch ไม่ได้ถือเป็นการเชื่อมโยงแบบง่ายของ
ทั้ง 2 ช่อง แต่แต่ละช่องจะมีการแบ่งพาร์ติชันเพิ่มเติม และพาร์ติชันเหล่านี้
ต่อกันในลำดับที่ต่างกัน สุดท้าย ค่านั้นจะเลื่อนไปทางซ้าย
1 ตำแหน่งเพื่อรับค่าออฟเซ็ตแนว 16 บิต
ลำดับของบิตในคำแนะนำที่ใช้เพื่อสร้างค่าทันทีคือ 31,
7, 30..25, 11.8 ซึ่งสอดคล้องกับการอ้างอิงช่องย่อยต่อไปนี้ โดยที่
ดัชนีหรือช่วงจะระบุบิตในฟิลด์โดยเรียงตัวเลขจากขวาไปซ้าย เช่น
imm7[6]
หมายถึง msb ของ imm7
และ imm5[0]
หมายถึง lsb ของ
imm5
imm7[6], imm5[0], imm7[5..0], imm5[4..1]
การทำให้การจัดการบิตนี้เป็นส่วนหนึ่งของคำสั่งของ Branch ด้วยตัวเองมี 2 ค่า
ข้อบกพร่องใหญ่ๆ ประการแรก จะเชื่อมโยงการใช้งานฟังก์ชันความหมายกับ
รายละเอียดในการสอนแบบไบนารี ข้อ 2 เพิ่มระยะเวลารันไทม์
โอเวอร์เฮด คำตอบคือให้เพิ่มการวางซ้อนในรูปแบบ BType
ซึ่งรวมถึง
ต่อท้าย "0" ให้คำนึงถึงฝั่งซ้าย
overlays:
signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0;
โปรดสังเกตว่ามีการทำเครื่องหมายการวางซ้อนแล้ว ดังนั้นจะมีการลงนามแบบเพิ่มเติมโดยอัตโนมัติ เมื่อดึงมาจากคำที่แนะนำ
วิธีการข้ามและลิงก์ (ทันที) ใช้การเข้ารหัสประเภท J ดังนี้
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
imm20 | ปุ่มเลือก | รหัสดำเนินการ |
นี่เป็นรูปแบบง่ายๆ ที่เพิ่มได้ง่ายๆ แต่รูปแบบที่นำไปใช้ได้ทันที วิธีการไม่ได้ตรงไปตรงมาอย่างที่เห็น ลำดับบิตที่ใช้เพื่อ แบบฟอร์มทันทีแบบเต็มคือ: 31, 19..12, 20, 30..21 และสุดท้ายคือ เลื่อนไปทางซ้ายหนึ่งคำเพื่อจัดแนวคำแบบครึ่งคำ วิธีแก้ไขคือให้เพิ่ม ซ้อนทับ (21 บิตเพื่อใช้ Shift ด้านซ้าย) เป็นรูปแบบดังนี้
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-type ตามที่ใช้ ก่อนหน้านี้
รูปแบบ I-Type ทันที:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | ปุ่มเลือก | รหัสดำเนินการ |
ในครั้งนี้ จะไม่มีการเปลี่ยนแปลงใดๆ ที่ต้องทำกับรูปแบบ
วิธีการสำหรับสาขาที่เราต้องเพิ่มมีดังนี้
beq
- สาขาถ้าเท่ากันbge
- สาขาหากมากกว่าหรือเท่ากับbgeu
- สาขา หากมีมากกว่าหรือเท่ากับ ไม่มีเครื่องหมายblt
- สาขา หากน้อยกว่าbltu
- สาขา หากมีน้อยกว่าที่ไม่ได้ลงชื่อbne
- สาขาหากไม่เท่ากัน
โดยมีการเข้ารหัสดังนี้
31..25 | 24..20 | 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 | Bne |
func3 | รหัสดำเนินการ |
คำสั่ง jal
มีการเข้ารหัสดังนี้
31..12 | 11..7 | 6..0 | ชื่อ opcode |
---|---|---|---|
imm20 | ปุ่มเลือก | 110 1111 | Jal |
รหัสดำเนินการ |
คำสั่ง jalr
มีการเข้ารหัสดังนี้
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | ปุ่มเลือก | 110 0111 | Jalr |
func3 | รหัสดำเนินการ |
ทำการเปลี่ยนแปลง แล้วสร้างได้เลย ตรวจสอบเอาต์พุตที่สร้างขึ้น เพียงแค่ ก่อนหน้านี้ คุณสามารถตรวจสอบงานกับ riscv32i.bin_fmt
เพิ่มวิธีการสำหรับร้านค้า
วิธีการของร้านใช้การเข้ารหัส S-Type ซึ่งเหมือนกับ B-Type
ที่ใช้โดยคำสั่ง Branch ยกเว้นองค์ประกอบของ
ทันที เราเลือกเพิ่มรูปแบบ SType
เพื่อให้สอดคล้องกับ RiscV เสมอ
เอกสารประกอบ
31..25 | 24..20 | 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;
โปรดทราบว่าไม่จำเป็นต้องมีตัวระบุช่วงบิตเมื่อจะเชื่อมต่อทั้งช่อง
วิธีการของสโตร์มีการเข้ารหัสดังต่อไปนี้
31..25 | 24..20 | 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 คุณไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ
การเข้ารหัสมีดังนี้
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | ปุ่มเลือก | 000 0011 | lb |
imm12 | rs1 | 100 | ปุ่มเลือก | 000 0011 | ลู |
imm12 | rs1 | 001 | ปุ่มเลือก | 000 0011 | L |
imm12 | rs1 | 101 | ปุ่มเลือก | 000 0011 | Lhu |
imm12 | rs1 | 010 | ปุ่มเลือก | 000 0011 | lw |
func3 | รหัสดำเนินการ |
ทำการเปลี่ยนแปลง แล้วสร้างได้เลย ตรวจสอบเอาต์พุตที่สร้างขึ้น เพียงแค่ ก่อนหน้านี้ คุณสามารถตรวจสอบงานกับ riscv32i.bin_fmt
บทแนะนำนี้จบลงเพียงเท่านี้ เราหวังว่าจะเป็นประโยชน์กับคุณ