concurrent procedure call in vhdl - vhdl

I am trying to understand the concurrent procedure call with different parameters' class. Assuming I have the procedure test and it is called concurrently like below:
ENTITY tb IS
END ENTITY tb;
ARCHITECTURE sim OF tb IS
SIGNAL cnt : integer RANGE 0 TO 3 := 0;
SIGNAL str : string(1 TO 5) := (OTHERS => ' ');
PROCEDURE test (CONSTANT number : IN integer RANGE 0 TO 3 := 0;
SIGNAL num_str : OUT string(1 TO 5)) IS
BEGIN
REPORT "here";
CASE number IS
WHEN 0 => num_str <= "zero ";
WHEN OTHERS => num_str <= "one ";
END CASE;
END PROCEDURE;
BEGIN
test(cnt, str); -- CONCURRENT CALL TO PROCEDURE TEST
PROCESS
BEGIN
FOR i IN 0 TO 3 LOOP
WAIT FOR 10 ns;
cnt <= i;
END LOOP;
WAIT;
END PROCESS;
END ARCHITECTURE sim;
In THE VHDL DESIGNER GUIED
Another point to note about concurrent procedure calls is that if there are no signals
associated with in-mode or inout-mode parameters, the wait statement in the equivalent
process does not have a sensitivity clause. If the procedure ever returns, the process suspends indefinitely. This may be useful if we want the procedure to be called only once at
startup time.
As procedure test has no signals associated with in-mode or inout-mode, it supposes to be executed once and then suspends indefinitely. But with this example, the procedure is executed 4 times.
Can someone explain to me what is happening or what I am missing?

Section 11.4 of the 2008 LRM (IEEE Std 1076-2008):
For any concurrent procedure call statement, there is an equivalent
process statement [...] The equivalent process statement also has no
sensitivity list, an empty declarative part, and a statement part that
consists of a procedure call statement followed by a wait statement.
The procedure call statement consists of the same procedure name and
actual parameter part that appear in the concurrent procedure call
statement.
If there exists a name that denotes a signal in the actual part of any
association element in the concurrent procedure call statement, and
that actual is associated with a formal parameter of mode in or inout,
then the equivalent process statement includes a final wait statement
with a sensitivity clause that is constructed by taking the union of
the sets constructed by applying the rule of 10.2 to each actual part
associated with a formal parameter.
Forget about the last part, in your case things are super simple and your equivalent process is:
process
begin
test(cnt, str);
wait on cnt;
end process;
The CONSTANT class declaration of your procedure's declaration only indicates that (section 4.2.2.2):
For parameters of class constant or variable, only the values of the
actual or formal are transferred into or out of the subprogram call.
It somehow forces you to manipulate this value as if it was a constant and nothing else... inside the procedure's body. It forbids you, for instance, to use signal attributes (e.g. number'EVENT). But it doesn't say anything about the actual parameter that you will associate to this formal parameter when instantiating the procedure.
And the result is, logically, what you observe: your procedure is called 4 times in the equivalent process. Each time the value of the actual parameter, that is, the signal cnt is passed through the formal parameter number.
And your book is right:
[...] if there are no signals associated with in-mode or inout-mode
parameters, the wait statement in the equivalent process does not have
a sensitivity clause.
Indeed, you have a signal (cnt) associated with an in-mode parameter (number).

Related

How do you add another process on VHDL?

I would like to add if MyVariable is equal to 1 if will report the device is on
architecture sim of T06_SignalTb is
signal MySignal : integer :=0;
begin
process is
variable MyVariable: integer :=0;
begin
report "***Process begin***";
MyVariable := MyVariable + 1;
MySignal <= MySignal + 1;
report "MyVariable=" & integer 'image(MyVariable) & ", MySignal=" & integer 'image(MySignal);
MyVariable := MyVariable + 1;
MySignal <= MySignal + 1;
report "MyVariable=" & integer 'image(MyVariable) & ", MySignal=" & integer 'image(MySignal);
Wait for 10 ns;
end process;
here is the process that i would like to add
process is
begin
MyVariable = 1;
report " the device is on";
end process;
You add another process by adding the code for your second process somewhere between begin and end architecture;. They will execute concurrently. However...
Variables in VHDL are only in scope within a single process. Notice that you declared MyVariable within (the so-called declarative region of) a single process.
This is for a very good reason. If a variable were to be in scope inside some other process, your code could be non-deterministic. (It is possible to do this in Verilog and consequently it is possible to write non-deterministic code in Verilog.)
So, you will not be able to use the variable MyVariable in your second process if you have declared it in the first process. So, what do do?
i) use a signal instead. Signals are VHDL constructs whose purpose is to allow separate processes to communicate.
ii) Or write the code in one process instead of two.
iii) Or use a special kind of VHDL variable called a shared variable, which you would declare in the same place as a signal. However, shared variables are tricky things. They have to be of a special type called a protected type and if you use them, you code can be non-deterministic (just like Verilog). I would be very surprised if this were the right solution for you.
BTW: this code
MySignal <= MySignal + 1;
report "MyVariable=" & integer 'image(MyVariable) & ", MySignal=" & integer 'image(MySignal);
suggests that you have forgotten that signals are not updated (ie don't get their new values) until all the processes suspend (ie finish executing).
Use variables to store information within a process; use signals to send information to another process.

How to write new line to file in VHDL?

I would like to separate my data with new line character in an output file, but the following codes result in error "can't resolve overload for procedure call":
write(out_line, "\n");
write(out_line, "");
write(out_line, '');
An example code how I want to use it:
ENTITY writer IS
PORT ( clk : IN STD_LOGIC := '0'; start : IN STD_LOGIC := '0');
END ENTITY;
ARCHITECTURE arch OF writer IS
SIGNAL vect : STD_LOGIC_VECTOR (2 downto 0) := "000";
TYPE state_type IS (init, write_file);
SIGNAL state : state_type := init;
BEGIN
PROCESS (clk, start)
FILE out_file : text;
VARIABLE out_line : line;
BEGIN
IF rising_edge(clk) THEN
CASE state IS
WHEN init =>
IF start = '1' THEN
state <= write_file;
ELSE
state <= init;
END IF;
WHEN write_file =>
state => init;
FOR i IN 0 TO 10 LOOP
write(out_line, vect);
writeline(out_file, out_line);
-- write(out_line, "\n"); <--
-- write(out_line, ""); <--
-- write(out_line, ''); <-- None of these work
writeline(out_file, out_line);
END LOOP;
END CASE;
END IF;
END PROCESS;
END ARCHITECTURE;
So I would like to know, is it possible in VHDL? If yes, how?
The following will consistently give you a single blank line:
write(out_line, string'(""));
writeline(out_file, out_line);
I suspect what #Dani posted may be tool dependent. For example while on one popular simulator, the following produces one line feed:
write(out_line, LF);
writeline(out_file, out_line);
However when I add a space after the LF, I get two lines:
write(out_line, LF & ' ');
writeline(out_file, out_line);
Creating a minimal, complete and verifiable example from the question's incomplete sample code:
library ieee; -- ADDED
use ieee.std_logic_1164.all; -- ADDED
use std.textio.all; -- ADDED
-- use ieee.std_logic_textio.all; -- ADDED for revisions earlier than -2008
ENTITY writer IS
-- PORT ( clk : IN STD_LOGIC := '0'; start : IN STD_LOGIC := '0');
END ENTITY;
ARCHITECTURE arch OF writer IS
SIGNAL vect : STD_LOGIC_VECTOR (2 downto 0) := "000";
-- TYPE state_type IS (init, write_file);
-- SIGNAL state : state_type := init;
BEGIN
PROCESS -- (clk, start)
FILE out_file : text;
VARIABLE out_line : line;
BEGIN
file_open(out_file, "some_file", WRITE_MODE); -- ADDED
-- IF rising_edge(clk) THEN
-- CASE state IS
-- WHEN init =>
-- IF start = '1' THEN
-- state <= write_file;
-- ELSE
-- state <= init;
-- END IF;
-- WHEN write_file =>
-- state => init;
FOR i IN 0 TO 10 LOOP
write(out_line, vect);
writeline(out_file, out_line);
-- write(out_line, "\n"); <--
-- write(out_line, ""); <--
-- write(out_line, ''); <-- None of these work
writeline(out_file, out_line);
END LOOP;
-- END CASE;
-- END IF;
wait; -- ADDED
END PROCESS;
END ARCHITECTURE;
demonstrates a way to get a blank line in the output:
some_file contents:
000
000
000
000
000
000
000
000
000
000
000
The second writeline procedure call produces an empty line without an intervening write procedure call.
Why is seen in IEEE Std 1076-2008 16.4 Package TEXTIO:
Procedures READLINE, WRITELINE, and TEE declared in package TEXTIO read and write entire lines of a file of type TEXT. Procedure READLINE causes the next line to be read from the file and returns as the value of parameter L an access value that designates an object representing that line. If parameter L contains a non-null access value at the start of the call, the procedure may deallocate the object designated by that value. The representation of the line does not contain the representation of the end of the line. It is an error if the file specified in a call to READLINE is not open or, if open, the file has an access mode other than read-only (see 5.5.2). Procedures WRITELINE and TEE each cause the current line designated by parameter L to be written to the file and returns with the value of parameter L designating a null string. Procedure TEE additionally causes the current line to be written to the file OUTPUT. If parameter L contains a null access value at the start of the call, then a null string is written to the file or files. If parameter L contains a non-null access value at the start of the call, the procedures may deallocate the object designated by that value. It is an error if the file specified in a call to WRITELINE or TEE is not open or, if open, the file has an access mode other than write-only.
The language does not define the representation of the end of a line. An implementation shall allow all possible values of types CHARACTER and STRING to be written to a file. However, as an implementation is permitted to use certain values of types CHARACTER and STRING as line delimiters, it might not be possible to read these values from a TEXT file.
A line feed (LF) format effector occurring as an element of a string written to a file of type TEXT, either using procedure WRITELINE or TEE, or using the WRITE operation implicitly defined for the type TEXT, is interpreted by the implementation as signifying the end of a line. The implementation shall transform the LF into the implementation-defined representation of the end of a line.
...
For each WRITE, OWRITE, and HWRITE procedure, after data is appended to the string value designated by the parameter L, L designates the entire line. The procedure may modify the value of the object designated by the parameter L at the start of the call or may deallocate the object.
If deallocation occurs out_line will have a value of null after a writeline call and a null string is written in the immediately following writeline call which also provides an end of line.
If the object value accessed by out_line is a null array (having no elements, 5.3.2.2 Index constraints and discrete ranges, a null string) the immediately following writeline call will result in an end of line being written to the file.
In essence your code example already contains one of these methods for writing a blank line, which depends on whether deallocation is used conditionally (may).
Variants of allocate() and free() can be relatively expensive in terms of execution time and when the size of the allocated object and it's element size is known a smaller 'allocated' object can be written to the same object space saving simulation time. The simulation kernel representation of an array object can have bounds separate from the array value, deallocation and re-allocation can be reserved for when the object size is larger than the previously allocated size or an explicit deallocate call occurs.
There's also a requirement that an implementation translate an LF character to an end of line in a write to a file. This is the other mechanism that allows you to write an LF character as the last or only character to a line and get a following blank line.
You could also explicitly write a null string to out_line
write(out_line, string'(""));
prior to the second writeline call. The qualified expression provides the type of the string literal unlike the attempt commented out in the original question where the type of the string literal can't be determined. See 9.3.2 Literals "... The type of a string or bit string literal shall be determinable solely from the context in which the literal appears, excluding the literal itself but using the fact that the type of the literal shall be a one-dimensional array of a character type. ...". The procedure write would be ambiguous in this context, failing overload resolution (12.5 The context of overload resolution).
Finally after a lot of searching and trying I found that the following code works:
write(out_line, lf);
writeline(out_file, out_line);
I found that write(out_line, cr); does the same thing, and write(out_line, nul); adds ' ' character between the outputs.

How to use a 'case' in VHDL blocks

I want to re-use some code block and to make it more readable I tried to put it in a block.
The code block is used to save some data to some buffers. This also includes a case statement. This block is used in a few states in a statemachine.
someBlock: block
begin
destinationAddr <= destinationAddr_i;
sourceAddr <= sourceAddr_i
case type is
when typeA =>
someData <= dataA;
dataLength <= 1;
when typeB =>
someData <= dataB;
dataLength <= 2;
when typeC =>
someData <= dataC;
dataLength <= 3;
end case;
end block;
The code is just an example of what I'm trying to do. I want this code to be inserted in the place I call someBlock.
If I make this block Sigasi and Vivado complain about the case statement. (mismatched input 'case', expecting 'end'). I placed the block declaration after the architecture begin but not inside a process.
Is this the wrong way to use a block? Is there some other way of making a 'function' that can manipulate all signals in the architecture?
edit:
ok figured it out. I tried using a procedure before, i placed it in the architecture but not in the process. The signals weren't accessible according to vivado because it couldn't be sure there wouldn't be multiple drivers (from different processes). If I place the procedure in the process it does work.
Thanks for the help everyone :)
First of all, type is a reserved word and cannot be used for an object name. You also cannot use a case statement based on a checking an object type.
It is complaining because the inside of a Block statement is not a sequential region of the code. Case statements must be used in a sequential region, such as a process, function or procedure. In addition, blocks cannot be re-used, they are there simply to add a local region for scoping purposes.
To make it re-useable, you probably want to use a procedure instead. This would be declared in a declarative region - ie. before a "begin". Here is an example:
procedure mux(constant s : in std_logic;
constant bits : in std_logic_vector(1 downto 0);
signal o : out std_logic
) is
begin
case s is
when '1' => o <= bits(1);
when '0' => o <= bits(0);
when others => o <= 'X'; -- for simulation only
end case;
end procedure;
begin
-- create a synchronous mux
process(clk)
begin
if rising_edge(clk) then
mux(s0, ipA, opA);
end if;
end process;
-- you can call it outside a process also - this infers an async process, sensitive to s1, ipB, opB
mux(s1, ipB, opB);
end architecture;

VHDL syn_looplimit and synthesis

I have a problem in synthesis with my VHDL code : I am trying to get the logarithm value of an input signal S_ink:
My code :
entity ....
....
architecture rtl of myEntity is
attribute syn_looplimit : integer;
attribute syn_looplimit of loopabc : label is 16384;
logcalc:process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := S_ink+1; --S_ink is an input of my entity (integer)
log:=0;
loopabc:while (temp/=0) loop
temp:=temp/2;
log :=log+1;
end loop loopabc;
S_klog<=3*log;
end if;
end if;
end process;
It works very well in simulation but doesn't synthesize.
The error message is : "While loop is not terminating. You can set the maximum of loop iterations with the syn_looplimit attribute"
However, this code synthesize (but that is not what I want)
entity ....
....
architecture rtl of myEntity is
attribute syn_looplimit : integer;
attribute syn_looplimit of loopabc : label is 16384;
logcalc:process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := 3000; -- a random constant value
log:=0;
loopabc:while (temp/=0) loop
temp:=temp/2;
log :=log+1;
end loop loopabc;
S_klog<=3*log;
end if;
end if;
end process;
When the synthesis tool translates the design, it will make a circuit with a topology that does not depend on the data values, but where the wires carries the data values. The circuit must have a fixed calculation latency between each level of flip-flops, so timing analysis can determine if the amount of logic between flip-flops can fit for the specified frequency. In this process any loops are unrolled, and you can think of this as converting the loop to a long sequence of ordinary (non-loop) statements. To do this unrolling, the synthesis tool must be able to determine the number of iterations in the loops, so it can repeated the loop body this number of times when doing loop unrolling.
In the first code example the number of iterations in the loop depends on the S_ink value, so the synthesis tool can't unroll the loop to a fixed circuit, since the circuit depends on the data value.
In the second code example the synthesis tool can determine the number of iterations in the loop, thus do the unrolling to a fixed circuit.
One way to address this is make the algorithm with a fixed number of iteration, where this number of iterations can handle the worst case input data, and where any superfluous iteration on other input data will not change the result.
Solution :
process(I_clk)
variable temp : integer;
variable log : integer;
begin
if(I_clk'event and I_clk='1') then
if (IN_rst='0') then
S_klog<=0;
temp:=0;
log:=0;
else
temp := S_ink+1;
log:=0;
for I in 1 to 14 loop
temp := temp/2;
if (temp /=0) then
log :=log+1;
end if;
end loop;
S_klog<=3*log; -- 3*log because of my application
end if;
end if;
end process;

print 2d array vhdl

How do I print matrix_a(1,1) on the console? The report command I commented does not work.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity ent is
end ent;
architecture Behavioral of ent is
type my_matrix is array(integer range 0 to 3, integer range 0 to 3) of integer;
signal matrix_a : my_matrix;
begin
matrix_a(1,1) <= 4;
--report "signal signal_d is " & integer'image((matrix_a(1,1)));
end Behavioral;
When do you expect that report to run?
You have placed it in the concurrent statement region of your architecture : everything there is effectively a process, scheduled according to specific rules; for example, the concurrent assignment matrix_a(1,1) <= 4; will run once at startup, and whenever any of its values change (i.e. never again as they are all literal constants).
But there is nothing to make the "report" run.
Now if you embed it explicitly in a process, sensitive to changes in matrix_a, then it will run at start and whenever matrix_a changes. So try this in place of the commented line:
process (matrix_a) is -- this list controls the process running
begin
report "signal signal_d is " & integer'image(matrix_a(1,1));
end process;

Resources