/ src / vm.rs
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  }