A
Andy Peters
Here's an odd one. Following is a stripped-down test entity which has
two shift registers, one "good" and one "bad." I ginned this up
because a colleague wrote some code that uses the latter and it showed
a strange simulation result.
---- code here:
library ieee;
use ieee.std_logic_1164.all;
entity shift_test is
end entity shift_test;
architecture test of shift_test is
signal gSysClk : std_logic := '1'; -- the clock
signal aReset : std_logic := '1'; -- async reset
signal sReset : std_logic; -- sync reset
signal srStart : std_logic := '0'; -- start shift
signal srStop : std_logic := '0';
signal goodSR : std_logic_vector(7 downto 0);
signal badSR : std_logic_vector(7 downto 0);
begin -- architecture test
bit0 : process (gSysClk) is
begin -- process bit0
if rising_edge(gSysClk) then
if gReset = '1' then
goodSR(0) <= '0';
badSR(0) <= '0';
elsif srStart = '1' then
goodSR(0) <= '1';
badSR(0) <= '1';
elsif srStop = '1' then
goodSR(0) <= '0';
badSR(0) <= '0';
end if;
end if;
end process bit0;
shifters : process (gSysClk) is
begin -- process shifters
if rising_edge(gSysClk) then
goodSR(goodSR'high downto 1) <= goodSR(goodSR'high - 1
downto 0);
badshiftloop : for i in 1 to badSR'high loop
badSR(i) <= badSR(i-1);
end loop badshiftloop;
end if;
end process shifters;
-- toggle the start and stop.
MainTest : process is
begin -- process MainTest
wait until sReset = '0';
wait for 500 NS;
wait until rising_edge(gSysClk);
srStart <= '1';
wait until rising_edge(gSysClk);
srStart <= '0';
wait for 500 NS;
wait until rising_edge(gSysClk);
srStop <= '1';
wait until rising_edge(gSysClk);
srStop <= '0';
wait until rising_edge(gSysClk);
wait;
end process MainTest;
-- clock:
gSysClk <= not gSysClk after 100 NS;
aReset <= '0' after 666 NS;
SyncReset : process (gSysClk) is
begin -- process SyncReset
if rising_edge(gSysClk) then
sReset <= aReset;
end if;
end process SyncReset;
end architecture test;
------- end code
Basically, we want to expressly set or clear the input to the shift
register. This is done in the bit0 process, depending on the state of
srStart and srStop.
The shifters process never explicitly assigns bit 0 as that is
ostensibly handled in bit0. The goodSR shift register functions as one
expects: goodSR(0) is set one clock after srStart and remains true
until srStop, and the bits shift through properly.
However, in the badSR, none of the bits are ever assigned ... the
shift register remains "UUUUUUUU". Looking at the drivers on this
signal, bit0 is actually assigned a '1' in the bit0 process at the
correct time, but it also has a driver shown for the shifters process,
and this driver's value is 'U'. The bit0 process creates a driver for
goodSR(0) but there is no driver in the shifters process like there is
for badSR(0). So it's the extra driver in shifters on badSR(0) that is
overriding the bit0 assignment (one delta cycle later).
But why is this the case? Why the second driver on the loop but not on
the simpler assignment? I don't see how the simulator infers a driver
in shifters on badSR(0) but not goodSR(0) when in neither case is an
explicit assignment made to either.
FWIW, I get the same results in ModelSim and in Active-HDL.
-a
two shift registers, one "good" and one "bad." I ginned this up
because a colleague wrote some code that uses the latter and it showed
a strange simulation result.
---- code here:
library ieee;
use ieee.std_logic_1164.all;
entity shift_test is
end entity shift_test;
architecture test of shift_test is
signal gSysClk : std_logic := '1'; -- the clock
signal aReset : std_logic := '1'; -- async reset
signal sReset : std_logic; -- sync reset
signal srStart : std_logic := '0'; -- start shift
signal srStop : std_logic := '0';
signal goodSR : std_logic_vector(7 downto 0);
signal badSR : std_logic_vector(7 downto 0);
begin -- architecture test
bit0 : process (gSysClk) is
begin -- process bit0
if rising_edge(gSysClk) then
if gReset = '1' then
goodSR(0) <= '0';
badSR(0) <= '0';
elsif srStart = '1' then
goodSR(0) <= '1';
badSR(0) <= '1';
elsif srStop = '1' then
goodSR(0) <= '0';
badSR(0) <= '0';
end if;
end if;
end process bit0;
shifters : process (gSysClk) is
begin -- process shifters
if rising_edge(gSysClk) then
goodSR(goodSR'high downto 1) <= goodSR(goodSR'high - 1
downto 0);
badshiftloop : for i in 1 to badSR'high loop
badSR(i) <= badSR(i-1);
end loop badshiftloop;
end if;
end process shifters;
-- toggle the start and stop.
MainTest : process is
begin -- process MainTest
wait until sReset = '0';
wait for 500 NS;
wait until rising_edge(gSysClk);
srStart <= '1';
wait until rising_edge(gSysClk);
srStart <= '0';
wait for 500 NS;
wait until rising_edge(gSysClk);
srStop <= '1';
wait until rising_edge(gSysClk);
srStop <= '0';
wait until rising_edge(gSysClk);
wait;
end process MainTest;
-- clock:
gSysClk <= not gSysClk after 100 NS;
aReset <= '0' after 666 NS;
SyncReset : process (gSysClk) is
begin -- process SyncReset
if rising_edge(gSysClk) then
sReset <= aReset;
end if;
end process SyncReset;
end architecture test;
------- end code
Basically, we want to expressly set or clear the input to the shift
register. This is done in the bit0 process, depending on the state of
srStart and srStop.
The shifters process never explicitly assigns bit 0 as that is
ostensibly handled in bit0. The goodSR shift register functions as one
expects: goodSR(0) is set one clock after srStart and remains true
until srStop, and the bits shift through properly.
However, in the badSR, none of the bits are ever assigned ... the
shift register remains "UUUUUUUU". Looking at the drivers on this
signal, bit0 is actually assigned a '1' in the bit0 process at the
correct time, but it also has a driver shown for the shifters process,
and this driver's value is 'U'. The bit0 process creates a driver for
goodSR(0) but there is no driver in the shifters process like there is
for badSR(0). So it's the extra driver in shifters on badSR(0) that is
overriding the bit0 assignment (one delta cycle later).
But why is this the case? Why the second driver on the loop but not on
the simpler assignment? I don't see how the simulator infers a driver
in shifters on badSR(0) but not goodSR(0) when in neither case is an
explicit assignment made to either.
FWIW, I get the same results in ModelSim and in Active-HDL.
-a