我想创建一个通用多路复用器,这意味着它可以具有可变数量的输入和可变的 data_width。这意味着为了声明数据输入,我需要一个如下所示的数组:
type data is array(entries-1 downto 0) of std_logic_vector(data_width-1 downto 0);
但是,我不确定如何做到这一点。我对应该在哪里声明“数据”类型感到困惑,因为我必须在输入端口声明中使用它
您可以按如下方式实现通用多位复用器:
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
泛型。该函数是在传入升序范围数组的假设下编写的。降序数组仍然有效,但所选索引与选择控件的二进制值不匹配。选择控件通过该功能unsigned
自动配置为所需的大小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;
使用 VHDL-2008,您可以声明一个完全不受约束的类型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;
上面的泛型多路复用器依赖泛型(条目,data_width)来传达一维数组类型(在这种情况下为std_logic_vector)的分区信息,因为这些可以在实例化的地方知道:
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;
这样做的好处是不需要对多路复用器实例化的块可见的类型声明,也不需要依靠目前综合不普遍支持的 VHDL 2008 功能。
请注意,通用多路复用器使用数组类型声明和生成语句类型转换(通过信号分配)来创建实际的多路复用器。这反映了您将如何在内存上操作读取接口。它可以通过在进程中声明并分配给 outp 的变量来完成。
除了允许设计描述反映结构模型之外,实现实例化多路复用器几乎没有优势。综合工具要求所有选择都用一个案例语句、一个选定的信号分配或条件信号分配来表示。
仅对于组合多路复用操作,并且没有任何特殊的数据类型,那么这样的函数可能会很方便:
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
DATA_WIDTH基于指定条目的数量从整个长度派生而来。
为了使用,该函数可以作为并发函数调用来调用,例如:
dut_out <= mux(ENTRIES,
dut_sel,
dut_in_0 &
dut_in_1 &
dut_in_2);