まえおき
Verilog-HDLのシミュレーションを行う際に、テストデータを外部ファイルに書いておき、(コンパイル時ではなく)シミュレーション実行時に読み込ませる手法はよく使われている手段です。
ファイルの読み込み方法として代表的なのは
- ファイルをまとめて読み込む($readmem)
- 1行づつ読み込む($fscanf)
の2パターンかと思いますが、今回は$fscanfを使用したケースを紹介します。
$fscanfを使用すべきテストパターン
- テストファイルの行数がテスト条件により可変長
- テストデータにランダムアクセスしない(頭から流すだけ)
- 1行に複数のデータがある
- bin/hex/decフォーマットが混在している
基本的な流れ
-
$fopen
を使用してファイルを開く -
$fgetc
で1文字読み出す - EOF(ファイル終端か否か判定する)
-
$fscanf
で1行分を書式付で読み出す
使用するシステムタスク
$fopen (ファイルオープン)
項目|内容|説明|
:---:|:---|:---
戻り値|ファイルディスクリプタ|0:オープン失敗
その他:オープン成功
(戻り値は、以後ファイルにアクセスする為に必要)
第一引数|ファイルパス|開きたいファイルのパスを指定
(実行ディレクトリからの相対パスでも可)
第二引数|アクセスモード|"r":リード専用
(その他のアクセスモードについては今回は割愛)
$feof(ファイル終端か調べる)
項目|内容|説明|
:---:|:---|:---
戻り値|ファイル終端に達したか否か|0以外の値が帰ってきたらファイル終端に達したことを示す
第一引数|ファイルディスクリプタ|$fopenの戻り値を渡す
$fscanf
項目|内容|説明|
:---:|:---|:---
戻り値|実行結果|-1が帰ってきたらエラー
第一引数|ファイルディスクリプタ|$fopenの戻り値を渡す
第二引数|出力フォーマット|%b:2進数
%h:16進数
(その他は説明割愛)
第三引数以降|信号|読み込んだ値を反映させるreg変数を渡す
サンプルコード
ファイルを読み込んで値を出力する"モジュール"として紹介します。
このモジュールをテストベンチTop階層で呼び出して使用します。
【モジュール仕様】
- クロック同期で動作する
- i_start入力ピンにHighを入力するとテキストデータの内容を出力する
- 出力が完了するとo_end出力ピンを1サイクルだけHighにする
- テキストデータは ”バイナリ6bit” + "Hex8bit"を1行に書く
FILE_READER.v
// =================================================================
// テストパターンファイル読み込みモジュール
// 未知の行数のテキストファイルを読み込み
// テキスト内容を出力する
// =================================================================
module FILE_READER #
(parameter TERGET_FILE_PATH="file.txt" //読込むファイルのパス
,parameter BIT_WIDE =4 //bit幅
)
(input wire i_clk //クロック
,input wire i_start //開始トリガ(1で開始)
,output wire o_end //終了トリガ
,output wire[BIT_WIDE-1:0] o_bin_dat //読み込みデータ
,output wire[7:0] o_hex_dat
);
integer fd =0 ;//ファイルディスクリプタ
integer cb =0 ;//キャラクタバッファ
integer rtn =0 ;//システムタスク戻り値
reg[BIT_WIDE-1:0] bin_dat =0 ;//テキストファイルの中身を受け取るFF
reg[7:0] hex_dat =0 ;//テキストファイルの中身を受け取るFF
reg end_trg =0 ;//終了トリガ
//出力ポートへ接続
assign o_end =end_trg ;
assign o_bin_dat =bin_dat ;
assign o_hex_dat =hex_dat ;
//スタートトリガをクロック立上りで監視
always@(posedge i_clk) begin:FILE_READ_SEQ
if(i_start)begin //開始条件
//ファイルオープン
//-------------------------------
fd=$fopen(TERGET_FILE_PATH,"r");
if(fd==0)begin
//オープン失敗
$display("File Open Error!!!!!");
//イベントから抜ける
disable FILE_READ_SEQ;
end else begin
//オープン成功
$display("File Open OK");
end
//ファイル読出しループ
//-------------------------------
begin:FILE_LOOP
forever begin
//ファイル終端に達したらループを抜ける
if($feof(fd) != 0)begin
$display("File End !!");
disable FILE_LOOP;
end
//クロック同期
@(posedge i_clk);
//書式付読出し
rtn=$fscanf(fd,"%b %h\n",bin_dat,hex_dat);
end
end
//ファイルを閉じで終了トリガを出す
//-------------------
$fclose(fd);
@(posedge i_clk);
end_trg <=1'b1;
bin_dat <={BIT_WIDE{1'b0}};
hex_dat <=8'h0;
@(posedge i_clk);
end_trg <=1'b0;
end
end
endmodule
動作環境
テストベンチTopと読み込むテキストファイルを紹介します。
FILE_READER_tb.v
`timescale 1ns/1ps
module FILE_READER_tb();
parameter BIT_WIDE =6 ;
reg i_clk =0 ;
reg i_start =0 ;
wire o_end ;
wire[BIT_WIDE-1:0] o_bin_dat ;
wire[7:0] o_hex_dat ;
FILE_READER #
(.TERGET_FILE_PATH ("./TestPattern.txt")
,.BIT_WIDE (BIT_WIDE )
)
dut
(.i_clk (i_clk )//
,.i_start (i_start )//
,.o_end (o_end )//
,.o_bin_dat (o_bin_dat )//
,.o_hex_dat (o_hex_dat )
);
//クロック
always#5 i_clk=~i_clk;
//
initial begin
#160;
@(posedge i_clk); i_start=1'b1;
@(posedge i_clk); i_start=1'b0;
@(posedge o_end);
end
endmodule
TestPattern.txt
100000 00
010000 01
001000 02
000100 03
000010 04
000001 05
000000 06
000000 07
000000 08
000001 09
000010 0A
000100 0B
001000 0C
010000 0D
100000 0E
010000 0F
001000 10
100100 20
010010 30
001001 40
000100 50
000010 60
000001 70
100000 80
010000 90
001000 A0
001001 B0
010010 C0
100010 D0
010001 E0
001000 F0