FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RocketChipをカスタマイズするためのチュートリアル(1)

RocketChipはChiselで記述されており、その実装はオープンになっているので、Chiselを操ることができればRocketChipを自由にカスタマイズすることができる。

さらに、RISC-VのGCCをカスタマイズすれば専用命令を追加することができ、自分の好きな命令を追加することができる。 これらのRocketChipのカスタマイズや、GCCの追加などをまとめてチュートリアルとして公開されているのが、lowRISCプロジェクトだ。

lowRISCプロジェクトはケンブリッジ大学で始まったプロジェクトで、RISC-VをベースとしたSoCを開発することを目的としている。

f:id:msyksphinz:20170813132837p:plain

lowRISC · lowRISC

lowRISC is creating a fully open-sourced, Linux-capable, RISC-V-based SoC, that can be used either directly or as the basis for a custom design. We aim to complete our SoC design this year.

このチュートリアルでは、キャッシュメモリに対してタグを挿入するためのRISC-Vカスタマイズの方法について説明してある。

このチュートリアルは2015年に記述されたものでずいぶんと古いが、RISC-Vのカスタマイズの方法を説明しているものとして貴重だ。

このチュートリアルでは、キャッシュメモリに対してタグを追加する。さらにタグをロードストアするための命令を追加する。 この追加したタグによって、キャッシュラインに対してより柔軟な属性を追加することができる。

RocketChipにタグ付きメモリを追加するためのチュートリアル

まず、本チュートリアルで何をしようとしているのか、ということだが、RocketChipに搭載されている512ビットのL1キャッシュタグに対してタグを追加する。 このタグは新規追加命令(ltag,stag)によってアクセスすることが出来る。 下記の図はチュートリアルから引用したものだが、512ビットのタグに対して64ビット毎にタグビットを追加する。 このタグ情報はメインデータメモリに対しても保存されており、タグ情報はメインデータメモリの特定の領域に保存されるようになる。 タグの転送による性能低下を防ぐために、RocketChipに対してタグキャッシュメモリを追加して、外部にタグ情報を何度も取得しに行く必要性を低減している。 タグアドレスのベースとしてはTagBaseAddrc=0x0F00_0000に設定してある。

f:id:msyksphinz:20170813134322p:plain

(※ http://www.lowrisc.org/docs/tagged-memory-v0.1/tags/ より引用)

f:id:msyksphinz:20170813134338p:plain

(※ http://www.lowrisc.org/docs/tagged-memory-v0.1/tags/ より引用)

新規命令としては、Load Tag、Store Tag命令を追加する。

# load the tag associated with DW located at rs1 + imm to register rd
ltag rd, imm(rs1)

# store the tag in rd to the DW located at rs1 + imm
stag rd, imm(rs1)

タグ付きキャッシュメモリをサポートするための命令を追加する

タグ付きキャッシュメモリをサポートするために、RocketChipへの命令追加と、GCCへの命令追加を行う。

新規命令としては、RISC-VのReservedの場所に命令を追加している。

f:id:msyksphinz:20170813135554p:plain

(※ http://www.lowrisc.org/docs/tagged-memory-v0.1/new-instructions/より引用)

チュートリアルではrocket/src/main/scala/instructions.scala となっているが、現在のRocketChipの実装では src/main/scala/rocket/Instructions.scala に移動しているようだ。

diff --git a/src/main/scala/rocket/Instructions.scala b/src/main/scala/rocket/Instructions.scala
index af61ea7..8386c19 100644
--- a/src/main/scala/rocket/Instructions.scala
+++ b/src/main/scala/rocket/Instructions.scala
@@ -214,6 +214,9 @@ object Instructions {
   def RDINSTRETH         = BitPat("b11001000001000000010?????1110011")
   def SCALL              = BitPat("b00000000000000000000000001110011")
   def SBREAK             = BitPat("b00000000000100000000000001110011")
+  def LTAG               = BitPat("b?????????????????000?????1010111")
+  def STAG               = BitPat("b?????????????????001?????1010111")
+
 }
 object Causes {
   val misaligned_fetch = 0x0

次に、制御信号を生成する記述を追加する。

diff --git a/src/main/scala/rocket/IDecode.scala b/src/main/scala/rocket/IDecode.scala
index bc88b9f..d16e498 100644
--- a/src/main/scala/rocket/IDecode.scala
+++ b/src/main/scala/rocket/IDecode.scala
@@ -325,3 +325,10 @@ class RoCCDecode(implicit val p: Parameters) extends DecodeConstants
     CUSTOM3_RD_RS1->    List(Y,N,Y,N,N,N,N,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N,N),
     CUSTOM3_RD_RS1_RS2->List(Y,N,Y,N,N,N,Y,Y,A2_ZERO,A1_RS1, IMM_X, DW_XPR,FN_ADD,   N,M_X,        MT_X, N,N,N,N,N,Y,CSR.N,N,N,N,N))
 }
+
+class TagDecode(implicit val p: Parameters) extends DecodeConstants
+{
+  val table: Array[(BitPat, List[BitPat])] = Array(
+    LTAG->              List(Y,N,N,N,N,N,N,Y,A2_IMM, A1_RS1, IMM_I, DW_XPR,FN_ADD,   Y,M_XRD,      MT_T, N,N,Y,N,N,N,CSR.N,N,N,N,N),
+    STAG->              List(Y,N,N,N,N,N,Y,Y,A2_IMM, A1_RS1, IMM_S, DW_XPR,FN_ADD,   Y,M_XWR,      MT_T, N,N,N,N,N,N,CSR.N,N,N,N,N))
+}

この信号線の意味だが、IDecode.scala に説明が入っている。

  def default: List[BitPat] =
                //           jal                                                                 renf1             fence.i
                //   val     | jalr                                                              | renf2           |
                //   | fp_val| | renx2                                                           | | renf3         |
                //   | | rocc| | | renx1     s_alu1                          mem_val             | | | wfd         |
                //   | | | br| | | | s_alu2  |       imm    dw     alu       | mem_cmd   mem_type| | | | div       |
                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | wxd     | fence
                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | | csr   | | amo
                //   | | | | | | | | |       |       |      |      |         | |           |     | | | | | | |     | | | dp
                List(N,X,X,X,X,X,X,X,A2_X,   A1_X,   IMM_X, DW_X,  FN_X,     N,M_X,        MT_X, X,X,X,X,X,X,CSR.X,X,X,X,X)

つまり、ここでは、MT_Tというメモリアクセスタイプを追加したということである。

diff --git a/src/main/scala/rocket/Consts.scala b/src/main/scala/rocket/Consts.scala
index bde6201..13617ff 100644
--- a/src/main/scala/rocket/Consts.scala
+++ b/src/main/scala/rocket/Consts.scala
@@ -16,6 +16,7 @@ trait ScalarOpConstants {
   def MT_BU = UInt("b100")
   def MT_HU = UInt("b101")
   def MT_WU = UInt("b110")
+  def MT_T  = UInt("b111") // tag
   def mtSize(mt: UInt) = mt(MT_SZ-2, 0)
   def mtSigned(mt: UInt) = !mt(MT_SZ-1)

こんな感じだろうか。

次に、このデコードテーブルを新たに追加する。

diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala
index 0940947..86ca02f 100644
--- a/src/main/scala/rocket/RocketCore.scala
+++ b/src/main/scala/rocket/RocketCore.scala
@@ -116,6 +116,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p)
     (usingRoCC.option(new RoCCDecode)) ++:
     ((xLen > 32).option(new I64Decode)) ++:
     (usingVM.option(new SDecode)) ++:
+    Seq(new TagDecode) ++:
     (usingDebug.option(new DebugDecode)) ++:
     Seq(new IDecode)
   } flatMap(_.table)

アセンブラのアップデート

GCCアセンブリ言語のサポートを行う。まずはbinutilsによるアセンブリのアップデートから。

diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index f80037b..667a80b 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -499,6 +499,11 @@
 #define MASK_CUSTOM3_RD_RS1  0x707f
 #define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
 #define MASK_CUSTOM3_RD_RS1_RS2  0x707f
+#define MATCH_STAG 0x1057
+#define MASK_STAG 0x707f
+#define MATCH_LTAG 0x57
+#define MASK_LTAG 0x707f
+
 #define CSR_FFLAGS 0x1
 #define CSR_FRM 0x2
 #define CSR_FCSR 0x3
@@ -975,6 +980,9 @@ DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
 DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
 DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
 DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
+
+DECLARE_INSN(stag, MATCH_STAG, MASK_STAG)
+DECLARE_INSN(ltag, MATCH_LTAG, MASK_LTAG)
 #endif
 #ifdef DECLARE_CSR
 DECLARE_CSR(fflags, CSR_FFLAGS)
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index 8343198..a852ae5 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -623,6 +623,9 @@ const struct riscv_opcode riscv_opcodes[] =
 {"sfence.vma","I",   "s,t",  MATCH_SFENCE_VMA, MASK_SFENCE_VMA, match_opcode, 0 },
 {"wfi",       "I",   "",     MATCH_WFI, MASK_WFI, match_opcode, 0 },

+{"ltag",         "I",   "d,o(s)", MATCH_LTAG, MASK_LTAG, match_opcode, 0 },
+{"stag",         "I",   "t,q(s)", MATCH_STAG, MASK_STAG, match_opcode, 0 },
+
 /* Terminate the list.  */
 {0, 0, 0, 0, 0, 0, 0}
 };