火曜日, 7月 24, 2007

組み合わせ回路

verilogで組み合わせ回路を記述する場合、alwaysかfunctionを使うことになると思います。

alwaysを使うとこんな感じでしょうか。


always @* begin: ReadDataMux
case(address)
ADDR_REG_A: readData = regA;
ADDR_REG_B: readData = regB;
ADDR_REG_C: readData = regC;
ADDR_REG_D: readData = regD;
default : readData = 0;
endcase
end


functionを使うならばこんな感じ。


function [7:0] BarrelShift (
input [7:0] dataIn,
input [2:0] shift
);
reg [15:0] rtData;
begin
rtData = {dataIn, dataIn} << shift;
BarrelShif = rtData[15:8];
end
endfunction

ともにVerilog2001を対象に書いています。

alwaysは"@*"が使えるので入力の種類が多いときなどに便利です。
短所は出力をregで宣伝しなければならないこと。

レジスタにならないものをregで宣言しなければならないことは
初心者を十分混乱させてくれます。

また、当初は簡単な組み合わせ回路だからとおもって

assign control = (signal==RED) ? STOP : GO;

と書いていたら、やっぱり安全第一ということで


always @* begin: DriveControl
case(signal)
RED : control = STOP;
YELLOW : control = ATTENTION; // STOP is better.
BLUE : control = GO;
default: control = STOP;
endcase
end


このように変更した場合に、
わざわざcontrolの宣言をwireからregに変えなければならないというのも面倒です。

functionの場合は、function内のみのスコープをもつ変数を使えるところが利点です。
Cでプログラムを書く人などはこちらのスタイルの方が好みかもしれません。

注意点は、ポートリストに入っていなくても同一モジュール内の信号を参照できてしまうことです。
この場合、シミュレーション時にラッチを生成しているような動作をしてしまい、検証の際に非常に痛い目に会うかもしれません。

例えば次のような場合、


function [7:0] FuncOut (input a, input b);
begin
FuncOut = a & b & c; // cはfunction外で宣言
end
endfunction


シミュレーションでは、
入力a,bに変化があった場合は出力も変化しますが
cが変化した時点では出力は変化しません。

両方使い分けれるようになれば、verilog初心者は卒業かな?
それだけで判断できるようことでもないですが。

しかし、verilogはいまだに中途半端な仕様です。

0 件のコメント: