বাইনারি নির্দেশনা ডিকোডার টিউটোরিয়াল

এই টিউটোরিয়ালের উদ্দেশ্য হল:

  • বাইনারি ফরম্যাট বর্ণনা ফাইলের গঠন এবং সিনট্যাক্স শিখুন।
  • বাইনারি ফরম্যাটের বর্ণনা কীভাবে 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 এবং opcodeimm12 ক্ষেত্রটি 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 এর বিরুদ্ধে আপনার কাজ পরীক্ষা করতে পারেন।

এটি এই টিউটোরিয়ালটি শেষ করেছে, আমরা আশা করি এটি কার্যকর হয়েছে।