vm.rs
1 use std::fmt::Display; 2 3 use crate::fonts::{FONT_SPRITES, FONT_SPRITES_SIZE}; 4 use crate::rom::Ch8Rom; 5 use anyhow::Result; 6 use rand::Rng; 7 8 pub type Byte = u8; 9 pub type Word = usize; 10 pub type Opcode = (u8, u8, u8, u8); 11 12 const STACK_DEPTH: usize = 16; 13 const MEMORY_SIZE: usize = 4096; 14 const REGISTER_COUNT: usize = 16; 15 const KEY_COUNT: usize = 16; 16 const PROGRAM_START: usize = 0x200; 17 18 #[derive(Debug, Clone)] 19 pub struct VM { 20 pub memory: Vec<Byte>, 21 pub registers: [Byte; REGISTER_COUNT], 22 pub index: Word, 23 pub pc: Word, 24 pub stack: [Word; STACK_DEPTH], 25 pub stack_pointer: usize, 26 pub keyboard: [bool; KEY_COUNT], 27 pub delay_timer: Byte, 28 pub sound_timer: Byte, 29 pub rom: Ch8Rom, 30 pub vram: [[Byte; 64]; 32], 31 } 32 33 impl Display for VM { 34 fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 35 println!("memory: {:x?}", self.memory); 36 37 Ok(()) 38 } 39 } 40 41 impl VM { 42 pub fn new(rom: Ch8Rom) -> Result<Self> { 43 Ok(Self { 44 memory: vec![0; MEMORY_SIZE], 45 registers: [0; REGISTER_COUNT], 46 index: 0, 47 pc: PROGRAM_START, 48 stack: [0; STACK_DEPTH], 49 stack_pointer: 0, 50 keyboard: [false; KEY_COUNT], 51 delay_timer: 0, 52 sound_timer: 0, 53 rom, 54 vram: [[0; 64]; 32], 55 }) 56 } 57 58 pub fn initialize(&mut self) -> Result<()> { 59 /* Load Rom */ 60 self.memory[PROGRAM_START..(PROGRAM_START + self.rom.size)] 61 .copy_from_slice(&self.rom.memory); 62 63 /* Load Sprites */ 64 self.memory[..FONT_SPRITES_SIZE].copy_from_slice(&FONT_SPRITES); 65 66 Ok(()) 67 } 68 69 pub fn fetch(&mut self) -> Result<(Opcode, Word)> { 70 let bytecode = (self.memory[self.pc] as Word) << 8 | (self.memory[self.pc + 1] as Word); 71 self.pc += 2; 72 73 let nibbles = ( 74 ((bytecode & 0xF000) >> 12) as u8, 75 ((bytecode & 0x0F00) >> 8) as u8, 76 ((bytecode & 0x00F0) >> 4) as u8, 77 ((bytecode & 0x000F) >> 0) as u8, 78 ); 79 80 Ok((nibbles, bytecode)) 81 } 82 83 pub fn tick(&mut self) -> Result<()> { 84 let (opcode, bytecode) = self.fetch()?; 85 self.execute(opcode, bytecode)?; 86 self.update_timers(); 87 88 Ok(()) 89 } 90 91 fn update_timers(&mut self) { 92 if self.delay_timer > 0 { 93 self.delay_timer -= 1; 94 } 95 96 if self.sound_timer > 0 { 97 self.sound_timer -= 1; 98 } 99 } 100 101 pub fn execute(&mut self, opcode: Opcode, bytecode: Word) -> Result<()> { 102 match opcode { 103 (0, 0, 0, 0) => Ok(()), 104 (0, 0, 0xE, 0) => self.clear_screen(), 105 (0, 0, 0xE, 0xE) => self.ret(), 106 (1, _, _, _) => self.jmp(bytecode & 0x0FFF), 107 (2, _, _, _) => self.bl(bytecode & 0xFFF), 108 (3, x, _, _) => self.skip_if_vx_eq_nn(x as usize, (bytecode & 0xFF) as u8), 109 (4, x, _, _) => self.skip_if_vx_ne_nn(x as usize, (bytecode & 0xFF) as u8), 110 (5, x, y, 0) => self.skip_if_vx_eq_vy(x as usize, y as usize), 111 (6, x, _, _) => self.set_vx_nn(x as usize, (bytecode & 0xFF) as u8), 112 (7, x, _, _) => self.add_nn_to_vx(x as usize, (bytecode & 0xFF) as u8), 113 (8, x, y, 0) => self.set_vx_vy(x as usize, y as usize), 114 (8, x, y, 1) => self.vx_or_eq_vy(x as usize, y as usize), 115 (8, x, y, 2) => self.vx_and_eq_vy(x as usize, y as usize), 116 (8, x, y, 3) => self.vx_xor_eq_vy(x as usize, y as usize), 117 (8, x, y, 4) => self.add_vy_to_vx(x as usize, y as usize), 118 (8, x, y, 5) => self.sub_vy_from_vx(x as usize, y as usize), 119 (8, x, _, 6) => self.rshift_vx(x as usize), 120 (8, x, y, 7) => self.sub_vx_from_vy(x as usize, y as usize), 121 (8, x, _, 0xE) => self.lshift_vx(x as usize), 122 (9, x, y, 0) => self.skip_if_vx_ne_vy(x as usize, y as usize), 123 (0xa, _, _, _) => self.set_vx_vi(bytecode & 0xFFF), 124 (0xb, _, _, _) => self.jmp_v0_off_nnn(bytecode & 0xFFF), 125 (0xc, x, _, _) => self.vx_rand_and_nn(x as usize, (bytecode & 0xFF) as u8), 126 (0xd, x, y, n) => self.draw(x as usize, y as usize, n), 127 (0xe, x, 9, 0xe) => self.skip_if_key(x as usize), 128 (0xe, x, 0xa, 1) => self.skip_if_not_key(x as usize), 129 (0xf, x, 0, 7) => self.set_vx_dt(x as usize), 130 (0xf, x, 0, 0xa) => self.wait_for_key(x as usize), 131 (0xf, x, 1, 5) => self.set_dt(x as usize), 132 (0xf, x, 1, 8) => self.set_st(x as usize), 133 (0xf, x, 1, 0xe) => self.add_vx_to_vi(x as usize), 134 (0xf, x, 2, 9) => self.set_font_address_vi(x as usize), 135 (0xf, x, 3, 3) => self.bcd_vx(x as usize), 136 (0xf, x, 5, 5) => self.set_v0_sub_vx_info_i(x as usize), 137 (0xf, x, 6, 5) => self.load_i_into_v0_vx(x as usize), 138 (_, _, _, _) => unimplemented!( 139 "Unimplemented Opcode: ({:#08x}, {:#08x}, {:#08x}, {:#08x})", 140 opcode.0, 141 opcode.1, 142 opcode.2, 143 opcode.3 144 ), 145 } 146 } 147 148 /* core functions */ 149 fn clear_screen(&mut self) -> Result<()> { 150 self.vram = [[0; 64]; 32]; 151 152 Ok(()) 153 } 154 155 fn ret(&mut self) -> Result<()> { 156 self.stack_pointer -= 1; 157 self.pc = self.stack[self.stack_pointer]; 158 159 Ok(()) 160 } 161 162 fn jmp(&mut self, address: Word) -> Result<()> { 163 self.pc = address; 164 165 Ok(()) 166 } 167 168 fn bl(&mut self, address: Word) -> Result<()> { 169 self.stack[self.stack_pointer] = self.pc; 170 self.stack_pointer += 1; 171 self.pc = address; 172 173 Ok(()) 174 } 175 176 fn skip_if_vx_eq_nn(&mut self, x: usize, nn: Byte) -> Result<()> { 177 if self.registers[x] == nn { 178 self.pc += 2; 179 } 180 181 Ok(()) 182 } 183 184 fn skip_if_vx_ne_nn(&mut self, x: usize, nn: Byte) -> Result<()> { 185 if self.registers[x] != nn { 186 self.pc += 2; 187 } 188 189 Ok(()) 190 } 191 192 fn skip_if_vx_eq_vy(&mut self, x: usize, y: usize) -> Result<()> { 193 if self.registers[x] == self.registers[y] { 194 self.pc += 2; 195 } 196 197 Ok(()) 198 } 199 200 fn set_vx_nn(&mut self, x: usize, nn: Byte) -> Result<()> { 201 self.registers[x] = nn; 202 203 Ok(()) 204 } 205 206 fn add_nn_to_vx(&mut self, x: usize, nn: Byte) -> Result<()> { 207 self.registers[x] = self.registers[x].wrapping_add(nn); 208 209 Ok(()) 210 } 211 212 fn set_vx_vy(&mut self, x: usize, y: usize) -> Result<()> { 213 self.registers[x] = self.registers[y]; 214 215 Ok(()) 216 } 217 218 fn vx_or_eq_vy(&mut self, x: usize, y: usize) -> Result<()> { 219 self.registers[x] |= self.registers[y]; 220 221 Ok(()) 222 } 223 224 fn vx_and_eq_vy(&mut self, x: usize, y: usize) -> Result<()> { 225 self.registers[x] &= self.registers[y]; 226 227 Ok(()) 228 } 229 230 fn vx_xor_eq_vy(&mut self, x: usize, y: usize) -> Result<()> { 231 self.registers[x] ^= self.registers[y]; 232 233 Ok(()) 234 } 235 236 fn add_vy_to_vx(&mut self, x: usize, y: usize) -> Result<()> { 237 let (result, overflow) = self.registers[x].overflowing_add(self.registers[y]); 238 self.registers[x] = result; 239 self.registers[0xF] = overflow as Byte; 240 241 Ok(()) 242 } 243 244 fn sub_vy_from_vx(&mut self, x: usize, y: usize) -> Result<()> { 245 let (result, overflow) = self.registers[x].overflowing_sub(self.registers[y]); 246 self.registers[x] = result; 247 self.registers[0xF] = !overflow as Byte; 248 249 Ok(()) 250 } 251 252 fn rshift_vx(&mut self, x: usize) -> Result<()> { 253 self.registers[0xF] = self.registers[x] & 0x1; 254 self.registers[x] >>= 1; 255 256 Ok(()) 257 } 258 259 fn sub_vx_from_vy(&mut self, x: usize, y: usize) -> Result<()> { 260 let (result, overflow) = self.registers[y].overflowing_sub(self.registers[x]); 261 self.registers[x] = result; 262 self.registers[0xF] = !overflow as Byte; 263 264 Ok(()) 265 } 266 267 fn lshift_vx(&mut self, x: usize) -> Result<()> { 268 self.registers[0xF] = (self.registers[x] & 0x80) >> 7; 269 self.registers[x] <<= 1; 270 271 Ok(()) 272 } 273 274 fn skip_if_vx_ne_vy(&mut self, x: usize, y: usize) -> Result<()> { 275 if self.registers[x] != self.registers[y] { 276 self.pc += 2; 277 } 278 279 Ok(()) 280 } 281 282 fn set_vx_vi(&mut self, address: Word) -> Result<()> { 283 self.index = address; 284 285 Ok(()) 286 } 287 288 fn jmp_v0_off_nnn(&mut self, address: Word) -> Result<()> { 289 self.pc = (self.registers[0] as Word) + address; 290 291 Ok(()) 292 } 293 294 fn vx_rand_and_nn(&mut self, x: usize, nn: Byte) -> Result<()> { 295 let mut rng = rand::thread_rng(); 296 let rand: Byte = rng.gen(); 297 self.registers[x] = rand & nn; 298 299 Ok(()) 300 } 301 302 fn draw(&mut self, x: usize, y: usize, n: u8) -> Result<()> { 303 let mut collision = false; 304 for i in 0..n { 305 let byte = self.memory[self.index + i as usize]; 306 for j in 0..8 { 307 let bit = (byte >> (7 - j)) & 0x1; 308 let x = (self.registers[x] as usize + j) % 64; 309 let y = (self.registers[y] as usize + i as usize) % 32; 310 let prev_bit = self.vram[y][x]; 311 self.vram[y][x] ^= bit; 312 if prev_bit == 1 && self.vram[y][x] == 0 { 313 collision = true; 314 } 315 } 316 } 317 self.registers[0xF] = collision as Byte; 318 319 Ok(()) 320 } 321 322 fn skip_if_key(&mut self, x: usize) -> Result<()> { 323 if self.keyboard[self.registers[x] as usize] { 324 self.pc += 2; 325 } 326 327 Ok(()) 328 } 329 330 fn skip_if_not_key(&mut self, x: usize) -> Result<()> { 331 if !self.keyboard[self.registers[x] as usize] { 332 self.pc += 2; 333 } 334 335 Ok(()) 336 } 337 338 fn set_vx_dt(&mut self, x: usize) -> Result<()> { 339 self.registers[x] = self.delay_timer; 340 341 Ok(()) 342 } 343 344 fn wait_for_key(&mut self, x: usize) -> Result<()> { 345 for i in 0..KEY_COUNT { 346 if self.keyboard[i] { 347 self.registers[x] = i as Byte; 348 return Ok(()); 349 } 350 } 351 self.pc -= 2; 352 353 Ok(()) 354 } 355 356 fn set_dt(&mut self, x: usize) -> Result<()> { 357 self.delay_timer = self.registers[x]; 358 359 Ok(()) 360 } 361 362 fn set_st(&mut self, x: usize) -> Result<()> { 363 self.sound_timer = self.registers[x]; 364 365 Ok(()) 366 } 367 368 fn add_vx_to_vi(&mut self, x: usize) -> Result<()> { 369 self.index += self.registers[x] as Word; 370 371 Ok(()) 372 } 373 374 fn set_font_address_vi(&mut self, x: usize) -> Result<()> { 375 self.index = (self.registers[x] as Word) * 5; 376 377 Ok(()) 378 } 379 380 fn bcd_vx(&mut self, x: usize) -> Result<()> { 381 let vx = self.registers[x]; 382 self.memory[self.index] = vx / 100; 383 self.memory[self.index + 1] = (vx / 10) % 10; 384 self.memory[self.index + 2] = vx % 10; 385 386 Ok(()) 387 } 388 389 fn set_v0_sub_vx_info_i(&mut self, x: usize) -> Result<()> { 390 for i in 0..=x { 391 self.memory[self.index + i] = self.registers[i]; 392 } 393 394 Ok(()) 395 } 396 397 fn load_i_into_v0_vx(&mut self, x: usize) -> Result<()> { 398 for i in 0..=x { 399 self.registers[i] = self.memory[self.index + i]; 400 } 401 402 Ok(()) 403 } 404 }