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;