続き。カウンタと7セグメントLEDに表示するデコーダ、スイッチ入力のチャタリング除去のモジュールを作成した。
QuartusIIで新規プロジェクトを作成。[Assignment]→[Import Assignment...]で前回作成したピンアサインを取り込む。
20130126追記:肝心のゼロサプレス部分に間違いがあります。
このままだと4桁の1001表示で10□1の様になります。ゼロサプレスは直前ではなくずっと前の桁がすべて0でなければならないので、segleddec.vは以下書き換え。
assign bout=(bcd==4'b0000)?bin:0;
https://gist.github.com/4639707
segleddec.vは4bitの入力を0~Fの16パターンと解釈し、それぞれのパターンに対応する7セグメントのLEDを点灯させる。DE0の7セグメントLEDはアノードコモンなので'0'で点灯。
TTLの7447はゼロサプレスの機能を持っている。これは普通の電卓の表示のように、桁の左側の余計なゼロを表示しないというもの。左側に位置する桁が'0'で、自分自身が'0'ならば表示を抑止する。ただし1桁目は'0'も表示する。
segleddec.v
左側の桁は'0000'ならboutを出力。右側の桁はそれをbinで受ける。右側の桁は自分が'0000'かつ左側の桁が'0000'(bin='1')なら表示を抑止。たくさん並んでいる桁なら、一番左側の桁のbinは'1'に吊ってあとはカスケード接続。ただし一番右、最後の桁はbinを'0'にして切り離す。
hexcounter.v:
こんな感じ。モジュールを定義しておいてこのように書くとインスタンスseg0,seg1,seg2,seg3を生成できる。
二進カウンターは特に問題ないが、パラメータ化して任意のビット長まで指定できるようにしてある。非同期リセット付き。
TTLなどは非同期リセットがかかるまでは値を保持するFFの内容は'1'か'0'かわからないものとして扱うが、パワーオン後にスキャンを行い初期設定するFPGAやASICは値が確定している。ただし'1'か'0'かは設定によるし、昔パワーオン直後のすべてのFFの値は'1'というPLDを使ったことがあった。
ついでにスイッチ入力をFF受けで同期化してチャタリングを抑止するunchat.vを組み込んだ。同期回路に非同期の信号を直接入れるのは気持ち悪い。以下の様なトラブルを調査したことがあるが、こんなことがありえるのだ。
入力信号は必ずFF受けで
ここではカウンターで16分周した(50MHz÷65536=20ns×65536=1.3ms)間隔でスイッチの入力をサンプリングする。チャタリングはこの周期内には収まっている前提。
パラメータ化はしていない。
QuartusIIで新規プロジェクトを作成。[Assignment]→[Import Assignment...]で前回作成したピンアサインを取り込む。
20130126追記:肝心のゼロサプレス部分に間違いがあります。
このままだと4桁の1001表示で10□1の様になります。ゼロサプレスは直前ではなくずっと前の桁がすべて0でなければならないので、segleddec.vは以下書き換え。
assign bout=(bcd==4'b0000)?bin:0;
https://gist.github.com/4639707
segleddec.vは4bitの入力を0~Fの16パターンと解釈し、それぞれのパターンに対応する7セグメントのLEDを点灯させる。DE0の7セグメントLEDはアノードコモンなので'0'で点灯。
TTLの7447はゼロサプレスの機能を持っている。これは普通の電卓の表示のように、桁の左側の余計なゼロを表示しないというもの。左側に位置する桁が'0'で、自分自身が'0'ならば表示を抑止する。ただし1桁目は'0'も表示する。
segleddec.v
assign bout=(bcd==4'b0000)?1'b1:1'b0; // ~&bcd
assign led=(bout&&bin)?8'b11111111:ALED(bcd,dp);
左側の桁は'0000'ならboutを出力。右側の桁はそれをbinで受ける。右側の桁は自分が'0000'かつ左側の桁が'0000'(bin='1')なら表示を抑止。たくさん並んでいる桁なら、一番左側の桁のbinは'1'に吊ってあとはカスケード接続。ただし一番右、最後の桁はbinを'0'にして切り離す。
hexcounter.v:
segleddec seg0(cnt[27:24],1'b0,1'b0, hled0,bout0_0); // Digit xxx0 always on
segleddec seg1(cnt[31:28],1'b0,bout2_1, hled1,bout1_0);
segleddec seg2(cnt[35:32],1'b0,bout3_2, hled2,bout2_1);
segleddec seg3(cnt[39:36],1'b0,1'b1, hled3,bout3_2);
こんな感じ。モジュールを定義しておいてこのように書くとインスタンスseg0,seg1,seg2,seg3を生成できる。
二進カウンターは特に問題ないが、パラメータ化して任意のビット長まで指定できるようにしてある。非同期リセット付き。
TTLなどは非同期リセットがかかるまでは値を保持するFFの内容は'1'か'0'かわからないものとして扱うが、パワーオン後にスキャンを行い初期設定するFPGAやASICは値が確定している。ただし'1'か'0'かは設定によるし、昔パワーオン直後のすべてのFFの値は'1'というPLDを使ったことがあった。
ついでにスイッチ入力をFF受けで同期化してチャタリングを抑止するunchat.vを組み込んだ。同期回路に非同期の信号を直接入れるのは気持ち悪い。以下の様なトラブルを調査したことがあるが、こんなことがありえるのだ。
入力信号は必ずFF受けで
ここではカウンターで16分周した(50MHz÷65536=20ns×65536=1.3ms)間隔でスイッチの入力をサンプリングする。チャタリングはこの周期内には収まっている前提。
パラメータ化はしていない。