So-net無料ブログ作成

Quartusで遊ぼう (10) [プログラム三昧]このエントリーを含むはてなブックマーク#

WS000219-320.png

作らせてみました。 リップル・キャリーカウンタ。

リップル・キャリーって何だ?

リップル・キャリー・カウンタは、あるフリップ・フロップの出力を次の段のフリップ・フロップのクロックとして使う回路です。 フリップ・フロップの出力の変化が次々とフリップ・フロップに伝達されるため、後段になるほど出力変化の時間が遅れていきます。 反面、半加算器が必要な同期式カウンタに比べると回路規模が圧倒的に小さくなるため、TTL時代のカウンタには良く使われていました。

リップル・キャリー型HDL記述

HDL 記述は、同期式カウンタに比べるとかなり複雑になってしいました。

module r_counter8(q, go, clk_b, reset_b);
  output[7:0]   q;
  input         go;
  input         clk_b;
  input         reset_b;
  
  reg[7:0]      q;
  
  always @(negedge clk_b or negedge reset_b) begin
    if (!reset_b)   q[0] <= 1'b0;
    else if (go)    q[0] <= ~q[0];
  end
  
  always @(negedge q[0] or negedge reset_b) begin
    if (!reset_b)   q[1] <= 1'b0;
    else            q[1] <= ~q[1];
  end
  
  always @(negedge q[1] or negedge reset_b) begin
    if (!reset_b)   q[2] <= 1'b0;
    else            q[2] <= ~q[2];
  end
  
  always @(negedge q[2] or negedge reset_b) begin
    if (!reset_b)   q[3] <= 1'b0;
    else            q[3] <= ~q[3];
  end
  
  always @(negedge q[3] or negedge reset_b) begin
    if (!reset_b)   q[4] <= 1'b0;
    else            q[4] <= ~q[4];
  end
  
  always @(negedge q[4] or negedge reset_b) begin
    if (!reset_b)   q[5] <= 1'b0;
    else            q[5] <= ~q[5];
  end
  
  always @(negedge q[5] or negedge reset_b) begin
    if (!reset_b)   q[6] <= 1'b0;
    else            q[6] <= ~q[6];
  end
  
  always @(negedge q[6] or negedge reset_b) begin
    if (!reset_b)   q[7] <= 1'b0;
    else            q[7] <= ~q[7];
  end
endmodule

"reset_b" は、非同期リセット入力です。 このカウンタは、 "go" がアサートされたときに限り、カウンタが進みます。 二段目以降のフリップ・フロップは、前段の出力が変化しない限り動作しないので、 "go" 条件を入れる必要はありません。

資源の消費量を調べた

論理合成をかけた結果、使用した Logic Element の個数は、8個となりました。 しかし、同期式カウンタの場合とはちょっと違っています。

Total registers8 / 2,210 ( < 1 % )
Total LABs4 / 221 ( 2 % )
Logic elements in carry chains0

この表は、 "Compilation Report → Fitter → Resource Section → Resource Usage Summary" から抜粋したものです。 確かに LE の数は、8個なのですが、 Logic Array Block (LAB) の数が4個になっています。 ひとつの LAB には、10個の LE が入っているので、40個の LE のうち20%しか使われていないことになります。

これは、ひとつの LAB には、二種類のクロックしか引き込めないという制約によるものです。 そのため、ひとつの LAB には二段分のフリップ・フロップしか存在できず、このような結果になりました。

残った未使用 LE は、どうなるかというと、おそらく、他のフリップ・フロップを使わない LE に割り当てられると思われますが、配線の制約は厳しくなると予想されます。

タイミングを調べた

次に "Compilation Report → Fitter → Timing Analyzer → Summary" でタイミング情報を調べてみました。

TypeSlackRequired TimeActual TimeFromToFrom ClockTo ClockFailed Paths
Worst-case tsuN/ANone0.390 nsgoq[0]~reg0--clk_b0
Worst-case tcoN/ANone22.055 nsq[7]~reg0q[7]clk_b--0
Worst-case thN/ANone-0.044 nsgoq[0]~reg0--clk_b0
Clock Setup: 'clk_b'N/ANoneRestricted to 304.04 MHz ( period = 3.289 ns )q[2]~reg0q[2]~reg0clk_bclk_b0

5行目の "Clock Setup" を見ると、このカウンタは300MHzのクロック入力に耐えることがわかります。 しかし、3行目の "Worst-case tco" を見ると、クロックが変化してからカウンタの最上位ビット q[7] が変化するまで最大22ナノ秒の時間が必要であることもわかります。 このため、カウンタの出力が信頼できるのはクロックが変化してから22ナノ秒後であり、カウンタの値に意味を持たせる場合には、40MHz程度の周波数でしか使用できません。 この "tco" (Time of Clock to Output) 時間は、カウンタの段数が増えるほど長くなるので、使用可能な周波数も低くなります。

同期式カウンタの場合

同じ仕様の8ビットの同期式カウンタを合成してみました。

  reg[7:0]      q;
  always @(negedge clk_b or negedge reset_b) begin
    if (!reset_b)   q <= 8'd0;
    else            q <= q + 8'd1;
  end

資源の消費量はこうなりました。

Total registers8 / 2,210 ( < 1 % )
Total LABs1 / 221 ( < 1 % )
Logic elements in carry chains7

同期式カウンタも8個の LE を使用しており、しかも一つの LAB で収まっています。 これは、 LE がカウンタや加算器を作りやすい構成になっているのためです。

タイミングは、こうなっています。

TypeSlackRequired TimeActual TimeFromToFrom ClockTo ClockFailed Paths
Worst-case tcoN/ANone7.142 nsq[5]~reg0q[5]clk_b--0
Clock Setup: 'clk_b'N/ANoneRestricted to 304.04 MHz ( period = 3.289 ns )q[0]~reg0q[7]~reg0clk_bclk_b0

この場合も300MHzのクロック入力に耐えることが出来ますが、クロックが変化してから q[5] が変化するまで 7.1ナノ秒の時間が必要です。 このことから、カウンタの値に意味がある場合の最大周波数は140MHzということになります。

考察

回路規模が小さくなることを期待して、リップル・キャリー・カウンタを合成しましたが、積極的に使いたくなる性能は出ませんでした。 CPLD を使っている限りは、同期式カウンタを使ったほうが良いようです。

参考文献

トランジスタ技術 (Transistor Gijutsu) 2008年 12月号 [雑誌]

トランジスタ技術 (Transistor Gijutsu) 2008年 12月号 [雑誌]

  • 作者:
  • 出版社/メーカー: CQ出版
  • 発売日: 2008/11/10
  • メディア: 雑誌

付録 : 「Quartus で遊ぼう」索引

Quartus で遊ぼう (1)
Altera の EPM2210F324 が話題になっているので、私も使ってみました。 ただし、ハードウェアは購入していないので、ソフトウェアで遊んだだけです。
Quartus で遊ぼう (2)
「Quartus で遊ぼう」の二回目は、組み合わせ論理回路の合成を調べます。
Quartus で遊ぼう (3)
論理合成後の状態を表示してくれるツールを探しました。
Quartus で遊ぼう (4)
前回作成した4値のアップ・ダウンカウンタで論理合成後に使われているフリップ・フロップは、何個(何ビット)でしょうか?
Quartus で遊ぼう (5)
今回は、ワン・ホット・コードを使ったステート・マシンでグリッチが発生すかどうかを観測します。
Quartus で遊ぼう (6)
トランジスタ技術誌に「リセット信号生成回路」のHDL記述がありました。 この記述は、ちょっともったいないですよ。
Quartus で遊ぼう (7)
トランジスタ技術誌に書かれていたインストラクション・デコーダは、3項演算子が連なっていました。 もっと、別の書き方はできないかな。
Quartus で遊ぼう (8)
Verilog の代入には、 <= と = の二種類が使われています。 これって、何が違うんでしょうかね。
Quartus で遊ぼう (9)
2進数の足し算で、キャリーを取り出したい時、どうしましょうか。
Quartus で遊ぼう (10)
作らせてみました。 リップル・キャリーカウンタ。
Quartus で遊ぼう (11)
先ごろ、請求していた"DVD"が届きました。

nice!(0)  コメント(3)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 3

DAI

昔、TTLで作る時計とか、周波数カウンタとかは非同期式でしたね。
だいぶ長期間、それがデジタル回路だと思っていました。
その思考のままで同期式が理解できず、HDLをかじった時に、
ああそうか、と思った記憶があります。それ以来、
TTLで直に製作は非同期、HDLなら同期式が楽と思っていましたが、
そう来ましたか、なんとまあ。
by DAI (2008-11-26 20:00) 

hamayan

> 昔、TTLで作る時計とか、周波数カウンタとかは非同期式でしたね。

単に早いクロックを2の乗数で分周して遅いクロックを得たい場合は、非同期式のバイナリ-カウンターで間に合う場合も多かったんですよ。14段のカウンターとか100円しないで購入できましたし。4000番台とか74シリーズを使っている時代は。

当時でも161とか使ってプリスケーラを組む場合は、それぞれの段の出力に意味が有るので、ここが同期していないと上手く行かない。RCOの出力にインバータを入れてLD端子に入れるとか、RCOをENT端子に入れてカスケードにするとかの場合ですね。

まあそう言った機能ICが有るから使い分けをしてきたんですが、FPGAやCPLDでは同期式で組んで置けよ!と言う事ですね。

by hamayan (2008-11-26 21:52) 

noritan

時計というと、商用電力から60Hzのパルスを作り出して、7490と7492で60分周して1Hzを作り、さらに7490と7492を駆使して、時分秒の各桁を作り、さらに7447でLEDに表示するという良くあるアプリケーションですね。

# ここで、50Hzと言うか60Hzと言うかで、生まれがわかります。

2の乗数に限らず、任意の分周比を作り出すためにカウンタの出力をデコードして非同期リセットに戻すという使い方が普通に行われていました。カウンタが確実にリセットされるまで非同期リセットが保持されることを保証するために、わざわざ伝達遅延の大きな素子を持ってきたりして。

今や、74XX90も74XX92も製造されていないみたいですね。

by noritan (2008-11-27 09:28) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。