FFのリセット

[] [] []


FFのリセットは負論理の非同期リセットを使うのが一般的だが、FPGAファミリやブロックによっては必ずしもそうなっていない。

FF

ブロックの図

Altera

Xilinx

LogicブロックのFF

(*1)

非同期リセット(*2)

/負論理

リセット値0/1

非同期/同期リセット

正論理(*3)

リセット値0/1

IOブロックのFF

DSPブロックのFF

非同期リセット

/負論理

リセット値0

同期リセット

正論理(*3)

リセット値0

RAMブロックのFF

(*1)LogicブロックのFFLAB,Slice単位でリセットラインを共有している

 Altera Cyclone3,4の場合:LAB=16xLE, LE=(LUT+FF)

     Cyclone5,Stratix3,4,5の場合:LAB=10xALM, ALM=2x(LUT+ADD+FF)

 Xilinx Spartan3の場合:Slice=2x(LUT+FF)

     Spartan6,Virtex5,6,7seriesの場合:Slice=4x(LUT+2xFF)

(*2)同期リセットはLUTを使ってD入力とANDをとる回路に合成される。

(*3)Spartan3,Virtex5FFのリセット端子は負論理にも切り替え可。

 Virtex6,7seriseの場合は、負論理はLogicブロックのLUTでリセットを反転した回路に合成される。

 

そこで、どのFPGAファミリでも使えるRTL記述するには次のようにするとよい

(1) 原則、FFは正論理の非同期リセットにする

これはXilinxが正論理になっており、Alteraは正負どちらでもよいので、Xilinxの方に合わせればよいということである。

もっとも既存のRTL記述を負論理から正論理に書きなおすのは大変なので、書きなおし量とのトレードオフになる。

右の記述でも同じ合成結果になるかもしれないが、左のように明示的に記述した方がよい。

// 正論理の非同期リセット

always @(posedge clk or posedge rst)

  begin

  if(rst)

      d_reg <= 8'd0;

  else

      ...

  end

×

// FFは負論理の非同期リセットのままリセット供給元で反転

assign rst_n = ~rst;

...

always @(posedge clk or negedge rst_n)

  begin

  if(~rst_n)

      d_reg <= 8'd0;

  else

      ...

  end

 

(2) ただし、DSPブロックのFFRAMブロックの出力FFにはリセットを付けない

これはAlteraは非同期リセットでXilinxは同期リセットと排反しているので、どちらでも使えるようにするには、リセットなしにするしかないためである。リセットを付けなくて問題ないか気になるが、

RAMの出力FFはリセット解除したらすぐRAMの出力値に変わってしまうので、リセットを付けても付けなくても大差ない。

DSPFFは前段のリセット値が伝搬するように、リセット期間を数クロック確保すれば問題ないが、シミュレーション上はFFの初期値が不定値xになるので、不定値のフィードバックループは作らないように注意した方がよい。

// 乗算器,FFにリセットは付いてない

always @(posedge clk)

  begin

  a_reg <= ain;

  b_reg <= bin;

  p_reg <= a_reg * b_reg;

  end

assign ain = p_reg + cin;

のような不定値のフィードバックループを作らないように注意

×

// 乗算器,FFに非同期リセットがついている

always @(posedge clk or posedge rst)

  begin

  if(rst)

    begin

    a_reg <= 16'd0;

    b_reg <= 16'd0;

    p_reg <= 32'd0;

  end

  else

    begin

    a_reg <= ain;

    b_reg <= bin;

    p_reg <= a_reg * b_reg;

    end

  end

 

// RAM,出力FFにリセットは付いてない

always @(posedge clk)

  begin

  if(we) ram[addr] <= din;      // write port

  dout <= ram[addr];            // read port

  dout_reg <= dout;             // 出力FF

  end

×

// RAM, 出力FFに非同期リセットがついている

always @(posedge clk)

  begin

  if(we) ram[addr] <= din;      // write port

  dout <= ram[addr];            // read port

  end

always @(posedge clk or posedge rst)

  begin

  if(rst)

    dout_reg <= 16'd0;

  else

    dout_reg <= dout;           // 出力FF

  end


[] [] []