Tujuan tutorial ini adalah:
- Mempelajari struktur dan sintaksis file deskripsi format biner.
- Pelajari bagaimana deskripsi format biner sesuai dengan deskripsi ISA.
- Menulis deskripsi biner untuk instruksi RiscV RV32I.
Ringkasan
Encoding petunjuk biner RiscV
Pengkodean instruksi biner adalah cara standar untuk mengenkode instruksi untuk dieksekusi pada mikroprosesor. Mereka biasanya disimpan dalam file yang dapat dieksekusi, biasanya dalam format ELF. Petunjuk dapat berupa lebar tetap atau variabel lebarnya.
Biasanya, instruksi menggunakan satu set format encoding, dengan masing-masing format disesuaikan untuk jenis petunjuk yang dienkode. Misalnya, {i>register-register<i} instruksi dapat menggunakan satu format yang memaksimalkan jumlah opcode yang tersedia, sedangkan instruksi {i>register-immediate<i} menggunakan petunjuk lain yang mengorbankan jumlah opcode yang tersedia untuk meningkatkan ukuran segera yang dapat dienkode. Instruksi cabang dan lompatan hampir selalu menggunakan format yang segera untuk mendukung cabang dengan offset yang lebih besar.
Format instruksi yang digunakan oleh instruksi yang ingin kita dekode di RiscV simulator adalah sebagai berikut:
Format R-Type, digunakan untuk petunjuk pendaftaran-daftar:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | rs2 | rs1 | func3 | rd | kode operasi |
Format I-Type, digunakan untuk instruksi segera pendaftaran, memuat instruksi, dan
instruksi jalr
, segera dalam 12 bit.
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | kode operasi |
Format khusus I-Type, digunakan untuk shift dengan instruksi langsung, 5 bit segera:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | rd | kode operasi |
Format U-Type, digunakan untuk instruksi langsung yang panjang (lui
, auipc
), 20 bit
segera:
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
uimm20 | rd | kode operasi |
Format B-Type, digunakan untuk cabang bersyarat, segera 12-bit.
31 | 30..25 | 24..20 | 19..15 | 14..12 | 11..8 | 7 | 6..0 |
---|---|---|---|---|---|---|---|
1 | 6 | 5 | 5 | 3 | 4 | 1 | 7 |
imm | imm | rs2 | rs1 | func3 | imm | imm | kode operasi |
Format J-Type, digunakan untuk instruksi jal
, 20 bit langsung.
31 | 30..21 | 20 | 19..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
1 | 10 | 1 | 8 | 5 | 7 |
imm | imm | imm | imm | rd | kode operasi |
Format S-Type, digunakan untuk instruksi penyimpanan, 12 bit seketika.
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm | rs2 | rs1 | func3 | imm | kode operasi |
Seperti yang Anda lihat dari format-format ini, semua instruksi ini panjangnya 32 bit, dan 7 bit rendah dalam setiap format adalah isian {i>opcode<i}. Perhatikan juga bahwa meskipun beberapa format memiliki ukuran instan yang sama, bitnya diambil dari bagian-bagian yang berbeda dari instruksi. Seperti yang akan kita lihat, decoder biner dapat menyatakan hal ini.
Deskripsi encoding biner
Pengkodean biner instruksi dinyatakan dalam format biner
(.bin_fmt
). Ini menjelaskan pengkodean biner dari
instruksi dalam ISA sehingga decoder instruksi format biner dapat
dibuat. Decoder yang dihasilkan menentukan opcode, mengekstrak nilai
bidang operand dan langsung, untuk memberikan informasi yang dibutuhkan oleh ISA
decoder agnostik encoding yang dijelaskan dalam tutorial sebelumnya.
Dalam tutorial ini kita akan menulis file deskripsi pengkodean biner untuk subset instruksi RiscV32I yang diperlukan untuk menyimulasikan instruksi yang digunakan dalam "Halo Dunia" kecil program ini. Untuk detail selengkapnya tentang RiscV ISA, lihat Spesifikasi Risc-V{.external}.
Mulailah dengan membuka file:
riscv_bin_decoder/riscv32i.bin_fmt
.
Isi file dibagi menjadi beberapa bagian.
Pertama, definisi 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;
};
Definisi decoder kami menentukan nama decoder RiscV32I
, serta
empat informasi tambahan. Yang pertama adalah namespace
, yang menentukan
namespace tempat kode yang dihasilkan akan ditempatkan. Kedua,
opcode_enum
, yang menyebutkan cara jenis enumerasi opcode yang dihasilkan
oleh decoder ISA harus direferensikan dalam kode yang dihasilkan. Ketiga,
includes {}
menentukan penyertaan file yang diperlukan oleh kode yang dibuat untuk
decoder ini.
Dalam kasus kami, ini adalah file yang dihasilkan oleh decoder ISA dari
tutorial sebelumnya.
File penyertaan tambahan dapat ditentukan di includes {}
dengan cakupan global
definisi. Ini berguna jika beberapa decoder ditentukan, dan semuanya membutuhkan
untuk menyertakan beberapa file yang sama. Keempat adalah daftar
nama-nama instruksi
grup yang membentuk instruksi
untuk membuat decoder. Di
jika hanya ada satu: RiscVInst32
.
Selanjutnya ada tiga definisi format. Keduanya mewakili instruksi yang berbeda format untuk kata instruksi 32-bit yang digunakan oleh instruksi yang sudah ditentukan dalam file.
// 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];
};
Yang pertama menentukan format petunjuk selebar 32 bit bernama Inst32Format
yang memiliki
dua kolom: bits
(lebar 25 bit) dan opcode
(lebar 7 bit). Setiap {i>field<i} memiliki
unsigned
, yang berarti bahwa nilai akan diperluas dari nol saat nilai tersebut diekstrak
dan ditempatkan dalam tipe integer C++. Jumlah lebar bitfield harus
sama dengan lebar format. Alat ini akan menghasilkan pesan {i>error<i} jika ada
perbedaan pendapat. Format ini tidak berasal dari format lain, sehingga
dianggap sebagai format tingkat atas.
Yang kedua menentukan format petunjuk selebar 32 bit bernama IType
yang memperoleh
dari Inst32Format
, sehingga kedua format tersebut terkait. Formatnya berisi 5
kolom: imm12
, rs1
, func3
, rd
, dan opcode
. Kolom imm12
signed
, yang berarti nilai tersebut akan di-sign-extended saat nilainya
diekstrak dan ditempatkan dalam
tipe integer C++. Perhatikan bahwa IType.opcode
keduanya memiliki
atribut bertanda tangan/tidak bertanda tangan yang sama dan mengacu pada bit kata instruksi yang sama
sebagai Inst32Format.opcode
.
Format ketiga adalah format kustom yang hanya digunakan oleh fence
instruksi, yang merupakan instruksi yang sudah ditentukan dan kita tidak memiliki
Anda khawatirkan dalam tutorial ini.
Poin utama: Gunakan kembali nama kolom dalam berbagai format terkait selama nama tersebut mewakili bit yang sama dan memiliki atribut bertanda tangan/tidak bertanda tangan yang sama.
Setelah definisi format di riscv32i.bin_fmt
muncullah grup petunjuk
definisi. Semua instruksi dalam grup instruksi harus memiliki
bit panjang, dan menggunakan format yang berasal (mungkin secara tidak langsung) dari sumber
format petunjuk tingkat atas. Ketika ISA dapat memiliki instruksi dengan
panjang, grup instruksi yang berbeda
digunakan untuk setiap panjang. Selain itu,
jika dekode ISA target bergantung pada mode eksekusi, seperti Arm vs. Thumb
instruksi terpisah diperlukan untuk setiap mode. Tujuan
Parser bin_fmt
menghasilkan decoder biner untuk setiap grup petunjuk.
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;
};
Grup petunjuk menentukan nama RiscV32I
, lebar [32]
, nama
jenis enumerasi opcode untuk menggunakan "OpcodeEnum"
, dan petunjuk dasar
format font. Jenis enumerasi opcode harus sama dengan yang dihasilkan oleh
decoder instruksi independen format yang dibahas dalam tutorial tentang ISA
decoder.
Setiap deskripsi encoding petunjuk terdiri dari 3 bagian:
- Nama opcode, yang harus sama dengan yang digunakan dalam petunjuk deskripsi decoder agar keduanya dapat bekerja sama.
- Format petunjuk yang akan digunakan untuk opcode. Inilah format yang digunakan untuk memenuhi referensi ke bitfield di bagian akhir.
- Daftar batasan kolom bit yang dipisahkan koma,
==
,!=
,<
,<=
,>
, dan>=
bahwa semua harus benar agar kode operasi berhasil mencocokkan dengan kata instruksi.
Parser .bin_fmt
menggunakan semua informasi ini untuk membuat decoder yang:
- Menyediakan fungsi ekstraksi (bertanda/tidak bertanda tangan) yang sesuai untuk setiap bit
di setiap format. Fungsi ekstraktor ditempatkan di namespace
yang dinamakan oleh versi {i>
snake-case<i} dari nama format. Misalnya,
fungsi ekstraktor untuk format
IType
ditempatkan dalam namespacei_type
. Setiap fungsi ekstraktor dideklarasikan sebagaiinline
, mengambiluint_t
terkecil jenis yang memiliki lebar format, dan menampilkanint_t
tersempit (untuk jenis yang ditandatangani),uint_t
(untuk yang tidak ditandatangani), yang menyimpan kolom yang diekstrak lebarnya. Mis.:
inline uint8_t ExtractOpcode(uint32_t value) {
return value & 0x7f;
}
- Fungsi dekode untuk setiap grup petunjuk. Metode ini mengembalikan nilai jenis
OpcodeEnum
, dan mengambil jenisuint_t
tersempit yang memiliki lebar format grup instruksi.
Menjalankan build awal
Ubah direktori ke riscv_bin_decoder
dan build project menggunakan
perintah berikut:
$ cd riscv_bin_decoder
$ bazel build :all
Sekarang ubah direktori Anda kembali ke
root repositori, lalu mari kita lihat
pada sumber yang dibuat. Untuk itu, ubah
direktori ke
bazel-out/k8-fastbuild/bin/riscv_bin_decoder
(dengan asumsi Anda menggunakan x86
{i>host<i} - untuk {i>host<i} lain, k8-fastbuild akan menjadi string lain).
$ cd ..
$ cd bazel-out/k8-fastbuild/bin/riscv_bin_decoder
riscv32i_bin_decoder.h
riscv32i_bin_decoder.cc
File header yang dihasilkan (.h)
Buka riscv32i_bin_decoder.h
. Bagian pertama dari file
berisi daftar
perlindungan boilerplate, termasuk file, deklarasi namespace. Setelah itu
terdapat fungsi bantuan dengan template dalam namespace internal
. Fungsi ini
digunakan untuk mengekstrak {i>field<i} bit dari format yang terlalu panjang untuk muat dalam C++ 64-bit
bilangan bulat.
#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
Setelah bagian awal, terdapat kumpulan tiga namespace, masing-masing
dari deklarasi format
dalam file riscv32i.bin_fmt
:
namespace fence {
...
} // namespace fence
namespace i_type {
...
} // namespace i_type
namespace inst32_format {
...
} // namespace inst32_format
Dalam setiap namespace ini, fungsi ekstraksi bitfield inline
untuk setiap isian bit dalam
format itu telah ditentukan. Selain itu, format dasar
duplikasi fungsi ekstraksi dari format turunan yang
1) nama {i>field<i} hanya muncul dalam satu nama {i>field<i}, atau 2) yang
nama {i>field<i} mengacu pada jenis {i>field<i} yang sama (posisi bertanda/tidak bertanda tangan dan bit)
dalam setiap format kemunculannya. Hal ini memungkinkan isian bit{i> <i}
yang mendeskripsikan
bit yang akan diekstrak menggunakan fungsi dalam namespace format tingkat atas.
Fungsi dalam namespace i_type
ditampilkan di bawah ini:
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
Terakhir, deklarasi fungsi dari fungsi decoder untuk instruksi
grup RiscVInst32
dideklarasikan. Dibutuhkan 32 bit tanpa
tandatangan sebagai nilai dari
kata petunjuk dan menampilkan anggota class enumerasi OpcodeEnum
yang cocok, atau OpcodeEnum::kNone
jika tidak ada kecocokan.
OpcodeEnum DecodeRiscVInst32(uint32_t inst_word);
File Sumber yang dihasilkan (.cc)
Sekarang buka riscv32i_bin_decoder.cc
. Bagian pertama
dari {i>file<i} berisi
deklarasi #include
dan namespace, diikuti dengan fungsi decoder
deklarasi:
#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
digunakan untuk tindakan dekode kosong, yaitu yang
yang menampilkan OpcodeEnum::kNone
. Tiga fungsi lainnya membentuk
decoder yang dihasilkan. Keseluruhan decoder bekerja secara hierarkis. Satu set
bit dalam kata instruksi dihitung
untuk membedakan antara
petunjuk atau kelompok petunjuk di tingkat atas. Bit tersebut tidak perlu
berdekatan. Jumlah bit menentukan
ukuran tabel pemeta yang
diisi dengan fungsi decoder tingkat kedua. Hal ini terlihat dalam
bagian dari file:
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,
...
};
Terakhir, fungsi decoder ditentukan:
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;
}
Dalam hal ini, di mana hanya ada 4 instruksi yang didefinisikan, hanya ada satu tingkat dekode dan tabel pencarian yang sangat renggang. Seperti petunjuk struktur decoder akan berubah dan jumlah level di hierarki tabel decoder akan meningkat.
Tambahkan petunjuk ALU daftar-daftar
Sekarang saatnya menambahkan beberapa petunjuk baru ke file riscv32i.bin_fmt
. Tujuan
kelompok instruksi pertama adalah instruksi
daftar-daftar ALU seperti
add
, and
, dll. Di RiscV32, semuanya menggunakan instruksi biner jenis R
format:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | rs2 | rs1 | func3 | rd | kode operasi |
Hal pertama yang perlu kita lakukan adalah menambahkan format. Silakan buka
riscv32i.bin_fmt
di editor favorit Anda. Tepat setelah Inst32Format
memungkinkan
tambahkan format bernama RType
yang berasal dari Inst32Format
. Semua bidang bit
dalam RType
adalah unsigned
. Gunakan nama, lebar bit, dan urutan (kiri ke kanan)
dari tabel di atas untuk menentukan format. Jika Anda butuh petunjuk, atau ingin melihat
solusi lengkap,
klik di sini.
Selanjutnya, kita perlu menambahkan instruksi. Petunjuknya adalah:
add
- penambahan bilangan bulat.and
- bitwise dan.or
- bitwise atau.sll
- geser ke kiri logis.sltu
- menetapkan lebih kecil dari, tidak ditandatangani.sub
- pengurangan bilangan bulat.xor
- bitwise xor.
Encodingnya adalah:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | nama opcode |
---|---|---|---|---|---|---|
000 0000 | rs2 | rs1 | 000 | rd | 011 0011 | tambahkan |
000 0000 | rs2 | rs1 | 111 | rd | 011 0011 | dan |
000 0000 | rs2 | rs1 | 110 | rd | 011 0011 | atau |
000 0000 | rs2 | rs1 | 001 | rd | 011 0011 | sll |
000 0000 | rs2 | rs1 | 011 | rd | 011 0011 | Sltu |
010 0000 | rs2 | rs1 | 000 | rd | 011 0011 | sub |
000 0000 | rs2 | rs1 | 100 | rd | 011 0011 | Xor |
func7 | func3 | kode operasi |
Tambahkan definisi petunjuk ini sebelum instruksi lain dalam
Grup petunjuk RiscVInst32
. String biner ditentukan dengan awalan
awalan 0b
(mirip dengan 0x
untuk angka heksadesimal). Untuk memudahkan
membaca string digit biner yang panjang, Anda juga dapat memasukkan tanda kutip tunggal '
sebagai
pemisah digit sesuai pilihan Anda.
Masing-masing definisi petunjuk ini akan memiliki tiga batasan, yaitu pada
func7
, func3
, dan opcode
. Untuk semua kecuali sub
, batasan func7
akan
menjadi:
func7 == 0b000'0000
Batasan func3
bervariasi di sebagian besar petunjuk. Untuk add
dan
sub
itu:
func3 == 0b000
Batasan opcode
untuk setiap petunjuk ini sama:
opcode == 0b011'0011
Jangan lupa untuk mengakhiri setiap baris dengan titik koma ;
.
Solusi akhirnya adalah di sini.
Sekarang lanjutkan dan bangun project Anda seperti sebelumnya, lalu buka project
File riscv32i_bin_decoder.cc
. Anda akan melihat bahwa fungsi decoder tambahan
dibuat untuk menangani instruksi baru. Sebagian besar
mirip dengan yang telah dibuat sebelumnya. Namun, perhatikan
DecodeRiscVInst32_0_c
yang digunakan untuk dekode 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];
}
Dalam fungsi ini, ada tabel dekode statis yang dihasilkan, dan nilai pencariannya yang diekstrak dari kata instruksi untuk memilih indeks yang sesuai. Tindakan ini menambahkan lapisan kedua dalam hierarki decoder instruksi, tetapi karena opcode dapat berupa mencari langsung dalam tabel tanpa perbandingan lebih lanjut, ini adalah contoh fungsi yang merupakan kebalikan dari memerlukan panggilan fungsi lain.
Tambahkan petunjuk ALU dengan langsung
Rangkaian petunjuk berikutnya yang akan kita tambahkan adalah instruksi ALU yang menggunakan nilai langsung alih-alih salah satu register. Ada tiga kelompok instruksi (berdasarkan bidang langsung): instruksi langsung I-Type dengan segera ditandatangani 12 bit, instruksi langsung I-Type khusus untuk shift, dan jenis U-Type langsung, dengan nilai langsung 20-bit yang tidak ditandatangani. Format tersebut ditunjukkan di bawah ini:
Format langsung I-Type:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | kode operasi |
Format langsung I-Type khusus:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | rd | kode operasi |
Format langsung U-Type:
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
uimm20 | rd | kode operasi |
Format I-Type sudah ada di riscv32i.bin_fmt
, jadi tidak perlu
menambahkan format tersebut.
Jika kita membandingkan format I-Type khusus dengan format R-Type yang kita tentukan
latihan sebelumnya, kita melihat bahwa satu-satunya perbedaan adalah kolom rs2
diganti namanya menjadi uimm5
. Daripada menambahkan format baru, kita dapat meningkatkan
format R-Type. Kita tidak dapat menambahkan isian lain, karena itu akan menambah lebar
formatnya, tetapi kita dapat menambahkan overlay. Overlay adalah alias untuk serangkaian
bit dalam formatnya, dan dapat digunakan untuk
menggabungkan beberapa suburutan dari
ke dalam entitas bernama terpisah. Efek sampingnya adalah kode yang dihasilkan
kini juga akan menyertakan fungsi ekstraksi untuk overlay, selain
{i>field <i}untuk
{i>field <i}itu. Dalam hal ini, jika rs2
dan uimm5
tidak ditandatangani,
tidak membuat banyak perbedaan kecuali untuk membuatnya eksplisit bahwa {i>field<i} tersebut digunakan
secara langsung. Untuk menambahkan overlay bernama uimm5
ke format R-Type, tambahkan
setelah kolom terakhir:
overlays:
unsigned uimm5[5] = rs2;
Satu-satunya format baru yang perlu kita tambahkan adalah format U-Type. Sebelum kita menambahkan
mari kita pertimbangkan dua petunjuk yang menggunakan format tersebut: auipc
dan
lui
. Keduanya menggeser nilai langsung 20-bit yang tersisa sebesar 12 sebelum menggunakannya
untuk menambahkan PC ke dalamnya (auipc
) atau menulisnya langsung ke register
(lui
). Dengan menggunakan {i>overlay<i}, kita dapat menyediakan
versi {i>pre-shifted<i} dari
mengalihkan sedikit komputasi dari
eksekusi instruksi ke instruksi
melakukan dekode. Pertama, tambahkan format sesuai dengan kolom yang ditentukan dalam tabel
di atas. Kemudian, kita dapat menambahkan overlay berikut:
overlays:
unsigned uimm32[32] = uimm20, 0b0000'0000'0000;
{i>Syntax<i} overlay memungkinkan kita menggabungkan, tidak hanya {i>field<i}, tetapi juga literal seperti ya. Dalam hal ini kita menggabungkannya dengan 12 angka nol, yang efeknya menggeser ke kiri dengan 12 tahun.
Instruksi I-Type yang perlu kita tambahkan adalah:
addi
- Tambahkan langsung.andi
- Bitwise dan dengan segera.ori
- Bitwise atau dengan segera.xori
- Bitwise xor dengan segera.
Encodingnya adalah:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 001 0011 | Addi |
imm12 | rs1 | 111 | rd | 001 0011 | Andi |
imm12 | rs1 | 110 | rd | 001 0011 | Ori |
imm12 | rs1 | 100 | rd | 001 0011 | Xori |
func3 | kode operasi |
Instruksi {i>R-Type<i} (I-Type khusus) yang perlu kita tambahkan adalah:
slli
- Beralih ke logika kiri dengan segera.srai
- Menggeser aritmetika kanan dengan seketika.srli
- Beralih ke logika kanan secara langsung.
Encodingnya adalah:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | nama opcode |
---|---|---|---|---|---|---|
000 0000 | uimm5 | rs1 | 001 | rd | 001 0011 | Slli |
010 0000 | uimm5 | rs1 | 101 | rd | 001 0011 | Srai |
000 0000 | uimm5 | rs1 | 101 | rd | 001 0011 | Srli |
func7 | func3 | kode operasi |
Instruksi U-Type yang perlu kita tambahkan adalah:
auipc
- Menambahkan bagian atas segera ke pc.lui
- Memuat langsung bagian atas.
Encodingnya adalah:
31..12 | 11..7 | 6..0 | nama opcode |
---|---|---|---|
uimm20 | rd | 001 0111 | auipc |
uimm20 | rd | 011 0111 | lui |
kode operasi |
Lanjutkan membuat perubahan, lalu bangun. Periksa output yang dihasilkan. Hanya seperti sebelumnya, Anda dapat memeriksa pekerjaan Anda dengan riscv32i.bin_fmt.
Menambahkan petunjuk cabang dan lompat dan tautkan
Rangkaian petunjuk berikutnya yang perlu ditentukan adalah cabang bersyarat instruksi {i> jump-and-link<i}, dan register lompat dan tautan, instruksi.
Cabang bersyarat yang kita tambahkan semuanya menggunakan encoding Jenis B.
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm7 | rs2 | rs1 | func3 | imm5 | kode operasi |
Meskipun pengkodean Tipe-B identik dalam tata letak dengan pengkodean {i>R-Type<i}, kita
memilih untuk menggunakan jenis format baru
agar selaras dengan dokumentasi RiscV.
Tetapi Anda juga dapat menambahkan overlay untuk mendapatkan cabang yang sesuai
perpindahan langsung, menggunakan kolom func7
dan rd
dari R-Type
encoding.
Menambahkan format BType
dengan kolom seperti yang ditentukan di atas diperlukan, tetapi tidak
memadai. Seperti yang dapat Anda lihat, proses langsung dibagi menjadi dua kolom petunjuk.
Selain itu, instruksi cabang tidak memperlakukan
ini sebagai penyambungan sederhana dari
kedua {i>field<i} tersebut. Sebaliknya, setiap isian dipartisi
lebih lanjut, dan partisi-partisi ini
digabungkan dalam
urutan yang berbeda. Akhirnya, nilai itu digeser
ke kiri sebesar
satu untuk mendapatkan offset sejajar 16-bit.
Urutan bit dalam kata instruksi yang digunakan untuk membentuk segera adalah: 31,
7, 30..25, 11..8. Hal ini sesuai dengan referensi sub-bidang berikut, di mana
indeks atau rentang menentukan bit dalam
ruang isian, diberi nomor dari kanan ke kiri, yaitu
imm7[6]
mengacu pada msb dari imm7
, dan imm5[0]
mengacu pada lsb dari
imm5
.
imm7[6], imm5[0], imm7[5..0], imm5[4..1]
Membuat manipulasi bit ini menjadi bagian dari
instruksi cabang itu sendiri memiliki dua
kelemahan besar. Pertama, model ini mengaitkan implementasi fungsi semantik ke
detail dalam representasi instruksi biner. Kedua, penambahan waktu proses
overhead. Jawabannya adalah menambahkan overlay ke format BType
, termasuk
akhir '0' untuk memperhitungkan
pergeseran kiri.
overlays:
signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0;
Perhatikan bahwa overlay ditandatangani, sehingga akan otomatis ditandatangani juga bila diekstrak dari kata instruksi.
Instruksi lompat dan tautkan (langsung) menggunakan encoding Jenis J:
31..12 | 11..7 | 6..0 |
---|---|---|
20 | 5 | 7 |
imm20 | rd | kode operasi |
Ini juga merupakan format yang mudah untuk ditambahkan, tetapi sekali lagi, format langsung yang digunakan oleh instruksinya tidak semudah yang terlihat. Urutan bit yang digunakan untuk membentuk langsung penuh adalah: 31, 19..12, 20, 30..21, dan yang digeser ke kiri sebanyak satu untuk penyelarasan setengah kata. Solusinya adalah dengan menambahkan overlay (21 bit untuk memperhitungkan pergeseran kiri) ke format:
overlays:
signed j_imm[21] = imm20[19, 7..0, 8, 18..9], 0b0;
Seperti yang dapat Anda lihat, sintaksis untuk overlay mendukung penetapan beberapa rentang {i>field<i} dalam format singkatan. Selain itu, jika tidak ada nama {i>field<i} yang digunakan, bit angka mengacu pada kata instruksi itu sendiri, jadi hal di atas bisa saja ditulis sebagai:
signed j_imm[21] = [31, 19..12, 20, 30..21], 0b0;
Terakhir, jump-and-link (register) menggunakan format tipe I seperti yang digunakan seperti yang telah dibahas sebelumnya.
Format langsung I-Type:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | kode operasi |
Kali ini, tidak ada perubahan yang harus dilakukan pada format.
Instruksi cabang yang perlu kita tambahkan adalah:
beq
- Cabang jika sama.bge
- Cabang jika lebih besar dari atau sama dengan.bgeu
- Cabang jika lebih besar dari atau sama tidak ditandatangani.blt
- Cabang jika kurang dari.bltu
- Cabang jika kurang dari tidak ditandatangani.bne
- Cabang jika tidak sama.
Kolom tersebut dienkode sebagai berikut:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | nama 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 | kode operasi |
Instruksi jal
dienkode sebagai berikut:
31..12 | 11..7 | 6..0 | nama opcode |
---|---|---|---|
imm20 | rd | 110 1111 | Jal |
kode operasi |
Instruksi jalr
dienkode sebagai berikut:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 110 0111 | Jalr |
func3 | kode operasi |
Lanjutkan membuat perubahan, lalu bangun. Periksa output yang dihasilkan. Hanya seperti sebelumnya, Anda dapat memeriksa pekerjaan Anda dengan riscv32i.bin_fmt.
Tambahkan petunjuk toko
Petunjuk penyimpanan menggunakan encoding S-Type, yang identik dengan B-Type
pengkodean yang digunakan oleh instruksi cabang, kecuali untuk komposisi
secara langsung. Kita memilih untuk menambahkan format SType
agar tetap selaras dengan RiscV
dokumentasi tambahan.
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm7 | rs2 | rs1 | func3 | imm5 | kode operasi |
Dalam kasus format SType
, item langsung untungnya berupa straight
sambungan maju dari dua bidang langsung, sehingga spesifikasi overlay
sederhana adalah:
overlays:
signed s_imm[12] = imm7, imm5;
Perhatikan bahwa penentu rentang bit tidak diperlukan saat menggabungkan seluruh kolom.
Petunjuk penyimpanan dienkode sebagai berikut:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | 6..0 | nama opcode |
---|---|---|---|---|---|---|
imm7 | rs2 | rs1 | 000 | imm5 | 010 0011 | sb |
imm7 | rs2 | rs1 | 001 | imm5 | 010 0011 | sh |
imm7 | rs2 | rs1 | 010 | imm5 | 010 0011 | sw |
func3 | kode operasi |
Lanjutkan membuat perubahan, lalu bangun. Periksa output yang dihasilkan. Hanya seperti sebelumnya, Anda dapat memeriksa pekerjaan Anda dengan riscv32i.bin_fmt.
Tambahkan petunjuk pemuatan
Petunjuk pemuatan menggunakan format I-Type. Tidak ada perubahan yang harus dilakukan di sana.
Encoding:
31..20 | 19..15 | 14..12 | 11..7 | 6..0 | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 000 0011 | lb |
imm12 | rs1 | 100 | rd | 000 0011 | {i>lbu<i} |
imm12 | rs1 | 001 | rd | 000 0011 | hh |
imm12 | rs1 | 101 | rd | 000 0011 | Lhu |
imm12 | rs1 | 010 | rd | 000 0011 | lw |
func3 | kode operasi |
Lanjutkan membuat perubahan, lalu bangun. Periksa output yang dihasilkan. Hanya seperti sebelumnya, Anda dapat memeriksa pekerjaan Anda dengan riscv32i.bin_fmt.
Demikianlah tutorial ini, semoga tutorial ini bermanfaat.