VHDL动态范围选择综合代码

VHDL动态范围选择综合代码,vhdl,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

处理复杂的范围选择逻辑

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

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

下面是一个简化的示例,不确定它是否可合成

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);
这不是一个好主意。不管怎样,你想得太多了

您的“选定_范围”是基于sel=00与否的两个可能值的多路复用器

这段代码分析、阐述和运行,并通过向sel添加初始值00和重做,表明这两个选项的表达式长度是正确的

这将在合成中得到更加简化,注意所选_范围的上两个和下三个“位”在这两种情况下是相同的

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


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

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


谢谢你的详细回答。对不起,这个例子不完整。我知道这是一个多路复用器,但我想问的是,我是否可以使用范围内的变量来合成代码。因为我正在处理的代码包含几十个信号,如sel,不同范围的组合将为50+。因此,我想通过常量和变量来生成范围来减少它的某些部分。通过不同控制条件的数量来描述可能具有不同长度的N个MUX。合成仍将尽可能地崩溃。只要计数器有一个静态范围,就没有理由不存在条件,并且对于每个段,都会有一些静态“选择”。对于所有的泛型和其他常量,您可以在generate语句中表示mux。复用方案越复杂,您就越可以从较小的mux构造它,关于这里,您应该定义这是一个设计规范。这样就不用在别人的例子周围挥手了。挥手没有任何帮助。如果你正在处理大量未知的情况,你可以编写一个程序来表达这些组合,并以表格形式查看它们,显示哪些输入和索引有助于哪个输出。它将告诉您如何记录它以及如何实现它以匹配。合成实际上一次只关心一个输出位。谢谢!我认为数组和生成的想法很棒。我要试一试。
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;
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)));
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;