FC2カウンター FPGAの部屋 diceのVerilog版
FC2ブログ

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

FPGAの部屋

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

diceのVerilog版

Sim's blogさんの”diceをverilogに書き換えてみました”でdiceのVeriog版が載っていたので、私の作った電子サイコロのVerilog版も貼ってみた。
非同期リセットのVHDL版と説明はこちら

まずは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


次は、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 = 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


dice_state_machine.v

`default_nettype none
`timescale 1ns / 1ps

// 1から6までのサイコロの目を表すステートマシン, Verilog2001

module dice_state_machine(
    input wire reset_sw,
    input wire clk,
    input wire roll,
    input wire roll_ena,
    output reg [2:0] spots
);

    parameter        st_one        = 6'b000001,
                    st_two        = 6'b000010,
                    st_three    = 6'b000100,
                    st_four        = 6'b001000,
                    st_five        = 6'b010000,
                    st_six        = 6'b100000;
    reg [5:0] current_state, next_state;
    
    always @(posedge clk) begin
        if (reset_sw)
            current_state <= st_one;
        else
            current_state <= next_state;
    end
            
    always @* begin
        case (current_state)
            st_one : begin
                spots <= 3'd1;
                if (roll & roll_ena)
                    next_state <= st_two;
                else
                    next_state <= st_one;
            end
            st_two : begin
                spots <= 3'd2;
                if (roll & roll_ena)
                    next_state <= st_three;
                else
                    next_state <= st_two;
            end
            st_three : begin
                spots <= 3'd3;
                if (roll & roll_ena)
                    next_state <= st_four;
                else
                    next_state <= st_three;
            end
            st_four : begin
                spots <= 3'd4;
                if (roll & roll_ena)
                    next_state <= st_five;
                else
                    next_state <= st_four;
            end
            st_five : begin
                spots <= 3'd5;
                if (roll & roll_ena)
                    next_state <= st_six;
                else
                    next_state <= st_five;
            end
            st_six : begin 
                spots <= 3'd6;
                if (roll & roll_ena)
                    next_state <= st_one;
                else
                    next_state <= st_six;
            end
            default : begin
                spots <= 3'd1;
                next_state <= st_one;
            end
        endcase
    end
    
// synthesis translate_off
    reg [20*8:1] DICE_STATE; 
    
    always @(current_state) begin
        case (current_state)
            st_one    : DICE_STATE <= "ST_ONE";
            st_two    : DICE_STATE <= "ST_TWO";
            st_three: DICE_STATE <= "ST_THREE";
            st_four    : DICE_STATE <= "ST_FOUR";
            st_five    : DICE_STATE <= "ST_FIVE";
            st_six    : DICE_STATE <= "ST_SIX";
            default    : DICE_STATE <= "ST_ONE";
        endcase
    end
// synthesis translate_on
endmodule
`default_nettype wire


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


同期リセットになっているはず。。。
特徴は`default_nettype none ~`default_nettype wireで括ってあることと、ステートマシンのステートをワンホットにしてあることだろうか?
痛い目にあったので、integerのリテラルには必ずビット幅を書くようにしている。

VHDL版非同期リセット電子サイコロとVerilog版同期リセットの電子サイコロのISE10.1iでのインプリメント結果を下に示す。
まずは、VHDL版非同期リセット電子サイコロから。
dice_VHDL_ISE101_090623.png

次は、Verilog版同期リセットの電子サイコロ。
dice_Verilog_ISE101_090623.png

VHDL版非同期リセット電子サイコロの方が、Verilog版同期リセットの電子サイコロよりもLUTの使用数が倍近く多い。

何か間違いがあったらお知らせください。
  1. 2009年06月23日 20:40 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:8

コメント

こんにちは。verilog 2001で、さらにステートマシンはワンホットですか。いい感じです。Latticeのツールがverilog 2001だとうまく動かないので最近verilog 1995に逆戻りしてます。うるうる。
  1. 2009/06/24(水) 22:39:41 |
  2. URL |
  3. Sim #mQop/nM.
  4. [ 編集 ]

Simさん、こんにちは。

そうです。Verilog2001で書きました。LatticeはVerilog2001が動かないんですね。それは嫌です。私だったらXilinxに戻ります。
それから、-1などには必ず-4'd1とか、ビット幅を書いておいた方がいいようです。これでバグったことがあります。(とはいっても私も1つ書くのを忘れていますが。。。)
http://marsee101.blog19.fc2.com/blog-entry-763.html
  1. 2009/06/25(木) 04:49:03 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

こんにちは
正確に言うと、synthesis用のSynplify自体はVerilog 2001どころかSystem Verilogまでサポートしています。ところが、IDEが勝手に文法チェックしてくれてVerilog 2001をはじいてくれます。何か方法がありそうなのですが、今のところ見つかっていません。
  1. 2009/06/25(木) 23:30:54 |
  2. URL |
  3. Sim #mQop/nM.
  4. [ 編集 ]

それでは、Synplifyを単体で使って、ネットリストを出力させて、それをLatticeのIDEのプロジェクトにしてはどうでしょうか?
私は仕事ではSynplify Pro + ISEの組み合わせで使っています。ISEからSynplify Proを使っていますが、論理合成が通らないときはSynplify Proを単体で立ち上げています。
  1. 2009/06/26(金) 04:07:29 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

そんな方法があるんですね。挑戦してみます。うまくいったら報告します。
  1. 2009/06/26(金) 19:57:37 |
  2. URL |
  3. Sim #mQop/nM.
  4. [ 編集 ]

Latticeではうまくできるかどうかわかりませんが、やってみてください。
  1. 2009/06/26(金) 22:52:00 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

無事、できました。
ちょっとはまったのが拡張子の違いです。SynplifyはEDIFファイルというのを出力するのですが、デフォルトで*.ediという拡張子がついています。LatticeのIDEでは*.edfという拡張子を読むようになっていました。この違いくらいで、プロジェクトに読み込むファイルを*.edfに指定してやれば問題なく最後までいけました。
この同期リセット&verilog 2001版diceですが、28sliceになりました。私が書いた非同期リセット版が32スライスだったので小さくなりました。ちなみにVHDLは35スライスでした。
使える環境があるとなると、SystemVerilogもやってみたくなってきました。
助言ありがとうございました。とても助かりました。
  1. 2009/06/26(金) 23:09:27 |
  2. URL |
  3. Sim #mQop/nM.
  4. [ 編集 ]

Simさん、おめでとうございます。
SystemVerilog勉強して、ブログに書いてください。
私もSystemVerilogの本は4冊持っているのですが、読んでないでいないです。。。読んで勉強しないと。。。
  1. 2009/06/27(土) 06:08:38 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

コメントの投稿


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

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