3

This has me bugging for quite some time, but is it possible to describe entities in VHDL similar to how templates work in C++ (or to lesser extend generics?). Simply leaving the actual port types to be only decided during synthesize/compilation?

An example would be a multiplexer, say I have a 4 input multiplexer, now I have several bus sizes I use this multiplexer for, -4,6,7,8-. Currently I wrote a different multiplexer for each different bus size; however the output is simply one of the chosen inputs forwarded, and is thus of the same type as the bus.

This seems overly redundant and error prone (choose correct multiplexer at correct times, keep them all in line, update them as I change the bus size). Is there no way to parameterize this?

non generic version below to show the idea.

entity mux_6bit_4input is
    port (  input_0 : in    std_logic_vector (5 downto 0);
        input_1 : in    std_logic_vector (5 downto 0);
        input_2 : in    std_logic_vector (5 downto 0);
        input_3 : in    std_logic_vector (5 downto 0);
        sel : in    std_logic_vector (1 downto 0);
        output  : out   std_logic_vector (5 downto 0)
    );
end entity mux_6bit_4input;
wap26
  • 2,180
  • 1
  • 17
  • 32
paul23
  • 8,799
  • 12
  • 66
  • 149

2 Answers2

5

Maybe I misunderstood the question, but doesn't the common solution using generics solve your problem?

library ieee;
use ieee.std_logic_1164.all;

entity mux_4x1 is
    generic (
        DATA_WIDTH: integer := 8
    );
    port (
        input_0: in std_logic_vector(DATA_WIDTH-1 downto 0);
        input_1: in std_logic_vector(DATA_WIDTH-1 downto 0);
        input_2: in std_logic_vector(DATA_WIDTH-1 downto 0);
        input_3: in std_logic_vector(DATA_WIDTH-1 downto 0);
        sel: in std_logic_vector (1 downto 0);
        output: out std_logic_vector(DATA_WIDTH-1 downto 0)
    );
end;

architecture behavior of mux_4x1 is
begin
    output <=
        input_0 when sel = "00" else
        input_1 when sel = "01" else
        input_2 when sel = "10" else
        input_3;
end;

Another solution, if you want to keep things really generic, is to use the cool generic types in VHDL-2008. My simulator doesn't yet support this feature, so here's an example from the excellent book VHDL 2008: Just the New Stuff:

entity generic_mux2 is
    generic (type data_type);
    port (
        sel: in bit;
        a, b: in data_type;
        z: out data_type
    );
end;

architecture rtl of mux2 is
begin
    z <= a when sel = '0' else b;
end;
rick
  • 1,626
  • 11
  • 18
  • You state your simulator doesn't support this. Is support by synthesizers also important or is the type ignored anyways during synthesis? – paul23 Nov 28 '13 at 16:22
  • I'm using Modelsim ASE 10.1b for simulation and Quartus II 12.1 for synthesis. These versions don't supports generic types, though both tools will probably do it eventually. Regarding your comment, note that the type is not "ignored", you just get an opportunity to specify it at a later time, when the component gets instantiated. Support by synthesizers is also important IMO, and in this case it shouldn't be too hard; it doesn't matter whether you're a simulator or a synthesizer, all you have to do is substitute the generic type with the actual type. – rick Nov 28 '13 at 20:38
  • with ignored I mean like how synthesizers ignore the delays, might've been that synthesizers would also ignore all type information anyways and simply use the minimal bus size. (Doesn't it ignore half the std_logic information already?) – paul23 Nov 29 '13 at 00:26
  • Not really, those types are *really* generic: the same code will work on std_logic_vectors, integers, custom data types that you create, you name it. The difference doesn't have to be in the bus size only. The synthesizer will create a different implementation for each type, if it has to. – rick Nov 29 '13 at 01:36
4

Another option is to use unconstrained arrays:

entity mux_4input is
    port ( 
        input_0 : in    std_logic_vector ;
        input_1 : in    std_logic_vector ;
        input_2 : in    std_logic_vector ;
        input_3 : in    std_logic_vector ;
        sel     : in    std_logic_vector (1 downto 0);
        output  : out   std_logic_vector
    );
end entity mux_4input;

They will inherit their width (and direction) from the signals they are conencted to in the instantiating entity.
It's probably not the right thing to do in this particular case of a mux, rick's answer is what I'd go for, but unconstrained arrays don't get mentioned much, so I thought I'd offer them! In this case, you'd probably also want some asserts to ensure that everything you've wired up is the same width.

Martin Thompson
  • 16,395
  • 1
  • 38
  • 56
  • I like this solution. Unconstrained arrays are often the best way to keep your code generic and clean at the same time. – rick Nov 26 '13 at 12:18
  • I didn't know this was possible, thanks Martin. Any pitfalls to avoid when using unconstrained arrays like this? – Russell Nov 26 '13 at 12:29
  • 1
    @Russell: One problem I already allude to - if you have multiple things which need to be the same width, the `generic` approach means you don't have to put your own asserts in. Another is that if you want to do a trial synthesis of a submodule, you have to create a wrapper for it to tell the synthesiser how wide the ports are that you want to trial. Other than that, I haven't come across any problems over the last few year when I started doing it. It probably didn't used to synthesise, and so didn't get much use, so some of the textbooks don't talk about it, so it doesn't get used :) – Martin Thompson Nov 27 '13 at 09:30