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?)
Related
I'm trying to return a word which is defined as:
subtype word is std_logic_vector(word_len - 1 downto 0);
By concatenating a whole bunch of other inputs from a record like so (this is inside a switch block):
return get_opc(ins.op) & std_logic_vector(ins.val) & "0000"; -- TODO Replace these with some sort of others construct
However, different opcodes have different sets of other inputs and so the amount that needs to be right-filled with zeroes changes. I'm not a huge fan of manually hardcoding trailing zeroes, it's a mess ad it won't play well if I resize my word.
My instinct was to try:
return get_opc(ins.op) & std_logic_vector(ins.val) & (others => '0');
But apparently you can't use others as an aggregate in this context.
I know I could create a buffer the size of a word, fill it with zeroes and then slot my different inputs into different slices but AFAIK, that would be extremely verbose, requiring me to specify the start and end point of each slice rather than just concatenating them on the left. This would soon get very messy.
Is there any easy way around this that keeps everything concise?
If you use VHDL-2008 (or VHDL-2019!), you can return an aggregate like this:
return (get_opc(ins.op), std_logic_vector(ins.val), others => '0');
This assumes that your return type is constrained. In other words, this is OK:
function F return word is
begin
return (get_opc(ins.op), std_logic_vector(ins.val), others => '0');
end function;
whereas if your return type is unconstrained like this, then it is not OK:
function F return std_logic_vector is
A lot of VHDL structures has the option for an optional_label before the declaration, but what is this label used for?
Here is a process declaration example from vdlande showing the option for a label:
optional_label: process (optional sensitivity list)
-- declarations
begin
-- sequential statements
end process optional_label;
Labels are used for identification.
IEEE1076-2008 for instance says
7.3.1 General
A configuration specification associates binding information with component labels representing instances of a given component declaration.
consider the next piece of code:
entity e is end entity;
architecture a of e is begin
process is begin wait; end process;
foo: process is begin wait; end process;
end architecture;
In simulation (with modelsim) this will show as
I.e. label foo is fixed, while the other process is just assigned some reference, in this case the line number. Is you are using attributes, configurations, aliases, etc, you often need to refer to specific objects and their location. You need fixed names for that.
If you look at the IEEE1076-2008 standard, you can see that about every statement can have a label: if, case, loop, etc.
You can use labels to identify things in a simulator as JHBonarius says, but there are other uses for labels, too:
i) Identifying the end of a long block of code, eg
my_if : if A = B then
-- lots of lines of code
end if my_if;
ii) keeping track of complicated code, eg
my_if_1 : if A = B then
my_if_2 : if A = B then
my_if_3 : if A = B then
my_if_4 : if A = B then
my_if_5 : if A = B then
my_if_6 : if A = B then
-- blah blah blah
end if my_if_6;
end if my_if_5;
end if my_if_4;
end if my_if_3;
end if my_if_2;
end if my_if_1;
iii) It is usually a good idea to label assertions so that they can be easily identified in an EDA tool, eg :
enable_check : assert enable = '1';
iv) If you label something, then you can decorate it with an attribute (ie attach some metadata for some other EDA tool), eg something like this might stop a synthesiser optimising something away:
attribute KEEP : boolean;
attribute KEEP of g0:label is TRUE;
...
g0 : CLK_EN port map ( ...
(The exact names will depend on the synthesiser.)
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;
Firstly here is what I'm aiming to do, using made-up VHDL syntax...
type type_johns_record is
first_element : std_logic;
second_element: std_logic_vector(3 downto 0);
third_element : boolean;
end record;
....
....
for ii in johns_record'range loop
if johns_record.type_johns_record'val(ii) = .... then
exit;
end if;
end loop;
Hopefully you can see that I'm trying to reference the elements of a record using similar syntax to that which can be used to reference an enumerated type. This however (of course) does not work. Is there a similar syntax that will work? My solution at the moment is to use a record_info field and work using std_logic_vectors as shown below....
type type_johns_record is record
first_element : std_logic;
second_element : std_logic_vector(3 downto 0);
third_element : boolean;
record_info : type_integer_array(2 downto 0);
end record;
function type_johns_record2slv(d : type_johns_record) return std_logic_vector is
begin
return (d.first_element & d.second_element & bool2sl(d.third_element));
end function;
constant johns_record_zero : type_johns_record := (first_element => '0',
second_element => "0000",
third_element => false,
record_info => (1, 4, 1));
-- can be used with any type for which a record_info is known
function get_record_element(input : std_logic_vector; element_number : integer; record_info : type_integer_array) return std_logic_vector is
variable r : type_slv32_array(record_info'length-1 downto 0);
variable pos : integer := 0;
begin
for ii in record_info'range loop
r(ii)(record_info(ii)-1 downto 0) := input(pos+record_info(ii)-1 downto pos);
end loop;
return r(element_number)(record_info(element_number)-1 downto 0);
end function;
I can then use these functions (which are in a package) as follows...
for ii in johns_record.record_info'range loop
if get_record_element(type_johns_record2slv(johns_record), ii, johns_record.record_info) = conv_std_logic_vector(4, johns_record.record_info(ii)) then
exit;
end if;
end loop;
This really sucks and specifying the record_info is error prone and only marginally less time consuming that writing out individual element comparisons line by line. Please offer a better solution!!!
In the IEEE VHDL Standards group, there are actually two proposals relating to this:
http://www.eda.org/twiki/bin/view.cgi/P1076/RecordMemberAttribute
and
http://www.eda.org/twiki/bin/view.cgi/P1076/RecordIntrospection
This does not mean relax, someone else will address the issue. Instead, we need you to comment on it and/or propose additional use models (to help with justification). All of our work is done by volunteers - just like you - no memberships required for basic participation. Much of our work is done on the TWIKI and email reflector and all with VHDL background are welcome to participate. Drop me an email, I will get you setup - see my Stack Exchange profile for details.
To participate, start here: http://www.eda.org/twiki/bin/view.cgi/P1076/
Current proposals:
http://www.eda.org/twiki/bin/view.cgi/P1076/CollectedRequirements
Meeting information:
http://www.eda.org/twiki/bin/view.cgi/P1076/MeetingMinutes
If you'd like to shorten your implementation code slightly, you could write a custom function for each record type (which you already have to do to convert to slv; this would just be a bit longer) that returns the nth element, like:
function get_record_element(input : johns_record_type; element_number : natural) return std_logic_vector is
begin
case element_number is
when 0 =>
return to_slv(input.first_element);
when 1 =>
return to_slv(input.second_element);
...
end function;
...
if get_record_element(johns_record, 2) = ... then
where to_slv is just a set of helper functions to convert other types. Is that more or less tedious than writing a more generic function and using an extra record element?
Instead of a record, then an array may be used, where the index value are based on an enumerated type, and the array elements are a super-set of the required type. Declaration like:
type johns_elements_t is (FIRST, SECOND, THIRD);
subtype johns_type_t is std_logic_vector(3 downto 0); -- Super-set of required types
type johns_array_t is array (johns_elements_t) of johns_type_t;
signal johns_array : johns_array_t;
Use is then like:
for johns_index in johns_array'range loop
if johns_array(johns_index) = "0000" then
exit;
end if;
VHDL attributes can be used to convert the values in the enumerated type between natural, like for example:
for natural_index in 0 to johns_elements_t'pos(johns_elements_t'high) loop
if johns_array(johns_elements_t'val(natural_index)) = "0000" then
Access to elements must then take into account how the contents is used for each elements accessed by the values in the enumerated type, but that is the case anyway when using a record, but now where is no type checking in the compiler. Another use case is:
if johns_array(FIRST)(0) = '1' then -- Used as std_logic
johns_array(FIRST)(0) <= '0';
...
In synthesis, the tool is likely to remove the unused bits in elements where only a subset of the bits are used, so the final design is not larger.
Also, some synthesis tools (for example Altera Quartus II) does not accept functions that return variable length results like std_logic_vector, so a solution for synthesis should taken that into account, since a functions like get_record_element may result in an error.
How do I write a code segment which would evaluate a generic and create (or not create) an attribute accordingly?
Example :
if G_MY_GENERIC then
attribute my_attribute_typ : string;
attribute my_attribute_typ of signal_having_an_attr : signal is "value";
else
--nothing is created
end if;
It is perfectly possible to write something similar to that, but the attribute will only be visible in the scope of the generate statement.
g_something: if test_condition generate
attribute my_attribute_typ : string;
attribute an_attribute of my_attribute_typ: signal is "value";
begin
-- attribute is visible in this scope
p_my_process: process(clk)
begin
-- attribute is also visible here
end process;
end generate;
-- but not here
Instead you have to use something like the following to conditionally set an attribute (cumbersome, but achieves the result):
signal asvRam : svRam_at(0 to gc_nFifoDepth-1) := (others => (others => '0'));
type svStr_at is array(boolean) of string(0 to 10);
constant c_svRamStyle : svStr_at := (false => " ", true => "distributed");
attribute ram_style : string;
attribute ram_style of asvRam : signal is c_svRamStyle(gc_bDistributedRam);
We talked more generalized conditional compilation in the IEEE VHDL Working Group. The debate was heated. Some wanted a compile time approach (similar to 'C') and some an elaboration time approach. Compile time approach works well in C because constants are also compile time objects, however, in VHDL, a compile time approach will not understand things in the VHDL environment, and hence, using a generic is not an option. OTOH, the compile time option would probably give you vendor name, tool type (simulator, synthesis, ...), ...
I have added your code as a requirement to the proposal page. It is at: http://www.eda.org/twiki/bin/view.cgi/P1076/ConditionalCompilation
If you are willing to share additional insight on your application, I would like to add that to the proposal also.
Basically: this is exactly how VHDL does not work. In VHDL you declare your intent to use specific bits of hardware, and then the synthesizer attempts to connect those bits of hardware. Any semblance of dynamically creating hardware like for ... generate loops are essentially just a semblance: syntactic sugar to take the pain away.
What you can do is conditionally assign to signals/variables:
process (sig1, sig2, enable) is
begin
if enable = '1'
then
out <= sig1;
else
out <= sig2;
end if;
end process;