Implement CPU Instructions
This commit is contained in:
parent
21b7f82422
commit
0be0030ed7
31
src/cpu.rs
31
src/cpu.rs
|
@ -6,25 +6,23 @@ pub struct Cpu {
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
ime: bool,
|
ime: bool,
|
||||||
state: State,
|
state: State,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub fn fetch(&self) -> u8 {
|
fn fetch(&self) -> u8 {
|
||||||
self.bus.read_byte(self.reg.pc)
|
self.bus.read_byte(self.reg.pc)
|
||||||
// TODO: Figure out where to increment the program counter.
|
// TODO: Figure out where to increment the program counter.
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(&self, opcode: u8) -> Instruction {
|
fn decode(&self, opcode: u8) -> Instruction {
|
||||||
Instruction::from_byte(self, opcode)
|
Instruction::from_byte(self, opcode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&mut self, instruction: Instruction) {
|
fn execute(&mut self, instruction: Instruction) {
|
||||||
unimplemented!()
|
Instruction::execute(self, instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub fn read_byte(&self, address: u16) -> u8 {
|
pub fn read_byte(&self, address: u16) -> u8 {
|
||||||
self.bus.read_byte(address)
|
self.bus.read_byte(address)
|
||||||
|
@ -49,7 +47,6 @@ enum State {
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub fn set_register(&mut self, register: Register, value: u8) {
|
pub fn set_register(&mut self, register: Register, value: u8) {
|
||||||
match register {
|
match register {
|
||||||
|
@ -60,7 +57,7 @@ impl Cpu {
|
||||||
Register::E => self.reg.e = value,
|
Register::E => self.reg.e = value,
|
||||||
Register::H => self.reg.h = value,
|
Register::H => self.reg.h = value,
|
||||||
Register::L => self.reg.l = value,
|
Register::L => self.reg.l = value,
|
||||||
Register::Flags => self.reg.a = value.into()
|
Register::Flags => self.reg.a = value.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +70,7 @@ impl Cpu {
|
||||||
Register::E => self.reg.e,
|
Register::E => self.reg.e,
|
||||||
Register::H => self.reg.h,
|
Register::H => self.reg.h,
|
||||||
Register::L => self.reg.l,
|
Register::L => self.reg.l,
|
||||||
Register::Flags => self.flags.into()
|
Register::Flags => self.flags.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +88,7 @@ impl Cpu {
|
||||||
pub fn set_register_pair(&mut self, pair: RegisterPair, value: u16) {
|
pub fn set_register_pair(&mut self, pair: RegisterPair, value: u16) {
|
||||||
let high = (value >> 8) as u8;
|
let high = (value >> 8) as u8;
|
||||||
let low = value as u8;
|
let low = value as u8;
|
||||||
|
|
||||||
match pair {
|
match pair {
|
||||||
RegisterPair::AF => {
|
RegisterPair::AF => {
|
||||||
self.reg.a = high;
|
self.reg.a = high;
|
||||||
|
@ -115,8 +112,6 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub enum Register {
|
pub enum Register {
|
||||||
A,
|
A,
|
||||||
B,
|
B,
|
||||||
|
@ -137,7 +132,6 @@ pub enum RegisterPair {
|
||||||
PC,
|
PC,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
a: u8,
|
a: u8,
|
||||||
b: u8,
|
b: u8,
|
||||||
|
@ -150,13 +144,12 @@ struct Registers {
|
||||||
pc: u16,
|
pc: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
struct Flags {
|
pub struct Flags {
|
||||||
z: bool, // Zero Flag
|
pub z: bool, // Zero Flag
|
||||||
n: bool, // Negative Flag
|
pub n: bool, // Negative Flag
|
||||||
h: bool, // Half-Carry Flag
|
pub h: bool, // Half-Carry Flag
|
||||||
c: bool, // Carry Flag
|
pub c: bool, // Carry Flag
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for Flags {
|
impl From<u8> for Flags {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::cpu::{Cpu, RegisterPair};
|
use super::cpu::{Cpu, Flags, Register, RegisterPair};
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
NOP,
|
NOP,
|
||||||
LD(LDTarget, LDTarget),
|
LD(LDTarget, LDTarget),
|
||||||
|
@ -35,6 +35,432 @@ pub enum Instruction {
|
||||||
RST(u8),
|
RST(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Cycles(u8);
|
||||||
|
|
||||||
|
impl Instruction {
|
||||||
|
pub fn execute(cpu: &mut Cpu, instruction: Self) -> Cycles {
|
||||||
|
match instruction {
|
||||||
|
Instruction::NOP => Cycles(4),
|
||||||
|
Instruction::LD(lhs, rhs) => match (lhs, rhs) {
|
||||||
|
(LDTarget::ByteAtAddress(nn), LDTarget::RegisterPair(RegisterPair::SP)) => {
|
||||||
|
// LD (nn), SP | Put Stack Pointer at address nn
|
||||||
|
cpu.write_word(nn, cpu.register_pair(RegisterPair::SP));
|
||||||
|
Cycles(20)
|
||||||
|
}
|
||||||
|
(LDTarget::RegisterPair(pairs), LDTarget::ImmediateWord(nn)) => {
|
||||||
|
// LD rp[p], nn | Put value nn into register pair
|
||||||
|
match pairs {
|
||||||
|
RegisterPair::BC => cpu.set_register_pair(RegisterPair::BC, nn),
|
||||||
|
RegisterPair::DE => cpu.set_register_pair(RegisterPair::DE, nn),
|
||||||
|
RegisterPair::HL => cpu.set_register_pair(RegisterPair::HL, nn),
|
||||||
|
RegisterPair::SP => cpu.set_register_pair(RegisterPair::SP, nn),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Cycles(12)
|
||||||
|
}
|
||||||
|
(LDTarget::IndirectRegister(pair), LDTarget::Register(InstrRegisters::A)) => {
|
||||||
|
let a = cpu.register(Register::A);
|
||||||
|
|
||||||
|
match pair {
|
||||||
|
InstrRegisterPairs::BC => {
|
||||||
|
// LD (BC), A | Put A into memory address BC
|
||||||
|
let addr = cpu.register_pair(RegisterPair::BC);
|
||||||
|
cpu.write_byte(addr, a);
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::DE => {
|
||||||
|
// LD (DE), A | Put A into memory address DE
|
||||||
|
let addr = cpu.register_pair(RegisterPair::DE);
|
||||||
|
cpu.write_byte(addr, a);
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::IncrementHL => {
|
||||||
|
// LD (HL+), A | Put A into memory address HL, then increment HL
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.write_byte(addr, a);
|
||||||
|
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, addr + 1);
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::DecrementHL => {
|
||||||
|
// LD (HL-), A | Put A into memory address HL, then decrement HL
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.write_byte(addr, a);
|
||||||
|
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, addr - 1);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
(LDTarget::Register(InstrRegisters::A), LDTarget::IndirectRegister(pair)) => {
|
||||||
|
match pair {
|
||||||
|
InstrRegisterPairs::BC => {
|
||||||
|
// LD A, (BC) | Put value at address BC into A
|
||||||
|
let addr = cpu.register_pair(RegisterPair::BC);
|
||||||
|
cpu.set_register(Register::A, cpu.read_byte(addr));
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::DE => {
|
||||||
|
// LD A, (DE) | Put value at address DE into A
|
||||||
|
let addr = cpu.register_pair(RegisterPair::DE);
|
||||||
|
cpu.set_register(Register::A, cpu.read_byte(addr));
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::IncrementHL => {
|
||||||
|
// LD A, (HL+) | Put value at address HL into A, then increment HL
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.set_register(Register::A, cpu.read_byte(addr));
|
||||||
|
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, addr + 1);
|
||||||
|
}
|
||||||
|
InstrRegisterPairs::DecrementHL => {
|
||||||
|
// LD A, (HL-) | Put value at address HL into A, then increment HL
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.set_register(Register::A, cpu.read_byte(addr));
|
||||||
|
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, addr - 1);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
(LDTarget::Register(reg), LDTarget::ImmediateByte(n)) => {
|
||||||
|
// LD r[y], n | Store n in Register
|
||||||
|
let cycles: Cycles;
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
InstrRegisters::B => {
|
||||||
|
cpu.set_register(Register::B, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::C => {
|
||||||
|
cpu.set_register(Register::C, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::D => {
|
||||||
|
cpu.set_register(Register::D, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::E => {
|
||||||
|
cpu.set_register(Register::E, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::H => {
|
||||||
|
cpu.set_register(Register::H, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::L => {
|
||||||
|
cpu.set_register(Register::L, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectHL => {
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.write_byte(addr, n);
|
||||||
|
cycles = Cycles(12);
|
||||||
|
}
|
||||||
|
InstrRegisters::A => {
|
||||||
|
cpu.set_register(Register::A, n);
|
||||||
|
cycles = Cycles(8);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectC => unreachable!(),
|
||||||
|
}
|
||||||
|
cycles
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
Instruction::STOP => Cycles(4),
|
||||||
|
Instruction::JR(cond, offset) => {
|
||||||
|
// JR cc[y - 4], d | If condition is true, then add d to current address and jump
|
||||||
|
// JR d | Add d to current address and jump
|
||||||
|
let prev = cpu.register_pair(RegisterPair::PC);
|
||||||
|
let flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
let new_address = (prev as i16 + offset as i16) as u16;
|
||||||
|
|
||||||
|
match cond {
|
||||||
|
JumpCondition::Always => {
|
||||||
|
cpu.set_register_pair(RegisterPair::PC, new_address);
|
||||||
|
Cycles(12)
|
||||||
|
}
|
||||||
|
JumpCondition::NotZero => {
|
||||||
|
if !flags.z {
|
||||||
|
cpu.set_register_pair(RegisterPair::PC, new_address);
|
||||||
|
return Cycles(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
JumpCondition::Zero => {
|
||||||
|
if flags.z {
|
||||||
|
cpu.set_register_pair(RegisterPair::PC, new_address);
|
||||||
|
return Cycles(12);
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
JumpCondition::NotCarry => {
|
||||||
|
if !flags.c {
|
||||||
|
cpu.set_register_pair(RegisterPair::PC, new_address);
|
||||||
|
return Cycles(12);
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
JumpCondition::Carry => {
|
||||||
|
if flags.c {
|
||||||
|
cpu.set_register_pair(RegisterPair::PC, new_address);
|
||||||
|
return Cycles(12);
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::ADD(lhs, rhs) => match (lhs, rhs) {
|
||||||
|
(MATHTarget::RegisterPair(RegisterPair::HL), MATHTarget::RegisterPair(pair)) => {
|
||||||
|
// ADD HL, rp[p] | add register pair to HL.
|
||||||
|
let hl = cpu.register_pair(RegisterPair::HL);
|
||||||
|
let mut flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
let sum;
|
||||||
|
|
||||||
|
match pair {
|
||||||
|
RegisterPair::BC => {
|
||||||
|
let bc = cpu.register_pair(RegisterPair::BC);
|
||||||
|
sum = Self::add_u16s(hl, bc, &mut flags);
|
||||||
|
}
|
||||||
|
RegisterPair::DE => {
|
||||||
|
let de = cpu.register_pair(RegisterPair::DE);
|
||||||
|
sum = Self::add_u16s(hl, de, &mut flags);
|
||||||
|
}
|
||||||
|
RegisterPair::HL => {
|
||||||
|
sum = Self::add_u16s(hl, hl, &mut flags);
|
||||||
|
}
|
||||||
|
RegisterPair::SP => {
|
||||||
|
let sp = cpu.register_pair(RegisterPair::SP);
|
||||||
|
sum = Self::add_u16s(hl, sp, &mut flags);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
cpu.set_register(Register::Flags, flags.into());
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, sum);
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
},
|
||||||
|
Instruction::INC(AllRegisters::Word(pair)) => {
|
||||||
|
// INC rp[p] | Increment Register Pair
|
||||||
|
match pair {
|
||||||
|
RegisterPair::BC => {
|
||||||
|
let bc = cpu.register_pair(RegisterPair::BC);
|
||||||
|
cpu.set_register_pair(RegisterPair::BC, bc + 1);
|
||||||
|
}
|
||||||
|
RegisterPair::DE => {
|
||||||
|
let de = cpu.register_pair(RegisterPair::DE);
|
||||||
|
cpu.set_register_pair(RegisterPair::DE, de + 1);
|
||||||
|
}
|
||||||
|
RegisterPair::HL => {
|
||||||
|
let hl = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, hl + 1);
|
||||||
|
}
|
||||||
|
RegisterPair::SP => {
|
||||||
|
let sp = cpu.register_pair(RegisterPair::SP);
|
||||||
|
cpu.set_register_pair(RegisterPair::SP, sp + 1);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
Instruction::INC(AllRegisters::Byte(reg)) => {
|
||||||
|
// INC r[y] | Increment Register
|
||||||
|
let mut flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
let cycles: Cycles;
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
InstrRegisters::B => {
|
||||||
|
let b = cpu.register(Register::B);
|
||||||
|
cpu.set_register(Register::B, Self::inc_register(b, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::C => {
|
||||||
|
let c = cpu.register(Register::C);
|
||||||
|
cpu.set_register(Register::C, Self::inc_register(c, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::D => {
|
||||||
|
let d = cpu.register(Register::D);
|
||||||
|
cpu.set_register(Register::D, Self::inc_register(d, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::E => {
|
||||||
|
let e = cpu.register(Register::E);
|
||||||
|
cpu.set_register(Register::E, Self::inc_register(e, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::H => {
|
||||||
|
let h = cpu.register(Register::H);
|
||||||
|
cpu.set_register(Register::H, Self::inc_register(h, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::L => {
|
||||||
|
let l = cpu.register(Register::L);
|
||||||
|
cpu.set_register(Register::L, Self::inc_register(l, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectHL => {
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.write_byte(addr, Self::inc_register(cpu.read_byte(addr), &mut flags));
|
||||||
|
cycles = Cycles(12);
|
||||||
|
}
|
||||||
|
InstrRegisters::A => {
|
||||||
|
let a = cpu.register(Register::A);
|
||||||
|
cpu.set_register(Register::A, Self::inc_register(a, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectC => unreachable!(),
|
||||||
|
}
|
||||||
|
cpu.set_register(Register::Flags, flags.into());
|
||||||
|
cycles
|
||||||
|
}
|
||||||
|
Instruction::DEC(AllRegisters::Word(pair)) => {
|
||||||
|
// DEC rp[p] | Decrement Register Pair
|
||||||
|
match pair {
|
||||||
|
RegisterPair::BC => {
|
||||||
|
let bc = cpu.register_pair(RegisterPair::BC);
|
||||||
|
cpu.set_register_pair(RegisterPair::BC, bc - 1);
|
||||||
|
}
|
||||||
|
RegisterPair::DE => {
|
||||||
|
let de = cpu.register_pair(RegisterPair::DE);
|
||||||
|
cpu.set_register_pair(RegisterPair::DE, de - 1);
|
||||||
|
}
|
||||||
|
RegisterPair::HL => {
|
||||||
|
let hl = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.set_register_pair(RegisterPair::HL, hl - 1);
|
||||||
|
}
|
||||||
|
RegisterPair::SP => {
|
||||||
|
let sp = cpu.register_pair(RegisterPair::SP);
|
||||||
|
cpu.set_register_pair(RegisterPair::SP, sp - 1);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
Cycles(8)
|
||||||
|
}
|
||||||
|
Instruction::DEC(AllRegisters::Byte(reg)) => {
|
||||||
|
// DEC r[y] | Decrement Register
|
||||||
|
let mut flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
let cycles: Cycles;
|
||||||
|
|
||||||
|
match reg {
|
||||||
|
InstrRegisters::B => {
|
||||||
|
let b = cpu.register(Register::B);
|
||||||
|
cpu.set_register(Register::B, Self::dec_register(b, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::C => {
|
||||||
|
let c = cpu.register(Register::C);
|
||||||
|
cpu.set_register(Register::C, Self::dec_register(c, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::D => {
|
||||||
|
let d = cpu.register(Register::D);
|
||||||
|
cpu.set_register(Register::D, Self::dec_register(d, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::E => {
|
||||||
|
let e = cpu.register(Register::E);
|
||||||
|
cpu.set_register(Register::E, Self::dec_register(e, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::H => {
|
||||||
|
let h = cpu.register(Register::H);
|
||||||
|
cpu.set_register(Register::H, Self::dec_register(h, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::L => {
|
||||||
|
let l = cpu.register(Register::L);
|
||||||
|
cpu.set_register(Register::L, Self::dec_register(l, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectHL => {
|
||||||
|
let addr = cpu.register_pair(RegisterPair::HL);
|
||||||
|
cpu.write_byte(addr, Self::dec_register(cpu.read_byte(addr), &mut flags));
|
||||||
|
cycles = Cycles(12);
|
||||||
|
}
|
||||||
|
InstrRegisters::A => {
|
||||||
|
let a = cpu.register(Register::A);
|
||||||
|
cpu.set_register(Register::A, Self::dec_register(a, &mut flags));
|
||||||
|
cycles = Cycles(4);
|
||||||
|
}
|
||||||
|
InstrRegisters::IndirectC => unreachable!(),
|
||||||
|
}
|
||||||
|
cpu.set_register(Register::Flags, flags.into());
|
||||||
|
cycles
|
||||||
|
}
|
||||||
|
Instruction::RLCA => {
|
||||||
|
// FIXME: Pretty sure this is an incorrect implementation
|
||||||
|
let mut flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
|
||||||
|
let a = cpu.register(Register::A);
|
||||||
|
let carry_bit = (a & 0x80) >> 7;
|
||||||
|
let new_a = a << 1;
|
||||||
|
|
||||||
|
flags.z = 0 == new_a;
|
||||||
|
flags.n = false;
|
||||||
|
flags.h = false;
|
||||||
|
flags.c = carry_bit == 0x01;
|
||||||
|
|
||||||
|
cpu.set_register(Register::A, new_a);
|
||||||
|
Cycles(4)
|
||||||
|
}
|
||||||
|
Instruction::RRCA => {
|
||||||
|
// FIXME: Pretty sure this is an incorrect implementation
|
||||||
|
let mut flags: Flags = cpu.register(Register::Flags).into();
|
||||||
|
|
||||||
|
let a = cpu.register(Register::A);
|
||||||
|
let carry_bit = a & 0x01;
|
||||||
|
let new_a = a >> 1;
|
||||||
|
|
||||||
|
flags.z = new_a == 0;
|
||||||
|
flags.n = false;
|
||||||
|
flags.h = false;
|
||||||
|
flags.c = carry_bit == 0x01;
|
||||||
|
|
||||||
|
cpu.set_register(Register::A, new_a);
|
||||||
|
Cycles(4)
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dec_register(reg: u8, flags: &mut Flags) -> u8 {
|
||||||
|
let res = reg - 1;
|
||||||
|
|
||||||
|
flags.z = res == 0;
|
||||||
|
flags.n = true;
|
||||||
|
flags.h = !Self::u8_half_carry(res, 1); // FIXME: Is this right?
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inc_register(reg: u8, flags: &mut Flags) -> u8 {
|
||||||
|
let res = reg + 1;
|
||||||
|
|
||||||
|
flags.z = res == 0;
|
||||||
|
flags.n = false;
|
||||||
|
flags.h = Self::u8_half_carry(reg, 1);
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_u16s(left: u16, right: u16, flags: &mut Flags) -> u16 {
|
||||||
|
let (sum, did_overflow) = left.overflowing_add(right);
|
||||||
|
flags.n = false;
|
||||||
|
flags.h = Self::u16_half_carry(left, right);
|
||||||
|
flags.c = did_overflow;
|
||||||
|
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u16_half_carry(left: u16, right: u16) -> bool {
|
||||||
|
Self::u8_half_carry((left >> 8) as u8, (right >> 8) as u8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u8_half_carry(left: u8, right: u8) -> bool {
|
||||||
|
((left & 0xF) + (right & 0xF)) & 0x10 == 0x10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
pub fn from_byte(cpu: &Cpu, byte: u8) -> Self {
|
pub fn from_byte(cpu: &Cpu, byte: u8) -> Self {
|
||||||
if byte == 0xCB {
|
if byte == 0xCB {
|
||||||
|
|
Loading…
Reference in New Issue