1use crate::errors::OpcodeError;
2use rand::Rng;
3
4const SCREEN_WIDTH: usize = 64;
5const SCREEN_HEIGHT: usize = 32;
6
7pub const SPRITES: [[u8; 5]; 16] = [
9 [0xF0, 0x90, 0x90, 0x90, 0xF0],
10 [0x00, 0x60, 0x20, 0x20, 0x70],
11 [0xF0, 0x10, 0xF0, 0x80, 0xF0],
12 [0xF0, 0x10, 0xF0, 0x10, 0xF0],
13 [0x90, 0x90, 0xF0, 0x10, 0x10],
14 [0xF0, 0x80, 0xF0, 0x10, 0xF0],
15 [0xF0, 0x80, 0xF0, 0x90, 0xF0],
16 [0xF0, 0x10, 0x20, 0x40, 0x40],
17 [0xF0, 0x90, 0xF0, 0x90, 0xF0],
18 [0xF0, 0x90, 0xF0, 0x10, 0xF0],
19 [0xF0, 0x90, 0xF0, 0x90, 0x90],
20 [0xE0, 0x90, 0xE0, 0x90, 0xE0],
21 [0xF0, 0x80, 0x80, 0x80, 0xF0],
22 [0xE0, 0x90, 0x90, 0x90, 0xE0],
23 [0xF0, 0x80, 0xF0, 0x80, 0xF0],
24 [0xF0, 0x80, 0xF0, 0x80, 0x80],
25];
26
27pub struct Processor {
33 screen_buffer: [bool; SCREEN_WIDTH * SCREEN_HEIGHT],
35 registers: [u8; 0x10],
37 pc: usize,
39 stack: [u16; 0x10],
41 sp: usize,
42 mem: [u8; 0x1000],
44 i: u16,
46 dt: u8,
48 st: u8,
50 input_state: [bool; 0x10],
52 debug_print: bool,
54 last_key_released: Option<u8>,
58
59 vblank: bool,
60}
61
62impl Processor {
63 pub fn new() -> Processor {
64 let mut c = Processor {
65 screen_buffer: [false; SCREEN_WIDTH * SCREEN_HEIGHT],
66 registers: [0x00; 0x10],
67 pc: 0x200,
68 stack: [0x00; 0x10],
69 sp: 0,
70 mem: [0x00; 0x1000],
71 i: 0,
72 dt: 0,
73 st: 0,
74 input_state: [false; 0x10],
75 debug_print: false,
76 last_key_released: None,
77 vblank: false,
78 };
79 (0..0x10).for_each(|i| c.mem[(6 * i)..(6 * i + 5)].copy_from_slice(&SPRITES[i]));
80
81 return c;
82 }
83 pub fn load_program(&mut self, program: &[u8]) {
87 program
88 .iter()
89 .enumerate()
90 .for_each(|(i, v)| self.mem[0x200 + i] = *v);
91 }
92 #[allow(dead_code)]
97 pub fn load_program_u16(&mut self, program: &[u16]) {
98 (0..program.len()).for_each(|i| {
99 self.mem[0x200 + 2 * i] = (program[i] >> 8) as u8;
100 self.mem[0x200 + 2 * i + 1] = program[i] as u8;
101 });
102 }
103 pub fn step(&mut self) -> Result<(), OpcodeError> {
108 let r = self.execute(((self.mem[self.pc] as u16) << 8) | self.mem[self.pc + 1] as u16);
109 self.pc += 2;
110 r
111 }
112 pub fn on_tick(&mut self) {
117 self.dt = self.dt.saturating_sub(1);
118 self.st = self.st.saturating_sub(1);
119 }
120 pub fn update_inputs(&mut self, inputs: [bool; 0x10]) {
124 inputs.iter().enumerate().for_each(|(i, v)| {
125 if !v && self.input_state[i] {
126 self.last_key_released = Some(i as u8);
127 }
128 });
129 self.input_state = inputs;
130 }
131 pub fn execute(&mut self, inst: u16) -> Result<(), OpcodeError> {
136 if self.debug_print {
137 println!("Inst is {:X}", inst);
138 println!("Initial state:");
139 self.dump_state();
140 }
141 match inst & 0xF000 {
154 0x0000 => match inst & 0x0FFF {
155 0x0E0 => self.clr(),
156 0x0EE => self.ret(),
157 _ => {}
158 },
159 0x1000 => self.jmp(inst & 0x0FFF),
160 0x2000 => self.call(inst & 0xFFF),
161 0x3000 => self.se_r_kk(reg_at(inst, 1), (inst & 0xFF) as u8),
162 0x4000 => self.sne_r_kk(inst),
163 0x5000 => {
164 if inst & 0xF != 0 {
165 return Err(OpcodeError::new(inst, self.pc as u8));
166 }
167 self.se_rx_ry(reg_at(inst, 1), reg_at(inst, 2));
168 }
169 0x6000 => self.ld_r_kk(reg_at(inst, 1), (inst & 0xFF) as u8),
170 0x7000 => self.add_r_kk(reg_at(inst, 1), (inst & 0xFF) as u8),
171 0x8000 => {
172 let rx = reg_at(inst, 1);
173 let ry = reg_at(inst, 2);
174 match inst & 0x000F {
175 0 => self.ld_rx_ry(rx, ry),
176 1 => self.or_rx_ry(rx, ry),
177 2 => self.and_rx_ry(rx, ry),
178 3 => self.xor_rx_ry(rx, ry),
179 4 => self.add_rx_ry(rx, ry),
180 5 => self.sub_rx_ry(rx, ry),
181 6 => self.shr(rx, ry),
182 7 => self.subn(rx, ry),
183 0xE => self.shl(rx, ry),
184 _ => return Err(OpcodeError::new(inst, self.pc as u8)),
185 }
186 }
187 0x9000 => {
188 if inst & 0xF != 0 {
189 return Err(OpcodeError::new(inst, self.pc as u8));
190 }
191 self.sne_rx_ry(reg_at(inst, 1), reg_at(inst, 2));
192 }
193 0xA000 => self.ld_i(inst & 0x0FFF),
194 0xB000 => self.jmp_r0(inst & 0x0FFF),
195 0xC000 => self.rand(reg_at(inst, 1), inst & 0xFF),
196 0xD000 => self.draw(reg_at(inst, 1), reg_at(inst, 2), reg_at(inst, 3)),
197 0xE000 => match inst & 0x00FF {
198 0x9E => self.skp_r(reg_at(inst, 1)),
199 0xA1 => self.sknp_r(reg_at(inst, 1)),
200 _ => return Err(OpcodeError::new(inst, self.pc as u8)),
201 },
202 0xF000 => match inst & 0x00FF {
203 0x07 => self.ld_r_dt(reg_at(inst, 1)),
204 0x0A => self.ld_r_kp(reg_at(inst, 1)),
205 0x15 => self.ld_dt_r(reg_at(inst, 1)),
206 0x18 => self.ld_st_r(reg_at(inst, 1)),
207 0x1E => self.add_i_r(reg_at(inst, 1)),
208 0x29 => self.ld_i_spr_x(reg_at(inst, 1)),
209 0x33 => self.ld_bcd_r(reg_at(inst, 1)),
210 0x55 => self.store_at_i(reg_at(inst, 1)),
211 0x65 => self.load_from_i(reg_at(inst, 1)),
212 _ => return Err(OpcodeError::new(inst, self.pc as u8)),
213 },
214 _ => return Err(OpcodeError::new(inst, self.pc as u8)),
215 }
216 if self.debug_print {
217 println!("Post state:");
218 self.dump_state();
219 }
220 self.last_key_released = None;
221
222 return Ok(());
223 }
224
225 pub fn dump_state(&self) {
229 for i in 0..16 {
230 print!("V{:X} = {:#2X}, ", i, self.registers[i])
231 }
232 println!("");
233 println!("Stack: {:X?}", self.stack);
234 println!(
235 "PC = {:X?}, SP = {:X?}, I = {:X?}, DT = {:X?}, ST = {:X?}",
236 self.pc, self.sp, self.i, self.dt, self.st
237 );
238 print!("Memory:");
239 self.mem.iter().enumerate().for_each(|(i, v)| {
240 if i % 0x40 == 0 {
241 print!("\n{:03X}: ", i);
242 }
243 print!("{:02X?}", v);
244 });
245 println!("");
246 print!("Screen:");
247 self.screen_buffer.iter().enumerate().for_each(|(i, s)| {
248 if i % 64 == 0 {
249 println!("");
250 }
251 print!("{}", if *s { 1 } else { 0 });
252 });
253 println!("");
254 }
255
256 fn ld_r_kk(&mut self, r: usize, kk: u8) {
257 self.registers[r] = kk;
258 }
259
260 fn ld_rx_ry(&mut self, rx: usize, ry: usize) {
261 self.registers[rx] = self.registers[ry];
262 }
263
264 fn or_rx_ry(&mut self, rx: usize, ry: usize) {
265 self.registers[rx] = self.registers[rx] | self.registers[ry];
266 self.registers[0xF] = 0x0;
267 }
268
269 fn and_rx_ry(&mut self, rx: usize, ry: usize) {
270 self.registers[rx] = self.registers[rx] & self.registers[ry];
271 self.registers[0xF] = 0x0;
272 }
273
274 fn xor_rx_ry(&mut self, rx: usize, ry: usize) {
275 self.registers[rx] = self.registers[rx] ^ self.registers[ry];
276 self.registers[0xF] = 0x0;
277 }
278
279 fn add_rx_ry(&mut self, rx: usize, ry: usize) {
280 let v = self.registers[rx] as u16 + self.registers[ry] as u16;
281 self.registers[rx] = v as u8;
282 self.registers[0xF] = if v > 0xFF { 1 } else { 0 };
283 }
284 fn sub_rx_ry(&mut self, rx: usize, ry: usize) {
285 let vf = if self.registers[ry] > self.registers[rx] {
286 0
287 } else {
288 1
289 };
290 self.registers[rx] = self.registers[rx].wrapping_sub(self.registers[ry]);
291 self.registers[0xF] = vf;
292 }
293 fn shr(&mut self, rx: usize, ry: usize) {
294 let vf = if self.registers[ry] & 0x01 == 1 { 1 } else { 0 };
295 self.registers[rx] = self.registers[ry] >> 1;
296 self.registers[0xF] = vf;
297 }
298 fn subn(&mut self, rx: usize, ry: usize) {
299 let vf = if self.registers[rx] > self.registers[ry] {
300 0
301 } else {
302 1
303 };
304 self.registers[rx] = self.registers[ry].wrapping_sub(self.registers[rx]);
305 self.registers[0xF] = vf;
306 }
307 fn shl(&mut self, rx: usize, ry: usize) {
308 let vf = if self.registers[ry] & 0x80 == 0x80 {
309 1
310 } else {
311 0
312 };
313 self.registers[rx] = self.registers[ry] << 1;
314 self.registers[0xF] = vf;
315 }
316 fn clr(&mut self) {
317 self.screen_buffer = [false; SCREEN_WIDTH * SCREEN_HEIGHT];
318 }
319 fn ret(&mut self) {
320 self.sp -= 1;
321 self.pc = self.stack[self.sp] as usize;
322 }
323 fn jmp(&mut self, addr: u16) {
324 self.pc = (addr - 2) as usize;
326 }
327 fn jmp_r0(&mut self, addr: u16) {
328 self.pc = (addr + self.registers[0] as u16) as usize - 2;
329 }
330 fn call(&mut self, addr: u16) {
331 self.stack[self.sp] = self.pc as u16;
332 self.sp += 1;
333 self.pc = addr as usize - 2;
334 }
335 fn se_r_kk(&mut self, r: usize, kk: u8) {
336 if self.registers[r] == kk {
337 self.pc += 2;
338 }
339 }
340 fn se_rx_ry(&mut self, rx: usize, ry: usize) {
341 if self.registers[rx] == self.registers[ry] {
342 self.pc += 2;
343 }
344 }
345 fn sne_r_kk(&mut self, inst: u16) {
346 if self.registers[reg_at(inst, 1)] as u16 != inst & 0xFF {
347 self.pc += 2;
348 }
349 }
350 fn sne_rx_ry(&mut self, x: usize, y: usize) {
351 if self.registers[x] != self.registers[y] {
352 self.pc += 2;
353 }
354 }
355 fn skp_r(&mut self, x: usize) {
356 if self.input_state[self.registers[x] as usize] {
357 self.pc += 2;
358 }
359 }
360 fn sknp_r(&mut self, x: usize) {
361 if !self.input_state[self.registers[x] as usize] {
362 self.pc += 2;
363 }
364 }
365 fn ld_r_kp(&mut self, r: usize) {
366 match self.last_key_released {
367 Some(i) => self.registers[r] = i as u8,
368 None => self.pc -= 2,
371 }
372 }
373 fn ld_i(&mut self, addr: u16) {
374 self.i = addr;
375 }
376 fn load_from_i(&mut self, n: usize) {
377 for j in 0..(n + 1) {
378 self.registers[j as usize] = self.mem[(self.i + j as u16) as usize];
379 }
380 self.i += (n + 1) as u16;
381 }
382 fn store_at_i(&mut self, n: usize) {
383 for j in 0..(n + 1) {
384 self.mem[(self.i + j as u16) as usize] = self.registers[j as usize];
385 }
386 self.i += (n + 1) as u16;
387 }
388 fn add_i_r(&mut self, r: usize) {
389 self.i = self.i.wrapping_add(self.registers[r] as u16);
390 }
391 fn add_r_kk(&mut self, r: usize, kk: u8) {
392 self.registers[r] = self.registers[r].wrapping_add(kk);
393 }
394 fn rand(&mut self, r: usize, mask: u16) {
395 self.registers[r] = (rand::thread_rng().gen_range(0..0xFF) & mask) as u8;
396 }
397 fn ld_st_r(&mut self, r: usize) {
398 self.st = self.registers[r];
399 }
400 fn ld_dt_r(&mut self, x: usize) {
401 self.dt = self.registers[x];
402 }
403 fn ld_r_dt(&mut self, x: usize) {
404 self.registers[x] = self.dt;
405 }
406 fn draw(&mut self, rx: usize, ry: usize, n: usize) {
407 if !self.vblank {
408 self.pc -= 2;
409 return;
410 }
411 self.vblank = false;
412 self.registers[0xF] = 0;
413 let x = self.registers[rx] % SCREEN_WIDTH as u8;
414 let y = self.registers[ry] % SCREEN_HEIGHT as u8;
415 for j in 0..n {
417 let mut val = self.mem[self.i as usize + j];
418 for k in 0..8 {
419 if x as usize + k >= SCREEN_WIDTH || y as usize + j >= SCREEN_HEIGHT {
420 continue;
421 }
422 let coord: usize = (y as usize + j) * SCREEN_WIDTH + x as usize + k;
423 let p = (val & 0x80) != 0; if p && self.screen_buffer[coord] {
425 self.registers[0xF] = 1;
426 }
427 self.screen_buffer[coord] = p ^ self.screen_buffer[coord];
428 val = val << 1;
429 }
430 }
431 }
432 fn ld_i_spr_x(&mut self, r: usize) {
434 self.i = (self.registers[r] as u16 & 0xF) * 0x6;
437 }
438 fn ld_bcd_r(&mut self, r: usize) {
439 self.mem[self.i as usize] = self.registers[r] / 100;
440 self.mem[self.i as usize + 1] = (self.registers[r] / 10) % 10;
441 self.mem[self.i as usize + 2] = self.registers[r] % 10;
442 }
443
444 pub fn get_register_value(&self, register: u8) -> u8 {
446 return self.registers[register as usize];
447 }
448 pub fn get_program_counter(&self) -> usize {
450 return self.pc;
451 }
452 pub fn get_i(&self) -> u16 {
454 return self.i;
455 }
456 pub fn get_mem_at(&self, addr: usize) -> u8 {
458 return self.mem[addr];
459 }
460 pub fn get_pixel_at(&self, x: u8, y: u8) -> bool {
465 return self.screen_buffer
466 [((x as usize % 64) + y as usize * 64) % self.screen_buffer.len()];
467 }
468 pub fn get_input_state(&self, i: usize) -> bool {
473 return self.input_state[i];
474 }
475 pub fn get_dt(&self) -> u8 {
477 return self.dt;
478 }
479 pub fn get_st(&self) -> u8 {
481 return self.st;
482 }
483 pub fn on_v_blank(&mut self) {
487 self.vblank = true;
488 }
489}
490
491fn reg_at(inst: u16, pos: u8) -> usize {
495 return ((inst >> (12 - pos * 4)) & 0x000F) as usize;
496}