# Machine code

*Instructions as numbers*

Machine code is a program expressed as raw bytes in memory, where each instruction byte splits into an opcode that names an operation and an operand that names its data. Defining that byte-to-meaning mapping is what defines a CPU's instruction set.

Group: Processor
URL: https://digiwleea.wleeaf.dev/learn/machine-code/

The [instruction register](https://digiwleea.wleeaf.dev/learn/instruction-register/) latches a byte and splits it into a high nibble and a low nibble. This lesson gives those nibbles **meaning**. A program is nothing more than a list of [bytes](https://digiwleea.wleeaf.dev/learn/binary/) sitting in [memory](https://digiwleea.wleeaf.dev/learn/ram/); what makes a byte an *instruction* is an agreement, the **instruction set**, that says which bit patterns mean which operations. That agreement is the contract between the hardware and the programs it runs.

## Opcode and operand

Recall the split: in our small machine the high 4 bits are the **opcode** (the operation, *what to do*) and the low 4 bits are the **operand** (usually *what to do it to*, here a memory address). Four opcode bits name up to sixteen instructions; four operand bits address sixteen memory locations. So one byte carries both the verb and its object.

```
instruction byte = opcode (bits 4-7) , operand (bits 0-3)
```

Reading instructions in [hex](https://digiwleea.wleeaf.dev/learn/hexadecimal/) makes this painless, because each nibble is one hex digit: the first digit is the opcode, the second is the operand. The byte `0x1E` is opcode `1`, operand `0xE` (address 14). The byte `0x25` is opcode `2`, operand `5`. You can read a program's bytes and immediately see the operation and address in each.

## A tiny instruction set

Here is a four-instruction set, enough to write real programs for the accumulator machine. Each opcode names what the CPU does; the operand is a memory address (ignored by `HALT`). `ACC` is the accumulator, the CPU's working register.

| opcode | name | what it does |
| --- | --- | --- |
| 0x1 | LOAD addr | ACC <- memory[addr] |
| 0x2 | ADD addr | ACC <- ACC + memory[addr] |
| 0x3 | STORE addr | memory[addr] <- ACC |
| 0xF | HALT | stop the clock |

_Four opcodes. The operand addr is the low nibble (a memory address 0-15). With just these, you can load a value, add another, and store the result, the core of any computation._

> **KEY:** Designing a CPU **is** choosing this table: which opcodes exist, what each does, and how the bits of a byte are carved into fields. The [control unit](https://digiwleea.wleeaf.dev/learn/control/) is then built to make each opcode's row actually happen. Real instruction sets (x86, ARM, RISC-V) are vastly bigger tables with wider instructions, but the idea is identical: a byte (or a few) names an operation and its operands.

## Assembling a line of a program

To turn a human-readable instruction into a byte, look up the opcode nibble and append the operand nibble. `ADD 14` is opcode `0x2`, address `14 = 0xE`, so the byte is `0x2E`, or `0010 1110` in binary. That hand-translation from a name to a number is what an **assembler** automates: it is pure table lookup plus packing nibbles, the inverse of the IR's split.

**Q (Try it):** Assemble `STORE 13` into a single byte, in hex and in binary. (Opcode for STORE is `0x3`; `13` is the operand.)

**A:** STORE is opcode `0x3`; `13` is `0xD` (`1101`). Pack opcode then operand: `0x3D`, which is `0011 1101` in binary. Bits 4-7 (`0011`) are the opcode, bits 0-3 (`1101`) the address.

And to **disassemble**, split a byte back into its nibbles, exactly what the [instruction register](https://digiwleea.wleeaf.dev/learn/instruction-register/) does in hardware. The figure below is that IR: load a byte and read the opcode and operand it exposes. Try the bytes from the program above.

_Circuit diagram: The instruction register decoding a byte (IR8): set the eight bits I0-I7 to an instruction, pulse LD, and read the opcode on OP0-OP3 (high nibble) and the operand on AR0-AR3 (low nibble). Before a load the outputs read Z. Open it in the lab, load 0010 1110 (0x2E, "ADD 14"), and read opcode 0010 and operand 1110._

> **KEY:** You can now read and write the machine's language. What remains is to watch it **run**: the [control unit](https://digiwleea.wleeaf.dev/learn/control/) steps through fetch-decode-execute, and a [worked program trace](https://digiwleea.wleeaf.dev/learn/program-trace/) follows a handful of these bytes through the machine, register by register, until they compute a result.

### FAQ

**Q:** What is machine code?

**A:** Machine code is a program expressed as raw bytes in [memory](https://digiwleea.wleeaf.dev/learn/ram/), where each instruction byte carries an **opcode** (the operation) and an **operand** (its data). Defining which bit patterns mean which operations is defining the CPU's **instruction set**, the contract between the hardware and the programs it runs.

**Q:** What is the difference between an opcode and an operand?

**A:** The **opcode** says *what to do* (load, add, store, halt); the **operand** says *what to do it to*, here usually a memory address. In this machine the high 4 bits of a byte are the opcode and the low 4 bits are the operand, so `0x2E` is opcode `0x2` (ADD) on operand `0xE` (address 14).

**Q:** How do you assemble an instruction into a byte?

**A:** Look up the opcode nibble and append the operand nibble. `ADD 14` is opcode `0x2` and address `14 = 0xE`, so the byte is `0x2E` (`0010 1110`). That table-lookup-plus-packing is exactly what an **assembler** automates, and the inverse of what the [instruction register](https://digiwleea.wleeaf.dev/learn/instruction-register/) does when it splits a byte back apart.

**Q:** What instructions are in this CPU's instruction set?

**A:** Four: `LOAD addr` (`0x1`, `ACC <- memory[addr]`), `ADD addr` (`0x2`, `ACC <- ACC + memory[addr]`), `STORE addr` (`0x3`, `memory[addr] <- ACC`), and `HALT` (`0xF`, stop the clock). With just load, add, and store you can compute and save a result, and the [control unit](https://digiwleea.wleeaf.dev/learn/control/) is built to make each row actually happen.
