1. Read the requirement into an interface
Every earlier chapter started from code. This one starts from a sentence, the way real work does:
A 4-bit counter
q.clearreturns it to 0.enableadvances it by one. When both are asserted in the same cycle,clearwins. With neither, it holds. After 15 it wraps to 0.
The first design step is to sort the sentence into what the outside can observe and what it can command. Observations become value methods; commands become Action methods.
| Phrase | BSV element |
|---|---|
"a 4-bit counter q" | Reg#(Bit#(4)), read by a value method |
"clear returns it to 0", "enable advances it" | commands: Action methods, or one Action taking both as arguments |
"clear wins" | a priority inside the next-state logic |
| "holds" | no write in that cycle |
| "wraps to 0" | Bit#(4) arithmetic, which is modulo 16 |
The graded problem declares the interface it grades against: one Action method
step(clear, enable) that takes both commands as Bool arguments, and a value method value.
Implement that interface, not a different one, because the grader calls the methods the problem
names. Separate clear and enable Action methods would also be a valid reading of the
sentence; the caution in section 3 says what that choice changes.
2. One register is the whole state
The counter's state is one value, so one register holds it: Reg#(Bit#(4)) q <- mkReg(0);.
The reset value is the reset from the fundamentals, applied before cycle 0. The wrap costs
nothing: adding 1 to a Bit#(4) holding 15 gives 0 at run time, because arithmetic keeps the
operand width. Only a literal 16 is rejected, as
types, widths and explicit conversion showed.
Check
q holds 15, enable is 1 and clear is 0. What does q hold after the edge?
3. Priority is exclusive branches in one action
Two commands can arrive in the same cycle, and the register can take only one next value. Write
the priority as if and else if inside one action so that exactly one branch writes:
Form
if (first) r <= valueA; // the winning command
else if (second) r <= valueB; // considered only when the first is absent
// neither branch: no write, the register holdsThe branch order is the priority. Two unconditional writes to the same register in one rule or
method are not "last one wins"; bsc rejects them with compile error G0004, because all
statements of an action happen together and a register cannot take two values at once. The
missing else is the hold.
Check
q holds 5, and in the same cycle clear is 1 and enable is 1. What does q hold after the edge?
Check
A method body contains q <= 0; followed by q <= q + 1; with no condition on either. What happens?
Caution. If an interface had two separate Action methods and a testbench could call both
in one cycle, the priority would no longer be decided by a branch inside one body; two callers
writing one register is the shadowing situation of
rules that share state. With the problem's single
step(clear, enable) method, both commands arrive in one call, and the if/else if above is
the whole answer.
4. Predict the counter before you build it
Fill in the table with the behaviour the requirement demands. Cycle 0 starts from the reset
value q = 0. The two input columns are clear and enable as the counter sees them in that
cycle, and the column you fill is q after the edge that ends the cycle.
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 | 0 | 1 | |
| 1 | 0 | 1 | |
| 2 | 1 | 1 | |
| 3 | 0 | 1 | |
| 4 | 0 | 0 | |
| 5 | 0 | 1 |
This is the browser model of the requirement, not your BSV. When your design is written, the grader runs the same kind of sequence against it with the real toolchain.
5. Choose the test cases from the requirement
A requirement with three behaviours needs more than one happy path. Before you run, list the cases the grader is likely to check and what each should show.
| Kind | Case | Expected |
|---|---|---|
| normal | enable for a few cycles | 0, 1, 2, 3 … one step per cycle |
| hold | neither asserted | the same value on consecutive observations |
| priority | clear and enable together | 0, regardless of the previous value |
| boundary | enable at 15 | 0 on the next observation |
| reset | after clear, then enable | counting resumes from 0 |
The design is finished when every row behaves, not when the sample output looks right. A fixed constant, an unintended write in the hold case, or reversed priority can fail different rows.
6. Apply it: two problems
The first Practice problem, expressions/select-op, is a pure function: a 2-bit sel chooses
whether the result is the AND, OR, XOR or NOR of two 4-bit operands. Its shape is the case of
selection, case, and the don't-care value, with one
arm per value, and its operators are those of
Bool, Bit and pure functions; NOR has no operator of
its own and is the complement of the OR.
The graded problem, modules-and-interfaces/clear-enable-counter, is the counter of this
chapter. Work in this order: read the interface the problem declares, instantiate the register,
write the action with the priority from section 3, and make this problem's value method report
the register unchanged, as in the first chapter. Run,
compare with your table from section 4, then submit for grading. Grading checks the rows of
section 5 against your module.
7. The design path
| Step | Chapter it comes from |
|---|---|
| sort the requirement into observations and commands | A module and its interface; Methods |
| one register per independent piece of state | Registers and one rule |
| next-state logic with explicit priority and a hold | Selection, case, and the don't-care value; Guards |
| width and wrap from the type | Types, widths and explicit conversion |
| rules that never compete for one register | Rules that share state |
| test the normal, boundary, priority and reset cases | Guards; this chapter |
This chapter closes the part of the course that builds a design from first principles. The chapters that follow hold the rules this part deliberately left out: the lexical and package details of a larger source tree, provisos and typeclasses, FIFOs and other library state, and the scheduling attributes that make a priority between rules explicit.