Sikau

Project: A whole computer · Day 1 · about 40 min

An assembler for the toy CPU

Turn assembly text with labels into 16-bit machine words.

One machine, three courses

This combined project brings How computers work, Assembly language and Operating systems together. You'll build a complete little computer system: an assembler that produces real machine words, a CPU that decodes and runs them, a decoder written in RISC-V, and a kernel that time-slices two programs on your CPU.

  • Day 1: the assembler (machine code)
  • Day 2: the CPU (fetch, decode, execute)
  • Day 3: a decoder in RISC-V assembly
  • Day 4: a kernel running two programs

The encoding

// The toy ISA: 16-bit words.  op (4 bits) | r (2) | s (2) | n (8)
const OPS = { HALT: 0, LOAD: 1, ADD: 2, SUB: 3, JMP: 4, JZ: 5, JNZ: 6, OUT: 7, DEC: 8, INC: 9, SYS: 10 };
const REGS = { A: 0, B: 1, C: 2, D: 3 };

function assemble(source) {
  const lines = [];
  const labels = {};
  source.split("\n").forEach((raw, i) => {
    const text = raw.split(";")[0].trim();
    if (!text) return;
    if (text.endsWith(":")) {
      labels[text.slice(0, -1)] = lines.length; // a label names the next word's address
      return;
    }
    lines.push({ parts: text.split(/[\s,]+/), line: i + 1 });
  });
  return lines.map(({ parts: [op, x, y], line }) => {
    const name = op.toUpperCase();
    const code = OPS[name];
    if (code === undefined) throw new Error(`Line ${line}: unknown instruction ${op}`);
    const reg = (t) => {
      if (!(t in REGS)) throw new Error(`Line ${line}: bad register ${t}`);
      return REGS[t];
    };
    const num = (t) => (t in labels ? labels[t] : Number(t)) & 255;
    let word = code << 12;
    if (["LOAD", "JZ", "JNZ"].includes(name)) word |= (reg(x) << 10) | num(y);
    else if (["ADD", "SUB"].includes(name)) word |= (reg(x) << 10) | (reg(y) << 8);
    else if (["OUT", "DEC", "INC"].includes(name)) word |= reg(x) << 10;
    else if (["JMP", "SYS"].includes(name)) word |= num(x);
    return word;
  });
}

LOAD A 3 → op 1, r 0, n 3 → 0x1003. ADD C B → op 2, r 2, s 1 → 0x2900. JNZ A loop (loop = 1) → 0x6001.

The rest of this lesson

  • Packing fields with shiftsexplain
  • Errors worth reportingexplain
  • Encode LOADfill
  • Instruction to wordmatch
  • Write the assemblerwrite code
  • Badge quizquiz
  • What you builtrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 4 lessons of Project: A whole computer