これまで主にVHDLを使用していたのですが,所属環境が変わってVerilog-HDLを使用する機会が多くなりました. 回路設計自体も初心者から抜け出せていないのに,違う言語に手を出すのは危険な気がしますが,仕方がありません. 今回は,Verilog-HDLの練習として簡単なスロットマシンを設計・記述し,FPGAに実装してみました.200行程度のシンプルな回路ですが,スロットマシンとしての主要な機能は抑えていると思います.
スロットマシンの仕様
今回設計したスロットマシンは,下記のような簡単な仕様を基に設計しました.
- スライドスイッチをhigh(= 1)にするとリセット動作 3個の7セグメントLEDに"0"を表示
- スライドスイッチをlow(= 0)にすると7セグメントLEDの数字が回転 "0"~"7"(8種類)の数字を順に表示
- 各タクトスイッチを押すと対応する数字の回転が停止
- 数字が揃えばフィーバーとし,10個のLEDが点滅
FPGAボード
今回使用したFPGAボードは,Terasic社のDE0です. 下記のソースコードは,Quartus II 12.0 Web Editionでコンパイル可能であり,DE0上で正常に動作することを確認しています. ソースコードは自己責任の上でご利用ください.
スロットマシンの回路構成
下図に今回設計したスロットマシンの回路構成を示します. 青色のブロックは順序回路を,緑色のブロックは組合せ回路を表しており,合計5種類のモジュールで構成されています. 斜体の白字はモジュール名を,黄色の字はモジュールの入出力を示していますが,clk入力は字を省略し,赤色の配線で表現しています.
スロットマシン・コントローラのステートマシン
下図にコントローラのステートマシンを示します. 黒字は各状態への遷移条件,赤字は状態遷移時の動作を示しています. 各7セグメントLEDに同時に表示される数字が異なるように,各カウンタの回転開始時期をずらしています(全タクトスイッチ同時押下によるフィーバーの防止).
ソースコードの解説
下にソースコードを示します.slot_machineモジュール内には,コントローラのステートマシンとフィーバー判定器が記述されています. 35行目がフィーバー判定器の記述です. ステートマシンの状態がslot_waitかつ全数字の回転が停止しているときに,3個のカウンタの数字が同一であれば,led10モジュールのen信号を"1"にします.
decoderモジュールは,カウンタが保持している数字を2進数表現から7セグメントLED用の信号パターンに変換する組合せ回路です.
led10モジュールは,フィーバーのときに10個のLEDを点滅させる回路です. slot_machineモジュール内のフィーバー判定器が出力するen信号により点滅動作が制御されます.
counterモジュールは,7セグメントLEDに表示する数字を変化させ,その数字を保持するための回路です. 数字の変化は,slot_machineモジュール内のコントローラが出力するen信号により制御されます.
clk_generatorモジュールは簡易的なクロック分周器です. クロック周波数が高いと7セグメントLEDの数字を視認できないため,クロック周波数を落としています. なお,ここでは,FPGAに外部から入力されるクロックの周波数は50MHzを想定しています.
ソースコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | `define max 2 `define length 22 module slot_machine(clk, sw, btn0, btn1, btn2, led7_0, led7_1, led7_2, led10); input clk, sw, btn0, btn1, btn2; output [6:0] led7_0, led7_1, led7_2; output [9:0] led10; reg [1:0] state; reg en_0, en_1, en_2; reg [1:0] cnt; wire clk_local; wire rst; wire en_led10; wire [2:0] cout_0, cout_1, cout_2; parameter init = 2'b00; parameter slot_start0 = 2'b01; parameter slot_start1 = 2'b11; parameter slot_wait = 2'b10; clk_generator uclk_generator(.clk(clk), .rst(rst), .clk_local(clk_local)); counter ucounter_0(.clk(clk_local), .rst(rst), .en(en_0), .cout(cout_0)); counter ucounter_1(.clk(clk_local), .rst(rst), .en(en_1), .cout(cout_1)); counter ucounter_2(.clk(clk_local), .rst(rst), .en(en_2), .cout(cout_2)); decoder udecoder_0(.din(cout_0), .led7(led7_0)); decoder udecoder_1(.din(cout_1), .led7(led7_1)); decoder udecoder_2(.din(cout_2), .led7(led7_2)); led10 uled10(.clk(clk_local), .rst(rst), .en(en_led10), .led10(led10)); assign rst = sw; assign en_led10 = ((state == slot_wait) & ~en_0 & ~en_1 & ~en_2 & (cout_0 == cout_1) & (cout_0 == cout_2)) ? 1'b1 : 1'b0; always @(negedge clk_local or posedge rst) begin if(rst == 1'b1) begin en_0 <= 1'b0; en_1 <= 1'b0; en_2 <= 1'b0; cnt <= 2'd0; state <= init; end else begin case(state) init: begin if(rst == 1'b0) begin en_0 <= 1'b1; en_1 <= 1'b0; en_2 <= 1'b0; cnt <= 2'd0; state <= slot_start0; end else begin en_0 <= 1'b0; en_1 <= 1'b0; en_2 <= 1'b0; state <= state; end end slot_start0: begin if(cnt == `max - 1) begin en_0 <= 1'b1; en_1 <= 1'b1; en_2 <= 1'b0; cnt <= 2'd0; state <= slot_start1; end else begin cnt <= cnt + 2'd1; state <= state; end end slot_start1: begin if(cnt == `max - 1) begin en_0 <= 1'b1; en_1 <= 1'b1; en_2 <= 1'b1; cnt <= 2'd0; state <= slot_wait; end else begin cnt <= cnt + 2'd1; state <= state; end end slot_wait: begin if(btn0 == 1'b0) begin en_0 <= 1'b0; end if(btn1 == 1'b0) begin en_1 <= 1'b0; end if(btn2 == 1'b0) begin en_2 <= 1'b0; end state <= state; end endcase end end endmodule module decoder(din, led7); input [2:0] din; output [6:0] led7; assign led7 = decoder_func(din); function [6:0] decoder_func; input [2:0] din; case(din) 3'd0: decoder_func = 7'b1000000; 3'd1: decoder_func = 7'b1111001; 3'd2: decoder_func = 7'b0100100; 3'd3: decoder_func = 7'b0110000; 3'd4: decoder_func = 7'b0011001; 3'd5: decoder_func = 7'b0010010; 3'd6: decoder_func = 7'b0000011; 3'd7: decoder_func = 7'b1111000; default: decoder_func = 7'b0111111; endcase endfunction endmodule module led10(clk, rst, en, led10); input clk, rst, en; output [9:0] led10; reg [9:0] led10; reg led10_state; parameter led10_init = 1'b0; parameter led10_func0 = 1'b1; always @(negedge clk or posedge rst) begin if(rst == 1'b1) begin led10 <= 10'b0000000000; led10_state <= led10_init; end else if(en == 1'b1) begin case(led10_state) led10_init: begin led10 <= 10'b0101010101; led10_state <= led10_func0; end led10_func0: begin led10 <= led10 ^ 10'b1111111111; led10_state <= led10_state; end endcase end end endmodule module counter(clk, rst, en, cout); input clk; input rst; input en; output [2:0] cout; reg [2:0] cout; always @(posedge clk or posedge rst) begin if(rst == 1'b1) begin cout <= 3'd0; end else if(en == 1'b1) begin if(cout == 3'd7) begin cout <= 3'd0; end else begin cout <= cout + 3'd1; end end end endmodule module clk_generator(clk, rst, clk_local); input clk; input rst; output clk_local; reg [`length - 1:0] cnt; assign clk_local = cnt[`length - 1]; always @(posedge clk or posedge rst) begin if(rst == 1'b1) begin cnt <= `length'd0; end else begin cnt <= cnt + `length'd1; end end endmodule |
製品紹介
技術評論社
売り上げランキング: 80089
0 件のコメント:
コメントを投稿