5.1.8 · D3 · Hardware › Instruction Set Architecture (ISA) › RISC-V extensions (M, A, F, D, V, C)
Yeh deep dive the parent topic on RISC-V extensions ke under aati hai. Parent note ne tumhe bataya tha ki M, A, F aur D extensions kya karte hain. Yahan hum prove karte hain ki tum har case survive kar sako jo yeh instructions throw kar sakti hain — har sign, har zero, har overflow, har rounding trap.
Shuru karne se pehle, ek rule: jab bhi koi symbol aaye, pehle hum plain words mein batayenge ki uska matlab kya hai.
Definition Words jo hum baar baar use karenge
rs1, rs2 ::: "source register 1 / 2" — woh input boxes jisse instruction values padhti hai.
rd ::: "destination register" — woh output box jisme instruction result likhti hai.
Two's complement ::: woh tarika jisse computer negative whole numbers likhta hai. n bits par, top bit ka weight − 2 n − 1 hota hai, na ki + 2 n − 1 . Toh 32 bits par, 0x80000000 ka matlab hai − 2 31 , na ki + 2 31 .
Hex 0x... ::: base-16 shorthand. Har hex digit 4 binary bits ke barabar hai. 0xF = 1111 = 15.
.w / .s / .d suffix ::: word (32-bit integer), single float (32-bit), double float (64-bit).
Floor ⌊ x ⌋ ::: "woh sabse bada integer jo ≤ x ho." Toh ⌊ 3.9 ⌋ = 3 aur ⌊ 2 ⌋ = 2 . Hum ise use karte hain "division ke baad sirf whole-number part" batane ke liye.
ULP ::: "unit in the last place" — ek representable floating-point number aur uske bilkul agले waale number ke beech ka gap. Yeh sabse choti change hai jo tum ek float mein kar sakte ho uske lowest mantissa bit ko flip karke. Rounding error hamesha ULPs mein measure ki jaati hai.
In chaar extensions ke har trap ka ek cell hota hai. Neeche diye examples par cell label laga hai, taki tum check kar sako ki kuch chhuta toh nahi.
#
Cell (case class)
Extension
Kyun baith sakti hai galti
C1
Positive × positive, dono halves chahiye
M
32×32 se 64 bits banta hai; MULH bhoolne se top half kho jaata hai
C2
Signed × signed, ek negative
M
sign bits upper half mein propagate karte hain
C3
Dono negative (product positive)
M
bit level par naive "do negatives" reasoning
C4
Mixed signed × unsigned
M
MULHSU — exam favourite
C5
Divide-by-zero / signed overflow
M
RISC-V trap nahi karta ; defined values return karta hai
C6
Atomic increment, contended
A
LR/SC retry loop
C7
Atomic compare-and-swap
A
LR/SC se CAS banana
C8
Exact float add (power-of-two operands)
F
koi rounding nahi — "clean" case
C9
Inexact float add (0.1 + 0.2)
F
rounding error, classic bug
C10
Single vs double precision drift
F/D
kai adds ke baad accumulation
C11
Degenerate float: zero, aur − 0
F
do zeros, ek value
Prerequisites jo tumhare paas khule reh sakte hain: 5.1.07-RISC-V-base-ISA , 5.2.03-IEEE-754-floating-point , 3.3.06-Instruction-encoding , 6.4.02-Cache-coherence-protocols .
Map padho (figure s01). Top row mein teen families hain: lavender M box ek 64-bit product ko do halves mein split karta hai, mint A box reservation dance dikhata hai, butter F/D box align-add-round pipeline dikhata hai. Har top box se ek arrow neeche jaata hai ek coral box ki taraf jisme exact case numbers hain (C1–C5, C6–C7, C8–C11) jinhe hum chalenge. Ise apni checklist ki tarah use karo — har coral cell ka apna worked example neeche hai.
Intuition 64-bit box jo fit nahi karta
Do 32-bit numbers multiply karo aur answer 64 bits tak wide ho sakta hai — yeh ek 32-bit register mein fit nahi karta . Toh hardware andar poora 64-bit product banata hai, phir tumhe do grabs mein fetch karne deta hai: MUL tumhe bottom 32 bits deta hai, aur MULH/MULHU/MULHSU mein se koi ek top 32 bits deta hai. Tum jo variant choose karte ho woh hardware ko batata hai ki inputs ke signs ko kaise interpret karna hai.
full 64-bit product rs1 × rs2 = 2 32 ⋅ ( MULH ) + ( MUL )
Multiplier picture padho (figure s02). Do lavender 32-bit inputs rs1 aur rs2 mint "multiplier array" ko feed karte hain; uska arrow neeche ek butter bar ki taraf jaata hai jis par "full 64-bit product" likha hai. Us bar se do arrows nikalte hain: left wala coral MULH box ki taraf (bits [63:32]) aur right wala lavender MUL box ki taraf (bits [31:0]). Upar ki line, product = 2^32 * MULH + MUL, woh ek hi equation hai jo tumhe har M example ke liye chahiye — picture sirf dikhati hai ki har half physically kahan se aata hai.
Worked example C1 — Positive × positive, dono halves rakhna
Statement: rs1 = 0x10000 (yani 65536 ), rs2 = 0x10000 (65536 ). MUL aur MULH (signed) compute karo.
Forecast: guess karo — kya top half zero hoga ya non-zero?
True values multiply karo. 65536 × 65536 = 2 16 ⋅ 2 16 = 2 32 = 4294967296 .
Yeh step kyun? Bits touch karne se pehle, real number jaano. 2 32 ke liye bit 32 set hona chahiye — toh yeh 32 bits mein fit nahi kar sakta , upper half mein spill karta hai.
64-bit hex mein likho. 2 32 = 0x0000000100000000.
Yeh step kyun? Hex par split karna ab trivial hai: 8 low hex digits, 8 high hex digits.
MUL = low 32 bits = 0x00000000.
Yeh step kyun? MUL bits [31:0] return karta hai (figure s02 ka right-hand MUL box); 0x0000000100000000 ke low 8 hex digits sab zero hain.
MULH = high 32 bits = 0x00000001.
Yeh step kyun? Yeh exactly woh value hai ⌊ ( 2 32 ) / 2 32 ⌋ = 1 jo formula se predicted thi (floor ⌊ ⋅ ⌋ = "greatest whole number ≤ ", definitions box se).
Verify: 2 32 ⋅ MULH + MUL = 2 32 ⋅ 1 + 0 = 2 32 = 6553 6 2 . ✓ Dono operands positive hain, toh signed aur unsigned yahan same answer dete hain.
Worked example C2 — Signed × signed, ek operand negative
Statement: rs1 = 0x80000000 (signed = − 2 31 ), rs2 = 0x00000002 (= + 2 ). MUL aur MULH compute karo.
Forecast: true product negative hai — top 32 bits par kya asar padega?
True value. − 2 31 × 2 = − 2 32 = − 4294967296 .
Yeh step kyun? Negative product ka matlab hai, 64-bit two's complement mein, upper bits 1s se bharte hain (sign extension), 0s se nahi.
− 2 32 ka 64-bit two's complement. 2 64 − 2 32 = 0xFFFFFFFF00000000 lete hain.
Yeh step kyun? 64 bits par − x likhne ke liye 2 64 − x compute karo. Yahan x = 2 32 hai.
MUL = low half = 0x00000000.
Yeh step kyun? 0xFFFFFFFF00000000 ke low 8 hex digits sab zero hain, aur MUL sirf bits [31:0] return karta hai.
MULH (signed) = high half = 0xFFFFFFFF.
Yeh step kyun? Upar ke saare 1s ek negative number ki sign extension hain — yahi wajah hai ki MULH (signed variant) exist karta hai.
Verify: 0xFFFFFFFF00000000 ko signed 64-bit interpret karo: high bit set hai ⇒ negative. Iska magnitude = 2 64 − 0xFFFFFFFF00000000 = 2 32 . Toh value = − 2 32 . ✓
Worked example C3 — Dono operands negative (product positive)
Statement: rs1 = rs2 = 0x80000000 (dono = − 2 31 ). MULH (signed) compute karo aur, ek trap check ke liye, MULHU bhi.
Forecast: negative × negative = positive. Kya MULH aur MULHU agree karenge? Padhne se pehle guess karo.
Signed true value. ( − 2 31 ) × ( − 2 31 ) = 2 62 .
Yeh step kyun? Positive result ⇒ top bits 0s hain, 1s nahi.
2 62 ka 64-bit hex. 2 62 = 0x4000000000000000.
Yeh step kyun? 2 62 ek single bit set karta hai — bit 62 — jo upper half mein jaata hai, toh hum jaante hain MULH mein hi action hai.
MULH (signed) = high half = 0x40000000.
Yeh step kyun? 0x4000000000000000 ke high 8 hex digits 40000000 hain; yeh bits [63:32] hain, exactly woh jo MULH return karta hai (figure s02 ka left box). Numerically ⌊ 2 62 / 2 32 ⌋ = 2 30 = 0x40000000.
MULHU (dono unsigned) har input ko + 2 31 maanta hai: 2 31 × 2 31 = 2 62 phir → high half 0x40000000.
Yeh step kyun? Yahan dono numerically match karte hain , lekin meaning alag hai: MULH kahta hai "− 2 31 ka square", MULHU kahta hai "+ 2 31 ka square". Same bits, alag kahani. Yeh parent note ka mistake box hai, concretely dikhaya gaya.
Verify: 2 32 ⋅ 0x40000000 = 2 32 ⋅ 2 30 = 2 62 , aur low half 0x00000000 hai, total = 2 62 . ✓
Worked example C4 — Mixed: signed × unsigned (
MULHSU)
Statement: rs1 = 0xFFFFFFFF signed treat kiya gaya (= − 1 ), rs2 = 0x00000002 unsigned treat kiya gaya (= + 2 ). MULHSU aur MUL compute karo.
Forecast: ek chote negative aur ek chote positive ka product — top bits sab 1s honge ya sab 0s?
True value. signed( − 1 ) × unsigned( 2 ) = − 2 .
Yeh step kyun? MULHSU woh akela variant hai jo kehta hai "pehla signed hai, doosra unsigned" — big-number libraries mein zaroori hai jahan ek signed limb ko ek unsigned limb se multiply kiya jaata hai.
− 2 ka 64-bit two's complement = 0xFFFFFFFFFFFFFFFE.
Yeh step kyun? 64 bits par − 2 yaani 2 64 − 2 hai, jo sab 1s hai sirf last bit 0 ke — isliye ...FE tail.
MUL = low half = 0xFFFFFFFE.
Yeh step kyun? MUL bits [31:0] return karta hai; 0xFFFFFFFFFFFFFFFE ke low 8 hex digits FFFFFFFE hain.
MULHSU = high half = 0xFFFFFFFF.
Yeh step kyun? Negative product ⇒ upar sign-extended 1s, lekin sirf isliye kyunki humne hardware ko bataya ki pehla operand signed tha.
Verify: 0xFFFFFFFFFFFFFFFE signed value = − ( 2 64 − 0x...FE ) = − 2 . ✓
Worked example C5 — Degenerate: divide by zero aur signed overflow
Statement: RISC-V M mein division par koi trap nahi. Yeh kya return karte hain?
(a) DIVU rd, x, 0 (unsigned divide by zero).
(b) REM rd, x, 0 (remainder by zero), x = 7 ke liye.
(c) DIV rd, 0x80000000, 0xFFFFFFFF — signed − 2 31 ÷ − 1 (overflow case).
Forecast: C mein, zero se divide karne par crash hota hai. Kya RISC-V crash karta hai? Guess karo.
Divide by zero "all ones" return karta hai. RISC-V spec define karta hai ki DIV/DIVU by zero = − 1 = 0xFFFFFFFF.
Yeh step kyun? Ise define karna (trap karne ki jagah) hardware ko simple rakhta hai aur software ko allow karta hai ki agar wo chaho toh divisor check karo.
Remainder by zero dividend return karta hai. REM x, 0 = x. Toh REM 7, 0 = 7.
Yeh step kyun? Consistency: a = q ⋅ 0 + r force karta hai r = a .
Signed overflow. − 2 31 ÷ − 1 = + 2 31 , jo signed 32-bit mein fit nahi karta . Spec result ko dividend 0x80000000 (= − 2 31 ) define karta hai, aur us case ka REM = 0 .
Yeh step kyun? + 2 31 store nahi ho sakta, toh ISA exception ki jagah ek defined fallback choose karta hai.
Verify: (a) 0xFFFFFFFF = 2 32 − 1 . (b) = 7 . (c) result 0x80000000, remainder 0 . ✓ (VERIFY block dekho)
Is poore section ko drive karne wale do acronyms hain, toh koi bhi code se pehle inhe pin karte hain:
Definition Do atomic acronyms
LR/SC ::: ==L oad-R eserved / S tore-C onditional==. lr.w ek word load karta hai aur us address ko "mere liye reserved" mark karta hai. sc.w ek word tab hi store karta hai jab mera reservation abhi intact ho, aur wapas report karta hai ki kya succeed hua. Dono milke tumhe read, think, aur write karne dete hain bina kisi doosre core ke beech mein aane ke.
CAS ::: ==C ompare-A nd-S wap==. Ek logical operation: "agar memory abhi bhi woh value hold karti hai jo main expect karta hoon, toh ise new value se overwrite karo; warna chodho." Yeh lock-free data structures ka workhorse hai, aur hum ise LR/SC se build karenge.
Code mein do RISC-V pseudo-instructions bhi milenge:
Definition Do pseudo-ops jo tumhein dikhenge
bnez rX, label ::: "b ranch if n ot e qual to z ero" — agar register rX non-zero hai, label par jump karo; warna next line par fall through karo. Hum ise failed sc.w ko retry karne ke liye use karte hain.
li rX, value ::: "l oad i mmediate" — constant value seedha register rX mein daalo. Hum ise success/failure return code set karne ke liye use karte hain.
Reservation timeline padho (figure s03). Top coral row core A ki timeline hai, bottom lavender row core B ki, time mein left se right. Dono lr.w -> 5 se start karte hain (dono counter value 5 padhte hain aur address reserve karte hain). Core A ka sc.w 6 OK pehle fire karta hai; core B ki row par girta hua vertical "invalidate" arrow key moment hai — woh store core B ka reservation kill kar deta hai. Toh core B ka sc.w FAIL box kuch nahi karta, aur mint boxes dikhate hain core B loop karta hua: lr.w -> 6 (ab fresh value) phir sc.w 7 OK. Bottom mein butter bar, counter: 5 -> 6 -> 7, moral hai: koi update lose nahi hua.
Worked example C6 — Contended atomic increment (LR/SC retry)
Statement: Do cores ek hi counter par increment loop chalate hain jo 5 se start hai. Core A store jeetta hai; core B ka reservation toot jaata hai. Core B ko trace karo.
Forecast: kya core B 6 (apni stale value) likhega ya 7? Guess karo.
Dono lr.w t0, (a0) karte hain aur 5 padhte hain. Har ek apne core ke liye address reserved mark karta hai.
Yeh step kyun? lr.w address ko per-core reservation register mein record karta hai — dekho 6.4.02-Cache-coherence-protocols ki cache line writes kaise track karti hai.
Core A ka sc.w succeed karta hai , 6 likhta hai. Woh write core B ka reservation invalidate kar deta hai.
Yeh step kyun? Reserved line par kisi bhi doosre ka store exactly woh hai jo reservation kill karta hai.
Core B ka sc.w fail karta hai (non-zero return karta hai). bnez (branch-if-not-zero) retry par jump karta hai.
Yeh step kyun? Failed sc.w matlab core B ne jo value load ki thi woh stale hai; retry karna hi ek tarika hai core A ke 6 ko silently overwrite karne aur ek increment lose karne se bachne ka.
Core B lr.w re-run karta hai, ab 6 padhta hai , 7 compute karta hai, aur sc.w succeed karta hai.
Yeh step kyun? Fresh value ke saath retry karna hi final result correct banata hai: koi update lose nahi hota.
Verify: final counter = 5 → 6 → 7 . Do increments, value 7. ✓
Worked example C7 — LR/SC se built compare-and-swap
Statement: CAS(addr, expected, new) (compare-and-swap) implement karo: new tab hi likho jab mem[addr] == expected. expected = 10, new = 42, aur current memory 10 use karo.
Forecast: kya swap hoga? Aur agar memory 11 hoti toh?
cas:
lr.w t0, (a0) # load current, reserve address
bne t0, a1, fail # if current != expected, give up
sc.w t1, a2, (a0) # try to store new
bnez t1, cas # reservation lost? (t1 != 0) retry
li a0, 0 # li = load immediate: success code 0
ret
fail:
li a0, 1 # failure code 1
ret
lr.w current = 10 padhta hai, a1 (expected) = 10. Equal ⇒ branch mat karo.
Yeh step kyun? CAS tab hi aage badhta hai jab value caller ki assumption se match kare.
sc.w 42 likhta hai. Maano koi interfering core nahi hai, succeed karta hai ⇒ t1 = 0.
Yeh step kyun? Hum sc.w tak tabhi pahunche kyunki value match ki aur lr.w se reservation abhi live hai; woh store hi new value ko atomically commit karta hai.
Success return karo (a0 = 0), memory ab 42 hai. li a0, 0 (load-immediate) success code dalta hai.
Yeh step kyun? Zero t1 matlab store bina kisi interference ke land hua, toh caller ko batana zaroori hai ki swap sach mein hua — isliye success code 0.
Counterfactual: agar memory 11 hoti, toh step 1 ka bne fire karta ⇒ fail par jump, memory unchanged, 1 return karta.
Yeh step kyun? Yeh matrix ke "expected value match nahi ki" branch ko cover karta hai: CAS failure report karke memory ko untouched chhodna zaroori hai taki caller fresh read ke saath retry kar sake.
Verify: matched case → memory 42, code 0. Mismatched case → memory 11, code 1. ✓
Parent note aur 5.2.03-IEEE-754-floating-point se single-precision layout yaad karo:
( − 1 ) s × 1. m × 2 e − 127
jahan s sign bit hai, m 23-bit mantissa hai, e 8-bit biased exponent hai.
Float pipeline padho (figure s04). Char boxes left se right flow karte hain, har ek agले se arrow se juda: lavender unpack (har number ko 1. m × 2 e mein split karo), mint align (chote number ka mantissa shift karo taki dono ek exponent share karein), butter add mantissas , coral normalize + pack (sum ko wapas 1. m × 2 e form mein daalo aur bits 0x3FE00000 likho). Neeche caption, "no bits fall off the shift → no rounding → exact", batata hai ki yeh particular example (C8) clean kyun hai: mint box ka align step kuch lose nahi karta.
Worked example C8 — Exact float add (dono operands powers of two)
Statement: fadd.s f2, f0, f1 with f0 = 1.5, f1 = 0.25. Hardware steps se haath se karo.
Forecast: kya result exact hoga (koi rounding nahi)? Guess karo.
Unpack. 1.5 = 1. 1 2 × 2 0 , toh e = 127 , m = .100... ; 0.25 = 1. 0 2 × 2 − 2 , toh e = 125 .
Yeh step kyun? Adders ko dono numbers ek same exponent scale par chahiye add karne se pehle (figure s04 ka mint "align" box unpacked exponents par kaam karta hai).
Align karo chote wale ko (0.25 ) exponent 0 tak: mantissa ko 2 right shift karo ⇒ 0.0 1 2 × 2 0 .
Yeh step kyun? 127 − 125 = 2 places ka shift; koi bits end se nahi girte, toh koi rounding nahi .
Mantissas add karo: 1.10 0 2 + 0.01 0 2 = 1.11 0 2 = 1.75 .
Yeh step kyun? Jab dono exponent 2 0 share karte hain, mantissas ka ordinary binary addition hi real sum hai — pehle align karne ka yahi poora point hai.
Normalize + pack: already [ 1 , 2 ) mein hai, toh e = 127 , mantissa .110... ⇒ bits 0x3FE00000.
Yeh step kyun? 1.75 = 1.1 1 2 × 2 0 , mantissa top three bits 110 → 0x3FE00000.
Verify: 0x3FE00000 decode karo ⇒ 1.75 . Exact, kyunki 1.5 , 0.25 , aur 1.75 sab two ke powers ke finite sums hain. ✓
Worked example C9 — Inexact float add (0.1 + 0.2 trap)
Statement: Kya fadd.s(0.1, 0.2) exactly 0.3 hai? Explain karo aur drift do.
Forecast: true ya false? Padhne se pehle guess karo.
0.1 ek finite binary fraction nahi hai: 0. 1 10 = 0.000110011 0011 2 . 23 mantissa bits tak round karne par yeh ek aise value ban jaati hai jo 0.1 se thodi alag hai.
Yeh step kyun? Sirf two ke powers ke sums exact hote hain; 0.1 ka repeating binary tail hai (parent ka mistake box).
0.2 ke liye bhi same baat. Dono stored values already approximations hain.
Yeh step kyun? 0.2 = 2 × 0.1 wahi repeating tail inherit karta hai, toh add karne se pehle hi, dono inputs already rounded hain — errors load time par bake in ho jaati hain, sirf add time par nahi.
Do approximations add karo, phir round karo. Result ek aise value ke paas jaata hai jo 0.3 ke aas paas hai lekin stored value of 0.3 nahi.
Yeh step kyun? Do rounding errors plus final rounding rarely cancel hokar exact 0.3 bit pattern nahi dete.
Single precision mein: 0.1f + 0.2f ek aise value ki tarah store hota hai jiska stored 0.3f se distance ek single ULP ke order mein hai.
Yeh step kyun? Ek ULP sabse chota gap hai jo format yahan express kar sakta hai; jab true sum do representable floats ke beech land karta hai, rounding ise nearer wale par snap karta hai, roughly ek ULP (≈ 3 × 1 0 − 8 near 0.3 single precision mein) ka residual chodta hai.
Verify: real IEEE-754 arithmetic mein (0.1 + 0.2) == 0.3 False evaluate hota hai; difference nonzero hai (double mein order 1 0 − 17 , single mein 1 0 − 8 ). ✓
Worked example C10 — Single vs double drift ek million adds par
Statement: 1.0 ko ek accumulator mein 1 0 6 baar add karo, ek baar float (single) ke roop mein, ek baar double ke roop mein. Kaun exact rehta hai?
Forecast: guess karo kaun ant mein exactly 1000000 hoga.
Single precision mein 24 significant bits hain (2 24 = 16777216 ). Jab running sum 2 24 se zyada ho jaata hai, ULP (neighbouring floats ke beech gap) 1 se bada ho jaata hai, toh 1 add karne se value change nahi ho sakti — increment rounding mein kho jaata hai .
Yeh step kyun? Jab ek ULP us amount se bada hota hai jo tum add kar rahe ho, "+ 1 " same float par waapas round ho jaata hai. 2 24 danger threshold jaanna hume batata hai ki single precision exactly kab freeze hona shuru karta hai.
Target 1 0 6 ko threshold se compare karo. 1 0 6 = 1000000 < 16777216 = 2 24 .
Yeh step kyun? Accumulator in 1 0 6 adds ke dauran 2 24 cross nahi karta, toh ULP poore time 1 par ya us se neeche rehta hai — har "+ 1 " abhi bhi representable hai aur exactly land karta hai.
Isliye single precision yahan abhi bhi exact hai: float sum exactly 1000000.0 tak pahunchta hai.
Yeh step kyun? Koi add kabhi swallow nahi hota, toh koi error accumulate nahi hoti; trap sirf bade counts ke liye aata hai (jaise 2 24 se aage sum karna).
Double precision mein 53 significant bits hain (2 53 ≈ 9 × 1 0 15 ).
Yeh step kyun? Iski ULP 1 se neeche rehti hai jab tak sum astronomically large na ho, toh double yahan enormous margin ke saath exact hai — isliye numerically sensitive code double mein accumulate karta hai.
Verify: 1 0 6 ones ka float sum = 1000000.0 exactly (kyunki 1 0 6 < 2 24 ); double bhi = 1000000.0 . Dono is size par exact hain — trap sirf 2 24 ke baad aata hai. ✓
Worked example C11 — Degenerate floats:
+ 0 , − 0 , aur unka sum
Statement: IEEE-754 mein do zeros hain: 0x00000000 (+ 0 ) aur 0x80000000 (− 0 ). fadd.s(+0, -0) kya hai? Aur kya +0 == -0?
Forecast: sum ka sign guess karo, aur kya dono zeros compare equal karte hain.
Dono value mein zero hain , sirf sign bit (bit 31) mein alag hain.
Yeh step kyun? Format sign bit ko set hone deta hai even jab magnitude zero ho, jisse hardware record karta hai ki result kis direction se underflow hokar zero hua.
+0 == -0 true hai IEEE comparison rules ke hisaab se, even though bit patterns alag hain.
Yeh step kyun? Numeric comparison poochta hai "same value?", "same bits?" nahi; dono 0.0 represent karte hain, toh standard equality mandate karta hai. Sirf bitwise inspection dono ko alag kar sakta hai.
fadd.s(+0, -0) = +0 default round-to-nearest mode ke under.
Yeh step kyun? Standard is exact tie case ko + 0 par fix karta hai taki answer har conforming FPU par portable ho — tumhe kabhi guess nahi karna padta ki kaun sa zero niklega.
Verify: value( + 0 ) = value( − 0 ) = 0.0 , equality holds; unka sum 0.0 hai + sign ke saath. ✓
Recall Self-test
M — MULH ki zaroorat kyun hai? ::: Ek 32×32 product 64 bits tak hota hai; MUL low 32 deta hai, MULH high 32.
M — DIVU x, 0 RISC-V par kya return karta hai? ::: 0xFFFFFFFF (sab ones); koi trap nahi.
A — LR/SC ka full form kya hai? ::: Load-Reserved / Store-Conditional.
A — Core A ke store ke baad core B ka sc.w fail kyun hota hai? ::: Core A ki write ne us line par core B ka reservation invalidate kar diya.
A — CAS ka kya matlab hai? ::: Compare-And-Swap: overwrite tab hi karo jab memory abhi bhi expected value hold karti ho.
F — kya 1.5 + 0.25 exact hai? ::: Haan, dono aur unka sum two ke powers ke finite sums hain.
F — kya 0.1 + 0.2 == 0.3? ::: Nahi; 0.1 aur 0.2 binary mein exact nahi hain, toh rounding alag hoti hai.
F — ULP kya hota hai? ::: Ek representable float aur uske agले waale ke beech gap; lowest mantissa bit flip karne se sabse choti change.
F — kya +0 aur -0 compare equal karte hain? ::: Haan, numerically equal; bits alag hain.
"H igh U ses the same S ign story you tell it." MULH=dono signed, MULHU=dono unsigned, MULHSU=S igned-then-U nsigned.