A CPU executes operations using data held in registers. An opcode identifies an operation and its operands, while a main loop reads, decodes, and performs it. section 5.7.1
A minimal CPU emulator proceeds through these steps:
- Initialize the CPU with registers and a current opcode. section 5.7.1
- Load values into registers and place an opcode in the current-operation field. section 5.7.1
- Decode opcode nibbles into an operation group and register operands. section 5.7.1
- Dispatch the decoded instruction and update the selected register. section 5.7.1
Adding two registers
With registers 0 and 1 containing 5 and 10, opcode 0x8014 decodes as an addition using those registers. Executing it changes register 0 to 15. section 5.7.1
Listing 5.20 Reading the opcode
impl CPU {
fn read_opcode(&self) -> u16 { #1
self.current_operation #1
} #1
fn run(&mut self) {
// loop { #2
let opcode = self.read_opcode();
let c = ((opcode & 0xF000) >> 12) as u8; #3
let x = ((opcode & 0x0F00) >> 8) as u8; #3
let y = ((opcode & 0x00F0) >> 4) as u8; #3
let d = ((opcode & 0x000F) >> 0) as u8; #3
match (c, x, y, d) {
(0x8, _, _, 0x4) => self.add_xy(x, y), #4
_ => todo!("opcode {:04x}", opcode), #5
}
// } #6
}
fn add_xy(&mut self, x: u8, y: u8) {
self.registers[x as usize] += self.registers[y as usize];
}
}
Inspect the Rust implementation that reads an opcode, extracts its fields with bit masks, matches the instruction, and performs addition. section 5.7.1



