Exercises — Verilog - VHDL syntax basics
Level 1 — Recognition
Exercise L1.1 — Name the connection
State whether each Verilog line describes combinational logic (output is a function, always) or sequential logic (output remembers, updates on a clock edge). (Reminder: ^ is XOR, & is AND, <= is the clocked non-blocking assignment — all defined just above.)
assign y = a ^ b;always @(posedge clk) q <= d;always @(*) y = a & b;
Recall Solution L1.1
The clue is what triggers the update.
assign= continuous —yre-evaluates the instantaorbchanges. Combinational. (^is XOR: 1 when the two bits differ.)always @(posedge clk)fires only on a rising clock edge, and storesdintoquntil the next edge;<=marks it as a register update. Sequential.always @(*)re-runs whenever any right-hand-side input changes, with no clock, soytracksa & b(AND) continuously. Combinational.
Rule map: assign and always @(*) → combinational; always @(posedge clk) → sequential. See Combinational vs Sequential Logic.
Exercise L1.2 — Pick the assignment operator
For each block, which operator belongs in the blank, = or <=? (Reminder: | is bitwise OR — 1 if either input is 1.)
always @(posedge clk) begin q ___ d; endalways @(*) begin y ___ a | b; end
Recall Solution L1.2
Apply the Golden Rule: clocked → <=, combinational → =.
- This is
posedge clk(clocked) →<=(non-blocking). - This is
always @(*)(combinational) →=(blocking).
Mnemonic from the parent: the arrow <= "waits for the edge"; plain = "equals now."
Exercise L1.3 — Read a literal
What decimal value does 4'hC represent, and how many wires does it drive?
Recall Solution L1.3
The prefix 4'h means 4 bits wide, base hexadecimal. The hex digit C = binary 1100.
- Binary
1100= . - Value = 12, and it drives 4 wires (one physical line per bit). See Number Systems and Bit-Widths.
Level 2 — Application
Exercise L2.1 — Concatenation value
Give the 8-bit value (binary and hex) produced by {4'b1100, 4'b0011}.
Recall Solution L2.1
Concatenation {high, low} glues bit-groups left-to-right, high bits first.
- High nibble
1100, low nibble0011→11000011. - Group into hex:
1100=C,0011=3→8'hC3. - Check decimal: , and `0xC3 = 12\cdot16 + 3 = 195$. ✓
Exercise L2.2 — Write a 4-input AND (Verilog and VHDL)
Write a module that outputs y = a AND b AND c AND d using continuous (combinational) assignment, once in Verilog and once in VHDL.
Recall Solution L2.2
Verilog (& = AND):
module and4 (input a, input b, input c, input d, output y);
assign y = a & b & c & d; // continuous → combinational
endmoduleVHDL (the interface is the entity, the behaviour is the architecture; and is the keyword, and <= here is a concurrent signal assignment, not a clocked one):
entity and4 is
port ( a, b, c, d : in std_logic;
y : out std_logic );
end and4;
architecture rtl of and4 is
begin
y <= a and b and c and d; -- concurrent → combinational
end rtl;Why assign / concurrent <=? There is no memory and no clock — y must always equal the AND of the four inputs, instantly. Both forms create a permanent wire relationship.
Exercise L2.3 — Complete the D flip-flop with reset (fill Verilog, then read its VHDL twin)
Fill the blanks so this is a correct positive-edge D flip-flop with synchronous reset to 0.
module dff (input clk, input rst, input d, output reg q);
always @(_____) begin
if (rst) q ___ 1'b0;
else q ___ d;
end
endmoduleRecall Solution L2.3
Verilog:
module dff (input clk, input rst, input d, output reg q);
always @(posedge clk) begin // synchronous → sample only on clock edge
if (rst) q <= 1'b0; // clocked → non-blocking
else q <= d;
end
endmoduleThe same flip-flop in VHDL (a process plays the role of always; rising_edge(clk) is posedge clk):
entity dff is
port ( clk, rst, d : in std_logic;
q : out std_logic );
end dff;
architecture rtl of dff is
begin
process (clk) begin
if rising_edge(clk) then -- synchronous
if rst = '1' then q <= '0';
else q <= d;
end if;
end if;
end process;
end rtl;Why posedge clk / rising_edge(clk)? Synchronous reset means the reset only acts at the clock edge, so rst lives inside the clocked block. Why <=? Clocked storage → non-blocking. See Flip-Flops and Latches.
Level 3 — Analysis
Exercise L3.1 — Blocking swap
Two registers a and b start at a=1, b=0. What are their values after one clock edge for each block?
Block A (blocking):
always @(posedge clk) begin
a = b;
b = a;
endBlock B (non-blocking):
always @(posedge clk) begin
a <= b;
b <= a;
endRecall Solution L3.1
Block A (=, blocking): lines execute in order, updating immediately.
a = b;→abecomes0.b = a;→ reads the newa(which is now0) →bbecomes0.- Result:
a=0, b=0— the swap is destroyed,awas clobbered.
Block B (<=, non-blocking): all right-hand sides are sampled first (using old values), then all left-hand sides update together.
- RHS sampled:
b=0,a=1(old values). - Then assign:
a<=0,b<=1. - Result:
a=0, b=1— a genuine swap. ✓
This is why real flip-flops need <=: on one edge every register grabs its input simultaneously. See Synthesis vs Simulation.
Exercise L3.2 — Shift register vs parallel load
Given a=1, b=0, c=0 initially, what are a,b,c after one clock edge?
always @(posedge clk) begin
b <= a;
c <= b;
endRecall Solution L3.2
Non-blocking → all RHS sampled from old values first:
- old
a=1, oldb=0. - Then:
b <= 1,c <= 0. ais not assigned here, so it keeps1.- Result:
a=1, b=1, c=0.
Notice c got the old b (0), not the new one. This is the correct shift-register behaviour: on each edge the "wave" moves one stage. Had this been blocking =, b would update to 1 first and c would also grab 1 — collapsing two stages into one edge (a classic bug).
Exercise L3.3 — Spot the inferred latch
Does this combinational block create an unintended latch? If so, on which input pattern is the old value remembered?
always @(*) begin
if (sel) y = a;
endRecall Solution L3.3
Yes — it infers a latch. In a combinational block, every output must be assigned on every path.
- When
sel = 1:y = a. Fine. - When
sel = 0:yis never assigned → the tool must remember the previousy→ it builds a latch (memory you didn't ask for). - So the old value is held whenever
sel = 0.
The figure below traces exactly this decision: follow the two branches out of if (sel) and watch which one fails to drive y.
Fix: give a default, e.g. y = 1'b0; before the if, or add an else y = ...;. Then y is defined on all paths and stays purely combinational.
Figure — the latch decision tree. The block wakes up on always @(*), then splits at if (sel). Follow the mint (sel = 1) branch: y is assigned, so the path is pure combinational (mint box, bottom-left). Follow the coral (sel = 0) branch: y is not assigned, so the tool must remember the old y — a latch is born (coral box, bottom-right). The italic caption shows the fix. Use this picture to see why "assign on every path" removes the latch: it collapses both bottom boxes into the mint one.

Level 4 — Synthesis
Exercise L4.1 — 2-to-1 multiplexer (no latch)
Write a combinational Verilog module mux2 with inputs a, b, sel and output y, such that y = a when sel = 0 and y = b when sel = 1. Make sure it infers no latch.
Recall Solution L4.1
Every path must assign y, so we use a complete if/else (or a default).
module mux2 (input a, input b, input sel, output reg y);
always @(*) begin
if (sel) y = b; // sel = 1
else y = a; // sel = 0 → every path assigns y
end
endmoduleWhy =? always @(*) is combinational → blocking. Why complete if/else? Both branches drive y, so no old value is ever remembered → no latch. (A one-liner assign y = sel ? b : a; works too and is even cleaner.)
Exercise L4.2 — 4-bit up-counter
Write a Verilog module counter4 with clk, rst, and 4-bit output count. On each rising edge, count increments by 1; a synchronous reset sets it to 0. What value follows count = 4'hF?
Recall Solution L4.2
module counter4 (input clk, input rst, output reg [3:0] count);
always @(posedge clk) begin
if (rst) count <= 4'd0; // clocked → non-blocking
else count <= count + 1;
end
endmodule[3:0] declares a 4-bit vector (bit 3 = MSB). Wrap-around: 4 bits hold values 0–15. After 4'hF (= 15 = 1111), adding 1 overflows to 10000, but only the low 4 bits are kept → 0000. So 4'hF is followed by 4'h0 — the counter naturally wraps every 16 edges. See Number Systems and Bit-Widths.
Exercise L4.3 — Registered adder
Build add_reg: on each clock edge it stores the sum of two 4-bit inputs x and y into a 5-bit output s (5 bits so the carry-out fits). Give the module.
Recall Solution L4.3
module add_reg (input clk, input [3:0] x, input [3:0] y, output reg [4:0] s);
always @(posedge clk) begin
s <= x + y; // clocked → non-blocking; 5-bit result holds carry
end
endmoduleWhy 5 bits? Two 4-bit numbers max out at , which needs bits (11110). A 4-bit output would drop the carry and give a wrong sum on overflow. Why <=? The result is stored on the edge → sequential → non-blocking.
Level 5 — Mastery
Exercise L5.1 — Simulation vs synthesis mismatch
The following combinational logic uses non-blocking assignments where blocking was needed. Compute y in simulation vs what a synthesizer would build, given a just changed to 1 (previously all signals 0). (& is AND; 1'b1 is a 1-bit constant 1, so a & 1'b1 just equals a.)
always @(*) begin
t <= a & 1'b1; // wrong operator for combinational
y <= t;
endRecall Solution L5.1
Simulation with <= in a combinational block: RHS are sampled from old values, so:
t <= a→ schedulest = 1, but reads oldt = 0for the next line.y <= t→ uses oldt = 0→ygets0this pass.- The block re-triggers when
tchanges to 1, and only then doesybecome 1 — one delta-cycle late. So in simulationyneeds two evaluation passes to reach 1 (it lags behinda).
What synthesis builds: the tool ignores the delta-timing and wires y = a directly (pure combinational path). So hardware gives y = 1 immediately, but simulation showed a delay.
That gap — sim behaves one way, silicon another — is the dreaded simulation/synthesis mismatch. Fix: use blocking = in combinational blocks so simulation matches the wire the tool actually builds. See Synthesis vs Simulation.
Exercise L5.2 — Blocking shift register bug
A student wants a 3-stage shift register but writes blocking assignments. Given q1=1, q2=0, q3=0, find q1,q2,q3 after one edge, and explain why only one flip-flop's worth of shift happens.
always @(posedge clk) begin
q3 = q2;
q2 = q1;
q1 = d; // d = 0
endRecall Solution L5.2
Blocking = updates immediately, in order:
q3 = q2;→q3 = 0(oldq2).q2 = q1;→q2 = 1(oldq1).q1 = d;→q1 = 0.- Result:
q1=0, q2=1, q3=0.
Here it happens to look correct — because the order (q3 first, then q2, then q1) reads the still-old value before it's overwritten. But reverse the order (q1=d; q2=q1; q3=q2;) and every stage grabs the just-written value → d races through all three flip-flops in one edge → the shift register collapses to a single stage.
Lesson: blocking makes correctness depend on line order — fragile and non-obvious. Non-blocking <= samples all old values first, so the shift is always exactly one stage regardless of order. Always use <= in clocked blocks.
Exercise L5.3 — Defend the design: async vs sync reset
Two flip-flops below differ only in the sensitivity list. For each, state: (a) is the reset synchronous or asynchronous, and (b) if rst pulses high between clock edges, does q go to 0 immediately or wait for the next clock edge?
// DFF-A
always @(posedge clk) begin if (rst) q <= 0; else q <= d; end
// DFF-B
always @(posedge clk or posedge rst) begin if (rst) q <= 0; else q <= d; endRecall Solution L5.3
The sensitivity list decides when the block wakes up.
- DFF-A wakes only on
posedge clk. Sorstis examined only at the clock edge → synchronous reset. Ifrstpulses between edges,qdoes not change until the next rising clock. (b) → waits for the next edge. - DFF-B also wakes on
posedge rst. So a risingrstfires the block immediately, independent of the clock → asynchronous reset. (b) →qgoes to 0 immediately.
Why it matters: async reset clears instantly (good for power-up safety) but its release must be handled carefully to avoid metastability; sync reset is simpler and cleaner in timing but can't clear a stuck clock. Both are valid — the sensitivity list is your explicit declaration of which you built. See Flip-Flops and Latches.
Recall One-line self-check before you leave
Golden Rule ::: Clocked always @(posedge clk) → <=; combinational always @(*) → =, and assign every output on every path.
Sum of two -bit numbers needs how many bits? ::: (to hold the carry-out).
4'hF + 1 in a 4-bit counter → ::: 4'h0 (wraps around, mod 16).
Connections
- Combinational vs Sequential Logic — the L1 recognition split.
- Flip-Flops and Latches — L3.3 latch, L5.3 reset styles.
- Synthesis vs Simulation — L5.1 mismatch, the L5 trap.
- Finite State Machines in HDL — combines the mux + register patterns from L4.
- Number Systems and Bit-Widths — literals, counter wrap, adder width.
- Testbenches — where you'd actually stimulate these modules.