キャリー信号は、組み合わせ回路の出力として作成する必要があるので、最終的にはリスト6のようにキャリー信号を作成します(最終的な60進カウンタのリスト7では、10進カウンタに相当する部分の信号名を「COUNT_TMP」→「CNT10」に変更しています)。
(省略) 28 always @(posedge CLK or negedge RESET) 29 begin 30 if (RESET == 1'b0) 31 begin 32 COUNT_TMP <= 4'h0; 33 CARRY <= 1'b0; 34 end 35 else if (ENABLE == 1'b1) 36 // else if (DEC == 1'b1) 37 if (DEC == 1'b1) 38 begin 39 if (COUNT_TMP == 4'h9) 40 COUNT_TMP <= 4'h0; 41 else 42 COUNT_TMP <= COUNT_TMP + 4'h1; 43 end 44 else 45 begin 46 if (COUNT_TMP == 4'h0) 47 COUNT_TMP <= 4'h9; 48 else 49 COUNT_TMP <= COUNT_TMP - 4'h1; 50 end 51 end 52 53 always @(COUNT_TMP or DEC) 54 begin 55 if (DEC == 1'b1) 56 if (COUNT_TMP == 4'h9) 57 CARRY <= 1'b1; 58 else 59 CARRY <= 1'b0; 60 else 61 if (COUNT_TMP == 4'h0) 62 CARRY <= 1'b1; 63 else 64 CARRY <= 1'b0; 65 end (省略)
リスト6 正しいハードウェア構成によるキャリーの作り方(UPDOWN10-4.v) |
作成したキャリー信号は6進カウンタと10進カウンタで参照します。このけた上げ・けた下げの信号は、ある意味1秒のイネーブルと同じ意味合いがあるととらえてもよいので、ここはif文でネストせずに、つまり優先順位としてはENABLEと同じと考えて“&&”の条件演算子で記述します。こうすることで60進カウンタがきちんと動作するのです(リスト7)。
(省略) 10 always @(posedge CLK or negedge RESET) 11 begin 12 if (RESET == 1'b0) 13 begin 14 CNT10 <= 4'h0; 15 end 16 else if (ENABLE == 1'b1) 17 // else if (DEC == 1'b1) 18 if (DEC == 1'b1) 19 begin 20 // if (CNT10 == 4'h9) 21 if (CARRY == 1'b1) 22 CNT10 <= 4'h0; 23 else 24 CNT10 <= CNT10 + 4'h1; 25 end 26 else 27 begin 28 // if (CNT10 == 4'h0) 29 if (CARRY == 1'b1) 30 CNT10 <= 4'h9; 31 else 32 CNT10 <= CNT10 - 4'h1; 33 end 34 end 35 36 always @(CNT10 or DEC) 37 begin 38 if (DEC == 1'b1) 39 if (CNT10 == 4'h9) 40 CARRY <= 1'b1; 41 else 42 CARRY <= 1'b0; 43 else 44 if (CNT10 == 4'h0) 45 CARRY <= 1'b1; 46 else 47 CARRY <= 1'b0; 48 end 49 50 always @(posedge CLK or negedge RESET) 51 begin 52 if (RESET == 1'b0) 53 begin 54 CNT6 <= 3'b000; 55 end 56 else if (ENABLE == 1'b1 && CARRY == 1'b1) 57 // else if (DEC == 1'b1) 58 if (DEC == 1'b1) 59 begin 60 if (CNT6 == 3'b101) 61 CNT6 <= 3'b000; 62 else 63 CNT6 <= CNT6 + 3'b001; 64 end 65 else 66 begin 67 if (CNT6 == 3'b000) 68 CNT6 <= 3'b101; 69 else 70 CNT6 <= CNT6 - 3'b001; 71 end 72 end (省略)
リスト7 最終的な60進カウンタ(CNT60.v) |
図7、リスト8のようにモジュールを接続したときのテストベンチをリスト9に示します。
1 module CNT60_ALL(CLK, RESET, DEC, LED, SA); 2 input CLK, RESET, DEC; 3 output [7:0] LED; 4 output [3:0] SA; 5 6 reg [22:0] tmp_count; 7 8 wire [3:0] CNT10; 9 wire [2:0] CNT6; 10 wire ENABLE, ENABLE_kHz; 11 wire [7:0] LED10, LED6; 12 13 parameter SEC1_MAX = 6000000; // 6MHz 14 15 always @(posedge CLK or negedge RESET) 16 begin 17 if (RESET == 1'b0) 18 tmp_count <= 23'h000000; 19 else if (ENABLE == 1'b1) 20 tmp_count <= 23'h000000; 21 else 22 tmp_count <= tmp_count + 23'h1; 23 end 24 25 assign ENABLE = (tmp_count == (SEC1_MAX - 1))? 1'b1 : 1'b0; 26 assign ENABLE_kHz = (tmp_count[11:0] == 12'hfff)? 1'b1 : 1'b0; 27 28 CNT60 i0(.CLK(CLK), .RESET(RESET), .DEC(DEC), .ENABLE(ENABLE), 29 .CNT10(CNT10), .CNT6(CNT6)); 30 DECODER7 i1(.COUNT(CNT10), .LED(LED10)); 31 DECODER7 i2(.COUNT({1'b0,CNT6}), .LED(LED6)); 32 DCOUNT i3(.CLK(CLK), .ENABLE(ENABLE_kHz), .L1(LED10), .L2(LED6), 33 .L3(8'hff), .L4(8'hff), .SA(SA), .L(LED)); 34 35 endmodule
リスト8 各モジュールのインスタンス(CNT60_ALL.v) |
1 module TEST_CNT60_ALL; 2 reg clk, reset, dec; 3 wire [7:0] led; 4 wire [3:0] sa; 5 6 parameter CYCLE = 100; 7 parameter SIM_SEC1_MAX = 4; 8 9 CNT60_ALL #(.SEC1_MAX(SIM_SEC1_MAX)) i1(.RESET(reset), 10 .CLK(clk), .DEC(dec), .LED(led), .SA(sa)); 11 12 always #(CYCLE/2) 13 clk = ~clk; 14 15 initial 16 begin 17 reset = 1'b0; clk = 1'b0; dec = 1'b1; 18 #CYCLE reset = 1'b1; 19 #(65*CYCLE*SIM_SEC1_MAX) dec = 1'b0; 20 #(10*CYCLE*SIM_SEC1_MAX) $finish; 21 end 22 23 initial 24 $monitor($time,,"clk=%b reset=%b dec=%b count60=%d%d", clk , reset, dec, i1.i0.CNT6 , i1.i0.CNT10); 25 26 endmodule
リスト9 最終的な60進カウンタのテストベンチ(TEST_CNT60_ALL.v) |
シミュレーション結果を画面4に示します。
Copyright © ITmedia, Inc. All Rights Reserved.