Skip to content
code0.HDL

12Implementation

Checkpoint B: a counter with clear and enable

Problem

Intended behavior. ClearEnableCounter holds a 4-bit count q. At every rising edge it picks its next value from two control inputs:

clearenableq after the edge
1any0
01q + 1, and 0 after 15
00unchanged

q is 0 after the module's implicit synchronous reset. clear is a different signal: an ordinary input, part of the design's function, that zeroes the count at the next edge whenever it is high. Reset returns the whole module to its starting state; clear is what the surrounding logic uses to restart the count during normal operation, so it must work while reset is low.

This contract differs from the other problems in this chapter. EdgeCounter counted events and only reset could zero it; ErrorMonitor had a flag that only reset cleared. Here a functional input zeroes the register, and it takes priority over counting.

Current behavior. The starter declares the register and connects it to q, but never gives it a next value, so q is 0 on every line of the public run.

Task. Write the update. The declaration val q = RegInit(0.U(4.W)) and the connection io.q := q stay; the TODO line between them is where the next value goes. Keep the ports and Main unchanged.

Read the starter

RegInit(0.U(4.W)) already fixes two parts of the contract: the reset value and the width. A 4-bit register cannot hold 16: it stores only the low four bits of the assigned sum, so 15 wraps to 0. The three rows of the table are three mutually exclusive cases with a fixed priority.

Predict before running

The public run drives enable for four cycles, holds for two, raises clear together with enable for one cycle, then counts for two more. Each line prints the inputs and q before that cycle's edge. Write the q column for the starter and for a correct design: the correct column is 0 1 2 3 4 4 4 0 1, and the last line shows q=2.

Make the change and explain

Write the three cases in priority order with the conditional connection the Learn chapter uses for RegInit: the first case that applies wins, and a register that no case connects in a cycle keeps its value. Run, compare with your prediction, and point to the line that makes the clear row win when both inputs are high.

Completion check

  • With reset low, twenty enabled cycles from 0 pass 15 and continue from 0; 16 never appears.
  • clear high gives 0 at the next edge, whatever enable and q are.
  • With reset and clear low, enable low keeps q unchanged for as many cycles as it stays low.
  • While reset is high, q is 0 at every edge even with enable high.
  • Any interleaving of clear and enable follows the table, not only the public sequence.

Progressive hints

Hint 1

The table has three rows and a priority: the first row applies whatever enable says. The sequential circuits chapter updates a RegInit register with := inside a condition. What happens to that register in a cycle where no condition connects it?

Hint 2

A chain of when and .elsewhen with no .otherwise says exactly "the first matching row wins, otherwise hold". Put the clear row first.

Hint 3

Adding 1.U with + keeps the register's width, so 15 + 1 is 0 without a comparison. Compare that with the Learn chapter's wrapCounter, which needs an explicit comparison because its maximum is not one less than a power of two.

Variation

Change the register to 3 bits and predict whether the public sequence reaches the first wrap. How many consecutive enabled edges from 0, with clear low, would reach it? Then try 5 bits and explain which bits of the count io.q shows and whether this public sequence reveals the truncation. Finally, give clear the lower priority and find every public line that changes.

Review this concept
Ready

CheerpJ runs Chisel in your browser. A cold Run downloads about 14.5 MB of Java and 47 MB of JARs. Compilation can take a minute. Licenses

Main.scala