5.1.7 · D3 · Hardware › Instruction Set Architecture (ISA) › RISC-V base ISA (RV32I - RV64I)
Intuition Yeh page kis kaam ki hai
Parent note ne tumhe RISC-V instruction encoding ke rules dikhaye the. Yeh page un sabhi scenarios ko dhundhta hai jo un rules se ban sakte hain — har sign, har field-split, har "gotcha" — aur har ek ko last bit tak solve karta hai. Kuch bhi tumhari imagination pe nahi chhoda gaya.
Hum do ideas pe zyada rely karenge jo parent ne introduce kiye the:
ek 12-bit immediate ek signed Two's Complement number hota hai (top bit = sign);
field splitting rs1/rs2/rd ko fixed jagahon pe rakhta hai (fast decode).
Agar inme se koi bhi shakya lagta ho, toh parent note RV32I/RV64I ko saath mein khula rakho.
Kuch bhi compute karne se pehle, territory ko map karte hain. Instruction encoding mein thodi si independent "axes" hoti hain jo har ek flip ho sakti hain. Ek worked example tab hi useful hai jab, doosron ke saath milke, woh har cell visit kare.
Axis (kya vary ho sakta hai)
Cell A
Cell B
Cell C
Immediate sign
positive imm
negative imm
zero / edge (-2048, +2047)
Format & field layout
I-type (contiguous imm)
S-type (imm do mein split )
B/J-type (imm split aur scaled ×2)
Ek instruction mein fit hota hai?
haan (≤12 bits)
nahi → lui+addi pair chahiye
bahut bada → 64-bit RV64I
Branch direction
forward (imm > 0)
backward (imm < 0)
not-taken (fall through)
Degenerate / x0
x0=0 use karta hai
nop (all-zero effect)
overflow wrap-around
RV32I vs RV64I
32-bit sign-extend
64-bit sign-extend
addw 32-bit wrap on 64-bit reg
Neeche, har example ko un cells se tag kiya gaya hai jo wo cover karta hai. Example 9 tak upar ki har cell kam se kam ek baar visit ho chuki hogi.
Intuition Bit diagrams ko kaise padhein
dekho. Yahi field map hai jo hum baar baar use karenge. Har colored block 32-bit word mein bits ka ek fixed-position run hai. Do orange arrows woh scary part dikhate hain: S-type aur B-type mein immediate ko tukdon mein toda jaata hai aur bikhar diya jaata hai — lekin har doosra field bilkul wahin rehta hai jahan tha. Yeh picture dhyan mein rakho; har example bas "in boxes ko bharo" jaisa hai.
addi x5, x6, 100 encode karo
Forecast: Padhne se pehle 32-bit hex guess karo. Kya 100 kisi negative cheez mein sign-extend hoga? (Hint: kya 100 ka bit 11 set hai?)
Step 1 — Format aur fixed fields chuno.
addi I-type hai: opcode = 0010011, funct3 = 000.
Yeh step kyun? Har derivation constant fields ko lock karne se shuru hoti hai; yeh operands pe depend nahi karte, isliye inhe pehle karna matlab hai ki hum movable ones ko galat jagah nahi rakh sakte.
Step 2 — Register numbers encode karo.
rd = 5 = 00101, rs1 = 6 = 00110.
Yeh step kyun? Registers plain 5-bit unsigned numbers hote hain (2 5 = 32 registers, exactly x0–x31). Yahan koi sign games nahi.
Step 3 — Immediate encode karo.
100 binary mein 0000 0110 0100 hai. Bit 11 (12 mein se sabse left wala) 0 hai, isliye yeh value non-negative hai; sign-extension zeros se pad karega → + 100 hi rehega.
Yeh step kyun? Hume bit 11 check karna hi parega number pe trust karne se pehle, kyunki 12-bit field signed hoti hai.
Step 4 — 32 bits pack karo. Layout hai imm[11:0] | rs1 | funct3 | rd | opcode:
imm 000001100100 r s 1 00110 f u n c t 3 000 r d 00101 o p co d e 0010011
8-bit bytes mein group karne par 0x06430293 milta hai.
Verify: Wapas decode karo — top 12 bits 0x064 = 100, positive, toh x 5 = x 6 + 100 . Sign-extended value exactly 100 hai. ✓
addi x5, x6, -1 encode karo aur stored value predict karo.
Forecast: − 1 ko represent karne wale 12 bits kya hain? Woh 32 bits mein sign-extend hokar kya banega?
Step 1 — − 1 ko 12-bit two's complement mein represent karo.
− 1 = 1111 1111 1111 (sab ones). Two's Complement dekho: all-ones hamesha − 1 hota hai, chahe width kuch bhi ho.
Yeh step kyun? Processor kabhi "nahi jaanta" ki tumhara matlab subtract tha — woh bas bits ko sign-extend karta hai. Toh hume − 1 ka bit pattern produce karna hai, decimal nahi.
Step 2 — XLEN = 32 tak sign-extend karo.
Bit 11 1 hai → use leftward copy karo: immediate 0xFFFFFFFF ban jaata hai.
Yeh step kyun? Sign-extension hi wajah hai ki addi ..., -1 sach mein ek subtract karta hai. 12-bit -1 aur 32-bit -1 same number hain, bas wider.
Step 3 — Result. x 5 = x 6 + ( − 1 ) = x 6 − 1 . RISC-V ko alag subi opcode ki zaroorat nahi: ek negative immediate hi subtraction hai.
Verify: Agar x 6 = 10 , toh x 5 = 9 . Immediate field 0xFFF sign-extended = − 1 ; 10 + ( − 1 ) = 9 . ✓
addi sabse bade aur sabse chhote immediate kya accept karta hai, aur +2048 pe kya hota hai?
Forecast: 12-bit signed field — iska range kya hai? 2048 ko place karne ki koshish karo.
Step 1 — 12 bits ka signed range compute karo.
Ek signed n -bit field ka span [ − 2 n − 1 , 2 n − 1 − 1 ] hota hai. n = 12 ke saath: [ − 2048 , + 2047 ] .
Yeh step kyun? 0 pe ek negative "slot" kharach ho jaata hai, isliye positive top (2047 ) negative bottom ki magnitude (2048 ) se ek kam hota hai.
Step 2 — Extremes encode karo.
+2047 = 0111 1111 1111, -2048 = 1000 0000 0000.
Yeh step kyun? Yahi "walls" hain. +2047 ka bit 11 = 0 (abhi bhi positive); -2048 ka bit 11 = 1 aur all-zero magnitude hai — sabse negative pattern.
Step 3 — addi x5, x6, 2048 ka kya hoga?
2048 ko bit 11 set chahiye, lekin ek set bit 11 negative matlab hota hai. Toh 2048 fit nahi hoga . Assembler ko instead lui+addi emit karna hoga (Example 5 dekho) ya ek temp register use karna hoga.
Yeh step kyun? Yahi exact frontier hai jahan "ek instruction" kaam karna band kar deta hai — yahi wajah hai ki two-instruction constant-load pattern exist karta hai.
Verify: 2 11 − 1 = 2047 ✓ aur − 2 11 = − 2048 ✓; bit pattern 1000 0000 0000 signed interpret karne par = − 2048 , jo confirm karta hai ki 2048 overflow karta hai. ✓
dekho: store immediate ko ek high piece imm[11:5] (7 bits, word ka top) aur ek low piece imm[4:0] (5 bits, jahan doosre formats mein rd hota hai) mein toda gaya hai. Teal brackets dikhate hain ki kaunse bits kahan jaate hain.
sw x7, -4(x8) encode karo (word x7 ko address x8 - 4 pe store karo).
Forecast: Offset -4 hai. Kaunse bits high piece mein jaate hain, kaunse low piece mein?
Step 1 — Fixed fields. sw S-type hai: opcode = 0100011, funct3 = 010.
Step 2 — Registers. Stores mein, rs1 = x8 (base address) = 01000, rs2 = x7 (store karne wali value) = 00111.
Yeh step kyun? Note karo ki rd nahi hota — store koi register result produce nahi karta. Wahi freed 5-bit slot exactly wahan hai jahan low immediate piece chhupti hai.
Step 3 — − 4 ke liye poora 12-bit immediate banao.
− 4 = 1111 1111 1100 (12 bits, two's complement).
Yeh step kyun? Hum pehle poora number banate hain, phir kaatte hain — kabhi ulta nahi, warna hum galat slice karenge.
Step 4 — Use split karo.
imm[11:5] = 1111111 (top 7 bits) → bits [31:25] pe rakha gaya.
imm[4:0] = 11100 (bottom 5 bits) → bits [11:7] pe rakha gaya.
Yeh step kyun? Split deliberate hai: rs1,rs2,funct3 apne I/R-type homes mein rehte hain toh decoder unhe format jaane bina padh sakta hai.
Step 5 — Effective address. x 8 + sext ( − 4 ) = x 8 − 4 .
Verify: 1111111 · 11100 = 1111 1111 1100 = − 4 ✓ reassemble karo. Agar x 8 = 0 x 1000 , toh address = 0x0FFC. ✓
x10 mein 0xDEADBEEF load karo (classic li expansion).
Forecast: 0xBEEF ke low 12 bits 0xEEF hain. Kya 0xEEF ek signed 12-bit ke roop mein positive hai ya negative? Isi se decide hoga ki hume upper part "round up" karna padega ya nahi.
Step 1 — Constant ko upper 20 + lower 12 mein split karo.
0xDEADBEEF = upper 0xDEADB (bits 31:12) aur lower 0xEEF (bits 11:0).
Yeh step kyun? lui bits 31:12 fill karta hai (20-bit immediate ko left mein 12 shift karke); addi ek signed 12-bit low part add karta hai. Saath mein yeh 32 bits cover karte hain.
Step 2 — Low part ka sign check karo.
0xEEF = 1110 1111 1111; bit 11 = 1 → negative : 0xEEF as signed 12-bit = − 273 .
Yeh step kyun? Yahi the subtlety hai. addi 0xEEF ko 0xFFFFFEEF tak sign-extend karega aur add karega — jo 273 subtract karta hai, upper bits ko corrupt karta hai jab tak hum compensate nahi karte.
Step 3 — Upper part ko 1 se round up karo.
Kyunki low add actually "− 273 " hai, upper immediate mein pehle se 1 add karo: 0xDEADB → 0xDEADC.
lui x 10 , 0xDEADC ⇒ x 10 = 0xDEADC000
addi x 10 , x 10 , − 273 ⇒ x 10 = 0xDEADC000 + ( 0xFFFFFEEF )
Yeh step kyun? Sign-extended − 273 ko 0xDEADC000 mein add karne se "missing" 0xBEEF low bits wapas milte hain aur upar add ki gayi +1 undo ho jaati hai.
Verify: 0xDEADC000 + 0xFFFFFEEF = 0xDEADBEEF (mod 2 32 ) ✓ — wrap se carry extra 1 ko cancel karta hai.
x11 mein 0x12345678 load karo.
Forecast: Low 12 bits 0x678 — sign bit set hai ya nahi? Kya is baar upper part round karna padega?
Step 1 — Split karo. Upper 0x12345, lower 0x678.
Step 2 — Low part ka sign-check karo. 0x678 = 0110 0111 1000; bit 11 = 0 → positive (+ 1656 ).
Yeh step kyun? Positive low part matlab hai ki addi exactly wahi add karta hai jo hum chahte hain — koi correction nahi chahiye . Example 5 se compare karo.
Step 3 — Emit karo.
lui x 11 , 0x12345 ; addi x 11 , x 11 , 0x678
Verify: 0x12345000 + 0x678 = 0x12345678 ✓. Upper part pe koi +1 nahi. ✓
dekho: ek address line pe do instructions hain. bne 0x104 pe hai; arrow backward curve karta hai loop 0x100 pe, toh offset negative aur small hai.
bne x1, x0, loop jahan loop branch se 4 bytes pehle hai.
Forecast: offset = target − pc = 0x100 − 0x104 = -4. B-type immediates 2 bytes ke units mein hote hain — toh jo "scaled" number store hoga woh kya hai?
Step 1 — Byte offset compute karo. target − p c = − 4 bytes.
Yeh step kyun? Branch targets hamesha branch ke apne address pc ke relative hote hain; PC-relative addressing (dekho Addressing Modes ) ki wajah se loops position-independent hote hain.
Step 2 — Implicit bit 0 = 0 enforce karo.
B-type immediate bit 0 store nahi karta (instructions ≥2-byte aligned hoti hain). − 4 even hai ✓, toh low bit drop hone se kuch nahi jata.
Yeh step kyun? Hamesha-zero bit ko drop karna hi wajah hai ki ek 12-bit field ± 2 KiB ki jagah ± 4 KiB tak pahunch sakta hai — range ki free doubling.
Step 3 — x0 se compare karo. bne x1, x0, ... tab branch karta hai jab x 1 = 0 . Koi dedicated "branch-if-nonzero" opcode ki zaroorat nahi; zero register hi constant 0 hai.
Verify: 0x104 se, offset − 4 0x100 = loop pe land karta hai ✓, aur − 4 even hai toh bit 0 = 0 satisfied hai ✓.
Worked example Exam twist: "
jal mein 20-bit immediate hai, toh yeh ± 2 19 bytes tak pahunchta hai." Sach ya jhooth — aur real reach kya hai?
Forecast: Store-the-bit-0 trick yaad karo. Kya J-type B-type ki tarah 2 se scale karta hai?
Step 1 — Recall karo ki J-type ek scaled offset store karta hai. B-type ki tarah, bit 0 implicit (0) hai. Toh 20 stored bits bytes ka ek half-count represent karte hain.
Yeh step kyun? Claim "20 bits" ko "20 bits of bytes " se confuse kar raha hai. Units 2-byte steps hain.
Step 2 — Real range compute karo.
Signed 20-bit half-steps: [ − 2 19 , 2 19 − 1 ] half-steps × 2 bytes = [ − 2 20 , + 2 20 − 2 ] bytes = ± 1 MiB .
Yeh step kyun? Count ko 2 se multiply karne se byte reach double ho jaati hai — exactly wahi mechanism jo Example 7 mein tha, ek bit wider.
Step 3 — Verdict. Jhooth. Reach ± 2 20 bytes (± 1 MiB) hai, ± 2 19 nahi.
Verify: 2 20 = 1 , 048 , 576 bytes = 1 MiB ✓; naive 2 19 iska exactly aadha hai. ✓
Worked example Ek saath do edge cases:
(a) addi x0, x0, 0 kya karta hai? (b) RV64I pe, agar x1 = 0xFFFFFFFF (sabse bada 32-bit unsigned) hai, toh addw x2, x1, x1 kya hai?
Forecast (a): Result kahan jaata hai? Forecast (b): Kya 64-bit result matter karta hai, ya sirf low 32 bits (phir sign-extended)?
Step 1 — Case (a): canonical nop.
addi x0, x0, 0 compute karta hai 0 + 0 = 0 aur use x0 mein write karta hai — lekin x0 saari writes discard karta hai . Net effect: kuch nahi badlega . Yahi official nop hai.
Yeh step kyun? Yeh ultimate degenerate instruction hai: ek real 32-bit encoding jiska semantics hai "kuch mat karo," jo pipeline stalls (dekho Pipelining ) aur alignment padding ke liye useful hai.
Step 2 — Case (b): wrap ke saath 32-bit sum compute karo.
0xFFFFFFFF + 0xFFFFFFFF = 0x1FFFFFFFE. addw sirf low 32 bits rakhta hai → 0xFFFFFFFE.
Yeh step kyun? *w instructions exactly isliye hain taaki 32-bit C arithmetic ek 64-bit machine pe sahi se wrap kare — top carry bit phek diya jaata hai.
Step 3 — 32-bit result ko 64 bits tak sign-extend karo.
Low-32 result 0xFFFFFFFE ka bit 31 = 1 hai → negative → sign-extend hokar 0xFFFFFFFFFFFFFFFE ban jaata hai.
Yeh step kyun? Har *w result sign-extend karne ke liye defined hai, toh ek 32-bit value 64-bit register mein "naturally" baithti hai.
Verify (a): x0 mein result = 0 regardless — nop ✓.
Verify (b): 0 x 1 F F F F F F F E ke low 32 bits = 0xFFFFFFFE; sign-extended = 0xFFFFFFFFFFFFFFFE ✓.
Recall Example 9 ke baad kaunse cells abhi bhi uncovered hain? (answer)
Koi bhi nahi — matrix ki har row (sign, format layout, fit, direction, degenerate, RV32I/RV64I) hit ho gayi. ✓
Recall Reveal
0xEEF lui part pe +1 kyun force karta hai lekin 0x678 nahi karta? ::: 0xEEF ka bit 11 set hai → signed-negative → addi subtract karta hai, isliye upper part compensate karne ke liye pre-increment hota hai. 0x678 ka bit 11 clear hai → positive → koi correction nahi.
12-bit signed immediate ka range? ::: [ − 2048 , + 2047 ] .
jal (J-type) ki real reach? ::: ± 2 20 bytes = ± 1 MiB (offsets 2 se scale hote hain).
addi x0, x0, 0 kya hai? ::: Canonical nop — x0 mein write discard ho jaati hai.
Mnemonic Teen "sign traps"
S ign-extend the immediate · S plit lekin pehle poora reassemble karo · S caled by 2 for branch/jump. Agar koi encoding tumhe surprise kare, toh in teen S's mein se ek culprit hai.
Related: RISC vs CISC · Assembler & Pseudo-instructions (li aur nop expansions wahan hain).