Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rusty VMs and Emulation

Rusty VMs and Emulation

Writing a Chip-8 Emulator in Rust

Ryan Levick

May 18, 2016
Tweet

More Decks by Ryan Levick

Other Decks in Programming

Transcript

  1. … an emulation of a particular computer system … [that]

    operate[s] based on the computer architecture & functions of a real or hypothetical computer
  2. Rust is a systems programming language that runs blazingly fast,

    prevents segfaults, and guarantees thread safety.
  3. 00110000 00110000 00110000 00110000 00110000 00110000 00110000 00100000 00110010 00110010

    00100000 01100110 00110110 00100000 00110110 01100010 00100000 00110000 01100011 00100000 00110110 01100011 00100000 00110011 01100110 00100000 00110110 01100100 00100000 00110000 01100011 00100000 01100001 00110010 00100000 01100101 01100001 00100000 01100100 01100001 00100000 01100010 00110110 00100000 01100100 01100011 00100000 01100100 00110110 00100000 00110110 01100101 00100000 00110000 00110000 00001010 00110000 00110000 00110000 00110000 00110000 00110001 00110000 00100000 00110010 00110010 00100000 01100100 00110100 00100000 00110110 00110110 00100000 00110000 00110011 00100000 00110110 00111000 00100000 00110000 00110010 00100000 00110110 00110000 00100000 00110110 00110000 00100000 01100110 00110000 00100000 00110001 00110101 00100000 01100110 00110000 00100000 00110000 00110111 00100000 00110011 00110000 00100000 00110000 00110000 00100000 00110001 00110010 00100000 00110001 01100001 00001010 00110000 00110000 00110000 00110000 00110000 00110010 00110000 00100000 01100011 00110111 00100000 00110001 00110111 00100000 00110111 00110111 00100000 00110000 00111000 00100000 00110110 00111001 00100000 01100110 01100110 00100000 01100001 00110010 00100000 01100110 00110000 00100000 01100100 00110110 00100000 00110111 00110001 00100000 01100001 00110010 00100000 01100101 01100001 00100000 01100100 01100001 00100000 01100010 00110110 00100000 01100100 01100011 00100000 01100100 00110110 00001010 00110000 00110000 00110000 00110000 00110000 00110011 00110000 00100000 00110110 00110000 00100000 00110000 00110001 00100000 01100101 00110000 00100000 01100001 00110001 00100000 00110111 01100010 00100000 01100110 01100101 00100000 00110110 00110000 00100000 00110000 00110100 00100000 01100101 00110000 00100000 01100001 00110001 00100000 00110111 01100010 00100000 00110000 00110010 00100000 00110110 00110000 00100000 00110001 01100110 00100000 00111000 01100010 00100000 00110000 00110010 00001010 00110000 00110000 00110000 00110000 00110000 00110100 00110000 00100000 01100100 01100001 00100000 01100010 00110110 00100000 00110110 00110000 00100000 00110000 01100011 00100000 01100101 00110000 00100000 01100001 00110001 00100000 00110111 01100100 00100000 01100110 01100101 00100000 00110110 00110000 00100000 00110000 01100100 00100000 01100101 00110000 00100000 01100001 00110001 00100000 00110111 01100100 00100000 00110000 00110010 00100000 00110110 00110000 00100000 00110001 01100110 00001010 00110000 00110000 00110000 00110000 00110000 00110101 00110000 00100000 00111000 01100100 00100000 00110000 00110010 00100000 01100100 01100011 00100000 01100100 00110110 00100000 01100001 00110010 00100000 01100110 00110000 00100000 01100100 00110110 00100000 00110111 00110001 00100000 00111000 00110110 00100000 00111000 00110100 00100000 00111000 00110111 00100000 00111001 00110100 00100000 00110110 00110000 00100000 00110011 01100110 00100000 00111000 00110110 00100000 00110000 00110010 00001010 00110000 00110000 00110000 00110000 00110000 00110110 00110000 00100000 00110110 00110001 00100000 00110001 01100110 00100000 00111000 00110111 00100000 00110001 00110010 00100000 00110100 00110110 00100000 00110000 00110000 00100000 00110001 00110010 00100000 00110111 00111000 00100000 00110100 00110110 00100000 00110011 01100110 00100000 00110001 00110010 00100000 00111000 00110010 00100000 00110100 00110111 00100000 00110001 00100000 00100000 00100000 00001010 00110000 00110000 00110000 00110000 00110001 00110000 00111000 00001010 00110110 00111001 00100000 01100110 01100110 00001010 00110000 00110000 00110000 00110000 00110000 01100011 00110000 00100000 00110001 00110010 00100000 01100011 00110000 00100000 00110001 00110010 00100000 01100011 00111000 00100000 00110111 00111001 00100000 00110000 00110001 00100000 00110100 00111001 00100000 00110000 00110010 00100000 00110110 00111001 00100000 00110000 00110001 00100000 00110110 00110000 00100000 00110000 00110100 00100000 01100110 00110000 00100000 00110001 00111000 00100000 00110111 00110110 00100000 00110000 00110001 00100000 00110100 00110110 00100000 00110100 00110000 00001010 00110000 00110000 00110000 00110000 00110000 01100100 00110000 00100000 00110111 00110110 00100000 01100110 01100101 00100000 00110001 00110010 00100000 00110110 01100011 00100000 01100001 00110010 00100000 01100110 00110010 00100000 01100110 01100101 00100000 00110011 00110011 00100000 01100110 00110010 00100000 00110110 00110101 00100000 01100110 00110001 00100000 00110010 00111001 00100000 00110110 00110100 00100000 00110001 00110100 00100000 00110110 00110101 00100000 00110000 00110000 00001010 00110000 00110000 00110000 00110000 00110000 01100101 00110000 00100000 01100100 00110100 00100000 00110101 00110101 00100000 00110111 00110100 00100000 00110001 00110101 00100000 01100110 00110010 00100000 00110010 00111001 00100000 01100100 00110100 00100000 00110101 00110101 00100000 00110000 00110000 00100000 01100101 01100101 00100000 00111000 00110000 00100000 00111000 00110000 00100000 00111000 00110000 00100000 00111000 00110000 00100000 00111000 00110000 00100000 00111000 00110000 00001010 00110000 00110000 00110000 00110000 00110000 01100110 00110000 00100000 00111000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110110 01100010 00100000 00110010 00110000 00100000 00110110 01100011 00100000 00110000 00110000 00100000 01100001 00110010 00100000 01100101 01100001 00100000 01100100 01100010 00100000 01100011 00110001 00100000 00110111 01100011 00100000 00110000 00110001 00001010 00110000 00110000 00110000 00110000 00110001 00110000 00110000 00100000 00110011 01100011 00100000 00110010 00110000 00100000 00110001 00110010 00100000 01100110 01100011 00100000 00110110 01100001 00100000 00110000 00110000 00100000 00110000 00110000 00100000 01100101 01100101 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00001010 00110000 00110000 00110000 00110000 00110001 00110000 00111000 00001010 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110000 00110000 00100000 00110110 01100010 00100000 00110010 00110000 00100000 00110110 01100011 00100000 00110000 00110000 00100000 01100001 00110010 00100000 01100101 01100001 00100000 01100100 01100010 00100000 01100011 00110001 00100000 00110111 01100011 00100000 00110000 00110001 00001010 00110000 00110000 00110000 00110000 00110001 00110000 00110000 00100000 00110011 01100011 00100000 00110010 00110000 00100000 00110001 00110010 00100000 01100110 01100011 00100000 00110110 01100001 00100000 00110000 00110000 00100000 00110000 00110000 00100000 01100101 01100101 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000 00100000
  4. 73 a2 6b 0c 6c 3f 6d 0c a2 ea

    da b6 dc d6 6e 00 22 d4 66 03 68 02 60 60 f0 15 f0 07 30 00 12 1a c7 17 77 08 69 ff a2 f0 d6 71 a2 ea da b6 dc d6 60 01 e0 a1 7b fe 60 04 e0 a1 7b 02 60 1f 8b 02 da b6 60 0c e0 a1 7d fe 60 0d e0 a1 7d 02 60 1f 8d 02 dc d6 a2 f0 d6 71 86 84 87 94 60 3f 86 02 61 1f 87 12 46 00 12 78 46 3f 12 82 47 1f 69 ff 47 00 69 01 d6 71 12 2a 68 02 63 01 80 70 80 b5 12 8a 68 fe 63 0a 80 70 80 d5 3f 01 12 a2 61 02 80 15 3f 01 12 ba 80 15 3f 01 12 c8 80 15 3f 01 12 c2 60 20 f0 18 22 d4 8e 34 22 d4 66 3e 33 01 66 03 68 fe 33 01 68 02 12 16 79 ff 49 fe 69 ff 12 c8 79 01 49 02 69 01 60 04 f0 18 76 01 46 40 76 fe 12 6c a2 f2 fe 33 f2 65 f1 29 64 14 65 00 d4 55 74 15 f2 29 d4 55 00 ee 80 80 80 80 80 80 80 00 00 00 00 00 6b 20 6c 00 a2 ea db c1 7c 01 3c 20 12 fc 6a 00 00 ee
  5. 73 a2 6b 0c 6c 3f 6d 0c a2 ea

    da b6 dc d6 6e 00 22 d4 66 03 68 02 60 60 f0 15 f0 07 30 00 12 1a c7 17 77 08 69 ff a2 f0 d6 71 a2 ea da b6 dc d6 60 01 e0 a1 7b fe 60 04 e0 a1 7b 02 60 1f 8b 02 da b6 60 0c e0 a1 7d fe 60 0d e0 a1 7d 02 60 1f 8d 02 dc d6 a2 f0 d6 71 86 84 87 94 60 3f 86 02 61 1f 87 12 46 00 12 78 46 3f 12 82 47 1f 69 ff 47 00 69 01 d6 71 12 2a 68 02 63 01 80 70 80 b5 12 8a 68 fe 63 0a 80 70 80 d5 3f 01 12 a2 61 02 80 15 3f 01 12 ba 80 15 3f 01 12 c8 80 15 3f 01 12 c2 60 20 f0 18 22 d4 8e 34 22 d4 66 3e 33 01 66 03 68 fe 33 01 68 02 12 16 79 ff 49 fe 69 ff 12 c8 79 01 49 02 69 01 60 04 f0 18 76 01 46 40 76 fe 12 6c a2 f2 fe 33 f2 65 f1 29 64 14 65 00 d4 55 74 15 f2 29 d4 55 00 ee 80 80 80 80 80 80 80 00 00 00 00 00 6b 20 6c 00 a2 ea db c1 7c 01 3c 20 12 fc 6a 00 00 ee
  6. Add

  7. pub struct Chip8 { regs: [u8; NUM_GENERAL_PURPOSE_REGS], i_reg: u16, delay_timer_reg:

    u8, sound_timer_reg: u8, stack_pointer_reg: u8, program_counter_reg: u16, memory: [u8; MEMORY_SIZE], stack: [u16; NUM_STACK_FRAMES], key_to_wait_for: Option<u8>, keyboard: [bool; NUM_KEYS], pub display: Box<Display>, }
  8. let mut computer = Chip8::new(program); loop { // Actual code

    throttles this loop to the // specified 60 instructions per second computer.cycle(); }
  9. impl Chip8 { // ... pub fn cycle(&mut self) {

    let instruction = self.instruction(); self.program_counter_reg = self.run_instruction(&instruction); } // ... }
  10. impl Chip8 { // ... fn instruction(&self) -> Instruction {

    let pc = self.program_counter_reg; let higher_order = self.memory[pc as usize] as u16; let lower_order = self.memory[(pc + 1) as usize] as u16; RawInstruction::new( (higher_order << 8) + lower_order ).to_instruction() } // ... }
  11. pub enum Instruction { ClearDisplay, Return, Jump(Address), Call(Address), SkipIfEqualsByte(Register, u8),

    SkipIfNotEqualsByte(Register, u8), SkipIfEqual(Register, Register), LoadByte(Register, u8), AddByte(Register, u8), Move(Register, Register), // ... }
  12. impl RawInstruction { // ... pub fn to_instruction(&self) -> Option<Instruction>

    { match self.xooo() { 0x0 => { match self.ooxx() { 0xE0 => Some(Instruction::ClearDisplay), 0xEE => Some(Instruction::Return), _ => None, } } 0x1 => Some(Instruction::Jump(self.oxxx())), 0x2 => Some(Instruction::Call(self.oxxx())), 0x3 => Some(Instruction::SkipIfEqualsByte(self.oxoo(), self.ooxx())), 0x4 => Some(Instruction::SkipIfNotEqualsByte(self.oxoo(), self.ooxx())), // ... } } // ... }
  13. impl Chip8 { // ... fn run_instruction(&mut self, instruction: &Instruction)

    -> u16 { match *instruction { Instruction::ClearDisplay => { self.display.clear(); self.program_counter_reg + 2 } Instruction::Return => { let addr = self.stack[(self.stack_pointer_reg - 1) as usize]; self.stack_pointer_reg -= 1; addr + 2 } Instruction::Jump(addr) => addr, Instruction::Call(addr) => { self.stack_pointer_reg += 1; self.stack[(self.stack_pointer_reg - 1) as usize] = self.program_counter_reg; addr } //... } } // ... }
  14. impl Chip8 { // ... fn run_instruction(&mut self, instruction: &Instruction)

    -> u16 { match *instruction { //... Instruction::AddByte(reg_number, value) => { let reg_value = self.read_reg(reg_number); self.load_reg( reg_number, value.wrapping_add(reg_value) ); self.program_counter_reg + 2 } //... } } // ... }
  15. for e in window { if let Some(_) = e.render_args()

    { let buffer = &computer.display.get_buffer(); draw_screen(buffer, &e); } if let Some(u) = e.update_args() { computer.cycle(u.dt); } }
  16. fn draw_screen(display_buffer: &display::Buffer, window: &PistonWindow) { window.draw_2d(|context, graphics| { piston_window::clear(color::BLACK,

    graphics); for (y, row) in display_buffer.iter().enumerate() { for (x, &val) in row.iter().enumerate() { if val { let dimensions = [(x * ENLARGEMENT_FACTOR) as f64, (y * ENLARGEMENT_FACTOR) as f64, ENLARGEMENT_FACTOR as f64, ENLARGEMENT_FACTOR as f64]; Rectangle::new(color::WHITE) .draw( dimensions, &context.draw_state, context.transform, graphics ); } } } }) }