Day 3: Procedural Combinational Logic¶
Course: Accelerated HDL for Digital System Design¶
Week 1, Session 3 of 16¶
Student Learning Objectives¶
- SLO 3.1: Write combinational logic using
always @(*)blocks with correct use of blocking assignment (=). - SLO 3.2: Identify and prevent unintentional latch inference through default assignments and complete branches.
- SLO 3.3: Explain the synthesis implications of
if/else(priority mux chain) vscase(parallel mux) and choose appropriately. - SLO 3.4: Design a multi-operation ALU using
casestatement for opcode decoding. - SLO 3.5: Use
yosys showandyosys statto compare synthesized circuits (first PPA exposure).
Pre-Class Video (~45 min)¶
| # | Segment | Duration | File |
|---|---|---|---|
| 1 | The always @(*) block: wildcard sensitivity, reg in combinational contexts |
12 min | video/day03_seg1_always_star.mp4 |
| 2 | if/else and case/casez statements |
15 min | video/day03_seg2_if_else_case.mp4 |
| 3 | The latch problem: why it happens, how to prevent it | 12 min | video/day03_seg3_latch_problem.mp4 |
| 4 | Blocking (=) vs. nonblocking (<=) — rule for combinational: use = |
6 min | video/day03_seg4_blocking_vs_nonblocking.mp4 |
Key concepts:
- always @(*) + = = combinational logic — synthesis produces gates, not flip-flops
- Incomplete branches or missing defaults → Yosys infers latches (synthesis warning!)
- if/else creates a priority chain; case creates a parallel mux structure
- casez provides explicit don't-care matching for priority encoding
Session Timeline¶
| Time | Activity | Duration |
|---|---|---|
| 0:00 | Warm-up Q&A: Day 2 follow-up, pre-class questions | 5 min |
| 0:05 | Mini-lecture: latch detection, if/else vs case deep dive, ALU walkthrough | 35 min |
| 0:40 | Lab Exercise 1: Latch detection | 15 min |
| 0:55 | Lab Exercise 2: Priority encoder — if/else | 15 min |
| 1:10 | Lab Exercise 3: Priority encoder — casez | 10 min |
| 1:20 | Break | 5 min |
| 1:25 | Lab Exercise 4: Three-way synthesis comparison (PPA seed) | 10 min |
| 1:35 | Lab Exercise 5: 4-bit ALU | 25 min |
| 2:00 | Lab Exercise 6 (Stretch): Mixed ALU | 15 min |
| 2:15 | Debrief: synthesis comparison discussion | 10 min |
| 2:25 | Preview Day 4 | 5 min |
In-Class Mini-Lecture (35 min) — expanded¶
Latch Detection with Yosys (10 min)¶
- Live demo: synthesize buggy code with an incomplete
if(noelse) — observe the Yosys latch warning - Use
yosys showto visualize the inferred latch in the netlist — "this is not what you intended" - Fix: default assignments at the top of
alwaysblocks, or ensure every branch is complete - Rule: if Yosys says "latch," you have a bug. Always.
if/else vs case — Synthesis Deep Dive (15 min)¶
if/else→ priority mux chain: each condition evaluated in order, later branches have longer combinational pathscase→ parallel mux: all branches evaluated simultaneously, tool selects by index- Live Yosys comparison: Synthesize a priority encoder using
if/else, then usingcase. Runshowon both — inspect the generated circuits side by side on the projector. casezfor don't-care matching — when priority IS intended,casezis explicit about it- Design heuristic: Use
casewhen all conditions are mutually exclusive (ALU opcodes, FSM states). Useif/elsewhen priority matters (interrupt controllers, arbiters). Usecasezfor pattern matching with explicit don't-cares. - Timing implication preview: Priority chains have longer worst-case paths — matters for Fmax. "We'll quantify this on Day 10."
ALU Design Walkthrough (10 min)¶
- 4-bit ALU using
casefor opcode decode: ADD, SUB, AND, OR, XOR - Walk through the code structure, discuss why
caseis natural for opcode decoding - Mention
defaulthandling — what should the ALU output for undefined opcodes?
Simulation as Latch Detective (2 min — quick callout)¶
- "Today's TBs detect latches before synthesis — a latch produces X in simulation, which the TB catches"
- Show the pattern:
if (output === 3'bxxx)→ FAIL → you have a latch - "Simulation + synthesis warnings = two independent checks. Trust both."
Lab Exercises¶
Exercise 1: Latch Detection (15 min)¶
Objective (SLO 3.2): Identify and fix latch inference in provided buggy code.
Tasks:
1. Download the provided buggy_comb.v file (or type in the buggy code from the handout).
2. Synthesize with Yosys. Find the latch warning in the output.
3. Use yosys show to visualize the latch in the netlist diagram.
4. Fix the code by adding a default assignment. Re-synthesize and confirm the latch warning is gone.
5. Try a second bug: case statement with a missing branch (no default). Observe, fix, and verify.
Simulation checkpoint: Run make sim in ex1_latch_bugs/starter/ — tb_latch_bugs.v detects latches by checking for X outputs. If any check prints FAIL with an X value, the latch hasn't been fixed yet.
Checkpoint: Both buggy files synthesize latch-free after fixes. Student can explain why each fix works.
Exercise 2: Priority Encoder — if/else (15 min)¶
Objective (SLO 3.1, 3.3): Implement a 4-input priority encoder using if/else chains.
Tasks:
1. Create priority_enc.v with input [3:0] req and output reg [1:0] grant.
2. Implement using always @(*) begin ... end with if/else chain: highest-numbered request wins.
3. Include a valid output that indicates whether any request is active.
4. Synthesize with Yosys and inspect the circuit using show — observe the priority mux chain.
Simulation checkpoint: Run make sim in ex2_priority_encoder/starter/ — exhaustively tests all 16 request patterns. Every input must map to the correct highest-priority encoding.
Checkpoint: Priority encoder synthesizes cleanly (no latch warnings), produces correct output.
Exercise 3: Priority Encoder — casez (10 min)¶
Objective (SLO 3.3): Re-implement the priority encoder using casez and compare the synthesis result.
Tasks:
1. Create priority_enc_casez.v using casez(req) with don't-care patterns: 4'b1???, 4'b01??, 4'b001?, 4'b0001.
2. Synthesize with Yosys and run show.
3. Compare visually: does the casez version look different from the if/else version? (They should be similar — both express priority.)
Checkpoint: casez version synthesizes and matches behavior of if/else version.
Exercise 4: Three-Way Synthesis Comparison (10 min) — PPA seed¶
Objective (SLO 3.5): First hands-on PPA exposure — compare LUT counts across implementations.
Tasks:
1. You now have three versions of the same logic: if/else, case (non-priority), and casez.
2. Run yosys stat on each version. Record the LUT count for each in a simple table:
| Implementation | LUTs |
|---|---|
if/else |
|
case |
|
casez |
- Are they the same? Different? Why? (Brief discussion — full analysis comes on Day 10.)
Checkpoint: LUT counts recorded. Student can articulate at least one observation about the differences (or lack thereof).
Cross-cutting thread note: This 10-minute exercise plants the seed for PPA analysis that becomes a major thread from Day 10 onward. Students will reference these numbers later.
Exercise 5: 4-Bit ALU (25 min)¶
Objective (SLO 3.1, 3.4): Implement a multi-operation ALU — the first "real" design.
Tasks:
1. Create alu.v with inputs a[3:0], b[3:0], opcode[2:0] and output result[3:0].
2. Implement at minimum: ADD (000), SUB (001), AND (010), OR (011), XOR (100).
3. Include a default case for undefined opcodes (output zero or hold — discuss the trade-off).
4. Create a top module wiring buttons to inputs and displaying the result on the 7-seg decoder from Day 2.
5. Program the Go Board and verify: manually test at least ADD, SUB, and AND.
Simulation checkpoint: Run make sim in ex3_alu/starter/ — tb_alu_4bit.v tests ADD, SUB, AND, OR with selected vectors including zero-flag and carry/borrow edge cases. All must pass before going to hardware.
Checkpoint: ALU on hardware. Multiple opcodes verified by changing button inputs and observing 7-seg output.
Exercise 6 (Stretch): Mixed ALU with Overflow (15 min)¶
Objective (SLO 3.3, 3.4): Demonstrate appropriate mixed use of case and if/else in one module.
Tasks:
1. Extend the ALU with an overflow output flag.
2. Use case for opcode decoding (parallel — opcodes are mutually exclusive).
3. Use if/else within the ADD/SUB branches for overflow detection (priority — check sign bits in order).
4. Synthesize and compare with the base ALU using yosys stat.
Deliverable¶
ALU running on hardware + screenshot comparing yosys show output for if/else vs case priority encoders.
Submit: ALU source file, top module, and synthesis comparison screenshot.
Assessment Mapping¶
| Exercise | SLOs Assessed | Weight |
|---|---|---|
| 1 — Latch detection | 3.2 | Core |
| 2 — Priority encoder (if/else) | 3.1, 3.3 | Core |
| 3 — Priority encoder (casez) | 3.3 | Core |
| 4 — Synthesis comparison | 3.5 | Core |
| 5 — 4-bit ALU | 3.1, 3.4 | Core — graded deliverable |
| 6 — Mixed ALU | 3.3, 3.4 | Stretch (bonus) |
⚠️ Common Pitfalls & FAQ¶
Day 3 introduces
always @(*)blocks — and with them, the most common bug in RTL design: unintended latches.
- Yosys says "latch"? This is always a bug. It means some output isn't assigned in every branch of your
if/elseorcase. Fix: add adefaultcase, or (better) add default assignments at the top of thealwaysblock, before anyif/case. - Simulation says "FAIL" with X values? X values in simulation mean "unknown" — your signal was never driven. In the latch_bugs exercise, this is how the testbench detects latches: a latch holds the previous value, which starts as X. The Yosys warning and the TB's X-detection are two independent checks for the same bug.
if/elsevscase— does it matter? They synthesize differently.if/elsecreates a priority chain (each condition checked in order).casecreates a parallel mux (all branches evaluated simultaneously). Usecasewhen conditions are mutually exclusive (opcodes, FSM states). Useif/elsewhen priority matters (arbiters). Usecasezwhen you need don't-care pattern matching. We'll quantify the timing difference on Day 10.- What should the ALU output for an undefined opcode? If your
casecovers all 4 opcodes (2'b00through2'b11), there's nothing undefined — a 2-bit signal can only take those 4 values. But adefaultis still good practice to prevent latches if you later add more opcodes. Output zero in thedefaultcase.
Preview: Day 4¶
Sequential logic — flip-flops, clocks, counters, and the crucial <= nonblocking assignment. Everything so far has been combinational (outputs depend only on current inputs). Tomorrow, your circuits gain memory. Watch the Day 4 video (~50 min).