FPGA開発日記

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

オープンソース・アウトオブオーダCPU NaxRiscvを概観する (5. SpinalHDLのソースコード解析)

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

もうちょっとなんとかSpinal HDLのわけわからん記述が読めるようになりたい: とりあえずRVC Alignerの部分で何とか理解できる部分はないだろうか。

class AlignerPlugin(var decodeCount : Int,
                    var inputAt : Int) extends Plugin with FetchPipelineRequirements with FetchInjector{
/* ... 途中省略 ... */
  val logic = create late new Area {
/* ... 途中省略 ... */

この辺のマスクの実装は良く分からんね。MASK_FRONTがFetchステージからのマスクかしら。 MASK_BACKはどういう意味なんだ?WORD_BRANC_VALID SLICE_COUNT`はフェッチラインの中でRVC命令が何個入るかを示している。

val maskGen = new Area {
      val maskStage = fetch.getStage(inputAt-1)
      import maskStage._
      MASK_FRONT := B((0 until SLICE_COUNT).map(i => B((1 << SLICE_COUNT) - (1 << i), SLICE_COUNT bits)).read(FETCH_PC(sliceRange)))
    }

    MASK_BACK  := B((0 until SLICE_COUNT).map(i => B((2 << i)-1, SLICE_COUNT bits)).read(WORD_BRANCH_SLICE))
    when(!WORD_BRANCH_VALID){ MASK_BACK.setAll() }

以下はフェッチした命令とその情報を格納するバッファを定義しているものと思われる:

    val buffer = new Area {
      val data = Reg(WORD)
      val mask = Reg(MASK_FRONT) init (0)
      val pc   = Reg(PC())
      val fault = Reg(Bool())
      val fault_page = Reg(Bool())
      val branchValid = Reg(WORD_BRANCH_VALID())
      val branchSlice = Reg(WORD_BRANCH_SLICE())
      val branchPcNext = Reg(WORD_BRANCH_PC_NEXT())
      val wordContexts = lastWordContextSpec.map(Reg(_))
      val firstWordContexts = firstWordContextSpec.map(Reg(_))
    }

うーん、decoderについては本当に記述が意味不明だ。

    val decoders = for (i <- 0 until SLICE_COUNT * 2) yield new Area {
      // 命令内のスライスにRVC命令の候補が含まれているか:
      val rvc = RVC.get generate slices.data(i)(1 downto 0) =/= 3

      // RVCが有効な場合:各スライスでどの部分が命令として有効化のビットマスクを作る
      val usage = if(RVC) {
        def mask16 = B(1 << i, SLICE_COUNT*2 bits)
        def mask32 = B(3 << i, SLICE_COUNT*2 bits)
        if(i == SLICE_COUNT*2 - 1) mask16 else rvc ? mask16 | mask32
      } else {
        B(1 << i, SLICE_COUNT*2 bits)
      }

      val notEnoughData = RVC.get match {
        case true =>
          if(i == SLICE_COUNT * 2 - 1)
            !rvc  // 最上位のスライスがRVCではない?
          else if(i == SLICE_COUNT - 1)
            !rvc && (!MASK_FRONT.lsb || !isInputValid) // うーん、これは何のため?
          else
            False
        case false => False
      }


      val pastPrediction = if(i <= SLICE_COUNT) False else WORD_BRANCH_VALID && U(i - SLICE_COUNT) > WORD_BRANCH_SLICE //TODO may use MASK_BACK instead for timings ?
      val usable = !notEnoughData && !pastPrediction
    }