RiscV ISA kod çözücü

Bu eğitimin hedefleri şunlardır:

  • Talimatların MPACT-Sim simülatöründe nasıl gösterildiğini öğrenin.
  • ISA açıklama dosyasının yapısını ve söz dizimini öğrenin.
  • RiscV RV32I talimat alt kümesi için ISA açıklamalarını yazın

Genel Bakış

MPACT-Sim'de hedef talimatların kodu çözülür ve dahili bir ve anlamsal açıdan daha erişilebilir hale getirmek için yürütmek için daha hızlı çalışır. Bu talimat örnekleri bir talimatta önbelleğe alınır Böylece, sıklıkla yürütülen talimatların çalıştırılma sayısını azaltmak için yürütüldü.

Ders dersi

Başlamadan önce, talimatların nasıl hazırlandığına ve temsil edilir. Instruction sınıfı şurada tanımlanmıştır: mpact-sim/mpact/sim/generic/instruction.h.

Talimat sınıfı örneği, şunları yapmak için gereken tüm bilgileri içerir: yürütülürken talimatı simüle eder, örneğin:

  1. Talimat adresi, simüle edilmiş talimat boyutu, ör. .text olarak boyut.
  2. Talimat işlem kodu.
  3. Koşullar işlenen arayüz işaretçisi (varsa).
  4. Kaynak işlenen arayüz işaretçilerinin vektörü.
  5. Hedef işlenen arayüz işaretçilerinin vektörü.
  6. Anlamsal işlev çağrılabilir.
  7. Mimari durum nesnesinin işaretçisi.
  8. Bağlam nesnesinin işaretçisi.
  9. İşaretçiyi alt öğe ve sonraki Talimat örneklerine yönlendirir.
  10. Ayırma dizesi.

Bu örnekler genellikle bir talimatlar (örnek) önbelleğinde depolanır ve yeniden çalıştırıldığında yeniden kullanılır. Böylece, performans artar yardımcı olabilir.

Bağlam nesnesi işaretçisi dışında tüm veriler, talimatı kod çözücüyü oluşturur. Bunun için çünkü eğitimde bu unsurların ayrıntılarını bilmek gerekmez, çünkü yardımcı olur. Bunun yerine bunların nasıl kullanıldıklarını anlamak için yeterli olacaktır.

Anlamsal işlev çağrılabilir; C++ işlevi/yöntem/işlev nesnesidir (lambdas dahil) içeren bir JavaScript kodu içerir. Örneğin, add talimatı için her bir kaynak işlenenini yükler, işlem görür ve sonucu tek bir hedef işlenenine yazar. Konu anlamsal işlevler, anlamsal işlev eğiticisinde ayrıntılı olarak ele alınmıştır.

Talimat işlenenleri

Talimat sınıfı, üç tür işlenen arayüzü işaretleyiciler içerir: değer, kaynak ve hedef. Bu arayüzler, anlamsal işlevlerin temel talimatın gerçek türünden bağımsız olarak yazılmalıdır işlenen. Örneğin, kayıtların ve anındaların değerlerine erişim aynı arayüzden geçiriliyor. Bu, aynı işlemi yapan talimatların da işlem ancak farklı işlenenlerde (ör. kayıtlar ve taklitler) uygulanmış olabilir.

Temel alınan öğeleri destekleyen ISA'lar için yüklem işlenen arayüzü talimatı yürütme (diğer ISA'lar için boştur), bir verilen talimat koşulun boole değerine göre yürütülmelidir.

// The predicte operand interface is intended primarily as the interface to
// read the value of instruction predicates. It is separated from source
// predicates to avoid mixing it in with the source operands needed for modeling
// the instruction semantics.
class PredicateOperandInterface {
 public:
  virtual bool Value() = 0;
  // Return a string representation of the operand suitable for display in
  // disassembly.
  virtual std::string AsString() const = 0;
  virtual ~PredicateOperandInterface() = default;
};

Kaynak işlenen arayüzü, talimat anlamsal işlevinin temel işlenene bakılmaksızın, talimat işlenenlerinden gelen değerler türü. Arayüz yöntemleri hem skaler hem de vektör değerli işlenenleri destekler.

// The source operand interface provides an interface to access input values
// to instructions in a way that is agnostic about the underlying implementation
// of those values (eg., register, fifo, immediate, predicate, etc).
class SourceOperandInterface {
 public:
  // Methods for accessing the nth value element.
  virtual bool AsBool(int index) = 0;
  virtual int8_t AsInt8(int index) = 0;
  virtual uint8_t AsUint8(int index) = 0;
  virtual int16_t AsInt16(int index) = 0;
  virtual uint16_t AsUint16(int) = 0;
  virtual int32_t AsInt32(int index) = 0;
  virtual uint32_t AsUint32(int index) = 0;
  virtual int64_t AsInt64(int index) = 0;
  virtual uint64_t AsUint64(int index) = 0;

  // Return a pointer to the object instance that implements the state in
  // question (or nullptr) if no such object "makes sense". This is used if
  // the object requires additional manipulation - such as a fifo that needs
  // to be pop'ed. If no such manipulation is required, nullptr should be
  // returned.
  virtual std::any GetObject() const = 0;

  // Return the shape of the operand (the number of elements in each dimension).
  // For instance {1} indicates a scalar quantity, whereas {128} indicates an
  // 128 element vector quantity.
  virtual std::vector<int> shape() const = 0;

  // Return a string representation of the operand suitable for display in
  // disassembly.
  virtual std::string AsString() const = 0;

  virtual ~SourceOperandInterface() = default;
};

Hedef işlenen arayüzü, ayırma ve işleme yöntemleri sunar. DataBuffer örnek (kayıt değerlerini depolamak için kullanılan dahili veri türü). CEVAP hedef işlemde de bir gecikme vardır. Bu gecikme talimat tarafından ayrılan veri arabelleği örneği gösterilene kadar beklenecek döngülerin sayısı anlamsal işlev, hedef kaydın değerini güncellemek için kullanılır. Örneğin, add talimatının gecikme süresi 1, mpy talimatının gecikme süresi ise 1 olabilir. 4 olabilir. Bu konu konulu videomuzu izleyin.

// The destination operand interface is used by instruction semantic functions
// to get a writable DataBuffer associated with a piece of simulated state to
// which the new value can be written, and then used to update the value of
// the piece of state with a given latency.
class DestinationOperandInterface {
 public:
  virtual ~DestinationOperandInterface() = default;
  // Allocates a data buffer with ownership, latency and delay line set up.
  virtual DataBuffer *AllocateDataBuffer() = 0;
  // Takes an existing data buffer, and initializes it for the destination
  // as if AllocateDataBuffer had been called.
  virtual void InitializeDataBuffer(DataBuffer *db) = 0;
  // Allocates and initializes data buffer as if AllocateDataBuffer had been
  // called, but also copies in the value from the current value of the
  // destination.
  virtual DataBuffer *CopyDataBuffer() = 0;
  // Returns the latency associated with the destination operand.
  virtual int latency() const = 0;
  // Return a pointer to the object instance that implmements the state in
  // question (or nullptr if no such object "makes sense").
  virtual std::any GetObject() const = 0;
  // Returns the order of the destination operand (size in each dimension).
  virtual std::vector<int> shape() const = 0;
  // Return a string representation of the operand suitable for display in
  // disassembly.
  virtual std::string AsString() const = 0;
};

ISA açıklaması

Bir işlemcinin ISA (Talimat Seti Mimarisi) soyut modeli tanımlar yazılımın donanımla etkileşime girmesini sağlar. Projeyi tanımlayan kayıtlarına ve diğer makineye ait yapılandırmanın ve davranışları (anlamsal) üzerine çalışır. Amaçları: ISA, talimatların gerçek kodlamasını içermez. Bunlar ayrı olarak ele alınır.

İşleyen ISA, soyut, kodlamadan bağımsız bir düzeyde ayarlanmış olmasını sağlar. Açıklama dosyası kullanılabilir talimat grubunu sıralar. Her talimat için adının, işlenenlerinin sayısı ile adlarını ve fonksiyonlarının özelliğini uygulayan bir C++ işlevine/çağrılanabilir öğesine bağlama. Ayrıca, Bir ayırma biçimlendirme dizesi ve talimatın donanım kaynağı adları. Birincisi, ikinci bir boyut oluşturmak için hata ayıklama, izleme veya etkileşimli kullanım talimatının temsili. İlgili içeriği oluşturmak için kullanılan ikincisi, simülasyonda daha fazla döngü doğruluğu oluşturmak için kullanılabilir.

ISA açıklama dosyası, isa-parser tarafından talimat kod çözücüyü devreye sokmaktır. Bu kod çözücü, talimat nesnelerinin alanları dolduruluyor. Belirli değerler, örneğin hedef tescil numarası, biçime özel talimattan alınır. kod çözücü. Bu tür kod çözücülerden biri, ikili kod çözücüdür. Bu kod çözücü, bir sonraki eğiticiye göz atın.

Bu eğitimde, basit ve skaler bir veri için ISA açıklama dosyasının nasıl yazılacağı bahsedeceğim. RiscV RV32I talimatının göstermeli ve diğer eğiticilerle birlikte özel geliştirmeler için "Hello World" simülasyonu çok önemli. RiscV ISA hakkında daha fazla bilgi için bkz. Risc-V Özellikleri.

İlk olarak dosyayı açın: riscv_isa_decoder/riscv32i.isa.

Dosyanın içeriği birden çok bölüme ayrılır. Birincisi, ISA beyan:

isa RiscV32I {
  namespace mpact::sim::codelab;
  slots { riscv32; }
}

Bu, RiscV32I öğesinin ISA adı olduğunu ve kod oluşturucunun RiscV32IEncodingBase adında bir sınıf oluşturup oluşturulan kod çözücü, işlem kodu ve işlenen bilgilerini almak için kullanılır. Kişinin adı bu sınıf, ISA adının Pascal büyük/küçük harfe dönüştürülerek oluşturulur, ardından EncodingBase ile birleştiriliyor. slots { riscv32; } beyanı RiscV32I'de yalnızca tek bir talimat yuvası riscv32 olduğunu belirtir ISA (VLIW talimatındaki birden çok yuvanın aksine) ve yalnızca geçerli talimatlar, riscv32 içinde yürütülecek şekilde tanımlanmış olan talimatlardır.

// First disasm fragment is 15 char wide and left justified.
disasm widths = {-15};

Bu, herhangi bir parçalamanın ilk sökme parçasının, spesifikasyon (aşağıda daha fazla bilgi verilmiştir), 15 karakter içinde iki yana yaslı olarak bırakılacaktır çok önemlidir. Sonraki parçalar bu alana, girin.

Bunun altında üç alan bildirimi bulunur: riscv32i, zicsr ve riscv32. Yukarıdaki isa tanımına göre, yalnızca riscv32 için tanımlanan talimatlar alanı RiscV32I SDK'sının bir parçası olacaktır. Diğer iki zaman aralığı ne için?

Slotlar, talimatları ayrı gruplar halinde hesaba katmak için kullanılabilir. Bu gruplar daha sonra bir araya getirilir. : riscv32i, zicsr notasyonuna dikkat edin (riscv32 alan bildirimi) Bu, riscv32 alanının devraldığını belirtir zicsr ve riscv32i alanlarında tanımlanan tüm talimatlar. RiscV 32 bit ISA RV32I adlı bir temel ISA'dan oluşur. Buna, bir dizi isteğe bağlı uzantı eklenir. Slot mekanizması, bu uzantılardaki talimatların tanımlamaları için ayrı ayrı belirtildiğinde ve gerektiği şekilde birleştirildiğinde önemli bir rol oynar. Bu durumda, RiscV 'I' ve grup tanımlı "zicsr" içindekilerden ayrı olarak grubu. Ek gruplar tanımlanabilir 'M' için (çarpma/böl), 'F' (tek duyarlıklı kayan nokta), 'D' (çift duyarlıklı kayan nokta), 'C' (kompakt 16 bit talimatlar) vb. gibi gereken nihai RiscV ISA için gereken

// The RiscV 'I' instructions.
slot riscv32i {
  ...
}

// RiscV32 CSR manipulation instructions.
slot zicsr {
  ...
}

// The final instruction set combines riscv32i and zicsr.
slot riscv32 : riscv32i, zicsr {
  ...
}

zicsr ve riscv32 alan tanımlarının değiştirilmesi gerekmez. Ancak Bu eğiticide odak noktası, riscv32i yuvaya yerleştirilmiştir. Bu alanda halihazırda tanımlanmış olan öğelere daha yakından bakalım:

// The RiscV 'I' instructions.
slot riscv32i {
  // Include file that contains the declarations of the semantic functions for
  // the 'I' instructions.
  includes {
    #include "learning/brain/research/mpact/sim/codelab/riscv_semantic_functions/solution/rv32i_instructions.h"
  }
  // These are all 32 bit instructions, so set default size to 4.
  default size = 4;
  // Model these with 0 latency to avoid buffering the result. Since RiscV
  // instructions have sequential semantics this is fine.
  default latency = 0;
  // The opcodes.
  opcodes {
    fence{: imm12 : },
      semfunc: "&RV32IFence"c
      disasm: "fence";
    ebreak{},
      semfunc: "&RV32IEbreak",
      disasm: "ebreak";
  }
}

İlk olarak, oluşturulması gereken başlık dosyalarının listelendiği bir includes {} Bu alana referans verildiğinde, oluşturulan koda doğrudan veya dolaylı olarak bildirmeliyiz. Dahil et dosyaları global olarak da listelenebilir kapsamlı bir includes {} bölümüdür. Bu durumda her zaman dahil edilirler. Bu her alana aynı "include" (ekleme) dosyasının eklenmesi gerekiyorsa yararlı olur. belirler.

default size ve default latency beyanları, aksi belirtildiğinde, bir talimatın boyutu 4 ve bir talimatın gecikmesinin hedef işlem gören yazma 0 döngüdür. Talimatın büyüklüğüne dikkat edin büyük bir değer, rastgele değeri hesaplamak için program sayacının simüle edilmiş senaryoda yürütülecek bir sonraki sıralı talimatın işlemci. Bu boyut, bayt cinsinden boyutla aynı olabilir veya olmayabilir. yürütülebilir giriş dosyasında talimat temsili.

Alan tanımının merkezinde işlem kodu bölümü bulunur. Gördüğünüz gibi yalnızca iki fence ve ebreak işlem kodları (talimatlar) şu ana kadar riscv32i. fence işlem kodu, ad (fence) ve işlem gören spesifikasyonu ({: imm12 : }) ve ardından isteğe bağlı sökme biçimi ("fence") ve anlamsal olarak bağlanacak çağrılabilir işlevine ("&RV32IFence") gidin.

Talimat işlenenleri, her bileşenle üçlü olarak belirtilir. noktalı virgülle ayrılmış, predicate ':' kaynak işlenen listesi ':' hedef işlenen listesi. Kaynak ve hedef işlenen listeleri virgülle ayrılmıştır. işlem görelerin adlarını içeren ayrılmış bir listedir. Gördüğünüz gibi, bu talimat veri işlemenin fence talimatı, koşul işleneni içermiyor, yalnızca tek bir kaynak içeriyor işlem gören adı imm12 ve hedef işleneni yok. RiscV RV32I alt kümesi koşullu yürütmeyi desteklemediğinden koşul işleneni her zaman boş olur inceleyebilirsiniz.

Anlamsal fonksiyon, C++ işlevini veya çağrılmasını sağlayabilirsiniz. İmzalama anlamsal işlev/çağrılanabilir: void(Instruction *).

Sökme spesifikasyonu, virgülle ayrılmış bir dize listesinden oluşur. Genellikle biri işlem kodu, diğeri de işlem kodu için olmak üzere yalnızca iki dize kullanılır. işlenenler. Biçimlendirildiğinde (Talimat'ta AsString() çağrısı kullanılarak) her bir dize, disasm widths uyarınca bir alan içinde biçimlendirilir yukarıda açıklanan özelliklere tabidir.

Aşağıdaki alıştırmalar, riscv32i.isa dosyasına talimat eklemenize yardımcı olur "Hello World" ifadesini taklit etmek için yeterlidir çok önemli. Acelesi olanlar için, çözüm önerileri riscv32i.isa ve rv32i_instructions.h olmalıdır.


İlk Derlemeyi Gerçekleştir

Dizini riscv_isa_decoder olarak değiştirmediyseniz bu işlemi şimdi yapın. Sonra Bu derleme başarılı olacaktır.

$ cd riscv_isa_decoder
$ bazel build :all

Şimdi dizininizi depo köküyle değiştirin ve bir bakalım. oluşturulan kaynaklarda gösterilir. Bunun için, dizini bazel-out/k8-fastbuild/bin/riscv_isa_decoder (x86 kullandığınız varsayılır) ana makine - diğer ana makineler için k8-Fastbuild, başka bir dize olacaktır).

$ cd ..
$ cd bazel-out/k8-fastbuild/bin/riscv_isa_decoder

Bu dizinde diğer dosyaların yanı sıra şunlar yer alır: oluşturulan C++ dosyaları:

  • riscv32i_decoder.h
  • riscv32i_decoder.cc
  • riscv32i_enums.h
  • riscv32i_enums.cc

Tarayıcıda tıklayarak riscv32i_enums.h öğesine bakalım. Şunları yapmalısınız: aşağıdaki gibi bir ifadeyi içerdiğini görürsünüz:

#ifndef RISCV32I_ENUMS_H
#define RISCV32I_ENUMS_H

namespace mpact {
namespace sim {
namespace codelab {
  enum class SlotEnum {
    kNone = 0,
    kRiscv32,
  };

  enum class PredOpEnum {
    kNone = 0,
    kPastMaxValue = 1,
  };

  enum class SourceOpEnum {
    kNone = 0,
    kCsr = 1,
    kImm12 = 2,
    kRs1 = 3,
    kPastMaxValue = 4,
  };

  enum class DestOpEnum {
    kNone = 0,
    kCsr = 1,
    kRd = 2,
    kPastMaxValue = 3,
  };

  enum class OpcodeEnum {
    kNone = 0,
    kCsrs = 1,
    kCsrsNw = 2,
    kCsrwNr = 3,
    kEbreak = 4,
    kFence = 5,
    kPastMaxValue = 6
  };

  constexpr char kNoneName[] = "none";
  constexpr char kCsrsName[] = "Csrs";
  constexpr char kCsrsNwName[] = "CsrsNw";
  constexpr char kCsrwNrName[] = "CsrwNr";
  constexpr char kEbreakName[] = "Ebreak";
  constexpr char kFenceName[] = "Fence";
  extern const char *kOpcodeNames[static_cast<int>(
      OpcodeEnum::kPastMaxValue)];

  enum class SimpleResourceEnum {
    kNone = 0,
    kPastMaxValue = 1
  };

  enum class ComplexResourceEnum {
    kNone = 0,
    kPastMaxValue = 1
  };

  enum class AttributeEnum {
    kPastMaxValue = 0
  };

}  // namespace codelab
}  // namespace sim
}  // namespace mpact

#endif  // RISCV32I_ENUMS_H

Gördüğünüz gibi, riscv32i.isa dosyası, numaralandırma türlerinden birinde tanımlanmış. Ayrıca işlem kodlarının tüm adlarını depolayan bir OpcodeNames dizisi vardır ( (riscv32i_enums.cc içinde tanımlanmıştır). Diğer dosyalar, oluşturulan kod çözücüyü içerir. Bu konu başka bir eğitimde daha ayrıntılı şekilde ele alınacaktır.

Bazel Derleme Kuralı

Bazel'deki ISA kod çözücü hedefi, mpact/sim/decoder/mpact_sim_isa.bzl üzerinden yüklenen mpact_isa_decoder mpact-sim deposunda. Bu eğitim için riscv_isa_decoder/BUILD:

mpact_isa_decoder(
    name = "riscv32i_isa",
    src = "riscv32i.isa",
    includes = [],
    isa_name = "RiscV32I",
    deps = [
        "//riscv_semantic_functions:riscv32i",
    ],
)

Bu kural, C++ kodunu oluşturmak için ISA ayrıştırıcı aracını ve oluşturucuyu çağırır, daha sonra, oluşturulan dosyayı diğer kuralların bağımlı olabileceği bir kitaplıkta derler. //riscv_isa_decoder:riscv32i_isa etiketi. includes bölümü kullanılır kullanın..isa İlgili içeriği oluşturmak için kullanılan isa_name, hangi belirli isa'yı belirtmek için kullanılır (birden fazla ISA ise zorunludur) kod çözücünün oluşturulacağı kaynak dosyada belirtilir.


Kayıt-Kayıt ALU Talimatları Ekleme

Şimdi riscv32i.isa dosyasına bazı yeni talimatlar eklemenin zamanı geldi. İlk Talimat grubu, add, and vb. RiscV32'de bunların tümü R tipi ikili talimat biçimini kullanır:

31..25 24...20 19...15 14..12 11..7 6..0
7 5 5 3 5 7
func7 rs2 rs1 func3 . işlem kodu

Biçimden bağımsız kod çözücü oluşturmak için .isa dosyası kullanılsa da girişlere yön vermek için ikili program biçimini ve düzenini göz önünde bulundurmak açısından yararlıdır. Siz Gördüğünüz gibi, veri feed'ini dolduran kod çözücüyle ilgili talimat nesneleri: rs2, rs1 ve rd. Bu noktada aynı şekilde kodlanan tam sayı kayıtları (bit dizileri) için bu adlar tüm talimatlarda aynı talimat alanlarında göstermektir.

Ekleyeceğimiz talimatlar şunlardır:

  • add - tam sayı toplama.
  • and - bit tabanlı ve.
  • or - bit tabanlı veya.
  • sll - sola kaydırma mantıksal.
  • sltu - "Küçüktür" olarak ayarla, imzasız.
  • sub: Tamsayı çıkarma işlemi.
  • xor - bit tabanlı xor.

Bu talimatların her biri,opcodes riscv32i alan tanımı. Hatırlayacağınız üzere, adları, işlem kodlarını, kodları, ve anlamsal işlevi hakkında daha fazla bilgi sahibi olmanızı sağlar. İsim kolay, yukarıdaki işlem kodu adlarını kullanalım. Ayrıca, hepsi aynı işlenenleri kullandığından işlenen spesifikasyonu için { : rs1, rs2 : rd} kullanabiliriz. Bunun anlamı, rs1 tarafından belirtilen kayıt kaynağı işleneninin kaynakta dizini 0 olur talimat nesnesindeki işlem gören vektörü, belirtilen kayıt kaynağı işleneni rs2'ye göre dizin 1'e ve kayıt hedef işleneni rd hedef işlenen vektördeki tek öğe olacaktır (endeks 0'da).

Sırada, anlamsal fonksiyon spesifikasyonu var. Bu, anahtar kelime semfunc ve atama için kullanılabilecek bir çağrılabilen C++ dizesi std::function olarak değiştirdik. Bu eğiticide, fonksiyonları kullanacağız; dizesi "&MyFunctionName" olacak. fence talimatı; bunlar "&RV32IAdd", "&RV32IAnd" vb. olmalıdır.

Sonuncusu da sökme spesifikasyonu. Bu anahtar kelime disasm anahtar kelimesiyle başlar ve ardından, talimatı dize olarak yazdırılmalıdır. Ekranın önünde % işareti kullanarak işlem gören adı, dize gösterimini kullanan bir dize değişikliğini gösterir işleyeceğiz. add talimatı için bu değer şu şekilde olacaktır: disasm: "add", "%rd, %rs1,%rs2". Bu, add talimatına ait girişin örneğin:

    add{ : rs1, rs2 : rd},
      semfunc: "&RV32IAdd",
      disasm: "add", "%rd, %rs1, %rs2";

Devam edin ve riscv32i.isa dosyasını düzenleyin ve tüm bu talimatları .isa açıklama. Yardıma ihtiyacınız olursa (veya çalışmanızı kontrol etmek isterseniz) açıklama dosyası burada bulabilirsiniz.

Talimatlar riscv32i.isa dosyasına eklendikten sonra gerekli olacaktır oluşturulan yeni anlamsal işlevlerin her biri için şu konumda bulunan rv32i_instructions.h dosyasına referansta bulunulmuştur: `../semantic_functions/. Yardıma ihtiyacınız olursa (veya çalışmalarınızı kontrol etmek isterseniz) yanıt burada bulabilirsiniz.

Bu işlemleri tamamladıktan sonra riscv_isa_decoder uygulamasına geri dönün. dizini oluşturun ve yeniden oluşturun. Oluşturulan kaynak dosyaları inceleyebilirsiniz.


Anında ALU Talimatları Ekleme

Ekleyeceğimiz bir sonraki talimat grubu, kayıtlardan biri yerine anında değer katar. Bu üç grup talimatlar (bir sonraki alana göre): I-Type hızlı talimatları hemen 12 bit imzalı, özel I-Type hızlı talimatları ve U Türü için 20 bitlik imzasız bir anlık değer gösterilir. Biçimler aşağıda gösterilmiştir:

I-Type'ın anlık biçimi:

31...20 19...15 14..12 11..7 6..0
12 5 3 5 7
imm12 rs1 func3 . işlem kodu

Özel I-Type hızlı biçimi:

31..25 24...20 19...15 14..12 11..7 6..0
7 5 5 3 5 7
func7 uimm5 rs1 func3 . işlem kodu

U-Type hızlı biçimi:

31...12 11..7 6..0
20 5 7
uimm20 . işlem kodu

Gördüğünüz gibi, rs1 ve rd işlenenleri ve tamsayı kayıtları temsil etmek için kullanılır. Dolayısıyla bu adlar elde edilir. Anlık değer alanlarının uzunluğu ve konumu farklıdır ve imm12 imzası varken iki (uimm5 ve uimm20) imzasız. Her biri bunlar kendi adlarını kullanır.

Dolayısıyla, I-Type talimatlarının işlenenleri { : rs1, imm12 :rd } olmalıdır. Özel I-Type talimatları için { : rs1, uimm5 : rd} olmalıdır. U Tipi talimat işleneni spesifikasyonu { : uimm20 : rd } olmalıdır.

Eklememiz gereken I-Type talimatları şunlardır:

  • addi - Hemen ekleyin.
  • andi - Bit tabanlı ve anında.
  • ori - Bit tabanlı veya anında.
  • xori - Bit tabanlı Xor ve anında.

Eklememiz gereken özel I-Type talimatları şunlardır:

  • slli - Hemen sola mantıksal olarak kaydırır.
  • srai - Hemen aritmetiği sağa kaydır.
  • srli - Hemen sağa kaydırır.

Eklememiz gereken U-Type talimatları şunlardır:

  • auipc - Hemen pc'ye ekle.
  • lui - Hemen üst öğeyi yükle.

İşletim kodları için kullanılacak adlar, talimat adlarından doğal bir şekilde gelir (hepsi benzersiz olduğundan yenilerini bulmaya gerek yok). Mesele, semantik fonksiyonları belirterek talimat nesnelerinin temel işlenenden bağımsız olan kaynak işlenenlerine arayüzler türü. Bu, aynı işleme sahip ancak aynı işlemi gerçekleştirecek talimatlar için işlem gören türlerinde farklılık gösterebilir, aynı anlamsal işlevi paylaşabilir. Örneğin, addi talimatı, aşağıdaki durumlarda add talimatıyla aynı işlemi gerçekleştirir: biri işlenen türü yok sayılır, böylece aynı anlamsal işlevi kullanabilir "&RV32IAdd" spesifikasyonu. Benzer şekilde andi, ori, xori ve slli için de geçerlidir. Diğer talimatlarda yeni anlamsal işlevler kullanılmaktadır, ancak bunlar adlandırılmalı işleme göre değil, işlenenlere göre değişir. Dolayısıyla srai için "&RV32ISra" kullanın. İlgili içeriği oluşturmak için kullanılan auipc ve lui U Tipi talimatlarının kayıtlı eşdeğerleri olmadığından sorun yok "&RV32IAuipc" ve "&RV32ILui" kullanmak için.

Sökme dizeleri önceki alıştırmadakilere çok benzer, ancak beklediğiniz gibi, %rs2 referansları %imm12, %uimm5 ve veya %uimm20 (hangisi uygunsa)

Devam edin ve değişiklikleri yapın ve geliştirin. Oluşturulan çıkışı kontrol edin. Tıpkı daha önceden çalışmanızı riscv32i.isa ve rv32i_instructions.h olmalıdır.


Eklememiz gereken dal ve atlama ve bağlantı talimatlarında bir hedef kullanılır yalnızca talimatın kendisinde ima edilen işlem göre, yani sonraki pc'de değer. Bu aşamada, bunu şu ada sahip uygun bir işlenen olarak ele alacağız: next_pc Sonraki bir eğiticide ayrıntılı olarak açıklanacaktır.

Şube Talimatları

Eklediğimiz dallar B-Type kodlamasını kullanıyor.

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 işlem kodu

Farklı doğrudan alanlar, 12 bit imzalı bir hemen olacak şekilde birleştirilir. değer. Biçim gerçekten alakalı olmadığından buna "hemen" adını veriyoruz. bimm12, 12 bit dal için anında kullanılır. Parçalanma, kod çözücüyü oluşturma hakkında bir sonraki eğiticiye göz atın. Tüm şube talimatları, rs1 ve rs2 tarafından belirtilen tam sayı kayıtlarını karşılaştırır. koşul doğruysa hemen değer mevcut pc değerine yürütülecek bir sonraki talimatın adresini üretir. bu nedenle dal talimatları { : rs1, rs2, bimm12 : next_pc } olmalıdır.

Eklememiz gereken dal talimatları şunlardır:

  • beq - Eşitse dal.
  • bge - Büyükse veya eşitse dal.
  • bgeu - Büyüktür veya eşittir imzalanmamışsa şube.
  • blt - Küçükse şubelere ayırın.
  • bltu - İmzalanmamışsa şubelerden yararlanın.
  • bne - Eşit değilse dal.

Bu işlem kodu adlarının tümü benzersiz olduğundan .isa içinde yeniden kullanılabilir dokunun. Elbette yeni anlamsal işlev adları da eklenmelidir (ör. "&RV32IBeq" vb.

Söküm spesifikasyonu şimdi biraz daha karmaşık. Talimat, hedefi aslında parçası olmadan hesaplamak için kullanılır sayısı kadar satır öğesidir. Ancak bu, söz konusu Google Hesabı'nda saklanan bilgilerin bir talimat nesnesidir. Dolayısıyla bu kullanılabilir. Çözüm, sisteme ifade söz dizimini kullanmanız gerekir. "%" yerine ardından işlem adını almak için %(ifade: yazdırma biçimi) yazabilirsiniz. Yalnızca çok basit desteklenir ancak adres artı ofseti bunlardan biri. @ geçerli talimat adresi için kullanılan simge. Yazdırma biçimi şuna benzer: C stilinde yazdırma biçimleri, ancak başında % yer almaz. için ayırma biçimi ve beq talimatı şu şekilde olur:

    disasm: "beq", "%rs1, %rs2, %(@+bimm12:08x)"

Yalnızca iki atlama ve bağlantı talimatı eklenmesi gerekir: jal (atlama ve bağlantı) ve jalr (dolaylı atlama ve bağlantı).

jal talimatı, J-Type kodlamasını kullanır:

31 30...21 20 19...12 11..7 6..0
1 10 1 8 5 7
imm imm imm imm . işlem kodu

Dal talimatlarında olduğu gibi 20 bit'lik anlık dosya da birden çok alana sahip olacağı için bu alanı jimm20 olarak adlandıracağız. Parçalanma önemli değil şu anda ancak önümüzdeki kod çözücüyü oluşturma hakkında eğitici videomuzu izleyin. İşlenen spesifikasyon { : jimm20 : next_pc, rd } olur. İki platform olduğuna dikkat edin üçüncü taraf işlem sağlayıcılarına, sonraki pc değerine ve teşekkür ederiz.

Yukarıdaki dal talimatlarına benzer şekilde, ayırma biçimi şu şekilde olur:

    disasm: "jal", "%rd, %(@+jimm20:08x)"

Dolaylı atlama ve bağlantı, hemen 12 bit ile I-Type biçimini kullanır. Google , Hedef talimat adresini üretmek için rs1. Bağlantı kaydı rd tarafından belirtilen tam sayı kaydı.

31...20 19...15 14..12 11..7 6..0
12 5 3 5 7
imm12 rs1 func3 . işlem kodu

Kalıbı görmüşseniz, işlem gören spesifikasyonunun jalr için { : rs1, imm12 : next_pc, rd } değeri ve sökme işlemi spesifikasyon:

    disasm: "jalr", "%rd, %rs1, %imm12"

Değişiklikleri yapın ve sonra oluşturun. Oluşturulan çıkışı kontrol edin. Adil önceki gibi çalışmanızı riscv32i.isa ve rv32i_instructions.h olmalıdır.


Mağaza Talimatları Ekleyin

Mağazanın talimatları çok basit. Tümü S-Type biçimini kullanır:

31..25 24...20 19...15 14..12 11..7 6..0
7 5 5 3 5 7
imm rs2 rs1 func3 imm işlem kodu

Gördüğünüz gibi, bu başka bir parçalı 12 bit'e ilişkin başka bir örnektir. simm12 olarak adlandıralım. Mağaza talimatlarının tümünde tam sayı değeri saklanır eklenerek elde edilen etkili adrese rs2 tarafından belirtilen kayıt rs1 tarafından gösterilen tam sayı kaydının değeri 12 bit'i hemen tıklayın. İşlem gören biçimi, şunun için { : rs1, simm12, rs2 } olmalıdır: mağazadaki talimatları uygulayın.

Uygulanması gereken mağaza talimatları şunlardır:

  • sb - Depolama baytı.
  • sh - Yarım kelime depolayın.
  • sw - Mağaza kelimesi.

sb için sökme teknik özellikleri beklediğiniz gibidir:

    disasm: "sb", "%rs2, %simm12(%rs1)"

Anlamsal fonksiyon spesifikasyonları da şu şekildedir: "&RV32ISb", vb.

Değişiklikleri yapın ve sonra oluşturun. Oluşturulan çıkışı kontrol edin. Adil önceki gibi çalışmanızı riscv32i.isa ve rv32i_instructions.h olmalıdır.


Yükleme Talimatları Ekleyin

Yükleme talimatları, simülatörü kullanın. Yük gecikmesinin yüksek olduğu durumları modelleyebilmek için belirsiz, yükleme talimatları iki ayrı eyleme bölünür: 1) etkili adres hesaplaması ile bellek erişimi ve 2) sonuç geri yazma. simülatörü kullanarak bu işlem, yüklemenin anlamsal işlemini ikiye ana talimat ve alt talimat olabilir. Dahası, işlem görenleri belirttiğimizde, bunları hem ana hem de child talimatıdır. Bu, işlenen spesifikasyonunu bir üçlülerin listesi. Söz dizimi şöyledir:

{(predicate : sources : destinations), (predicate : sources : destinations), ... }

Yükleme talimatlarının tümü, önceki videolarda olduğu gibi I-Type biçimini talimatlar:

31...20 19...15 14..12 11..7 6..0
12 5 3 5 7
imm12 rs1 func3 . işlem kodu

İşlem gören spesifikasyonu, adresi hesaplamak için gerekli işlenenleri böler. ve yük verileri için kayıt hedefinden bellek erişimini başlatın: {( : rs1, imm12 : ), ( : : rd) }

Anlamsal işlem iki talimata bölündüğünden, anlamsal fonksiyonlar iki çağrılabilir. lw (kelime yükle) için bu değer şu şekildedir: yazılmış:

    semfunc: "&RV32ILw", "&RV32ILwChild"

Söküm spesifikasyonu daha gelenekseldir. ele alacağız. lw için bu değer:

    disasm: "lw", "%rd, %imm12(%rs1)"

Uygulanması gereken yükleme talimatları şunlardır:

  • lb - Bayt yükleme.
  • lbu - Yükleme baytı imzasız.
  • lh - Yarım kelime yükle.
  • lhu - Yarım kelime imzasız yükle.
  • lw - Kelime yükle.

Değişiklikleri yapın ve sonra oluşturun. Oluşturulan çıkışı kontrol edin. Adil önceki gibi çalışmanızı riscv32i.isa ve rv32i_instructions.h olmalıdır.

Bu noktaya ulaştığınız için teşekkür ederiz. Umarız bu bilgiler işinize yaramıştır.