使用std_logic_vector数组作为端口类型,两个范围都使用泛型

时间:2015-02-12 02:38:25

标签: vhdl

是否可以创建一个端口是std_logic_vectors数组的实体,数组的大小和std_logic_vector都来自泛型? IE浏览器。有可能创造例如。总线多路复用器的总线宽度和总线数是否可配置?

entity bus_multiplexer is
        generic (bus_width : positive := 8;
                sel_width : positive := 2);
        port (  i : in array(integer range 2**sel_width - 1 downto 0) of std_logic_vector(bus_width - 1 downto 0);
                sel : in std_logic_vector(sel_width - 1 downto 0);
                o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;

architecture dataflow of bus_multiplexer is
begin
        o <= i(to_integer(unsigned(sel)));
end dataflow;

上述似乎不起作用,因为需要单独定义数组类型。 在端口之前定义类型也不起作用,因为它期望实体定义在它之后结束。在端口定义之后定义它并不起作用,因为它在此之前被使用。在包中定义它并不起作用,因为类型定义似乎不喜欢在&#34;基类型&#34;中具有不受约束的范围。

有可能以某种方式在VHDL-93中执行此操作吗? (VHDL-2008怎么样?)

在包中定义类型为array(natural range <>, natural range <>) of std_logic - 如在端口定义中没有给出错误 - 但实际使用它如果它的定义方式似乎相当笨拙。

是否有一些理智的方式来使用它?是否有一些简单的方法可以将N个单独的std_logic_vectors映射到这样定义的端口,同样也可以用于实际的输出逻辑?

我尝试了原作o <= i(to_integer(unsigned(sel)), bus_width - 1 downto 0),但都没有奏效。我知道我可以一次做一点,但我更喜欢更简单的东西。虽然对于内部实现来说逐位方法可能没什么用,但我每次使用组件时都不希望为端口映射做这些...

是否有一些理智的(-ish)方式来做到这一点?

(附录:我知道有一些类似的问题,但是他们中的大多数都没有处理来自仿制药的两个范围的情况,并且使用包中的类型定义来解决。确实谈到两个通用维度显然并不需要来自不同的std_logic_vectors的输入,最终使用std_logic&#34;方法的&#34; 2d数组,这对我来说并不起作用(至少没有进一步澄清如何使用它而不会失去理智))

2 个答案:

答案 0 :(得分:6)

这适用于VHDL2008:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package bus_multiplexer_pkg is
        type bus_array is array(natural range <>) of std_logic_vector;
end package;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.bus_multiplexer_pkg.all;

entity bus_multiplexer is
        generic (bus_width : positive := 8;
                sel_width : positive := 2);
        port (  i : in bus_array(2**sel_width - 1 downto 0)(bus_width - 1 downto 0);
                sel : in std_logic_vector(sel_width - 1 downto 0);
                o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;

architecture dataflow of bus_multiplexer is
begin
        o <= i(to_integer(unsigned(sel)));
end dataflow;

它可以像这样使用:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.all;
use work.bus_multiplexer_pkg.all;

entity bus_multiplexer_4 is
        generic (bus_width : positive := 8);
        port (  bus0, bus1, bus2, bus3 : in std_logic_vector(bus_width - 1 downto 0);
                sel : in std_logic_vector(1 downto 0);
                o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer_4;

architecture structural of bus_multiplexer_4 is
        signal i : bus_array(3 downto 0)(bus_width - 1 downto 0);
begin
        i <= (0 => bus0, 1 => bus1, 2 => bus2, 3 => bus3);
        u: entity bus_multiplexer generic map (bus_width => bus_width, sel_width => 2) port map (i => i, sel => sel, o => o);
end;

但它不适用于VHDL93,因为您不能将std_logic_vector保留在类型定义中,如问题中所述。

不幸的是,我不知道如果没有带VHDL93的2d数组,是否有任何方法可以做任何类似的事情。

编辑:Paebbels的答案显示了如何使用2d数组在VHDL93中执行此操作,并使用自定义过程使其易于管理。由于他的例子非常大,这里也是同一概念的最小例子:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package bus_multiplexer_pkg is
        type bus_array is array(natural range <>, natural range <>) of std_logic;

        procedure slm_row_from_slv(signal slm : out bus_array; constant row : natural; signal slv : in std_logic_vector);
        procedure slv_from_slm_row(signal slv : out std_logic_vector; signal slm : in bus_array; constant row : natural);
end package;

package body bus_multiplexer_pkg is
        procedure slm_row_from_slv(signal slm : out bus_array; constant row : natural; signal slv : in std_logic_vector) is
        begin
                for i in slv'range loop
                        slm(row, i) <= slv(i);
                end loop;
        end procedure;

        procedure slv_from_slm_row(signal slv : out std_logic_vector; signal slm : in bus_array; constant row : natural) is
        begin
                for i in slv'range loop
                        slv(i) <= slm(row, i);
                end loop;
        end procedure;
end package body;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.bus_multiplexer_pkg.all;

entity bus_multiplexer is
        generic (bus_width : positive := 8;
                sel_width : positive := 2);
        port (  i : in bus_array(2**sel_width - 1 downto 0, bus_width - 1 downto 0);
                sel : in std_logic_vector(sel_width - 1 downto 0);
                o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer;

architecture dataflow of bus_multiplexer is
begin
        slv_from_slm_row(o, i, to_integer(unsigned(sel)));
end dataflow;

它可以像这样使用:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.all;
use work.bus_multiplexer_pkg.all;

entity bus_multiplexer_4 is
        generic (bus_width : positive := 8);
        port (  bus0, bus1, bus2, bus3 : in std_logic_vector(bus_width - 1 downto 0);
                sel : in std_logic_vector(1 downto 0);
                o : out std_logic_vector(bus_width - 1 downto 0));
end bus_multiplexer_4;

architecture structural of bus_multiplexer_4 is
        signal i : bus_array(3 downto 0, bus_width - 1 downto 0);
begin
        slm_row_from_slv(i, 0, bus0);
        slm_row_from_slv(i, 1, bus1);
        slm_row_from_slv(i, 2, bus2);
        slm_row_from_slv(i, 3, bus3);
        u: entity bus_multiplexer generic map (bus_width => bus_width, sel_width => 2) port map (i => i, sel => sel, o => o);
end;

答案 1 :(得分:1)

是的,这是可能的。

您使用二维数组的尝试很好,因为嵌套的一维数组在内部维度中需要固定大小。所以处理这样一个二维数组的方法是编写一些函数和程序,将二维数组转换为嵌套的一维向量。

我在这里回答了类似的问题:
  - Fill one row in 2D array outside the process (VHDL)
  - Creating a generic array whose elements have increasing width in VHDL

这是my vectors package

这是一个FIFO接口多路复用器的例子,它在数据宽度和输入计数方面都是可变的。它使用循环仲裁器来选择输入。

实体&#39; PoC.bus.Stream.Mux&#39;:

-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- 
-- ============================================================================
-- Authors:           Patrick Lehmann
-- 
-- License:
-- ============================================================================
-- Copyright 2007-2015 Technische Universitaet Dresden - Germany
--                     Chair for VLSI-Design, Diagnostics and Architecture
-- 
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
-- 
--    http://www.apache.org/licenses/LICENSE-2.0
-- 
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- ============================================================================

library IEEE;
use     IEEE.STD_LOGIC_1164.all;
use     IEEE.NUMERIC_STD.all;

library PoC;
use     PoC.config.all;
use     PoC.utils.all;
use     PoC.vectors.all;


entity Stream_Mux is
  generic (
    PORTS            : POSITIVE                  := 2;
    DATA_BITS        : POSITIVE                  := 8;
    META_BITS        : NATURAL                   := 8;
    META_REV_BITS    : NATURAL                   := 2
  );                 
  port (             
    Clock            : IN  STD_LOGIC;
    Reset            : IN  STD_LOGIC;
    -- IN Ports      
    In_Valid         : IN  STD_LOGIC_VECTOR(PORTS - 1 downto 0);
    In_Data          : IN  T_SLM(PORTS - 1 downto 0, DATA_BITS - 1 downto 0);
    In_Meta          : IN  T_SLM(PORTS - 1 downto 0, META_BITS - 1 downto 0);
    In_Meta_rev      : OUT T_SLM(PORTS - 1 downto 0, META_REV_BITS - 1 downto 0);
    In_SOF           : IN  STD_LOGIC_VECTOR(PORTS - 1 downto 0);
    In_EOF           : IN  STD_LOGIC_VECTOR(PORTS - 1 downto 0);
    In_Ack           : OUT STD_LOGIC_VECTOR(PORTS - 1 downto 0);
    -- OUT Port      
    Out_Valid        : OUT STD_LOGIC;
    Out_Data         : OUT STD_LOGIC_VECTOR(DATA_BITS - 1 downto 0);
    Out_Meta         : OUT STD_LOGIC_VECTOR(META_BITS - 1 downto 0);
    Out_Meta_rev     : IN  STD_LOGIC_VECTOR(META_REV_BITS - 1 downto 0);
    Out_SOF          : OUT STD_LOGIC;
    Out_EOF          : OUT STD_LOGIC;
    Out_Ack          : IN  STD_LOGIC
  );
end;

architecture rtl OF Stream_Mux is
  attribute KEEP               : BOOLEAN;
  attribute FSM_ENCODING       : STRING;

  subtype T_CHANNEL_INDEX is NATURAL range 0 to PORTS - 1;

  type T_STATE is (ST_IDLE, ST_DATAFLOW);

  signal State                 : T_STATE          := ST_IDLE;
  signal NextState             : T_STATE;

  signal FSM_Dataflow_en       : STD_LOGIC;

  signal RequestVector         : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
  signal RequestWithSelf       : STD_LOGIC;
  signal RequestWithoutSelf    : STD_LOGIC;

  signal RequestLeft           : UNSIGNED(PORTS - 1 downto 0);
  signal SelectLeft            : UNSIGNED(PORTS - 1 downto 0);
  signal SelectRight           : UNSIGNED(PORTS - 1 downto 0);

  signal ChannelPointer_en     : STD_LOGIC;
  signal ChannelPointer        : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
  signal ChannelPointer_d      : STD_LOGIC_VECTOR(PORTS - 1 downto 0)     := to_slv(2 ** (PORTS - 1), PORTS);
  signal ChannelPointer_nxt    : STD_LOGIC_VECTOR(PORTS - 1 downto 0);
  signal ChannelPointer_bin    : UNSIGNED(log2ceilnz(PORTS) - 1 downto 0);

  signal idx                   : T_CHANNEL_INDEX;

  signal Out_EOF_i             : STD_LOGIC;

begin
  RequestVector       <= In_Valid AND In_SOF;
  RequestWithSelf     <= slv_or(RequestVector);
  RequestWithoutSelf  <= slv_or(RequestVector AND NOT ChannelPointer_d);

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (Reset = '1') then
        State        <= ST_IDLE;
      else
        State        <= NextState;
      end if;
    end if;
  end process;

  process(State, RequestWithSelf, RequestWithoutSelf, Out_Ack, Out_EOF_i, ChannelPointer_d, ChannelPointer_nxt)
  begin
    NextState                 <= State;

    FSM_Dataflow_en           <= '0';

    ChannelPointer_en         <= '0';
    ChannelPointer            <= ChannelPointer_d;

    case State is
      when ST_IDLE =>
        if (RequestWithSelf = '1') then
          ChannelPointer_en    <= '1';

          NextState            <= ST_DATAFLOW;
        end if;

      when ST_DATAFLOW =>
        FSM_Dataflow_en        <= '1';

        if ((Out_Ack   AND Out_EOF_i) = '1') then
          if (RequestWithoutSelf = '0') then
            NextState          <= ST_IDLE;
          else
            ChannelPointer_en  <= '1';
          end if;
        end if;
    end case;
  end process;

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (Reset = '1') then
        ChannelPointer_d    <= to_slv(2 ** (PORTS - 1), PORTS);
      elsif (ChannelPointer_en = '1') then
        ChannelPointer_d    <= ChannelPointer_nxt;
      end if;
    end if;
  end process;

  RequestLeft         <= (NOT ((unsigned(ChannelPointer_d) - 1) OR unsigned(ChannelPointer_d))) AND unsigned(RequestVector);
  SelectLeft          <= (unsigned(NOT RequestLeft) + 1)    AND RequestLeft;
  SelectRight         <= (unsigned(NOT RequestVector) + 1)  AND unsigned(RequestVector);
  ChannelPointer_nxt  <= std_logic_vector(ite((RequestLeft = (RequestLeft'range => '0')), SelectRight, SelectLeft));

  ChannelPointer_bin  <= onehot2bin(ChannelPointer);
  idx                 <= to_integer(ChannelPointer_bin);

  Out_Data            <= get_row(In_Data, idx);
  Out_Meta            <= get_row(In_Meta, idx);

  Out_SOF             <= In_SOF(to_integer(ChannelPointer_bin));
  Out_EOF_i           <= In_EOF(to_integer(ChannelPointer_bin));
  Out_Valid           <= In_Valid(to_integer(ChannelPointer_bin)) and FSM_Dataflow_en;
  Out_EOF             <= Out_EOF_i;

  In_Ack              <= (In_Ack  'range => (Out_Ack   and FSM_Dataflow_en)) AND ChannelPointer;

  genMetaReverse_0 : if (META_REV_BITS = 0) generate
    In_Meta_rev    <= (others => (others => '0'));
  end generate;
  genMetaReverse_1 : if (META_REV_BITS > 0) generate
    signal Temp_Meta_rev : T_SLM(PORTS - 1 downto 0, META_REV_BITS - 1 downto 0)    := (others => (others => 'Z'));
  begin
    genAssign : for i in 0 to PORTS - 1 generate
      signal row  : STD_LOGIC_VECTOR(META_REV_BITS - 1 downto 0);
    begin
      row    <= Out_Meta_rev AND (row'range => ChannelPointer(I));
      assign_row(Temp_Meta_rev, row, i);
    end generate;
    In_Meta_rev    <= Temp_Meta_rev;
  end generate;
end architecture;