Active-HDL 10.5 - VHDL assignment woes - Page 1
Forum section: electronics / general

author: bsccara
author_rank: Contributor
timestamp: October 23, 2019, 03:45:14 pm
content: I'm simulating a two-stage 9 bit serial-to-parallel converter on Active-HDL, coded in VHDL. This converter takes in two sequential 9 bits values and outputs a 18 bit concatenation of both. On the testbench the input of the converter is connected to 'WrData', the CE to 'WrEn' and the output to 'to_load'. The testbench drives a 2 clock cycle long pulse into the 'WrEn' signal three times:Code:Clock <= not Clock after 5ns;tb : PROCESSBEGINWrData <= (others => '0');WrEn <= '0';wait for 35ns;WrData <= "001011000";WrEn <= '1'; -- Pulse 1wait for 20ns;WrEn <= '0';wait for 20ns;WrData <= "111111111";WrEn <= '1', '0' after 20ns; -- Pulse 2wait for 40ns;WrData <= "101100110";WrEn <= '1'; -- Pulse 3wait for 20ns;WrEn <= '0';wait;END PROCESS;I expected the converter to have loaded the same value into the two stages at the end of the 'WrEn' pulse. But as can be seen from the waveforms that only happens during the first and third pulses; on the second pulse the value is only loaded into the first stage. The difference in the testbench is the way the 'WrEn' signal is driven. I expected the line:Code:signal <= '1', '0' after xns;to be equivalent to:Code:signal <= '1';wait for xns;signal <= '0';but in this instance it isn't. Any idea why ?

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 24, 2019, 06:34:14 pm
content: Quote from: bsccara on October 23, 2019, 03:45:14 pmHave you thus replaced this line with the equivalent, and in this case does it simulate properly? (Sorry this is not clear from what you said?)

author: bsccara
author_rank: Contributor
timestamp: October 25, 2019, 01:11:18 am
content: Yes, I tested both methods for pulse 2. The testbench as shown already uses both methods and the screenshot shows that the simulation result, at the point marked with the red cursor, is incorrect when using the 'after' method. Or is it

author: hamster_nz
author_rank: Super Contributor
timestamp: October 25, 2019, 01:58:29 am
content: Your stimulus signals change on the active clock edge. There is the ambiguity between the which occurs first - the clock rising or the removal of the the 'wrEn' signal.I am pretty sure that you should see the expected behavior if you change "...after 20ms" to "...after 21ms", or you add a short wait to the start of the test bench - maybe just change "wait for 35ns" to "wait for 36ns",

author: bsccara
author_rank: Contributor
timestamp: October 25, 2019, 10:50:16 am
content: Yes and I've tested that; changing the one-liner to '... after 20.001ns' is enough to make it work. But why is that needed, while the 'wait for...' form works ?The simulation is not taking into account actual routing delays, just using the RTL. I assumed that the SW would find clock signals (since they're fed into the CLK inputs of the FFs) and use that knowledge and the fact that this is a fully synchronous design so all transitions implicitly happen some time after a clock edge to dissambiguate the edges. And it does seem to work that way for the most part, since I've used the one-liner in others simulations without issues.Well, maybe its because the 'WrEn' is driven outside the RTL, so the SW assumes nothing. But anyway why does the other form work ? On a mature SW ?

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 25, 2019, 03:04:19 pm
content: Quote from: bsccara on October 25, 2019, 01:11:18 amThat was not exactly answering my question - because we haven't seen the rest of your code, for all we know, the second occurence could have just failed for some other reason than the way you generate 'WrEn'. So this was the rationale of my question.Now if that's settled, the reason of the discrepancy is simple, but not trivial.It all comes down to the way HDL simulators work. Look up "delta time" for digital simulation, and you'll start understanding what is happening here.To cut a long story short, with hamster_nz's hint and mine (you'll have things to read about), generating synchronous signals in test benches with the wait or after keywords is ridden with pitfalls, so just avoid it. It's fine for generating your clock (and otherwise asynchronous signals), but you should consider the signals generated this way to be essentially asynchronous to one another - this doesn't seem logical, but again it's all related to how sequential logic is simulated.So if 'WrEn' is to be synchronous to the clock 'Clock', to avoid any weird simulation behavior (and avoid having to trick the simulator by "manually" adding delta times, which frankly sucks and is not fully fail-safe), generate the synchronous signals with a process, on the rising (or falling, depends on your design) edge of the clock, instead of using wait/after.Yes that's a bit more work (you'll usually need state machines to do that), but this is the only guaranteed way of the simulation being correct.Again, as it is, the 'WrEn' signal essentially behaves as if it were asynchronous to 'Clock', as unintuitive as it looks. The discrepancy between wait and after is related to how the simulator handles them (it probably adds the delta time to one of them, and not the other...)

author: Bassman59
author_rank: Super Contributor
timestamp: October 25, 2019, 08:04:50 pm
content: Quote from: SiliconWizard on October 25, 2019, 03:04:19 pmIn other words, to generate the stimulus you need to ensure synchronization to the clock, like:Code:testprocess: process iswait for SOMETIME;wait until rising_edge(clock);foo <= bar;wait for MORETIME;wait until rising_edge(clock);foo <= bletch;end process testprocess;And now your assignments to foo are guaranteed to be synchronous with your clock and races go away.