索引付けを静的合成にする方法があります。
最初に、ループに基づいて、の範囲内の値を持つ必要があります。そうしないと、ヌルスライス(IEEE Std 1076-2008 8.5スライス名)になります。実体宣言で示すことができる
:変更内容
library ieee;
use ieee.std_logic_1164.all;
entity shift_register is
generic (
N: integer := 6;
M: integer := 6
);
port (
en_s: in std_logic;
cod_result: in std_logic_vector (N + M - 1 downto 0);
position: in integer range 0 to N + M - 1 ; -- range ADDED
shift_result: out std_logic_vector(N + M - 1 downto 0)
);
end entity shift_register;
はposition
のポート宣言の範囲の制約を追加することです。この考え方は、デフォルト値が整数であることができるシミュレーションをサポートすることです。integer'left
です。 shift_register
をシミュレートすると、shift_aux
のインデックス範囲の最初の値がposition
(実際のドライバ)に指定されていないと、en_s
の立ち上がりエッジでエラーが発生します。
合成の観点から、無制限の整数では、正と負の両方の整数値を考慮する必要があります。 forループは正の整数値のみを使用しています。
同じプロセスで、変数i
の宣言で行うことができます
variable i: integer range 0 to N + M - 1 := 0; -- range ADDED
我々はのためのループを見てすぐに合成の問題に対処するために。
ザイリンクスサポートの問題AR# 52302は、インデックスに動的値を使用している問題を示しています。
architecture shift_loop of shift_register is
begin
process (en_s)
variable shift_aux: std_logic_vector(N + M - 1 downto 0);
-- variable i: integer range 0 to N + M - 1 := 0; -- range ADDED
begin
if en_s'event and en_s = '1' then
-- i := position;
shift_aux := (others => '0');
for i in 0 to N + M - 1 loop
-- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0);
if i = position then
shift_aux(N + M - 1 downto i)
:= cod_result(N + M - 1 - i downto 0);
end if;
end loop;
shift_result <= shift_aux;
end if;
end process;
end architecture shift_loop;
i
ループは、それがインデックスの計算に使用することができる合成に展開される静的な値となった場合:
溶液はないループのもの修正することです。
これはN + M入力マルチプレクサを示しています。ここで、各入力はi = position
のときに選択されています。
NとMの大きな値に関連する変数の数が非常に多くの合成作業を必要とするか、単に失敗することが予想されるかもしれませんが、このコンストラクトは最適化によって実際にバレルシフタに縮小できます。
合成が成功すると、割り当ての各出力要素が、パトリックの barrel shifterと一致する別のマルチプレクサに折りたたまれます。
NとMの値が十分大きいと、バレルシフタのマルチプレクサレイヤ数の深さを整数の距離範囲のバイナリ表現のビット数に基づいて定義できます。
position
に宣言された整数型またはサブタイプが必要か、またはN + Mのlog2値を見つける必要があります。静的にしか使用されないので、log2値を使用できます。 (XSTはlog2(x)をサポートします。ここで、xは静的値を決定するためのRealです。関数はIEEEパッケージmath_realにあります)。これにより、バイナリの長さはposition
になります。 (シフト距離、マルチプレクサのレベル数を記述するために必要なビット数)。左のオペランドが2であるとi
の値はループ文で見つかった一連の文で定数として扱われている場合
architecture barrel_shifter of shift_register is
begin
process (en_s)
use ieee.math_real.all; -- log2 [real return real]
use ieee.numeric_std.all; -- to_unsigned, unsigned
constant DISTLEN: natural := integer(log2(real(N + M))); -- binary lengh
type muxv is array (0 to DISTLEN - 1) of
unsigned (N + M - 1 downto 0);
variable shft_aux: muxv;
variable distance: unsigned (DISTLEN - 1 downto 0);
begin
if en_s'event and en_s = '1' then
distance := to_unsigned(position, DISTLEN); -- position in binary
shft_aux := (others => (others =>'0'));
for i in 0 to DISTLEN - 1 loop
if i = 0 then
if distance(i) = '1' then
shft_aux(i) := SHIFT_LEFT(unsigned(cod_result), 2 ** i);
else
shft_aux(i) := unsigned(cod_result);
end if;
else
if distance(i) = '1' then
shft_aux(i) := SHIFT_LEFT(shft_aux(i - 1), 2 ** i);
else
shft_aux(i) := shft_aux(i - 1);
end if;
end if;
end loop;
shift_result <= std_logic_vector(shft_aux(DISTLEN - 1));
end if;
end process;
end architecture barrel_shifter;
XSTも**
をサポートしています。
これは、変数の代わりに、またはループステートメントの代わりにgenerateステートメントに構造的に、またはサブプログラムとして実装することができます。
この2つのアーキテクチャの基本的な考え方は、あなたのものから派生したものを合成することです。
最初の上に第二のアーキテクチャの利点は、これらのアーキテクチャのいずれも元にテストベンチを欠いて検証されたN + M.
のより大きな値に対して最適化中に合成努力の量の減少です。彼らは分析して精緻化しています。単純なケーステストベンチ書き込み
:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity shift_register_tb is
end entity;
architecture foo of shift_register_tb is
constant N: integer := 6;
constant M: integer := 6;
signal clk: std_logic := '0';
signal din: std_logic_vector (N + M - 1 downto 0)
:= (0 => '1', others => '0');
signal dout: std_logic_vector (N + M - 1 downto 0);
signal dist: integer := 0;
begin
DUT:
entity work.shift_register
generic map (
N => N,
M => M
)
port map (
en_s => clk,
cod_result => din,
position => dist,
shift_result => dout
);
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if now > (N + M + 2) * 20 ns then
wait;
end if;
end process;
STIMULI:
process
begin
for i in 1 to N + M loop
wait for 20 ns;
dist <= i;
din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1));
end loop;
wait;
end process;
end architecture;
そしてシミュレートはposition
の範囲とループ反復の回数だけ乗算なく被乗数のビット数をカバーするために必要であることがわかります。フルバレルシフターは必要ありません。
これは、shift_registerアーキテクチャで簡単に修正することができ、shift_loopアーキテクチャをより魅力的にするという副作用があります。乗算器のビット長(おそらくM)に基づいて合成する方が簡単ですN + M)。
そして、それはあなたを与えるだろう:
library ieee;
use ieee.std_logic_1164.all;
entity shift_register is
generic (
N: integer := 6;
M: integer := 6
);
port (
en_s: in std_logic;
cod_result: in std_logic_vector (N + M - 1 downto 0);
position: in integer range 0 to M - 1 ; -- range ADDED
shift_result: out std_logic_vector(N + M - 1 downto 0)
);
end entity shift_register;
architecture shift_loop of shift_register is
begin
process (en_s)
variable shift_aux: std_logic_vector(N + M - 1 downto 0);
-- variable i: integer range 0 to M - 1 := 0; -- range ADDED
begin
if en_s'event and en_s = '1' then
-- i := position;
shift_aux := (others => '0');
for i in 0 to M - 1 loop
-- shift_aux(N + M - 1 downto i) := cod_result(N + M - 1 - i downto 0);
if i = position then -- This creates an N + M - 1 input MUX
shift_aux(N + M - 1 downto i)
:= cod_result(N + M - 1 - i downto 0);
end if;
end loop; -- The loop is unrolled in synthesis, i is CONSTANT
shift_result <= shift_aux;
end if;
end process;
end architecture shift_loop;
は、テストベンチを変更:
STIMULI:
process
begin
for i in 1 to M loop -- WAS N + M loop
wait for 20 ns;
dist <= i;
din <= std_logic_vector(SHIFT_LEFT(unsigned(din),1));
end loop;
wait;
end process;
はシフトを示す結果になりますが(Mによって指定された)乗数値の範囲を超えている。
ここでは、道徳的なものは完全ではありませんバレルシフタは、乗算器の範囲で動作し、製品の範囲では動作しません。
コードの最後のビットは合成適格でなければなりません。
私はなぜ動作しないのか分かりますが、私の仕事はx <= a * bを使うことができないようにブース乗数を実装することです。とにかくお返事 –
@DarioFigliuzziので、あなたの実際の質問は "私はどのようにバレルシフタを実装しますか?"です。そうである場合、これに関する既存の質問があります。 –
私はこの問題を回避する方法についてもっと考えていました。代わりの方法 –