//単純な回路
module ON_Circuit(
input BTN0,
output LD0
);
assign LD0 = BTN0;
endmodule
//AND回路
module AND_Circuit(
input SW0,
input SW1,
output LD0
);
assign LD0 = SW0 & SW1;
endmodule
//OR回路
module OR_Circuit(
input SW0,
input SW1,
output LD0
);
assign LD0 = SW0 || SW1;
endmodule
//3bit セレクタ回路
module OR_Circuit(
input [2:0] SWA,
input [2:0] SWB,
input SW15,
output [2:0] LD
);
assign LD = (SW15 == 1) ? SWB : SWA;
endmodule
//フリップフロップ (非同期リセット)
module Flip_Flop(
input CLK,
input RESET,
input D,
output Q
);
reg ff; //レジスタ宣言
assign Q = ff;
always@(posedge CLK or posedge RESET) //always文
begin
if (RESET) //if文
ff <= 0; //ノンブロッキング代入文
else
ff <= D;
end
endmodule
`timescale 1ns/1ns
module TestBench;
//入力はreg宣言
reg CLK, RESET, D;
//出力はwire宣言
wire Q;
Flip_Flop uut( //モジュール名は自分で作成した名前に書き換えること
.CLK(CLK),
.RESET(RESET),
.D(D),
.Q(Q)
);
always //always文でクロック信号の生成 (繰り返し動作) を記述
#5 CLK = ~CLK; //5ns毎にCLKの入力を反転→10ns周期のCLK入力を実現
initial begin
$monitor( $stime, "CLK=%b RESET=%b D=%b Q=%b", CLK, RESET, D, Q); //出力信号の確認
//各入力信号に初期値0を与える
CLK = 0;
RESET = 0;
D = 0;
//最初の50nsは初期値を表示する
#50;
//50nsの初期値表示後
#3 D = 1’b1; //3~8nsでDは1
#5 D = 1’b0; //8~18nsでDは0
#10 D = 1’b1; //18ns以降はDは1
#12 RESET = 1’b1; //30~40nsでRESETは1
#12 RESET = 1’b0; //40~50nsでRESETは0
#10 $stop; //最後の入力を与えてから10ns (クロック信号が1周期) したら終了
end
endmodule
module Counter(
input CLK,
input RESET,
output [3:0] Q
);
reg [3:0] ff; //順序回路のalways文で代入するのでレジスタ宣言
always @(posedge CLK or posedge RESET) //CLK or RESETの立ち上がり時に実行
begin
if (RESET) //RESET信号が入力された場合はカウンタを0にする
ff <= 0;
else
ff <= ff + 1; //上記以外の場合はカウンタを+1ずつ増やす
end
assign Q = ff; //ffに保持している値を出力Qに代入
endmodule
module TestBench;
//入力はreg宣言
reg CLK;
reg RESET;
//出力はwire宣言
wire [3:0] Q;
Counter uut(
.CLK(CLK),
.RESET(RESET),
.Q(Q)
);
always
#5 CLK = ~CLK; //CLK信号を5ns毎に反転 (10nsで1周期)
initial begin
//初期値の設定
CLK = 0;
RESET = 0;
#5 RESET = 1'b1;
#5 RESET = 1'b0;
#490 $stop;
end
endmodule
module Divide_Clock(
input CLK,
input RESET,
output LD0
);
wire enable;
reg ff; //LEDの状態を管理する変数 順序回路のalways文で代入するのでレジスタ宣言
reg [25:0] temp_count; //クロックの立ち上がり回数(クロックサイクル数)をカウントするための変数
//クロックサイクル数(temp_count) を数えるためのalways文
always @(posedge CLK or posedge RESET) //CLK or RESETの立ち上がり時に実行
begin
if (RESET) //RESET信号が入力された場合
temp_count <= 0; //サイクル数を0にして初期化
else if (temp_count == 49999999) // RESET信号が1ではなくtemp_countが49999999のとき
temp_count <= 0; // サイクル数を初期化 (=0)
else // それ以外
temp_count <= temp_count + 1; // サイクル数+1
end
//3項演算子 (講義資料参照)
assign enable = (temp_count == 0) ? 1 : 0; //temp_count == 0ならenable = 1, それ以外はenable = 0
//LEDの出力を決めるalways文
always @(posedge CLK or posedge RESET)
begin
if (RESET) //RESET信号が入力された場合
ff <= 0; // LEDを消灯
else if (enable == 1)// RESET信号が1ではなくクロックサイクル数が0である
ff <= ~ff; // LEDを点灯→消灯 or 消灯 → 点灯
end
assign LD0 = ff; //ffに保持している値を出力LD0に代入
endmodule
module TestBench;
//入力はreg宣言
reg CLK;
reg RESET;
//出力はwire宣言
wire LD0;
// Divide_Clockモジュールのインスタンス化
Divide_Clock uut(
.CLK(CLK),
.RESET(RESET),
.LD0(LD0)
);
always
#5 CLK = ~CLK; //CLK信号を5ns毎に反転 (10nsで1周期)
initial begin
//初期値の設定
CLK = 0;
RESET = 0;
//wait for 100ns for global reset to finish
#100;
#5 RESET = 1'b1; //5nsでRESET信号を1に
#5 RESET = 1'b0; //10nsでRESET信号を0に
#4990 $stop; //5000nsでシミュレーション終了
end
endmodule
module Decimal_Counter(
input CLK,
input RESET,
output [3:0] Q
);
wire inc; //10-2のイネーブル信号と同じ
reg [3:0] ff; //カウンタ用変数 順序回路のalways文で代入するのでレジスタ宣言
reg [26:0] temp_count; //クロックサイクルを数えるための変数
//クロックサイクル数(temp_count) を数えるためのalways文
always @(posedge CLK or posedge RESET) //CLK or RESETの立ち上がり時に実行
begin
if (RESET) //RESET信号が入力された場合
temp_count <= 0; //サイクル数を0にして初期化
else if (temp_count == 99999999)// RESET信号が1ではなくtemp_countが99999999のとき
temp_count <= 0; //初期化
else // それ以外のとき
temp_count <= temp_count + 1; //サイクル数+1
end
//三項演算子
//サイクル数temp_count == 0であればinc = 1, そうでなければ inc = 0
assign inc = (temp_count == 0) ? 1:0;
//カウンタ用のalways文
always @(posedge CLK or posedge RESET) //CLK or RESETの立ち上がり時に実行
begin
if (RESET) //RESET信号が入力された場合はカウンタを0にする
ff <= 0;
else if (inc) // サイクル数が0である(=99999999クロック目)
if (ff == 9) //カウンタが上限の9である場合
ff <= 0; //カウンタの値は0に戻す
else //カウンタが9以外の値の場合
ff <= ff + 1; //カウンタ+1
end
assign Q = ff; //ffに保持している値を出力Qに代入
endmodule
module TestBench;
// 10-2を参考に記述する。出力信号のビット幅の違いに注意!
endmodule
module SimpleFSM(
input CLK,
input RESET,
input START,
output [1:0] LED
);
//stateを管理するための変数をreg宣言
reg [2:0] state;
//stateレジスタに書き込み
always @(posedge CLK or posedge RESET) begin //CLK信号が立ち上がったらbegin以降を実行
if (RESET)
state <= 3'd0; //RESET信号が入力された場合はstate=0 (初期状態)
else begin
case (state)
3'd0: if (START) state <= 3'd1; //START信号が入力されたら1へ遷移
3'd1: state <= 3'd2; //1から2へ遷移
3'd2: state <= 3'd3; //2から3へ遷移
3'd3: state <= 3'd4; //3から4へ遷移
3'd4: state <= 3'd0;
default: state <= 3'd0;
endcase
end
end
//出力Qのreg宣言
reg [1:0] Q;
//Qレジスタに書き込み
always@(state) //stateに変化があった場合にbegin以降を実行
begin
case(state) //case文による条件分岐
0: Q <= 2'd0; //state = 0 のとき出力 Qに0を代入
1: Q <= 2'd3; //state = 1 のとき出力 Qに3を代入
2: Q <= 2'd1; //state = 2 のとき出力 Qに1を代入
3: Q <= 2'd2; //state = 3 のとき出力 Qに2を代入
4: Q <= 2'd0; //state = 4 のとき出力 Qに0を代入
default: Q <= 2'd0; //上記以外のstateの場合出力Qに0を代入
endcase
end
assign LED = Q; // レジスタQの出力を出力信号LEDに接続
endmodule
`timescale 1ns / 1ps
module TestBench;
// Inputs
reg CLK;
reg RESET;
reg START;
// Outputs
wire [1:0] LED;
// Instantiate the Unit Under Test (UUT)
SimpleFSM uut (
.CLK(CLK),
.RESET(RESET),
.START(START),
.LED(LED)
);
always
#5 CLK = ~CLK; // clock generation
initial begin
// Initialize Inputs
CLK = 0;
RESET = 0;
START = 0;
// Wait 50 ns for global reset to finish
#50;
// Add stimulus here
#10 RESET = 1;
#10 RESET = 0;
#10 START = 1;
#20 START = 0;
#50;
#10 START = 1;
#20 START = 0;
#100 $stop;
end
endmodule
// 組み合わせ:4入力AND
module and4(input a, b, c, d, output y);
wire w1, w2;
AND_Circuit u1(.SW0(a), .SW1(b), .LD0(w1)); // aとbのAND
AND_Circuit u2(.SW0(c), .SW1(d), .LD0(w2)); // cとdのAND
AND_Circuit u3(.SW0(w1), .SW1(w2), .LD0(y)); // w1とw2のAND
endmodule
module clk_divider_10hz(
input CLK,
input RESET,
output CLK_OUT
);
reg [26:0] temp_count;
// 【TODO】ここに実装
// Week 2の分周回路を参考に
assign CLK_OUT = (temp_count == 0) ? 1 : 0;
endmodulemodule digit_counter(
input CLK,
input RESET,
input ENABLE, // 10Hzパルス
input STOP, // 停止信号
output reg [3:0] DIGIT
);
// 【TODO】ここに実装
// Week 2の10進カウンタを参考に
// ※ENABLE && !STOPのときだけカウント
endmodulemodule slot_control_fsm(
input CLK,
input RESET,
input BTN_START,
input BTN_STOP_L,
input BTN_STOP_C,
input BTN_STOP_R,
output reg [2:0] STOP_DIGITS
);
// 状態定義
parameter S_IDLE = 3'd0;
parameter S_ROLLING = 3'd1;
parameter S_STOP_L = 3'd2;
parameter S_STOP_C = 3'd3;
parameter S_STOP_R = 3'd4;
reg [2:0] state;
// 状態遷移ロジック
always @(posedge CLK or posedge RESET) begin
if (RESET)
state <= S_IDLE;
else begin
case (state)
S_IDLE: if (BTN_START) state <= S_ROLLING;
// 【TODO】状態遷移表を見て、case文を完成させる
default: state <= S_IDLE;
endcase
end
end
// 出力ロジック
always @(*) begin
case (state)
S_IDLE: STOP_DIGITS = 3'b111; // 全桁停止
// 【TODO】各状態でのSTOP_DIGITSを定義
default: STOP_DIGITS = 3'b111;
endcase
end
endmodulemodule seven_seg_controller(
input CLK,
input [3:0] DIGIT1, // 左桁の値(0-9)
input [3:0] DIGIT2, // 中桁の値(0-9)
input [3:0] DIGIT3, // 右桁の値(0-9)
output [11:0] SEG // {AN[3:0], DP, SEG[6:0]}
);
reg [11:0] buff;
reg [3:0] current_digit;
// リフレッシュ用カウンタ(高速スキャン用)
reg [16:0] refresh_counter;
wire [1:0] scan_clk;
// 高速スキャン用クロック生成(約190Hz)
// 100MHz / 2^17 ? 763Hz → 2ビットで4分周 → 約190Hz
always @(posedge CLK) begin
refresh_counter <= refresh_counter + 1;
end
assign scan_clk = refresh_counter[16:15];
// 表示する桁と数字の選択
always @(*) begin
case (scan_clk)
2'd0: begin
buff[11:8] = 4'b1011; // AN[3:0] = 左桁(AN3)点灯
current_digit = DIGIT1;
end
2'd1: begin
buff[11:8] = 4'b1101; // AN[3:0] = 中桁(AN2)点灯
current_digit = DIGIT2;
end
2'd2: begin
buff[11:8] = 4'b1110; // AN[3:0] = 右桁(AN1)点灯
current_digit = DIGIT3;
end
default: begin
buff[11:8] = 4'b1111; // AN[3:0] = 全消灯
current_digit = 4'd10; // 無効値(消灯用)
end
endcase
// DP(ドット)は常に消灯
buff[7] = 1'b1;
// BCD to 7segment変換
case (current_digit)
4'd0: buff[6:0] = 7'b1000000; // 0
4'd1: buff[6:0] = 7'b1111001; // 1
4'd2: buff[6:0] = 7'b0100100; // 2
4'd3: buff[6:0] = 7'b0110000; // 3
4'd4: buff[6:0] = 7'b0011001; // 4
4'd5: buff[6:0] = 7'b0010010; // 5
4'd6: buff[6:0] = 7'b0000010; // 6
4'd7: buff[6:0] = 7'b1011000; // 7
4'd8: buff[6:0] = 7'b0000000; // 8
4'd9: buff[6:0] = 7'b0010000; // 9
default: buff[6:0] = 7'b1111111; // 消灯
endcase
end
assign SEG = buff;
endmodulemodule slot_machine_top(
input CLK, // 100MHz
input RESET, // BTNU
input BTN_START, // BTND
input BTN_STOP_L, // BTNL
input BTN_STOP_C, // BTNC
input BTN_STOP_R, // BTNR
output [11:0] SEG
);
// ========== 内部信号の宣言 ==========
wire clk_10hz; // 10Hzパルス
wire [2:0] stop_digits; // 各桁の停止信号
wire [3:0] digit1, digit2, digit3; // 各桁の値
// ========== モジュールのインスタンス化 ==========
// 1. クロック分周器(10Hz生成)
clk_divider_10hz div(
.CLK(CLK),
.RESET(RESET),
.CLK_OUT(clk_10hz)
);
// 2. 制御ステートマシン
slot_control_fsm fsm(
.CLK(CLK),
.RESET(RESET),
.BTN_START(BTN_START),
.BTN_STOP_L(BTN_STOP_L),
.BTN_STOP_C(BTN_STOP_C),
.BTN_STOP_R(BTN_STOP_R),
.STOP_DIGITS(stop_digits)
);
// 3. 桁カウンタ(左桁)
digit_counter cnt1(
.CLK(CLK),
.RESET(RESET),
.ENABLE(clk_10hz),
.STOP(stop_digits[2]),
.DIGIT(digit1)
);
// 4. 桁カウンタ(中桁)
// 【TODO】 cnt2をインスタンス化(cnt1を参考に)
// ヒント: stop_digits[1]を使用、digit2に出力
// 5. 桁カウンタ(右桁)
// 【TODO】 cnt3をインスタンス化(cnt1を参考に)
// ヒント: stop_digits[0]を使用、digit3に出力
// 6. 7セグメント表示制御
seven_seg_controller disp(
.CLK(CLK),
.DIGIT1(digit1),
.DIGIT2(digit2),
.DIGIT3(digit3),
.SEG(SEG)
);
endmodule`timescale 1ns / 1ps
module slot_machine_top_sim();
reg CLK, RESET, BTN_START, BTN_STOP_C, BTN_STOP_L, BTN_STOP_R;
wire [11:0] SEG;
// テスト対象のモジュール
slot_machine_top uut(
.CLK(CLK),
.RESET(RESET),
.BTN_START(BTN_START),
.BTN_STOP_C(BTN_STOP_C),
.BTN_STOP_L(BTN_STOP_L),
.BTN_STOP_R(BTN_STOP_R),
.SEG(SEG)
);
// クロック生成(100MHz = 10ns周期)
initial CLK = 0;
always #5 CLK = ~CLK;
// テストシナリオ
initial begin
// 初期化
RESET = 1; BTN_START = 0;
BTN_STOP_L = 0; BTN_STOP_C = 0; BTN_STOP_R = 0;
#10 RESET = 0;
// スタート
#20 BTN_START = 1;
#20 BTN_START = 0;
// 待機
#300;
// ストップ1(左桁停止)
BTN_STOP_L = 1;
#50 BTN_STOP_L = 0;
// 左桁停止後、中・右桁がカウント
#100;
// ストップ2(中桁停止)
BTN_STOP_C = 1;
#50 BTN_STOP_C = 0;
// 中桁停止後、右桁のみカウント
#100;
// ストップ3(右桁停止)
BTN_STOP_R = 1;
#50 BTN_STOP_R = 0;
// 全桁停止後、少し待つ
#100;
$finish;
end
endmodule講義資料 > 情報電子オプティクス実験B > HDLによるハードウェア設計 > Verilogソースコード例