4.1.7 · D5Computer Architecture (Deep)

Question bank — Instruction formats — R-type, I-type, J-type (MIPS - RISC-V)

1,615 words7 min readBack to topic

True or false — justify

The 6-bit opcode alone always uniquely identifies the operation.
False. For R-type instructions the opcode is 0 for all of them; the actual operation (add vs sub vs and) lives in the 6-bit funct field. Opcode picks the format; funct finishes the job.
Every MIPS instruction is 32 bits wide.
True. Fixed width is the core RISC choice: it lets fetch be a blind PC += 4 and lets the decoder slice the same bit positions every time. See Single-Cycle Datapath.
In R-type binary, the destination register rd appears first because you write it first in assembly.
False. In binary the order is opcode, rs, rt, rd, shamt, funct — sources first, destination third. The assembler reorders from the syntax add $rd,$rs,$rt.
A 16-bit immediate can hold any 32-bit constant you need.
False. It holds only 16 bits directly. For a full 32-bit constant you build it in two instructions (lui for the top half, then ori/addi for the bottom). See Sign Extension and Immediates.
beq stores the target as an absolute memory address.
False. It stores a signed word offset relative to PC+4. Hardware computes target = (PC+4) + (imm × 4). This is PC-relative addressing — see PC-relative vs Absolute Addressing.
A J-type instruction can jump to any address in the 32-bit space.
False. Only 26 bits are stored; the top 4 bits are inherited from the current PC, confining j to the same 256 MB region. For anywhere, use jr with a full 32-bit register.
For loads, rt is a source register just like it is for stores.
False. In lw $rt, off($rs) the loaded word is written into rt, so rt is the destination. In sw $rt, off($rs) the value in rt is read out, so there it's a source. Same field, opposite role.
The shamt field is used by every R-type instruction.
False. Only shift instructions (sll, srl, sra) use shamt; for add, sub, and, etc. it is simply 0. The field exists for the ops that need it and is ignored otherwise.
Multiplying the branch offset by 4 loses precision.
False. It loses nothing, because instruction addresses are always multiples of 4 (word-aligned). The low two bits of any legal target are already 00, so storing word counts instead of byte counts is free reach, not lost information.
The immediate in beq is sign-extended, but the address in j is not.
True. A branch offset can go backward (loops), so it is signed and sign-extended. The J-type field is an unsigned chunk pasted between PC's top bits and two trailing zeros — no sign involved. See Sign Extension and Immediates.

Spot the error

"add $t0,$s1,$s2 encodes as funct=0, opcode=32."
Swapped. It is opcode=0, funct=32 (0x20). Opcode 0 flags R-type; funct 32 names add. The student inverted the two fields.
"In lw $t0, 32($s3), $t0 is the base and $s3 receives the data."
Reversed. $s3 is the base address (rs); $t0 (rt) receives the loaded word. The syntax rt, offset(rs) puts the destination first, the base inside the parentheses.
"Branch target = PC + imm × 4."
Off by one instruction. The base is PC+4, not PC: target = (PC+4) + imm×4. MIPS uses the address of the following instruction as the reference point.
"J-type reconstructs the address as (top 4 of PC) ‖ address ‖ 0000."
Wrong tail width. Only two zeros are appended (word alignment), not four: 4 + 26 + 2 = 32. Appending four zeros would give 36 bits.
"R-type has 6+5+5+5+5+5 = 31 bits, so one bit is unused."
Miscounted funct. funct is 6 bits, not 5: 6+5+5+5+5+6 = 32. No padding bit exists in MIPS formats.
"To distinguish add from sub the assembler picks a different opcode."
No. Both keep opcode 0; only their funct codes differ (add=32, sub=34). Opcode stays fixed for the whole R-type family.
"Because I-type dropped rd, immediate-arithmetic can't have a destination."
False premise. The destination is repurposed onto rt. addi $rt,$rs,imm writes the result into rt. Losing the rd field doesn't lose the destination — it relocates it.

Why questions

Why does MIPS use exactly three formats instead of one per instruction?
To keep decoding uniform and cheap: the same bit positions feed the same hardware wires (register file ports, immediate path). Three rulebooks cover all needs while the decoder stays a small fixed circuit. See Control Unit and Decoding.
Why are register fields exactly 5 bits?
MIPS has registers, and naming one of 32 things needs bits — no more, no less. See MIPS Register File and Conventions.
Why give all R-type ops opcode 0 and a separate funct field?
It saves opcode space. One opcode value plus a 6-bit funct yields up to register operations without consuming 64 precious opcode slots that I- and J-type also need.
Why is the branch offset relative to PC while a jump target is (mostly) absolute?
Branches target nearby code (loops, ifs), so a small signed PC-relative offset both fits in 16 bits and lets code be relocated freely. Jumps target far labels (function calls), needing the wider 26-bit absolute-ish field. See PC-relative vs Absolute Addressing.
Why store the branch offset in words rather than bytes?
The two low bits of any instruction address are always 00, so storing them would waste bits. Counting in words and shifting left by 2 in hardware multiplies the reach fourfold for free (±128 KB instead of ±32 KB).
Why does jr exist when j already jumps?
j is confined to its 256 MB PC region (top 4 bits fixed). jr reads a full 32-bit register, so it can reach anywhere — essential for returning from calls and for long-distance transfers.
Why can two source registers and a destination all be named in R-type but only two registers in I-type?
The 16-bit immediate consumes the bits that R-type spent on rd, shamt, and funct (). Something had to go to make room for the constant, so I-type keeps only rs and rt.

Edge cases

What is funct for a load word lw?
A trick question — lw has no funct field. It is I-type, whose layout ends in a 16-bit immediate, not opcode 0 + funct. Only R-type instructions carry funct.
What happens if a branch offset of 0 is encoded?
target = (PC+4) + 0×4 = PC+4, i.e. control simply falls through to the next instruction — a harmless no-effect branch, not an infinite loop.
Can a branch offset be negative, and what does that mean?
Yes. The immediate is signed; a negative value means the target is behind the branch (target = PC+4 + imm×4 < PC). This is exactly how backward loops are built.
If a jump crosses a 256 MB region boundary, what does j produce?
It cannot cross it. The top 4 bits are forced to match the current PC, so a j whose intended target lies in another region silently lands in the wrong place — the assembler must instead use jr (via a register holding the full address).
What does shamt hold for a non-shift R-type like and?
It is set to 0 and ignored by the ALU. The field is only meaningful for sll, srl, sra; for everything else it is inert padding-with-a-purpose.
Is opcode 0 a legal, meaningful instruction on its own?
The all-zero word 0x00000000 decodes as R-type with funct = 0, which is sll $0,$0,0 — a shift of register $0 by 0. Since $0 is hardwired to zero, this is the canonical nop (no operation).
For a sw (store word), which register is the destination?
None in the register file. sw $rt, off($rs) writes to memory; rt is a source (the data), rs is a source (the base). No register receives a result, unlike lw.

Recall One-line self-test

Field that decides the format ::: the 6-bit opcode (with funct as tie-breaker when opcode is 0). Reference point for a branch target ::: PC+4, not PC. Bits appended below a J-type address ::: two zeros (word alignment).

Related deep dives: RISC-V Formats (R, I, S, B, U, J) · Control Unit and Decoding · MIPS Register File and Conventions