前回のRocket Chipの標準論理合成では、FPGA向けにVivadoで合成してもBlockRAMが正常に推論されず、Dcacheが面積のほとんどを消費してしまう構成になってしまっていた。
msyksphinz.hatenablog.com
どうにかして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
$(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を活用したことで、しっかり面積が削減できている。
これで、公平な評価が取れそうだな。