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で表示します。
図230.1 GTKWaveによる波形
前のブログ
次のブログ