From bc56fca299f6320f36fb1be83c1bdff2f4a06452 Mon Sep 17 00:00:00 2001 From: Denis Nutiu Date: Wed, 4 Dec 2024 22:34:19 +0200 Subject: [PATCH] implement Jump, SetRegister, AddValueToRegister --- src/emulator.rs | 22 ++++++++++++++++++---- src/instruction.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/src/emulator.rs b/src/emulator.rs index c904803..bc61e26 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -2,7 +2,7 @@ use crate::display::Display; use crate::instruction::{Instruction, ProcessorInstruction}; use crate::stack::Stack; use anyhow::anyhow; -use log::{debug, info, warn}; +use log::{debug, info, trace, warn}; use std::fs::File; use std::io::Read; use std::path::Path; @@ -98,12 +98,17 @@ where /// Emulation loop executes the fetch -> decode -> execute pipeline fn emulation_loop(&mut self) -> Result<(), anyhow::Error> { + let mut last_program_counter = self.program_counter; loop { // fetch instruction let instruction = self.fetch_instruction()?; self.program_counter += 2; - debug!("PC={} {:04x}", self.program_counter, instruction); + if last_program_counter != self.program_counter { + debug!("PC={} {:04x}", self.program_counter, instruction); + } + last_program_counter = self.program_counter; + // decode & execute self.execute_instruction(instruction)?; @@ -114,11 +119,20 @@ where fn execute_instruction(&mut self, instruction: Instruction) -> Result<(), anyhow::Error> { match instruction.processor_instruction() { ProcessorInstruction::ClearScreen => { - info!("clear display"); + trace!("Clear display"); self.display.clear() } ProcessorInstruction::Jump(address) => { - todo!("implement jump") + trace!("Jump to address {:04x}", address); + self.program_counter = address + } + ProcessorInstruction::SetRegister(register, data) => { + trace!("Set register {} to data {:04x}", register, data); + self.registers[register] = data + } + ProcessorInstruction::AddValueToRegister(register, data) => { + trace!("Add to register {} data {:04x}", register, data); + self.registers[register] += data } ProcessorInstruction::UnknownInstruction => { warn!("Unknown instruction: {:04x}, skipping.", instruction); diff --git a/src/instruction.rs b/src/instruction.rs index bcf0c6e..32f2af1 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -1,5 +1,17 @@ use std::fmt; use std::fmt::{Display, Formatter, LowerHex}; +use log::info; +/* +Although every instruction will have a first nibble that tells you what kind of instruction it is, +the rest of the nibbles will have different meanings. To differentiate these meanings, +we usually call them different things, but all of them can be any hexadecimal number from 0 to F: + + X: The second nibble. Used to look up one of the 16 registers (VX) from V0 through VF. + Y: The third nibble. Also used to look up one of the 16 registers (VY) from V0 through VF. + N: The fourth nibble. A 4-bit number. + NN: The second byte (third and fourth nibbles). An 8-bit immediate number. + NNN: The second, third and fourth nibbles. A 12-bit immediate memory address. + */ #[derive(Debug, Clone, Copy)] pub enum ProcessorInstruction { @@ -7,6 +19,10 @@ pub enum ProcessorInstruction { ClearScreen, /// Jumps to a given address Jump(u16), + /// Sets the register in the first argument to the given value + SetRegister(usize, u8), + /// Adds the value to the register + AddValueToRegister(usize, u8), UnknownInstruction } @@ -44,7 +60,17 @@ impl Instruction { } // Jump 0x1000..=0x1FFF => { - ProcessorInstruction::Jump(data & 0xFFF) + // 1NNN + ProcessorInstruction::Jump(Self::grab_inner_data(data)) + } + // Set Register + 0x6000..=0x6FFF => { + // 6XNN + ProcessorInstruction::SetRegister(Self::grab_first_nibble(data), Self::grab_last_byte(data)) + } + 0x7000..0x7FFF => { + // 7XNN + ProcessorInstruction::AddValueToRegister(Self::grab_first_nibble(data), Self::grab_last_byte(data)) } // Unknown instruction _ => { @@ -53,7 +79,20 @@ impl Instruction { } } + /// Grabs the inner data from the data, ignores the opcode. + fn grab_inner_data(data: u16) -> u16 { + data & 0x0FFF + } + /// Grabs the last byte from the data. + fn grab_last_byte(data: u16) -> u8 { + (data & 0x00FF) as u8 + } + + /// Grabs the first nibble from the data. + fn grab_first_nibble(data: u16) -> usize { + ((data & 0x0F00) >> 8) as usize + } } impl Display for Instruction {