Build a 4-bit occupancy counter from its brief: up and down together hold, it stops at 0 and 15, a flush wins, and the reset is asynchronous.
Hardware context: A 4-bit occupancy counter for a 15-entry buffer. Build the occupancy counter from its brief: hold on up and down together, stop at 0 and 15, flush first.
A 15-entry buffer keeps a count of its full entries. At a rising edge, up says an entry arrived and down says one left; both together mean one arrived and one left, so the count holds. A flush (clr) empties the buffer and wins over everything else at that edge. The count never wraps: up at 15 stays 15 and down at 0 stays 0, so a broken neighbour cannot turn a full buffer into an empty one. rst_n is asynchronous and active low: the count is 0 as soon as rst_n falls, without waiting for an edge (lesson R1.2).
This is an Implement problem: write the body of occ_count from the brief. The fixture resets the counter, then runs twenty steps of one rising edge each and records count after every edge. Some steps pulse rst_n between two edges.
Brief: ports clk, rst_n, clr, up, down in and count[3:0] out; rising edge; asynchronous active-low reset to 0; one edge of latency; priority clr, then up or down; no wrap. Synthesis check: the design must build on the site's synthesis flow with no latch (an incomplete assignment in combinational logic is a latch). The cell and level counts come from an open-source flow and are a proxy for area and depth, not a foundry result.
Signals in the timeline
| Signal | Width | Role |
|---|---|---|
script | 80 | input of each check |
Full specification
module occ_count (
input logic clk,
input logic rst_n, // asynchronous, active low
input logic clr, // synchronous flush
input logic up, // an entry arrives at this edge
input logic down, // an entry leaves at this edge
output logic [3:0] count
);
// your design
endmodule
| At a rising edge | count becomes |
|---|---|
| clr = 1 (whatever up and down are) | 0 |
| up = 1, down = 0 | count + 1, or 15 if count is 15 |
| up = 0, down = 1 | count - 1, or 0 if count is 0 |
| up = 1, down = 1 | count (one in, one out) |
| up = 0, down = 0 | count |
| rst_n falls (at any time) | 0 at once, without an edge |
The result is count after each of the twenty edges: count_step0 (bits 3:0) to count_step19 (bits 79:76).
Examples
Example 1
Fill past fifteen, then drain- Input
up x17, up+down, down x2
- Output
count_step0 = 1, count_step1 = 2, count_step2 = 3, count_step3 = 4, count_step4 = 5, count_step5 = 6, count_step6 = 7, count_step7 = 8, count_step8 = 9, count_step9 = 10, count_step10 = 11, count_step11 = 12, count_step12 = 13, count_step13 = 14, count_step14 = 15, count_step15 = 15, count_step16 = 15, count_step17 = 15, count_step18 = 14, count_step19 = 13
Seventeen arrivals: the count climbs to 15 and stays there. Up and down together hold 15, then two departures give 14 and 13.
Example 2
Up and down together hold- Input
up x3, up+down x2, down, up+down, idle, down x3, up+down, down x2, up x2, up+down, up x3
- Output
count_step0 = 1, count_step1 = 2, count_step2 = 3, count_step3 = 3, count_step4 = 3, count_step5 = 2, count_step6 = 2, count_step7 = 2, count_step8 = 1, count_step9 = 0, count_step10 = 0, count_step11 = 0, count_step12 = 0, count_step13 = 0, count_step14 = 1, count_step15 = 2, count_step16 = 2, count_step17 = 3, count_step18 = 4, count_step19 = 5
After three arrivals the count is 3. Each up+down step leaves it unchanged; only a lone up or a lone down moves it.
Example 3
The flush wins- Input
up x5, clr+up, up x2, clr+down, up, clr, up+down, up x3, clr+up+down, down, up x3
- Output
count_step0 = 1, count_step1 = 2, count_step2 = 3, count_step3 = 4, count_step4 = 5, count_step5 = 0, count_step6 = 1, count_step7 = 2, count_step8 = 0, count_step9 = 1, count_step10 = 0, count_step11 = 0, count_step12 = 1, count_step13 = 2, count_step14 = 3, count_step15 = 0, count_step16 = 0, count_step17 = 1, count_step18 = 2, count_step19 = 3
clr+up at 5 gives 0, not 6; clr+down gives 0 as well. The flush takes precedence over every other input at that edge.
Constraints and contract
- The inputs change only between edges and are known 0/1 values.
- Keep the module name and the ports.
Hints
Hint 1
Sketch it first: one 4-bit register, and a cloud of logic that computes the next count from count, clr, up and down. Then write one always_ff for the register.
Hint 2
Write the rows of the table in priority order as an if ... else if chain. Which rows leave count as it is? Those need no branch at all in a clocked block.
Hint 3
The reset has to be in the sensitivity list to act without an edge: always_ff @(posedge clk or negedge rst_n). Up counts only when down is 0 and count is not 15; down mirrors it.
What the grader checks: Six directed and ten seeded scripts of twenty edges each, some with a reset pulse between two edges, are applied to the counter alone; count after every edge is compared with an independent model of the brief. Passing shows the priority, the limits and the asynchronous reset on these scripts; the synthesis check adds the latch count.
The submitted design must synthesize with 0 latches and no combinational loop. Counts come from the pinned open-source synthesis flow. They are proxies for logic size and depth, not physical area or timing.
16 checks on Icarus Verilog + Yosys · server. Run the examples first, then check the full regression. The suite is local and inspectable. A passing result establishes the tested cases, not a proof for all possible inputs.
See all 1 steps and the final capstone