このサンプルプログラムは,いくつかのLEDを環状に配置し,それらをスイッチで止めるものです.外観を下に示します.14個のLEDが並んでおり,スイッチを押すとひとつだけLEDが点灯し,そのLEDが矢印方向に進んでいきます.その後,スイッチを離すとLEDがゆっくりと進むようになり,およそ3秒後に完全に停止する前に3回ほど点滅します.

このように,内部の状態を遷移するような回路の場合,状態マシン図などを使うと分かりやすくなります.下の図では状態変化の様子を示しています.

回路でこれを実現するにはregとして状態を管理することになります.今回は状態が下表のようになりますので全部で4種類となります.従いまして2ビットのregがあればよいわけです.この状態をMODEという名前でVerilogHDLでは取り扱うこととします.
| 状態 | MODE |
| 停止状態 | 2'b00 |
| 高速移動状態 | 2'b01 |
| 低速移動状態 | 2'b10 |
| 点滅状態 | 2'b11 |
ルーレットを動作させるためのコードを下に示します.MODEが変化していく様子を確認してください.
`timescale 1ns / 1ps
module roulette(M_CLK, SW, LED);
input M_CLK; // マスタークロック(4[MHz])
input SW; // スイッチ
output [13:0] LED; // ルーレット用LED
wire DIVIDED_CLK; // 分周されたクロック(およそ30[Hz])
wire CLK_FOR_STOPPING; // 停止用クロック(およそ2[Hz]
wire CLK_FOR_BLINKING; // 点滅用カウンタ(およそ7.5[Hz])
wire [3:0]LED_LOCATE; // LEDの位置
wire CLK; // ルーレット回路を動かすためのクロック
reg [2:0]COUNT_FOR_STOPPING = 3'b111; // 停止用カウンタ
reg [2:0]COUNT_FOR_BLINKING = 3'b101; // 点滅用カウンタ
reg STOP = 1'b1; // LEDの移動を停止するとき1,移動しているとき0
reg [1:0]MODE = 2'b00; //停止状態
Divider17 d(.SRC_CLK(M_CLK), .DEST_CLK(DIVIDED_CLK)); // 2^17分周器
Divider4 d2(.SRC_CLK(DIVIDED_CLK), .DEST_CLK(CLK_FOR_STOPPING)); // 2^4分周器
Divider2 d3(.SRC_CLK(DIVIDED_CLK), .DEST_CLK(CLK_FOR_BLINKING)); // 2^2分周器
always @(posedge CLK) // クロックが立ち上がるとき
begin
if(SW == 2'b0) // スイッチが押されている
begin
MODE <= 3'b001;// 高速移動状態へ
STOP <= 1'b0;// LEDを移動させる
end
else if(SW == 2'b1) // スイッチが離されている
begin
case(MODE)
2'b01:// 高速移動状態のとき
begin
COUNT_FOR_STOPPING <= 3'b111; //低速移動カウンタを初期化する
MODE <= 2'b10; // 低速移動状態へ
end
2'b10: // 低速移動状態のとき
begin
if(COUNT_FOR_STOPPING == 3'b000) //低速移動カウンタがアンダーフローしたら
begin
COUNT_FOR_STOPPING <= 3'b111; // 停止用カウンタを初期化する
STOP <= 1'b1; // LEDを停止させる
MODE <= 2'b11; // 点滅状態へ
end
else
begin
/* 停止用カウンタをデクリメントする */
COUNT_FOR_STOPPING <= COUNT_FOR_STOPPING-3'b001;
end
end
2'b11: // 点滅状態のとき
begin
if(COUNT_FOR_BLINKING == 3'b000) // 点滅用カウンタがアンダーフローしたら
begin
COUNT_FOR_BLINKING <= 3'b101; // 点滅用カウンタを初期化する
MODE <= 2'b00; // 停止状態へ
end
else
begin
/* 点滅用カウンタをデクリメントする */
COUNT_FOR_BLINKING <= COUNT_FOR_BLINKING-3'b001;
end
end
endcase
end
end
/* クロックのセレクタ */
function ClockSelector;
input [1:0]MODE;
begin
/* 状態により変える */
case(MODE)
2'b10:ClockSelector=CLK_FOR_STOPPING;//低速移動状態のとき,停止用クロックを選択する
2'b11:ClockSelector=CLK_FOR_BLINKING;//点滅状態のとき,点滅用クロックを選択する
default:ClockSelector=DIVIDED_CLK; // 上記以外のとき,分周クロックを選択する
endcase
end
endfunction
assign CLK = ClockSelector(MODE); // クロックセレクタにより,クロックを得る
/* カウンタを得る */
counter COUNT(.CLK(CLK), .STOP(STOP), .BLINKING(COUNT_FOR_BLINKING[0]), .LED_LOCATE(LED_LOCATE));
/* デコードする */
decoder DECODER(.LED_LOCATE(LED_LOCATE), .LED(LED));
endmodule
