Verilog超入門

\[ \newcommand{dn}[3]{\frac{\mathrm{d}^{#3} #1}{\mathrm{d} #2^{#3}}} \newcommand{\d}[2]{\frac{\mathrm{d} #1}{\mathrm{d} #2}} \newcommand{\dd}[2]{\frac{\mathrm{d}^2 #1}{\mathrm{d} {#2}^2}} \newcommand{\ddd}[2]{\frac{\mathrm{d}^3 #1}{\mathrm{d} {#2}^3}} \newcommand{\pdn}[3]{\frac{\partial^{#3} #1}{\partial {#2}^{#3}}} \newcommand{\pd}[2]{\frac{\partial #1}{\partial #2}} \newcommand{\pdd}[2]{\frac{\partial^2 #1}{\partial {#2}^2}} \newcommand{\pddd}[2]{\frac{\partial^3 #1}{\partial {#2}^3}} \newcommand{\p}{\partial} \newcommand{\D}[2]{\frac{\mathrm{D} #1}{\mathrm{D} #2}} \newcommand{\Re}{\mathrm{Re}} \newcommand{\Im}{\mathrm{Im}} \newcommand{\bra}[1]{\left\langle #1 \right|} \newcommand{\ket}[1]{\left|#1 \right\rangle} \newcommand{\braket}[2]{\left\langle #1 \middle|#2 \right\rangle} \newcommand{\inner}[2]{\left\langle #1 ,#2 \right\rangle} \newcommand{\l}{\left} \newcommand{\m}{\middle} \newcommand{\r}{\right} \newcommand{\f}[2]{\frac{#1}{#2}} \newcommand{\eps}{\varepsilon} \newcommand{\ra}{\rightarrow} \newcommand{\F}{\mathcal{F}} \newcommand{\L}{\mathcal{L}} \newcommand{\t}{\quad} \newcommand{\intinf}{\int_{-\infty}^{+\infty}} \newcommand{\R}{\mathcal{R}} \newcommand{\C}{\mathcal{C}} \newcommand{\Z}{\mathcal{Z}} \newcommand{\bm}[1]{\boldsymbol{#1}} \]

最近、Verilogに関する質問を受けることが多くなってきたので、まとめておきます。

Verilogは状態関係記述言語である

Verilogわからん!て聞いてくる大半の人が、基本的な勘違いをしています。

wire reg は変数

まず、Verilogは回路を記述する言語なので、変数というものはありません。 回路にあるのは部品と配線です。

reg がフリップフロップ wire が配線に対応する

これも嘘です。元々Verilogは回路を記述する言語で、この対応が存在しました。 しかし、実質的に論理回路を書くための言語として使われて続けた結果、この対応は形骸化しています。

このことを理解するには、論理回路を1段抽象化して、「状態の関係」を表したグラフとして見る必要があります。

回路と状態

これは、AとBをANDに入力し出力をCにつなぐという回路です。

-A-|
   AND-C-
-B-|

これをVerilogで書くと、こうなります。

module AND(
    input  wire A,
    input  wire B,
    output wire C
);
assign C = A & B;
endmodule

「Cの値は、AとBの値によって定まる」と読むことができます。

回路図 状態関係 Verilog
配線 状態変数 wire
論理ゲート 依存関係 assign

Verilogでは、論理回路を状態の依存関係として記述しています。

reg は何か

上の回路を、Verilogではこのように書くこともできます。

module AND(
    input  wire A,
    input  wire B,
    output reg  C
);
always @(*) begin
    C <= A & B;
end
endmodule

これを、愚直に回路図に書いてみると、こうなります。

-A-----|
   |   AND-[C]-
-B-----|    ^
 | |        |
 | +--------|
 +----------|     

AとBのANDがCのレジスタの入力に、AとBがレジスタのクロック入力に入っています。

回路図 状態関係 Verilog
配線/フリップフロップ 状態変数 wire/reg
論理ゲート 依存関係 assign

「状態変数の依存関係が変わらない」

wire と reg に 本質的な違いはない! ←結論

コンパイラが賢いので、無駄なレジスタは取り除いてくれます。

実際、 System Verilog では、wireとregをまとめて「logic」とすることができます。 System Verilog を使える環境ではそっちを使ったほうが楽です。

FPGAのしくみ

FPGAがなぜ任意の論理回路に姿を変えることができるのか

組合回路

ROMは任意の組み合わせ回路になることができます。

例えば、2入力1出力の4bitのROMは、任意の2入力の組み合わせ回路になります。

アドレス
0b00 0
0b01 1
0b10 1
0b11 1

0,1,1,1,1を書き込めば、ORゲートになりますし、0,0,0,1を書き込めば、ANDゲートになります。

FPGAはROMを使って書き換え可能な組み込み回路を実現しています。

順序回路

順序回路は、オートマトンで表現できます。

FPGAの構造

FPGAには、ROM と DFF が大量にあります。

VerilogをFPGAに書き込むまで

FPGAの正体は、大量のロジックブロックと、それらを接続する大量のスイッチでした。

FPGAに書き込むデータは、

  1. LUTに書き込む値
  2. スイッチのON/OFF

を、バイナリ化したものになります。

Synthesis

ネットリストを出力します。

大きな真理値表を分割し、複数の 4 入力真理値表に組みなおします。

Place & Route

FPGAのどのLUTにどの組み合わせ回路を割り当てるか、どのFFにどの状態変数を割り当てるか、を設定します。

Package

ビットストリームを作ります。

関数とオートマトン

数学の関数は、入力に対して出力が一意に定まります。 一方、コンピュータにおける関数は、オートマトンです。 これを端的に表現したのが状態遷移図です。 内部状態の違いによって、同じ入力でも違う出力を返します。

FPGAを使う上での注意

コンフィグレーション

いままで、FPGAの中には大量のROMが入ってと言いましたが、本当は違います。SRAMです。電源を切ると消えます。

なので、FPGAの隣には不揮発なROMがあり、ここにFPGAのビットストリームが格納されています。 電源を入れたら、ROMのデータをFPGA内部のSRAMに送り、FPGA内部のスイッチ切り替えたり、LUTの値を書き換えたりします。 これをコンフィグレーションといいます。

ビットストリームというのは、FPGAの内部SRAMが数珠つなぎにクソ長シフトレジスタになっていて、そこにデータを流し込むってイメージです。

自分でFPGAを使って回路を組む場合には、コンフィグレーションに注意する必要があります。リセットって難しい。

FPGAのIO

FPGAも通常のLSIと同じように、IOバッファがあります。

System Verilog

System Verilog (Verilog2005) は、Verilog の進化版です。 ちょうどC言語に対するC++のようなイメージです。

古いIDEだとサポートされてなかったり…

完全に規格に準拠した実装はあまりないですが…

logic

上で述べた通り、wireとregには本質的な違いはありません。 System Verilog ではこれらの違いを考えずに logic と書けます。

always_comb

Verilog では、if else による真理値表の記述は、always中に限られているという制約がありましたが、 SystemVerilog では wire でも if else を使えます。

interface

上2つはVerilogの 失敗を修正しただけ 開発当初の思想と現代の使われ方の違いによる矛盾を解消するものですが、 interface はハードウェアの抽象化に重要な機能です。

interface の中にロジックを記述することができ、特にバスを作るときに便利です。