私はまだIIRフィルターを操作していませんが、与えられた方程式を計算するだけでよい場合
y[n] = y[n-1]*b1 + x[n]
CPUサイクルごとに1回、パイプライン処理を使用できます。
1サイクルで乗算を実行し、1サイクルで各入力サンプルの合計を実行する必要があります。つまり、FPGAは、所定のサンプルレートでクロックが供給されている場合、乗算を1サイクルで実行できる必要があります。次に、現在のサンプルの乗算と最後のサンプルの乗算結果の合計を並行して行うだけで済みます。これにより、2サイクルの一定の処理遅延が発生します。
では、式を見てパイプラインを設計しましょう。
y[n] = y[n-1]*b1 + x[n]
パイプラインコードは次のようになります。
output <= last_output_times_b1 + last_input
last_output_times_b1 <= output * b1;
last_input <= input
3つのコマンドすべてを並行して実行する必要があり、2行目の「出力」は最後のクロックサイクルからの出力を使用することに注意してください。
私はVerilogであまり機能しなかったので、このコードの構文はおそらく間違っています(たとえば、入力/出力信号のビット幅がない;乗算の実行構文)。しかし、あなたはアイデアを得るべきです:
module IIRFilter( clk, reset, x, b, y );
input clk, reset, x, b;
output y;
reg y, t, t2;
wire clk, reset, x, b;
always @ (posedge clk or posedge reset)
if (reset) begin
y <= 0;
t <= 0;
t2 <= 0;
end else begin
y <= t + t2;
t <= mult(y, b);
t2 <= x
end
endmodule
PS:おそらく、経験豊富な一部のVerilogプログラマーがこのコードを編集して、このコメントとコードの上のコメントを後で削除することができます。ありがとう!
PPS:係数 "b1"が固定定数である場合、1つのスカラー入力のみを使用して "time b1"のみを計算する特別な乗数を実装することにより、設計を最適化できる場合があります。
「残念ながら、これは実際にはy [n] = y [n-2] * b1 + x [n]と同等です。これは、追加のパイプラインステージが原因です。」古いバージョンの回答へのコメントとして
はい、それは実際には次の古い(INCORRECT !!!)バージョンに適していました。
always @ (posedge clk or posedge reset)
if (reset) begin
t <= 0;
end else begin
y <= t + x;
t <= mult(y, b);
end
私はうまくいけば、2番目のレジスタでも入力値を遅らせることにより、このバグを今すぐ修正します。
always @ (posedge clk or posedge reset)
if (reset) begin
y <= 0;
t <= 0;
t2 <= 0;
end else begin
y <= t + t2;
t <= mult(y, b);
t2 <= x
end
今回は正しく機能することを確認するために、最初の数サイクルで何が起こるかを見てみましょう。以前の出力値(y [-1] == ??など)が利用できないため、最初の2サイクルは多かれ少なかれ(定義された)ガベージを生成することに注意してください。レジスタyは0で初期化されます。これは、y [-1] == 0と仮定することと同じです。
最初のサイクル(n = 0):
BEFORE: INPUT (x=x[0], b); REGISTERS (t=0, t2=0, y=0)
y <= t + t2; == 0
t <= mult(y, b); == y[-1] * b = 0
t2 <= x == x[0]
AFTERWARDS: REGISTERS (t=0, t2=x[0], y=0), OUTPUT: y[0]=0
2番目のサイクル(n = 1):
BEFORE: INPUT (x=x[1], b); REGISTERS (t=0, t2=x[0], y=y[0])
y <= t + t2; == 0 + x[0]
t <= mult(y, b); == y[0] * b
t2 <= x == x[1]
AFTERWARDS: REGISTERS (t=y[0]*b, t2=x[1], y=x[0]), OUTPUT: y[1]=x[0]
3番目のサイクル(n = 2):
BEFORE: INPUT (x=x[2], b); REGISTERS (t=y[0]*b, t2=x[1], y=y[1])
y <= t + t2; == y[0]*b + x[1]
t <= mult(y, b); == y[1] * b
t2 <= x == x[2]
AFTERWARDS: REGISTERS (t=y[1]*b, t2=x[2], y=y[0]*b+x[1]), OUTPUT: y[2]=y[0]*b+x[1]
4番目のサイクル(n = 3):
BEFORE: INPUT (x=x[3], b); REGISTERS (t=y[1]*b, t2=x[2], y=y[2])
y <= t + t2; == y[1]*b + x[2]
t <= mult(y, b); == y[2] * b
t2 <= x == x[3]
AFTERWARDS: REGISTERS (t=y[2]*b, t2=x[3], y=y[1]*b+x[2]), OUTPUT: y[3]=y[1]*b+x[2]
cylce n = 2で始まると、次の出力が得られることがわかります。
y[2]=y[0]*b+x[1]
y[3]=y[1]*b+x[2]
これは
y[n]=y[n-2]*b + x[n-1]
y[n]=y[n-1-l]*b1 + x[n-l], where l = 1
y[n+l]=y[n-1]*b1 + x[n], where l = 1
上記のように、l = 1サイクルの追加の遅れを導入します。つまり、出力y [n]はラグl = 1だけ遅れます。つまり、出力データは同等ですが、1つの「インデックス」だけ遅延します。より明確にするために、1つの(通常の)クロックサイクルが必要であり、中間ステージに1つの追加(ラグl = 1)クロックサイクルが追加されるため、出力データは2サイクル遅れます。
以下は、データがどのように流れるかをグラフィカルに示すスケッチです。
PS:私のコードをよく見ていただきありがとうございます。だから私も何かを学びました!;-)このバージョンが正しいかどうか、またはさらに問題が発生した場合はお知らせください。