Verilogで外部テキストファイル読み込み

# まえおき
Verilog-HDLのシミュレーションを行う際に、テストデータを外部ファイルに書いておき、(コンパイル時ではなく)シミュレーション実行時に読み込ませる手法はよく使われている手段です。

ファイルの読み込み方法として代表的なのは

* ファイルをまとめて読み込む($readmem)
* １行づつ読み込む($fscanf)

の２パターンかと思いますが、今回は$fscanfを使用したケースを紹介します。

# $fscanfを使用すべきテストパターン
* テストファイルの行数がテスト条件により可変長
* テストデータにランダムアクセスしない（頭から流すだけ）
* １行に複数のデータがある
* bin/hex/decフォーマットが混在している


# 基本的な流れ

1. `$fopen`を使用してファイルを開く
1. `$fgetc`で1文字読み出す
1. EOF(ファイル終端か否か判定する)
1. `$fscanf`で1行分を書式付で読み出す

# 使用するシステムタスク

## $fopen (ファイルオープン)

    項目|内容|説明|
   :---:|:---|:---
    戻り値|ファイルディスクリプタ|0:オープン失敗<br>その他:オープン成功<br>(戻り値は、以後ファイルにアクセスする為に必要)
    第一引数|ファイルパス|開きたいファイルのパスを指定<br>（実行ディレクトリからの相対パスでも可）
    第二引数|アクセスモード|"r":リード専用<br>（その他のアクセスモードについては今回は割愛）


## $feof（ファイル終端か調べる）
    項目|内容|説明|
    :---:|:---|:---
    戻り値|ファイル終端に達したか否か|0以外の値が帰ってきたらファイル終端に達したことを示す
    第一引数|ファイルディスクリプタ|$fopenの戻り値を渡す

## $fscanf

    項目|内容|説明|
    :---:|:---|:---
    戻り値|実行結果|-1が帰ってきたらエラー
第一引数|ファイルディスクリプタ|$fopenの戻り値を渡す
第二引数|出力フォーマット|%b:2進数<br>%h:16進数<br>（その他は説明割愛）
第三引数以降|信号|読み込んだ値を反映させるreg変数を渡す

# サンプルコード

ファイルを読み込んで値を出力する"モジュール"として紹介します。
このモジュールをテストベンチTop階層で呼び出して使用します。

【モジュール仕様】

* クロック同期で動作する
* i_start入力ピンにHighを入力するとテキストデータの内容を出力する
* 出力が完了するとo_end出力ピンを1サイクルだけHighにする
* テキストデータは ”バイナリ6bit” + "Hex8bit"を１行に書く

```verilog: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と読み込むテキストファイルを紹介します。

```verilog: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

```

```text: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
```


# 実行結果

![image.png](https://qiita-image-store.s3.amazonaws.com/0/204268/aab75335-7d04-2083-3ad4-f9b452f5cddd.png)