Last time I talked about how to create an adder in Verilog with an eye to putting it into a Lattice iCEstick board. The adder is a combinatorial circuit and didn’t use a clock. This time, we’ll finish the demo design and add two clocked elements: a latch that remembers if the adder has ever generated a carry and also some counters to divide the 12 MHz clock down to a half-second pulse to blink some of the onboard LEDs.
Clocks are an important part of practical digital design. Suppose you have a two input
AND gate. Then imagine both inputs go from zero to one, which should take the output from zero to one, also. On paper, that seems reasonable, but in real life, the two signals might not arrive at the same time. So there’s some small period of time where the output is “wrong.” For a single gate, this probably isn’t a big deal since the delay is probably minuscule. But the errors will add up and in a more complex circuit it would be easy to get glitches while the inputs to combinatorial gates change with different delays.
The most common solution to this is to only “look” at the signals (and store them in a flip flop) on a clock edge (usually, just the rising edge). Now the circuit will work fine if the longest delay from one flip flop’s output to the next flip flop’s input is less than the period of the clock. This makes things much simpler to design.
If you need a refresher on flip flops, they are elements that remember a single bit. A D flip flop will remember its input (named D) at the clock edge and hold that output until the next clock edge. There are other kinds of flip flops, like the T flip flop (which toggles state) or the JK flip flop which can perform several functions. With Verilog, you generally won’t create flip flops directly, but will let the compiler infer them from your code.
Let’s jump right in with some examples. I’ll explain these each in more details as we go. Consider this code:
reg myoutput; wire myinput; always @(posedge clk) myoutput<=myinput;
This would infer a D type flip flop. The compiler will recognize other types, too. For instance:
reg myoutput; wire myinput; always @(posedge clk) myoutput<=myinput?~myoutput:myoutput;
This would infer a T flip flop. Usually, though, the inference is not this direct. The input might be a logic expression. The compiler can also infer counters which are lots of flip flops:
reg [3:0] ctr; always @(posedge clk) begin if (ctr_reset) ctr<=4'b0; else ctr<=ctr+1; end
Just as using the plus operator allowed the Verilog compiler to do the best thing for an adder, the expression above will let it build an efficient counter without you having to worry about the details. You can build a counter out of individual modules that infer flip flops (or modules that your tool provides for you) but it is better to leave the details to the compiler.
Building a Flip Flop
The demo circuit had three distinct parts: the binary adder circuit from last time is already done. Another part of the example design is to provide an output that latches when a carry is generated. Here’s the part of the code that does that:
reg carrylatch; // latch carry result always @(posedge clk) begin if (reset==1'b1) carrylatch<=1'b0; else begin if (carry) carrylatch<=1'b1; end end
In English, this says that when the clock has a rising edge, check to see if the reset line is high. If it is, clear the carry latch. Otherwise, check to see if the carry is set and if so, set the carry latch. It will remain set until a reset clears it.
The Verilog tool will recognize this is a flip flop with synchronous reset. If you get really concerned about performance, you may want to investigate if your FPGA does better with an asynchronous reset and learn how your tool can be told to do that instead. But for now, this is sufficient. The realization will probably be a D type flip flop with a rising edge-sensitive clock input and a clock enable tied to the carry line. The D input will be tied to a logic 1.
Key Verilog Point #2: Blocking vs Non-Blocking Assignments
Did you notice that some assignments use
= and some use
<=? This is an important Verilog feature. When you are using assignments, you always use the equal sign. If you are writing a sequential block, you almost never want to use the single equal sign, even though Verilog will allow this. Here’s why:
always @(posedge clk) begin a<=1’b1; b<=a; end
Because the nonblocking assignment (
<=) appears, the value of b will become whatever a was at the moment the clock edge occured. That is, all the assignments in the block happen all at one time. In simulation, that means they happen at the end statement since simulations have to pretend everything happens in parallel. In an FPGA, parallel execution is just how the hardware works.
The problem is, if you do not use a non-blocking assignment. Suppose we had:
always @(posedge clk) begin a=1’b1; b=a; end
The Verilog compiler is smart enough to know that b should equal 1 in this case and has to generate extra circuitry (a latch) to make sure b isn’t set at the same time as a. This can cause lots of timing issues and unless you are sure you need to do it and understand the ramifications, you should avoid it at all costs.
Key Verilog Point #3: Default Net Types
You may notice that some of the variables in the Verilog code are of type wire and some are of type reg. A wire has to be constantly driven to some value. A reg is more like a regular variable. A reg may, but doesn’t always, infer a flip flop. However, you can set a value in a reg and it sticks.
One problem you wind up with in Verilog is that if you make up a name, the compiler (by default) will assume you mean for it to be a wire unless you tell it otherwise. That sounds handy, but the problem is if you misspell a name, it just becomes a new wire and then you can’t figure out why your code doesn’t do what you want.
The answer is to always include this at the front of a Verilog file:
This causes the compiler to throw an error if you use an undeclared net. That will save you a lot of debugging time wondering why things aren’t working.
Counting and Dividing
The remainder of the Verilog takes the 12MHz clock and uses it to drive a 16 bit counter. When the counter overflows, another counter increases. When that counter reaches 91, the secondary counter goes to zero. This takes roughly 1/2 second at 12MHz.
You can figure that out by noting that 12MHz is 83 ns or .000083 us. A 16-bit counter will overflow on the 65536th count (two to the 16 power). Do the math and that comes out to nearly 5.5ms per overflow. If you let the secondary counter go to 91, that will take almost 497ms. If you go to 92, you go over (502 ms). Note that counting to 91 (or 92) only takes a 7 bit counter. A graphical representation of the situation is shown here with the code for it below.
// The 12MHz clock is too fast // The first counter will / 2^16 (about 5.46ms) // Then the second counter goes to 91 which is 0.497s // close enough to 1/2 second for our purpose always@(posedge clk) begin if (reset==1'b1) begin cnt1<=0; cnt2<=0; half_sec_pulse<=0; dec_cntr<=0; end else if (runstop==1'b0) // don't do anything unless enabled begin cnt1 <= cnt1 + 1; if (cnt1 == 0) if (cnt2 == 91) begin cnt2 <= 0; half_sec_pulse <= 1; end else cnt2 <= cnt2 + 1; else half_sec_pulse <= 0; if (half_sec_pulse == 1) dec_cntr <= dec_cntr + 1; // count half seconds end end
(Note: as mentioned in the comments below, there’s nothing special about a 16-bit counter. I just wanted to show a nested counter, but since this example doesn’t use the intermediate clock, you could have just as easily made a single longer counter to do the job with one division. The FPGA doesn’t care if you make a 2 bit counter or a 60 bit counter unless you run out of resources.)
This is a form of sequential circuit and the counters will turn into a chain of flip flops when synthesized. Here’s the definition for the counters:
// Manage 12MHz clock reg [15:0] cnt1; reg [6:0] cnt2; reg [1:0] dec_cntr; reg half_sec_pulse;
The counter declarations look like arrays, but they aren’t (Verilog does support arrays, but these are not arrays). The numbers in square brackets are telling you the number of bits in the value. So cnt1 has 16 bits numbered from 15 (the most significant) to 0 (the least significant).
We’ll use the array-like bit notation and the assign statement to make some LEDs blink too:
// Make the lights blink assign LED4 = (dec_cntr == 2); assign LED5 = dec_cntr;
Updating the Test Bench
Since the new design requires a clock, the testbench has to provide it. It would be very annoying to have to write each clock transition. Luckily, you don’t have to. Here’s how the clock generation works:
always begin #1 clk<=~clk; end
In English, this says: At all times, you should delay one clock cycle (the #1) and then invert the clock signal and keep doing that forever. Another item to consider is the FPGA reset:
rs=1'b0; // run/stop reset=1'b1; #10 reset=1'b0;
This bit of code sets the reset line, holds it for 10 clock cycles, and then clears it.
At the end of the test bench is a 400 cycle delay just to let the counters do something.
There’s one small problem with the simulation. The 12 MHz divider won’t do anything interesting in “only” 400 cycles. It isn’t uncommon to change magic numbers to smaller values when simulating. In this case, I change the primary counter increment to 8000 hex so it will flip every other clock cycle and then changed the test for 91 down to a more reasonable value.
You can see the entire code on EDAPlayground and you can even run the simulation from there. The waveform shown here will appear. If you want to know more about how it all works, check out the video and I’ll walk through it step by step.
Next time, I’ll show you how to take the Verilog (which should work since it simulates correctly) and push it down to the FPGA board. If you’ve been paying attention, you should have at least one serious question: How do I tell someone that LED1, for example, maps to the LED on the board? That’s a great question, and I’ll answer it next time. Here’s a clue though: It doesn’t depend on the name of the net. I could have called that signal BigJim and I’d still be able to map it to the LED. If you plan to work along, you can get a head start by installing the open source tool kit now. Of course, if you don’t have an iCEstick, that won’t do you much good unless you just want to dry run the tools.
If you are looking for a detailed Verilog tutorial, try these:
- Doulos (host of EDAPlayground) has a very professionally done set of tutorials
- Another tutorial set up as a self study course
- The creator of EDAPlayground has a series on YouTube that would be helpful, especially if you are using EDAPlayground