From 92229e3d93bc6384f8dc851673194c41135d31f0 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Wed, 13 Oct 2021 20:50:48 -0500 Subject: [PATCH] JP u16 instruction --- src/console.rs | 9 ++++++++- src/cpu.rs | 48 ++++++++++++++++++++++++++++++++++++++---------- src/utils.rs | 10 ++++++++++ 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/console.rs b/src/console.rs index 2161cce..d22e5f5 100644 --- a/src/console.rs +++ b/src/console.rs @@ -1,3 +1,5 @@ +use std::{thread, time}; + use crate::cpu::CPU; use crate::ppu::PPU; use crate::bus::Bus; @@ -18,6 +20,11 @@ impl Console { } pub fn cpu_run(&mut self) { - self.cpu.run(&mut self.bus); + let mut exit = false; + while !exit { + self.cpu.run(&mut self.bus); + + thread::sleep(time::Duration::from_millis(100)); + } } } diff --git a/src/cpu.rs b/src/cpu.rs index 07c0b47..5cd0db6 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,6 +1,7 @@ -use crate::utils::{BitIndex, get_bit, set_bit}; +use crate::utils::{BitIndex, get_bit, set_bit, join_bytes}; use crate::bus::Bus; +#[derive(Debug)] pub enum Register { A(u8), // Accumulator F(u8), // Flags @@ -20,6 +21,7 @@ pub enum Register { PC(u16), // Program counter } +#[derive(Debug)] pub enum FlagRegister { Zero(bool), // Set when the result of a math operation is zero or if two values matches using the CP instruction Substract(bool), // Set if a substraction was performed in the last math instruction @@ -117,19 +119,19 @@ impl Registers { } fn get_af(&self) -> u16 { - ((self.a as u16) << 8) | (self.f as u16) + join_bytes(self.a, self.f) } fn get_bc(&self) -> u16 { - ((self.b as u16) << 8) | (self.c as u16) + join_bytes(self.b, self.c) } fn get_de(&self) -> u16 { - ((self.d as u16) << 8) | (self.e as u16) + join_bytes(self.d, self.e) } fn get_hl(&self) -> u16 { - ((self.h as u16) << 8) | (self.l as u16) + join_bytes(self.h, self.l) } fn set_af(&mut self, val: u16) { @@ -157,6 +159,7 @@ impl Registers { } } +#[derive(Debug)] pub enum OpcodeParameter { Register(Register), Register_U8(Register), @@ -197,6 +200,7 @@ pub enum OpcodeParameter { NoParam, } +#[derive(Debug)] pub enum CpuOpcode { LD(OpcodeParameter), LDD(OpcodeParameter), @@ -266,17 +270,35 @@ impl CPU { } pub fn run(&mut self, bus: &mut Bus) { - println!("Opcode: {:02X}", bus.read(self.registers.get(Register::PC(0)))); + let program_counter = self.registers.get(Register::PC(0)); + let byte_read = bus.read(program_counter); + let opcode = CPU::parse_opcode(byte_read, program_counter, bus); + self.exec(opcode, bus); } - pub fn exec(&mut self, opcode: CpuOpcode) { + pub fn exec(&mut self, opcode: CpuOpcode, bus: &mut Bus) { + println!("Executing {:?}", opcode); + println!("Current PC{:?}", self.registers.get(Register::PC(0))); match opcode { + CpuOpcode::JP(params) => match params { + OpcodeParameter::U16(address) => self.registers.set(Register::PC(address)), + _ => {}, + }, CpuOpcode::NOP => self.registers.increment_pc(), _ => println!("Illegal instruction"), }; } - pub fn parse_opcode(opcode: u8) -> CpuOpcode { + fn read_parameter_bytes(address: u16, bus: &Bus) -> [u8; 3] { + [ + bus.read(address), + bus.read(address + 1), + bus.read(address + 2), + ] + } + + pub fn parse_opcode(opcode: u8, address: u16, bus: &Bus) -> CpuOpcode { + let params = CPU::read_parameter_bytes(address, &bus); match opcode { 0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))), 0x0E => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::C(0))), @@ -499,7 +521,7 @@ impl CPU { //0xCB => CpuOpcode::BIT, //0xCB => CpuOpcode::SET, //0xCB => CpuOpcode::RES, - 0xC3 => CpuOpcode::JP(OpcodeParameter::U16(0)), + 0xC3 => CpuOpcode::JP(OpcodeParameter::U16(join_bytes(params[1], params[2]))), 0xC2 => CpuOpcode::JP(OpcodeParameter::FlagRegisterReset_U16(FlagRegister::Zero(true), 0)), 0xCA => CpuOpcode::JP(OpcodeParameter::FlagRegisterSet_U16(FlagRegister::Zero(true), 0)), 0xD2 => CpuOpcode::JP(OpcodeParameter::FlagRegisterReset_U16(FlagRegister::Carry(true), 0)), @@ -600,7 +622,13 @@ mod tests { #[test] fn test_cpu_instructions() { let mut cpu = CPU::new(); - cpu.exec(CpuOpcode::NOP); + let mut bus = Bus::new(); + cpu.exec(CpuOpcode::NOP, &mut bus); assert_eq!(cpu.registers.get(Register::PC(0)), 0x101); + + let mut cpu = CPU::new(); + let mut bus = Bus::new(); + cpu.exec(CpuOpcode::JP(OpcodeParameter::U16(0x1F1F)), &mut bus); + assert_eq!(cpu.registers.get(Register::PC(0)), 0x1F1F); } } diff --git a/src/utils.rs b/src/utils.rs index 77a2d7f..719feaa 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -33,6 +33,10 @@ pub fn set_bit(byte: u8, value: bool, index: BitIndex) -> u8 { } } +pub fn join_bytes(byte1: u8, byte2: u8) -> u16 { + ((byte1 as u16) << 8) | (byte2 as u16) +} + #[cfg(test)] mod tests { use super::*; @@ -84,4 +88,10 @@ mod tests { assert_eq!(get_bit(0b10111111, BitIndex::I6), false); assert_eq!(get_bit(0b01111111, BitIndex::I7), false); } + + #[test] + fn test_join_two_bytes() { + assert_eq!(join_bytes(0b10101010, 0b11111111), 0b1010101011111111); + assert_eq!(join_bytes(0b11111111, 0b10101010), 0b1111111110101010); + } }