Sim's blog

電子工作はじめてみました

diceをverilogに書き換えてみました

2009-06-22 21:43:31 | FPGA
diceを動かしてみましたの続きになります。

やっぱり、7セグLEDの方が雰囲気が出るということで、比叡につないでみました。

Spartan-3スタータキットにあわせて、アノードコモンの7セグLEDにしています。
電流制限抵抗は510Ωなので1セグメントあたり3mAくらい流れている計算になります。
ちゃんとデータシート見てないけど、このくらいならたぶん平気かな。
比叡の回路図を見ると電流制限抵抗が120Ωでした。

というわけで、オリジナルのVHDLソースをなるべくそのままVerilogに書き直してみました。(<が全角になっています)
// dice_top.vhd
module dice_top (reset_sw, clk, roll, an_n, a_n, b_n, c_n, d_n, e_n, f_n, g_n, dp_n);
    input reset_sw;
    input clk;
    input roll;
    output [3:0] an_n;
    output a_n;
    output b_n;
    output c_n;
    output d_n;
    output e_n;
    output f_n;
    output g_n;
    output dp_n;

    wire roll_sig;
    wire roll_ena;
    wire [2:0] binary;

    assign an_n = 4'b1110;
    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

// reject_chatter.vhd
module reject_chatter (reset_sw, clk, roll, roll_sig, roll_ena);
    input reset_sw;
    input clk;
    input roll;
    output roll_sig;
    output reg roll_ena;

//  parameter frequency_KHz = 1;
    parameter frequency_KHz = 50000;
    parameter divided_200Hz = frequency_KHz * 5;

    reg [17:0] sw_cnt;
    reg [1:0] roll_cnt;
    reg roll_node;

    // 200Hz, 5ms
    always @(posedge clk or negedge reset_sw)
        if(reset_sw == 1'b0)
            sw_cnt <= 0;
        else if(sw_cnt == (divided_200Hz - 1))
            sw_cnt <= 0;
        else
            sw_cnt <= sw_cnt + 1;

    always @(posedge clk or negedge reset_sw)
        if(reset_sw == 1'b0)
            roll_node <= 1'b1;
        else if(sw_cnt == (divided_200Hz - 1))
            roll_node <= roll;

    assign roll_sig = roll_node;

    // 50Hz, 20ms
    always @(posedge clk or negedge reset_sw)
        if(reset_sw == 1'b0) begin
            roll_cnt <= 2'b00;
            roll_ena <= 1'b0;
            end
        else if(sw_cnt == (divided_200Hz - 1))
            if(roll_cnt == 2'b11) begin
                roll_cnt <= 2'b00;
                roll_ena <= 1'b1;
                end
            else begin
                roll_cnt <= roll_cnt + 1;
                roll_ena <= 1'b0;
                end
        else
            roll_ena <= 1'b0;

endmodule

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

    parameter [2:0]
        st_one = 3'h1, st_two = 3'h2, st_three = 3'h3,
        st_four = 3'h4, st_five = 3'h5, st_six = 3'h6;

    reg [2:0] current_state, next_state;

    always @(posedge clk or negedge reset_sw)
        if(reset_sw == 1'b0)
            current_state <= st_one;
        else
            current_state <= next_state;

    always @(current_state, roll, roll_ena)
        case(current_state)
        st_one : begin
            spots = 3'b001;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_two;
            else
                next_state = st_one;
            end
        st_two : begin
            spots = 3'b010;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_three;
            else
                next_state = st_two;
            end
        st_three : begin
            spots = 3'b011;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_four;
            else
                next_state = st_three;
            end
        st_four : begin
            spots = 3'b100;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_five;
            else
                next_state = st_four;
            end
        st_five : begin
            spots = 3'b101;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_six;
            else
                next_state = st_five;
            end
        st_six : begin
            spots = 3'b110;
            if(roll == 1'b1 & roll_ena == 1'b1)
                next_state = st_one;
            else
                next_state = st_six;
            end
        default : begin
            spots = 3'b001;
            next_state = st_one;
            end
        endcase

endmodule

// seven_seg_dec.vhd
module seven_seg_dec (binary, a_n, b_n, c_n, d_n, e_n, f_n, g_n);
    input [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 @(binary)
        case(binary)
        3'b001: begin // 1
            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'b010: begin // 2
            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'b011: begin // 3
            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'b100: begin // 4
            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'b101: begin // 5
            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'b110: begin // 6
            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

endmodule

Verilogにはtypeがないのでparameterでごまかしています。
オリジナルと違うのは比叡に合わせてリセットをアクティブローにしているところと、roll_nodeの初期値を1にしたことです。roll_nodeは0のとき、キーが押されていることになるのですが、リセットを押した直後は一瞬だけキーを押したことになるので、リセットのときの初期値を1'b1、つまりキーは押されていない状態にしました。
VHDLはなんでもsignalでいいみたいなんですが、Verilogは状況に応じてwireとregを使い分けないといけないのが面倒です。
VHDLの方は35スライスでしたが、Verilogだと32スライスと3スライス減りました。理由は分かりません。

いい勉強をさせていただきました。

最新の画像もっと見る

8 コメント

コメント日が  古い順  |   新しい順
Unknown (nekosan)
2009-06-23 00:00:10
まだまだお勉強の最中なのでトンチンカンなことを言ってたらゴメンナサイ。

>VHDLはなんでもsignalでいいみたいなんですが

が気になってこのあたりを入門書で復習してみました。

VHDLのオブジェクトクラスには「constant」「signal」「
variable」があるとかいてあるんですが、このsignalとvariableのお話とは関係ないでしょうかね?

verilogがよく解ってないのでなんともいえないんですが…

wireとregという文言からするとニュアンスがやっぱりちょっと違う気もする…

確かにsignalで定義したものを合成したときに、レジスタが使われるのか単なる配線になっちゃうのか、よく判んなかったりして混乱した記憶があります。

ロジックIC組み合わせて回路組むときとVHDLで回路書くときでは、そのあたりが全然違う感覚なので戸惑ってしまいます…難しいですね。
返信する
re:Unknown (Sim)
2009-06-23 07:10:11
こんにちは、nekosanさん

私の理解している範囲で話させてください。
まずは、ざっくりverilogのalwaysとVHDLのprocessが対応しています。verilogでは、alwaysの中で代入されるのがreg宣言、alwaysの外で代入されるのがwire宣言します。VHDLではprocessの中で代入されるものも外で代入されるものも、どちらもsignal宣言でいいみたいです。

クロック用のprocess文と組み合わせ回路用のprocess文があるのは、alwaysも一緒です。クロック用のprocess文で代入されるsignalはFFになって、それ以外は配線になります。verilogの場合は、reg宣言はalways文内で代入されることを示しているだけなので、どちらのalwaysで使われるかによってFFになるか配線になるかの場合分けが出てきます。regと書いてあるのにFFにならないのは、なんか変な感じです。

どちらもプログラマの意図を反映していないような気がします。せっかく宣言するのだから、FFにしたいという意図を記述させるようにして、もしFFにならなかったらエラーを出す、という方が安全な気がします。verilogのように形式的に宣言を使い分けるのって、なんか意味がなくて嫌です。逆にVHDLもなんでもかんでもsignalでいいなら宣言する意味ないじゃん、とか思っちゃいます。
センシティビティリストの件でも、プログラマが注意深くならないといけない言語って、結局ミスの元になるので生産性が低くなっちゃいます。このあたりは嫌なところです。verilogの宣言しなくても信号が使えちゃうあたりなんか最悪です。そのあたりはverilog 2001で改善されたので、私はverilog 2001が好きです。
なんか長々とすみません。
返信する
Unknown (marsee)
2009-06-23 20:48:40
私の同期リセット版Verilogの電子サイコロも自分のブログに貼ってみました。トラックバックもさせていただきました。
返信する
HTML文書作成用コード変換器のご紹介 (のりたん)
2009-06-23 21:38:00
> (<が全角になっています)

もし、さしつかえなければ、ご利用ください。
> http://noritan-micon.blog.so-net.ne.jp/2009-06-11
> HTML文書作成用コード変換器
返信する
re:Unknown (Sim)
2009-06-24 22:28:35
こんにちは、marseeさん
ありがとうございます。同期版も勉強させていただきます。
返信する
re:HTML文書作成用コード変換器のご紹介 (Sim)
2009-06-24 22:36:46
こんにちは、のりたんさん
ご紹介ありがとうございます。
試しに使ってみました。ちゃんと<が<になってくれました。

ちょっと愚痴。gooブログって、一度セーブすると、せっかく<にしたのが全部<に化けちゃうんです。あっ、間違った、直そうとすると、またソースを貼りなおさないといけないみたいで、もう勘弁してってかんじてす><。
返信する
Unknown (nekosan)
2009-06-24 23:57:09
simさん、ご解説ありがとうございます。

>verilogの場合は、reg宣言はalways文内で代入されることを示しているだけなので、どちらのalwaysで使われるかによってFFになるか配線になるかの場合分けが出てきます。regと書いてあるのにFFにならないのは、なんか変な感じです。

なるほど。verilogとVHDLでは事情の違いはあるにしても、このあたりはなんとなくしっくり来ない感があるっていうことなんでしょうかね…

なんとなく、生成後にどんな回路に変換されるのかが想像しにくいのは困ってしまいますね。何らかの記述をすると明示でいるのだと解り易くていいんですけどね。

返信する
re:Unknown (Sim)
2009-06-26 19:52:20
こんにちは、nekosanさん
現状だと、慣れるしかないのが悲しいところです。HDLも人間が楽できる方向に進化してもらいたいものです。
返信する

コメントを投稿