SANMAN

思いつきの考えを垂れ流すブログ

VerilogなどのRTLで回路設計するときのポイントについて

以前書いたエントリのRTLコーディング能力を身につける上でのポイントについて書く。Markdown以前の記事で不具合目についたのでちょっと修正した。

VHDLとか他のRTLでも基本は同じだが、Verilogで。 SystemVerilogでもVerilog使えるし。

初心者が設計するときに知っておいたほうが良いのは

  • いわゆるプログラミング言語ではなく、回路記述言語
  • シミュレーション用記述(テストベンチ)はプログラミング
  • いろいろな予約後があるが、回路はalways文とassign文の2つが主
  • regは必ずしも回路としてのレジスタになるわけではない
  • RTLというレベル
  • データの帯域計算
    といった所。

Verilogプログラミング言語ではない?

Verilogは回路記述と、その回路動作のシミュレーションのために使うことが出来る言語。
回路記述においては、いわゆるCなどで行うプログラミングとは異なるが、シミュレーションの動作記述はCとかと同じプログラミング。 RTLでおかしなクソ回路を作ってしまう場合は、回路の挙動を考慮した回路記述ではなく、機能や処理のみ注目しすぎたプログラミング的設計をしてしまっていることが良くある。
プログラミング的な設計は論理としては正しく、(論理)シミュレーションでも正しい結果を出すが、現実の回路では動作しなかったり、動作周波数がめちゃくちゃ下がる。 それかコンパイラが頑張って解析してくれるか。

同じ言語で2つのことをしてしまうため、ややこしい。 とりあえず回路を書いていると意識しよう。

回路記述でつかうのはalways文とassign文で済む

if文、case文とかも普通に使うけれども、Verilogらしい特殊な文だとこの2つ。 他にもfunction文やcasex文などいろいろな書き方が提供されているが、回路を作る上ではalways文かassign文を使い、if文やcase文での条件分岐させるだけでだいたい何でも作れる。case文で実現される機能はif文でも書けるけど、見やすさのためにcase文を使う感じだと思っておけば良い。本当は各条件の優先順位の有無とかで適用のさせ方が違うんだけど、そういうのは慣れてから。

だいたい以下の様な記述に終始する。

// 回路モジュール名sample_moduleのIO定義
module sample_module(
input wire clk, 
input wire rst_n,
input wire enable,
output wire [2:0] data_out // 入出力方向  データ型  [最上位ビット:最下位ビット] ポート名
);

// カウンターのためのreg
reg [3:0] sample_reg;

// 4bitカウンター
always@(posedge clk or negedge rst_n) // clkの立ち上がり or rst_nの立ち下がりで動作する。非同期リセット。
    if(!rst_n)
        sample_reg <= 4'b0000; // rst_nが0なら4bit全て0にリセットする
    else if( enable )
        sample_reg <= sample_reg + 4'd1; // enableが1なら1ずつカウントアップする
    else
        sample_reg <= sample_reg; // それ以外(上2つの条件でない)では値を保持する


assign data_out = sample_reg[0] ? sample_reg[3:1] : sample_reg[2:0]; // sample_reg[0]が1なら最下位ビットを切り捨てて出力する。それ以外は最上位ビットを切り捨てる。

endmodule // モジュール内動作記述の終了を示す

moduleとか出てきてるけれど、当たり前の定義をする記述なので慣れたら特に意識することはない。 機能を実装するのはalwaysかassignを使い、if文かcase文で条件分岐させるだけ。

for文などはコピペ的な作業が楽になるもので、繰り返し処理する回路を作るものではない。合成できる記述とそうでないものの区別は結構難しいようだ。ソフトウェアの考えがこびりついてて、理解に苦しむかも。

regに注意

regはレジスタ。すなわち回路でいうとFF(Flip-Flop)になると思ってしまうが、そうではない。
regはalways文中で使う変数(のタイプ)であり、複雑な組み合わせ回路の記述にも使える。 書き方で順序回路なのか組み合わせなのかを判断しなければならない。

このregとalwaysの取り扱いのややこしさを解決するため、SystemVerilogではlogicやalways_combが導入された。

RTLというレベル

Register Transfer Level(レジスタ転送レベル)の事で、回路設計時の抽象度のこと。 Verilogなどはこの抽象レベルでの設計に使えるHDL(Hardware Description Language:ハードウェア記述言語)と呼ぶ。

RTLでの設計はレジスタ回路(FF)と組み合わせ論理回路の2つをたくさん使う。

FF→組み合わせ論理→FF

このパターンがたくさん。

FF→組み合わせ論理→FF→組み合わせ論理→FF→組み合わせ論理→FF→組み合わせ論理→FF.....

FFは1bitの情報を保持できるレジスタ
組み合わせ論理はANDとかOR、条件分岐や、足し算など。

always文で実現される。

データの帯域計算

480Mbpsとかで表される、処理できる・しなければならないデータの量について意識する必要がある。 この帯域計算(データレートの計算)ができなければ仕様の検討ができない。

帯域計算のやり方・考え方については今度別エントリで書くつもりだが、いくつかポイントとしては

  • 実際に使えるデータの転送帯域は規格上の値と違う事がある 例えば、1Gbpsの転送ができるインターフェースがあるが、実際はその30%は通信の確立に必要なデータに消費され、70%しか任意に使えない。など。 最近の高速なインターフェースではよくあるので、規格上5Gbpsの転送が可能とか書いてあるのを鵜呑みにしてはいけない。

  • bpsBpsなどの単位に注意 bps=bit per seconds Bps=byte per seconds 480Mbpsや3MB/s などbitとbyteで使い分けることがよくあるので注意して見る。 またbitとbyte以外にもTransferを単位としたMT/sなどもある。

がある。 わかってしまえばただの算数です。

おわりに

最近書いてないので無理やり書いた。 はてなブログverilogソースコード対応してるのね。SystemVerilogはダメっぽいけど。