Not on the Barcelona calendar — part of the "Keep Going" self-study track (baseline D13)
HDL for Digital System Design · UCF ECE · Barcelona Summer 2026
| Phase | Time | Activity |
|---|---|---|
| 🌍 Contextualize | 10 min | SV is what you'll write at a chip company · IEEE 1800 lingua franca |
| ⚠️ Reframe | 15 min | SV = Verilog + guardrails · intent declarations, not new hardware |
| 🛠 Assemble | 70 min | Refactor traffic light FSM · refactor UART TX · enum states · typedef struct |
| 🛡 Fortify | 45 min | PPA before / after must be identical · Verilator lint · 🤖 AI refactor critique |
| 🔗 Transfer | 10 min | Park Güell bridge · D13 SV for verification |
▸ Phase 1 of 5 · ~10 min
SV is what your first job offer will ask for
logic and always_ff.-g2012.Job posting reality: "Verilog/SystemVerilog" really means "we expect you to write SV; we'll read your Verilog." After today you'll do both.
SV was standardized as IEEE 1800 in 2005. It's not new. What's new is that the open-source tool stack finally supports enough of it for classroom use.
▸ Phase 2 of 5 · ~15 min
Guardrails, not a new language
"SV is to Verilog what C++ is to C — a different language with new paradigms I have to study from scratch."
SV is Verilog with guardrails. Five small additions (logic, always_ff, always_comb, enum, typedef) catch 80% of the bugs you've been writing all month.
Verilog-2001
module dff (
input wire clk,
input wire d,
output reg q
);
always @(posedge clk)
q <= d;
endmodule
SystemVerilog
module dff (
input logic clk,
input logic d,
output logic q
);
always_ff @(posedge clk)
q <= d;
endmodule
logic replaces both wire and reg — no more "wait, is this a reg or a wire?" mental tax.always_ff tells the tool "this is a flip-flop" — the compiler errors if you write combinational logic inside.// ❌ Verilog: this synthesizes — and creates a latch you didn't want
always @(*) begin
case (op)
2'b00: y = a;
2'b01: y = b;
// 10, 11 missing — y holds last value → LATCH
endcase
end
// ✓ SystemVerilog: tool ERRORS at compile time
always_comb begin
case (op)
2'b00: y = a;
2'b01: y = b;
// → "always_comb infers latch" — STOPS THE BUILD
endcase
end
always_comb + always_ff = intent. The tool checks your code matches what you meant.
enum States Replace localparam SoupVerilog
localparam IDLE = 3'd0;
localparam START = 3'd1;
localparam DATA = 3'd2;
localparam STOP = 3'd3;
reg [2:0] state;
// $display("state=%d", state); // 1, 2, …
SystemVerilog
typedef enum logic [1:0] {
IDLE, START, DATA, STOP
} state_t;
state_t state;
// $display("state=%s", state.name());
// → "state=START"
.name() for debug — readable waveforms, readable logs.▸ Phase 3 of 5 · ~70 min · Refactor & resimulate
Two refactors · one simulation · one PPA check
logic, always_ff, always_comb, typedef enum states, $display with .name(). Compile with iverilog -g2012.typedef struct packed for UART config (parameter group: CLKS_PER_BIT, parity preview).yosys stat diff. uart_pkg with shared typedefs. Import into both modules.
module traffic_light (
input logic clk, rst,
output logic [1:0] light // 00=R, 01=Y, 10=G
);
typedef enum logic [1:0] {RED, GREEN, YELLOW} state_t;
state_t state, next;
logic [3:0] tick;
always_ff @(posedge clk) begin
if (rst) begin state <= RED; tick <= 0; end
else if (tick == 4'hF) begin state <= next; tick <= 0; end
else tick <= tick + 1;
end
always_comb begin
next = state; // default — no latch
unique case (state)
RED: next = GREEN;
GREEN: next = YELLOW;
YELLOW: next = RED;
endcase
end
always_comb light = (state == RED) ? 2'b00 :
(state == YELLOW) ? 2'b01 : 2'b10;
always_ff @(posedge clk)
$display("[%0t] state=%s", $time, state.name());
endmodule
typedef struct packed// Group related config — pass as one signal
typedef struct packed {
logic [15:0] clks_per_bit;
logic parity_en; // preview: D13 parity exercise
logic parity_type; // 0=even, 1=odd
} uart_cfg_t;
module uart_tx_sv (
input logic clk, rst,
input uart_cfg_t cfg, // ← one port, three fields
input logic tx_start,
input logic [7:0] tx_data,
output logic tx_out, tx_busy
);
typedef enum logic [1:0] {IDLE, START, DATA, STOP} state_t;
state_t state;
logic [15:0] baud_cnt;
logic [2:0] bit_idx;
logic [7:0] data_latched;
// … FSM body unchanged from yesterday, with logic/always_ff …
endmodule
A single struct packed port replaces 3 separate inputs. Same bits on the wire; cleaner interface.
▸ Phase 4 of 5 · ~45 min · Identical hardware · safer source
Prove the refactor is free
yosys -p "synth_ice40 -top uart_tx; stat" uart_tx.v | grep SB_
yosys -p "synth_ice40 -top uart_tx_sv; stat" -sv uart_tx_sv.sv | grep SB_
| Version | SB_LUT4 | SB_DFF* | Fmax (MHz) |
|---|---|---|---|
| UART TX — Verilog | ? | ? | ? |
| UART TX — SystemVerilog | = | = | = |
verilator --lint-only -Wall -sv uart_tx_sv.sv
always_comb. SV catches this; lint reinforces it.default. Often a latch waiting to happen.Prompt: "Refactor this Verilog FSM to idiomatic SystemVerilog using logic, always_ff, always_comb, and a typedef enum for states. Keep the hardware identical."
enum for states? Or did it just rename localparams? The point is the type, not the keyword.default to the case? Or rely on always_comb to catch the latch later? Both work; defaults are clearer.unique case or priority case? If it picked one, ask why. (unique = "I promise exactly one match"; priority = "first match wins.")$display in simulation now prints state=RED instead of state=0.▸ Phase 5 of 5 · ~10 min · Park Güell · then assertions
Parameterization, modularity, and tiles
Gaudí's trencadís mosaic — broken tiles assembled into modular benches, ceiling medallions, salamander scales. One pattern, parameterized per surface.
A SystemVerilog typedef + parameter + generate is the silicon version of the same idea: repeating units with controlled variation.
generate block in one sentence. Bring to D13.
This deck fixed how RTL is written. The companion deck fixes how RTL is checked: assertions, constraint-based stimulus, and an AI-generated TB.
Your SV UART from here is the starting point — it gets 5+ assertions and an optional parity extension.
🔗 End of the SV-for-Design self-study deck
You wrote less code, the synth produced the same hardware, the lint caught real bugs.
Next in the track: SV checks the design before the design ships.