火曜日, 4月 13, 2010

Constant Function

by Jorge Franganillo
Verilog2001からconstant functionというものがサポートされています。
使い用によっては便利だなと思いつつ、使わなくてもなんとかなるものなのであまり気にしていませんでしたが、使いたくなったときに調べるのが面倒なのでメモしときます。

まずどういうときに使うのかというと、使いたい時というのは多分限られていて例えばFIFOなどのパラメータ化を考えたとき、昔のVerilog HDLではパラメータとしてデータのビット幅とFIFOの深さそれとFIFOのポインタのビット幅をという3つのパラメータを指定する必要がありました。

この中でFIFOのポインタのビット幅というのはFIFOの深さから導けるのですが、単純な四則演算などで計算することが出来ず、for文などを使う必要があるため別途パラメータとして渡してあげなければならなかったわけです。
例えば次のような感じです。
module my_fifo (clk, rst_n, we, re, wdt, rdt, full, empty);

  parameter DT_WIDTH = 8;
  parameter FIFO_DEPTH = 16;
  parameter PTR_WIDTH = 4;

  input clk, rst_n, we, re;
  input [DT_WIDTH-1:0] wdt;
  output [DT_WIDTH-1:0] rdt; 
  output full, empty;

  reg [DT_WIDTH-1:0] ram [0:FIFO_DEPTH-1];
  reg [PTR_WIDTH-1:0] wr_ptr;
  reg [PTR_WIDTH-1:0] rd_ptr;

  ...;

endmodule
それがVerilog2001からは演算結果が定数となる場合であれば、parameterの右辺にfunctionを使えるようになったため以下のように書けるので、パラメータの受け渡しの際にFIFO_DEPTHとPTR_WIDTHの間で不整合が起こるような危険を回避できます。
module my_fifo (clk, rst_n, we, re, wdt, rdt, full, empty);

  parameter DT_WIDTH = 8;
  parameter FIFO_DEPTH = 16;
  localparam PTR_WIDTH = log2(FIFO_DEPTH);

  input clk, rst_n, we, re;
  input [DT_WIDTH-1:0] wdt;
  output [DT_WIDTH-1:0] rdt; 
  output full, empty;

  reg [DT_WIDTH-1:0] ram [0:FIFO_DEPTH-1];
  reg [PTR_WIDTH-1:0] wr_ptr;
  reg [PTR_WIDTH-1:0] rd_ptr;

  ...;

endmodule
ここでlog2()は2を底とする入力の対数を計算するfunctionとします。

で、この2を底とする入力の対数を求めるfunctionなんですがConstant Functionの例では必ずと行っていいほどこの例になっています。しかし、なかには間違えているコードもあるようなのでご注意ください。
例えばこちらの"3.0 LRM Errors"ではIEEE Verilog-2001 Standardで紹介されている次のコードに誤りがあると指摘しています。
//define the clogb2 function 
function integer clogb2; 
  input depth; 
  integer i,result; 
  begin 
    for (i = 0; 2 ** i < depth; i = i + 1) 
      result = i + 1; 
    clogb2 = result; 
  end 
endfunction
どこが悪いのかわかりますか?

1つは入力のdepthが1ビットとなっていること。

そしてもうひとつはdepthが1だった場合にforループが実行されず、resultが初期化されないためにこのfunctionが不定値を返してしまうことです。

そこでこのfunctionは次のように置き換えるべきだと書いてあるのですが。。。
function integer clogb2; 
  input [31:0] value; 
  for (clogb2=0; value>0; clogb2=clogb2+1) 
    value = value>>1; 
endfunction 
これはこれで問題がある気がします。

入力が2の定数である場合、結果が正しくないですよね?
例えば入力value=2の時、1を返すのが正しい結果のはずですがforループが2回実行されるので結果2を返してしまいます。

こちらで紹介されている例のほうが良いでしょう。
function integer log2;
  input integer value;
  begin
    value = value-1;
    for (log2=0; value>0; log2=log2+1)
      value = value>>1;
  end
endfunction
入力が0だと問題ですが、対数を求める関数なのでもともと入力は1以上であるはずです。

使う機会はそれほど多くないかもしれませんが覚えておいて損はないでしょう。

0 件のコメント: