What I want to do doesn't seem particularly complex, but I can't think of a simple way to do it in VHDL.
I have a component with a generic parameter called FOO. I would like to generate 16 of these components and for the first 8 instances I want FOO to be set to 0 and the other 8 instances I want FOO to be set to 4096.
Ideally, I would be able to do something like this:
generate_loop: for I in 0 to 15 generate
begin
comp_inst: my_component
generic map
(
FOO => 0 when I < 8 else 4096
)
port map
(
...
);
end generate;
This is of course not valid VHDL, but that captures the idea of what I'd like to do.
So my question is: is there a way to implement this in a single generate loop (i.e. without having to have 2 separate generate loops with different indices), and if so, how do I do it?
As user1155120 mentions in the comments, the base type of a for-loop is a universal integer. The fractional part of an integer division will be truncated. You can use this fact to realize your specific system, as
for 0<=i<8, i/8=0
for 8<=i<15, i/8=1
Thus the code could be
generate_loop: for I in 0 to 15 generate
begin
comp_inst: entity work.my_component
generic map (FOO => 4096 * (I/8))
port map (
...
);
end generate;
Alternatively, especially useful for more complex situations, you could do what Brian Drummond suggested: write a function
architecture arch of ent is
function gen_FOO(I : natural) return natural is begin
if I<8 then
return 0;
else
return 4096;
end if;
end function;
begin
generate_loop: for I in 0 to 15 generate
begin
comp_inst: entity work.my_component
generic map (FOO => gen_FOO(I))
port map (
...
);
end generate;
Related
Simply put, I have a component " X " and I want to connect 24 of them in a row; obviously means that the output of one is the input of the next one; I could just write them myself with copypaste and link them but I wonder if there is a way to do this elegantly.
I know the instruction for I in N downto 0 generate but I don't think I can use it to create components in series, it only creates components in parallel, where each one works on a different value of the I parameter, or not ?
The generate statement is indeed what you need. Example if your X component has one input a and one output b of type bit:
entity bar is
end entity bar;
architecture rtl of bar is
signal c: bit_vector(0 to 24);
component x is
port(
a: in bit;
b: out bit
);
end component x;
begin
u0: for i in 0 to 23 generate
x0: x
port map(
a => c(i),
b => c(i+1)
);
end generate u0;
end architecture rtl;
The input of the first X instance is c(0) and the output of the last one is c(24).
Is it possible to group related constants together inside of packages?
What I want to do is to have generic constants but then grouped together with related constants and types. In software like Python this could be done with package inside of package or class to group constants together.
What I want to do is something like this:
library constants;
...
if (some_signal = constants.group_a.SOME_CONSTANT_VALUE) then
...
end if;
Reader can see where the constant is coming from like here group_a.
If I understand the question well you can use records inside your package
package ex_pkg is
type constants_group_1_t is record
CONSTANT1 : integer;
CONSTANT2 : integer;
CONSTANT3 : integer;
CONSTANT4 : integer;
end record constants_group_1_t;
constant constant_group1 : constants_group_1_t := (
CONSTANT1 => 1,
CONSTANT2 => 2,
CONSTANT3 => 3,
CONSTANT4 => 4
);
end package;
then you can use it as
liberary work;
...
if some_integer = work.ex_pkg.constants_group1.CONSTANT1 then
end if;
so basically you declare a new record type containing all the constants that you want to use, which can be any of your chosen types, then creating a constant of the newly created type and assign for each field its value. You can then access it like "record.field" moreover you can define a record of records for as deep abstraction as you want.
I want to know if it is possible to convert a enum type, like FSM states to std_logic_vector or integer. I'm doing a testbench with OSVVM for a FSM and I want to use the scoreboard package to automatically compare the expected state with the actual one.
Thanks!
To convert to integer, use:
IntVal := StateType'POS(State) ;
From there, it is easy to convert to std_logic_vector, but I prefer to work with integers when possible as they are smaller in storage than std_logic_vector. For verification, it will be easier if you start to think more about integers when the value is less than 32 bits.
If you need it as std_logic_vector, using only numeric_std you can:
Slv8Val := std_logic_vector(to_unsigned(IntVal, Slv8Val'length)) ;
For verification, I liberally use numeric_std_unsigned, so the conversion is a easier:
Slv8Val := to_slv(IntVal, Slv8Val'length) ;
In the event you have an integer and want to convert it back to a enumerated value, you can use 'VAL.
State := StateType'VAL(IntVal) ;
In OSVVM, we use records with resolved values to create a transaction interface. We have a resoled types for integers (osvvm.ResolutionPkg.integer_max). We transfer enumerated values through the record using 'POS (as we put it in) and 'VAL (as we get it out).
Note don't confuse 'VAL with 'VALUE. 'VALUE converts a string to a value - opposite to 'IMAGE.
You of course learn all of this in SynthWorks' OSVVM class :).
Maybe like this...
function my_func(inp : t_my_enum) return integer is
begin
case inp is
when stateA =>
return 1;
when stateB =>
return 2;
when others =>
return 0;
end case;
end function my_func;
... <= my_func(stateB);`
How can one handle this case:
entity foo is
generic (
num_instances : natural := 8
);
port (
data_in_per_instance : in std_logic_vector(num_instances-1 downto 0);
data_out_per_instance : out std_logic_vector(num_instances-1 downto 0)
);
end foo;
architecture bar of foo is
component do_stuff is
port(
din : in std_logic;
dout : out std_logic
);
end component do_stuff;
signal sig_per_instance : std_logic_vector(num_instances-1 downto 0);
begin
L1: for i in 0 to num_instances-1 generate
L2: do_stuff
port map(
din => data_in_per_instance(i),
dout => data_out_per_instance(i)
);
end generate;
end bar;
The problem here is that if num_instances is reduced to 0 there will be an error when the signal ranges (num_instances-1 downto 0) are evaluated....
Is there an elegant way around this? All I can come up with is using a function like max(num_instances-1,0) to prevent this problem (but then synthesis may not give me exactly what I want, i.e. nothing).
Is there some way to handle this case a little more seamless?
A simple answer is to wrap the for-generate statement in an if-generate, if num_instances /= 0 generate ... Unfortunately if-generates have no else part, however there is nothing to stop you adding a second if num_instances = 0 generate ... statement to handle that special case.
Alternatively you can wrap the problem part of the for-generate using if-generate.
EDIT: re the need for a correct signal declaration guarded by the if ... generate.
AHA! You may have discovered a legitimate use for VHDL's (in my experience) rarely used "block" statement!
A block statement may contain signal declarations, and can be wrapped in a generate.
So this is valid VHDL:
Normality : block is
-- signal declarations here
begin
-- concurrent code here
end block Normality;
and it can be legally wrapped in a generate statement...
A std_logic_vector with an empty range (for example 3 downto 4) is perfectly legitimate - it's called a "null range" by the LRM. If you create one, then (at least with Modelsim) you will get warnings, which is usually considered poor form. To eliminate those, then Brian's block suggestion is what you'll have do.
Similarly the for..generate will result in an empty loop and no instances. No warnings for this.
I'm intrigued why you'd want a block with no instances in? I'd make num_instances a positive to force at least one of them, but that may not actually what you want!
I am wondering if it is possible to use a variable inside a generate statement.
signal bitmap_nodes : std_logic_vector(0 to NB_NODES-1) := (others => '0');
CIRCULAR: if (CLOCKWISE = 0) generate
variable index : integer := 0;
begin
GENERATE_NODE : for i in NB_NODES-1 to 0 generate
begin
node_inst: node
port map (
rx_bitmap => bitmap_nodes(index)
);
-- Increment index
index := index + 1;
end generate GENERATE_NODE;
end generate CIRCULAR;
Here, the variable is only used for the vector slicing. What it will do is assign the following (assume NB_NODES equals 4):
NODE0 -> bitmap_nodes(3)
NODE1 -> bitmap_nodes(2)
NODE2 -> bitmap_nodes(1)
NODE3 -> bitmap_nodes(0)
That seems to be the same as:
LAST: if (i = 0) generate
firstnode : node
port map (
rx_bitmap => bitmap_nodes(NB_NODES-1)
);
end generate LAST;
isn't it?
EDIT:
I'm still not clear why you'd like to do this, but you can (post-VHDL87) put a shared variable in this area (you can treat it much like the part between architecture and begin). Remember that shared variables have to be of a protected type if you're not going to have all sorts of problems with race conditions.
However, you can't increment a variable like you are doing as the generate statement has to be populated with concurrent statements (and variable assignments aren't).
Again, I'd be really interested to see an example where this functionality is necessary (or is it more of an academic question?)