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;
Related
I'm watching a beginner tutorial on VHDL. The lecturer says that it's bad practice to not include an else-condition inside a "process" block because it will create a latch and is bad for timing in advance circuits. He said that including an else-condition will create a mux instead and is better to use in most case.
Why is that?
snippet from lecture video
Why is a latch design bad for timing and what makes the mux design better?
The point is to make VHDL code that results in the design you want, and the risk is that you will inadvertently create a latch.
There are several basic constructions in VHDL, that can illustrate this.
Mux by process with if-then-else, can be made with this code:
process (all) is -- Mux
begin
if sel = '0' then
z <= a;
else
z <= b;
end if;
end process;
Mux by process with if-then and default assign, can be made with this derived code:
process (all) is -- Mux
begin
z <= b; -- Default b, thus for sel = '1', since no overwrite
if sel = '0' then
z <= a;
end if;
end process;
However, if you want to make a mux, then a better coding style is by continuous assign with this code:
z <= a when (sel = '0') else b;
Finally, what can lead to a latch with a process, is if the resulting output is not assigned in all branches of the code. That can occur, if the if-then does neither have an else, nor a default assign to the output, like this code:
process (all) is -- Latch
begin
if en = '1' then
q <= d;
end if;
end process;
So a good rule when designing combinatorial logic using a process, is to have an initial line that makes a default assignment to the resulting output, for example just assing undefined 'X'. A latch is thereby avoided, and functional verification should catch the undefined 'X', if this is a bug.
Also, remember to check the syntheis report for warnings about created latches, since that is most likely a bug in the design.
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.)
I'm trying to write some fairly generic VHDL code but I'm running into
a situation where I don't understand the standard well enough. (I'm
using VHDL-2008.)
I have written a function that operates on unconstrained
std_logic_vector(s) and returns an unconstrained
std_logic_vector. However, it seems as if I am unable to use this
function as an input to a port in my entity if I pass two
(constrained) std_logic_vectors to it (see instantiation of test_2 in
my example program). However, for some reason it seems to work ok if I
pass bit string literals to it (see instantiation of test_1).
Can someone explain why the I am not allowed to use the concatenate()
function as an input in the instantiation of test_2 while I am allowed
to use a very similar construct in the instantiation of test_1?
To try the code with ModelSim I compiled it with vcom -2008 unconstrained_example.vhd
-- test entity/architecture
library ieee;
use ieee.std_logic_1164.all;
entity test is
port (value : in std_logic_vector);
end entity;
architecture a of test is
begin
-- Intentionally empty
end architecture;
library ieee;
use ieee.std_logic_1164.all;
-- Test instantiation
entity testit is
end entity;
architecture a of testit is
signal my_constrained_slv1 : std_logic_vector(5 downto 0);
signal my_constrained_slv2 : std_logic_vector(9 downto 0);
function concatenate(value1 : std_logic_vector; value2 : std_logic_vector) return std_logic_vector is
begin
return value1 & value2;
end function;
begin
process begin
-- Using the function in this context seems to work ok
report "Value is " & to_string(concatenate(my_constrained_slv1, my_constrained_slv2));
wait;
end process;
-- This instantiation seems to work
test_1: entity work.test
port map (
value => concatenate("000000", "1111111111"));
-- For this entity instantiation I'm getting an error from ModelSim:
-- ** Error: unconstrained_example.vhd(43): (vcom-1383) Implicit signal in port map for port "value" is not fully constrained.
test_2: entity work.test
port map (
value => concatenate(my_constrained_slv1, my_constrained_slv2));
end architecture;
Your function call is not a conversion function and also does not fulfill the requirements to spare an implicit signal declaration.
VHDL-2008 allows such complex expressions in a port association. The language says, that in such cases, an implicit signal will be created:
If the actual part of a given association element for a formal signal port of a block is the reserved word inertial followed by an expression, or is an expression that is not globally static, then the given association element
is equivalent to association of the port with an anonymous signal implicitly declared in the declarative region that immediately encloses the block. The signal has the same subtype as the formal signal port and is the target of an implicit concurrent signal assignment statement of the form:
anonymous <= E;
where E is the expression in the actual part of the given association element. The concurrent signal assignment statement occurs in the same statement part as the block.
Source: IEEE-1076-2017 Draft 5a
signal temp : std_logic_vector; -- derived from the formal in the port association list
temp <= concatenate(my_constrained_slv1, my_constrained_slv2);
test_2: entity work.test
port map (
value => temp
);
end block;
The problem is, that VHDL needs to infer the type for the implicit signal temp from the formal in the port association list (value : std_logic_vector). It knows, that it is a std_logic_vector, but no constraints are known, due to the unconstrained port.
So if port value in entity test is constrained, it should work:
entity test is
port (
value : in std_logic_vector(15 downto 0)
);
end entity;
I came up with the following workaround which is quite ugly but
fulfills my main criteria that I should not have to manually specify
any widths or repeat any information. By hiding away the call to concatenate in a function I can
reuse the function to get the range further down. A short experiment indicates that Vivado 2015.4 accepts this construct as well.
test_2_helper : block
impure function test_2_help_func return std_logic_vector is
begin
-- This is the only place I have to change in case the assignment has to
-- change in some way. (E.g. use other variables or become more complicated, etc.)
return concatenate(my_constrained_slv1, my_constrained_slv2);
end function;
signal test_2_helper_sig : std_logic_vector(test_2_help_func'range);
begin
test_2: entity work.test
port map (
-- It seems to be syntactically legal to use test_2_help_func(test_2_help_func'range)
-- here. Unfortunately this does not work in simulation. Probably because the
-- test_2_help_func does not have any explicit arguments and this may cause issues
-- with the event driven simulation. As a work around the test_2_helper_sig signal
-- is assigned every clock cycle below instead.
value => test_2_helper_sig);
process
begin
-- Note: If you remove the wait for the clock edge and instead use process(all)
-- test_2_helper_sig does not seem to change during simulation, at least in
-- Modelsim 10.6 where I tested this.
wait until rising_edge(clk);
test_2_helper_sig <= test_2_help_func;
end process;
end block;
Note: This is inspired by the following answer: VHDL - Why does using the length attribute directly on a function produce a warning?
I am writing a statemachine, which has a generic parameter, and some states existence depends on this. Since I have my states defined in something like an enum (don't know the vhdl term for it), I wonder if I can define this enum depending on the generic somewhat like so:
generic(x: bool); -- in the entity
....
architecture ...
if x then generate
type states_t is (State1, State2, State3ifX)
else
type states_t is (State1, State2)
end generate;
variable state : states_t;
begin
case state is
....
if x then generate
when State3ifX =>
...
end if;
end case
end architecture;
Do I have to carry the dead weight (logic for state3, danger to drop into it (does not matter in my case since I do not expect radiation), additional bit since ceil(ld(3))=2 > ld(2)=1), or is there a possibility to strip unnecessary state(s)?
(In my case there are several states that could be stripped, however seperate architectures are not worth while the effort)
you can define the "states"-type in a process that is optionally generated using a generic. see a reference example below:
entity blabla is
generic(sel: std_logic := '0');
port(
...
architecture Behavioral of blabla is
begin
q1: if sel='0' generate
p: process(clk)
type t_state is (s1, s2, s3);
variable state: t_state;
begin
if rising_edge(clk) then
...
end if;
end process;
end generate;
q2: if sel='1' generate
p: process(clk)
type t_state is (s1, s2);
variable state: t_state;
begin
if rising_edge(clk) then
...
end if;
end process;
end generate;
I can't think of a way to achieve what you need.
On the upside, your concern about having to "carry the dead weight (logic for state3, danger to drop into it)" is not something you need to worry about - the synthesizer will optimise the logic away, so the state register will only be as big as it needs to be for the states you can actually reach.
I know its an old tread but still a hit on google so Im adding how Im doing it
label: if x generate
declarations <- put types, signals & attribures here !!!!
begin
ur code
end generate label;
You might want to consider second architecture or even simpler just a different entity - just another vhd file with slightly different name (like _x1, then _x2)
I find "genercis system" not really practical in more advanced cases (to much bloat-code to write), and then u might use different synthezisers so two archoitecture with one entity might not work, generate with decalrations inside might not work.... I would create different vhd for that - it will work in all the cases)
Cheers
I have a code listing that is full of code like the following, but larger chunks.
if (m = '00000') then
done <= '1';
else
done <= '0';
end if;
Is there any way of making this like a function of a c like #define so that I don't have to write the same code all over the place?
This code is not VHDL in the first place, so you have other things to worry about. (It's a bit more VHDL-like after the edit)
Thankfully VHDL has nothing like C's #define. Instead it has tools for proper abstractions such as packages (very roughly, C++ namespaces but done right), functions and procedures.
This allows you to write
done <= test_zero(m);
assuming done is a signal ( or done := test_zero(m); if it's a variable)
test_zero is then a function, something like
function test_zero ( word : in std_logic_vector) return std_logic is
begin
if word = (word'range => '0') then
return '1';
else
return '0';
end if;
end test_zero;
which (because it uses the "range" attribute) will work with different sizes of "m".
You will end up with a collection of useful functions : keep them in a package and use them throughout the project.
A package usually appears as two parts : the package specification (a bit like a C header file done right)
package my_tools is
function test_zero ( word : in std_logic_vector) return std_logic;
end my_tools;
and a package body containing the implementations
package body my_tools is
function test_zero ( word : in std_logic_vector) return std_logic is
...
end test_zero;
end my_tools;
To use it, it is compiled into a library (we'll use the default library "work" which is already declared by an implicit library work; in every VHDL file). Then you can choose either to make everything in the package visible in your code:
use work.my_tools.all;
Or make only one function visible:
use work.my_tools.test_zero;
Or make it obvious to anyone reading the code where the mysterious "test_zero" function came from:
done <= my_tools.test_zero(m);
If you have used C++ namespaces you will recognise these different strategies.
What makes the VHDL equivalent "namespaces done right" is that the VHDL compiler uses these declarations to track dependencies automatically and compile the right bits, instead of needing additional #includes and external tools like makefiles which must be kept in sync with the actual code by hand.