Vivado综合:不支持复杂分配

时间:2017-02-01 14:41:02

标签: vhdl variable-assignment synthesis vivado

我在vhdl中实现了Booth修改后的乘数。我需要与Vivado进行综合,但由于这个错误,它是不可能的: "不支持复杂的作业"。 这是导致错误的移位器代码:

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;
shift_result    : out std_logic_vector(N+M-1 downto 0)
);    
end shift_register;   

architecture shift_arch of shift_register is
begin
process(en_s)  

variable shift_aux : std_logic_vector(N+M-1 downto 0);
variable i : integer := 0;  --solo per comodità 
begin   
   if(en_s'event and en_s ='1') then
      i := position;
      shift_aux := (others => '0');
      shift_aux(N+M-1 downto i) := cod_result(N+M-1-i downto 0); --ERROR!!
      shift_result <= shift_aux ;
   end if;
end process;
end shift_arch;

展位乘数适用于任何操作员维度。所以我不能用特定的代码更改这个通用代码。 请帮我!非常感谢

2 个答案:

答案 0 :(得分:1)

有一种方法可以使索引寻址为静态以进行综合。

首先,基于循环我们可以告诉position必须具有shift_aux范围内的值,否则您最终会得到空切片(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(实际驱动程序)未在en_s的索引范围内提供初始值,则模拟position将在shift_aux的上升沿失败。

从综合的角度来看,无界整数要求您考虑正负整数值。你的for循环只使用正整数值。

在过程中变量i的声明中也可以这样做:

        variable i:          integer range 0 to N + M - 1 := 0;  -- range ADDED

为了解决直接的综合问题,我们来看看for循环。

Xilinx支持问题AR# 52302告诉我们问题是使用索引的动态值。

解决方案是修改for循环的作用:

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的大值所涉及的变量数量可能需要过高的合成努力或者只是失败。

当合成成功时,您将把赋值中的每个输出元素折叠成一个与Patrick相匹配的独立多路复用器 barrel shifter

对于足够大的N和M值,我们可以根据整数距离范围的二进制表达式中的位数来定义桶形移位器中多路复用器层数的深度。

要么position需要声明的整数类型或子类型,要么找到N + M的log2值。我们可以使用log2值,因为它只能静态使用。 (XST支持log2(x),其中x是用于确定静态值的Real,该函数可在IEEE包math_real中找到)。这给了我们position的二进制长度。 (描述移位距离,多路复用器级别数需要多少位。)

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;

如果左操作数为2,则XST也支持**,并且i的值在循环语句中找到的语句序​​列中被视为常量。

这可以通过信号而不是变量实现,也可以在结构中在生成语句中实现,而不是在进程内部实现循环语句,甚至可以作为子程序实现。

这里提供的这两种架构的基本思想是产生符合条件的合成。

第二种结构优于第一种结构的优势在于减少了在较大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指定):

shift_register_tb_1.png

所以这里的道德是你不需要一个完整的桶式移位器,只有一个工作在乘数范围而不是产品范围。

最后一点代码应该是合成资格。

答案 1 :(得分:0)

您正尝试使用运行时变化值创建范围,而综合工具不支持此范围。将支持cod_result(N+M-1 downto 0);,因为NM1在合成时都是已知的。

如果您正在尝试实现乘数,您将使用x <= a * b获得最佳结果,并让综合工具选择实施它的最佳方式。如果操作数大于设备中的乘数宽度,则需要查看文档以确定最佳路径,这通常涉及某种流水线操作。

如果您需要运行时变量转换,请查找“Barrel Shifter”。这些答案现有,例如this one