Last active
December 30, 2020 19:04
-
-
Save JayHelton/ce7d2ca3d7913217f8ae825e4a73f94c to your computer and use it in GitHub Desktop.
chip 8 emu exercise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct CPU { | |
registers: [u8; 16], | |
position_in_memory: usize, | |
memory: [u8; 4096], | |
stack: [u16; 16], | |
stack_pointer: usize, | |
} | |
impl CPU { | |
fn run(&mut self) { | |
loop { | |
let op_byte1 = self.memory[self.position_in_memory] as u16; | |
let op_byte2 = self.memory[self.position_in_memory + 1] as u16; | |
let opcode = op_byte1 << 8 | op_byte2; | |
let x = ((opcode & 0x0F00) >> 8) as u8; | |
let y = ((opcode & 0x00F0) >> 4) as u8; | |
let op_minor = (opcode & 0x000F) as u8; | |
let addr = opcode & 0x0FFF; | |
self.position_in_memory += 2; | |
println!("{:04x}", opcode); | |
match opcode { | |
0x0000 => { | |
println!("EXIT"); | |
return; | |
} | |
0x00EE => { | |
println!("RETURN"); | |
self.ret(); | |
} | |
0x2000...0x2FFF => { | |
println!("CALL {:04x}", addr); | |
self.call(addr); | |
} | |
0x8000...0x8FFF => match op_minor { | |
4 => { | |
println!("ADD positions, {} {}", x, y); | |
self.add_xy(x, y); | |
} | |
_ => { | |
unimplemented!("opcode: {:04x}", opcode); | |
} | |
}, | |
_ => unimplemented!("opcode {:04x}", opcode), | |
} | |
} | |
} | |
// when a function is called, we need to add the address to the instructions on the stack | |
// when we return from a function, we remove that address and go back to the other address | |
fn call(&mut self, addr: u16) { | |
let sp = self.stack_pointer; | |
let stack = &mut self.stack; | |
if sp > stack.len() { | |
panic!("Stack overflow!") | |
} | |
println!("Previous address {:04x}", self.position_in_memory); | |
stack[sp] = self.position_in_memory as u16; | |
self.stack_pointer += 1; | |
println!("{:04x} calling this address", addr); | |
self.position_in_memory = addr as usize; | |
} | |
fn ret(&mut self) { | |
if self.stack_pointer == 0 { | |
panic!("Stack underflow"); | |
} | |
self.stack_pointer -= 1; | |
println!( | |
"{:04x} returning to this address", | |
self.stack[self.stack_pointer] | |
); | |
self.position_in_memory = self.stack[self.stack_pointer] as usize; | |
} | |
fn add_xy(&mut self, x: u8, y: u8) { | |
self.registers[x as usize] += self.registers[y as usize]; | |
} | |
} | |
fn main() { | |
let mut cpu = CPU { | |
registers: [0; 16], | |
memory: [0; 4096], | |
position_in_memory: 0, | |
stack: [0; 16], | |
stack_pointer: 0, | |
}; | |
cpu.registers[0] = 5; | |
cpu.registers[1] = 10; | |
cpu.memory[0x000] = 0x21; // 1) CALL instruction at 0x100 | |
cpu.memory[0x001] = 0x00; | |
cpu.memory[0x002] = 0x21; // 4) CALL instruction at 0x100 again | |
cpu.memory[0x003] = 0x00; | |
cpu.memory[0x100] = 0x80; // 2 ) Add registers 0 and 1 together, then put the result in register 0, increment to next full instrauction in mem | |
cpu.memory[0x101] = 0x14; // (part of instruction 2) | |
cpu.memory[0x102] = 0x80; // 3 ) Add registers 0 and 1 together, then put the result in register 0, increment to next full instrauction in mem | |
cpu.memory[0x103] = 0x14; // (part of instruction 3) | |
cpu.memory[0x104] = 0x00; // 4 ) RETURN from current stack reference, deincrement stack, go to previous address () | |
cpu.memory[0x105] = 0xEE; // (part of instruction 4) | |
cpu.run(); | |
assert_eq!(cpu.registers[0], 45); | |
println!("5 + (10 * 2) + (10 * 2) = {}", cpu.registers[0]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment