はじめに
FPGAを用いたアクセラレータを作成する研究室に所属しているにも関わらず、卒論以来verilogHDLを触らずに半年経過し、思い出しがてらに、はじめからハードウェアプログラミングとやらを復習しようと思い立ち、メイン機であるMacbook Airでのプログラム作成の備忘録を残そうと思った。いつもは、研究室のマシンを使うが、夏のタイミングにエアコンが壊れ研究室が地獄となっている中、わざわざ行こうとも思わないので、ラップトップでの開発環境を[わざわざ]整えた。<- エアコンを早く修理してください。泣
Icarus Verilog
当初、大学で使っている、QuartusのModelSimをMacにインストールして環境を一発構築!!なんて思ったが、なんとwindowsとlinuxにしか対応していない。渋々、フリーで使えるコンパイラを探していると、Icarus Verilogを発見。
導入も簡単なようで。。brewをインストールしているなら以下の方法で一発!
$brew install icarus-verilog
インストールできていれば、以下のコマンドで確認可能!
$iverilog
iverilog: no source files.
Usage: iverilog [-ESvV] [-B base] [-c cmdfile|-f cmdfile]
[-g1995|-g2001|-g2005|-g2005-sv|-g2009|-g2012] [-g<feature>]
[-D macro[=defn]] [-I includedir]
[-M [mode=]depfile] [-m module]
[-N file] [-o filename] [-p flag=value]
[-s topmodule] [-t target] [-T min|typ|max]
[-W class] [-y dir] [-Y suf] [-l file] source_file(s)
See the man page for details.
GtkWave
次にデバッグを容易にするための波形観測ツールを導入すべく、GtkWaveを発見。
これのインストールはまたまたbrewで可能です。ただ、途中で不足パッケージのインストールを求められた記憶が。。。でも簡単!
$brew install caskroom/cask/gtkwave
インストールされたら/Applicationに入っているのでopenコマンドで開くことができる。
$open /Applications/gtkwave.app
サンプル
実際に使い物になるのか確認するために、同期FIFOをverilogHDLを用いてちょっちょっと書いてみた。
所々間違いが見つかりそうだが、今後使い回す予定もないので今回は目をつぶる。
//---------------------------------------
//module FIFO
// made by Ryohei.K
//---------------------------------------
`default_nettype none
`define FIFO_D 4
module FIFO(
input wire clk,
input wire n_rst,
input wire [DATA_WIDTH - 1:0] din,
input wire rd_en,
input wire wr_en,
output reg empty,
output reg full,
output reg [DATA_WIDTH - 1:0] dout
);
parameter DATA_WIDTH = 8;
parameter FIFO_DEPTH = 4;
reg [0:2**FIFO_DEPTH] rd_addr;
reg [0:2**FIFO_DEPTH] wr_addr;
reg [DATA_WIDTH - 1:0] data[0:2**FIFO_DEPTH - 1];
//FIFO
always @(posedge clk)begin
if(wr_en & !full)data[wr_addr] <= din;
if(rd_en & !empty)dout <= data[rd_addr];
end
//Write address
always @(posedge clk or posedge n_rst)begin
if(n_rst)begin
wr_addr <= 0;
end else begin
if(wr_en == 1'b1 & full == 1'b0)begin
if(wr_addr == `FIFO_D'b1111)begin
wr_addr <= 0;
end else begin
wr_addr <= wr_addr + 1'b1;
end
end
end
end
//Read address
always @(posedge clk or posedge n_rst)begin
if(n_rst)begin
rd_addr <= 0;
end else begin
if(rd_en)begin
if(rd_addr == `FIFO_D'b1111)begin
rd_addr <= 0;
end else begin
rd_addr <= rd_addr + 1'b1;
end
end
end
end
//Full flag
always @(posedge clk or posedge n_rst)begin
if(n_rst)begin
full <= 0;
end else begin
if( wr_addr == `FIFO_D'b1111 & wr_en == 1 & rd_en == 0)begin
full <= 1;
end else if(full == 1 &rd_en == 1)begin
full <= 0;
end
end
end
//Empty flag
always @(posedge clk or posedge n_rst)begin
if(n_rst)begin
empty <= 1;
end else begin
if(wr_en)begin
empty <= 0;
end
end
end
endmodule
`timescale 1ps/1ps
module FIFO_bench();
parameter DATA_WIDTH = 8;
parameter FIFO_DEPTH = 4;
reg clk,n_rst,rd_en,wr_en;
reg [DATA_WIDTH - 1:0] din;
wire [DATA_WIDTH - 1:0] dout;
FIFO #(.FIFO_DEPTH(FIFO_DEPTH))u0(
.clk(clk),
.n_rst(n_rst),
.rd_en(rd_en),
.wr_en(wr_en),
.din(din),
.dout(dout)
);
initial begin
n_rst = 1;
#10 n_rst = ~n_rst;
end
initial begin
clk = 0;
rd_en = 0;
forever #10 clk = ~clk;
end
initial begin
#10 wr_en = 1;
din = 1;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 2;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 3;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 4;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 5;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 6;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 7;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 8;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 9;
#10 wr_en = ~wr_en;
#10 wr_en = 1;
din = 10;
#10 wr_en = ~wr_en;
#10 rd_en = 1'b1;
#10 rd_en = ~rd_en;
#10 rd_en = 1'b1;
#10 rd_en = ~rd_en;
#10 rd_en = 1'b1;
#10 rd_en = ~rd_en;
#10 rd_en = 1'b1;
#10 rd_en = ~rd_en;
#10 rd_en = 1'b1;
#10 rd_en = ~rd_en;
end
initial begin
$dumpfile("FIFO.vcd");
$dumpvars(0, FIFO_bench);
$monitor ("%t: clk = %b r_data = %b", $time, clk,dout);
end
initial begin
#500 $finish();
end
endmodule
$dumpfile("ファイル名")で波形データを生成することができる。
$dumpvars(階層,ターゲット)でターゲットのデータを観測できるらしい。
問題点
ここで問題が発生した、いつも大学ではシミュレーションをするときにncverilogを用いるがそのときには下位モジュールの配列メモリのデータを確認することができたが、今回のIcarus verilogを用いたところ、どうやら一筋縄ではできないようだ。ncverilogであれば
$shm_probe("",M)
こんな表記を入れれば全ての信号をダンプすることができるがIcarusverilogはそううまくいかなかった。
解決策
どうやら調べた結果、直接メモリの値にパスを通さす必要があるようだ。
integer i; /add
initial begin
$dumpfile("FIFO.vcd");
$dumpvars(0, FIFO_bench);
for(i = 0;i < 2**FIFO_DEPTH;i++) /add
$dumpvars(1,u0.data[i]); /add
$monitor ("%t: clk = %b r_data = %b", $time, clk,dout);
end
テストベンチの最後に上記の記述を足すことで波形を見ることができた。
おわりに
あんまり慣れない備忘録系の記述に戸惑いつつもどうにか書き終わってホッとしている。
これからもっと勉強する予定なので、順次学習の記録を残していこうと思う。