31 |
BSV(Bluespec SystemVerilog) (3) |
BSV(Bluespec SystemVerilog)によるシミュレーション
bscとは、Bluespecが最近オープンソース化したコンパイラです。詳しくは、ここを見てください。
いろいろと調整した結果、bscがインストールできました。早速、以下のようなフィボナッチモジュール(ファイル名FibOne.bsv)をコンパイルしてみます。これは、フィボナッチ数列を発生するモジュールで、前の値に次の値を加算することを繰り返すものです。
モジュールファイル:FibOne.bsv
(* synthesize *) module mkFibOne(); // register containing the current Fibonacci value Reg#(int) this_fib(); // interface instantiation mkReg#(0) this_fib_inst(this_fib); // module instantiation // register containing the next Fibonacci value Reg#(int) next_fib(); mkReg#(1) next_fib_inst(next_fib); rule fib; // predicate condition always true, so omitted this_fib <= next_fib; next_fib <= this_fib + next_fib; // note that this uses stale this_fib $display("%0d", this_fib); if ( this_fib > 10000 ) $finish(0) ; endrule: fib endmodule: mkFibOne
モジュール内にテストベンチのような\$displayや\$finishの記述があるので、これだけでテストが可能です(が、モジュール設計としては良くないので、後で外します)。
BSVプログラムの説明
以下の部分は、現在の値this_fibと次の値next_fibを保持するレジスタのインスタンスです。
// register containing the current Fibonacci value Reg#(int) this_fib(); // interface instantiation mkReg#(0) this_fib_inst(this_fib); // module instantiation // register containing the next Fibonacci value Reg#(int) next_fib(); mkReg#(1) next_fib_inst(next_fib);
次のように、ruleブロックにアルゴリズム計算ルールを記述します。
this_fib <= next_fib; next_fib <= this_fib + next_fib; // note that this uses stale this_fib
コメントにも書いているように、this_fibとnext_fibは同時に変更されるので、それぞれ、直前の値を読み込み、同時に値を更新します。
Bluesimによるシミュレーション
コンパイル及びシミュレーションモデル生成(リンク)の2段階で行います。太字が入力部分です。
\$ bsc -sim FibOne.bsv
Elaborated module file created: mkFibOne.ba
\$ bsc -sim -e mkFibOne -o mkFibOne.exec
Bluesim object created: mkFibOne.{h,o}
Bluesim object created: model_mkFibOne.{h,o}
Simulation shared library created: mkFibOne.exec.so
Simulation executable created: mkFibOne.exec
mkFibOne.execというbluesimの実行ファイルが生成されたので起動します。
\$ ./mkFibOne.exec
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
Verlogの生成
次に、確認のためにverilogシミュレーションを実行します。まずbscにより、モジュールを合成可能なVerilogコードにコンパイルします。
\$ bsc -verilog FibOne.bsv
Verilog file created: mkFibOne.v
生成されたファイル名はモジュール名+".v"(mkFibOne.v)となります。
モジュールファイル:mkFibOne.v
// // Generated by Bluespec Compiler (build 38534dc) // // On Mon Mar 23 06:33:47 JST 2020 // // // Ports: // Name I/O size props // CLK I 1 clock // RST_N I 1 reset // // No combinational paths from inputs to outputs // // `ifdef BSV_ASSIGNMENT_DELAY `else `define BSV_ASSIGNMENT_DELAY `endif `ifdef BSV_POSITIVE_RESET `define BSV_RESET_VALUE 1'b1 `define BSV_RESET_EDGE posedge `else `define BSV_RESET_VALUE 1'b0 `define BSV_RESET_EDGE negedge `endif module mkFibOne(CLK, RST_N); input CLK; input RST_N; // register next_fib_inst reg [31 : 0] next_fib_inst; wire [31 : 0] next_fib_inst$D_IN; wire next_fib_inst$EN; // register this_fib_inst reg [31 : 0] this_fib_inst; wire [31 : 0] this_fib_inst$D_IN; wire this_fib_inst$EN; // register next_fib_inst assign next_fib_inst$D_IN = this_fib_inst + next_fib_inst ; assign next_fib_inst$EN = 1'd1 ; // register this_fib_inst assign this_fib_inst$D_IN = next_fib_inst ; assign this_fib_inst$EN = 1'd1 ; // handling of inlined registers always@(posedge CLK) begin if (RST_N == `BSV_RESET_VALUE) begin next_fib_inst <= `BSV_ASSIGNMENT_DELAY 32'd1; this_fib_inst <= `BSV_ASSIGNMENT_DELAY 32'd0; end else begin if (next_fib_inst$EN) next_fib_inst <= `BSV_ASSIGNMENT_DELAY next_fib_inst$D_IN; if (this_fib_inst$EN) this_fib_inst <= `BSV_ASSIGNMENT_DELAY this_fib_inst$D_IN; end end // synopsys translate_off `ifdef BSV_NO_INITIAL_BLOCKS `else // not BSV_NO_INITIAL_BLOCKS initial begin next_fib_inst = 32'hAAAAAAAA; this_fib_inst = 32'hAAAAAAAA; end `endif // BSV_NO_INITIAL_BLOCKS // synopsys translate_on // handling of system tasks // synopsys translate_off always@(negedge CLK) begin #0; if (RST_N != `BSV_RESET_VALUE) $display("%0d", $signed(this_fib_inst)); if (RST_N != `BSV_RESET_VALUE) if ((this_fib_inst ^ 32'h80000000) > 32'h80002710) $finish(32'd0); end // synopsys translate_on endmodule // mkFibOne
テストベンチの作成
bluesimは暗黙のクロックやリセットが動作するため、テストベンチ無しでもシミュレーションが実行できました。一方verilogではそのような機能は無いので以下のようなテストベンチ(ファイル名tbmkFibOne.v)を用意します。
テストベンチ中の/*AUTO〇〇*/という記述は、emacsのverilog modeによるインスタンスやポートの自動生成の機能です。C-c C-aにより、面倒なポートリストやインスタンス部分が自動生成できます。テストベンチでは、モジュールへの入力用に/*AUTOREGINPUT*/と、モジュールからの出力用に/*AUTOWIRE*/を指定しておきます。
テストベンチファイル:tbmkFibOne.v
`timescale 1ns/1ps module tb_mkFibOne; /*AUTOREGINPUT*/ // Beginning of automatic reg inputs (for undeclared instantiated-module inputs) reg CLK; // To mkFibOne of mkFibOne.v reg RST_N; // To mkFibOne of mkFibOne.v // End of automatics /*AUTOWIRE*/ mkFibOne mkFibOne (/*AUTOINST*/ // Inputs .CLK (CLK), .RST_N (RST_N)); initial begin RST_N = 1'b0; #30; RST_N = 1'b1; end initial begin CLK = 1'b0; forever begin #5; CLK = ~CLK; end end initial begin $dumpfile("tbmkFibOne.vcd"); $dumpvars(0,mkFibOne); end endmodule
Verilogシミュレーションの実行
iverilogにより実行ファイルmkFibOne.exevを生成し、シミュレーションを実行すると、同じ結果となりました。
\$ iverilog tbmkFibOne.v mkFibOne.v -o mkFibOne.exev
\$ ./mkFibOne.exev
VCD info: dumpfile tbmkFibOne.vcd opened for output.
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
波形ビュワーであるgtkwaveを起動します。verilogシミュレーションで生成したVCDファイルを指定します。
\$ gtkwave -f tbmkFibOne.vcd
GTKWave Analyzer v3.3.111 (w)1999-2020 BSI
[0] start time.
[520000] end time.
verilogシミュレーションの波形をgtkwaveで表示します。
