ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

RISC-Vの実装の1つ - SCR1の解析 - シミュレーション環境の疑問点の確認(1)

スポンサーリンク

前回のSCR1ネタ最後に以下のように書いた。

ここまでに記載したようにとりあえず...の対策をいくつか施して動かした部分もあるし、実はこのシミュレーションも正常に終わってなかったりしているので、引き続きもう少しシミュレーション環境の調査を行っていくつもりだが、今日はここまで。

tech-diningyo.hatenablog.com

ということで今日は、Vivado+SCR1+riscv-testsシミュレーション環境についてももう少し調べていく。今日は$readmemhがうまく動かないという話題について。

$readmemhうまく行かない問題

表題の通りだが、前回の記事では読み込むRISC-VバイナリのHEXデータファイルを以下のようにして、直書き&フルパス指定することによって、実行していた。

always @(negedge rst_n) begin
    //memory = '{SIZE{'0}};
    $readmemh("./scr1/build/addi.hex", memory); // 修正後
    //if(stuff_file.len()>0) $readmemh(stuff_file,memory);
end

これについて少し調べてみる。

いろいろ試してみたが、どうもSystem Verilogstringに入れると解釈できていないように見える。

試したのは以下の3つのケース

  • SCR1オリジナル
  • (すでにやってるけど)$readmemhに直接ファイル名を指定
  • reg宣言した変数にファイルパスを設定して、その変数を$readmemhに与える

ソースコード的には以下のような物を用意して、コメントアウトする部分を切り替えて試してみた。

reg[1023:0] tmp;

always @(negedge rst_n) begin
    //memory = '{SIZE{'0}};

    // case 1 - original, but set file name on this always block directly
    stuff_file = "/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex";
    $display("case1:%s", stuff_file);
    if(stuff_file.len()>0) $readmemh(stuff_file, memory);
    
    // case 2 - set file name directly to $readmemh task
    $display("case2:%s", "/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex");
    $readmemh("/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex", memory);
    
    // case 3 - set file name to reg valuable and feed $readmemh task
    tmp = "/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex";
    $display("case3:%s", tmp);
    $readmemh(tmp, memory);
end

case1 : SCR1のオリジナルソースコード

以下のようなメッセージが得られた。

case1:/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex
WARNING: File õ referenced on /home/dnn-admin/workspace/hw/study/fpga-scr1/scr1/src/tb/scr1_memory_tb_axi.sv at line 154 cannot be opened for reading. Please ensure that this file is available in the current working directory.

ここで気になるのは警告文中のファイル名が謎の文字列"õh"に化けているように見えること。。。

なんかやっぱり、string型の変数にファイル名設定するとVivadoでは読み込めてないように見える。$displayの出力は普通なのに。。

上記のようになっているので当然、読み出されるデータも不定になっていた。

case2 : 直接ファイルを指定

こちらも既に試しているとおりではあるが、以下のメッセージが得られた。実行時間の情報を出しているのはcase1のように警告が出ていないことを示すため。

case2:/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex
relaunch_sim: Time (s): cpu = 00:00:05 ; elapsed = 00:00:07 . Memory (MB): peak = 6431.449 ; gain = 0.000 ; free physical = 10548 ; free virtual = 28752

警告が出ていないことからもわかるが、正常にメモリがデータが読み込まれているため、シミュレーション時の波形においても正しいでデータが読み込まれている。

case3 : reg変数に設定した後、$readmemh

得られた出力は以下のようになった。

case3:                                                                /home/dnn-admin/workspace/hw/study/1000_scr1/scr1/build/addi.hex
relaunch_sim: Time (s): cpu = 00:00:05 ; elapsed = 00:00:06 . Memory (MB): peak = 6447.441 ; gain = 7.988 ; free physical = 10477 ; free virtual = 28689

"case2"という文字の直後にスペースが入っているのは、reg変数のビット幅の関係。

こちららも特に警告は出ておらず、正常に$readmemhにより所望のファイルが読み込まれていた。

結果まとめ

以上の結果からすると、やっぱりVivadoシミュレータにおいてはstring変数に設定したファイルパスが$readmemhの処理の上では認識されていないことになる。

ということで、この挙動についてverilogの仕様を追ってみることにする。

verilogの仕様の確認

現在実行しているシミュレーションでこの$readmemhが実行されているのはテストベンチ上のメモリモデルscr1_memory_tb_axiである。このファイルはVivado上ではSystem Verilogのファイルとして認識されているので、エラボレーション時にもSystem Verilogの文法が適用されている。

そのため、まずはSystem Verilogにおける$readmemhの定義を確認していく。確認したのはこのPDFでこれによると、$readmemhの項目では以下の事項のみが触れられている。

22.14 $readmemb and $readmemh 22.14.1 Reading packed data $readmemb and $readmemh are extended to unpacked arrays of packed data, associative arrays of packed data, and dynamic arrays of packed data. In such cases, the system tasks treat each packed element as the vector equivalent and perform the normal operation.

When working with associative arrays, indexes must be of integral types. When an associative array’s index is of an enumerated type, address entries in the pattern file are in numeric format and correspond to the numeric values associated with the elements of the enumerated type.

22.14.2 Reading 2-state types $readmemb and $readmemh are extended to packed data of 2-state types, such as int or enumerated types. For 2-state integer types, reading proceeds the same as for conventional Verilog variable types (e.g., inte-ger), with the exception that X or Z data are converted to 0. For enumerated types, the file data represents the numeric values associated with each element of the enumerated type (see 4.10). If a numeric value is out of range for a given type, then an error shall be issued and no further reading shall take place.

この22.14で記載されているのはSystem Verilogにおいて拡張された部分のみで、ざっくり以下のことが書いてある。

  • packed dataのunpacked arrayに読み込めるようなった。
  • 2-state typesの型に読み込めるようになった。

実際に知りたいファイル指定部分の扱いは書いていなかったのでVerilog-HDLの方の仕様書(IEEE Std 1364-2001)で確認してみる。

"17.2.8 Loading memory data from a file"によると、以下のようになっている。

load_memory_tasks ::=
$readmemb ( " file_name " , memory_name [ , start_addr [ , finish_addr ] ] ) ;
| $readmemh ( " file_name " , memory_name [ , start_addr [ , finish_addr ] ] ) ;

今回知りたいのは上記の" file_name "が何を指しているのか、、、なのだが、ここには書いていないので、別の項目も探してみると以下の説明が$fopenの項目である17.2.1で見つかる。

file_open_function ::=
integer multi_channel_descriptor = $fopen ( " file_name " );
| integer fd = $fopen ( " file_name ", type );

ここには" file_name "についての説明が記載してあり、それは以下のようになっている。

filename is a character string, or a reg containing a character string that names the file to be opened.

ということで、verilog(IEEE Std 1364-2001)の仕様では" file_name "として許容されるのは

  • a character string → "string"のように""で括られた文字列
  • reg containing a character string → reg変数に"a character string"を格納したもの

ということになりそう。

上記で先に調べたとおりSystem Verilogにおいてはこの" file_name "についての扱いは拡張されていないように見えるので、$readmemhstring型の文字列が扱えないのは一概にバグとは言えない感じに思える。VCSとかでは普通に扱えるからてっきり読めるんだと思ってた。

商用のシミュレータ使ってると結構ベンダ依存の拡張が存在してて、ツール切り替えるときに動いてた記述が動かなくなることがあるけど、これもその一つということなのか。因みに上記で$displaystringを与えると動いていたが、System Verilogの仕様でしっかり拡張されているようで以下の一文が書いてあった。

  • $display , $write , $fdisplay , $fwrite , $swrite , and their variants
    • The argument corresponding to a string % format specifier ( s ) may have the string data type.

ということで、結論としてはstringで読めないのは仕方がなさそうなのでreg変数で動くように書き換える(前項のcase3の対応)、、、ということになりそう。