VHDL动态范围选择可合成代码

时间:2016-02-16 03:04:42

标签: vhdl

处理复杂的范围选择逻辑。

选择信号的组合太多,选择和连接的范围太多。

我正在寻找一种更好的方法来使其可读,使用由预定义常量和动态输入生成的有意义的变量。

以下简化示例,不确定它是否可合成。

library ieee;
use ieee.std_logic_1164.all;

entity fum is
end entity;

architecture foo of fum is
    signal sel:             std_logic_vector (1 downto 0);
    signal selected_range:  std_logic_vector (5 downto 0);
    signal counter:         std_logic_vector (7 downto 0);

    constant BASE_ADDR_LOW: integer := 2;
    constant RANGE1_BITS  : integer := 2;
    -- this is simplified
    -- dozens of constants involved, and their values can be configured before compiling.
begin

some_process:
    process (sel, counter)
    variable range0_high : integer := BASE_ADDR_LOW;
    variable range1_low  : integer := 0;
    variable range1_high : integer := 0;
    begin

    if (sel = "00") then
    -- this is simpilfied as well
    -- dozens of inputs as sel involved, for 50+ combinations via nested if and case
        range0_high := BASE_ADDR_LOW+1; -- 3
        range1_low  := range0_high+2;   -- 5
        range1_high := range1_low+RANGE1_BITS-1; -- 6

    -- the following elsif will not work as the range1 has 0 bit.
    -- not sure if there is a better way to do this

    -- elsif (sel = "01" ) then
    --  range0_high := BASE_ADDR_LOW+1; -- 5
    --  range1_low  := range0_high+2;   -- N/A
    --  range1_high := range1_low+RANGE1_BITS;  --N/A
    else
        range0_high := BASE_ADDR_LOW;   -- 2
        range1_low  := range0_high+2;   -- 4
        range1_high := range1_low+RANGE1_BITS; --6
    end if;

    -- using variables in range
    selected_ranges <= counter(range1_high downto range1_low) & counter(range0_high downto 0);

    end process;
end architecture;

如果某些字段可能是0位,有没有办法制作可综合的代码?

-- e.g. range0_high = 5, range1_* not in use
-- selected_ranges <= *nothing &* counter(5 downto 0);

2 个答案:

答案 0 :(得分:0)

这不是Minimal, Complete, and Verifiable example。无论你是否过度思考问题。

您选择的&#39; selected_ranges&#39;是基于sel = "00"是否具有两个可能值的多路复用器。

library ieee;
use ieee.std_logic_1164.all;

entity fum is
end entity;

architecture foo of fum is
    signal sel:             std_logic_vector (1 downto 0);
    signal selected_range:  std_logic_vector (5 downto 0);
    signal counter:         std_logic_vector (7 downto 0);
begin
some_process:
    process (sel, counter)
    begin
        if sel = "00" then
            selected_range <= counter (6 downto 5) & counter (3 downto 0);
        else 
            selected_range <= counter (6 downto 4) & counter (2 downto 0);
        end if;
    end process;
end architecture;

此代码分析,详细说明和运行,并通过向sel的{​​{1}}添加初始值并重做,表明两个备选方案的表达式长度都是正确的。

这将在综合中得到更加简化,注意上面的两个和下面的三个比特&#39;对于这两种情况,"00"都是相同的。

所以,是的,你的代码是合成资格的,不是它没有动态范围(根据selected_range只有一个&#39;可以是不同的,那些代表一个2:1多路复用器由两个输入门驱动,查看sel

您只是选择了一种难以表达代码功能的方法。 (这里的表达仍然是冗长的。)

答案 1 :(得分:0)

我将采用具有N个输入的普通多路复用器,并通过从包含多路复用器数据输入(mux_data_in)的数组中选择结果来描述它:

type t_mux_data_in is array(natural range <>) of std_logic_vector(selected_range'range);
signal mux_data_in : t_mux_data_in(0 to N-1);
...
selected_range <= mux_data_in(to_integer(unsigned(sel)));

多路复用器数据输入使用for .. generate循环和一些辅助函数生成,这些函数指定循环中每次迭代i的范围。在循环中,您必须检查范围1是否为空。

完整代码如下所示,示例代码中给出了范围。我不得不修改案例sel = "01"以得到一个空的范围1,看看我的评论。该代码在ISE 14.7中很好地合成,实际上生成了一个6位3对1多路复用器,因为情况2和3是相同的。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity fum is
    generic (
        SEL_BITS : positive := 2);
    port (
        sel :            in  std_logic_vector (SEL_BITS-1 downto 0);
        counter :        in  std_logic_vector (7 downto 0);
        selected_range : out std_logic_vector (5 downto 0));
end entity;

architecture foo of fum is
    constant BASE_ADDR_LOW: integer := 2;
    constant RANGE1_BITS  : integer := 2;

    -- functions defining range
    function range0_high(sel : integer) return integer is
    begin
        case sel is
        when 0      => return BASE_ADDR_LOW+1;
        when 1      => return BASE_ADDR_LOW+3; -- updated to +3 to get a 5 (!)
        when others => return BASE_ADDR_LOW;   -- default
        end case;
    end function;

    function range1_low(sel : integer) return integer is
    begin
        return range0_high(sel)+2; -- default
    end function;

    function range1_high(sel : integer) return integer is
    begin
        case sel is
        when 0      => return range1_low(sel)+RANGE1_BITS-1;
        when 1      => return range1_low(sel);             -- updated to empty range (!)
        when others => return range1_low(sel)+RANGE1_BITS; -- default
        end case;
    end function;

    -- all multiplexer data inputs
    constant N : positive := 2**SEL_BITS;
    type t_mux_data_in is array(natural range <>) of std_logic_vector(selected_range'range);
    signal mux_data_in : t_mux_data_in(0 to N-1);

begin
    -- build multiplexer data inputs
    genDataIn: for i in 0 to N-1 generate
        constant r1_low : integer := range1_low(i);
        constant r1_high: integer := range1_high(i);
    begin
        genHighEmpty: if r1_low = r1_high generate
            mux_data_in(i) <= counter(range0_high(i) downto 0);
        end generate;
        genHigh: if r1_low /= r1_high generate
            mux_data_in(i) <= counter(r1_high downto r1_low) & counter(range0_high(i) downto 0);
        end generate;
    end generate;

    -- the multiplexer
    selected_range <= mux_data_in(to_integer(unsigned(sel)));
end architecture;