【HDL】60進カウンタで気付きにくい不具合 | 組込みとともに

【HDL】60進カウンタで気付きにくい不具合

本日もALTERA DE1と戯れました。

今回デジタル・デザイン・テクノロジNo.2で紹介された60進カウンタを実際に試してみたいと思います。


いきなり動画から入りますが、↓のようにうまく動きませんでした。

本来[0059]の次は[0100]のはずですが、[0080]となってしまっていますね

また[00d9]の次で[0100]となっていてなんだかおかしな動作ですあせる
本来は↓のような動作です。

一見問題なさそうなHDLですが私のような初心がが陥りやすい不具合が潜んでいます。

ソースは下記の通りです。

---(一部抜粋です)---

/* 前記省略 */ wire [15:0] mSEG7_DIG; wire EN; // イネーブル信号(1秒に1回1クロック) wire SECCA; // 秒のキャリー(分へのキャリー) wire [2:0] SEC10; // 秒 10の桁 wire [3:0] SEC1; // 秒 1の桁 wire MINCA; // 分のキャリー(時へのキャリー) wire [2:0] MIN10; // 分 10の桁 wire [3:0] MIN1; // 分 1の桁 DIV1Hz C1Hz(CLOCK_50, EN); // 1秒周期のイネーブル生成 CNT60 SEC(CLOCK_50, EN, SECCA, SEC1, SEC10 ); // 秒の60進カウンタ CNT60 MIN(CLOCK_50, SECCA, MINCA, MIN1, MIN10 ); // 分の60進カウンタ assign mSEG7_DIG = { MIN10,MIN1,SEC10,SEC1 }; // 7セグメントLEDへ出力 SEG7_LUT_4 u0 ( HEX0,HEX1,HEX2,HEX3,mSEG7_DIG ); /* 以下略 */ ///modules (下記モジュールには不具合はありません) /* 6進カウンタ */ /* EN(Enable)=1のときのみカウントアップ */ module CNT6( CLK, EN, CA, Q ); input CLK, EN; output CA; output [2:0] Q; reg [2:0] Q; always@ (posedge CLK) begin if ( EN == 1'b1 ) if ( Q == 3'h5 ) Q <= 3'h0; else Q <= Q + 3'h1; end assign CA = (Q == 3'h5) & EN; endmodule /* 10進カウンタ */ /* EN(Enable)=1のときのみカウントアップ */ module CNT10( CLK, EN, CA, Q ); input CLK, EN; output CA; output [3:0] Q; reg [3:0] Q; always@ (posedge CLK) begin if ( EN == 1'b1 ) if ( Q == 4'h9 ) Q <= 4'h0; else Q <= Q + 4'h1; end assign CA = (Q == 4'h9) & EN; endmodule /* 1秒周期で1Clock期間のイネーブル信号の出力 */ module DIV1Hz(CLK, EN1Hz); input CLK; output EN1Hz; // イネーブル出力信号 reg [25:0] Q; assign EN1Hz = (Q == 26'd9999999/*49999999*/); /* デバック用 */ always@ (posedge CLK) begin if (EN1Hz == 1'b1) Q <= 26'h0; else Q <= Q + 26'h1; end endmodule /* 6進カウンタと10進カウンタを組み合わせて60進カウンタ */ /* EN(Enable)=1のときのみカウントアップ */ module CNT60 ( CLK, EN, CA, DIG1, DIG10); input CLK, EN; output CA; // キャリー output [3:0] DIG1; output [2:0] DIG10; wire CA10; // 10進→6進のキャリー CNT10 CNT10( CLK, RST, EN, CA10, DIG1 ); // 10進カウンタ 1の桁 CNT6 CNT6( CLK, RST, CA10, CA, DIG10 ); // 6進カウンタ 10の桁 endmodule


---


さぁ、どこが悪かったか分かりますでしょうか?





いきなり答えを言ってしまいますよ!


ここです!!

↓↓↓

assign mSEG7_DIG = { MIN10,MIN1,SEC10,SEC1 }; // 7セグメントLEDへ出力


よーく見てください。

まずmSEG7_DIGは16ビットの信号です。

つまり、SEC1,SEC10,MIN1,MIN10はそれぞれ4ビットであることが前提ですが

SEC10, MIN10は3ビットにしました(0~5は3ビットで足りるので)

しかし、このままではmSEG_DIGが足りないビット分だけ桁が詰まるので不具合の動作となります。

対策としては次のようにします。


assign mSEG7_DIG = { { 1'b0,MIN10}, MIN1, {1'b0,SEC10}, SEC1 };
つまり1ビット分0をつめておけばOKです。

答えは簡単ですが、なかなか気付かなかったりしますから注意が必要ですねあせる



今回の参考文献

ディジタル・デザイン・テクノロジ 2009年 08月号 [雑誌]
¥1,890
Amazon.co.jp