我希望创建一个通用复用器,意味着它可以具有可变数量的输入和可变数据宽度。这意味着对于声明数据输入,我需要一个数组,它看起来像这样:
type data is array(entries-1 downto 0) of std_logic_vector(data_width-1 downto 0);
然而,我不确定如何实现这一点。我对于在哪里声明类型“data”感到困惑,因为我必须在输入端口声明中使用它。
type data is array(natural range <>) of
std_ulogic_vector(data_width-1 downto 0);
--## Compute the integer result of the function ceil(log(n))
--# where b is the base
function ceil_log(n, b : positive) return natural is
variable log, residual : natural;
begin
residual := n - 1;
log := 0;
while residual > 0 loop
residual := residual / b;
log := log + 1;
end loop;
return log;
end function;
function mux_data(Inputs : data; Sel : unsigned)
return std_ulogic_vector is
alias inputs_asc : data(0 to Inputs'length-1) is Inputs;
variable pad_inputs : data(0 to (2 ** Sel'length) - 1);
variable result : std_ulogic_vector(inputs_asc(0)'range);
begin
assert inputs_asc'length <= 2 ** Sel'length
report "Inputs vector size: " & integer'image(Inputs'length)
& " is too big for the selection vector"
severity failure;
pad_inputs := (others => (others => '0'));
pad_inputs(inputs_asc'range) := inputs_asc;
result := pad_inputs(to_integer(Sel));
return result;
end function;
signal mux_in : data(0 to entries-1);
signal mux_out : std_ulogic_vector(data_width-1 downto 0);
signal mux_sel : unsigned(ceil_log(entries, 2)-1 downto 0);
...
mux_out <= mux_data(mux_in, mux_sel);
mux_data
函数的工作原理是创建一个临时数组pad_inputs
,该数组保证为2的幂且大于或等于条目数。它将输入复制到此数组中,任何未使用的位置都默认为(others => '0')
。然后可以安全地使用整数索引来提取所选的输入。别名存在是为了确保函数优雅地处理非0基础数组。
类型data
已定义为std_ulogic_vector
的无约束数组。 mux_data
函数将自动适应任何大小,而不需要知道entries
通用参数。该函数的编写是基于传入升序范围数组的假设。降序数组仍将工作,但所选索引将不匹配选择控件的二进制值。无符号的选择控件会自动配置为所需大小,使用ceil_log
函数。通过这种方式,逻辑将适应于entries
和data_width
的任何值。对于那些怀疑者,这个将综合。
在VHDL-2008之前,不可能将类型为data
的信号放在端口上,因为它需要使用通用约束进行声明。处理此问题的标准方法是将您的输入展平为一维数组:
port (
mux_in_1d : std_ulogic_vector(entries*data_width-1 downto 0);
...
);
...
-- Expand the flattened array back into an array of arrays
process(mux_in_1d)
begin
for i in mux_in'range loop
mux_in(i) <= mux_in_1d((i+1)*data_width-1 downto i*data_width);
end loop;
end process;
data
并在端口上使用它。-- Declare this in a package
type data is array(natural range <>) of std_ulogic_vector;
...
port (
mux_in : data(0 to entries-1)(data_width-1 downto 0);
...
);
...
-- Substitute this line in the mux_data function
variable pad_inputs : data(0 to (2 ** Sel'length) - 1)(inputs_asc(0)'range);
您可以实现一个多路复用器,而无需端口元素具有特定的数据数组类型:
library ieee;
use ieee.std_logic_1164.all;
entity generic_mux is
generic (
entries: natural := 3;
data_width: natural := 8
);
port (
signal inp: in std_logic_vector (entries*data_width-1 downto 0);
signal sel: in natural range 0 to entries-1;
signal outp: out std_logic_vector (data_width-1 downto 0)
);
end entity;
architecture foo of generic_mux is
type mux_array is array (natural range 0 to entries-1) of
std_logic_vector(outp'range);
signal array_val: mux_array;
begin
GEN: for i in array_val'range generate
array_val(i) <= inp (outp'LEFT+(i*data_width) downto i*data_width);
end generate;
outp <= array_val(sel);
end architecture;
library ieee;
use ieee.std_logic_1164.all;
entity instantiation is
end entity;
architecture foo of instantiation is
constant entries: natural := 4;
constant data_width: natural := 8;
signal a: std_logic_vector (data_width-1 downto 0) := X"FE";
signal b: std_logic_vector (data_width-1 downto 0) := X"ED";
signal c: std_logic_vector (data_width-1 downto 0) := X"FA";
signal d: std_logic_vector (data_width-1 downto 0) := X"CE";
signal sel: natural range 0 to 3;
signal inp: std_logic_vector (entries*data_width-1 downto 0);
signal outp: std_logic_vector (data_width-1 downto 0);
begin
inp <= d & c & b & a;
MUX: entity work.generic_mux
generic map (entries => 4)
port map (
inp => inp,
sel => sel,
outp => outp
);
STIMULUS:
process
begin
for i in 1 to entries-1 loop
wait for 10 ns;
sel <= i;
end loop;
wait for 10 ns;
wait;
end process;
end architecture;
仅用于组合MUX操作,并且没有任何特殊数据类型,那么可以使用以下函数:
function mux(constant ENTRIES : natural;
sel : std_logic_vector;
data : std_logic_vector) -- Data for sel = 0 at left position
return std_logic_vector is
constant DATA_WIDTH : natural := data'length / ENTRIES;
alias data_norm : std_logic_vector(0 to data'length - 1) is data;
type data_split_t is array (0 to ENTRIES - 1) of std_logic_vector(0 to DATA_WIDTH - 1);
variable data_split_v : data_split_t;
variable res_v : std_logic_vector(0 to DATA_WIDTH - 1);
begin
for i in 0 to ENTRIES - 1 loop
data_split_v(i) := data(i * DATA_WIDTH to (i + 1) * DATA_WIDTH - 1);
end loop;
res_v := data_split_v(to_integer(unsigned(sel)));
return res_v;
end function;
DATA_WIDTH从整个data
长度中派生,基于指定条目的数量。
对于使用,该函数可以作为并发函数调用,例如:
dut_out <= mux(ENTRIES,
dut_sel,
dut_in_0 &
dut_in_1 &
dut_in_2);