3.5.3 · Hardware › HDL & Digital Design Flow
Combinational logic mein koi memory nahi hoti : iska output sirf current inputs par depend karta hai. Sequential logic mein memory hoti hai : iska output inputs aur past par depend karta hai, jo flip-flops mein store rehta hai. Verilog mein, is stored, clock-driven behaviour ko hum ek always block se describe karte hain jo clock edge par "jaag" jaata hai. always block ek loop nahi hai — yeh ek sensitivity-driven process hai jo aise hardware ko model karta hai jo events par react karta hai.
Ek pure combinational circuit f ( inputs ) compute kar sakta hai lekin count , wait , koi state yaad rakhna , ya steps ko time mein sequence karna nahi kar sakta. Har useful digital system — CPUs, counters, FSMs, UARTs — ko yeh jaanna padta hai ki "woh pehle kahan tha." Yaad rakhne ke liye, hume ek aisa element chahiye jo value ko tab tak hold kare jab tak change karne ko na kaha jaaye , aur sabko sync mein rakhne ke liye values sirf ek shared clock edge par change karte hain. Woh shared dhol ki taak hi hai jo laakhon gates ko reliably saath kaam karwaati hai.
always block
always block Verilog ka ek procedural construct hai jo continuously re-execute karta hai jab bhi uski sensitivity list mein koi signal change hota hai. Ise combinational ya sequential logic model karne ke liye use kiya jaata hai, depending on yeh kaise trigger hota hai.
always @(posedge clk) → sequential logic (flip-flops), clock edge par react karta hai.
always @(*) → combinational logic, kisi bhi input change par react karta hai.
Ek flip-flop ek 1-bit memory element hai jo active clock edge par apna input D sample karta hai aur use output Q par hold karta hai agli active edge tak.
Do assignment operators aur do block styles hain. Inhe sahi choose karna 80% bugs se bachata hai.
Intuition Do operators kyun?
Real flip-flops sab ek hi instant par sample karte hain apni purani input values use karke, phir ek saath update karte hain. Agar code variables ko ek-ek karke program order mein update karta, toh baad ki line pehle ki line ki nayi value dekhti — jo parallel flip-flops ka behaviour nahi hai.
Blocking = turant, order mein execute karta hai (normal software ki tarah). Combinational chains ke liye achha hai jahan order = data flow hota hai.
Non-blocking <= pehle sab right-hand sides evaluate karta hai (old values use karke), phir sab left-hand sides ek saath assign karta hai. Yeh exactly ek saath clock hone wale flip-flops ki rank ko model karta hai.
Worked example Shift register —
<= kyun zaroori hai
Goal: har clock par q1 → q2 → q3 shift (ek 3-stage shift register).
always @( posedge clk) begin
q2 <= q1; // OLD q1 use karta hai
q3 <= q2; // OLD q2 use karta hai
end
Non-blocking kyun? Saare RHS (q1, q2) kisi bhi update se pehle read hote hain. Toh q3 ko purana q2 milta hai, jo ek sahi shift deta hai.
Agar hum blocking = likhte:
q2 = q1; // q2 ab q1 ke barabar hai
q3 = q2; // q3 = q2 = q1 --> GALAT, do stages collapse ho gayi
Galat kyun? Blocking pehle q2 update karta hai, toh line 2 nayi q2 dekhti hai. Do flip-flops ek mein merge ho jaate hain; shift register ek stage kho deta hai.
Intuition Step by step banao
Step 1 — WHAT chahiye? Ek box jahan Q sirf rising clock edge par D banta hai, warna hold karta hai.
Step 2 — Verilog mein HOW? "Rising edge par, D ko Q mein copy karo." Yeh literally yeh hai:
always @( posedge clk)
q <= d;
posedge kyun? Yeh block ko sirf 0 → 1 transition par fire karta hai, isliye q ek cycle mein ek baar update hota hai.
<= kyun? Taaki agar kai aise flops clk share karen, toh sab pre-edge values use karen — sahi parallel behaviour.
Worked example Asynchronous reset ke saath D flip-flop
always @( posedge clk or posedge rst) begin
if (rst) q <= 1'b0 ; // Kyun? reset dominate karta hai, turant 0 force karta hai
else q <= d; // Kyun? D ka normal capture
end
rst ko sensitivity list mein kyun daala? Kyunki yeh asynchronous hai — ise rst rise hote hi act karna chahiye, clock edge ka wait nahi karna chahiye. if (rst) pehle kyun check kiya? Priority: reset ko normal operation override karna chahiye.
Worked example Synchronous reset (comparison ke liye)
always @( posedge clk) begin // rst list mein NAHI hai
if (rst) q <= 1'b0 ;
else q <= d;
end
Alag kyun hai? Yahan reset sirf clock edge par effect leta hai. Timing ki nazariye se sasta hai, lekin reset agli clock tick tak ignore hoti hai. Apne design ki requirement ke hisaab se choose karo.
Worked example 2:1 mux, teen equivalent tarike
always @( * ) begin // @(*) kyun? auto-include SARE read signals
if (sel) y = b; // '=' kyun? combinational, order = logic flow
else y = a;
end
Clock kyun nahi? Mux mein memory nahi hoti; ise kisi bhi input par turant respond karna chahiye, isliye hum kisi bhi change par trigger karte hain.
Khatraa: agar always @(*) ka koi path kisi branch mein y assign karne mein fail karta hai, toh synthesizer purani value "yaad rakhne" ke liye ek latch infer karta hai — usually ek bug. Fix: har branch mein har output assign karo, ya upar ek default do.
Common mistake Common errors ko samjhana
Galti 1: "always @(posedge clk) ek loop hai jo hamesha bahut tezi se run karta hai."
Kyun sahi lagta hai: "always" word while(1) jaisa lagta hai. Reality: yeh event-driven hai — yeh ek triggering edge par ek baar execute hota hai, phir so jaata hai. Fix: ise is tarah padho: "jab bhi yeh event ho, body ek baar karo."
Galti 2: "Clocked blocks ke andar = use karo, yeh simpler hai."
Kyun sahi lagta hai: blocking normal code ki tarah behave karta hai; simulation single flop ke liye sahi bhi dikh sakta hai. Reality: multiple registers ke saath tum race conditions aur simulation/synthesis mismatch create karte ho. Fix: clocked → hamesha <=.
Galti 3: "@(a or b) mein signal bhool jaana theek hai."
Kyun sahi lagta hai: code compile aur simulate hota rehta hai. Reality: simulation missing signal ko ignore karta hai (stale output) jabki synthesis use include karta hai → mismatch . Fix: combinational logic ke liye always @(*) use karo.
Galti 4: ek hi reg ko do always blocks se drive karna.
Kyun sahi lagta hai: behaviours ko OR karne jaisa lagta hai. Reality: do drivers = race / multiple-driver error. Fix: ek register, ek always block.
Mnemonic Pairing yaad rakho
"CLOCK tumhe NON-blocking hug deta hai (<=); COMB ise BLOCK by block karta hai (=)."
Clock ↔ <=, Combinational ↔ =.
Recall Feynman: ek 12-saal ke bacche ko explain karo
Socho ek class jahan sab log ek mini-whiteboard par jawab likhte hain. Combinational baccha question dekhte hi jawab chilla deta hai. Sequential baccha apna board sirf tab paltata hai jab teacher ghanti bajati hai (woh clock hai) — tab tak woh apna pichla jawab pakde rehta hai. Ab, tricky part yeh hai: jab ghanti bajti hai, sab bacchon ko woh dikhaana chahiye jo unhone ghanti se pehle likha tha — apne neighbour ke naaye board ki nakal nahi karni. Non-blocking <= yeh rule hai "pehle sab ke purane board padho, phir saath mein palto." Blocking = hai "ek-ek karke karo," jo chillane-wale bacchon ke liye theek hai lekin ghanti-wale bacchon ke liye gada machaa deta hai.
Recall Quick self-test (pehle predict karo, phir dekho)
Clocked logic ke liye kaun sa operator use karte hain, aur kyun?
always @(*) mein unassigned branch accidentally kaun sa hardware create karta hai?
Async reset ko sensitivity list mein kyun daalna chahiye?
Sequential always block ko kya trigger karta hai? Ek clock edge, jaise always @(posedge clk).
Clocked/sequential logic ke liye kaun sa assignment use karte hain? Non-blocking <=.
Combinational logic ke liye kaun sa assignment use karte hain? Blocking =.
Non-blocking <= flip-flops ko sahi model kyun karta hai? Saare RHS old values se evaluate hote hain, phir saare LHS ek saath update hote hain — jo parallel flops ke saath clocking karne se match karta hai.
Blocking = shift register ko kyun tod deta hai? Baad ki lines abhi-abhi-update ki hui value dekhti hain, jo stages ko shift karne ki jagah collapse kar deti hai.
Kya always @(posedge clk) ek loop hai? Nahi — yeh event-driven hai; yeh triggering edge par ek baar run karta hai phir so jaata hai.
Inferred latch kya hota hai aur kab hota hai? Ek unwanted memory element jo tab create hota hai jab always @(*) output har branch mein assign nahi hoti.
Inferred latches se kaise bacha jaaye? Har branch mein har output assign karo, ya block ke upar defaults set karo.
Async aur sync reset mein kya fark hai? Async reset sensitivity list mein hota hai aur turant act karta hai; sync reset sirf clock edge par act karta hai.
Reset flop ke if mein rst pehle kyun daala jaata hai? Reset ko normal data capture par priority dene ke liye.
always @(*) ka matlab kya hai?Combinational logic jo block ke andar read hone wale kisi bhi signal ke liye sensitive hai.
Agar do always blocks ek hi reg drive karen toh kya error aata hai? Multiple-driver / race condition.
reads old values then assigns