【问题标题】:Creating a generic multiplexer创建通用多路复用器
【发布时间】:2014-07-05 18:32:53
【问题描述】:

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

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

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

【问题讨论】:

    标签: arrays generics types vhdl mux


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      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 =&gt; '0')。然后它可以安全地使用整数索引来提取选定的输入。存在别名是为了确保函数能够优雅地处理基于非 0 的数组。

      data 类型已定义为std_ulogic_vector 的无约束数组。 mux_data 函数将自动适应任何大小,而无需知道 entries 泛型。该函数是在传入升序范围数组的假设下编写的。降序数组仍然有效,但所选索引与选择控件的二进制值不匹配。 unsigned 选择控件通过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);
      

      【讨论】:

        【解决方案3】:

        您可以在没有特定数据数组类型的端口元素的情况下实现多路复用器:

        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。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-10-12
          • 2016-04-30
          • 2016-04-17
          • 1970-01-01
          • 2012-10-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多