【问题标题】:VHDL dynamic range selection synthesizable codeVHDL动态范围选择综合代码
【发布时间】:2016-02-16 03:04:42
【问题描述】:

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

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

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

一个简化的例子如下,不确定是否可以合成。

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);

【问题讨论】:

  • 挥手没有用。
  • 如果您正在处理未知的大量条件,您可以编写一个程序来表达组合并以表格形式查看它们,显示哪个贡献的输入和索引进入哪个输出。它将告诉您如何记录它以及如何实现它以匹配。综合实际上一次只关心一个输出位。

标签: vhdl


【解决方案1】:

这不是Minimal, Complete, and Verifiable example。不管你是不是在想问题。

您的“selected_ranges”是多路复用器,具有两个可能的值,具体取决于是否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;

这段代码分析、阐述和运行,并通过在"00"sel 中添加初始值并重做,表明两种备选方案的表达式长度都是正确的。

这将在综合中更加简化,注意到selected_range 的高两位和低三位“位”对于两种情况都是相同的。

所以,是的,您的代码符合合成条件,不,它不是动态范围的(根据sel,只有一个“位”可以不同,这些代表一个由两个输入驱动的 2:1 多路复用器大门看着sel

您只是选择了一种艰难的方式来表达您的代码的功能。 (而且这里的表达还是很冗长的)。

【讨论】:

  • 感谢您的详细回答。对不起,不完整的例子。我知道它是一个多路复用器,但我想问的是我是否可以将范围内的变量用于可合成的代码。因为我正在处理的代码有几十个作为 sel 的信号,不同范围的组合将是 50+。这样,我想通过常量和变量生成范围来减少它的某些部分
  • 通过不同控制条件的数量来描述 N 个多路复用器(可能具有不同的长度)。合成仍然会尽可能地崩溃。只要counter 具有静态范围,就没有理由不满足条件(并且对于每个段,都有一些静态“选择”)。对于所有泛型和其他常量,您可以在生成语句中表达多路复用器。
  • 多路复用方案越复杂,您可以从更小的多路复用器中构建它,您应该在这里定义这是一个设计规范。 (它可以避免在别人的例子周围挥手)。
【解决方案2】:

我将采用具有 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,请参阅我的cmets。该代码在 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;

【讨论】:

  • 谢谢!我认为数组和生成的想法很棒。我会试一试的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-29
相关资源
最近更新 更多