এই টিউটোরিয়ালের উদ্দেশ্য হল:
- বাইনারি ফরম্যাট বর্ণনা ফাইলের গঠন এবং সিনট্যাক্স শিখুন।
- বাইনারি ফরম্যাটের বর্ণনা কীভাবে ISA বর্ণনার সাথে মিলে যায় তা জানুন।
- নির্দেশাবলীর RiscV RV32I উপসেটের জন্য বাইনারি বিবরণ লিখুন।
ওভারভিউ
RiscV বাইনারি নির্দেশ এনকোডিং
বাইনারি ইন্সট্রাকশন এনকোডিং হল একটি মাইক্রোপ্রসেসরে এক্সিকিউশনের নির্দেশাবলী এনকোড করার আদর্শ উপায়। এগুলি সাধারণত একটি এক্সিকিউটেবল ফাইলে সংরক্ষণ করা হয়, সাধারণত ELF ফরম্যাটে। নির্দেশাবলী হয় নির্দিষ্ট প্রস্থ বা পরিবর্তনশীল প্রস্থ হতে পারে।
সাধারণত, নির্দেশাবলী এনকোডিং বিন্যাসের একটি ছোট সেট ব্যবহার করে, প্রতিটি বিন্যাসকে এনকোড করা নির্দেশাবলীর জন্য কাস্টমাইজ করা হয়। উদাহরণস্বরূপ, রেজিস্টার-রেজিস্টার নির্দেশাবলী একটি ফর্ম্যাট ব্যবহার করতে পারে যা উপলব্ধ অপকোডের সংখ্যা সর্বাধিক করে, যখন রেজিস্টার-তাত্ক্ষণিক নির্দেশাবলী অন্যটি ব্যবহার করে যা এনকোড করা যেতে পারে এমন তাৎক্ষণিক আকার বাড়ানোর জন্য উপলব্ধ অপকোডের সংখ্যা বন্ধ করে। শাখা এবং লাফের নির্দেশাবলী প্রায় সবসময়ই এমন ফর্ম্যাট ব্যবহার করে যা তাৎক্ষণিক আকারকে সর্বাধিক করে তোলে যাতে বড় অফসেটগুলির সাথে শাখাগুলিকে সমর্থন করা যায়।
আমরা আমাদের RiscV সিমুলেটরে ডিকোড করতে চাই নির্দেশাবলী দ্বারা ব্যবহৃত নির্দেশাবলীর বিন্যাসগুলি নিম্নরূপ:
আর-টাইপ ফরম্যাট, রেজিস্টার-রেজিস্টার নির্দেশাবলীর জন্য ব্যবহৃত:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | rs2 | rs1 | func3 | rd | অপকোড |
আই-টাইপ ফরম্যাট, রেজিস্টার-তাত্ক্ষণিক নির্দেশাবলী, লোড নির্দেশাবলী এবং jalr
নির্দেশের জন্য ব্যবহৃত, 12 বিট তাৎক্ষণিক।
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | অপকোড |
বিশেষায়িত আই-টাইপ ফরম্যাট, তাৎক্ষণিক নির্দেশাবলী সহ শিফটের জন্য ব্যবহৃত, 5 বিট তাৎক্ষণিক:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | rd | অপকোড |
U-টাইপ বিন্যাস, দীর্ঘ তাৎক্ষণিক নির্দেশাবলীর জন্য ব্যবহৃত ( lui
, auipc
), 20 বিট তাৎক্ষণিক:
31..12 | 11..7 | ৬..০ |
---|---|---|
20 | 5 | 7 |
uimm20 | rd | অপকোড |
বি-টাইপ বিন্যাস, শর্তাধীন শাখার জন্য ব্যবহৃত, 12-বিট তাৎক্ষণিক।
31 | 30..25 | 24..20 | 19..15 | 14..12 | 11..8 | 7 | ৬..০ |
---|---|---|---|---|---|---|---|
1 | 6 | 5 | 5 | 3 | 4 | 1 | 7 |
imm | imm | rs2 | rs1 | func3 | imm | imm | অপকোড |
J-টাইপ বিন্যাস, jal
নির্দেশের জন্য ব্যবহৃত, 20 বিট তাৎক্ষণিক।
31 | 30..21 | 20 | 19..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
1 | 10 | 1 | 8 | 5 | 7 |
imm | imm | imm | imm | rd | অপকোড |
S-টাইপ বিন্যাস, স্টোর নির্দেশাবলীর জন্য ব্যবহৃত, 12 বিট তাৎক্ষণিক।
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm | rs2 | rs1 | func3 | imm | অপকোড |
আপনি এই ফর্ম্যাটগুলি থেকে দেখতে পাচ্ছেন, এই সমস্ত নির্দেশাবলী 32 বিট দীর্ঘ, এবং প্রতিটি বিন্যাসে কম 7 বিট হল অপকোড ক্ষেত্র৷ এছাড়াও লক্ষ্য করুন যে বেশ কয়েকটি ফরম্যাটের একই আকারের অবিলম্বে, তাদের বিটগুলি নির্দেশের বিভিন্ন অংশ থেকে নেওয়া হয়েছে। আমরা দেখব, বাইনারি ডিকোডার স্পেসিফিকেশন ফরম্যাট এটি প্রকাশ করতে সক্ষম।
বাইনারি এনকোডিং বিবরণ
নির্দেশের বাইনারি এনকোডিং বাইনারি বিন্যাসে ( .bin_fmt
) বর্ণনা ফাইলে প্রকাশ করা হয়। এটি একটি ISA-তে নির্দেশাবলীর বাইনারি এনকোডিং বর্ণনা করে যাতে একটি বাইনারি বিন্যাস নির্দেশনা ডিকোডার তৈরি করা যায়। পূর্ববর্তী টিউটোরিয়ালে বর্ণিত 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
এর নাম, সেইসাথে তথ্যের চারটি অতিরিক্ত অংশ নির্দিষ্ট করে। প্রথমটি হল namespace
, যা নামস্থানকে সংজ্ঞায়িত করে যেখানে জেনারেট করা কোডটি স্থাপন করা হবে। দ্বিতীয়ত, opcode_enum
, যা ISA ডিকোডার দ্বারা উত্পন্ন অপকোড গণনার ধরনটি জেনারেট করা কোডের মধ্যে উল্লেখ করা উচিত। তৃতীয়, includes {}
এই ডিকোডারের জন্য তৈরি করা কোডের জন্য প্রয়োজনীয় ফাইল অন্তর্ভুক্ত করে। আমাদের ক্ষেত্রে, এই ফাইলটি পূর্ববর্তী টিউটোরিয়াল থেকে ISA ডিকোডার দ্বারা উত্পাদিত হয়। অতিরিক্ত অন্তর্ভুক্ত ফাইলগুলিকে একটি বিশ্বব্যাপী স্কোপযুক্ত includes {}
সংজ্ঞায় উল্লেখ করা যেতে পারে। এটি দরকারী যদি একাধিক ডিকোডার সংজ্ঞায়িত করা হয়, এবং তাদের সকলকে একই ফাইলগুলির মধ্যে কিছু অন্তর্ভুক্ত করতে হবে। চতুর্থ হল নির্দেশনা গোষ্ঠীর নামের একটি তালিকা যা নির্দেশাবলী তৈরি করে যার জন্য ডিকোডার তৈরি করা হয়েছে। আমাদের ক্ষেত্রে শুধুমাত্র একটি আছে: 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 ডিকোডিং একটি এক্সিকিউশন মোডের উপর নির্ভর করে, যেমন আর্ম বনাম থাম্ব নির্দেশাবলী, প্রতিটি মোডের জন্য একটি পৃথক নির্দেশ গ্রুপ প্রয়োজন। 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"
ব্যবহার করার জন্য opcode গণনার প্রকারের নাম এবং একটি বেস নির্দেশ বিন্যাস সংজ্ঞায়িত করে। opcode গণনার ধরনটি ISA ডিকোডারের টিউটোরিয়ালে আচ্ছাদিত ফর্ম্যাট স্বাধীন নির্দেশনা ডিকোডার দ্বারা উত্পাদিত হওয়া উচিত।
প্রতিটি নির্দেশ এনকোডিং বিবরণ 3টি অংশ নিয়ে গঠিত:
- অপকোড নাম, যা অবশ্যই একই হতে হবে যেটি নির্দেশনা ডিকোডারের বিবরণে ব্যবহার করা হয়েছিল যাতে দুটি একসাথে কাজ করতে পারে।
- অপকোডের জন্য ব্যবহার করার জন্য নির্দেশ বিন্যাস। এটি সেই বিন্যাস যা চূড়ান্ত অংশে বিটফিল্ডের রেফারেন্সগুলিকে সন্তুষ্ট করতে ব্যবহৃত হয়।
- বিট ক্ষেত্রের সীমাবদ্ধতার একটি কমা বিভক্ত তালিকা,
==
,!=
,<
,<=
,>
, এবং>=
যেগুলি নির্দেশ শব্দের সাথে সফলভাবে মেলে অপকোডের জন্য অবশ্যই সত্য হতে হবে৷
.bin_fmt
পার্সার একটি ডিকোডার তৈরি করতে এই সমস্ত তথ্য ব্যবহার করে:
- প্রতিটি বিন্যাসে প্রতিটি বিট ক্ষেত্রের জন্য উপযুক্ত হিসাবে নিষ্কাশন ফাংশন (স্বাক্ষরিত/স্বাক্ষরবিহীন) প্রদান করে। এক্সট্র্যাক্টর ফাংশন ফরম্যাট নামের স্নেক-কেস সংস্করণ দ্বারা নামকৃত নামস্থানে স্থাপন করা হয়। উদাহরণস্বরূপ,
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
এ পরিবর্তন করুন (অন্য হোস্টের জন্য, 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
খুলুন। ফাইলের প্রথম অংশে স্ট্যান্ডার্ড বয়লারপ্লেট গার্ড রয়েছে, এতে ফাইল, নামস্থান ঘোষণা অন্তর্ভুক্ত রয়েছে। এর পরে নেমস্পেসে 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-টাইপ বাইনারি নির্দেশ বিন্যাস ব্যবহার করে:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | rs2 | rs1 | func3 | rd | অপকোড |
আমাদের প্রথম জিনিসটি ফরম্যাট যোগ করতে হবে। এগিয়ে যান এবং আপনার প্রিয় সম্পাদকে riscv32i.bin_fmt
খুলুন। Inst32Format
ঠিক পরে RType
নামে একটি ফরম্যাট যোগ করতে দেয় যা Inst32Format
থেকে এসেছে। RType
এর সমস্ত বিটফিল্ড unsigned
। ফরম্যাটটি সংজ্ঞায়িত করতে উপরের টেবিল থেকে নাম, বিট প্রস্থ এবং ক্রম (বাম থেকে ডানে) ব্যবহার করুন। আপনি একটি ইঙ্গিত প্রয়োজন হলে, বা সম্পূর্ণ সমাধান দেখতে চান, এখানে ক্লিক করুন .
পরবর্তী আমরা নির্দেশাবলী যোগ করতে হবে. নির্দেশাবলী হল:
-
add
- পূর্ণসংখ্যা যোগ করুন। -
and
- bitwise এবং. -
or
- bitwise or. -
sll
- লজিক্যাল বাম স্থানান্তর করুন। -
sltu
- কম-এর চেয়ে সেট করুন, স্বাক্ষরবিহীন। -
sub
-পূর্ণসংখ্যা বিয়োগ। -
xor
- bitwise xor.
তাদের এনকোডিং হল:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ | অপকোড নাম |
---|---|---|---|---|---|---|
000 0000 | rs2 | rs1 | 000 | rd | 011 0011 | যোগ করুন |
000 0000 | rs2 | rs1 | 111 | rd | 011 0011 | এবং |
000 0000 | rs2 | rs1 | 110 | rd | 011 0011 | বা |
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 | উপ |
000 0000 | rs2 | rs1 | 100 | rd | 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 নির্দেশাবলী যা একটি রেজিস্টারের পরিবর্তে একটি তাৎক্ষণিক মান ব্যবহার করে। এই নির্দেশাবলীর তিনটি গ্রুপ রয়েছে (তাত্ক্ষণিক ক্ষেত্রের উপর ভিত্তি করে): 12 বিট স্বাক্ষরিত অবিলম্বে I-টাইপ অবিলম্বে নির্দেশাবলী, শিফটের জন্য বিশেষায়িত I-টাইপ তাত্ক্ষণিক নির্দেশাবলী এবং 20-বিট সহ অবিলম্বে U-টাইপ স্বাক্ষরবিহীন তাৎক্ষণিক মান। বিন্যাসগুলি নীচে দেখানো হয়েছে:
আই-টাইপ তাৎক্ষণিক বিন্যাস:
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | অপকোড |
বিশেষায়িত আই-টাইপ তাৎক্ষণিক বিন্যাস:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
func7 | uimm5 | rs1 | func3 | rd | অপকোড |
ইউ-টাইপ তাৎক্ষণিক বিন্যাস:
31..12 | 11..7 | ৬..০ |
---|---|---|
20 | 5 | 7 |
uimm20 | rd | অপকোড |
riscv32i.bin_fmt
এ আই-টাইপ ফরম্যাটটি ইতিমধ্যেই বিদ্যমান, তাই সেই বিন্যাসটি যোগ করার প্রয়োজন নেই।
যদি আমরা পূর্ববর্তী অনুশীলনে সংজ্ঞায়িত R-টাইপ বিন্যাসের সাথে বিশেষ I-Type বিন্যাসের তুলনা করি, তাহলে আমরা দেখতে পাই যে শুধুমাত্র পার্থক্য হল যে rs2
ক্ষেত্রগুলির নাম পরিবর্তন করে uimm5
করা হয়েছে। একটি সম্পূর্ণ নতুন বিন্যাস যোগ করার পরিবর্তে আমরা আর-টাইপ বিন্যাসকে বাড়িয়ে তুলতে পারি। আমরা অন্য ক্ষেত্র যোগ করতে পারি না, কারণ এটি বিন্যাসের প্রস্থ বাড়াবে, কিন্তু আমরা একটি ওভারলে যোগ করতে পারি। একটি ওভারলে ফরম্যাটে বিটগুলির একটি সেটের একটি উপনাম, এবং এটি একটি পৃথক নামকৃত সত্তায় বিন্যাসের একাধিক পরবর্তী অংশকে একত্রিত করতে ব্যবহার করা যেতে পারে। পার্শ্ব-প্রতিক্রিয়া হল যে জেনারেট করা কোডটি এখন ক্ষেত্রগুলির জন্য ছাড়াও ওভারলে এর জন্য একটি নিষ্কাশন ফাংশন অন্তর্ভুক্ত করবে। এই ক্ষেত্রে, যখন rs2
এবং uimm5
উভয়ই স্বাক্ষরবিহীন থাকে তখন এটি স্পষ্ট করা ছাড়া খুব বেশি পার্থক্য করে না যে ক্ষেত্রটি অবিলম্বে ব্যবহৃত হয়। R-Type ফরম্যাটে uimm5
নামের একটি ওভারলে যোগ করতে, শেষ ক্ষেত্রের পরে নিম্নলিখিত যোগ করুন:
overlays:
unsigned uimm5[5] = rs2;
শুধুমাত্র নতুন বিন্যাসটি আমাদের যুক্ত করতে হবে তা হল U-টাইপ বিন্যাস। ফরম্যাট যোগ করার আগে, সেই ফর্ম্যাটটি ব্যবহার করে এমন দুটি নির্দেশনা বিবেচনা করা যাক: auipc
এবং lui
। এই দুটিই 20-বিট তাৎক্ষণিক মানটি 12 দ্বারা বাম স্থানান্তরিত করে এটি ব্যবহার করার আগে এটিতে পিসি যুক্ত করে ( auipc
) অথবা এটি সরাসরি একটি রেজিস্টারে ( lui
) লিখতে। একটি ওভারলে ব্যবহার করে আমরা অবিলম্বে একটি প্রাক-স্থানান্তরিত সংস্করণ প্রদান করতে পারি, নির্দেশনা সম্পাদন থেকে নির্দেশনা ডিকোডে কিছুটা গণনা স্থানান্তরিত করে। প্রথমে উপরের টেবিলে নির্দিষ্ট ক্ষেত্র অনুযায়ী বিন্যাস যোগ করুন। তারপর আমরা নিম্নলিখিত ওভারলে যোগ করতে পারেন:
overlays:
unsigned uimm32[32] = uimm20, 0b0000'0000'0000;
ওভারলে সিনট্যাক্স আমাদের শুধুমাত্র ক্ষেত্র নয়, আক্ষরিকও সংযুক্ত করতে দেয়। এই ক্ষেত্রে আমরা এটিকে 12টি শূন্য দিয়ে সংযুক্ত করি, ফলস্বরূপ এটিকে 12 দ্বারা বামে স্থানান্তর করা হয়।
আই-টাইপ নির্দেশাবলী আমাদের যোগ করতে হবে:
-
addi
- অবিলম্বে যোগ করুন। -
andi
- Bitwise এবং অবিলম্বে। -
ori
- বিটওয়াইজ বা অবিলম্বে। -
xori
- অবিলম্বে বিটওয়াইজ xor।
তাদের এনকোডিং হল:
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 001 0011 | addi |
imm12 | rs1 | 111 | rd | 001 0011 | andi |
imm12 | rs1 | 110 | rd | 001 0011 | অরি |
imm12 | rs1 | 100 | rd | 001 0011 | xori |
func3 | অপকোড |
আর-টাইপ (বিশেষ আই-টাইপ) নির্দেশাবলী আমাদের যোগ করতে হবে:
-
slli
- অবিলম্বে লজিক্যাল বামে স্থানান্তর করুন। -
srai
- অবিলম্বে ডান পাটিগণিত স্থানান্তর করুন। -
srli
- অবিলম্বে ডান লজিক্যাল স্থানান্তর করুন।
তাদের এনকোডিং হল:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ | অপকোড নাম |
---|---|---|---|---|---|---|
000 0000 | uimm5 | rs1 | 001 | rd | 001 0011 | স্লি |
010 0000 | uimm5 | rs1 | 101 | rd | 001 0011 | srai |
000 0000 | uimm5 | rs1 | 101 | rd | 001 0011 | srli |
func7 | func3 | অপকোড |
আমাদের যে U-টাইপ নির্দেশাবলী যোগ করতে হবে তা হল:
-
auipc
- পিসিতে উপরের অবিলম্বে যোগ করুন। -
lui
- লোড উপরের অবিলম্বে.
তাদের এনকোডিং হল:
31..12 | 11..7 | ৬..০ | অপকোড নাম |
---|---|---|---|
uimm20 | rd | 001 0111 | auipc |
uimm20 | rd | 011 0111 | লুই |
অপকোড |
এগিয়ে যান এবং পরিবর্তন করুন এবং তারপর তৈরি করুন। উত্পন্ন আউটপুট পরীক্ষা করুন. ঠিক আগের মতই, আপনি riscv32i.bin_fmt এর বিরুদ্ধে আপনার কাজ পরীক্ষা করতে পারেন।
শাখা যোগ করুন এবং জাম্প এবং লিঙ্ক নির্দেশাবলী
নির্দেশাবলীর পরবর্তী সেট যা সংজ্ঞায়িত করা প্রয়োজন তা হল শর্তসাপেক্ষ শাখা নির্দেশাবলী, জাম্প-এন্ড-লিংক নির্দেশনা এবং জাম্প-এন্ড-লিঙ্ক রেজিস্টার নির্দেশনা।
আমরা যে শর্তসাপেক্ষ শাখাগুলি যোগ করছি সেগুলি B-টাইপ এনকোডিং ব্যবহার করে।
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
7 | 5 | 5 | 3 | 5 | 7 |
imm7 | rs2 | rs1 | func3 | imm5 | অপকোড |
যদিও বি-টাইপ এনকোডিং R-টাইপ এনকোডিংয়ের বিন্যাসে অভিন্ন, আমরা RiscV ডকুমেন্টেশনের সাথে সারিবদ্ধ করার জন্য এটির জন্য একটি নতুন ফর্ম্যাট টাইপ ব্যবহার করা বেছে নিই। কিন্তু আপনি R-Type এনকোডিংয়ের func7
এবং rd
ক্ষেত্রগুলি ব্যবহার করে যথাযথ শাখা স্থানচ্যুতি অবিলম্বে পেতে একটি ওভারলে যুক্ত করতে পারেন।
উপরে উল্লেখিত ক্ষেত্রগুলির সাথে একটি বিন্যাস BType
যোগ করা আবশ্যক, কিন্তু যথেষ্ট নয়। আপনি দেখতে পাচ্ছেন, অবিলম্বে দুটি নির্দেশের ক্ষেত্রে বিভক্ত। অধিকন্তু, শাখা নির্দেশাবলী এটিকে দুটি ক্ষেত্রের একটি সরল সংযোগ হিসাবে বিবেচনা করে না। পরিবর্তে, প্রতিটি ক্ষেত্র আরও বিভাজন করা হয়েছে, এবং এই পার্টিশনগুলি একটি ভিন্ন ক্রমে সংযুক্ত করা হয়েছে। অবশেষে, একটি 16-বিট সারিবদ্ধ অফসেট পাওয়ার জন্য সেই মানটি একজনের দ্বারা বামে স্থানান্তরিত হয়।
অবিলম্বে গঠন করতে ব্যবহৃত নির্দেশ শব্দের বিটের ক্রম হল: 31, 7, 30..25, 11..8। এটি নিম্নোক্ত সাব-ফিল্ড রেফারেন্সের সাথে মিলে যায়, যেখানে সূচক বা ব্যাপ্তি ক্ষেত্রের বিটগুলি নির্দিষ্ট করে, ডান থেকে বামে সংখ্যা করা হয়, অর্থাৎ, imm7[6]
বোঝায় imm7
এর msb, এবং imm5[0]
এর 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-টাইপ এনকোডিং ব্যবহার করে:
31..12 | 11..7 | ৬..০ |
---|---|---|
20 | 5 | 7 |
imm20 | rd | অপকোড |
এটি যোগ করার জন্য একটি সহজ বিন্যাস, কিন্তু আবার, নির্দেশ দ্বারা ব্যবহৃত তাৎক্ষণিকটি যতটা সহজ মনে হয় ততটা সহজ নয়। সম্পূর্ণ তাৎক্ষণিক গঠন করতে ব্যবহৃত বিট সিকোয়েন্সগুলি হল: 31, 19..12, 20, 30..21, এবং অর্ধশব্দ সারিবদ্ধকরণের জন্য চূড়ান্ত তাৎক্ষণিকটি একটি বামে স্থানান্তরিত হয়। সমাধান হল ফরম্যাটে আরেকটি ওভারলে (বাম শিফটের জন্য অ্যাকাউন্টে 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;
অবশেষে, জাম্প-এন্ড-লিঙ্ক (রেজিস্টার) পূর্বে ব্যবহৃত আই-টাইপ বিন্যাস ব্যবহার করে।
আই-টাইপ তাৎক্ষণিক বিন্যাস:
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|
12 | 5 | 3 | 5 | 7 |
imm12 | rs1 | func3 | rd | অপকোড |
এই সময়, বিন্যাসে কোন পরিবর্তন করতে হবে না।
শাখা নির্দেশাবলী আমাদের যোগ করতে হবে, হল:
-
beq
- শাখা সমান হলে। -
bge
- এর চেয়ে বড় বা সমান হলে শাখা। -
bgeu
- এর চেয়ে বড় বা সমান স্বাক্ষরবিহীন শাখা। -
blt
- এর চেয়ে কম হলে শাখা। -
bltu
- স্বাক্ষরবিহীন থেকে কম হলে শাখা। -
bne
- শাখা সমান না হলে।
তারা নিম্নরূপ এনকোড করা হয়:
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ | অপকোড নাম |
---|---|---|---|---|---|---|
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 | ৬..০ | অপকোড নাম |
---|---|---|---|
imm20 | rd | 110 1111 | জল |
অপকোড |
jalr
নির্দেশনাটি নিম্নরূপ এনকোড করা হয়েছে:
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 110 0111 | jalr |
func3 | অপকোড |
এগিয়ে যান এবং পরিবর্তন করুন এবং তারপর তৈরি করুন। উত্পন্ন আউটপুট পরীক্ষা করুন. ঠিক আগের মতই, আপনি riscv32i.bin_fmt এর বিরুদ্ধে আপনার কাজ পরীক্ষা করতে পারেন।
দোকান নির্দেশাবলী যোগ করুন
দোকানের নির্দেশাবলী এস-টাইপ এনকোডিং ব্যবহার করে, যা শাখা নির্দেশাবলী দ্বারা ব্যবহৃত B-টাইপ এনকোডিং-এর অনুরূপ, তাৎক্ষণিক রচনা ব্যতীত। আমরা RiscV ডকুমেন্টেশনের সাথে সারিবদ্ধ থাকার জন্য SType
ফর্ম্যাট যোগ করতে বেছে নিই।
31..25 | 24..20 | 19..15 | 14..12 | 11..7 | ৬..০ |
---|---|---|---|---|---|
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 | ৬..০ | অপকোড নাম |
---|---|---|---|---|---|---|
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-টাইপ বিন্যাস ব্যবহার করে। সেখানে কোনো পরিবর্তন করতে হবে না।
এনকোডিংগুলি হল:
31..20 | 19..15 | 14..12 | 11..7 | ৬..০ | opcode_name |
---|---|---|---|---|---|
imm12 | rs1 | 000 | rd | 000 0011 | পাউন্ড |
imm12 | rs1 | 100 | rd | 000 0011 | lbu |
imm12 | rs1 | 001 | rd | 000 0011 | lh |
imm12 | rs1 | 101 | rd | 000 0011 | lhu |
imm12 | rs1 | 010 | rd | 000 0011 | lw |
func3 | অপকোড |
এগিয়ে যান এবং পরিবর্তন করুন এবং তারপর তৈরি করুন। উত্পন্ন আউটপুট পরীক্ষা করুন. ঠিক আগের মতই, আপনি riscv32i.bin_fmt এর বিরুদ্ধে আপনার কাজ পরীক্ষা করতে পারেন।
এটি এই টিউটোরিয়ালটি শেষ করেছে, আমরা আশা করি এটি কার্যকর হয়েছে।