私は再利用可能なバレルシフターを作成しようとしています。ビットの入力配列を取り、それらを特定の数の位置にシフトします(別の入力によって決定されます)。モジュールをパラメーター化して、どのn
でも機能するようにします。
必要な選択行の数は、n
->つまり、以下のコードのSHIFT_CNT = log2(NUMBITS-1)+1
によって決まります。 std_logic_vector
またはstd_logic
以外のポートを使用することは、私の組織(および私は全体的に考えると)では不適切なフォームと見なされるため、選択行の数にstd_logic_vector
を使用しました。入力ジェネリックに基づいてstd_logic_vector
の長さを調整する必要があります。 2番目のジェネリックを使用せずにこれを行う方法はありますか?私は this の投稿を見てきましたが、ジェネリックを扱いません。 This postは、ジェネリックを完全に削除するか、ログ値をジェネリックとして使用します。これは、将来のユーザーにとって直感的ではありません(INPUT
が2の累乗でない場合、問題が発生する可能性があります) )。
以下のSHIFT_CNT
の宣言は間違いなく間違っています。 2番目のジェネリックを使用せずにエンティティ宣言で長さを自動的に生成する方法はありますか?
entity BarrelShifter is
generic ( NUMBITS : integer :=8);
Port ( INPUT : in std_logic_vector (NUMBITS-1 downto 0);
OUTPUT : out std_logic_vector (NUMBITS-1 downto 0);
SHIFT_CNT : in std_logic_vector ((NUMBITS-1)'length downto 0)
);
end BarrelShifter;
数学ライブラリを使用して、logarit結果のlog2とceilを計算し、SHIFT_CNTのサイズを宣言できます。
use IEEE.math_real.all;
または特定の機能
use IEEE.math_real."ceil";
use IEEE.math_real."log2";
たとえば、値aのclog2を計算するとします。
result := integer(ceil(log2(real(a))));
これらの関数を使用してパラメーターを計算する場合、あなたのコードは合成可能(私がやった)。
エンティティで使用したくない場合は、ライブラリで宣言するか、これらの関数でジェネリックを宣言できます。
次のように、ライブラリにlog2関数を作成できます。
function f_log2 (x : positive) return natural is
variable i : natural;
begin
i := 0;
while (2**i < x) and i < 31 loop
i := i + 1;
end loop;
return i;
end function;
ライブラリがインポートされている場合は、次のようにポートを指定できます。
shift_cnt : in std_logic_vector(f_log2(NUMBITS)-1 downto 0)
これはやや醜いソリューションですが、リソースを使用しません(関数は純粋で、すべての入力はコンパイル時に既知であるため)。
私は通常これを行いますが、あなたが言及しているようにログ値をジェネリックとして指定することを好むかもしれません。
2つの代替アプローチ:
あなたはそれを逆に作業し、generic
をshift_bits
-次に、そこから入力ベクトルと出力ベクトルの幅を計算します。
generic ( shift_bits: integer :=3);
Port ( INPUT : in std_logic_vector ((2**shift_bits)-1 downto 0);
OUTPUT : out std_logic_vector ((2**shift_bits)-1 downto 0);
SHIFT_CNT : in std_logic_vector (shift_bits-1 downto 0)
);
または、カウントを数値として扱います。
generic ( NUMBITS : integer :=8);
Port ( INPUT : in std_logic_vector (NUMBITS-1 downto 0);
OUTPUT : out std_logic_vector (NUMBITS-1 downto 0);
SHIFT_CNT : in integer range 0 to numbits-1
);
ツールがそれを理解できるようにします。
NUMBITS値を8として入力する代わりに、2(log2(8))として入力し、以下のように再入力して問題を回避できます。ジェネリックはクリーンではありませんが、スケーリング可能です。
entity BarrelShifter is
generic ( NUMBITS : integer :=2);
Port ( INPUT : in std_logic_vector (((2**Nbits)-1) downto 0);
OUTPUT : out std_logic_vector (((2**Nbits)-1) downto 0);
SHIFT_CNT : in std_logic_vector ((NUMBITS-1) downto 0)
);
end BarrelShifter;
カーンが述べた方法を使用していたときに、丸めエラーが発生しました。そこで、丸め誤差の影響を受けず、原則として32ビット以上を処理できる独自のバージョンを作成しました。 Lのタイプは、論理左シフト演算子を持つ任意のタイプに置き換えることができます。
ほとんどの場合、log2ceilは、指定された数値を格納するために必要なビット数ですが、log2floorは、最も高いビットセットとして説明できます。
ほとんどの場合、これらの関数は定数の生成に使用されるため、合成には問題ありません。したがって、それらのハードウェアは推論されません。
function log2ceil (L: POSITIVE) return NATURAL is
variable i, bitCount : natural;
begin
i := L-1;
bitCount:=0;
while (i > 0) loop
bitCount := bitCount + 1;
i:=srlInteger(i,1);
end loop;
return bitCount;
end log2ceil;
function log2floor (L: POSITIVE) return NATURAL is
variable i, bitCount : natural;
begin
i := L;
bitCount:=0;
while (i > 1) loop
bitCount := bitCount + 1;
i:=srlInteger(i,1);
end loop;
return bitCount;
end log2floor;
function srlInteger(arg: integer; s:natural) return integer is
begin
return to_integer(SHIFT_RIGHT(to_UNSIGNED(ARG,32), s));
end srlInteger;