0
\$\begingroup\$

I have been getting into FPGA programming and Verilog and have been playing around in EDA playground for a bit creating some simple stuff. Often I need a clock so what I do is generate one on the testbench side using:

for (i = 0; i < 1000; i = i+1)
begin
    #10 clk = 1;
    #10 clk = 0;
end

Which works well. Problem is that if I remove the #10, it doesn't work. And I can't figure out why. The reason I'd expect it to work if I remove the #10 statements is because if I am correct, = is blocking in Verilog. (Where <= is not) So to me, it would sound like it should generate a signal as fast as it can. But if I try it in EDA playground, no signals are generated at all. (The signal inspector would just be completely empty)

Does anyone know why?

Thanks!

\$\endgroup\$
  • 1
    \$\begingroup\$ @Oldfart's answer is a good one, but I want to clarify that the code you show is not combinational logic as the title of your question suggests. The code you show would only be used as part of a behavioral testbench and never synthesized into logic. You shouldn't ever need to add delays to your combinational logic to make it work correctly. \$\endgroup\$ – Elliot Alderson Aug 30 at 12:39
  • \$\begingroup\$ imagine somebody asked you to do some job at infinitely speed taking 0 time....thats what simulator tries to do and gets hanged as well ;( \$\endgroup\$ – Mitu Raj Aug 30 at 13:57
5
\$\begingroup\$

It would sound like it should generate a signal as fast as it can.

Which is exactly what it does. However....

The simulator is a virtual environment. It works in 'delta' time where each delta is infinitely small in time but the deltas still happen after each other. So a simulator is (theoretically) infinitely fast.

Thus if you remove your #.. delays your loop takes 2000 deltas, each infinitely small in time which add op to 2000*0 = zero time. (I did say it was a virtual environment).

You could compare a 'delta' with a sort of Dirac pulse: it is infinitely small. It does not exist other than in mathematical models.


Does this mean this would work on an actual FPGA? Since an FPGA isn't infinitely fast.

No, this wil not work on an FPGA. The behavioral speed and real speed are unrelated. I often simulate with an arbitrary clock, but when I go to the FPGA I have to use an actual clock (either internal or, external). I specify the clock to the synthesis stool. The synthesis stool plus Place & Route will tell me afterwards if the design will run at that clock speed. (Meet timing).

For some FPGA IP, e.g. a PLL, I must simulate with the actual clock frequency otherwise the PLL model will not work.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your reply! I have another question though. Does this mean this would work on an actual FPGA? Since an FPGA isn't infinitely fast. \$\endgroup\$ – Its-a-me-mario Aug 30 at 15:55
  • \$\begingroup\$ Okay, thanks. Still don't really understand it though. If the commands happen in series, why doesn't it work? I know this is litteraly my main question, but I just can't really understand it. I'm probably misunderstanding what # and = exactly do, as someone coming from c++, I'm pretty sure somehow I'm still looking at fpga's as CPU's even though that is wrong. \$\endgroup\$ – Its-a-me-mario Aug 30 at 21:15
  • \$\begingroup\$ The simulator evaluates a bunch of events. Each event has a time associated with it. In your original code, the events would occur at 10, 20, 30, ... , 19990, 20000 time steps. If you removed the delays, then the events would occur at 0, 0, 0, ..., 0, 0 time steps. That's the weird thing about delta delays, they take zero time (I personally find "zero" more intuitive than "infinitesimal") but they still occur in a sequence. So all 2000 of your transitions will still occur in the same instant at t=0. \$\endgroup\$ – Mr. Snrub Aug 30 at 22:41
  • \$\begingroup\$ @Its-a-me-mario No. Delays are only useful in simulation workflows; they cannot be synthesized to hardware. \$\endgroup\$ – duskwuff Aug 30 at 22:47
  • \$\begingroup\$ @Mr.Snrub Thanks! I think I understand. \$\endgroup\$ – Its-a-me-mario Aug 31 at 19:40
1
\$\begingroup\$

First, as Elliot pointed out, a clock generator is not combinational logic. Behavioral models are used to represent the digitized output of an analog phase lock loop. These kind of models cannot be synthesized. FPGAs have device/vendor specific macro-modules program embedded PLLs to target frequencies. The behavioral model in your code for simulation is quick, easy, simulator agnostic, and effective. But cannot be used for anything beyond simulations.

The reason you don't see the clock toggle is because you remove the time delay you are changing prior assignments to intermediate assignments. Intermediate assignments are only visible within the procedural block that assigns it. All other concurrent logic will only see the final assignments. This is true for blocking and non-blocking assignments, except non-blocking assignments cannot sample the intermediate value.


Just for fun, if you wanted to model an ideal infinite clock with ideal logic, use #0. It is completely unrealistic and you will not get waveform, but it will simulate.


Quick description of Verilog terms:

  • "Concurrent logic" things that can be evaluated in parallel from a hardware perspective (ex always, assign, initial). In reality the simulator can evaluate any of these block in a non-deterministic order within the same timestep.
  • "Procedural block" is basically begin, end, and the body of code in-between. Once started, the simulator will procedural execute all the code with in the always block unless it is stopped by a time block delay (@, #, wait). (fork-join is a special scenario; look into it after mastering the fundamentals).
  • "Combinational logic" is where output values can be directly determined by input values. Typically uses blocking assignment (=)
  • "Sequential logic" can retain prior values and are often clock driven and typically uses non-blocking assignments (<=). Think edge-sensitive flip-flops (ex always @(posedge clk)) and level-sensitive latches (avoid latches; not supported on most FPGAs)
  • "Structural model" a module that instantiates other modules Verilog primitives (and,or, nand, nor, etc).
  • "RTL" stands for Register-Transfer-Level and are modules with sequential and or combinational logic that is synthesizable. It can instantiate sub moduels so long as they are synthesizable.
  • "Behavioural models" are typically non-synthesizable and are used to mimic specific behavior or a simplified version of something more complex.
\$\endgroup\$
  • \$\begingroup\$ Thanks for your reply! I, however, don't really understand. I'm new to all the terms like "combinational logic" and "Behavioural models". You say removing the time delay makes prior assignments intermediate assignments. What are "intermediate assignments"? And what is a procedural block? Sorry, I'm so stupid lol. \$\endgroup\$ – Its-a-me-mario Aug 30 at 21:11
  • \$\begingroup\$ @Its-a-me-mario to long to put in a comment, so I appended to my answer. I suggest finding a good online resource, book, or take a class on Verilog/SystemVerilog. \$\endgroup\$ – Greg Aug 30 at 22:24
  • \$\begingroup\$ Thanks for the explaination! I think I mostly understand. Still need to spend some time properly understanding <= and = as I'm not certain when I should use what. \$\endgroup\$ – Its-a-me-mario Aug 31 at 19:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.