VHDL Procedures - vhdl

For a class, I was asked to write a VHDL procedure that takes two integer inputs A and B and replaces A with A+B and B with A-B. I wrote the following program and testbench. It completes implementation and the Behavioral Syntax check but it will not simulate. Although I get no errors, I do get some warnings stating that A and B are in combinational feedback loops. Can someone shed some light on what the problem may be?
Module:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Problem2 is
Port ( A : inout integer;
B : inout integer);
end Problem2;
architecture Behavioral of Problem2 is
procedure AB (signal A,B: inout integer) is
begin
A<=A+B after 20 ns;
B<=A-B after 30 ns;
end AB;
begin
AB(A=>A, B=>B);
end Behavioral;
TestBench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY Problem2_test IS
END Problem2_test;
ARCHITECTURE behavior OF Problem2_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT Problem2
PORT(
A : INOUT integer;
B : INOUT integer
);
END COMPONENT;
--BiDirs
signal A : integer;
signal B : integer;
-- No clocks detected in port list. Replace <clock> below with
-- appropriate port name
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: Problem2 PORT MAP (
A => A,
B => B
);
ABproc: process is
begin
A<=25;
B<=22;
wait;
end process;
END;

The problem is:
Your component writes to it's own inputs. This is the equivalent of an infinite loop. The reason you've done this is because ....
The description of the problem doesn't make sense.
I was asked to write a VHDL procedure that takes two integer inputs A and B...
Fine
...and replaces A with...
What?!
You can't replace A (or B) because you'll get this problem. You could write a procedure that takes two integer inputs, and gives two integer outputs. Those outputs could then feed some registers which then feed the input, but there has to be a register there to break the combinatorial feedback loop.

Don't test it inside a the problem2 entity. Just call the procedure straight from your test bench.
(This code is not tested!)
ABproc: process is
begin
A<=25;
B<=22;
AB(A, B);
wait 1 ns;
assert A = 47;
assert B = 3;
wait; -- forever
end process;

Related

VHDL Latch inference using procedure

I expect the following code to simply generate two AND gates, but the gate of the procedure gets a latch at the output. In my original code, removing (commenting) the direct path gets rid of the latch, but I haven't been able to isolate this.
What causes this latch, and how can it be avoided?
Note that this is a purely combinatorial circuit without ifs and such generally associated with latch inference.
I am using Vivado 2018.3 on Linux Mint 19.
Edit 1: putting the direct path in a process statement gets rid of the latch.
Edit 2: the latch is no longer there after synthesis, so it can (probably) not cause problems. The question remains why it is generated in the first place.
library IEEE;
use IEEE.std_logic_1164.all;
entity mcve is
port (
a, b : in std_logic;
o : out std_logic_vector(1 downto 0)
);
end entity;
architecture rtl of mcve is
procedure and_proc (signal pa, pb : in std_logic; signal po : out std_logic) is
begin
po <= pa and pb;
end procedure;
begin
o(0) <= a and b;
and_proc(a, b, o(1));
end architecture;

Difference between block and process statement in VHDL

I recently ran into a question regarding VHDL block and process structures and didn't find any explanation in text books or internet forums.
Is there any difference between the block and the process statements in the codes bellow?
library IEEE;
use IEEE.std_logic_1164.all;
entity example is
port ( a, b, clock : in std_logic;
c : out std_logic);
end entity;
architecture rtl of example is
begin
test_block : block (clock'event and clock = '1')
begin
c <= guarded a and b;
end block test;
end rtl;
and
library IEEE;
use IEEE.std_logic_1164.all;
entity example is
port ( a, b, clock : in std_logic;
c : out std_logic);
end entity;
architecture rtl of example is
begin
test_proc : process (clock)
begin
if (clock'event and clock = '1') then
c <= a and b;
end if;
end process test_proc;
end rtl;
The main difference is in the keyword guarded. If you write your code without it, whole logic would be regular combinational. So, I guess, if you want to write mostly concurrent code with some sequential logic, you can carefuly use block statement and when sequential needed use guarded. I've asked my colleagues who have huge background in FPGA design and they told that block is kinda anachronism, almost nobody use it, but it still in standard to give some choice for designers.

VHDL-2008 continuously force an external name

I'd like to be able to continuously force a signal down in my testbench hierarchy. Here is a simple example illustrating how I've been doing this in my test benches.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity double_inverter is
port(
a : in std_logic;
z : out std_logic
);
end double_inverter;
architecture x of double_inverter is
signal b : std_logic;
begin
b <= not a;
z <= not b;
end architecture x;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity inverter_tb is
end inverter_tb;
architecture y of inverter_tb is
signal z : std_logic;
signal clk : std_logic := '0';
begin
clk <= not clk after 5 ns;
dut : entity work.double_inverter
port map(
a => '0',
z => z
);
continuous_stim : process(clk)
begin
<< signal dut.b : std_logic >> <= force clk;
end process;
end architecture y;
This works in Modelsim 10.4b i.e. signal b in the double_inverter instance will be set by clk and not signal a, but is there a better way to control external name signals?
Thanks for your help.
In some situations you can use is an alias to the external name:
alias dut_b is <<signal dut.b : std_logic >> ;
Since we think of signals being declared in an architecture, our instinct is to put the alias in the architecture. However, in this situation, it is not allowed because the DUT has not been elaborated yet.
You may be allowed to put it in the process - I would have to do some research to check if the language allows this. My concern is that processes do not allow signal declarations, so I am not confident that it will allow aliases to signals in a process - no harm in trying it and letting us know if it worked.
Generally when I am using something like this, I put it in a architecture declarative region of a component that creates the test cases and is instanced by the testbench. To avoid issues with elaboration order, I make sure to instance my DUT first in the testbench and typically the component that generates the test cases last (with the transaction based models in the middle) - VHDL elaborates designs in the order they are instantiated.

Test bench file for integer types

I'm trying to simulate the following VHDL module in XIlinx ISE 14.7, but the generated VHDL test bench file assumes that all input and output ports are of type std_logic and std_logic_vector.
package newtype is
type row_t is array(0 to 2) of integer;
end newtype;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use work.newtype.all;
entity mymodule is
port (indata : in row_t;
sum : out integer);
end mymodule;
architecture Behavioral of mymodule is
begin
process (indata)
begin
sum <= indata(0) + indata(1) + indata(2);
end process;
end Behavioral;
I modified the generated code replacing std_logic_vector with my types, but this time it gives me syntax errors.
Could you please tell me what is the right way write a text bench file when you work with integer types?
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use work.newtype.all;
ENTITY mymodule_test IS
END mymodule_test;
ARCHITECTURE behavior OF mymodule_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT mymodule
PORT(
indata : IN row_t;
sum : OUT integer
);
END COMPONENT;
--Inputs
signal indata : row_t := (0,0,0);
--Outputs
signal sum : integer;
-- No clocks detected in port list. Replace <clock> below with
-- appropriate port name
constant <clock>_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: mymodule PORT MAP (
indata => indata,
sum => sum
);
-- Clock process definitions
<clock>_process :process
begin
<clock> <= '0';
wait for <clock>_period/2;
<clock> <= '1';
wait for <clock>_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for <clock>_period*10;
-- insert stimulus here
wait;
end process;
END;
You haven't posted the syntax errors you encountered. But, if I create a new project in Xilix ISE 14.7 and just add the above code, I get these syntax errors:
ERROR:HDLCompiler:806 -
"mymodule_test.vhdl"
Line 28: Syntax error near "<". ERROR:HDLCompiler:806 -
"mymodule_test.vhdl"
Line 39: Syntax error near "<". ERROR:HDLCompiler:806 -
"mymodule_test.vhdl"
Line 41: Syntax error near "<". ERROR:HDLCompiler:806 -
"mymodule_test.vhdl"
Line 54: Syntax error near "<".
All these lines contain the indentifier or prefix <clock> which is a template parameter of Xilinx's testbench generator. If this, generator detects a clock within the design you have selected in the wizard (here mymodule), then <clock> is replaced by the actual name of the clock signal. The testbench generator didn't found a clock signal within your design, so it just inserted the plain template code. These syntax errors are not related to the usage of the type integer within the testbench.
Your design does not depend on a clock signal, so you can safely remove all the testbench code associated with the clock signal:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use work.newtype.all;
ENTITY mymodule_test IS
END mymodule_test;
ARCHITECTURE behavior OF mymodule_test IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT mymodule
PORT(
indata : IN row_t;
sum : OUT integer
);
END COMPONENT;
--Inputs
signal indata : row_t := (0,0,0);
--Outputs
signal sum : integer;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: mymodule PORT MAP (
indata => indata,
sum => sum
);
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
-- insert stimulus here
wait;
end process;
END;

Procedure call in loop with non-static signal name

In some testbench code I use a procedure to do something with a signal. I then use this procedure multiple times in sequence on different signals. This works fine as long as I explicitly define the signal; as soon as I index signals in a loop it fails with
(vcom-1450) Actual (indexed name) for formal "s" is not a static signal name.
Why is this not possible and how can I work around it?
Probably I could move this to a for ... generate, but then I want do_something to be called in a nicely defined sequence.
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo(0));
do_something(foo(1));
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo(i));
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I'm using ModelSim 10.4 PE.
Interestingly, if foo is a variable local to the process, (and s is adjusted to suit) ghdl compiles this. Which highlights the problem in the original version. The "for" loop is required to drive the whole of foo all the time because you can't make signal drivers appear or disappear at will - it can't be ambivalent about which bits it's driving, (and as you can see, the procedure tries to drive different bits at different times).
So if you can readjust your application to allow variable update semantics, and make foo a variable local to the process, that will work. (You would have to copy its value to a signal before every "wait" if you wanted to see the effect!)
Alternatively, pass the entire foo signal and the index to the subprogram, so that the latter always drives all of foo as follows...
(I've also added the missing bits and fixed the spurious concurrent "wait" : in future, PLEASE check your code example actually compiles before posting!)
library ieee;
use ieee.std_logic_1164.all;
entity test is
end test;
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
begin
dummy: process is
procedure do_something (
signal s : out std_logic_vector(1 downto 0);
constant i : in natural
) is begin
s <= (others => '0');
s(i) <= '1';
report "tic";
wait for 1 ns;
-- actually we would do something more interesting here
s(i) <= '0';
report "toc";
end procedure;
begin
-- This works well, but requires manual loop-unrolling
do_something(foo,0);
do_something(foo,1);
-- This should do the same
for i in foo'range loop
-- This is the offending line:
do_something(foo,i);
end loop;
wait; -- for ever
end process dummy;
end architecture tb;
I share your feelings about this being a silly limitation of the language. Minus the wait and report statements your example certainly has a valid hardware implementation, let alone well defined simulation behavior.
I think this situation can be avoided in most cases. For example, in your simple example you could just copy the contents of the procedure into the process body, or pass the whole vector as Brian proposed. If you really need to do it, this is one workaround:
architecture tb of test is
signal foo : std_logic_vector(1 downto 0);
signal t : std_logic;
signal p : integer := 0;
begin
foo(p) <= t;
dummy: process is
procedure do_something (
signal s : out std_logic
) is begin
s <= '1';
wait for 1 ns;
s <= '0';
end procedure;
begin
for i in foo'range loop
p <= idx;
do_something(t);
wait for 0 ns;
end loop;
wait;
end process dummy;
end architecture tb;
This only works in simulation and will result in one delta cycle delay per iteration, compared to unrolling the loop which finishes in zero time when the procedure contains no wait statements.

Resources