diff options
| author | Samuel Perrouault <samuel.perrouault@gmail.com> | 2025-03-26 11:10:08 +0100 |
|---|---|---|
| committer | Samuel Perrouault <samuel.perrouault@gmail.com> | 2025-03-26 11:12:20 +0100 |
| commit | 1782b338364149bef81871fcb8418db7ab6d18fb (patch) | |
| tree | f2a67ba87a0f9c99a069f96b6f7db687bb0ec16b | |
| parent | 4f2d873f58709a3ba7d39905f95f333f71dcd552 (diff) | |
handle ADD instruction
| -rw-r--r-- | Readme.md | 2 | ||||
| -rw-r--r-- | src/chip8.rs | 295 |
2 files changed, 152 insertions, 145 deletions
@@ -1 +1 @@ -Following along on https://multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
+Following along on https://multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/ diff --git a/src/chip8.rs b/src/chip8.rs index 50b5c12..e372367 100644 --- a/src/chip8.rs +++ b/src/chip8.rs @@ -1,144 +1,151 @@ -use std::io::Read;
-use std::io::Write;
-
-const WIDTH: u16 = 64;
-const HEIGHT: u16 = 32;
-const PIXELS: usize = (WIDTH * HEIGHT) as usize;
-
-fn unknown_opcode(opcode: u16) {
- eprintln!("Unknwown opcode {:#06x}", opcode);
- std::process::exit(1);
-}
-
-pub struct Chip8 {
- v: [u8; 4096],
- i: u16,
- pc: u16,
- stack: [u16; 16],
- sp: u16,
- memory: [u8; 4096],
- screen: [u8; PIXELS],
- delay_timer: u8,
- sound_timer: u8,
- key: [u8; 16],
- draw: bool,
-}
-
-impl Chip8 {
- pub fn new() -> Self {
- return Self {
- v: [0; 4096],
- i: 0,
- pc: 0x200,
- stack: [0; 16],
- sp: 0,
- memory: [0; 4096],
- screen: [0; PIXELS],
- delay_timer: 0,
- sound_timer: 0,
- key: [0; 16],
- draw: false,
- };
- }
-
- pub fn load_rom<R: Read>(&mut self, mut reader: R) -> std::io::Result<()> {
- reader.read(&mut self.memory[0x200..])?;
- Ok(())
- }
-
- pub fn cycle(&mut self) {
- let pc = self.pc as usize;
- let opcode = (self.memory[pc] as u16) << 8 | self.memory[pc + 1] as u16;
- match opcode & 0xF000 {
- 0x0000 => match opcode & 0x000F {
- 0x0000 => {
- eprintln!("CLS");
- self.screen = [0; PIXELS];
- self.draw = true;
- self.pc += 2;
- }
- 0x000E => {
- eprintln!("RET");
- self.pc += 2;
- }
- _ => unknown_opcode(opcode),
- },
- 0x6000 => {
- let x = (opcode & 0x0F00) >> 8;
- let value = opcode & 0x00FF;
- eprintln!("LD V{}, {}", x, value);
- self.v[x as usize] = value as u8;
- self.pc += 2;
- }
- 0xA000 => {
- self.i = opcode & 0x0FFF;
- self.pc += 2;
- eprintln!("LD I, {}", self.i);
- }
- 0xD000 => {
- let x = (opcode & 0x0F00) >> 8;
- let y = (opcode & 0x00F0) >> 4;
- let nibble = opcode & 0x000F;
- eprintln!("DRW V{}, V{}, {}", x, y, nibble);
- self.v[0xF] = 0;
- for yy in 0..nibble {
- let pixel = self.memory[(self.i + yy) as usize];
- for xx in 0..8 {
- if (pixel & (0x80 >> xx)) != 0 {
- let si = x + xx + ((y + yy) * WIDTH);
- if self.screen[si as usize] == 1 {
- self.v[0xF] = 1;
- }
- self.screen[si as usize] ^= 1;
- }
- }
- }
- self.draw = true;
- self.pc += 2;
- }
- _ => unknown_opcode(opcode),
- };
-
- if self.delay_timer > 0 {
- self.delay_timer -= 1;
- }
-
- if self.sound_timer > 0 {
- if self.sound_timer == 1 {
- eprintln!("BEEP");
- }
- self.sound_timer -= 1;
- }
- }
-
- pub fn display(&mut self) -> std::io::Result<()> {
- if self.draw {
- self.draw = false;
- self.draw()
- } else {
- Ok(())
- }
- }
-
- fn draw(&self) -> std::io::Result<()> {
- let lines: String = std::iter::once("\x1B[2J\n")
- .chain((0..HEIGHT).flat_map(|y| {
- (0..WIDTH)
- .map(move |x| {
- let si = x + y * WIDTH;
- if self.screen[si as usize] == 0 {
- "░"
- } else {
- "█"
- }
- })
- .chain(std::iter::once("\n"))
- }))
- .collect();
-
- let stdout = std::io::stdout();
- let mut handle = stdout.lock();
- handle.write_all(lines.as_bytes())?;
- handle.flush()
- }
-}
+use std::io::Read; +use std::io::Write; + +const WIDTH: u16 = 64; +const HEIGHT: u16 = 32; +const PIXELS: usize = (WIDTH * HEIGHT) as usize; + +fn unknown_opcode(opcode: u16) { + eprintln!("Unknwown opcode {:#06x}", opcode); + std::process::exit(1); +} + +pub struct Chip8 { + v: [u8; 4096], + i: u16, + pc: u16, + stack: [u16; 16], + sp: u16, + memory: [u8; 4096], + screen: [u8; PIXELS], + delay_timer: u8, + sound_timer: u8, + key: [u8; 16], + draw: bool, +} + +impl Chip8 { + pub fn new() -> Self { + return Self { + v: [0; 4096], + i: 0, + pc: 0x200, + stack: [0; 16], + sp: 0, + memory: [0; 4096], + screen: [0; PIXELS], + delay_timer: 0, + sound_timer: 0, + key: [0; 16], + draw: false, + }; + } + + pub fn load_rom<R: Read>(&mut self, mut reader: R) -> std::io::Result<()> { + reader.read(&mut self.memory[0x200..])?; + Ok(()) + } + + pub fn cycle(&mut self) { + let pc = self.pc as usize; + let opcode = (self.memory[pc] as u16) << 8 | self.memory[pc + 1] as u16; + match opcode & 0xF000 { + 0x0000 => match opcode & 0x000F { + 0x0000 => { + eprintln!("CLS"); + self.screen = [0; PIXELS]; + self.draw = true; + self.pc += 2; + } + 0x000E => { + eprintln!("RET"); + self.pc += 2; + } + _ => unknown_opcode(opcode), + }, + 0x6000 => { + let x = (opcode & 0x0F00) >> 8; + let value = opcode & 0x00FF; + eprintln!("LD V{}, {}", x, value); + self.v[x as usize] = value as u8; + self.pc += 2; + } + 0x7000 => { + let x = (opcode & 0x0F00) >> 8; + let value = opcode & 0x00FF; + eprintln!("ADD V{}, {}", x, value); + self.v[x as usize] += value as u8; + self.pc += 2; + } + 0xA000 => { + self.i = opcode & 0x0FFF; + self.pc += 2; + eprintln!("LD I, {}", self.i); + } + 0xD000 => { + let x = (opcode & 0x0F00) >> 8; + let y = (opcode & 0x00F0) >> 4; + let nibble = opcode & 0x000F; + eprintln!("DRW V{}, V{}, {}", x, y, nibble); + self.v[0xF] = 0; + for yy in 0..nibble { + let pixel = self.memory[(self.i + yy) as usize]; + for xx in 0..8 { + if (pixel & (0x80 >> xx)) != 0 { + let si = x + xx + ((y + yy) * WIDTH); + if self.screen[si as usize] == 1 { + self.v[0xF] = 1; + } + self.screen[si as usize] ^= 1; + } + } + } + self.draw = true; + self.pc += 2; + } + _ => unknown_opcode(opcode), + }; + + if self.delay_timer > 0 { + self.delay_timer -= 1; + } + + if self.sound_timer > 0 { + if self.sound_timer == 1 { + eprintln!("BEEP"); + } + self.sound_timer -= 1; + } + } + + pub fn display(&mut self) -> std::io::Result<()> { + if self.draw { + self.draw = false; + self.draw() + } else { + Ok(()) + } + } + + fn draw(&self) -> std::io::Result<()> { + let lines: String = std::iter::once("\x1B[2J\n") + .chain((0..HEIGHT).flat_map(|y| { + (0..WIDTH) + .map(move |x| { + let si = x + y * WIDTH; + if self.screen[si as usize] == 0 { + "░" + } else { + "█" + } + }) + .chain(std::iter::once("\n")) + })) + .collect(); + + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(lines.as_bytes())?; + handle.flush() + } +} |
