2012/09/03

FPGA / Verilog-HDL入門 - スロットマシンの設計

これまで主にVHDLを使用していたのですが,所属環境が変わってVerilog-HDLを使用する機会が多くなりました. 回路設計自体も初心者から抜け出せていないのに,違う言語に手を出すのは危険な気がしますが,仕方がありません. 今回は,Verilog-HDLの練習として簡単なスロットマシンを設計・記述し,FPGAに実装してみました.200行程度のシンプルな回路ですが,スロットマシンとしての主要な機能は抑えていると思います.

スロットマシンの仕様

今回設計したスロットマシンは,下記のような簡単な仕様を基に設計しました.

  1. スライドスイッチをhigh(= 1)にするとリセット動作
  2. 3個の7セグメントLEDに"0"を表示
  3. スライドスイッチをlow(= 0)にすると7セグメントLEDの数字が回転
  4. "0"~"7"(8種類)の数字を順に表示
  5. 各タクトスイッチを押すと対応する数字の回転が停止
  6. 数字が揃えばフィーバーとし,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
製品紹介
FPGA ボードで学ぶ組込みシステム開発入門 ~Altera編~
小林 優
技術評論社
売り上げランキング: 80089

0 件のコメント:

コメントを投稿