Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
494 views
in Technique[技术] by (71.8m points)

vhdl - Using array of std_logic_vector as a port type, with both ranges using a generic

Is it possible to create an entity with a port that is an array of std_logic_vectors, with both the size of the array and the std_logic_vector coming from generics? Ie. is it possible to create eg. a bus multiplexer with both the bus width and bus count configurable?

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;

The above doesn't seem to work because the array type needs to be defined separately. Defining the type before the port also does not work, as then it expects the entity definition to end after it. Defining it after the port definition doesn't work since it'd be used before that. Defining it in a package doesn't work because the type definition doesn't seem to like having an unconstrained range in the "base type".

Is it possible to somehow do this in VHDL-93? (What about VHDL-2008?)

Defining the type as array(natural range <>, natural range <>) of std_logic in the package works - as in the port definition doesn't give an error - but actually using it if it's defined that way seems to be quite unwieldy.

Is there some sane way to use it like this? Is there some simple way to map N separate std_logic_vectors to a port defined like that, and likewise for the actual output logic?

I tried the original and o <= i(to_integer(unsigned(sel)), bus_width - 1 downto 0), but neither worked. I know I could do it one bit at a time, but I'd prefer something simpler. And while the bit-by-bit -approach might be okay for the internal implementation, I certainly wouldn't want to have to do that for the port mapping every time I use the component...

Is there some sane(-ish) way to do this?

(Addendum: I know there are some similar questions, but most of them don't deal with the case of both ranges coming from generics, and were solved using a type definition in a package. The one that did talk about two generic dimensions apparently didn't need the input to come from distinct std_logic_vectors and ended up using the "2d-array of std_logic" method, which doesn't work for me (at least without further clarification about how to use it without losing one's sanity))

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This works with 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;

And it can be used like this:

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;

It doesn't work with VHDL93, however, because you can't leave the std_logic_vector unconstrained in the type definition, as stated in the question.

Unfortunately, I don't know if there's any way to do anything similar without 2d arrays with VHDL93.

Edit: Paebbels's answer shows how to do this in VHDL93 by using 2d arrays, with custom procedures to make it manageable. Since his example is quite big, here's also a minimal example of the same concept:

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;

And it can be used like this:

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;

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...