From: Greg Burri Date: Sun, 11 Sep 2022 19:09:08 +0000 (+0200) Subject: Add call/ret operations X-Git-Url: http://git.euphorik.ch/index.cgi?a=commitdiff_plain;h=2405927df9d71394d561b387c786e578cad62ac0;p=rust_in_action.git Add call/ret operations --- diff --git a/ch5-data-in-depth/src/chip8.rs b/ch5-data-in-depth/src/chip8.rs index 77c7363..b5a1844 100644 --- a/ch5-data-in-depth/src/chip8.rs +++ b/ch5-data-in-depth/src/chip8.rs @@ -9,6 +9,9 @@ struct CPU { registers: [u8; 16], // 4 bits can address a 16 positions register. The last position (0xF) is used to indicate an overflow. position_in_memory: usize, // Programm counter. memory: [u8; 0x1000], // 4 KB of memory. + + stack: [u16; 16], + stack_pointer: usize, } impl CPU { @@ -17,6 +20,8 @@ impl CPU { registers: [0; 16], position_in_memory: 0, memory: [0; 0x1000], + stack: [0; 16], + stack_pointer: 0, } } @@ -36,15 +41,42 @@ impl CPU { let x = ((opcode & 0x0F00) >> 8) as u8; let y = ((opcode & 0x00F0) >> 4) as u8; let d = ((opcode & 0x000F) >> 0) as u8; + let nnn = opcode & 0x0FFF; match (c, x, y, d) { (0, 0, 0, 0) => { return; } + (0, 0, 0xE, 0xE) => self.ret(), + (0x2, _, _, _) => self.call(nnn), (0x8, _, _, 0x4) => self.add_xy(x, y), _ => todo!("opcode: {:04x}", opcode), } } } + fn call(&mut self, addr: u16) { + let sp = self.stack_pointer; + let stack = &mut self.stack; + + if sp > stack.len() { + panic!("Stack overflow!"); + } + + stack[sp] = self.position_in_memory as u16; + self.stack_pointer += 1; + self.position_in_memory = addr as usize; + } + + fn ret(&mut self) { + if self.stack_pointer == 0 { + panic!("Stack underflow!"); + } + + self.stack_pointer -= 1; + let addr = self.stack[self.stack_pointer]; + self.position_in_memory = addr as usize; + + } + fn add_xy(&mut self, x: u8, y: u8) { let arg1 = self.registers[x as usize]; let arg2 = self.registers[y as usize]; @@ -86,4 +118,31 @@ mod tests { assert_eq!(cpu.registers[0], 35); } + + // 5 + (10 * 2) + (10 * 2) = 45. (two calls). + #[test] + fn call_and_ret() { + let mut cpu = CPU::new(); + + cpu.registers[0] = 5; + cpu.registers[1] = 10; + + let code: [u8; 12] = [ + 0x21, 0x00, // Call function at 0x100. + 0x21, 0x00, // Call function at 0x100. + 0x00, 0x00, // Halt, end of program. + + 0x80, 0x14, // Add register 1 to register 0. + 0x80, 0x14, // Add register 1 to register 0. + 0x00, 0xEE, // Return from the function. + ]; + + cpu.memory[0x000..0x006].copy_from_slice(&code[0..6]); + cpu.memory[0x100..0x106].copy_from_slice(&code[6..12]); + + cpu.run(); + + assert_eq!(cpu.registers[0], 45); + } + } \ No newline at end of file