F
filmil
Greetings.
I noticed a difference between the simulation results from the two
different architectures given below. The architectures are almost the
same, except for the lines marked with "-- XXX Difference".
The intention of both architectures is that the signal 'output' be set
to the value of the variable v. The signal 'output' is only read when
rd = '1'. The first architecture sets output to an undefined value
for other values of rd, while the second drives output irrespective of
the value of rd. Thus, I expect the value of 'output', when rd='1' to
be the same in both cases.
The simulation shows results I didn't expect. In case of behavior_1,
the signal is driven as expected. In case of behavior_2, the output
signal has value "(others => '0')", which is not equal to the value of
'v'.
Why do I see different behaviors? I suspect it has to do with 'v'
being a variable and not a signal, but I don't know why.
FYI, this is a minimal example that shows the issue. The actual code
I used when I found this had to do with a FIFO. In its architecture I
used a shared variable for a memory array instead of a signal array,
for simulation efficiency.
f
--- Snippet: entity driver, architectures behavior_1 and behavior_2
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
entity driver is
generic( CLK_PERIOD : Time := 4 ns );
end;
architecture behavior_1 of driver is
constant WIDTH : positive := 3;
subtype t is std_logic_vector(WIDTH-1 downto 0);
constant UNDEF : t := (others => 'X');
signal clk, rd : std_logic;
signal output : t;
shared variable v : integer range 0 to (2**WIDTH-1) := 0;
begin
rdgen : process
variable i : integer;
begin
wait for 5 * CLK_PERIOD;
for i in 1 to 5 loop
wait until rising_edge(clk);
rd <= '1';
wait until rising_edge(clk);
rd <= '0';
end loop;
wait;
end process;
clkgen : process
begin
clk <= '1';
wait for CLK_PERIOD / 2;
clk <= '0';
wait for CLK_PERIOD / 2;
end process;
sequential : process(clk)
begin
if rising_edge(clk) then
v := v + 1;
end if;
end process;
output <= std_logic_vector(to_unsigned(v, WIDTH)) when rd = '1' else
UNDEF; -- XXX Difference
end;
architecture behavior_2 of driver is
constant WIDTH : positive := 3;
subtype t is std_logic_vector(WIDTH-1 downto 0);
constant UNDEF : t := (others => 'X');
signal clk, rd : std_logic;
signal output : t;
shared variable v : integer range 0 to (2**WIDTH-1) := 0;
begin
rdgen : process
variable i : integer;
begin
wait for 5 * CLK_PERIOD;
for i in 1 to 5 loop
wait until rising_edge(clk);
rd <= '1';
wait until rising_edge(clk);
rd <= '0';
end loop;
wait;
end process;
clkgen : process
begin
clk <= '1';
wait for CLK_PERIOD / 2;
clk <= '0';
wait for CLK_PERIOD / 2;
end process;
sequential : process(clk)
begin
if rising_edge(clk) then
v := v + 1;
end if;
end process;
output <= std_logic_vector(to_unsigned(v, WIDTH)); -- XXX Difference
end;
I noticed a difference between the simulation results from the two
different architectures given below. The architectures are almost the
same, except for the lines marked with "-- XXX Difference".
The intention of both architectures is that the signal 'output' be set
to the value of the variable v. The signal 'output' is only read when
rd = '1'. The first architecture sets output to an undefined value
for other values of rd, while the second drives output irrespective of
the value of rd. Thus, I expect the value of 'output', when rd='1' to
be the same in both cases.
The simulation shows results I didn't expect. In case of behavior_1,
the signal is driven as expected. In case of behavior_2, the output
signal has value "(others => '0')", which is not equal to the value of
'v'.
Why do I see different behaviors? I suspect it has to do with 'v'
being a variable and not a signal, but I don't know why.
FYI, this is a minimal example that shows the issue. The actual code
I used when I found this had to do with a FIFO. In its architecture I
used a shared variable for a memory array instead of a signal array,
for simulation efficiency.
f
--- Snippet: entity driver, architectures behavior_1 and behavior_2
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
entity driver is
generic( CLK_PERIOD : Time := 4 ns );
end;
architecture behavior_1 of driver is
constant WIDTH : positive := 3;
subtype t is std_logic_vector(WIDTH-1 downto 0);
constant UNDEF : t := (others => 'X');
signal clk, rd : std_logic;
signal output : t;
shared variable v : integer range 0 to (2**WIDTH-1) := 0;
begin
rdgen : process
variable i : integer;
begin
wait for 5 * CLK_PERIOD;
for i in 1 to 5 loop
wait until rising_edge(clk);
rd <= '1';
wait until rising_edge(clk);
rd <= '0';
end loop;
wait;
end process;
clkgen : process
begin
clk <= '1';
wait for CLK_PERIOD / 2;
clk <= '0';
wait for CLK_PERIOD / 2;
end process;
sequential : process(clk)
begin
if rising_edge(clk) then
v := v + 1;
end if;
end process;
output <= std_logic_vector(to_unsigned(v, WIDTH)) when rd = '1' else
UNDEF; -- XXX Difference
end;
architecture behavior_2 of driver is
constant WIDTH : positive := 3;
subtype t is std_logic_vector(WIDTH-1 downto 0);
constant UNDEF : t := (others => 'X');
signal clk, rd : std_logic;
signal output : t;
shared variable v : integer range 0 to (2**WIDTH-1) := 0;
begin
rdgen : process
variable i : integer;
begin
wait for 5 * CLK_PERIOD;
for i in 1 to 5 loop
wait until rising_edge(clk);
rd <= '1';
wait until rising_edge(clk);
rd <= '0';
end loop;
wait;
end process;
clkgen : process
begin
clk <= '1';
wait for CLK_PERIOD / 2;
clk <= '0';
wait for CLK_PERIOD / 2;
end process;
sequential : process(clk)
begin
if rising_edge(clk) then
v := v + 1;
end if;
end process;
output <= std_logic_vector(to_unsigned(v, WIDTH)); -- XXX Difference
end;