目次
概要
- ハードウェア記述言語
- 記述に際しても「ハードウェアを設計している」意識が大切(逐次的でないことがある)
- シミュレーションとテストが重要。
参考
- 超入門ページ
- おすすめ参考書まとめ(上から読んでいくとよい)
文法
テンプレ
// moduleのポートを設定(PORTはバスでもシグナルでもよい)
module MODULE_NAME (
PORT1, // in, desc.
PORT2, // in, desc.
PORT3 // out, desc.
);
// in / outの設定。ここでバスを明示しなければならない
input selector1;
input A;
input B
output [5:0] data;
output [5:0] data_initiated = 6'd0;
// output(wire)とフリップフロップ(reg)の定義。バスを明示しなければならない。
wire [5:0] output; // 本当は書かなくてもいい。outputがregの場合だけ記述しなければならない。
reg Q;
reg [7:0] COUNTER;
[expression]
endmodule
expression
NET
- 一つの回路のこと
- assign: 配線を接続し、NETを作成する。
- always: センシティビリティリストにトリガーされる記述、NETを作成する
代入
- ブロッキング代入「=」とノンブロッキング代入「<=」の二通りの代入演算子が存在
assgin O = I1 & I2; // assign文の後で
Q <= D; // always文の中で
- 動作の差
初期値を X が 1, A が 5, B が 0 とする。
ノンブロッキング代入
X <= A;
B <= X;
X が 5, A が 5, B が 1 となる。
ブロッキング代入
X = A;
B = X;
X が 5, A が 5, B が 5 となる。
以下の手続き代入文では、A = B の後に B = A が実行されるために、A と B はともに B の値として最終的に同一値を持ちます。ノンブロッキング手続き代入文では、右辺の値が確定してから左辺への代入が実行されるために、AとB の値はスワップします。
reg A, B;
always @(posedge CLK) begin
A = B; // ブロッキング代入
B = A;
end
always @(posedge CLK) begin
A <= B; // ノンブロッキング代入
B <= A;
end
数値
3'b10 // 3bit 3 (3bit定数:2進数で3)
4'o10 // 4bit 8 (4bit定数:8進数で8)
8'h80 // 8bit 128 (8bit定数:16進数で80)
8'd128 // 8bit 128 (8bit定数:10進数で128)
8'bZ // ハイインピーダンス
8'bX // 不定
always
- sensitivity listを常に監視し、満たされたらexpressionを実行する
- すべての always 内の文は同時処理であるため記述の順番による処理の時間差はない
always @([sensitivity list]) begin
[expression]
end
- conditionには立ち上がりエッジや立下りエッジ、値の変化そのものが入ることがおおい
// 立ち上がり
always@ (posedge CLK) begin
Q <= D;
end
// 立ち下がり
always@ (negedge CLK) begin
Q <= D;
end
// CLKの変化
always@ (CLK) begin
Q <= D;
end
if
if ([condition1]) begin
[expression1]
end else begin
[expression2]
end
シグナルのバス化
Q{3:0} <= {Q{2:0}, D};
assign
- wireの代入に使う(regの代入には<=)
assign O[7:0] = A[7:0] + 8'd1;
モジュールの接続
//以下二つは一つの記述の中では混用不可
fulladd add0(a[0], b[0], 1'b0, q[0], cout[0]);
fulladd add0(.A(a[0]), .B(b[0]), .CIN(1'b0), .Q(q[0]), .COUT(cout[0])); // Recommended
トラブルシューティング
Anonymous ports
- port設定の引数の最後にカンマが付いていると起きる。
Multi-source in Unit
- 別のalways文の右辺に同じものがあるから?なんで起きるのか理解できていない。
コーディングルール
あと、これは、好みだと思いますが ・モジュールのI/O は大文字、内部reg, wire宣言は小文字 とするとソースが見やすくなると思います (キー入力が楽になりますよ、たぶん) ・内部reg, wire宣言は以下のルールを適用する wire xxxx_sig ; /* 後ろに"_sig"を付ける / reg xxxx_reg ; / 後ろに"_reg"を付ける / ex) wire SPI_DATA_READY; // SPIモジュールデータ受信完了 ↓ wire spi_data_ready_sig ; / SPIモジュールデータ受信完了 */
シミュレーション
- Simulatorが備付で存在する。
- Veritakとかいう有料のものもある
CQ Endeavor本
- ネットリスト
- 配線のこと。
- 設計手順
- 基本設計(ブロック図、入出力信号表などを出力する)
- テストベンチ
- テスト用のverilog
- verilogのエラー
- 文法ミス
- 文法上問題ないが、論理剛性不能なもの
- 設計手順
- RTL(Register Transfer Level):代入、if, case, 論理剛性可能な記述、クロックを意識した記述
- ゲートレベル:ゲート回路やフリップフロップなどの接続関係を示したもの(ネットリスト)
- always
- wireへの代入はalways文では文法エラー
- regへの代入は<=
- シミュレーション記述の場合に限り、逆に=のほうがよい
- 信号の型
- wire:ブロックとブロックをつなぐ配線(シミュレーションではtri, wand, triorも使う)
- reg:レジスタ(シミュレーションではintegerも使う)
- 使い分け
- 入力はネット
- 出力はネットかレジスタ
- 入出力はネット
- assign(継続的代入)
- NAND, セレクタ、桁上がり、加算回路などに利用
// 以下は同じ
wire [7:0] dout; assign dout = (sel==1'b1) ? d1 : d0;
wire [7:0] dout = (sel==1'b1) ? d1 : d0;
-
begin-endブロック
- alwaysのbegin-endでは、逐次処理される
-
if, case文の前後はbegin-endで囲むこと(?)
-
モジュールの出力にレジスタ信号をつなげることはできない(「レジスタ信号」というのは、記録されているメモリの線だから、つなげても意味がない。)
-
busが全部を差すなら、添え字はいらない。省略可能。
-
if, case文は、always文、function文の中でしか使えない
-
文法的分類
- ステートメント(always, function, assign)
- module直下に記述するもの。
- モジュールアイテム (if, case, for, while)
- ステートメントの中に記述するもの。 module直下に記述すると文法エラー
- ステートメント(always, function, assign)
-
回路設計:4つの基本スタイル
- assign(1行で記述する単純な組み合わせ回路)
- 2入力論理回路、桁上がり信号、セレクタ、加算回路
- function, always(複数行で記述する複雑な組み合わせ回路)
- 条件分岐を含む複雑な回路(always, functionは同等な回路が実装可能)
- always(ラッチやフリップフロップを含む順序回路)
- 下位モジュール接続
- 名前による接続であれば、引数の順番は入れ替え可能
- assign(1行で記述する単純な組み合わせ回路)
-
論理合成不能によるエラー
- 一つのフリップフロップは一つのalways文によって記述しなければならない(ノンブロッキング代入の左辺にQが出るとして、そんなalways文は2つ書いてはいけない)
- 非同期リセットの条件分岐はifで書かなければならない
パターン
セレクタ
// selector
wire selector1;
reg [5:0] data = 6'd0;
reg [11:0] latch = 12'd0;
always@ (latch or selector1) begin
if (selector1 == 1'd1)
data[5:0] <= latch[11:6];
else
data[5:0] <= latch[5:0];
end
// こっちでも動くらしいが、動作が確認できない。謎。
// selector
wire selector1;
wire [5:0] data = 6'd0;
reg [11:0] latch = 12'd0;
assign data = (selector1 == 1'b1) ? latch[11:6] : latch[5:0];
ラッチ
// latch
reg [11:0] latch;
reg [11:0] counter;
always@ (posedge request) begin
latch[11:0] <= counter[11:0];
end
同期回路
非同期信号の同期化
- とても参考になるページ
- http://members3.jcom.home.ne.jp/zakii/digital/13_2ff_sync.htm
- 非同期信号はオーバーサンプリングして同期化することができる.
- 非同期信号は多重FFをかませないと,メタステーブル化して回路が不安定になる.