FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages

FIRRTLに入門する (24. FIRRTLにおけるメモリの生成を調査する)

https://raw.githubusercontent.com/freechipsproject/firrtl/master/doc/images/firrtl_logo.svg?sanitize=true
$ sbt assembly && ./utils/bin/firrtl -td regress -i ./regress/ICache.fir -X sverilog -ll trace 2>&1 | tee ICache.log
======== Starting Transform CheckInitialization$ ========
Exception in thread "main" firrtl.passes.PassExceptions:
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.data[1] <= mux(refill_done, mux(_T_321[1], _T_304[1], VOID), VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.mask[0] <= mux(refill_done, _GEN_7, VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.data[3] <= mux(refill_done, mux(_T_321[3], _T_304[3], VOID), VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.mask[3] <= mux(refill_done, _GEN_10, VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.data[0] <= mux(refill_done, mux(_T_321[0], _T_304[0], VOID), VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.data[2] <= mux(refill_done, mux(_T_321[2], _T_304[2], VOID), VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.mask[2] <= mux(refill_done, _GEN_9, VOID)
firrtl.passes.CheckInitialization$RefNotInitializedException:  @[ICache.scala 97:25] : [module ICache]  Reference tag_array is not fully initialized.
   : tag_array._T_328.mask[1] <= mux(refill_done, _GEN_8, VOID)

いろいろ調査した結果、どうもSRAMを最初に展開しておかないといけないのが問題らしい。つまり、以下のようなFIRコードを考える。

circuit VecMem :
  module VecMem :
    input clock : Clock

    input in: UInt<32>
    input wr_en: UInt<1>
    input rd_en: UInt<1>

    input addr: UInt<6>
    input data: UInt<1>

    output rdata : UInt<32>[4]

    smem array : UInt<32>[4][64]

    when rd_en :
      read mport rdata_tmp = array[addr], clock
    when wr_en :
      write mport wdata = array[addr], clock

    rdata <= rdata_tmp

このときにExpandConnect()においてIsInvalidの場合、ちゃんと展開しておかなければならない。

  • src/main/scala/firrtl/passes/Passes.scala
object ExpandConnects extends Pass {
    ...
           case sx: DefMemory => flows(sx.name) = SourceFlow; sx
           case sx: DefNode => flows(sx.name) = SourceFlow; sx
           case sx: IsInvalid =>
             // create_expsからcreate_exps_connectに置き換える。
             val invalids = create_exps_connect(sx.expr).flatMap { case expx =>
                flow(set_flow(expx)) match {
                   case DuplexFlow => Some(IsInvalid(sx.info, expx))
                   case SinkFlow => Some(IsInvalid(sx.info, expx))

これでFIRRTLを実行してみる。

sbt assembly && ./utils/bin/firrtl -td regress -i regress/VecMem.fir -X sverilog -ll trace 2>&1 | tee VecMem.log

ExpandConnect()実行前。

...
    array.wdata.data is invalid
    array.wdata.mask is invalid
...

ExpandConnect()実行後。

    array.wdata.data[0] is invalid
    array.wdata.data[1] is invalid
    array.wdata.data[2] is invalid
    array.wdata.data[3] is invalid
    array.wdata.mask[0] is invalid
    array.wdata.mask[1] is invalid
    array.wdata.mask[2] is invalid
    array.wdata.mask[3] is invalid

このように展開しておく。これで一応エラーなく実行できるようになったようだ。

  logic [31:0][3:0] array [0:63];
...
  assign array_rdata_tmp_addr = array_rdata_tmp_addr_pipe_0;
  assign array_rdata_tmp_data = array[array_rdata_tmp_addr];
...

ただしこれでもまだおかしいところがある。また解析して作り直そう。