Step 04 · Machine essentials · B4

Instructions, addresses and the guest

Step a tiny invented CPU, then identify which parts of that model KytyPS5 implements differently.

Before this page: Objects, owners and borrowed memory. View the learning route.

Learn, run, explain

Before you start

Complete B3. You can now read the array, borrowed program view and Cpu reference in this example.

What a CPU keeps track of

A processor executes instructions and keeps small working values in registers. The program counter identifies the next instruction. Real x86-64 instructions have varying byte lengths; our invented machine instead indexes an array of fixed C++ Instruction objects. Its only arithmetic register is called accumulator. Its memory is four numbered words, not a console address space.

enum class Op names the allowed operations. A switch chooses behavior by operation; break exits that switch, while return exits the function. Cpu& lets run update the caller's Cpu object. A bool is true or false; here false reports an invalid program.

InstructionEffect
set 7accumulator becomes 7
add 5accumulator becomes 12
store 2memory word 2 receives 12
haltexecution returns success

The loop fetches the instruction at pc, increments pc, then executes it. There are no jumps, calls, interrupts, caches or real instruction encodings in this model. Unsigned addition wraps at its type's width; this program only adds the small values 7 and 5.

#include <array>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <span>

// Invented instruction set. These are not x86, RDNA, ELF or PM4 encodings.
enum class Op { set, add, store, halt };
struct Instruction { Op op; std::uint32_t operand; };
struct Cpu {
    std::size_t pc = 0;
    std::uint32_t accumulator = 0;
    std::array<std::uint32_t, 4> memory{};
};

bool run(std::span<const Instruction> program, Cpu& cpu) {
    while (cpu.pc < program.size()) {
        const Instruction instruction = program[cpu.pc];
        ++cpu.pc;
        switch (instruction.op) {
        case Op::set: cpu.accumulator = instruction.operand; break;
        case Op::add: cpu.accumulator += instruction.operand; break;
        case Op::store:
            if (instruction.operand >= cpu.memory.size()) return false;
            cpu.memory[instruction.operand] = cpu.accumulator;
            break;
        case Op::halt: return true;
        default: return false;
        }
    }
    return false; // Reaching the end without halt is an error in this model.
}

int main() {
    const std::array program{Instruction{Op::set, 7}, Instruction{Op::add, 5},
                            Instruction{Op::store, 2}, Instruction{Op::halt, 0}};
    Cpu cpu;
    if (!run(program, cpu) || cpu.memory[2] != 12 || cpu.pc != 4) return 1;
    std::cout << "pc=" << cpu.pc << " accumulator=" << cpu.accumulator
              << " memory[2]=" << cpu.memory[2] << '\n';
    const std::array bad{Instruction{Op::store, 4}, Instruction{Op::halt, 0}};
    Cpu invalid;
    if (run(bad, invalid) || invalid.memory != std::array<std::uint32_t, 4>{}) return 1;
    Cpu missing_halt;
    if (run(std::span<const Instruction>{program}.first(3), missing_halt)) return 1;
    std::cout << "out-of-range store and missing halt rejected\n";
}

Use the B1 setup once. From this learning repository's root:

cmake --build _Build/curriculum/beginner --target machine
ctest --test-dir _Build/curriculum/beginner -R '^beginner_machine$' --output-on-failure

To see the output directly in PowerShell, run .\_Build\curriculum\beginner\machine.exe; in a POSIX shell, run ./_Build/curriculum/beginner/machine. Tests compare the full output and require a successful exit.

Expected output, with exit status 0:

pc=4 accumulator=12 memory[2]=12
out-of-range store and missing halt rejected

Guest versus host

The guest is the software and machine contract being supported. The host is the computer and operating system running the emulator. Our host C++ program interprets each invented instruction in a switch. On KytyPS5's native x86-64 execution path, the host CPU executes guest CPU instructions directly; the emulator supplies compatible mappings and services and adapts selected boundaries. The GPU's shader instructions still need a different translation path.

Real programs also call functions. A return address records where execution should continue after a call. Registers and a stack hold arguments, local state and saved values according to an ABI, a binary agreement between caller and callee. Two x86-64 programs can use different agreements. Matching the instruction set therefore does not automatically make a console program callable like a normal host function.

A virtual address identifies a location in a process's address space. The operating system maps pages of that space to backing storage and assigns access permissions. An ELF file offset, a guest virtual address and a host pointer are different concepts. KytyPS5 arranges mappings so supported guest addresses are usable in the host process; an arbitrary integer cast to a pointer does not create a mapping or make an access valid.

Exercise

Write a row after each instruction containing pc, accumulator and memory[2]. Change add's operand to 8 and predict the result. Explain why store 4 must fail even though the memory array has four elements, and why a missing halt is reported as an error.

Hint

After fetch, pc has already advanced. Four elements have indices 0 through 3.

Worked answer and rubric

The original rows are (1,7,0), (2,12,0), (3,12,12), (4,12,12). With add 8, the last three accumulator values are 15 and memory[2] becomes 15 at the store; update the internal check and expected output. Store 4 is outside [0,4). Missing halt is an error by this invented machine's contract, not a claim about x86 execution. You are ready when you can explain why this interpreter is useful for learning but does not describe KytyPS5's guest CPU implementation.

Follow the real boundary next

Native execution, calling conventions and virtual memory expand these ideas. Later D2 follows actual source functions from mapped ELF segments to guest entry. Keep those real addresses separate from this lesson's word indices.

Before moving on

Ticks record your own assessment. Keep your prediction, actual output and explanation; a tick alone is not evidence of understanding.