In short
A hardware description language (HDL) describes digital hardware as text so that it can be simulated, verified and then automatically synthesised into gates on an ASIC or FPGA. Verilog (IEEE 1364, now largely superseded by SystemVerilog IEEE 1800) is the dominant HDL in Indian industry; VHDL (IEEE 1076) is the other. The central skill examined is writing *synthesizable* RTL - code whose meaning in simulation matches the hardware the tool builds - and knowing where simulation-only constructs stop. It appears in GATE EC/EE digital questions, in every university digital-design and VLSI lab, and in the first technical round at Intel India, Qualcomm, Texas Instruments Bengaluru, Samsung SRI-B, NXP, Micron, Nvidia, Synopsys, Cadence, BEL, ISRO, SCL Mohali and VLSI services firms such as Tessolve, L&T Technology Services and Sankalp.
Explained
What an HDL is, and the Verilog design flow
- An HDL is concurrent and timed, unlike C: statements describe hardware that all exists at once, with events ordered in simulation time.
- Three purposes: modelling (describe intent), simulation (check behaviour against a testbench), synthesis (map RTL to a gate netlist).
- Abstraction levels, highest to lowest: behavioural/algorithmic → RTL (register-transfer level) → gate level → switch (transistor) level. Verilog supports all four; only RTL and gate level are synthesizable.
- Flow: specification → RTL coding → functional simulation → synthesis (constraints: clock period, area, power) → gate-level netlist → static timing analysis → place and route → GDSII (ASIC) or bitstream (FPGA) → post-layout verification.
- A design unit is a
module...endmodulewith a port list; ports areinput,outputorinout. Hierarchy is built by instantiating modules inside modules. - Verilog is case sensitive, free format, uses
//and/* */comments, and all identifiers start with a letter or underscore. Keywords are lowercase. - Port connection on instantiation: by position (
dut d1(a, b, y);) or by name (dut d1(.a(x), .b(y), .y(z));) - always prefer by name.
Lexical elements, data types, nets versus variables
- Four-valued logic:
0,1,x(unknown/conflict) andz(high impedance). Synthesis treatsxas "don't care"; simulation propagates it, which is how uninitialised registers are caught. - Number literals:
<size>'<base><value>-4'b1010,8'hFF,6'o17,12'd255,-8'sd5(the sign goes before the literal, never inside it). Underscores are ignored:16'b1010_1100_0011_0001. An unsized number is at least 32 bits, and decimal if the base is also omitted. - Nets (
wire,tri,wand,wor,supply0,supply1) model physical connections; they must be driven continuously and hold no state. Default net type iswirewith valuezwhen undriven. - Variables (
reg,integer,real,time,realtime) hold a value between assignments. **regdoes not mean a flip-flop** - it means "assigned inside a procedural block"; whether it becomes a flop depends on the code. - Vectors:
wire [7:0] data;(MSB first is conventional). Part selectdata[3:0], bit selectdata[2], indexed part selectdata[i +: 4](Verilog-2001). - Arrays / memories:
reg [7:0] mem [0:1023];- 1024 words of 8 bits. You can select a word, then a bit of that word, but not a slice across words in classic Verilog. - Signed types:
reg signed [7:0] a;and$signed/$unsignedcasts (Verilog-2001). Withoutsigned, arithmetic is unsigned - a frequent bug source. - parameter gives compile-time constants, overridable per instance (
#(.WIDTH(16))); localparam cannot be overridden; `define `` is a text macro (global, avoid for widths).
Operators, expression width and precedence
- Arithmetic:
+ - * / % **.*is synthesizable (maps to a multiplier);/and%by a non-power-of-two constant are large and often unsupported by simple flows. - Bitwise (
& | ^ ~ ~^) operate bit by bit; logical (&& || !) return a 1-bit truth value; reduction (&a,|a,^a) collapse a vector to one bit (^ais parity). - Relational
< <= > >=; equality==/!=(returnxif any operand bit isx) versus case equality===/!==(comparexandzliterally - simulation only, not synthesizable). - Shifts:
<<,>>(logical, zero fill) and<<<,>>>(arithmetic):>>>sign-extends a signed operand,<<<fills with zeros. - Conditional
cond ? a : bbuilds a multiplexer. Concatenation{a, b}and replication{4{2'b10}}. - Width rules: operands of an arithmetic/bitwise operator are extended to the widest operand *and* to the width of the assignment target (context-determined); the shift count and the
?:condition are self-determined, and comparison operands size only against each other, not against the target. Truncation on assignment is silent. - Precedence (high → low):
~ !unary →**→* / %→+ -→ shifts → relational → equality →&→^ ~^→|→&&→||→?:. Use brackets rather than relying on this.
Modelling styles
- Gate level (structural, primitives): instantiate built-ins
and,or,nand,nor,xor,xnor,not,buf,bufif1,notif0. Output is the first port. Used for library cells and post-synthesis netlists. - Switch level:
nmos,pmos,cmos,tran- for transistor-level study, never for synthesis. - Dataflow: continuous assignment
assign y = (a & b) | ~c;drives a net; it re-evaluates whenever any right-hand-side signal changes. Delays may be attached:assign #5 y = a & b;(simulation only, ignored by synthesis). - Behavioural:
alwaysandinitialblocks withif/else,case,for,while,repeat,forever. This is where RTL for registers, counters and state machines is written. - Hierarchical/structural: connecting sub-modules with named ports - the normal way large chips are composed.
- A real design mixes styles: combinational logic as
assignoralways @(*), sequential logic asalways @(posedge clk), hierarchy as instantiations. - generate ... endgenerate with
genvarreplicates hardware at elaboration time (for example an 8-bit ripple-carry adder from 8 full adders); aforloop insidealwaysinstead unrolls into combinational logic.
Procedural blocks, blocking versus non-blocking, inference rules
- **
initialruns once at time 0 - testbenches only.always** repeats forever, triggered by its sensitivity list or internal delays. - Sensitivity list:
always @(a or b)/always @(a, b)for combinational logic - preferalways @(*)(Verilog-2001) so no signal is forgotten;always @(posedge clk)or@(negedge clk)for edge-triggered logic. - **Blocking assignment
=executes immediately and in order, like software. Use it for combinational** logic. - **Non-blocking assignment
<=samples all right-hand sides, then updates all left-hand sides at the end of the time step - this is exactly what a bank of flip-flops does. Use it for sequential** logic. - Golden rules:
<=insidealways @(posedge clk);=insidealways @(*); never mix both for the same variable; never assign one variable from two differentalwaysblocks (multiple drivers). - Flip-flop inference: a variable assigned inside an edge-triggered block becomes a register. Asynchronous reset:
if (!rst_n) q <= 0; else q <= d;inside@(posedge clk or negedge rst_n). Synchronous reset: reset tested inside@(posedge clk)alone. - Unintended latch: in a combinational
always, any output not assigned on every path holds its old value, so the tool infers a latch. Cure: a default assignment at the top of the block, a finalelse, and adefaultin everycase. - case variants:
case(exact, withx/zmatched literally),casez(z/?as don't-care),casex(xandzas don't-care - risky, can mask bugs).full_case/parallel_casedirectives change synthesis but not simulation and are best avoided. - Timing controls:
#delay,@(event),wait(expr), named events (event e; -> e;). All are simulation constructs; synthesis ignores#delays, which is why delay-based "models" mismatch hardware.
Tasks, functions, testbenches and the simulation model
- function: returns one value, executes in zero simulation time, no timing controls, at least one input, cannot call a task - synthesizable.
- task: may have delays and multiple
output/inoutarguments, returns nothing - used for stimulus and checks, generally not synthesizable. - Testbench structure: a top module with no ports; declare
regfor DUT inputs andwirefor outputs; instantiate the DUT; generate a clock (always #5 clk = ~clk;); drive stimulus ininitial; check withifcomparisons or assertions; finish with$finish. - System tasks:
$display(prints with newline),$monitor(prints on any change),$write,$strobe(end-of-timestep values),$time/$realtime,$random,$readmemb/$readmemh(load memory from file),$dumpfile/$dumpvars(VCD waveform),$finish,$stop. - **
timescale**timescale 1ns/100ps`sets the **time unit** of#` delays and the precision to which they are rounded; the smallest precision in the whole design becomes the simulator's resolution. - Event-driven scheduler: at each time step, events are placed in the active region (blocking assignments,
assign, RHS evaluation of<=), then inactive (#0), then non-blocking update, then monitor ($monitor,$strobe). This ordering is why<=avoids race conditions and why#0is a code smell. - Race condition: two blocks reading and writing the same signal in the same time step with blocking assignments give simulator-dependent results; non-blocking assignments remove the race.
- Open tools in Indian labs: Icarus Verilog + GTKWave (free), Xilinx Vivado / Intel Quartus for FPGA, ModelSim/Questa, Synopsys VCS and Design Compiler, Cadence Xcelium and Genus. Verification today is mostly SystemVerilog + UVM.
Synthesizable subset, guidelines, and Verilog versus VHDL/SystemVerilog
- Synthesizable: module/port/parameter,
wire/reg,assign,always @(*)and@(posedge/negedge),if,case, boundedfor,function,generate, operators, instantiation. - Not synthesizable:
initial(except FPGA RAM/register initial values),#delays,while/foreverwith no clock,===/!==,real,$displayand other system tasks,force/release,fork...join, UDPs in most flows. - Coding guidelines that interviewers check: one clock per block; register all outputs of a pipeline stage; no combinational feedback loops; no gated or internally generated clocks (use clock enables); reset every state-holding element; synchronise asynchronous inputs with two flip-flops; avoid
xpropagation by initialising in reset. - Verilog versions: Verilog-1995 (IEEE 1364-1995), Verilog-2001 (
always @(*), ANSI port lists,signed,localparam, generate,+:), Verilog-2005 (IEEE 1364-2005). IEEE withdrew 1364 after folding Verilog into SystemVerilog (IEEE 1800), whose latest published revision is IEEE 1800-2023 - check the current standard before quoting a year. - SystemVerilog adds
logic,bit,always_comb/always_ff/always_latch,typedef/enum/struct,unique/priority case, interfaces, packages, classes, assertions (SVA), constrained-random generation and functional coverage.
| Verilog | VHDL | |
|---|---|---|
| Origin / standard | Gateway 1984, IEEE 1364 | US DoD 1980s, IEEE 1076 |
| Style | C-like, terse | Ada-like, verbose |
| Case sensitivity | Case sensitive | Not case sensitive |
| Type checking | Weak (silent truncation) | Strong, explicit conversions |
| Data types | Few, built-in, 4-state | Rich, user-defined, std_logic |
| Learning curve | Easier to start | Stricter, catches more at compile |
| Typical use | ASIC/front-end, verification, most Indian product firms | Defence, aerospace, European and some PSU/FPGA work |
| Aspect | wire | reg |
|---|---|---|
| Assigned by | assign, module output, primitive | Procedural = / <= |
| Holds value | No (needs a driver) | Yes, until reassigned |
| Multiple drivers | Allowed (resolved) | Not allowed |
| Hardware inferred | Net / combinational logic | Flop, latch or just wiring |
Key points
- HDL - text description of hardware for simulation *and* synthesis; concurrent, not sequential like C.
- Verilog levels - behavioural, RTL, gate, switch; only RTL and gate map to silicon.
- Four-value logic -
0,1,x,z;xin a waveform usually means uninitialised or multiply driven. - **
regis not a register** - it is a procedurally assigned variable; the clock edge creates the flip-flop. - **
assigndrives nets only**, continuously; procedural assignments drive variables only. - **Blocking
=** - sequential, immediate; for combinationalalways @(*). - **Non-blocking
<=** - RHS sampled, LHS updated at end of time step; foralways @(posedge clk); makes shift registers and swaps work. - **
always @(*)** removes incomplete-sensitivity-list bugs that exist only in simulation. - Latch inference comes from an incompletely assigned combinational output - fix with defaults and
default:. - One driver rule - a signal assigned in two
alwaysblocks is a synthesis error and a simulation race. - **
==versus===** -===comparesx/zexactly and is simulation-only. - Width and sign - unsigned by default; expressions widen to the widest operand and to the LHS; subtraction of unsigned values never goes negative.
- **
parameterfor per-instance constants,localparam** for internal ones, `define `` for text macros. - generate/genvar replicates structure at elaboration; a
forinsidealwaysunrolls into logic, it does not loop in time. - function = zero time, one return, synthesizable; task = may consume time, multiple outputs, for testbenches.
- **
timescale unit/precision** scales and rounds#delays;#delays are never synthesised. - Event regions - active → inactive → NBA → monitor; the reason
$strobeshows settled values and<=avoids races. - Standards - Verilog-2001/IEEE 1364-2005; Verilog is now part of SystemVerilog IEEE 1800 (latest published revision 1800-2023).
Formulas and examples
Two's-complement range for n bits: −2n−1 to +2n−1 − 1
Value of a sized literal s'bB = Σ bᵢ·2ⁱ, then truncated or zero-extended to s bits
Memory bits for
reg [W-1:0] mem [0:D-1] = D × W bits (D = depth, W = word width in bits)Unsigned wrap-around: result = (exact value) mod 2ⁿ
Clock divider by toggling: terminal count = f_in / (2 × f_out) − 1 (f in Hz)
Simulated delay = (#value × time_unit), rounded to the nearest precision step of
timescale1. Literal width, truncation and replication
4'b1010= 8+0+2+0 = 10;8'hFF= 255;6'o17= 1×8+7 = 15.{4{2'b10}}=8'b10101010= 128+32+8+2 = 170 =8'hAA.wire [3:0] s; assign s = 4'd12 + 4'd5;→ exact 17, but the target is 4 bits → 17 mod 16 = 1 (4'b0001); the carry is lost.wire [4:0] s5; assign s5 = 4'd12 + 4'd5;→ the LHS is 5 bits, so operands widen → 17 (5'b10001). Width is decided by the *assignment*, not just the operands.
2. The unsigned-subtraction trap
reg [7:0] y; // 8-bit unsigned
y = 3'd2 - 3'd5; // operands widen to 8 bits, unsigned
- Exact value −3; unsigned 8-bit result = (−3) mod 256 = 253 (
8'hFD), soif (y < 0)is never true. - With
reg signed [7:0] y; y = 8'sd2 - 8'sd5;the result is −3. Cast or declare at full width:$signed(3'd5)is the 3-bit pattern101read as signed = −3, not 5, so$signed(3'd2) - $signed(3'd5)gives +5. Lesson: declaresignedat the right width, and never test an unsigned expression for negativity.
3. Blocking versus non-blocking - trace it Start with a = 1, b = 2.
always @(posedge clk) begin a = b; b = a; end // blocking
always @(posedge clk) begin a <= b; b <= a; end // non-blocking
| Style | Step | a | b | Hardware |
|---|---|---|---|---|
| Blocking | after a = b | 2 | 2 | one flop; b feeds a, then a feeds b |
| Blocking | after b = a | 2 | 2 | swap fails |
| Non-blocking | RHS sampled | 1 | 2 | two flops, cross-coupled |
| Non-blocking | NBA update | 2 | 1 | swap succeeds |
4. Parameterised counter and clock divider on a 50 MHz FPGA board
- A counter for 1000 states (0-999) needs n = ⌈log₂ 1000⌉ = 10 bits, since 2⁹ = 512 < 1000 ≤ 1024 = 2¹⁰; it counts 0 to 999 and its maximum representable value is 1023.
- To generate a 1 Hz square wave from 50 MHz: terminal count = 50,000,000/(2×1) − 1 = 24,999,999; width = ⌈log₂ 25,000,000⌉ = 25 bits (2²⁴ = 16,777,216 < 25,000,000 ≤ 33,554,432 = 2²⁵).
module clkdiv #(parameter integer TC = 24_999_999, parameter integer W = 25)
(input wire clk, input wire rst_n, output reg slow);
reg [W-1:0] cnt;
always @(posedge clk or negedge rst_n)
if (!rst_n) begin cnt <= {W{1'b0}}; slow <= 1'b0; end
else if (cnt == TC) begin cnt <= {W{1'b0}}; slow <= ~slow; end
else cnt <= cnt + 1'b1;
endmodule
5. Timescale rounding and memory size
- With `
timescale 1ns/100ps`:#2.57is rounded to the 0.1 ns precision step → **2.6 ns**. Withtimescale 10ns/1ns`:#5` means 5 × 10 ns = 50 ns. reg [7:0] mem [0:1023];→ 1024 × 8 = 8192 bits = 1024 bytes = 1 KiB. Widening toreg [31:0] mem [0:1023]gives 32,768 bits = 4 KiB.
6. Latch versus multiplexer - the same intent, two results
// infers a LATCH on y: no else branch
always @(*) if (sel) y = a;
// clean 2:1 MUX: default assignment covers every path
always @(*) begin y = b; if (sel) y = a; end
Where it is used
- Semiconductor product companies in India: RTL design and verification of SoC blocks at Intel India, Qualcomm, Texas Instruments, Samsung SRI-B, NXP, Micron, Nvidia, AMD, Western Digital and Microchip - mostly Bengaluru, Hyderabad, Noida, Pune.
- EDA and design services: Synopsys, Cadence, Siemens EDA build the tools; Tessolve, Sankalp, L&T Technology Services, HCLTech, Wipro, Tata Elxsi and Mirafra supply RTL/DV engineers on projects.
- Strategic and public sector: ISRO/VSSC and LRDE-DRDO FPGA payload and radar logic, BEL, SCL Mohali (indigenous fabrication), C-DAC; MeitY's Chips to Startup (C2S) programme and the India Semiconductor Mission fund HDL-based tapeouts in colleges.
- FPGA embedded products: motor control, power electronics, protocol bridges, image and radar signal processing, 5G radio units, defence avionics - written in Verilog/VHDL and targeted to Xilinx/AMD or Intel/Altera devices.
- Job roles and typical entry titles: RTL design engineer, design verification (DV) engineer, FPGA engineer, physical design engineer (reads synthesised Verilog netlists), DFT engineer - campus interviews test exactly the Verilog in this note.
- Lab and project work: digital design labs, mini-projects on UART, SPI/I²C masters, ALUs, FIFOs and processor cores, simulated in Icarus/ModelSim and implemented on Basys/Nexys or DE-series boards.
Interview questions
- Q: What is the difference between blocking and non-blocking assignment? A: Blocking (
=) evaluates and updates immediately in statement order; non-blocking (<=) samples all right-hand sides and updates left-hand sides at the end of the time step, which models a bank of flip-flops. Use=for combinational and<=for sequential logic. - Q: Does
regalways become a flip-flop? A: No.regonly means the variable is assigned procedurally; a flip-flop is inferred only when it is assigned inside an edge-triggeredalwaysblock and its value must persist. - Q: Why does an incomplete
iforcasein a combinational block infer a latch? A: Because the output keeps its previous value on the unassigned path, which requires memory; adding a default assignment or adefault/elsebranch removes it. - Q: What is the difference between
==and===? A:==returnsxwhen any operand bit isxorz;===compares those values literally and returns only 0 or 1, and it is not synthesizable. - Q: What does
always @(*)do that an explicit list may not? A: It makes the block sensitive to every signal read inside it, preventing simulation-synthesis mismatch from a forgotten signal. - Q: What goes wrong if two
alwaysblocks assign the same signal? A: It is a multiple-driver error in synthesis and a non-deterministic race in simulation, since the execution order of the blocks is not defined. - Q: What does
timescale 1ns/10psmean? A:#1equals 1 ns and delays are rounded to 10 ps; the finest precision in the design sets the simulator's time resolution. - Q: Difference between a task and a function? A: A function returns a single value in zero simulation time with no timing controls and is synthesizable; a task can consume time, have multiple outputs, and is normally for testbenches.
- Q: How do you write a flip-flop with asynchronous versus synchronous reset? A: Asynchronous:
always @(posedge clk or negedge rst_n) if (!rst_n) q <= 0; else q <= d;. Synchronous:always @(posedge clk) if (!rst_n) q <= 0; else q <= d;. - Q:
a = 3'd2 - 3'd5assigned to an 8-bit unsigned reg gives what? A: 253 - the operands are unsigned, so the result wraps modulo 256; to get −3 declare the targetsignedand write the literals signed at full width (8'sd2 - 8'sd5). - Q: Why is
casexdiscouraged? A: It treatsxin the case expression as a don't-care, so unknown values can silently match a branch and hide bugs;casezwith?is safer. - Q: Why should a design avoid generated or gated clocks in RTL? A: They create extra clock domains and skew that static timing analysis and clock-tree synthesis handle poorly; use a synchronous clock enable, or a library clock-gating cell inserted by the tool.
- Q: Which Verilog constructs are not synthesizable? A:
initialblocks,#delays,===/!==,real, system tasks like$display,force/release, and unboundedwhile/foreverloops.
Common mistakes
- Using
<=in combinational blocks or=in clocked blocks - the code may simulate "correctly" yet synthesise to different hardware (or build a shift register where a wire was wanted). - Assuming
regmeans a register andwiremeans combinational - and then trying toassignaregor procedurally assign awire. - Omitting
else/defaultin a combinational block, creating unintended latches that then fail timing or hold stale data. - Ignoring width and sign: silent truncation on assignment, lost carry bits, and unsigned subtraction that is never negative.
- Writing a
forloop expecting it to iterate over clock cycles; in analwaysblock it unrolls into parallel hardware in one cycle. - Relying on
#delays for functionality, or on an incomplete sensitivity list - both produce a simulation result the synthesised chip will not reproduce. - Driving one signal from two
alwaysblocks, forgetting to reset state elements, or leaving module outputs unconnected so they sit atx/zin the waveform.
Related topics
Combinational circuits · Sequential circuits: flip-flops, counters and registers · Finite state machine design · Programmable logic: PLDs, CPLDs and FPGAs · Number systems and Boolean algebra · Microprocessors and embedded system design