A hardware register holds data that a CPU can access directly. Operations usually need their operands in registers. In a CHIP-8 emulator, registers are represented as `u8` values inside a `CPU` struct: the Rust array models the processor’s registers rather than creating physical ones. section 5.7.1
Add two registers
Start with two registers holding 5 and 10. The opcode `0x8014` selects register 0, register 1, and addition. Executing it adds the value in register 1 to register 0, leaving 15 in register 0. 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];
}
}
Follow the decoded `x` and `y` values into `add_xy`: they are register indexes, while the array elements are the values being added. section 5.7.1
A larger CPU model has 16 general-purpose registers, so one hexadecimal digit can select a register. It also tracks `position_in_memory`, a special-purpose value normally called the program counter. The execution loop reads an opcode from memory, advances that position, then performs the selected operation. The last general-purpose register can serve as a carry flag for arithmetic overflow. section 5.7.3 section 5.7.3
Registers also participate in control flow: comparing their values can determine whether the CPU changes its position in memory. Thus registers hold more than arithmetic operands; their contents can affect which instruction runs next. section 5.7.5



