1. A synchronous reset is sampled at the edge like any other input
A register starts the simulation holding x, and it holds x until something assigns it. Reset is
the input that gives it a known value. In this course the reset is synchronous: it is tested inside
the always @(posedge clock) block, so it takes effect only at a rising edge where it is high, and
raising it between edges does nothing until the next edge.
Form
always @(posedge clock) begin
if (reset) count <= 4'd0;
else count <= count + 4'd1;
endCounter.v is exactly this block, the counter whose trace Registers and nonblocking assignment read line by line. In its testbench
reset is high across the first two rising edges and is lowered on the falling edge at time 20.
// A 4-bit counter with a synchronous, active-high reset.
module counter (
input clock,
input reset,
output reg [3:0] count
);
always @(posedge clock) begin
if (reset) count <= 4'd0;
else count <= count + 4'd1;
end
endmodulePractice this concept
Use this concept in a short Verilog problem as your next step.
Check
reset is lowered at time 20, on a falling edge. After which rising edge does count first hold 1?
An asynchronous reset, written into the sensitivity list, acts without waiting for an edge. The examples of this course do not use it, and neither does any Practice problem here.
2. Enable means update or hold
An enable input decides whether the register takes a new value at this edge or keeps its current
one. In a clocked block, holding is what happens when no statement assigns the register, so an
else if (enable) with no final else is the enable:
always @(posedge clock) begin
if (reset) count <= 4'd0;
else if (enable) count <= count + 4'd1;
// no else: count keeps its value
endIn Nets,
variables and the combinational always a missing branch in a combinational block was a defect,
because it forced storage into a circuit that should have none. In a clocked block the register is
the storage, and a path that assigns nothing simply means "hold". Operate the model below: clear
and enable are sampled at each edge, and q counts modulo 16.
Concept experiment · counter4
A browser model of the circuit, not a compiled design. The real toolchain runs in the examples.
Inputs
Outputs
- q
- 0
No edge has happened yet. Set the inputs, then apply a clock edge.
reset and clear are different inputs. The model's input is called clear, and so is the
input of the Practice problem clear-enable-counter in
Design from a requirement. In the code, a
synchronous clear looks exactly like this chapter's reset: the first branch of the chain, storing
0. The difference is its job. reset puts the design into its starting state; it is raised when the
system starts or restarts, and usually every register shares it. clear is a command of one block's
normal operation, like enable: the design that uses the counter raises it whenever it wants to start
counting again. A design can have both, and then reset comes first in the chain, clear second.
When a requirement names its inputs, use its names and its priority, not this chapter's.
3. Priority is the order of the if/else chain
When two inputs are high at the same edge, the chain decides which one wins: the first condition that is true takes the edge, and the later ones are not even examined. Put reset first and it wins over enable whatever enable is.
reset | enable | Branch taken | count after the edge |
|---|---|---|---|
| 1 | any | if (reset) | 0 |
| 0 | 1 | else if (enable) | current + 1 |
| 0 | 0 | none | current, held |
Check
count is 4. At the next rising edge reset is 1 and enable is 0. What does count hold after the edge?
A nested version breaks this rule in a way that compiles cleanly:
if (enable) begin
if (reset) count <= 4'd0;
else count <= count + 4'd1;
endCheck
In the nested version, reset is 1 and enable is 0 at an edge. What happens?
Fill in the table for the counter with the right priority. Both inputs are the values sampled at
the edge that ends each cycle; write q after that edge.
Predict, then compare · counter4
Fill in each cell before comparing. Empty cells count as a mismatch.
| Cycle | clearinputs sampled at the edge | enableinputs sampled at the edge | qafter the edge |
|---|---|---|---|
| 0 | 1 | 0 | |
| 1 | 0 | 1 | |
| 2 | 0 | 1 | |
| 3 | 0 | 0 | |
| 4 | 1 | 1 | |
| 5 | 0 | 1 |
4. Wrap where the requirement says, not where the width runs out
A 4-bit register wraps from 15 to 0 by itself: 15 + 1 is 16, and the low four bits of 16 are 0000. A decade counter has to wrap after 9, and the design must decide that on the edge where the current value is 9. The decision is one more branch, placed after reset and before the increment:
if (reset) count <= 4'd0;
else if (count == 4'd9) count <= 4'd0;
else count <= count + 4'd1;Compare with the last value you want to see, not the first value you want to avoid.
The whole counter is now one transition contract. At every rising edge, the first row whose condition holds decides the next value:
| Priority | Condition sampled at the rising edge | count after the edge |
|---|---|---|
| 1 | reset is 1 | 0, whatever enable and count are |
| 2 | enable is 1 and count is the last value, MAX | 0, the wrap |
| 3 | enable is 1 | count + 1 |
| 4 | none of the above | count, held |
The decade counter is this table with MAX = 9 and enable always 1; the if/else chain is the
table written top to bottom.
Check
The wrap branch is written else if (count == 4'd10) count <= 0;. What does the trace show?
5. Check every row of the contract in one run
WrapCounter.v follows the table with MAX = 5 in a 3-bit register, so it counts 0 to 5 and wraps.
The wrap is the inner if of the enable branch, so it happens only on an enabled edge.
// Counts 0 to 5 and wraps. Priority: reset, then enable, then hold.
module wrap_counter (
input clock,
input reset,
input enable,
output reg [2:0] count
);
always @(posedge clock) begin
if (reset)
count <= 3'd0;
else if (enable) begin
if (count == 3'd5) count <= 3'd0;
else count <= count + 3'd1;
end
// No final else: with enable low the register holds.
end
endmoduleTb.v changes reset and enable only on falling edges and prints one EDGE line per rising
edge. Two values are printed for the same register:
previscountread at the edge, in the same time step as the<=, before the update. It is the value theifchain decided from.countis printed by$strobe, which waits until the end of the time step, after the<=has updated the register. It is the value the edge produced, the same value a read on the next falling edge would see.
module tb;
reg clock = 0;
reg reset = 1, enable = 0;
reg [2:0] prev;
wire [2:0] count;
wrap_counter dut (.clock(clock), .reset(reset), .enable(enable), .count(count));
always #5 clock = ~clock;
// One line per rising edge: the value read at the edge, then the value after it.
always @(posedge clock) begin
prev = count;
$strobe("EDGE t=%0t reset=%b enable=%b prev=%0d count=%0d", $time, reset, enable, prev, count);
end
// Drive both inputs on the falling edge, half a period before they are sampled.
task apply(input r, input e);
begin
@(negedge clock);
reset = r; enable = e;
end
endtask
initial begin
// Count twice, hold once, then count up to 5.
apply(0, 1); apply(0, 1);
apply(0, 0);
apply(0, 1); apply(0, 1); apply(0, 1);
// Wrap to 0 and count once more, then reset while enabled and reset again.
apply(0, 1); apply(0, 1);
apply(1, 1);
apply(1, 0);
apply(0, 1);
@(posedge clock) #1 $finish;
end
endmoduleThe inputs reach the edges in this order: reset alone; enable twice; both low; enable five times;
reset with enable; reset alone again; enable. Use the contract table to predict count on the
lines that test a single row.
Check
EDGE t=35 reset=0 enable=0 prev=2 count=?
Check
EDGE t=75 reset=0 enable=1 prev=5 count=?
Check
EDGE t=95 reset=1 enable=1 prev=1 count=?
Check
reset stays 1 for the edges at 95 and 105. At 115 reset is 0 and enable is 1. What is count after the edge at 115?
Check the result. Press Run and compare the twelve lines with the table.
| Lines | Row of the contract | What to see |
|---|---|---|
t=5 | 1 | prev=x count=0: the register had never been assigned before the first reset edge |
t=15, t=25 | 3 | count is prev + 1 |
t=35 | 4 | prev=2 count=2, held |
t=45 to t=65 | 3 | 3, 4, 5 |
t=75 | 2 | prev=5 count=0, the wrap |
t=95, t=105 | 1 | 0 on both edges, with enable 1 and then 0 |
t=115 | 3 | 1, counting again from 0 |
On every increment or wrap line, prev and count differ. They agree on a hold line or when
reset writes 0 to a register that was already 0.
That is the edge itself: the chain reads the old value, and the new value exists only after the
nonblocking updates of the time step.
Change one thing. In Tb.v, replace $strobe with $display and run again. Predict first.
Check
With $display instead of $strobe, what does the count column show on each EDGE line?
The scheduling behind this, the active and nonblocking-update regions of one time step, is in
Registers and
nonblocking assignment. Put $strobe back before you go on.
6. Run, then fix the counter
Press Run on Counter.v above and read the trace with the previous chapter's rule: each EDGE
line shows the value before the edge, each AFTER line the value after. Count how many edges
reset is high and where the counting starts.
The checkpoint is the Practice problem decade-counter: the plain counter from above resets
correctly but keeps going to 10, 11, 12. Add the wrap branch between reset and increment, keeping
the synchronous reset. Its testbench prints at the rising edge, so read each line remembering that it
shows the value from before that edge when you compare the lines with your prediction.
The nested if of section 3 is a Practice problem of its own, reset-priority in
Testbench techniques: a counter that counts correctly
while enabled, yet a reset raised while enable is low leaves the value unchanged. When you reach
it, trace the nested if with reset=1 enable=0 and restructure it as one chain with reset first.
The accumulator of that chapter settles the same kind of priority with its clear input and checks
it against a model.
7. Summary
| Element | Meaning |
|---|---|
if (reset) inside always @(posedge clock) | synchronous reset: acts at the next rising edge |
else if (enable) … with no final else | update when enabled, otherwise hold |
| order of the chain | the first true condition wins the edge |
nested if (enable) if (reset) | reset ignored while enable is 0 |
else if (count == 4'd9) | wrap at a value the requirement sets |
| contract table | reset, then wrap, then increment, then hold: the first true row decides each edge |
read at the edge vs $strobe | the value before the edge vs the value after it |
reset vs clear | same code shape; reset starts the system, clear is a command of normal operation |