always @(*)CRAFT cycle · 2.5 hours · Wed 5/27 · PM visit: Sagrada Família
HDL for Digital System Design · UCF ECE · Barcelona Summer 2026
| Phase | Time | Activity |
|---|---|---|
| 🌍 Contextualize | 10 min | Real-time decisions in Barcelona infrastructure |
| ⚠️ Reframe | 15 min | if/else vs case = different hardware |
| 🛠 Assemble | 70 min | Latch hunt · priority encoder · 4-bit ALU |
| 🛡 Fortify | 45 min | Sim · yosys show diff · first PPA compare |
| 🔗 Transfer | 10 min | Brief for the Sagrada visit · Day 4 preview |
▸ Phase 1 of 5 · ~10 min
Decisions that have to happen the instant the inputs change
Sagrada Família visit. Gaudí's designs are essentially massive combinational systems: every load distributes simultaneously through a branching structure. Take photos — we'll use them tomorrow.
All of today's hardware describes "input changes ⇒ output changes now." No clocks. No memory. Pure logic.
▸ Phase 2 of 5 · ~15 min
Same intent, different gates
if/else ≠ case in Hardware"They're equivalent — pick the prettier one."
if/else → priority mux chain. Later branches sit on a longer combinational path.case → parallel mux. All branches evaluated at once, tool picks by index.
case when branches are mutually exclusive (ALU opcodes, FSM states).if/else when priority is part of the spec (arbiters, interrupt handlers).
always @(*) and the signal must remember its old value → Yosys infers a latch. Cover every path → pure combinational logic. This is the bug you'll hunt in Ex 1.
// ❌ Buggy — no else, no default
always @(*) begin
if (sel == 2'b00) y = a;
if (sel == 2'b01) y = b;
// when sel == 2'b10 or 2'b11, y holds its previous value
// → Yosys infers a LATCH
end
// ✓ Fixed — default at the top
always @(*) begin
y = 1'b0; // default covers every path
case (sel)
2'b00: y = a;
2'b01: y = b;
2'b10: y = c;
2'b11: y = d;
endcase
end
found and reported 1 problem with "latch" in it = you have a bug. Always.
▸ Phase 3 of 5 · ~70 min · You build
Three builds, escalating complexity
if/else, then with casez. Same I/O, different gates.case on opcode: ADD, SUB, AND, OR, XOR. Wire to switches + LEDs.case, but an interrupt-style "abort" using if override. See how both compose.
if/else style
always @(*) begin
out = 3'd0;
if (in[3]) out = 3'd4;
else if (in[2]) out = 3'd3;
else if (in[1]) out = 3'd2;
else if (in[0]) out = 3'd1;
end
casez style
always @(*) begin
out = 3'd0;
casez (in)
4'b1???: out = 3'd4;
4'b01??: out = 3'd3;
4'b001?: out = 3'd2;
4'b0001: out = 3'd1;
endcase
end
casez makes it explicit with ? don't-cares; if/else hides it in branch order.
casemodule alu4 (
input wire [3:0] a, b,
input wire [2:0] op,
output reg [3:0] y
);
localparam OP_ADD = 3'd0, OP_SUB = 3'd1,
OP_AND = 3'd2, OP_OR = 3'd3, OP_XOR = 3'd4;
always @(*) begin
y = 4'd0; // default — kills latches
case (op)
OP_ADD: y = a + b;
OP_SUB: y = a - b;
OP_AND: y = a & b;
OP_OR: y = a | b;
OP_XOR: y = a ^ b;
default: y = 4'd0; // belt and suspenders
endcase
end
endmodule
Use upper switches for op, lower switches for a/b, LEDs for y.
▸ Phase 4 of 5 · ~45 min · Verify · test · harden · PPA
Latch-free, sim-clean, gate-counted
cd labs/week1_day03/ex1_latch_bugs/starter
make sim # TB outputs FAIL with an X if a latch is present
A latch can produce correct outputs if the inputs happen to drive it the right way. Sim + synth catches the latent case before silicon does.
yosys stat# Synthesize the SAME priority encoder three ways
yosys -p "synth_ice40 -top pe_if; stat" pe_if.v
yosys -p "synth_ice40 -top pe_case; stat" pe_case.v
yosys -p "synth_ice40 -top pe_casez; stat" pe_casez.v
Compare the SB_LUT4 count for each variant. Predict which is cheapest before reading the numbers.
This is the start of the PPA thread — it runs all the way to Day 14.
yosys showyosys -p "read_verilog pe_if.v; \
proc; opt; flatten; \
show -prefix pe_if -format svg"
Open pe_if.svg and pe_case.svg side by side on the projector. The if/else version is a visibly longer chain; the case version is a fan-in mux.
op through 0..4 with fixed a, b.3 - 5 wraps to 0xE in 4-bit unsigned.a = 4'b1100, b = 4'b1010, check AND/OR/XOR.op = 3'd7 — should be all-zeros, never X.▸ Phase 5 of 5 · ~10 min
Carry it to Sagrada this afternoon
case statement, splitting load into sub-loads.Thu 5/28 is the Montserrat excursion — no class. Day 4 is Friday 5/29.
Day 4 introduces time: always @(posedge clk), flip-flops, counters, a real blinker from the 25 MHz crystal. This is where you start using <= instead of = — the rule is simple; the reasoning is deep.
🔗 End of Day 3 · Sagrada Família 17:00
You can now build any combinational circuit, detect a latch, and read a Yosys schematic.
After Montserrat, Friday we add a clock — and everything changes.