前回のRocket Chipの標準論理合成では、FPGA向けにVivadoで合成してもBlockRAMが正常に推論されず、Dcacheが面積のほとんどを消費してしまう構成になってしまっていた。
どうにかしてBlockRAMを使うように変更することはできないだろうか。
そもそも、なぜSRAMの部分がLUTで作られてしまうかというと、Rocket Chipの標準フローで合成すると、ASIC用にSRAMは外部定義に変更される。
rocket-chip/emulator/freechips.rocketchip.system.DefaultConfig.behav_srams.v
というのがそれだ。
ASICを作る場合は、このモジュールを各プロセスに対応するSRAMに置き換える。
ただしこれは標準的なSRAMのように、WMEMのようなビット単位のWrite Maskが付いているSRAMを前提としており、BlockRAMを推論するのには不向きな構成になっている。
module data_arrays_0_ext( input RW0_clk, input [8:0] RW0_addr, input RW0_en, input RW0_wmode, input [31:0] RW0_wmask, input [255:0] RW0_wdata, output [255:0] RW0_rdata ); reg reg_RW0_ren; reg [8:0] reg_RW0_addr; reg [255:0] ram [511:0]; `ifdef RANDOMIZE_MEM_INIT integer initvar; initial begin ... always @(posedge RW0_clk) if (RW0_en && RW0_wmode) begin if (RW0_wmask[0]) ram[RW0_addr][7:0] <= RW0_wdata[7:0]; if (RW0_wmask[1]) ram[RW0_addr][15:8] <= RW0_wdata[15:8]; if (RW0_wmask[2]) ram[RW0_addr][23:16] <= RW0_wdata[23:16]; if (RW0_wmask[3]) ram[RW0_addr][31:24] <= RW0_wdata[31:24]; if (RW0_wmask[4]) ram[RW0_addr][39:32] <= RW0_wdata[39:32]; if (RW0_wmask[5]) ram[RW0_addr][47:40] <= RW0_wdata[47:40]; if (RW0_wmask[6]) ram[RW0_addr][55:48] <= RW0_wdata[55:48];
そこでどうにかしてこの外部SRAM向けのWrapperが生成されるのを防がなければならないのだが、SiFive社の提供するFreedom環境ではSRAM Wrapperは生成されていない。どうやっているんだろう。
いろいろ調査した結果、SRAM Wrapperを作らない方法としては、FIRRTLでのVerilogファイルを生成する際、--repl-seq-mem
を付加しないことがポイントなのではないかと思えてきた。
rocket-chip/emulator/Makefrag-verilator
の抜粋
%.v: %.fir $(FIRRTL_JAR) echo $(FIRRTL) mkdir -p $(dir $@) $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf
freedom/common.mk
の抜粋
$(verilog): $(firrtl) $(FIRRTL_JAR) $(FIRRTL) -i $(firrtl) -o $@ -X verilog
したがって、Rocket-Chipのリポジトリ内の Makefrag-verilator
を以下のように改造した。これでfreechips.rocketchip.system.DefaultConfig.v
を再生成すると、外部SRAM Wrapperを生成しなくなっていた。成功だ!
diff --git a/emulator/Makefrag-verilator b/emulator/Makefrag-verilator index 021e131..86fdea6 100644 --- a/emulator/Makefrag-verilator +++ b/emulator/Makefrag-verilator @@ -3,8 +3,9 @@ #-------------------------------------------------------------------- firrtl = $(generated_dir)/$(long_name).fir verilog = \ - $(generated_dir)/$(long_name).v \ - $(generated_dir)/$(long_name).behav_srams.v \ + $(generated_dir)/$(long_name).v + +# $(generated_dir)/$(long_name).behav_srams.v \ .SECONDARY: $(firrtl) $(verilog) @@ -12,9 +13,12 @@ $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(boot mkdir -p $(dir $@) cd $(base_dir) && $(SBT) "run-main $(PROJECT).Generator $(generated_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)" -%.v %.conf: %.fir $(FIRRTL_JAR) +%.v: %.fir $(FIRRTL_JAR) + echo $(FIRRTL) mkdir -p $(dir $@) - $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf + $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog + +# $(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno -ffaaf
freechips.rocketchip.system.DefaultConfig.v
をVivadoで合成し、Utilizationを出力させてみた。よっしゃ!しっかりBlockRAMが使われている!
+---------------------------------------+----------------------------+------------+------------+---------+------+-------+--------+--------+--------------+ | Instance | Module | Total LUTs | Logic LUTs | LUTRAMs | SRLs | FFs | RAMB36 | RAMB18 | DSP48 Blocks | +---------------------------------------+----------------------------+------------+------------+---------+------+-------+--------+--------+--------------+ | dcache | DCache_dcache | 2585 | 2584 | 0 | 1 | 2577 | 0 | 36 | 0 | | (dcache) | DCache_dcache | 898 | 897 | 0 | 1 | 536 | 0 | 4 | 0 | | data | DCacheDataArray | 324 | 324 | 0 | 0 | 0 | 0 | 32 | 0 | | tlb | TLB | 1363 | 1363 | 0 | 0 | 2041 | 0 | 0 | 0 |
合成結果の効果は見ての通りだ。BlockRAMを活用したことで、しっかり面積が削減できている。
これで、公平な評価が取れそうだな。