What if your Verilog code looks right but never works on real hardware?
Synthesizable vs non-synthesizable constructs in Verilog - When to Use Which
Imagine you want to design a digital circuit using Verilog. You write code that looks like normal programming, but some parts can't be turned into real hardware. You try to test your design, but it doesn't work on the chip because some code is only for simulation.
Writing code without knowing which parts can become hardware leads to confusion. You spend hours debugging why your design doesn't work on the actual chip. Manual trial and error wastes time and causes frustration.
Understanding which Verilog constructs are synthesizable means you write code that can be directly turned into hardware. Non-synthesizable parts are only for simulation and testing. This clear separation saves time and ensures your design works on real devices.
initial begin
$display("Hello");
endalways @(posedge clk) begin q <= d; end
It enables you to confidently write Verilog code that can be transformed into real, working digital circuits.
When designing a microprocessor, you use synthesizable code for the processor logic and non-synthesizable code to simulate how it behaves before building the chip.
Not all Verilog code can become hardware.
Synthesizable constructs map to real circuits.
Non-synthesizable constructs help test and simulate designs.
Practice
non-synthesizable and used only for simulation?Solution
Step 1: Understand the role of
initialblocksinitialblocks run once at simulation start and are not synthesizable into hardware.Step 2: Compare with synthesizable constructs
alwaysblocks,assignstatements, and module instantiations describe hardware and are synthesizable.Final Answer:
Initial blocks (initial) -> Option BQuick Check:
initial= Non-synthesizable [OK]
initial blocks only simulate, never synthesize [OK]- Confusing
alwayswithinitial - Thinking
assignis non-synthesizable - Assuming module instantiations are simulation-only
always block sensitive to the positive edge of clock clk?Solution
Step 1: Identify correct edge sensitivity
Synthesizable clocked logic usesposedge clkornegedge clkto trigger on clock edges.Step 2: Check syntax correctness
always @(posedge clk)is correct;always @(clk)triggers on any change, which is not typical for clocked logic.Final Answer:
always @(posedge clk) begin ... end -> Option DQuick Check:
Useposedge clkfor clock edge sensitivity [OK]
posedge or negedge for clock edges [OK]- Using level sensitivity instead of edge sensitivity
- Mixing clock and reset signals incorrectly
- Omitting
beginandendfor multiple statements
reg [3:0] count; initial begin count = 0; #5 count = 4'b1010; end always @(posedge clk) begin count <= count + 1; end
Assuming
clk toggles every 1 time unit starting at 0.Solution
Step 1: Analyze
Theinitialblock effectinitialblock setscountto 0 at time 0, then to 10 at time 5 (delay #5).Step 2: Analyze
Thealwaysblock behavioralwaysblock incrementscounton every positive clock edge, but the non-blocking assignment means the update happens after the clock edge, so the delayed assignment at time 5 overrides the count value at that time.Final Answer:
Count stays 0 until time 5, then becomes 10 and increments every clock cycle -> Option AQuick Check:
initial#delay executes after clock edges [OK]
initial affects count after clock increments [OK]- Ignoring the
initialblock's delayed assignment - Assuming
countincrements from 10 immediately - Confusing blocking and non-blocking assignments
always @(posedge clk) begin
integer i;
for (i = 0; i < 4; i = i + 1) begin
data[i] = i;
end
endSolution
Step 1: Check variable declarations and loop usage
Declaringinteger iinside thealwaysblock is allowed for synthesis as loop variable.Step 2: Identify assignment type issue
Using blocking assignment=inside clockedalwaysblock causes unintended behavior; non-blocking<=is required for registers.Final Answer:
Using blocking assignment (=) instead of non-blocking (<=) inside always block -> Option CQuick Check:
Use non-blocking (<=) in clocked always blocks [OK]
- Thinking loop variables cannot be declared inside always blocks
- Believing for loops are non-synthesizable
- Ignoring difference between blocking and non-blocking assignments
sig is high during clock cycles, but also print the count value for debugging during simulation. Which approach correctly separates synthesizable and non-synthesizable constructs?Solution
Step 1: Identify synthesizable counting logic
Counting on clock edges must be in analways @(posedge clk)block using non-blocking assignments.Step 2: Identify non-synthesizable debugging code
Printing with$displayis simulation-only and must be placed in aninitialor separate simulation-only block.Final Answer:
Use analways @(posedge clk)block to increment count and aninitialblock with$displayto print count -> Option AQuick Check:
Separate hardware logic and simulation prints [OK]
initial, counting in clocked always [OK]- Trying to print inside synthesizable
alwaysblock - Using continuous assignment for counting
- Confusing tasks/functions for simulation prints
Ready to prove it?
Pass the test and this pattern moves unknown
