# How a Computer Works — Von Neumann Architecture, CPU, Registers, Buses and the Instruction Cycle

Source: https://skills101.in/learn/coa/computer-organisation-basics — Skills101 free tutorial (Computer Organisation & Architecture (COA)). Updated 2026-11-09.

Every program you write — Python, Java, C — eventually becomes a sequence of tiny instructions executed by the CPU billions of times a second. **Computer Organisation and Architecture (COA)** explains how. It's a core subject in B.Tech/BCA/MCA, a regular GATE topic, and the reason some code is 10× faster than other code that looks the same.

## 1. Architecture vs organisation

| | Computer **architecture** | Computer **organisation** |
|---|---|---|
| Question | *what* the machine does, as seen by a programmer | *how* it's built to do that |
| Examples | instruction set, data types, addressing modes, number of registers | control signals, cache design, pipelines, bus widths |
| Analogy | the car's controls (steering, pedals) | the engine and gearbox underneath |

Two processors can share an architecture (e.g. both run x86-64 programs) with very different organisations (different caches, pipelines, speeds).

## 2. The von Neumann model

Almost every computer follows the **stored-program** idea of John von Neumann (1945): **instructions and data live in the same memory**, and the CPU fetches them one after another.

![Von Neumann architecture: the CPU (control unit, ALU and registers) connects through the system bus (address, data and control lines) to main memory holding both program and data, and to input/output devices](https://skills101.in/learn-img/coa/von-neumann.svg)

Main parts:

- **CPU** = **Control Unit (CU)** + **Arithmetic Logic Unit (ALU)** + **registers**
- **Memory** — holds program and data
- **I/O** — keyboard, display, disk, network
- **System bus** — the wires connecting them

The **von Neumann bottleneck**: instructions and data share one path to memory, so the CPU often waits for memory. Caches (lesson 5) exist largely to fight this. The **Harvard architecture** uses separate memories/paths for instructions and data — common in microcontrollers, and modern CPUs use it at the cache level (separate instruction and data caches).

## 3. Inside the CPU

| Part | Job |
|---|---|
| **ALU** | arithmetic (+, −) and logic (AND, OR, NOT, compare) |
| **Control Unit** | decodes instructions and sends control signals to everything else |
| **Registers** | tiny, ultra-fast storage inside the CPU |

The registers you must know:

| Register | Holds |
|---|---|
| **PC** (Program Counter) | address of the **next** instruction |
| **IR** (Instruction Register) | the instruction being executed now |
| **MAR** (Memory Address Register) | the address to read/write in memory |
| **MDR / MBR** (Memory Data/Buffer Register) | the data just read from / about to be written to memory |
| **ACC** (Accumulator) | result of ALU operations (in simple accumulator machines) |
| **General-purpose registers** | R0, R1, … for operands and results |
| **Flags / status register** | Zero, Carry, Sign, Overflow bits from the last operation |
| **SP** (Stack Pointer) | top of the stack (function calls) |

## 4. Buses

| Bus | Carries | Direction |
|---|---|---|
| **Address bus** | which memory location / device | CPU → memory/I/O (one-way) |
| **Data bus** | the actual data | both ways |
| **Control bus** | signals: read, write, interrupt, clock | both ways |

**Address bus width decides addressable memory:** with `n` address lines and byte-addressable memory, the CPU can address **2ⁿ bytes**. 16 lines → 64 KB; 32 lines → 4 GB.

```python
for lines in [16, 20, 32]:
    size = 2 ** lines
    print(f"{lines} address lines -> {size:,} bytes = {size // 1024:,} KB")
```

```text
16 address lines -> 65,536 bytes = 64 KB
20 address lines -> 1,048,576 bytes = 1,024 KB
32 address lines -> 4,294,967,296 bytes = 4,194,304 KB
```

(The 20-line case is the original 8086's famous 1 MB limit.)

## 5. The instruction cycle: fetch → decode → execute

![Instruction cycle: fetch (MAR gets PC, memory read into MDR, IR gets MDR, PC increments), decode (control unit reads the opcode), execute (ALU or memory operation), then check for interrupts and repeat](https://skills101.in/learn-img/coa/instruction-cycle.svg)

In register-transfer notation (used in exams):

| Step | Micro-operations |
|---|---|
| **Fetch** | `MAR ← PC`; `MDR ← Memory[MAR]`, `PC ← PC + 1`; `IR ← MDR` |
| **Decode** | control unit examines the opcode in `IR`, fetches operand addresses |
| **Execute** | e.g. for ADD X: `MAR ← X`; `MDR ← Memory[MAR]`; `ACC ← ACC + MDR` |
| **Interrupt check** | if an interrupt is pending, save PC and jump to the handler |

## 6. A tiny CPU in Python

Let's build a toy accumulator machine with 4 instructions and watch the cycle run. The program computes `marks1 + marks2` and stores it.

```python
memory = {
    0: ("LOAD", 10),    # ACC <- M[10]
    1: ("ADD", 11),     # ACC <- ACC + M[11]
    2: ("STORE", 12),   # M[12] <- ACC
    3: ("HALT", None),
    10: 78, 11: 92, 12: 0,
}
PC, ACC = 0, 0
while True:
    MAR = PC                      # fetch
    MDR = memory[MAR]
    PC = PC + 1
    IR = MDR
    opcode, addr = IR             # decode
    if opcode == "HALT":          # execute
        print(f"HALT  -> M[12] = {memory[12]}")
        break
    if opcode == "LOAD":
        ACC = memory[addr]
    elif opcode == "ADD":
        ACC = ACC + memory[addr]
    elif opcode == "STORE":
        memory[addr] = ACC
    print(f"{opcode:5} {addr} -> ACC = {ACC:3}, PC = {PC}")
```

```text
LOAD  10 -> ACC =  78, PC = 1
ADD   11 -> ACC = 170, PC = 2
STORE 12 -> ACC = 170, PC = 3
HALT  -> M[12] = 170
```

Real CPUs do exactly this — just with hundreds of instructions, many registers, and billions of cycles per second (a 3 GHz clock = 3 × 10⁹ ticks per second; one instruction may take one or several cycles).

## 7. Performance basics

**CPU time = Instruction count × CPI × Clock cycle time** (CPI = average Clock cycles Per Instruction).

```python
instructions = 2_000_000
cpi = 1.5
clock_hz = 2e9
cpu_time = instructions * cpi / clock_hz
print(f"CPU time = {cpu_time * 1000:.2f} ms")
print(f"MIPS = {instructions / (cpu_time * 1e6):.0f}")
```

```text
CPU time = 1.50 ms
MIPS = 1333
```

To make a program faster you can reduce instructions (better algorithm/compiler), reduce CPI (better organisation, pipelining) or raise the clock.

## Common mistakes

- Confusing MAR (an **address**) with MDR (the **data**).
- Saying PC holds the current instruction — it holds the address of the **next** one.
- Forgetting that the address bus is one-way and the data bus two-way.

## Quick recap

- Architecture = what the programmer sees; organisation = how it's built.
- **Von Neumann**: program and data share memory → bottleneck; Harvard separates them.
- CPU = **ALU + CU + registers** (PC, IR, MAR, MDR, ACC, flags, SP).
- `n` address lines → **2ⁿ** addressable locations.
- Cycle: **fetch** (MAR←PC, MDR←M, PC++, IR←MDR) → **decode** → **execute** → interrupt check.
- CPU time = IC × CPI × cycle time.


Practice quiz and free certificate: https://skills101.in/learn/coa/computer-organisation-basics