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スライス減りました。理由は分かりません。

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