2012年7月1日日曜日

固定小数点演算信号処理の極意シリーズ (その5) verilog記述法

その4にひきつづきまして、今回はverilogについてすこし説明します.わたしはVHDLを知らないのでverilogだけしか使えません.以下、全然体系的ではありませんが、ダーッと説明します.

●C言語に似たverilogですが、intはあるけどfloatとかdoubleはありません.代わりに、レジスタを宣言するregと、配線の宣言をするwireがあり、regとwireを区別して宣言しなくてはいけません.

reg   a;
1bitのフリップフロップを設けてその出力にaと名付ける.reg宣言した時点では、clockとかresetについてはまだ何も言及していません.
reg   [3:0]  abc;
4bitのフリップフロップを設けてその出力にabcと名付ける.変数を使うときはabcと略記するとabc[3:0]の4bitバスを意味します.律儀にabc[3:0]と表記してもOKです.バスの1本1本を表現したいときはabc[2]のように表記します.abc[1:0]のように一部でもOKです.
wire [4:0] sum;
フリップフロップではなく、ゲート回路(組み合わせ回路ともいう)の出力にsumと名付ける.wire宣言した時点では「なにかの回路」がなんなのかにはまだ何も言及してません.

●regやwireを宣言した後には、a,abc,sumをつかって「なにかの回路」を言及できるようになります.それにはassignを使います.
assign sum = a + abc;
     または
wire [4:0] sum = a + abc;
これらは式を読んでそのまんま加算の意味です.assignというのが面食らいますが、配線をつなぐ意味があります.後者はwire宣言と同時に配線をつないでいるのでassignを省略できてます.
ここまでの記述で、下図のように、フリップフロップ出力を加算したsumという値を得ることができています.
しかし、これではまだ動く回路とは言えません.clockを配線してないし、出力をフリップフロップでバッファしてないので不完全です.

●下図のような完全な回路にするにはフリップフロップの実体を記述しなくてはいけません.フリップフロップの実体とは、clock,reset,入力,出力です.
まずフリップフロップaの実体を記述します.
wire ain;
always @(posedge clock or negedge reset)
if(!reset) a<=0;
else a<=ain;
フリップフロップにはverilog特有の記述がいろいろあります.
posedge clockは、clockの立ち上がりエッジで動作させる意味です.
negedge resetは、resetがLOW activeである意味です.
if(!reset) a<=0;は、resetがLOWならaをゼロにする意味です.
a<=ain;は、clockの立ち上がりでainをラッチしてaに出力する意味です.
if文は上の行が高プライオリティですので、resetが高優先度です.
<=はreg宣言した変数に代入する時のおきまりの表記です.=だとエラーになります.
reg宣言した変数にはalways文の中でしか代入できません.
要するにこれは、reset付きのDフリップフロップです.

次にフリップフロップabcの実体を記述します.
wire [3:0] abcin;
always @(posedge clock or negedge reset)
if(!reset) abc<=0;
else abc<=abcin;

最後にフリップフロップsumoutの実体を記述します.
reg [4:0] sumout;
always @(posedge clock or negedge reset)
if(!reset) sumout<=0;
else sumout<=sum;

●最後にサブルーチンみたいなmoduleという単位に閉じ込めます.
module adder (
  input clock,
  input reset,
  input ain,
  input [3:0] abcin, 
  output [4:0] sumout
);
   上記の全てのcodeをここに転記する.......
endmodule
こうしたことで、adderという名前のmoduleをいくつでも呼び出して使うことができます.

●上記でフリップフロップでバッファされた演算回路の完全な記述をひとまず解説しました.つぎは、verilogならではの小技を解説します.

4bitバスを2つ連結して8bitバスにする
wire [3:0]  P, Q;       このように連続して宣言もできます.
wire [7:0]  R = {P,Q};      
こまかく書くとこういうこと→R={P[3],P[2],P[1],P[0],Q[3],Q[2],Q[1],Q[0]};

論理反転する
wire [7:0]  POS;
wire [7:0]  NEG = ~POS;         POSが11001010ならNEGは00110101になります.

MSBだけ反転する
wire [7:0]  MSBREV = {~POS[7],POS[6:0]};

引き算
wire [8:0] sub = POS - NEG;

かけ算
wire [15:0] mul = POS * NEG;

割り算
source codeに/演算子を記述することはできますが、論理合成してくれないのでhardware化できません.なのでverilogでhardwareを記述するときには/演算子は使いません.ただし、純粋softwareであるテストベンチを記述するには/演算子を使えるので使います.注意しましょう.

8bitシフトレジスタ
wire in;
reg [7:0] shift;
always @(posedge clk or negedge xrst)
if(!xrst) shift<=0;
else shift <= {shift[6:0],in};       LSBからMSBへ向けてshiftする

レジスタのenable動作
wire en;
wire [31:0] in;
reg [31:0] out;
always @(posedge CLOCK or negedge RESET)
if(!RESET) out<=0;
else if(en) out<=in;       en=1の時だけinをラッチする、それ以外はダンマリ.

これでverilogがバシバシ使えるかというと、そうではありませんけど、これくらいを理解すれば、次のステップの解説へ進むことができると思います.

つぎへ           前へ

人気ブログランキングへ

2 件のコメント:

  1. verilogなどのソース記述する人の頭の中は、
    スケマティック(回路図)が浮かんでいるのでしょうか。
    それとも、ずばりソースで考えているのでしょうか?

    返信削除
  2. ナイスな質問です.
    わたしは1993年に初めてverilogを触りました.それまではgate使いでした.たぶん、gate使いだった最後の世代じゃないかと思います.
    そのわたしですら、schematicを思い浮かべてverilogを吐くことはしません.頭の中で浮かべるのはデータフローです.データフローをverilogとして吐き出します.
    なので、schematicからの派生としてverilogを位置づけた上記の解説は、どんだけ有意味なのかあまり自信がないのです.

    返信削除