FC2カウンター FPGAの部屋 Verilatorを試してみる4(C++モード4:diceプロジェクト)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Verilatorを試してみる4(C++モード4:diceプロジェクト)

Verilatorを試してみる3(C++モード3:VCDファイルを出力)”の続き。

今度は、ISE11.1iのチュートリアルで使用しているdiceをVerilogで書いたものをシミュレーションしてみた。つまり、今までは単一のVerilogファイルをVerilatorでシミュレーションしていたが、今回は複数のVerilogファイルから成るプロジェクトをVerilatorでシミュレーションしてみた。
まずは、dice_top.vから下に示す。

`default_nettype none

`timescale 1ns / 1ps


// 電子サイコロ Verilog2001


module dice_top(
    input wire reset_sw,
    input wire clk,
    input wire roll,
    output wire [3:0] an_n,
    output wire a_n,
    output wire b_n,
    output wire c_n,
    output wire d_n,
    output wire e_n,
    output wire f_n,
    output wire g_n,
    output wire dp_n

);
    
    wire roll_sig;
    wire roll_ena;
    wire [2:0] binary;
    
    assign an_n = 4'b1110; // AN0のみ点灯
    assign dp_n = 1'b1; // ドットの消灯
    
    reject_chatter inst_reject_chatter(
        .reset_sw(reset_sw),
        .clk(clk),
        .roll(roll),
        .roll_sig(roll_sig),
        .roll_ena(roll_ena)
    );
        
    dice_state_machine inst_dice_sm(
        .reset_sw(reset_sw),
        .clk(clk),
        .roll(roll_sig),
        .roll_ena(roll_ena),
        .spots(binary)
    );

    seven_seg_dec inst_seven_seg_dec(
        .binary(binary),
        .a_n(a_n),
        .b_n(b_n),
        .c_n(c_n),
        .d_n(d_n),
        .e_n(e_n),
        .f_n(f_n),
        .g_n(g_n)
    );
    
endmodule

`default_nettype wire


dice_state_machine.v は、ここに示したので、seven_seg_dec.v を下に示す。

`default_nettype none
`timescale 1ns / 1ps

// 7セグメントLEDデコーダ、0で点灯します。

(* bram_map="yes" *)
module seven_seg_dec(
    input wire [2:0] binary,
    output reg a_n,
    output reg b_n,
    output reg c_n,
    output reg d_n,
    output reg e_n,
    output reg f_n,
    output reg g_n
);

    always @* begin
        case (binary)
            3'd1 : begin
                a_n=1'b1; b_n=1'b0; c_n=1'b0; d_n=1'b1; e_n=1'b1; f_n=1'b1; g_n=1'b1;
            end
            3'd2 : begin
                a_n=1'b0; b_n=1'b0; c_n=1'b1; d_n=1'b0; e_n=1'b0; f_n=1'b1; g_n=1'b0;
            end
            3'd3 : begin
                a_n=1'b0; b_n=1'b0; c_n=1'b0; d_n=1'b0; e_n=1'b1; f_n=1'b1; g_n=1'b0;
            end
            3'd4 : begin
                a_n=1'b1; b_n=1'b0; c_n=1'b0; d_n=1'b1; e_n=1'b1; f_n=1'b0; g_n=1'b0;
            end
            3'd5 : begin
                a_n=1'b0; b_n=1'b1; c_n=1'b0; d_n=1'b0; e_n=1'b1; f_n=1'b0; g_n=1'b0;
            end
            3'd6 : begin
                a_n=1'b0; b_n=1'b1; c_n=1'b0; d_n=1'b0; e_n=1'b0; f_n=1'b0; g_n=1'b0;
            end
            default : begin
                a_n=1'b1; b_n=1'b0; c_n=1'b0; d_n=1'b1; e_n=1'b1; f_n=1'b1; g_n=1'b1;
            end
        endcase
    end
endmodule
`default_nettype wire


最後にreject_chatter.v を下に示す。

`default_nettype none
`timescale 1ns / 1ps

// スイッチのチャタリング除去とサイコロの表示変更タイミング20msをカウントする
// Verilog2001

module reject_chatter(
    input wire reset_sw,
    input wire clk,
    input wire roll,
    output wire roll_sig,
    output reg roll_ena
);
    reg [17:0] sw_cnt;
    reg [1:0] roll_cnt;
    reg roll_node;
    
    parameter frequency_KHz = 1; // KHz単位でのクロック周波数(シミュレーション用に値を変更)
    // parameter frequency_KHz = 50000; // KHz単位でのクロック周波数
    parameter divided_200Hz = frequency_KHz * 5; // 200Hzに分周するための分周比
    
    // 200Hz, 5ms
    always @(posedge clk) begin
        if (reset_sw)
            sw_cnt <= 18'd0;
        else begin
            if (sw_cnt == (divided_200Hz-1))
                sw_cnt <= 18'd0;
            else
                sw_cnt <= sw_cnt + 18'd1;
        end
    end
    
    always @(posedge clk) begin
        if (reset_sw)
            roll_node <= 1'b0;
        else
            if (sw_cnt == (divided_200Hz-1))
                roll_node <= roll;
    end
    assign roll_sig = roll_node;
    
    // 50Hz, 20ms
    always @(posedge clk) begin
        if (reset_sw) begin
            roll_cnt <= 2'd0;
            roll_ena <= 1'b0;
        end else begin
            if (sw_cnt==(divided_200Hz-1)) begin
                if (roll_cnt==2'b11) begin
                    roll_cnt <= 2'd0;
                    roll_ena <= 1'b1;
                end else begin
                    roll_cnt <= roll_cnt + 2'd1;
                    roll_ena <= 1'b0;
                end
            end else
                roll_ena <= 1'b0;
        end
    end
endmodule    
`default_nettype wire


parameter の frequency_KHz はシミュレーション用に1に設定してある。
次に、dice_top.v 用のテストベンチ、dice_top_tb.cpp を下に示す。

// dice_top_tb.cpp

#include <iostream>
#include <verilated.h>    // Defines common routines
#include "verilated_vcd_c.h"
#include "Vdice_top.h"

unsigned int main_time = 0;     // Current simulation time

double sc_time_stamp () {       // Called by $time in Verilog
    return main_time;
}

int main(int argc, char** argv) {
    Verilated::commandArgs(argc, argv);   // Remember args
    
    Vdice_top *top = new Vdice_top();
    
    Verilated::traceEverOn(true);
    VerilatedVcdC* tfp = new VerilatedVcdC;
    top->trace (tfp, 99);
    tfp->open ("simx.vcd");
    
    top->reset_sw = 1;        // Set some inputs
    top->clk = 0;
    top->roll = 0;
    
    while (!Verilated::gotFinish()) {
        if (main_time > 10
            top->reset_sw = 0;    // リセットを解除する
        
        if ((main_time % 5) == 0)    // クロックを生成する
            top->clk = !top->clk;
            
        if (main_time > 20 && main_time < 980)    // roll を1にする
            top->roll = 1;
        else
            top->roll = 0;
            
        top->eval();    // 評価
        
        printf("Time %d : clk = %d spots = %d\n", main_time, top->clk, top->v__DOT__inst_dice_sm__DOT__spots_node);

        tfp->dump(main_time);
        
        if (main_time>1000)
            break;         // 終了
        
        main_time++;
    }
    
    tfp->close();
    
    top->final();        // シミュレーション終了
}


printf文を見るとわかると思うが、上の階層とは”__DOT__”で区切られているようだ。

これですべてのソースは示したので、ここからはVerilatorのコマンドを入れて、コンパイル、make、実行ファイルの実行と続く。まずは、Cygwin上でコンパイルをする。指定するVerilogファイルはトップのファイルだけで大丈夫みたいだ。下のVerilogファイルを指定しなくても良いようだ。

verilator --cc --trace -Wno-lint dice_top.v --exe dice_top_tb.cpp


obj_dirディレクトリに入る。

cd obj_dir/


makeコマンドでmakeする。

make -j -f Vdice_top.mk Vdice_top


実行形式のファイルを実行する。

./Vdice_top.exe


下に実行した後のCygwinウインドウを示す。
Verilator_11_110527.png

simx.vcdファイルが出来ている。これをVeritakで読み込むと下のようなシミュレーション波形を得ることができた。
Verilator_12_110527.png

これで複数ファイルのシミュレーションも行うことができた。コンパイルの時にトップモジュールだけをコマンドラインに書けば下もコンパイルしてくれた。
  1. 2011年05月27日 05:01 |
  2. シミュレーション
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1812-780e884e
この記事にトラックバックする(FC2ブログユーザー)