5.1.3 · D3 · Hardware › Instruction Set Architecture (ISA) › Addressing modes
Yeh ek Deep Dive child hai 5.1.3 Addressing modes ka. Parent ne tumhe E A ke formulas diye the. Yahan hum unhe exhaust karte hain — har mode, har degenerate case, har trap jo exam set kar sakta hai. Agar koi scenario exist karta hai, toh woh neeche ki matrix mein hai aur uska ek fully worked example bhi hai.
Shuru karne se pehle, paanch plain-word reminders (hum koi bhi symbol tab tak use nahi karenge jab tak hum use re-earn na kar lein):
Definition Notation jo hum reuse karte hain
A ::: address / displacement field — woh raw number jo instruction word ke andar carry hota hai.
R , ( R ) ::: ek register name R , aur us mein abhi store kiya hua number ( R ) . Parentheses ka matlab hai "contents of".
M [ x ] ::: address x par memory mein store kiya hua number . Memory ko ek lambi numbered street samjho; M [ x ] woh hai jo house number x ke andar hai.
E A ::: effective address — woh final house number jahan operand rehta hai, mode ka rule run hone ke baad.
P C ::: program counter — woh address jahan se CPU abhi instructions padh raha hai.
Ek "memory access" = street par ek trip lekar ek house kholna. Hum inhe count karte hain kyunki har trip time leta hai. Dekho Memory Hierarchy ki trips kyun expensive hoti hain.
Definition Assembly punctuation jo hum is page par use karte hain
#value ::: hash sign ek immediate ko mark karta hai — # ke baad ka number hi operand hai, instruction word mein baked in. Koi address nahi, koi memory trip nahi.
(R) ek operand mein ::: "register R mein held address par jao" (register-indirect).
A(R) ::: displacement — "A + ( R ) compute karo, phir wahan jao".
* ek target se pehle ::: target current P C ke relative measure kiya gaya hai, matlab assembler *+A ko E A = P C + A mein convert karta hai.
Neeche ke har worked example ko us cell ke saath tag kiya gaya hai jise woh cover karta hai. Goal: koi bhi reader kisi aisi case se na mile jise humne skip kiya ho.
Cell
Isko tricky kya banata hai
Covered by
C1 — zero memory access
operand kabhi memory touch nahi karta (immediate / register)
Ex 1
C2 — the "how many trips?" axis
direct (1) vs indirect (2) vs register-indirect (1)
Ex 2
C3 — sign of the displacement
A can be negative (backward offset)
Ex 3
C4 — degenerate / zero inputs
A = 0 , ya ( R ) = 0 — kya rules phir bhi hold karte hain?
Ex 4
C5 — scaled indexing (arrays of wide elements)
element size = 1 byte
Ex 5
C6 — PC-relative, both directions
forward branch aur backward loop
Ex 6
C7 — auto-increment / decrement ordering
R access ke relative kab change hota hai?
Ex 7
C8 — the stack (real-world word problem)
push/pop as auto-dec/auto-inc
Ex 8
C9 — exam twist: same bits, four modes
ek instruction word chaar tarike se decode kiya
Ex 9
C10 — limiting behaviour / wrap-around
E A address space se exceed kar jaata hai
Ex 10
Shared machine state sabhi examples ke liye (yeh street yaad kar lo):
Address
Contents
Register
Contents
100
500
R1
400
200
108
R2
3
400
700
R3
408
403
900
Rz
0
404
111
PC
200
408
222
SP
600
500
800
Rb
596
596
42
600
55
608
333
MOVE #25, R3 (immediate) aur ADD R1, R2 (register)
Upar ke punctuation box se yaad karo: #25 ka matlab hai number 25 seedha instruction word mein baked in hai.
Forecast: har ek apna operand laane ke liye kitni memory trips karta hai? Padhne se pehle guess karo.
Immediate #25. Operand = 25 . Yeh step kyun? # (upar define kiya) kehta hai "number instruction word ke andar hi hai." Koi E A hai hi nahi — kuch look up karna hi nahi. Trips = 0 .
Register R1, R2. Operand = ( R 1 ) = 400 aur ( R 2 ) = 3 . Yeh step kyun? Registers CPU ke andar rehte hain, memory street par nahi (dekho Registers and Register File ). Ek register padhna memory access nahi hai. Trips = 0 .
Verify: parent ki table mein 0 memory accesses listed hain dono immediate aur register modes ke liye. Dono operands (25 aur 400 ) bina kisi M [ … ] ke mile. ✓
Worked example Address 100 par Direct, memory-indirect, register-indirect
Forecast: teen loads jinmein number 100 ya pointer hold karne wala register mention hai. Inhe memory trips ke hisaab se rank karo.
Direct LOAD 100. E A = A = 100 . Operand = M [ 100 ] = 500 . Kyun? Field hi address hai — ek trip.
Memory-indirect LOAD (100). E A = M [ 100 ] = 500 , phir operand = M [ 500 ] = 800 . Do trips kyun? Pehli trip 100 par stored pointer padhti hai (jo 500 hai); doosri trip woh data padhti hai jahan pointer point karta hai. Yahi woh extra cost hai jiske baare mein parent ne warn kiya tha.
Register-indirect LOAD (R1). ( R 1 ) = 400 , toh E A = 400 , operand = M [ 400 ] = 700 . Sirf ek trip kyun? Pointer pehle se register mein baitha hai — use fetch karne ke liye koi memory trip nahi chahiye, sirf data ke liye final trip.
Neeche ka figure: har colored arrow ek memory trip hai. Amber path follow karo (direct, ek hop house 100 tak), cyan path (indirect, 100 tak hop karke pointer 500 padho, phir doosra hop house 500 tak), aur daaye taraf amber path (register-indirect, register pehle se 400 hold karta hai toh sirf ek hop house 400 tak). Arrows gino aur trips gino.
Verify: operands hain 500 , 800 , 700 ; trip counts 1 , 2 , 1 . Parent table se exactly match. ✓
LOAD -4(R3) with ( R 3 ) = 408 . Displacement A = − 4 .
Yahan R 3 ko base pointer ki tarah use kiya ja raha hai; shared street table se, ( R 3 ) = 408 .
Forecast: kya E A street par upar jaata hai ya neeche ? Operand kya hai?
E A = A + ( R 3 ) = ( − 4 ) + 408 = 404 . A negative kyun ho sakta hai? Displacement field ek signed number hai (dekho Instruction Format on field encoding). Negative offset base se backward walk karta hai — exactly wahi jo chahiye struct field ke liye jo pointer se pehle baitha ho, ya p[-1].
Operand = M [ 404 ] = 111 . Kyun? Computed E A par ek memory trip.
Verify: − 4 + 408 = 404 aur M [ 404 ] = 111 . Base minus 4 se 4 houses neeche landa — signed displacement arithmetic ke saath consistent. ✓
Worked example Kya hota hai jab
A = 0 ya ( R ) = 0 ?
Hum shared table se do registers use karte hain: R 1 (400 hold karta hai) aur R z (0 hold karta hai — ek register jiske contents zero hain; isme kuch special nahi, yeh bas ek normal register hai jo abhi 0 store karta hai).
Forecast: kya formulas break hote hain, ya gracefully collapse ho jaate hain?
Displacement with A = 0 : LOAD 0(R1). E A = 0 + ( R 1 ) = 0 + 400 = 400 . Yeh kyun matter karta hai? Zero offset ke saath displacement mode register-indirect mein degenerate ho jaata hai — same result jaise LOAD (R1). Toh register-indirect koi alag machine nahi; yeh displacement ka A = 0 corner hai.
Register holding 0: LOAD 100(Rz) with ( R z ) = 0 . E A = 100 + 0 = 100 , operand = M [ 100 ] = 500 . Yeh kyun matter karta hai? Ab register kuch contribute nahi karta aur displacement direct mein degenerate ho jaata hai (E A = A ).
Yahi deep lesson hai: modes ek family banate hain, aur zero inputs tumhe unke beech slide karte hain.
Verify: case 1 mein E A = 400 , operand 700 (= Ex 2 ka register-indirect result). Case 2 mein E A = 100 , operand 500 (= Ex 2 ka direct result). Dono collapses confirm. ✓
int arr[] jahan har element 4 bytes ka hai; arr[3] padho
Base register R b = 596 (array ka start, shared table se). Index register R 2 = 3 . Element size (scale) s = 4 .
Forecast: hum simply E A = 596 + 3 kyun nahi kar sakte?
Naïve (galat): 596 + 3 = 599 . Galat kyun? Element 3 sirf 3 bytes aage nahi hai — woh 3 elements aage hai, aur har element 4 bytes wide hai. Byte offset = index × scale.
Scaled index: E A = ( R b ) + ( R 2 ) ⋅ s = 596 + 3 ⋅ 4 = 596 + 12 = 608 . Operand = M [ 608 ] = 333 . Multiply kyun? Hardware ka scaled-index mode × s bake in karta hai, toh arr[i] element width se regardless ek single instruction mein compile hota hai (dekho Pointers and Arrays ).
Agar hum element 0 chahte: E A = 596 + 0 ⋅ 4 = 596 , operand = M [ 596 ] = 42 . Element 0 kyun check karein? Yeh confirm karta hai ki base pehle element ka address hai, zero offset ke saath.
Verify: 596 + 3 × 4 = 608 with M [ 608 ] = 333 , aur 596 + 0 × 4 = 596 with M [ 596 ] = 42 . ✓
Worked example Ek forward branch aur ek backward loop,
P C = 200
Punctuation box se yaad karo: * ek target se pehle matlab "current P C ke relative", toh assembler *+A ko E A = P C + A mein convert karta hai.
Forecast: ek loop jo back jump karta hai, uska offset positive hai ya negative?
Forward BRANCH +6: E A = P C + A = 200 + 6 = 206 . Absolute kyun nahi? Distance store karna code ko relocatable banata hai — ise kaheen bhi load karo aur P C + A phir bhi sahi instruction par land karta hai (dekho Instruction Set Architecture (ISA) ).
Backward BRANCH -8 (loop top): E A = P C + A = 200 + ( − 8 ) = 192 . Negative kyun? Ek loop ko repeat karne ke liye backward jump karna hota hai; assembler ek negative signed offset encode karta hai.
PC-relative se data LOAD *+8 (PC ke 8 aage ek constant padho): * ise PC-relative mark karta hai, toh E A = P C + 8 = 200 + 8 = 208 . Kyun? Same rule; position-independent constant pools bhi ise use karte hain.
Neeche ka figure: horizontal line address axis hai jisme P C = 200 amber mein marked hai. Cyan arrow + 6 ko house 206 tak forward trace karo (forward branch), amber arrow − 8 ko house 192 tak backward (loop jumping back), aur white arrow + 8 ko house 208 tak forward (PC-relative data read). Har landing spot bas P C plus ek signed distance hai.
Verify: 200 + 6 = 206 , 200 − 8 = 192 , 200 + 8 = 208 . Dono directions predict kiye gaye jagah land karte hain. ✓
LOAD (R1)+ phir LOAD -(R1), track karo ki kab R1 change hota hai
Start ( R 1 ) = 400 , step d = 1 .
Forecast: kya register memory access se pehle change hota hai ya baad mein? Yeh + aur - ke liye alag hota hai.
Auto-increment (R1)+ — pehle access, phir bump. E A = ( R 1 ) = 400 , operand = M [ 400 ] = 700 . Phir R 1 ← 400 + 1 = 401 . Yeh order kyun? Post-increment: current pointer use karo, phir advance karo — forward streaming mein *p++ ke liye perfect.
Auto-decrement -(R1) — pehle bump, phir access. Ab ( R 1 ) = 401 ; pehle R 1 ← 401 − 1 = 400 , phir E A = ( R 1 ) = 400 , operand = M [ 400 ] = 700 . Yeh order kyun? Pre-decrement: padhne se pehle back up karo — yeh pairing (post-inc / pre-dec) exactly wahi hai jo ek stack ko chahiye (agla example).
Verify: dono operations ke baad R 1 wapas 400 par aa jaata hai; dono reads M [ 400 ] = 700 dekhte hain. Order confirm. ✓
Worked example Push 77, phir pop karo, ek stack use karke jo
downward grow karta hai
Stack pointer SP = 600 , word size d = 1 , stack lower addresses ki taraf grow karta hai. "Grows down" matlab push pre-decrement use karta hai, pop post-increment use karta hai. Dekho Stack and Subroutines .
Forecast: PUSH 77 phir POP ke baad, kya value waapas aati hai aur SP kahan khatam hota hai?
PUSH 77 = auto-decrement store -(SP). Pehle S P ← 600 − 1 = 599 , phir M [ 599 ] ← 77 . Pre-decrement kyun? Pehle jagah banao top pointer ko neeche move karke, phir likho. Agar pehle likhte toh current top clobber ho jaata.
POP = auto-increment load (SP)+. E A = ( S P ) = 599 , operand = M [ 599 ] = 77 ; phir S P ← 599 + 1 = 600 . Post-increment kyun? Pehle top padho , phir SP ko wapas upar move karke slot free karo.
Net effect: humne 77 wapas paya aur SP 600 par return ho gaya. Yeh correctness kyun prove karta hai? Ek push jo immediately ek pop ke baad hoe, woh SP par no-op honi chahiye aur pushed value return karni chahiye — aur aisa hi hota hai.
Verify: pushed value 77 recover hui; SP 600 par start aur end hota hai; mid-sequence SP 599 tha. ✓
A = 100 carry karte hain aur R 1 = ( 400 ) name karte hain. Har interpretation ke under operand compute karo.
Forecast: chaar modes, chaar answers, usi number 100 / register 400 se.
Immediate: operand = A = 100 . (0 trips.) Number hi operand hai.
Direct: E A = 100 , operand = M [ 100 ] = 500 . (1 trip.)
Indirect: E A = M [ 100 ] = 500 , operand = M [ 500 ] = 800 . (2 trips.)
Displacement 100(R1): E A = 100 + 400 = 500 , operand = M [ 500 ] = 800 . (1 trip.)
Yeh classic exam trap kyun hai: modes 3 aur 4 same operand 800 dete hain lekin alag reasons se aur alag trip counts ke saath (2 vs 1). Operand se kabhi answer mat padho — hamesha mode name karo aur trips count karo.
Verify: operands 100 , 500 , 800 , 800 with trips 0 , 1 , 2 , 1 . ✓
Worked example Displacement jo ek 3-bit (0–7) address space ko overshoot karta hai
Maan lo ek toy machine mein sirf addresses 0 se 7 tak hain (address width 3 bits, toh 2 3 = 8 houses). LOAD 6(Rw) compute karo with ( R w ) = 5 .
Forecast: 6 + 5 = 11 , lekin house 11 exist hi nahi karta. Hardware kya karta hai?
Raw sum: E A raw = 6 + 5 = 11 . Yeh problem kyun hai? 11 > 7 ; yeh ek aisa house name karta hai jo is street par exist hi nahi karta.
Wrap (modulo the address space): real hardware sirf low 3 bits rakhta hai, matlab E A = 11 mod 8 = 3 . Modulo 2 n kyun? Ek n -bit adder simply carry-out drop kar deta hai; leftover 2 n se divide karne ke baad ka remainder hai. Toh overshoot silently low end par wrap ho jaata hai.
Limit ki sanity: exactly E A raw = 8 par hume 8 mod 8 = 0 milega — bilkul pehle house par wrap. Boundary kyun check karein? 8 sabse chhota overshoot hai; yeh confirm karna ki woh 0 par map karta hai dikhata hai ki wrap continuous hai bina kisi gap ke.
Verify: 11 mod 8 = 3 aur 8 mod 8 = 0 . Wrap-around ek generic aur boundary value dono par confirm. ✓
Recall Humne kaun si cells cover kiin?
Sab dus: zero-access (Ex1), trip-count axis (Ex2), negative displacement (Ex3), zero/degenerate collapse (Ex4), scaled index (Ex5), PC-relative dono taraf (Ex6), inc/dec ordering (Ex7), stack (Ex8), one-word-four-modes (Ex9), wrap-around (Ex10).
Har E A ek formula tha; har operand ko ek trip count ki zaroorat thi. Un do habits ko master karo.
Recall Quick self-test
LOAD (100) with M[100]=500, M[500]=800 — operand aur trips? ::: operand 800, 2 memory trips (indirect).
LOAD 0(R1) with (R1)=400 — yeh kis mode mein degenerate hota hai? ::: register-indirect; EA=400, operand M[400]=700.
Scaled arr[3], base 596, element size 4 — EA aur operand? ::: EA = 596 + 3×4 = 608, operand M[608]=333.
Push onto a downward stack, SP=600 — kaun sa auto-mode aur new SP? ::: pre-decrement -(SP); SP becomes 599.
LOAD 6(Rw), (Rw)=5, 3-bit address space — EA? ::: 11 mod 8 = 3.
"Kitne modes offer bhi karein?" ke peeche ka RISC-vs-CISC tension RISC vs CISC mein hai.