1

我正在尝试为 ASIC(它必须是 ASIC 的一部分)创建可合成的 VHDL(函数或过程),它将在 standard_logic_vector 中查找第一个“1”并输出“1”所在的向量位置。对于例如,我有一个“10001000”的 8 位 slv(位置 3 和 7 中的“1”)。如果我使用这个 slv,输出应该是 4(输出基于 1)。

实际的 VHDL 将搜索一个大的 slv,长度可达 512 位。我尝试实现二进制搜索功能,但我得到综合错误,指出“无法合成非常量范围值。[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;

感谢你的协助!-杰森

编辑代码并添加了一个测试台

4

2 回答 2

1

您的设计肯定取决于延迟和其他性能要求,但是,您可以使用或减少、序列器(用于切片向量的多路复用器选择)、移位寄存器和计数器的某种组合。我画了一个简单的电路,它应该在大约 30 个时钟周期内找到你的“1”的 lsb 实例

在此处输入图像描述

实现此设计的 RTL 转换应该是直截了当的。

于 2018-03-28T20:00:41.243 回答
0

你说你在考虑硬件,但实际上你不是。或者你是在误导自己。

input( mid-1 downto ll ) > 0

不是OR-reduction,而是比较操作。你必须知道>的是larger than比较运算符。综合将因此推断出一个比较器。但我问,比较器必须有多少输入?好吧,这就是你的问题:它取决于 的值mid,其中:

  • 最初取决于 的值nbits,这取决于 的值nob是函数的变量输入。
  • 在循环内改变。因此它的价值不是恒定的。

硬件组件不能有可变数量的电线。

但是你为什么要二分查找呢?为什么不保持简单?

library ieee;
use ieee.std_logic_1164.all;

entity detect_one is
    generic(
        input_size : positive := 512);
    port(
        input : in std_logic_vector (input_size-1 downto 0);
        output : out natural range 0 to input_size);
end entity;

architecture rtl of detect_one is
begin
    main: process(input)
    begin
        output <= 0;
        for i in input_size-1 downto 0 loop
            if input(i)='1' then
                output <= i+1;
            end if;
        end loop;
    end process;
end architecture;


entity detect_one_tb is end entity;
library ieee;
architecture behavior of detect_one_tb is
    constant input_size : positive := 512;
    use ieee.std_logic_1164.all;
    signal input : std_logic_vector (input_size-1 downto 0) := (others => '0');
    signal output : integer;
begin
    DUT : entity work.detect_one
        generic map ( input_size => input_size )
        port map(
            input => input,
            output => output);

    test: process begin
        wait for 1 ns;
        assert (output = 0) report "initial test failure" severity warning;
        for i in 0 to input_size-1 loop
            input <= (others => '0');
            input(i) <= '1';
            wait for 1 ns;
            assert (output = i+1) report "single ones test failure" severity warning;
        end loop;
        input <= (others => '1');
        wait for 1 ns;
        assert (output = 1) report "initial multiple ones test failure" severity warning;
        for i in 0 to input_size-2 loop
            input(i) <= '0';
            wait for 1 ns;
            assert (output = i+2) report "multiple ones test failure" severity warning;
        end loop;
        wait;
    end process;
end architecture;
于 2018-03-29T08:40:40.203 回答