创建一个通用复用器

3

我希望创建一个通用复用器,意味着它可以具有可变数量的输入和可变数据宽度。这意味着对于声明数据输入,我需要一个数组,它看起来像这样:

type data is array(entries-1 downto 0) of std_logic_vector(data_width-1 downto 0);

然而,我不确定如何实现这一点。我对于在哪里声明类型“data”感到困惑,因为我必须在输入端口声明中使用它。

3个回答

4
您可以按照以下方式实现通用的多位选择器:
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函数。通过这种方式,逻辑将适应于entriesdata_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);

1

您可以实现一个多路复用器,而无需端口元素具有特定的数据数组类型:

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;

上述通用的复用器依赖于泛型(entries, 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功能。
请注意,通用复用器使用数组类型声明和生成语句类型转换(通过信号分配)来创建实际的多路复用器。这反映了如何在内存上操作读接口。它也可以通过在进程中声明变量并将其分配给输出来完成。
实例化复用器的实现除了允许设计描述反映结构模型之外,几乎没有优势。综合工具要求所有选择都表示为case语句、选择信号分配或条件信号分配。

0

仅用于组合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);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接