遅延の移動とは
- 同期設計において論理深度の偏りは、いくつかのボトルネックを発生させます。突出した1つのボトルネックだけでFFのSetup時間が大きくなり、不幸にも最大動作周波数を押し下げることが多々あります。
- ここでは、全体の遅延バランスを考えた設計[1]がある程度できており、論理合成によりボトルネックが把握できているものとします。ここでは、論理記述の構造を変えずに、簡単に遅延調整する方法[2][3][4]を示します。
- 下図の組み合わせ回路Aと組み合わせ回路Bを縦続させたパイプラインをご覧ください。システムのターゲットを遅延Sとし、遅延A>遅延S>遅延Bとします。
- 基本的な考え方は、遅延Bの余裕分に収まるよう遅延Aの超過分?を移動させることです。非常に単純で簡単なことですが、これを論理設計でどうするかと言うことがポイントになります。
記述変更での対応1
- タイミングを分断するFFを移動させることになりますが、それは組み合わせ回路の中に入り込んでの対応を意味します。超過遅延Aと余裕遅延Bがあるとして、超過遅延Aを持つ回路が記述変更の対象になります。
- 例えば、16ビットどうしの掛け算をラッチするパイプラインステージが遅延超過と仮定します。信号a,bは前段ステージのFF出力、信号cは後段ステージの組み合わせ回路入力です。
always @(posedge clk)
c[31:0] <= #1 a[15:0] * b[15:0];
- 以下は16ビットどうしの掛け算は重いので、2つの掛け算に分解して後で結果を足しこむものです(信号定義を省いているため、冗長ですがビットレンジを記載しています)。この場合は、上図の後方遅延調整になります。
always @(posedge clk) begin
c_h[31:8] <= #1 a[15:0] * b[15:8];
c_l[23:0] <= #1 a[15:0] * b[7:0];
end
assign c[31:0] = {c_h[31:8], 8'd0} + {8'd0, c_l[23:0]};
- さて、前方遅延調整は前段ステージの出力FFには細工が必要です。実際には前段ステージのFF入力を信号aD, bD(DはFFのD端子入力の意味)とし、その信号だけを残してFF自体は削除します。この準備の結果、信号a, b→信号aD, bDにするだけで以下のようになります。
always @(posedge clk)
c_h[31:8] <= #1 aD[15:0] * bD[15:8];
c_l[23:0] <= #1 aD[15:0] * bD[7:0];
end
assign c[31:0] = {c_h[31:8], 8'd0} + {8'd0, c_l[23:0]};
- 上記は意図的に組み合わせ回路を分割しましたが、中間的な信号が元々存在することが結構あります。この場合はそのまま利用します。
記述変更での対応2
- 中間信号を利用する注意点は、同じ位相(ステージの位置)のものだけを使う、FFのD端子の信号はCE端子がない形を考慮必要があります。例えば、FIFOのBusy, Full信号が次のように定義されているとします。詳しくは設計例FIFOを参照してください(ただし、信号名のrdとwrはiとoに変わります)。
always @(posedge clk)
if (reset)
rdPtr[3:0] <= #1 4'd0;
else if (rdAlloc)
rdPtr[3:0] <= #1 rdPtr[3:0] + 4'd1;
always @(posedge clk)
if (reset)
wrPtr[3:0] <= #1 4'd0;
else if (wrAlloc)
wrPtr[3:0] <= #1 wrPtr[3:0] + 4'd1;
assign busy = (rdPtr[3:0] != wrPtr[3:0]);
assign full = (rdPtr[3] != wrPtr[3]) & (rdPtr[2:0] == wrPtr[2:0]);
- BusyとFullは組み合わせ回路なので、後々のことを考え遅延0つまりFF出力したくなります。この場合、前方遅延調整を利用します。
// CE端子がないFF記述
always @(posedge clk) begin
rdPtr[3:0] <= #1 rdPtrD[3:0];
wrPtr[3:0] <= #1 wrPtrD[3:0];
busy <= #1 busyD;
full <= #1 fullD;
end
// D型FFへの変換、システム共通のリセットであればreset信号は必ずしも入れる必要はない
// (便利に使うD端子としては不必要だが、上記のFF代入のところでresetは必ず必要)
assign rdPtrD[3:0] = reset ? 4'd0 : rdPtr[3:0] + rdAlloc;
assign wrPtrD[3:0] = reset ? 4'd0 : wrPtr[3:0] + wrAlloc;
// 上記D端子と同位相のBusy, Full信号を生成
assign busyD = (rdPtrD[3:0] != wrPtrD[3:0]);
assign fullD = (rdPtrD[3] != wrPtrD[3]) & (rdPtrD[2:0] == wrPtrD[2:0]);
- 以上のように、Busy, Full信号を生成していたassign文の使用する信号を全て前のステージのFFのD端子入力に置き換えることによって、Busy, Full信号をFF化する前のD端子信号が生成できます(FFの移動ではなく生成)。動作・結果とも両者とも全く等価です。
- ここで、D端子以外の信号を使うと位相がおかしくなり誤作動してしまうので注意が必要です。また、FIFOのポインターrdPtrDとwrPtrDは、それぞれをresetとrdAlloc, wrAlloc含んだ純粋なFFのD端子信号にしなければいけません。よく忘れるのが、FFのCE端子を考慮しないことです(CE端子がない記述にする)。
回路デザイン > テクニック > 遅延の移動 次のページ(ステートマシン)  このページのTOP ▲