Intuition The big picture (WHY this exists)
A CPU is dumb: it only ever sees a 32-bit number. The instruction format is the agreed-upon way to slice those 32 bits into meaning — which operation, which registers, what constant. Without a fixed layout, hardware couldn't know if bits 21–25 are a register number or part of a constant. Formats are the contract between the assembler (software) and the decoder (hardware).
The deep reason MIPS uses only 3 formats of fixed 32-bit width : it makes the hardware decode trivially and uniformly . Every instruction is fetched the same way (PC += 4), and the same bit positions are reused across formats so the same wires feed the register file. This is the RISC philosophy: regularity over richness.
Every MIPS instruction = exactly 32 bits. The first 6 bits (the opcode ) tell the decoder which format to expect. That's the master key.
Definition The three formats
R-type (Register): operations using three registers — e.g. add $t0,$t1,$t2. Opcode is 0; the real operation is in the funct field.
I-type (Immediate): operations with a 16-bit constant or memory offset — e.g. addi, lw, sw, beq.
J-type (Jump): unconditional jumps with a 26-bit address — e.g. j, jal.
opcode ⏟ 6 rs ⏟ 5 rt ⏟ 5 rd ⏟ 5 shamt ⏟ 5 funct ⏟ 6 \underbrace{\text{opcode}}_{6} \;\underbrace{\text{rs}}_{5}\;\underbrace{\text{rt}}_{5}\;\underbrace{\text{rd}}_{5}\;\underbrace{\text{shamt}}_{5}\;\underbrace{\text{funct}}_{6} 6 opcode 5 rs 5 rt 5 rd 5 shamt 6 funct
Intuition Why these widths?
5-bit register fields because MIPS has 2 5 = 32 2^5 = 32 2 5 = 32 registers. You need exactly log 2 32 = 5 \log_2 32 = 5 log 2 32 = 5 bits to name one.
shamt (shift amount) = 5 bits, because you can shift a 32-bit word by 0–31 positions (log 2 32 = 5 \log_2 32 = 5 log 2 32 = 5 ).
funct = 6 bits: opcode 0 is overloaded for all R-type ops, so a second 6-bit field distinguishes add vs sub vs and... This gives 2 6 = 64 2^6=64 2 6 = 64 R-type operations without burning opcodes.
Total: 6 + 5 + 5 + 5 + 5 + 6 = 32 6+5+5+5+5+6 = 32 6 + 5 + 5 + 5 + 5 + 6 = 32 . ✓
rs, rt are source registers; rd is the destination .
opcode ⏟ 6 rs ⏟ 5 rt ⏟ 5 immediate ⏟ 16 \underbrace{\text{opcode}}_{6}\;\underbrace{\text{rs}}_{5}\;\underbrace{\text{rt}}_{5}\;\underbrace{\text{immediate}}_{16} 6 opcode 5 rs 5 rt 16 immediate
Intuition Why drop to 16-bit immediate?
We lost rd, shamt, funct (16 bits) and gave them all to a constant. 6 + 5 + 5 + 16 = 32 6+5+5+16=32 6 + 5 + 5 + 16 = 32 . ✓
Here rt becomes the destination (e.g. addi $rt, $rs, imm), and for loads/stores the immediate is a byte offset : lw $rt, offset($rs).
beq reuse I-type? — the genius of relative addressing
beq $rs,$rt,label needs two registers to compare and a target. But 16 bits can't hold a 32-bit address! Trick: the 16-bit immediate is a signed word offset relative to PC . Branch target = ( PC + 4 ) + ( imm × 4 ) = (\text{PC}+4) + (\text{imm} \times 4) = ( PC + 4 ) + ( imm × 4 ) . Multiplying by 4 (since instructions are word-aligned, always multiples of 4) effectively gives an 18-bit reach for "free."
opcode ⏟ 6 address ⏟ 26 \underbrace{\text{opcode}}_{6}\;\underbrace{\text{address}}_{26} 6 opcode 26 address
Intuition Why 26 bits for a 32-bit address?
6 + 26 = 32 6+26=32 6 + 26 = 32 . A 26-bit field can't hold a full 32-bit address. MIPS reconstructs the target as:
target = ( PC + 4 ) [ 31 : 28 ] ⏟ top 4 bits ∥ address ⏟ 26 ∥ 00 ⏟ 2 \text{target} = \underbrace{(\text{PC}+4)_{[31:28]}}_{\text{top 4 bits}} \;\Vert\; \underbrace{\text{address}}_{26}\;\Vert\; \underbrace{00}_{2} target = top 4 bits ( PC + 4 ) [ 31 : 28 ] ∥ 26 address ∥ 2 00
The bottom 00 is appended because instructions are word-aligned (the low 2 bits are always 0 — so why store them?). The top 4 bits come from the current PC. This gives effective 4 + 26 + 2 = 32 4+26+2 = 32 4 + 26 + 2 = 32 bits.
add $t0, $s1, $s2 (R-type)
Registers: $s1=17, $s2=18, $t0=8. For add: opcode=0, funct=32.
Slots: add rd, rs, rt → rd=$t0=8, rs=$s1=17, rt=$s2=18, shamt=0.
0 ( 6 ) ∣ 17 ( 5 ) ∣ 18 ( 5 ) ∣ 8 ( 5 ) ∣ 0 ( 5 ) ∣ 32 ( 6 ) 0_{(6)}\;|\;17_{(5)}\;|\;18_{(5)}\;|\;8_{(5)}\;|\;0_{(5)}\;|\;32_{(6)} 0 ( 6 ) ∣ 1 7 ( 5 ) ∣ 1 8 ( 5 ) ∣ 8 ( 5 ) ∣ 0 ( 5 ) ∣ 3 2 ( 6 )
Binary: 000000 10001 10010 01000 00000 100000
Why this step? Note the source order: in the instruction add $t0,$s1,$s2 the destination is written first , but in the binary rd sits in the middle . The assembler does this reordering for you.
lw $t0, 32($s3) (I-type)
lw $rt, offset($rs) → rt=$t0=8, rs=$s3=19, imm=32. opcode for lw = 35.
35 ( 6 ) ∣ 19 ( 5 ) ∣ 8 ( 5 ) ∣ 32 ( 16 ) 35_{(6)}\;|\;19_{(5)}\;|\;8_{(5)}\;|\;32_{(16)} 3 5 ( 6 ) ∣ 1 9 ( 5 ) ∣ 8 ( 5 ) ∣ 3 2 ( 16 )
Binary: 100011 10011 01000 0000000000100000
Why this step? rs is the base address register, the immediate is added to it. rt receives the loaded word — so rt is destination here, opposite to its source role in stores.
Worked example 3. Branch target of
beq $t0,$t1, LABEL where LABEL is 5 instructions ahead
The assembler computes offset in words : target is 5 instructions after the instruction following the branch. PC of beq = P P P . Then PC+4 = P + 4 P+4 P + 4 , and imm = 5.
target = ( P + 4 ) + 5 × 4 = P + 24 \text{target} = (P+4) + 5\times 4 = P + 24 target = ( P + 4 ) + 5 × 4 = P + 24
Why ×4? Each instruction is 4 bytes; the offset is stored in words to maximize reach. Hardware shifts left by 2.
j 0x00400024
Drop the bottom 2 bits (always 0) and take bits [27:2] of the byte address as the 26-bit field.
0 x 00400024 = 0000 0000 0100 0000 0000 0000 0010 0100 0x00400024 = 0000\,0000\,0100\,0000\,0000\,0000\,0010\,0100 0 x 00400024 = 0000 0000 0100 0000 0000 0000 0010 0100 .
Bits [27:2] → field = 0 x 100009 0x100009 0 x 100009 (after right-shift by 2). opcode j=2.
Why this step? We never store low 2 bits or top 4 bits — hardware reconstructs them, saving space.
Common mistake "rd is the first register in the binary too."
Why it feels right: In assembly you write the destination first (add $rd, $rs, $rt), so you assume it's first in bits.
The fix: In R-type binary the order is rs, rt, rd (sources first, destination third ). The assembler reorders. Memorize the bit order separately from the syntax order.
Common mistake "The branch offset is in bytes / is the absolute address."
Why it feels right: Addresses are usually byte addresses.
The fix: Branch immediates are signed word offsets relative to PC+4 , multiplied by 4 by hardware. Jump fields are word-shifted too. Always multiply the stored value by 4.
Common mistake "J-type can jump anywhere in memory."
Why it feels right: 26 bits + 2 implied looks like 28 — close to 32.
The fix: The top 4 bits come from the current PC , so j can only reach inside the same 256 MB region. To go further you need jr (jump register, an R-type that uses a full 32-bit register value).
Recall Feynman: explain to a 12-year-old
Imagine a 32-light switchboard. The first 6 switches spell a code word that tells you what kind of message this is. If it's a "do math with three lockers" message, the next switches name locker A, locker B, locker C and a tiny extra code for which math (add? subtract?). If it's a "do something with a small number" message, fewer switches name lockers and the rest spell out the number. If it's a "jump far away" message, almost all switches spell the place to jump. Same 32 switches, three different rulebooks — and the first 6 switches always say which rulebook to use.
Mnemonic Remember the three formats
"R egisters R ule, I mmediate I njects, J ust J ump."
R = 3 regs + funct · I = 2 regs + 16-bit const · J = 26-bit address.
Field order of R-type: "Oh, Really Rotten Rascals Shun Funerals" = Opcode, Rs, Rt, Rd, Shamt, Funct.
How many bits is a MIPS register field and why? 5 bits, because
2 5 = 32 2^5=32 2 5 = 32 registers exist, needing
log 2 32 = 5 \log_2 32 = 5 log 2 32 = 5 bits.
Total width of every MIPS instruction? 32 bits, fixed, for uniform decoding.
What field tells the decoder which format an instruction is? The 6-bit opcode (opcode 0 ⇒ R-type, look at funct).
R-type bit-field order from MSB? opcode(6), rs(5), rt(5), rd(5), shamt(6→5), funct(6).
Why do all R-type ops share opcode 0? The 6-bit funct field distinguishes them (
2 6 = 64 2^6=64 2 6 = 64 ops), saving opcode space.
In R-type, which register is the destination? rd (the third register field), even though it's written first in assembly.
I-type bit-field order? opcode(6), rs(5), rt(5), immediate(16).
In lw $t0,32($s3), what is rs, rt, imm? rs=
s 3 ( b a s e ) , r t = s3 (base), rt= s 3 ( ba se ) , r t = t0 (destination), imm=32 (offset).
Branch target formula for beq? target = (PC+4) + (signed_imm × 4).
Why multiply branch/jump offsets by 4? Instructions are word-aligned (multiples of 4); storing word counts extends reach for free.
J-type fields and target reconstruction? opcode(6)+address(26); target = PC[31:28] ‖ address ‖ 00.
Effective branch reach? ±128 KB (16 signed bits + 2 implied = 18-bit signed byte range).
Why can't j reach all of memory? Top 4 bits come from current PC ⇒ confined to a 256 MB region; use jr for full 32-bit jumps.
What is shamt and how wide? Shift amount, 5 bits (0–31 positions for a 32-bit word).
MIPS Register File and Conventions — why 32 registers ⇒ 5-bit fields
Single-Cycle Datapath — how fixed positions let rs/rt always feed the register file
Control Unit and Decoding — opcode/funct drive control signals
Sign Extension and Immediates — how 16-bit imm becomes 32-bit
PC-relative vs Absolute Addressing — branch vs jump target math
RISC-V Formats (R, I, S, B, U, J) — how RISC-V splits immediates for hardware simplicity
Intuition Hinglish mein samjho
Dekho, CPU sirf ek 32-bit number dekhta hai — usko khud se nahi pata ki yeh "add" hai ya "load" hai. Isliye hum 32 bits ko fixed tarike se kaat-te hain, jisko instruction format kehte hain. MIPS mein sirf 3 format hote hain: R-type (teen register, jaise add), I-type (do register + ek 16-bit constant, jaise addi, lw, beq), aur J-type (bada 26-bit address, jaise j). Sabse pehle 6 bits = opcode , yeh master key hai jo batati hai konsa rulebook lagega.
Register field 5 bits ka kyun? Kyunki MIPS mein 32 register hote hain aur log 2 32 = 5 \log_2 32 = 5 log 2 32 = 5 . R-type mein opcode 0 hota hai aur asli operation funct field mein chhupa hota hai — isse 64 R-type ops bin extra opcode ke ban jaate hain. Ek important baat: assembly mein destination pehle likhte ho (add $rd,$rs,$rt) par binary mein order hota hai rs, rt, rd — yani rd beech mein! Yeh galti sabse common hai, dhyan rakhna.
Branch aur jump mein ek smart trick hai. beq ka offset bytes mein nahi, words mein store hota hai, aur hardware usko 4 se multiply karta hai (kyunki har instruction 4 byte ka hota hai, low 2 bits hamesha 0). Isse reach badh jaati hai muft mein. Jump ke liye target banta hai: PC ke top 4 bits + 26-bit address + neeche 00. Isi wajah se j sirf apne 256 MB region mein hi jump kar sakta hai — poori memory mein jaane ke liye jr (register wala jump) chahiye.
Yeh sab matter kyun karta hai? Kyunki yeh "regularity" hi RISC ka dil hai — fixed positions ki wajah se decoder simple rehta hai, same wires register file ko feed karte hain, aur PC har baar +4 hota hai. Simple hardware = fast aur reliable chip.