Skip to content

Commit

Permalink
cpu: add more instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
choffmann committed May 18, 2024
1 parent 95e596f commit 31af5a1
Show file tree
Hide file tree
Showing 4 changed files with 453 additions and 0 deletions.
18 changes: 18 additions & 0 deletions gameboy-lib/src/cpu/command/misc_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,31 @@ impl<'a> MiscCommand<'a> {

return pc;
}

fn ccf(&mut self) -> u16 {
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = !self.cpu.registers.f.carry;

self.cpu.pc.wrapping_add(1)
}

fn scf(&mut self) -> u16 {
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = true;

self.cpu.pc.wrapping_add(1)
}
}

impl Command for MiscCommand<'_> {
fn execute(&mut self) -> u16 {
match &self.instruction {
MiscInstruction::Nop => self.nop(),
MiscInstruction::Swap(from) => self.swap(from),
MiscInstruction::CCF => self.ccf(),
MiscInstruction::SCF => self.scf(),
_ => unimplemented!(),
}
}
Expand Down
3 changes: 3 additions & 0 deletions gameboy-lib/src/cpu/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::{instructions::Instruction, Cpu};
pub mod alu_commands;
pub mod load_commands;
pub mod misc_commands;
pub mod rotate_commands;

pub trait Command {
fn execute(&mut self) -> u16;
Expand Down Expand Up @@ -32,13 +33,15 @@ impl<'a> CommandFactory<'a> {
Instruction::Load(load_command) => Box::new(LoadCommand::new(load_command, self.cpu)),
Instruction::Arithmetic(alu_command) => Box::new(ArithmeticCommand::new(alu_command, self.cpu)),
Instruction::Misc(misc_command) => Box::new(misc_commands::MiscCommand::new(&misc_command, self.cpu)),
Instruction::Rotate(rotate_command) => Box::new(rotate_commands::RotateCommand::new(rotate_command, self.cpu)),
_ => unimplemented!(),
}
}

fn prefix_command(&'a mut self, instruction: &'a Instruction) -> Box<dyn Command + 'a> {
match instruction {
Instruction::Misc(misc_command) => Box::new(misc_commands::MiscCommand::new(&misc_command, self.cpu)),
Instruction::Rotate(rotate_command) => Box::new(rotate_commands::RotateCommand::new(rotate_command, self.cpu)),
_ => unimplemented!(),
}
}
Expand Down
229 changes: 229 additions & 0 deletions gameboy-lib/src/cpu/command/rotate_commands.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
use crate::cpu::{instructions::RotateInstruction, registers::Register, Cpu};

use super::Command;


pub struct RotateCommand<'a> {
instruction: &'a RotateInstruction,
cpu: &'a mut Cpu,
}

impl<'a> RotateCommand<'a> {
pub fn new(instruction: &'a RotateInstruction, cpu: &'a mut Cpu) -> RotateCommand<'a> {
RotateCommand { instruction, cpu }
}

fn rlca(&mut self) -> u16 {
let value = self.cpu.registers.a;
let carry = value >> 7;
let result = (value << 1) | carry;

self.cpu.registers.a = result;
self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

self.cpu.pc.wrapping_add(1)
}

fn rla(&mut self) -> u16 {
let value = self.cpu.registers.a;
let carry = value >> 7;
let result = (value << 1) | self.cpu.registers.f.carry as u8;

self.cpu.registers.a = result;
self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

self.cpu.pc.wrapping_add(1)
}

fn rrca(&mut self) -> u16 {
let value = self.cpu.registers.a;
let carry = value & 1;
let result = (value >> 1) | (carry << 7);

self.cpu.registers.a = result;
self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

self.cpu.pc.wrapping_add(1)
}

fn rra(&mut self) -> u16 {
let value = self.cpu.registers.a;
let carry = value & 1;
let result = (value >> 1) | ((self.cpu.registers.f.carry as u8) << 7);

self.cpu.registers.a = result;
self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

self.cpu.pc.wrapping_add(1)
}

fn rlc(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value >> 7;
let result = (value << 1) | carry;

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn rl(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value >> 7;
let result = (value << 1) | self.cpu.registers.f.carry as u8;

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn rrc(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value & 1;
let result = (value >> 1) | (carry << 7);

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn rr(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value & 1;
let result = (value >> 1) | ((self.cpu.registers.f.carry as u8) << 7);

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn sla(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value >> 7;
let result = value << 1;

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn sra(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value & 1;
let result = (value >> 1) | (value & 0x80);

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}

fn srl(&mut self, register: &Register) -> u16 {
let (value, pc) = self.cpu.extract_operand(register);
let carry = value & 1;
let result = value >> 1;

if let Register::HL = register {
self.cpu.memory
.write(self.cpu.registers.get_16(&Register::HL), result);
} else {
self.cpu.registers.set(register, result);
}

self.cpu.registers.f.zero = result == 0;
self.cpu.registers.f.subtract = false;
self.cpu.registers.f.half_carry = false;
self.cpu.registers.f.carry = carry == 1;

return pc;
}
}

impl Command for RotateCommand<'_> {
fn execute(&mut self) -> u16 {
match &self.instruction {
RotateInstruction::RLCA => self.rlca(),
RotateInstruction::RLA => self.rla(),
RotateInstruction::RRCA => self.rrca(),
RotateInstruction::RRA => self.rra(),
RotateInstruction::RLC(register) => self.rlc(register),
RotateInstruction::RL(register) => self.rl(register),
RotateInstruction::RRC(register) => self.rrc(register),
RotateInstruction::RR(register) => self.rr(register),
RotateInstruction::SLA(register) => self.sla(register),
RotateInstruction::SRA(register) => self.sra(register),
RotateInstruction::SRL(register) => self.srl(register),
}
}
}
Loading

0 comments on commit 31af5a1

Please sign in to comment.