Why do we use functions in VHDL - vhdl

Functions are obviously less verbose to write than entities. But it implies many drawbacks, including:
No generic keyword equivalent
Only one output possible
It appears that functions can be called recursively. May it not be the case with entities? If so, is there any good reason to use functions except for aesthetic purposes?

Functions can't create hardware directly - they have to exist within an architecture to do so. There's nothing to stop you putting all your functionality into a function (or procedure) and then just calling that within a process though.
Regarding some of your other points:
With procedures you can have multiple inout or out parameters.
Entities can recurse... Consider:
entity recurse is
generic (
depth : integer := 1;
param : integer := 3);
port (
a : in integer;
b : out integer);
end entity recurse;
architecture a1 of recurse is
signal c : integer;
begin
c <= a + 1;
bottom: if depth = param generate
b <= a + 1;
end generate bottom;
mid:if depth /= param generate
recurse_1: entity work.recurse
generic map (
param => param,
depth => depth+1)
port map (
a => c,
b => b);
end generate mid;
end architecture a1;
Not very useful, but it synthesises and simulates just fine.
And finally, of course you only use functions for aesthetic purposes (assuming you include maintainability and readability into the definition of aesthetic, which most programming types do in my experience). You only use enumerated types, entities, records and a whole host of other language features for 'aesthetic purposes'. Even assembly mnemonics are aesthetic! Maybe should return to toggling DIP switches :)

Functions in vhdl make the code easy to maintain and read. generally architectures are very big and while debugging if something is not working you can easily find the problematic function and correct it and no need to analyse the entire architecture body.
in case of small codes it's useless but in more big machines it makes you better understand if you consider it function wise.
There is no rule for this so all comments are welcome.
in short : the advantage of functions are
overloading
operators definition
overloading of operators therefore
Better Structure of code

I can see why you are confused, another good question would be why there's both procedure and function. (VHDL seems quite inelegant sometimes!)
That being said, I use both procedures and functions all the time, although mostly in testbenches. For example, for a testbench for a firewall system I made a while back I wrote a procedure called pd_tb_send_udp_packet() that I use repeatedly in the main process, e.g.,
pd_tb_send_udp_packet("10.10.10.2", 1234, false);
pd_tb_send_udp_packet("10.10.10.1", 1234, true);
pd_tb_send_udp_packet("10.10.10.1", 1235, false);
pd_tb_send_udp_packet("ff02:100::1", 1234, false);
pd_tb_send_udp_packet("ff02:101::1", 1234, true);
This procedure generates a random UDP packet with the given addr/port and sends it to the firewall system, then tests whether it is forwarded or not based on the final boolean parameter. Here are the first lines of it, where I use functions from a library:
if f_atvtb_is_ipv6_addr(dest_ip_addr) then
v_ipv6 := true;
v_ipv6_addr := f_atvtb_ipv6_addr(dest_ip_addr);
else
v_ipv6 := false;
v_ipv4_addr := f_atvtb_ip_addr(dest_ip_addr);
end if;
The latter two return 128 and 32 bit std_logic_vectors from the string input, respectively.
While I could probably do all this without using procedures and functions somehow, it would definitely be a lot more messy.

Related

what is a {globally|locally} static {primary|expression|range|subexpression} and what does it mean?

Found lots of questions on SO that refer to error messages or warnings about something that is not locally or globally static.
There are many questions that ask about getting rid of such error messages, but astonishly, nobody seems to have ever asked what static really means.
The IEEE standard talks about static expressions in ยง9.4, but the definition isn't easy to understand (as it is recursive and - funnily enough - thus appears to be static itself by definition).
Thought it would be valuable to have an SO question that answers all the implications of what static really means in VHDL in one single place.
as stated in the comments above, a static expression is basically something that can be fully evaluated at compile time (either during the compilation of the design unit it is defined in - than it is said to be locally static - or during the evaluation of the complete design which makes it globally static).
This basically makes a static expression a constant after evaluation ('compilation'). Very similar to constexpr in C++.
What are the implications of this for synthesis?
One interesting usage is - considering an innocent looking footnote in Chapter 9.4 of the standard:
The rules for globally static expressions imply that a declared constant or a generic may be initialized with an
expression that is not globally static, for example, with a call to an impure function. The resulting constant value may be
globally static, even though its initial value expression is not. Only interface constant, variable, and signal declarations
require that their initial value expressions be static expressions.
that you can actually use VHDL statements that are not synthesisable (like, e.g., pointers or real numbers) as long as they fulfill the static requirements, i.e. can be fully evaluated into synthesisable constructs at compile time:
architecture rtl of sintab is
type sinus_table_type is array(natural range <>) of signed(31 downto 0);
function sinus_table(start_value, end_value, step : real) return sinus_table_type is
constant table_size : natural :=
integer(ieee.math_real.ceil(
end_value - start_value) / step);
variable sintab : sinus_table_type(0 to table_size - 1);
begin
for i in sintab'low to sintab'high loop
sintab(i) := to_signed(integer(
ieee.math_real.sin(start_value + real(i) * step) *
32767.0), sintab(i)'length);
end loop;
return sintab;
end function sinus_table;
function isin(sintab : sinus_table_type; us : signed) return signed is
variable ret : signed(us'range);
begin
ret := sintab(to_integer(us mod sintab'length));
return ret;
end function isin;
constant PI : real := 3.1415926;
constant stab : sinus_table_type := sinus_table(0.0, 2.0 * PI, 0.01);
begin
calc : process
begin
wait until rising_edge(clk);
res <= isin(stab, arg);
end process calc;
end architecture rtl;
In the above example, non-synthesisable expressions (using ieee.math_real, generally not synthesisable), are used to construct a constant array of scaled signed values as a lookup table, fulfilling the requirement of static as these expressions can be fully evaluated at compile time.

better alternative on for loop verilog

I am a newbie in verilog. I have been searching online and most of them suggest to not use for-loop in verilog coding. So is there a better alternative to replace for-loop?
The problem that I am facing now is that I need to perform 1 or 2 for-loop in a case statement. And I have been thinking of better alternatives but come up with none. It will be great if any one of you can shed some light on this.
Example of my code:
always #(*)
case (help)
4'd1: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; end
4'd2: for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
4'd3: begin
for (i=A; i<=20;i=i+B)
begin temp[i-1]=1; B=B+1; end
for (i=A; i>=1;i=i-B)
begin temp[i-1]=1; B=B+1; end
end
default: temp = 0;
For-loops are fine in Verilog, but they need to able to static unroll if you plan on synthesizing. Static unroll means the loop is not depended on any external variables. For example for(i=0;i<10;i=i+1) is static. for(i=A; i<=20;i=i+B) is not static as it is a depends on the variables A and B.
You can make a loop static my moving the variables as a condition inside the for-loop. for(i=A; i<=20;i=i+B) becomes:
tmp_var = A;
for (i=0; i<=20;i=i+1) begin
if (i==tmp_var) begin
// ... your logic here ...
tmp_var = tmp_var+B;
end
end
Issues that need to be addressed beyond the scope of the question:
They way you are using B and temp is a little concerning.
B appears to be an input, but you are also incrementing it. For synthesis it is illegal to manipulate an input. If it is an input, then create a local variable with default value as B and you may change this value later in the within same always block. If it is not an input, then it is creating latching logic; which is not good and I will cover that next with temp.
temp is latching logic. Latching logic are troublesome because timing is critical; knowing when the latch is transparent or closed, and respecting the hold time requirements. The more complex the logic the harder it is to predict. In RTL one way latches are inferred is by incomplete assignments inside an combinational blocks (ie always #*). To resolve this, make sure every bit is assigned each pass of the combinational blocks. One way to safe guard this is to assign default values before staring your logic. Example:
always #(*) begin
temp = 0; // default to a constant
temp_B = B; // default to an input value
// ... your logic ...
end

My sorting algorithm runtime errors

I developed the following sorting algorithm but there are some run time errors that I cant figure out. The program terminates when it comes to the part of filling the array. I'm still a beginner in ada so I couldn't figure out where the problem is...
With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;
Procedure sort is
n,i,x : Integer;
-- Max_Heapify Function...
Procedure Max_Heapify ( i, n : integer) is
j, Temp : Integer;
begin
Temp:=Int_Acc(i);
j:=2*i;
if Temp>Int_Acc(j) then
elsif Temp<=Int_Acc(j) then
Int_Acc(j/2):=Int_Acc(j);
j:=2*j;
end if;
end loop;
Int_Acc(j/2):=Temp;
end Max_Heapify;
begin
Get(n);
for i in MyArr'range loop
Put_Line("Enter Element " & Integer'Image(i));
Get(MyArr(i));
end loop;
end;
end sort;
Thanks in advance :)
Your Problem is that you are insisting on writing Ada code using c - Style programming paradigms.
Firstly:
The declarations:
Type Arr is array(1..20) of Integer;
Type int_access is access Arr;
MyArr : int_access;
Where you use Int_Acc : in out int_access as parameters to procedures are useless in Ada. You are trying to pass a pointer to an array in (which you are doing!), but you should just pass your Type Arr as in out - The Ada compiler knows to do this as a pointer!
Secondly:
I cannot see where you actually allocate any memory to MyArr. This is a possible source of your runtime error. (when you write to or index an array that does not exist, i would expect to have a problem!)
Thirdly:
You seem to be mixing fixed length arrays with variable length input. If N > 20, you will have a problem.
Fourthly:
Insulting the language is not the best way of getting help from those who like it.
NWS has nailed it : there is a pointer, but no array there.
But it's clear that you have learned C, which leaves you with a lot to learn about other languages including Ada. There really are better ways of doing many things, that aren't taught to C programmers because C doesn't allow them.
Allocating variable sized arrays without pointers, malloc and free for example...
Type Arr is array(positive range <>) of Integer; -- of any size
begin
Put_Line("Enter Number Of Elements Of Array");
Get(n);
declare -- now we know the size
My_Arr : Arr(1 .. n);
begin -- My_Arr is in scope until the end of this block
...
end;
end sort;
Using the type system better...
Bad programming :
for i in 1 .. n loop
Get(MyArr(i));
end loop;
HeapSort(MyArr,n);
for i in 1 .. n loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
This is bad because it violates the DRY principle : loop bounds repeated, and something that hopefully represents the array size passed around as a separate parameter... a maintenance nightmare if you decide to rename n to something meaningful for example.
better programming : Use the type system. Recognise that merely declaring an array has declared a new subtype of integer, representing the index of the array. You can access it as My_Arr'range, and the high bound as My_Arr'last.
for i in My_Arr'range loop
Get(MyArr(i));
end loop;
HeapSort(MyArr);
for i in My_Arr'range loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
And accidents such as redefining n after the array declaration can no longer generate buffer overflows.
NOTE: Heapsort now gets its range from the array. (Max_Heapify may still need a separate parameter to operate on subsets of the array)
Arguably best - if it makes the intent clearer - name the index datatype explicitly and use it...
declare -- now we know the size
subtype My_Range is positive range 1 .. n;
My_Arr : Arr(My_Range);
begin -- My_Arr is in scope until the end of this block
for i in My_Range loop ...
And lastly, which do you prefer; a Storage_Error exception immediately the bug occurs (writing to memory you forgot to allocate) or something odd happening much later because something scribbled across another variable?
EDIT
Having cleared up the major issues two more subtle ones remain...
If I compile the modified program (in Gnat 4.8) I get several warnings : one of them is important and tells you exactly what the problem is...
Most of the warnings stem from the fact that
for i in My_Arr'range loop
declares its own loop variable i which hides any existing in-scope declaration. So you can tidy up the code by removing the unnecessary declarations.
What remains is:
sort.adb:51:28: warning: loop range may be null
sort.adb:51:28: warning: bounds may be wrong way round
The for loop bounds are empty ranges, reversed...
1 .. 3 declares a subtype with 3 values
reverse 1 .. 3 declares the same subtype and iterates backwards over it.
But 3 .. 1 declares an EMPTY subtype (containing NO valid values) so iterating over it - either way round - does precisely nothing.
Hopefully that is the missing part of the puzzle. I'm not clear why one faulty loop gets this warning while the other (at line 38) doesn't...
if j<n **and then** Int_Acc(j+1)>Int_Acc(j) then
j:=j+1;
I think you want just 'and' instead of 'and then,' although I haven't looked at Ada code in years.
Did that compile?

VHDL component and outputs based on generic

I have a system consisting out of several components that has to be attached to a bus. However to keep the system bus independent, I gave the system a generic bus port that I run through a bus specific module that translates between my system and a specific bus. Thus it is easy to connect the entire system to different buses by switching the translating module.
However I don't want to go through the hassle of connecting the system with the translation module every time. Thus I wonder if it is possible to instantiate a module from a generic parameter, and use its types for the outputs of the architecture.
The whole becomes clearer with a little illustration, my translator modules have the following "signature".
entity translate<BusName>
port(toSystem: out toSystem_t,
fromSystem: in fromSystem_t,
toBus: out to<BusName>_t,
fromBus: in from<BusName>_t
end entity;
I now want to build an entity containing the system and a translator, based on a generic, somewhat like so:
entity entireSystem is
generic(busType := translate<BusName>)
port(toBus: out to<BusName>_t,
fromBus: in from<BusName>_t)
end entity
architecture genArc of entireSystem is
signal toTrans: fromSystem;
signal fromTrans: toSystem;
begin
system: system(toTrans,fromTrans)
translator: translate<BusName>(
fromTrans,
toTrans,
toBus,
fromBus
)
end architecture;
My problems are:
Can I use a generic parameter to directly instantiate a component, or do I have to go the if generic=xxx generate path? Can I derive the type of ports from a generic parameter.
It would be best if I can use one generic parameter to determine the ports and the entity, so that one can not pick wrong types for an entity by accidents. It would be fine to derive the types from the generic parameter with a function.
I don't think so, no.
If you want to instantiate different things based on a generic, you have to use if..generate.
The only influence that generics can have on the types of ports is that of changing the width. You can't switch between (say) an integer and a boolean based on a generic.
Can I use a generic parameter to directly instantiate a component,
or do I have to go the if generic=xxx generate path?
You can use the generic map syntax in module instantiation to pass the bus size to your sub-components. i.e.:
u_system: system
generic map ( INPUT_WIDTH => INPUT_WIDTH, OUTPUT_WIDTH => OUTPUT_WIDTH )
port map ( ... )
In the top level, you will need to have two generics instead of one.
Alternatively, assuming that your top level component must have the same bus size as your sub-components, you can try to do this in a package file and define the bus size by using function call. i.e.:
package pack is
-- # Define support bus name here
constant BusA : integer := 0;
...
constant BusZ : integer := 25;
-- # Bus name here
constant busname : integer := BusA;
-- # Input and Output Width
constant IWIDTH : integer := getIWIDTH( busname )
constant OWIDTH : integer := getOWIDTH( busname )
-- # Function declaration
function getIWIDTH( ii: integer ) return integer;
function getOWIDTH( ii: integer ) return integer;
end pack;
package body pack is
function getIWIDTH( ii: integer ) return integer is
variable oo : integer;
begin
-- # get iwidth here
return oo;
end function;
function getOWIDTH( ii: integer ) return integer is
variable oo : integer;
begin
-- # get owidth here
return oo;
end function;
end package body;

Avoid duplicating code in VHDL

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.

Resources