私がVerilog HDLで躓いたところ
久しぶりの投稿₍₍ (ง ˘ω˘ )ว ⁾⁾
長らく書いていなかったので、反省しています。
書きたいことはいくつかあるんですが! 忙しくてなかなか筆が進みません (言い訳)
久しぶりのエントリですが、今回は Verilog HDL について扱っていきます。
学部実験「マイクロプロセッサの設計と実装」参考・旧サイト にて、
Verilogと戯れて つらかった 楽しかった思い出を振り返ろうと思います。
Verilogを書くときに、私が躓き、調べたことをまとめてみます。参考に慣れば幸いです。
※私のイメージが入っています。もしかしたら正しくないかも
躓いたところを一つずつ
思い出しつつ書いているので順番は適当です、許してください。
wireにはassignを、regにはinitial/always文を
// wire型 wire poyo; assign poyo = punipuni; // reg型 reg fuwa always @(posedge clk) begin fuwa <= howa; end
wire
型変数はワイヤ(導線)で、 assign
文で導線をつなげる、割り当てるってイメージでしょうか。
一方で reg
型変数はレジスタで、 always
文などで タイミングを指定して代入 していきます。そんなイメージです。
数字のあれこれ
5'b00011 // 2進5bit 32'hdeadbeaf // 16進32bit 8'd12345// 10進8bit
数字は次のような書式になっています
◯ ' ⬛XXXXX
ここで、
- ◯:ビット幅を表す
- ⬛:あとに続く数字の書式を表す b=2進数、h=16進数、d=10進数
たとえば、7bit幅で21を表したいときには、 7'b0010101
7'd21
7'h15
のようにかけると思います。
符合拡張、ゼロ拡張の仕方
input wire fuwa[7:0]; output wire poyo[31:0]; // 符合拡張 assign poyo = $signed({fuwa[7:0]}); // assign poyo = $signed(fuwa); でもきっと同じ // assign poyo = {24{fuwa[7]} , fuwa}; // ゼロ拡張 assign poyo = $signed({1'b0, fuwa[7:0]}); // assign poyo = $unsigned(fuwa); // assign poyo = {24'b0, fuwa};
$signed()
関数を使うと自動的に符合拡張してくれます。
最上位ビットを繰り返して {}
で結合してもいいんですが、繰り返し回数ミスしそうで怖いので私は使いませんでした。
ゼロ拡張は、{1'b0, fuwa}
みたいに上に0をつけて $signed()
関数を使うやり方を見ておおおーって使っていました。
よく考えたら $unsigned()
関数があるしそちらを使ったほうがいいかもしれない。
おそらく配線上ではどれも変わらないのでは?と思います。
moduleとポートと
wire poyoyo[31:0]; wire puwawa[7:0]; // モジュールの呼び出し fuwafuwa fuwa1( .poyo(poyoyo), .puwa(puwawa) ); // モジュールの記述 module fuwafuwa( input wire poyo[31:0], input wire puwa[7:0] ); // fuwafuwaの処理 endmodule
モジュールはVerilogで一つの大きな単位となっていて、他の言語で言うClassみたいなイメージで扱いました。
モジュールの呼び出しには
.port()
の部分は省略でき、その場合にはモジュールの宣言と同じ順序で引数が代入されるのですが、
間違える場合もあるので、少し面倒でも .poyo(poyoyo)
のようにポート名も書きました。
モジュールの記述はいくつかの書式があるのですが、 VSCodeでの折りたたむ機能で、入出力ポートだけは見たい! みたいな場合を想定して、 上のような記述にしていました。
if/case文はmodule内に書けない
module mod( input wire flag, input wire[31:0] poyoyo, output wire[31:0] poyo ); // だめな例 if (flag == 1'b1) begin assign poyo = poyoyo; end else begin assign poyo = 32'b0; end // いい例 assign poyo = fun(flag, poyoyo); function fun[31:0]; input flag; input [31:0] po[31:0]; if (flag == 1'b1) begin fun = po; end else begin fun = 32'b0; end endfunction endmodule
function
文や always
文内で if
/ case
文がかけます。
function
は戻り値をひとつだけ取ることができて、function名にイコールでつなぐことで返すことができます。
また、 if
文では else
を、 case
文では default
を必ず入れましょう。
入れないと例外的な入力が来たときにフリップフロップが生まれてしまうので、だめっぽいです
マクロ定数のような何か
// define文でマクロ定数宣言 `define ENABLE 1 // マクロ定数を用いる assign poyo = `ENABLE
`define
文でマクロを宣言します。用いるときにはバッククオートを忘れずにつけましょう。
参考にしたサイトなど
わからない〜ってなったときに度々お世話になったサイトさんを紹介させていただきます。
-
- 旧wiki 実装の手順とか参考になった
-
- 筑波大学の授業のサイトだと思う
http://research.kek.jp/people/uchida/educations/verilogHDL/index.html
- 技術教育をされているところらしい
http://www.icrus.org/machida/product/verilog.pdf
- 東京電機大学さんの文法書PDF
Amano Lab./Academic Programs/Computer System
- 慶応大学さんの授業のサイト、pdfがいっぱい
-
- ミスしがちなところをまとめてくれてます
基本的にVerilogは情報が少ない気がします。 ためになるホームページさんは文字化けするので……(Googleのキャッシュから読み込めば読める裏技あり)
つよつよのひとにまとめてほしいです。
おわりに
気が向いたら追記していこうと思いますが、ひとまず公開します。
これから実験をやっていく人は私の屍を超えていってください