创建通用多路复用器

时间:2014-05-17 09:58:51

标签: arrays generics types vhdl mux

我想创建一个通用的多路复用器,这意味着它可以有可变数量的输入和可变的data_width。这意味着为了声明数据输入,我需要一个如下所示的数组:

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

但是,我不确定如何才能做到这一点。我很困惑,我应该在哪里声明类型“数据”,因为我必须在输入端口声明中使用它

3 个答案:

答案 0 :(得分:3)

您可以按如下方式实现通用多位多路复用器:

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泛型。该函数是在假设传入上升范围数组的情况下编写的。降序数组仍然有效,但选定的索引将与select控件的二进制值不匹配。 unsigned选择控件自动配置为ceil_log功能所需的大小。通过这种方式,逻辑将适应entriesdata_width的任何值。对于怀疑者来说,这个合成。

在端口上放置data类型的信号是不可能的(在VHDL-2008之前),因为它需要使用泛型设置的约束来声明。处理此问题的标准方法是将输入展平为一维数组:

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 :(得分: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;

上面的通用mux反而依赖于泛型(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功能。

请注意,通用mux使用数组类型声明和生成语句类型转换(通过信号分配)来创建实际的多路复用器。这反映了如何在内存上操作读取接口。它可以通过在进程中声明的变量来完成,分配给outp。

除了允许设计描述反映结构模型之外,实现实例化多路复用器几乎没有什么优势。综合工具要求所有选择都在case语句,选定的信号分配或条件信号分配中表示。

答案 2 :(得分:0)

仅适用于组合多路复用操作,且没有任何特殊的数据类型, 那么像这样的函数可能很方便:

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);