アルゴリズムのステップを異なるサイクルで実行しようとしているときに、プロセス内の「順次」構造はそれ自体では実行できないことに気付きました。実際、変数は役に立ちません。シーケンシャル プログラムは、明示的な "wait for some_event" を使用しない限り (たとえば、wait for raise_edge(clk))、展開され、1 クロック サイクルで実行されます。
おそらく変数を使用していることに気付いたように、これはかなり長いクロック サイクルである可能性があります。
VHDL で実行をシーケンシャル化するには、主に 3 つの方法があり、それぞれ目的が異なります。
a と b の間の線形補間を実装してみましょう。
a, b, c, x : unsigned(15 downto 0);
x <= ((a * (65536 - c)) + (b * c)) / 65536;
(1) は古典的なステート マシンです。最良の形態は単一プロセス SM です。ここで、計算はいくつかのサイクルに分割され、一度に多くても 1 つの乗算が進行することを保証します (乗算器は高価です!) が、C1 は並列で計算されます (加算/減算は安価です!)。中間結果のシグナルの代わりに変数で安全に書き直すことができます。
type state_type is (idle, step_1, step_2, done);
signal state : state_type := idle;
signal start : boolean := false;
signal c1 : unsigned(16 downto 0); -- range includes 65536!
signal p0, p1, s : unsigned(31 downto 0);
process(clk) is
begin
if rising_edge(clk) then
case state is
when idle => if start then
p1 <= b * c;
c1 <= 65536 - c;
state <= step_1;
end if;
when step_1 => P0 <= a * c1;
state <= step_2;
when step_2 => s <= p0 + p1;
state <= done;
when done => x <= s(31 downto 16);
if not start then -- avoid retriggering
state <= idle;
end if;
end case;
end if;
end process;
(2) は、Martin Thompson によってリンクされた「暗黙のステート マシン」です (優れた記事です!) ... Martin の回答が消えたため、リンクを追加するために編集されました。明示的なステート マシンの場合と同じ注意事項が適用されます。
process(clk) is
begin
if start then
p1 <= b * c;
c1 <= 65536 - c;
wait for rising_edge(clk);
p0 <= a * c1;
wait for rising_edge(clk);
s <= p0 + p1;
wait for rising_edge(clk);
x <= s(31 downto 16);
while start loop
wait for rising_edge(clk);
end loop;
end if;
end process;
(3) はパイプライン化されたプロセッサです。ここでは、実行に数サイクルかかりますが、すべてが並行して行われます! パイプラインの深さ (サイクル単位) により、論理的に連続する各ステップを連続して実行できます。これにより、計算の長いチェーンがサイクルサイズのステップに分割されるため、高いパフォーマンスが可能になります...
signal start : boolean := false;
signal c1 : unsigned(16 downto 0); -- range includes 65536!
signal pa, pb, pb2, s : unsigned(31 downto 0);
signal a1 : unsigned(15 downto 0);
process(clk) is
begin
if rising_edge(clk) then
-- first cycle
pb <= b * c;
c1 <= 65536 - c;
a1 <= a; -- save copy of a for next cycle
-- second cycle
pa <= a1 * c1; -- NB this is the LAST cycle copy of c1 not the new one!
pb2 <= pb; -- save copy of product b
-- third cycle
s <= pa + pb2;
-- fourth cycle
x <= s(31 downto 16);
end if;
end process;
ここでは、リソースは共有されません。各クロック サイクルで 2 つの乗算があるため、2 つの乗算器を使用します。また、中間結果とコピーのためにさらに多くのレジスタを使用します。ただし、すべてのサイクルで a、b、c の新しい値を指定すると、サイクルごとに新しい結果が出力されます。つまり、入力から 4 サイクル遅れます。