lp6m’s blog

いろいろかきます

Verilogのテストベンチ(bdfファイルとかRAMとかの話)

大学の学生実験でFPGAボード上で簡単なCPUを作っている(easyではない).

使っているツールはALTERA社のQuartusというツール.これでANDとかORとかDフリップフロップとかをぽちぽちして回路を作る.

ぽちぽちの回路はBlock Diagramというらしい〜

Quartusにはmodelsimというシミュレータもあるけど、とりあえず今回はicarus-verilog http://iverilog.icarus.com/を用いてテストをしてみました.

QuartusはWindowsLinuxにはあるのにMacにはなくて悲しい.

Verilog HDLでつくったモジュールとBlock Diagramでつくったモジュールが混在した回路でも問題なくテストできました.

適当に回路を作る

3進カウンタをつくりました.ぽちぽち.
f:id:lp6m:20160704042511p:plain
次にこれをVerilog HDLに書き出します.
メニューから File -> Create/Update -> Create HDL Design from Current File ... を選択してVerilog HDLを選んで,保存.
複数のモジュールを使用している際はすべてのモジュールをそれぞれ書き出します.
もちろんもともとVerilog HDLでモジュールをつくっている場合はそのままでOK.
書き出されたファイルは以下のようなものです.

// Copyright (C) 1991-2015 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions 
// and other software and tools, and its AMPP partner logic 
// functions, and any output files from any of the foregoing 
// (including device programming or simulation files), and any 
// associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License 
// Subscription Agreement, the Altera Quartus Prime License Agreement,
// the Altera MegaCore Function License Agreement, or other 
// applicable license agreement, including, without limitation, 
// that your use is for the sole purpose of programming logic 
// devices manufactured by Altera and sold by Altera or its 
// authorized distributors.  Please refer to the applicable 
// agreement for further details.

// PROGRAM		"Quartus Prime"
// VERSION		"Version 15.1.1 Build 189 12/02/2015 SJ Lite Edition"
// CREATED		"Mon Jul 04 04:11:37 2016"

module counter(
	clear,
	clock,
	Q1,
	Q2
);


input wire	clear;
input wire	clock;
output wire	Q1;
output wire	Q2;

wire	SYNTHESIZED_WIRE_0;
wire	SYNTHESIZED_WIRE_3;
reg	SYNTHESIZED_WIRE_4;
reg	DFF_inst1;

assign	Q1 = SYNTHESIZED_WIRE_4;
assign	Q2 = DFF_inst1;
assign	SYNTHESIZED_WIRE_3 = 1;




always@(posedge clock or negedge clear or negedge SYNTHESIZED_WIRE_3)
begin
if (!clear)
	begin
	SYNTHESIZED_WIRE_4 <= 0;
	end
else
if (!SYNTHESIZED_WIRE_3)
	begin
	SYNTHESIZED_WIRE_4 <= 1;
	end
else
	begin
	SYNTHESIZED_WIRE_4 <= SYNTHESIZED_WIRE_0;
	end
end


always@(posedge clock or negedge clear or negedge SYNTHESIZED_WIRE_3)
begin
if (!clear)
	begin
	DFF_inst1 <= 0;
	end
else
if (!SYNTHESIZED_WIRE_3)
	begin
	DFF_inst1 <= 1;
	end
else
	begin
	DFF_inst1 <= SYNTHESIZED_WIRE_4;
	end
end


assign	SYNTHESIZED_WIRE_0 = ~(SYNTHESIZED_WIRE_4 | DFF_inst1);


endmodule

icarus-verilogのインストール

Macだと

brew install icarus-verilog 

でおわり.

テストを書く.

テストについては「Verilog testbench」とかでしらべたら山のようにでてくるのでググる.
とりあえず上の回路に対応するベンチを書いてみました.

//counter_test.v
module counter_test;
//テストベンチの入力はreg
//テストベンチの出力はwire
//複数行にかいてもいい.バスのときはreg[15:0] Q;とか. 
reg clear, clock;
wire q2,q1;

parameter STEP = 100;

//常に実行される
always begin
	clear = 1'b1;
	#(STEP/2) clock = !clock;
end

//最初に一度だけ実行される
initial begin
	clear = 1'b0;
	clock = 1'b1;
	//monitorは引き数の値が1つでも変わった時に値を表示するように設定する.(alwaysにはかかないものらしい)
	$monitor("Counter: %b%b", q2, q1);
	#1000 $finish; //1000STEPで停止
end

//インスタンスの作成(回路の呼び出し)counter_instance はなんでもいい
//counter の部分は呼び出したいモジュールのVerilogファイルの1行目にあるモジュール名を入れる.
//引数はVerilogファイルの冒頭にあるinputの/outputにある順番にかく.
counter counterinstance(clear,clock,q1,q2);
endmodule

コンパイル

使用したモジュールすべてのVerilogファイルと、テストベンチのファイルをすべてまとめてコンパイルします.

iverilog -o counter counter.v counter_test.v 

たくさんある場合は

 iverilog -o simple2 simple2.v ./lib/phase/*.v ./lib/selector/*.v ./lib/other/*.v ./lib/component/*.v ./lib/calc/*.v ./lib/cable/*.v ./lib/7SEG/*.v dummy_ram.v simple2_test.v

こんなかんじ.

  • oの後に指定したファイル名でコンパイルされたファイルが出力されます.
vvp counter

または

./counter

と入力すればシミュレーションがはじまります.

Counter: 00
Counter: 01
Counter: 10
Counter: 00
Counter: 01
Counter: 10
Counter: 00
Counter: 01
Counter: 10
Counter: 00
Counter: 01

無事にシミュレーションできました.

ハマった点としては,ぽちぽちでカウンタを作る際に、DFFのpresetを1にしておけば,DFFの出力の初期値は0だと思っていたのですが、出力されたVerilogのコードを読んだところ,初期値については何もかかれておらず,テストするとxx(値不定)となってしまいました.
そのため上のテストベンチではinitialブロック内でclear = 0として一度クリアしています.
Verilog、入門のページみながら適当にかいたりしているけど難しい・・・・・・・・・・・・・・

RAMについて

CPUをつくる実験ではRAMを使ったりします.
f:id:lp6m:20160704101153p:plain
RAMはQuartus上ではVerilogに変換できないので,自分でダミーのVerilogファイルを書きます.

module ram(
    input [15:0] data,
    input wren,
    input wire [11:0] address,
    input clock,
    output reg [15:0] q
    );

    //16bit幅 4096word
    (* ram_style = "BLOCK" *) reg [15:0] bram[0:4095]; 
    
    initial begin
        bram[12'd0] = 16'b1000000000000001;
        bram[12'd1] = 16'b1000000100000011;
        bram[12'd2] = 16'b1100100000000000;
        bram[12'd3] = 16'b1100000011010000;
        bram[12'd4] = 16'b1000000100000101;
        bram[12'd5] = 16'b1100100000000000;
        bram[12'd6] = 16'b1100000011010000;
    end

    always @(posedge clock) begin
        if(wren)
            bram[address] <= data;
        else
            q <= bram[address];
    end

endmodule

こんなかんじでダミーのRAMをつくればOK.(説明が雑)
wrenが1のときにclockがはいったらdataの内容をbram[address]に書き込んで,wrenが0のときはbram[address]の内容をqに入れて出力というのをかいただけ.
とりあえずこれでデバッグできるようになったので嬉しいです〜〜〜
ぽちぽちのときは値不定なんてほとんどないと思うんだけどVerilogでかくとif文の条件分岐とかが足りてないと値不定になってしまってなるほどなあというかんじ.

ここ間違ってるとか表記おかしいとかあったら教えてください.