FPGA を使った時計の製作実習中のことです。

インテル® Quartus® Prime 開発ソフトウェア を使って秒・分・時のカウンターの記述をおこなっていました。
秒一桁のカウンター ( 0 ~ 9 ) はクロックのイネーブル信号でカウントアップさせれば良かったので割とうまくできましたが、

秒二桁への桁上り ( 09 → 10 ) がうまくできませんでした。その時の私のデザインがこちらです。

クロックの立ち上がりで 秒一桁が 9 を過ぎても秒二桁目がカウントアップしている様子が確認できませんでした。

そこで、クロックイネーブルの信号を無視して秒一桁が 9 の次に秒二桁がカウントアップするような回路を作成し、実機で確認したところ

秒一桁が 8 のときに秒二桁が 1 をカウントしまったのです。

その時のシミュレーション画像がこちらです。

ということは、

秒一桁が 10 をカウントする次に秒二桁がカウントアップすればいいのでは?とよからぬことを考えて回路を書き換えたところ、

無事 桁上りの表示が実機で確認できました。

しかし、秒二桁から分一桁への桁上りがなかなかできなかったので先輩にデザインを見てもらうと、 if 文が全然理解できていないね。と一言。

Quartus® II 開発ソフトウェア ではエラーは出てないし、どこが悪いんだろう・・・

先輩によると if 文では上から順に条件文の真偽を確かめているということでした。

それに基づいて先ほどのデザインの和訳をしてみます。

自分で何を書いていて、なにをさせたいのかわからなくなってしまいました。

最後の二行は必要ないですもんね。

Quartus® II 開発ソフトウェア も混乱させてしまったのか非常に時間がかかりました。。。ごめん Quartus® II。

 

2つ目の else if の記述を見ていただけると分かると思いますが、

この記述では、 qa が 4'b1001 (9) の “clk の立ち上がりエッジ” でデータを取り、 qa をゼロにする という記述をおこなっていたのです。

クロックの 1MHz が High になった瞬間だけ 9 になっていましたが、人間の目ではとても認識できるものではありませんよね。

 

上記の記述だと条件分岐が行ったり来たりしていたことがわかりました。

clk と clr_n 以外に条件となる信号は、 clk_en でした。clk_en は 1MHz のクロックをもとに生成した 1s 周期の信号です。

1s の clk_en をトリガーとしてカウントアップをさせたかっただけなのです。条件式の優先順位が明確になっていないと記述できないですね。

改善したカウンターの記述がこちらです。

 

always@(posedge clk)
begin
  if (clr_n == 1'b0)
   qa <= 4'b0000;//d'0


  else if (clk_en == 1'b1)
   if(qa == 4'b1001)//d'9
    qa <= 4'b0000;


  else
    qa <= qa + 4'b0001;


  else
    qa <= qa;
end

 

if 文を使用する際は各信号に優先順位をつけるようにし、優先順位の高いものから条件文を書くように心がけることが必要でした。

ネスティング (入れ子) しすぎると条件が複雑化し、設計者が意図しない冗長な論理が構成されることがあり、

FPGA のロジック・エレメント (LE) を大幅に消費してしまうことがわかりました。

 

例として、前回のネスティングしすぎた誤ったカウンターで時計のデザインを作成したところ、およそ 700LE を消費していました。

これが、記述をし直したことで およそ 40LE の消費で済みました。

FPGA を有効に使うためにも簡潔で最適な記述が必要なようです。

ツールでも最適化が行われますが、限界があります。

ツールの機能を最大限有効に使用するには、デザイン記述が重要であることを認識しました。