Skip to content
code0.HDL

Reset, enable and priority

Give a register a synchronous reset and an enable, order the if/else chain so reset wins, and make a counter wrap where the requirement says rather than where the width runs out.

In this chapter

  • Write a synchronous reset inside the clocked block and say at which edge it takes effect
  • Add an enable as a branch that assigns nothing when it is low, and explain why a missing branch means hold here but a latch in a combinational block
  • Order an if/else chain so that reset wins over enable, and trace the nested version that silently ignores reset
  • Make a counter wrap at a value the requirement sets and predict the trace when the comparison is off by one
  • State a counter as one transition table (reset, wrap, increment, hold), check each row in a run, and explain why the value read at an edge differs from the value $strobe prints after it
Concepts in this chapter
  • Reset and enable priority
Prerequisite concepts

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;
end

Counter.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.

Counter.v
// 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
endmodule

Practice 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
end

In 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.

resetenableBranch takencount after the edge
1anyif (reset)0
01else if (enable)current + 1
00nonecurrent, held

Check

count is 4. At the next rising edge reset is 1 and enable is 0. What does count hold after the edge?

Your answer

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;
end

Check

In the nested version, reset is 1 and enable is 0 at an edge. What happens?

Your answer

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.

State table
Cycleclearinputs sampled at the edgeenableinputs sampled at the edgeqafter the edge
010
101
201
300
411
501

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:

PriorityCondition sampled at the rising edgecount after the edge
1reset is 10, whatever enable and count are
2enable is 1 and count is the last value, MAX0, the wrap
3enable is 1count + 1
4none of the abovecount, 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?

Your answer

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.

WrapCounter.v
// 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
endmodule

Tb.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:

  • prev is count read at the edge, in the same time step as the <=, before the update. It is the value the if chain decided from.
  • count is 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.
Tb.v
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
endmodule

The 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.

LinesRow of the contractWhat to see
t=51prev=x count=0: the register had never been assigned before the first reset edge
t=15, t=253count is prev + 1
t=354prev=2 count=2, held
t=45 to t=6533, 4, 5
t=752prev=5 count=0, the wrap
t=95, t=10510 on both edges, with enable 1 and then 0
t=11531, 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?

Your answer

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

ElementMeaning
if (reset) inside always @(posedge clock)synchronous reset: acts at the next rising edge
else if (enable) … with no final elseupdate when enabled, otherwise hold
order of the chainthe 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 tablereset, then wrap, then increment, then hold: the first true row decides each edge
read at the edge vs $strobethe value before the edge vs the value after it
reset vs clearsame code shape; reset starts the system, clear is a command of normal operation

Checkpoint

Submit the Practice problem for grading

Grading runs on the server against hidden tests; the result is recorded in this browser only.