standard_logic_vector の最初の '1' を検索し、'1' がどのベクトル位置にあったかを出力する ASIC (ASIC の一部である必要があります) 用の合成可能な VHDL (関数またはプロシージャ) を作成しようとしています。たとえば、「10001000」の 8 ビット slv があります (位置 3 と 7 の「1」)。この slv を使用すると、出力は 4 になります (出力は 1 ベースです)。
実際の VHDL は、長さが最大 512 ビットの大きな slv を検索します。二分探索関数を実装しようとしましたが、「定数でない範囲の値を合成できませんでした。[CDFG-231] [精巧な] 定数でない範囲の値がファイル '...' の 61 行目にあります」という合成エラーが発生します。以下のコードで、不平を言う場所を示しました。非定数範囲値を使用せずにバイナリ検索アルゴリズムを実装する方法がわかりません。このコードを合成できるように変更するにはどうすればよいですか?
HDL のバイナリ検索アルゴリズムを検索して、潜在的なコードを確認し、エラーを検索しようとしましたが、何も見つかりませんでした。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
entity bin_search is
generic (
constant NREGS : positive := 16 -- number of registers
);
port (
clk_i : in std_logic; -- clock
bin_i : in unsigned( NREGS-1 downto 0 ); -- input
en_i : in std_logic; -- input enable
addr_o : out natural range 0 to NREGS -- first binary location
);
end bin_search;
architecture rtl of bin_search is
function f_bin_search( input: unsigned; nob: positive ) return natural is
constant nbits : positive := 2**nob;
variable lower : natural range 0 to 1 := 0;
variable upper : natural range 0 to 1 := 0;
variable idx : natural range 0 to nob := 4;
variable cnt : natural range 0 to nbits := 0;
variable mid : positive range 1 to nbits := nbits/2; --
variable ll : natural range 0 to nbits := 0;
variable ul : positive range 1 to nbits := nbits; --
begin
if input = 0 then
cnt := 0;
return cnt;
else
loop1: while ( idx > 0 ) loop
if ( input( mid-1 downto ll ) > 0 ) then -- <===WHERE SYNTH COMPLAINS
lower := 1;
else
lower := 0;
end if;
if ( input( ul-1 downto mid ) > 0 ) then
upper := 1;
else
upper := 0;
end if;
if ( idx = 1 ) then
if ( lower = 1 ) then
cnt := mid;
else
cnt := ul;
end if;
elsif ( lower = 1 ) then
ul := mid;
mid := ( ( ll+ul )/2 );
elsif ( upper = 1 ) then
ll := mid;
mid := ( ll+ul )/2;
else
cnt := 0;
exit loop1;
end if;
idx := idx-1;
end loop loop1;
return cnt;
end if;
end f_bin_search;
begin
test_proc: process ( clk_i )
begin
if rising_edge( clk_i ) then
if en_i = '1' then
addr_o <= f_bin_search( bin_i, 4 );
end if;
end if;
end process test_proc;
end rtl;
入力が「1」でインクリメントされる単純なテスト ベンチを次に示します。addr_o は、'1' を持つ入力 lsb の位置 (1 ベース) である必要があります。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_misc.all;
use ieee.numeric_std.all;
entity bin_search_tb is
end bin_search_tb;
architecture behavior of bin_search_tb is
constant NREGS : positive := 16;
signal clk : std_logic;
signal input : unsigned( NREGS-1 downto 0 );
signal start : std_logic;
signal addr : natural range 0 to NREGS;
constant clk_per : time := 1 ns;
signal row : natural range 0 to 2**NREGS-1;
begin
bin_search_inst: entity work.bin_search( rtl )
generic map (
NREGS => NREGS
)
port map (
clk_i => clk, -- master clock
bin_i => input, -- captured events
en_i => start, -- start binary search
addr_o => addr -- addr where the first '1' appears
);
-- master clock process
clk_proc: process
begin
clk <= '0';
wait for clk_per / 2;
clk <= '1';
wait for clk_per / 2;
end process clk_proc;
--
stim1_proc: process
begin
input <= ( others => '0' );
start <= '0';
row <= 1;
wait until clk'event and clk = '1';
loop
wait until clk'event and clk = '1';
input <= to_unsigned( row, input'length );
start <= '1';
wait until clk'event and clk = '1';
start <= '0';
wait for 4*clk_per;
row <= row+1;
end loop;
end process stim1_proc;
end architecture behavior;
ご協力ありがとうございます。-ジェイソン
コードを編集し、テストベンチを追加しました