# Instruction Sets and Addressing Modes — Formats, Immediate to Indexed Addressing, RISC vs CISC

Source: https://skills101.in/learn/coa/instruction-formats-addressing-modes — Skills101 free tutorial (Computer Organisation & Architecture (COA)). Updated 2026-11-09.

An **instruction set architecture (ISA)** is the vocabulary a CPU understands: which operations exist, how they're encoded in bits, and how they find their operands. Addressing modes and instruction-format numericals are among the most asked COA questions in university and GATE exams.

## 1. Instruction format

An instruction is split into **fields**:

```text
| opcode | mode | operand / address fields ... |
```

- **Opcode** — which operation (ADD, LOAD, JUMP…). With `k` opcode bits you can have **2ᵏ** distinct operations.
- **Operand fields** — registers, memory addresses or constants.

**Number of addresses per instruction** (for `X = A + B`):

| Format | Example | Notes |
|---|---|---|
| 3-address | `ADD X, A, B` | short programs, long instructions |
| 2-address | `MOV X, A` / `ADD X, B` | one operand is also the destination |
| 1-address (accumulator) | `LOAD A` / `ADD B` / `STORE X` | ACC is implied (like our toy CPU) |
| 0-address (stack) | `PUSH A` / `PUSH B` / `ADD` / `POP X` | operands on a stack |

## 2. Instruction format numericals

**Example 1.** A CPU has 64 registers and 32-bit instructions. An instruction has an opcode, two register operands and a 12-bit immediate. How many opcodes are possible?

Register field = log₂64 = 6 bits each → 12 bits; immediate 12 bits; opcode = 32 − 12 − 12 = **8 bits → 256 opcodes**.

**Example 2 (expanding opcodes).** Instructions are 16 bits. Two-address instructions use a 4-bit opcode and two 6-bit address fields (4 + 6 + 6 = 16). There are 15 two-address instructions. What is the maximum number of one-address instructions?

A 4-bit opcode has 2⁴ = 16 patterns; 15 are used, so **1 pattern is free**. A one-address instruction doesn't need the second 6-bit address field, so that free pattern can be extended with those 6 bits: 1 × 2⁶ = **64** one-address instructions.

```python
import math

# Example 1
reg_bits = int(math.log2(64))
opcode_bits = 32 - 2 * reg_bits - 12
print("Ex1: opcode bits =", opcode_bits, "-> opcodes =", 2 ** opcode_bits)

# Example 2
two_addr_patterns = 2 ** 4
free_patterns = two_addr_patterns - 15
one_addr = free_patterns * 2 ** 6
print("Ex2: free 4-bit patterns:", free_patterns, "-> max one-address instructions:", one_addr)
```

```text
Ex1: opcode bits = 8 -> opcodes = 256
Ex2: free 4-bit patterns: 1 -> max one-address instructions: 64
```

**Rule:** leftover opcode patterns × 2^(bits freed by dropping an address field).

## 3. Addressing modes

The **effective address (EA)** is the memory address where the operand actually is. Each mode is a different way to compute it.

![Addressing modes compared: immediate (operand is in the instruction), direct (instruction holds the address), indirect (instruction holds the address of the address), register, register indirect, indexed or base plus offset, and PC-relative](https://skills101.in/learn-img/coa/addressing-modes.svg)

| Mode | Instruction contains | Operand is | Memory accesses for operand | Use |
|---|---|---|---|---|
| **Immediate** | the value itself | `#5` | 0 | constants |
| **Direct (absolute)** | address A | `M[A]` | 1 | global variables |
| **Indirect** | address A of a pointer | `M[M[A]]` | 2 | pointers |
| **Register** | register R | `R` | 0 | fastest; temporaries |
| **Register indirect** | register R holding an address | `M[R]` | 1 | pointers in registers |
| **Indexed / base + offset** | address A + index register | `M[A + R]` | 1 | arrays, struct fields |
| **PC-relative** | offset d | `M[PC + d]` (target PC+d for branches) | 1 | branches, position-independent code |
| **Auto-increment** | register R | `M[R]`, then R ← R + size | 1 | stepping through arrays |

## 4. Simulate the modes

```python
memory = {100: 500, 200: 300, 300: 42, 500: 7, 510: 99}
R = {"R1": 300, "R2": 10}
PC = 150

def operand(mode, field):
    if mode == "immediate":         return field
    if mode == "direct":            return memory[field]
    if mode == "indirect":          return memory[memory[field]]
    if mode == "register":          return R[field]
    if mode == "register_indirect": return memory[R[field]]
    if mode == "indexed":           base, reg = field; return memory[base + R[reg]]
    if mode == "relative":          return memory[PC + field]

tests = [("immediate", 100), ("direct", 100), ("indirect", 100), ("register", "R1"),
         ("register_indirect", "R1"), ("indexed", (500, "R2")), ("relative", 50)]
for mode, field in tests:
    print(f"{mode:18} field={str(field):12} operand={operand(mode, field)}")
```

```text
immediate          field=100          operand=100
direct             field=100          operand=500
indirect           field=100          operand=7
register           field=R1           operand=300
register_indirect  field=R1           operand=42
indexed            field=(500, 'R2')  operand=99
relative           field=50           operand=300
```

Trace two of them: **indirect 100** → `M[100] = 500` → `M[500] = 7`. **Indexed (500, R2)** → EA = 500 + 10 = 510 → `M[510] = 99` (this is exactly `arr[10]` when the array starts at 500).

## 5. RISC vs CISC

| | **RISC** (Reduced Instruction Set) | **CISC** (Complex Instruction Set) |
|---|---|---|
| Instructions | few, simple, fixed length | many, complex, variable length |
| Memory access | only LOAD/STORE touch memory | many instructions operate on memory directly |
| CPI | ~1 (easy to pipeline) | varies, many cycles |
| Registers | many | fewer |
| Control unit | hardwired | often microprogrammed |
| Examples | **ARM** (phones, Apple M-series), **RISC-V** | **x86** (Intel/AMD PCs) |

Modern x86 chips internally translate complex instructions into RISC-like **micro-operations**, so the line has blurred — but the exam distinctions above are still standard. **RISC-V** is an open ISA growing fast, including in Indian chip projects (e.g. the Shakti processors from IIT Madras).

## 6. Hardwired vs microprogrammed control

- **Hardwired control unit**: control signals generated by fixed logic circuits — fast, hard to change (RISC).
- **Microprogrammed control unit**: each instruction is a small program of **micro-instructions** stored in a control memory — flexible, easier to add complex instructions, slower (classic CISC).

## Common mistakes

- Immediate vs direct: `#100` is the **value** 100; `100` (direct) is the value **at address** 100.
- Counting memory accesses for indirect as 1 (it's 2 for the operand, plus the instruction fetch).
- Forgetting that PC already points to the next instruction when computing PC-relative targets in exam questions (read the question's convention).

## Quick recap

- Instruction = opcode + operand fields; k opcode bits → 2ᵏ operations; expanding opcodes reuse leftover patterns.
- Modes: immediate (value), direct `M[A]`, indirect `M[M[A]]`, register, register indirect `M[R]`, indexed `M[A+R]`, relative `M[PC+d]`, auto-increment.
- RISC: simple, fixed-length, load/store, pipelines well (ARM, RISC-V). CISC: complex, variable length (x86).
- Hardwired control = fast; microprogrammed = flexible.


Practice quiz and free certificate: https://skills101.in/learn/coa/instruction-formats-addressing-modes