JP u16 instruction

This commit is contained in:
Franco Colmenarez 2021-10-13 20:50:48 -05:00
parent 5d04b7c346
commit 92229e3d93
3 changed files with 56 additions and 11 deletions

View File

@ -1,3 +1,5 @@
use std::{thread, time};
use crate::cpu::CPU; use crate::cpu::CPU;
use crate::ppu::PPU; use crate::ppu::PPU;
use crate::bus::Bus; use crate::bus::Bus;
@ -18,6 +20,11 @@ impl Console {
} }
pub fn cpu_run(&mut self) { 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));
}
} }
} }

View File

@ -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; use crate::bus::Bus;
#[derive(Debug)]
pub enum Register { pub enum Register {
A(u8), // Accumulator A(u8), // Accumulator
F(u8), // Flags F(u8), // Flags
@ -20,6 +21,7 @@ pub enum Register {
PC(u16), // Program counter PC(u16), // Program counter
} }
#[derive(Debug)]
pub enum FlagRegister { pub enum FlagRegister {
Zero(bool), // Set when the result of a math operation is zero or if two values matches using the CP instruction 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 Substract(bool), // Set if a substraction was performed in the last math instruction
@ -117,19 +119,19 @@ impl Registers {
} }
fn get_af(&self) -> u16 { 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 { 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 { 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 { 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) { fn set_af(&mut self, val: u16) {
@ -157,6 +159,7 @@ impl Registers {
} }
} }
#[derive(Debug)]
pub enum OpcodeParameter { pub enum OpcodeParameter {
Register(Register), Register(Register),
Register_U8(Register), Register_U8(Register),
@ -197,6 +200,7 @@ pub enum OpcodeParameter {
NoParam, NoParam,
} }
#[derive(Debug)]
pub enum CpuOpcode { pub enum CpuOpcode {
LD(OpcodeParameter), LD(OpcodeParameter),
LDD(OpcodeParameter), LDD(OpcodeParameter),
@ -266,17 +270,35 @@ impl CPU {
} }
pub fn run(&mut self, bus: &mut Bus) { 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 { match opcode {
CpuOpcode::JP(params) => match params {
OpcodeParameter::U16(address) => self.registers.set(Register::PC(address)),
_ => {},
},
CpuOpcode::NOP => self.registers.increment_pc(), CpuOpcode::NOP => self.registers.increment_pc(),
_ => println!("Illegal instruction"), _ => 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 { match opcode {
0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))), 0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))),
0x0E => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::C(0))), 0x0E => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::C(0))),
@ -499,7 +521,7 @@ impl CPU {
//0xCB => CpuOpcode::BIT, //0xCB => CpuOpcode::BIT,
//0xCB => CpuOpcode::SET, //0xCB => CpuOpcode::SET,
//0xCB => CpuOpcode::RES, //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)), 0xC2 => CpuOpcode::JP(OpcodeParameter::FlagRegisterReset_U16(FlagRegister::Zero(true), 0)),
0xCA => CpuOpcode::JP(OpcodeParameter::FlagRegisterSet_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)), 0xD2 => CpuOpcode::JP(OpcodeParameter::FlagRegisterReset_U16(FlagRegister::Carry(true), 0)),
@ -600,7 +622,13 @@ mod tests {
#[test] #[test]
fn test_cpu_instructions() { fn test_cpu_instructions() {
let mut cpu = CPU::new(); 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); 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);
} }
} }

View File

@ -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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -84,4 +88,10 @@ mod tests {
assert_eq!(get_bit(0b10111111, BitIndex::I6), false); assert_eq!(get_bit(0b10111111, BitIndex::I6), false);
assert_eq!(get_bit(0b01111111, BitIndex::I7), 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);
}
} }