How to make this code generic?

T

Thoma

Hi all,

I am new with possibility of the VHDL "generic" keyword.
I tried to make the below code generic.

Do you think this is possible?
If yes, this would allow me to make a number of my descriptions
customizable.

Does anyone have a solution? An example?

Thank you in advance.

Thoma

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity barrelshifter is
Port ( entrance : in STD_LOGIC_VECTOR (3 downto 0);
selection : in STD_LOGIC_VECTOR (3 downto 0);
sortie : out STD_LOGIC_VECTOR (3 downto 0));
end barrelshifter;

architecture Behavioral of barrelshifter is

signal internal : std_logic_vector(6 downto 0);

begin
internal <= entrance(2 downto 0) & entrance;
sortie <= internal(3 downto 0) when (selection(0) = '1') else
internal(4 downto 1) when (selection(1) = '1') else
internal(5 downto 2) when (selection(2) = '1') else
internal(6 downto 3);
end Behavioral;
 
K

KJ

Hi all,

I am new with possibility of the VHDL "generic" keyword.
I tried to make the below code generic.

Do you think this is possible?
If yes, this would allow me to make a number of my descriptions
customizable.

Does anyone have a solution? An example?

Thank you in advance.

Thoma

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity barrelshifter is
    Port ( entrance : in  STD_LOGIC_VECTOR (3 downto 0);
           selection : in  STD_LOGIC_VECTOR (3 downto 0);
           sortie : out  STD_LOGIC_VECTOR (3 downto 0));
end barrelshifter;

architecture Behavioral of barrelshifter is

signal internal : std_logic_vector(6 downto 0);

begin
  internal <= entrance(2 downto 0) & entrance;
  sortie <= internal(3 downto 0) when (selection(0) = '1') else
            internal(4 downto 1) when (selection(1) = '1') else
                                internal(5 downto 2) when (selection(2) = '1') else
            internal(6 downto 3);
end Behavioral;

I'm not exactly sure how you want to parameterize this. I'm guessing
that that the width of all of the I/O would be one parameter.
Assuming...

entity barrelshifter is
generic(Width: in positive)
Port ( entrance : in STD_LOGIC_VECTOR (Width - 1 downto 0);
selection : in STD_LOGIC_VECTOR (Width - 1 downto 0);
sortie : out STD_LOGIC_VECTOR (Width - 1 downto 0));
end barrelshifter;

Then parameterize the width of 'internal'

signal internal : std_logic_vector(Width - 2 downto 0);

Then go through your signal assignments and replace '3' with 'Width -
1'; '4' with 'Width', etc.

Kevin Jennings
 
A

Andy

In general, parameterizable code cannot contain long if-then-elsif
trees or case statements, because they are fixed by their very nature.

You need to re-write the tree in the form of a loop that indexes over
the parameterizable signal(s), and calculates the other indices off of
the loop index. The loop may contain if-statements, but they can't
have anything to do with indexes into paramerizable signals.

You can also use unconstrained ports (no range specified in the port,
each port on each instance takes its width from the signal mapped to
it). Then you can use pre-defined attributes like 'length or 'range to
create loops or matching width internal signals. You may have to
include concurrent assertion statements to make sure that different
ports are sized appropriately if they have to match.

Andy
 
T

Thoma

Hi Kevin,

entity barrelshifter is
Generic ( width : in positive );
Port ( entrance : in STD_LOGIC_VECTOR (width - 1 downto 0);
selection : in STD_LOGIC_VECTOR (width - 1 downto 0);
sortie : out STD_LOGIC_VECTOR (width - 1 downto 0));
end barrelshifter;

architecture Behavioral of barrelshifter is

signal internal : std_logic_vector(2 * (width - 1) downto 0);

begin
internal <= entrance(width - 2 downto 0) & entrance;

-- My problem lies here:

-- If width = 4
sortie <= internal(3 downto 0) when (selection(0) = '1') else
internal(4 downto 1) when (selection(1) = '1') else
internal(5 downto 2) when (selection(2) = '1') else
internal(6 downto 3);

-- But if width = 6
sortie <= internal(5 downto 0) when (selection(0) = '1') else
internal(6 downto 1) when (selection(1) = '1') else
internal(7 downto 2) when (selection(2) = '1') else
internal(8 downto 3) when (selection(3) = '1') else
internal(9 downto 4) when (selection(4) = '1') else
internal(10 downto 5);

end Behavioral;

I do not know how to make the 'sortie' expression generic.
Have you some tips?

Thoma
 
C

Charles Gardiner

Hi Thoma,

you can also use so called "unconstrained types". The beauty being that
the vector widths are decided by the hierarchical layer in which the
unit is instantiated. The vector width can in fact be propagated through
multiple levels.
You generally cannot do this on the top level by the way, at least not
if you want to synthesise it. Synthesis tools must map the vectors to
physical pins somehow.


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity barrelshifter is
Port ( entrance : in STD_LOGIC_VECTOR;
selection : in STD_LOGIC_VECTOR;
sortie : out STD_LOGIC_VECTOR );
end barrelshifter;

architecture Behavioral of barrelshifter is

-- Not sure that meets your intention, but something similar anyway
signal internal : std_logic_vector((2 * entrance'length) - 2 downto 0);

begin
-- check for correct usage. Many simulators will fail during
-- elaboration anyway if they detect a width assignment problem
assert entrance'length > 3 report "Input vector too small"
severity failure;

process(entrance)
variable v_entrance : std_logic_vector(entrance'length - 1 downto
0);
begin
-- Covers the case that entrance is not 'n' downto 0
v_entrance := entrance;
internal <= v_entrance(v_entrance'left - 2 downto 0) & v_entrance;
end process;

sortie <= internal(sortie'length - 1 downto 0)
when (selection(0) = '1') else
internal(sortie'length downto 1)
when (selection(1) = '1') else
internal(sortie'length + 1 downto 2)
when (selection(2) = '1') else
internal(sortie'length + 2 downto 3);
end Behavioral;
 
K

KJ

Hi Thoma,

you can also use so called "unconstrained types". The beauty being that
the vector widths are decided by the hierarchical layer in which the
unit is instantiated. The vector width can in fact be propagated through
multiple levels.

The catch to using unconstrained type is that you also need to then
add additional code to test and verify that it works with 'unexpected'
vector ranges when instantiated. The downside to using unconstrained
vectors in the OP's case are:

- Additional code is typically needed to 'normalize' the vectors,
converting any vectors that are (0 to n) into (n downto 0) for example
if that's how the rest of the code is expecting them. Typically that
code would be more typing than the additional amount of typing in the
entity to explicitly define the vector size and direction.
- Additional code is typically required to make sure that vectors that
have size relationships do in fact have them. In the OP, 'entrance',
'selection' and 'sortie' all need to be of the same size so the
architecture would typically have to have this check as an assertion.
Again, this is more typing then by defining the vector size and
direction in the entity.
- If you don't add the additional code to handle the above bullets,
then you've created a potential problem for some user down the
road...long after you (or whoever wrote it) has forgotten the detailed
dependencies and will now need to (re)discover them.
- Any usage errors don't get caught until you start the simulation as
opposed to being caught as soon as you compile the file...wasted time
and potentially more rework to other code because the problem gets
caught later.
- Usage of the entity by someone else (or the same person later down
the road) is less clear because relationships that are expected (i.e.
the above mentioned vector directions and vector size relationships)
are buried in the architecture either explicitly in assertions (if
that extra code was added) or implicitly because the sim crashes. I'd
much rather have those relationships explicitly defined on the entity
and not have to wade through somebody's code trying to discover what
they are.

The above mentioned downsides are neatly avoided by defining a generic
and then defining the vector sizes all in the entity. The only
downside to that approach is to the user of the entity in that they
must now specify the value for the generic. This can easily be
handled cleanly by specifying that value by use of the 'length
attribute. In the OP's case, proper use of the entity would be of the
following form and would work regardless of changes in size of the
vectors.

The_Shifter : entity work.barrelshifter
generic map(Width => entrance'length)
Port map(entrance => entrance,
selection => selection,
sortie => sortie);

Unless you can prove your design works with all abuses of vector
directions and sizes you should probably limit it to the forms that
you have tested and verified and make it easy on the user by defining
the tested relationships right on the entity via generics and
explicitly defined vector sizes and directions. If you want to go the
extra mile and insure that it works with all forms, go for it...but
also first yourself if that extra work is within the scope of what the
boss is paying for right now or if this is something that is only
important to you...and why? When starting from scratch, most entities
will not benefit and simply incur costs now (extra time) and later
(rediscovering implicit assumptions).

In my opinion, this particular case is probably not a good use of
unconstrained types because it creates additional work with no
benefit...ask yourself, what's the upside here?

Kevin Jennings
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top