chore: refactor parts of instruction.rs

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-03-23 20:22:11 -05:00
parent 501d93c37b
commit e5fb07c4d1
1 changed files with 220 additions and 330 deletions

View File

@ -150,14 +150,14 @@ impl Instruction {
cpu.write_byte(addr, a); cpu.write_byte(addr, a);
} }
InstrRegisterPair::IncrementHL => { InstrRegisterPair::IncrementHL => {
// LD (HL+), A | Put A into memory address HL, then increment HL // LD (HL+), A | Put A into byte at address HL, then increment HL
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, a); cpu.write_byte(addr, a);
cpu.set_register_pair(RegisterPair::HL, addr + 1); cpu.set_register_pair(RegisterPair::HL, addr + 1);
} }
InstrRegisterPair::DecrementHL => { InstrRegisterPair::DecrementHL => {
// LD (HL-), A | Put A into memory address HL, then decrement HL // LD (HL-), A | Put A into byte at address HL, then decrement HL
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, a); cpu.write_byte(addr, a);
@ -180,8 +180,8 @@ impl Instruction {
// LD A, (HL+) | Put value at address HL into A, then increment HL // LD A, (HL+) | Put value at address HL into A, then increment HL
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr); let byte = cpu.read_byte(addr);
cpu.set_register(Register::A, byte);
cpu.set_register(Register::A, byte);
cpu.set_register_pair(RegisterPair::HL, addr + 1); cpu.set_register_pair(RegisterPair::HL, addr + 1);
} }
InstrRegisterPair::DecrementHL => { InstrRegisterPair::DecrementHL => {
@ -344,13 +344,12 @@ impl Instruction {
Instruction::ADD(lhs, rhs) => match (lhs, rhs) { Instruction::ADD(lhs, rhs) => match (lhs, rhs) {
(MATHTarget::RegisterPair(RegisterPair::HL), MATHTarget::RegisterPair(pair)) => { (MATHTarget::RegisterPair(RegisterPair::HL), MATHTarget::RegisterPair(pair)) => {
// ADD HL, rp[p] | add register pair to HL. // ADD HL, rp[p] | add register pair to HL.
use RegisterPair::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
match pair { match pair {
RegisterPair::BC BC | DE | HL | SP => {
| RegisterPair::DE
| RegisterPair::HL
| RegisterPair::SP => {
let hl_value = cpu.register_pair(RegisterPair::HL); let hl_value = cpu.register_pair(RegisterPair::HL);
let value = cpu.register_pair(pair); let value = cpu.register_pair(pair);
let sum = Self::add_u16s(hl_value, value, &mut flags); let sum = Self::add_u16s(hl_value, value, &mut flags);
@ -582,32 +581,27 @@ impl Instruction {
Instruction::ADC(target) => match target { Instruction::ADC(target) => match target {
MATHTarget::Register(reg) => { MATHTarget::Register(reg) => {
// ADC A, r[z] | Add register r[z] plus the Carry flag to A // ADC A, r[z] | Add register r[z] plus the Carry flag to A
// FIXME: Do I Add register A as well? use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let a_value = cpu.register(Register::A); let a_value = cpu.register(Register::A);
let cycles: Cycles;
let sum;
match reg { let (cycles, sum) = match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let value = cpu.register(reg.to_register()) + (flags.c() as u8); let value = cpu.register(reg.to_register()) + (flags.c() as u8);
sum = Self::add_u8s(a_value, value, &mut flags); let sum = Self::add_u8s(a_value, value, &mut flags);
cycles = Cycles::new(4); (Cycles::new(4), sum)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL))
sum = Self::add_u8s(a_value, value, &mut flags); + (flags.c() as u8);
cycles = Cycles::new(8); let sum = Self::add_u8s(a_value, value, &mut flags);
(Cycles::new(8), sum)
} }
} };
cpu.set_flags(flags);
cpu.set_register(Register::A, sum); cpu.set_register(Register::A, sum);
cpu.set_flags(flags);
cycles cycles
} }
MATHTarget::ImmediateByte(n) => { MATHTarget::ImmediateByte(n) => {
@ -625,32 +619,26 @@ impl Instruction {
Instruction::SUB(target) => match target { Instruction::SUB(target) => match target {
MATHTarget::Register(reg) => { MATHTarget::Register(reg) => {
// SUB r[z] | Subtract the value in register r[z] from register A, then store in A // SUB r[z] | Subtract the value in register r[z] from register A, then store in A
use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let a_value = cpu.register(Register::A); let a_value = cpu.register(Register::A);
let cycles: Cycles;
let diff;
match reg { let (cycles, diff) = match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let value = cpu.register(reg.to_register()); let value = cpu.register(reg.to_register());
diff = Self::sub_u8s(a_value, value, &mut flags); let diff = Self::sub_u8s(a_value, value, &mut flags);
cycles = Cycles::new(4); (Cycles::new(4), diff)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
diff = Self::sub_u8s(a_value, value, &mut flags); let diff = Self::sub_u8s(a_value, value, &mut flags);
cycles = Cycles::new(8); (Cycles::new(8), diff)
} }
} };
cpu.set_flags(flags);
cpu.set_register(Register::A, diff); cpu.set_register(Register::A, diff);
cpu.set_flags(flags);
cycles cycles
} }
MATHTarget::ImmediateByte(n) => { MATHTarget::ImmediateByte(n) => {
@ -668,29 +656,24 @@ impl Instruction {
MATHTarget::Register(reg) => { MATHTarget::Register(reg) => {
// SBC A, r[z] | Subtract the value from register r[z] from A, add the Carry flag and then store in A // SBC A, r[z] | Subtract the value from register r[z] from A, add the Carry flag and then store in A
// FIXME: See ADC, is this a correct understanding of this Instruction // FIXME: See ADC, is this a correct understanding of this Instruction
use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let a_value = cpu.register(Register::A); let a_value = cpu.register(Register::A);
let cycles: Cycles;
let diff;
match reg { let (cycles, diff) = match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let value = cpu.register(reg.to_register()) + (flags.c() as u8); let value = cpu.register(reg.to_register()) + (flags.c() as u8);
diff = Self::sub_u8s(a_value, value, &mut flags); let diff = Self::sub_u8s(a_value, value, &mut flags);
cycles = Cycles::new(4); (Cycles::new(4), diff)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL))
diff = Self::sub_u8s(a_value, value, &mut flags); + (flags.c() as u8);
cycles = Cycles::new(8); let diff = Self::sub_u8s(a_value, value, &mut flags);
(Cycles::new(8), diff)
} }
} };
cpu.set_register(Register::A, diff); cpu.set_register(Register::A, diff);
cpu.set_flags(flags); cpu.set_flags(flags);
@ -748,29 +731,21 @@ impl Instruction {
Instruction::XOR(target) => match target { Instruction::XOR(target) => match target {
MATHTarget::Register(reg) => { MATHTarget::Register(reg) => {
// XOR r[z] | Bitwise XOR register r[z] and register A, store in register A // XOR r[z] | Bitwise XOR register r[z] and register A, store in register A
use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let a_value = cpu.register(Register::A); let a_value = cpu.register(Register::A);
let cycles: Cycles;
let result;
match reg { let (cycles, result) = match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let value = cpu.register(reg.to_register()); let value = cpu.register(reg.to_register());
result = a_value ^ value; (Cycles::new(4), a_value ^ value)
cycles = Cycles::new(4);
} }
InstrRegister::IndirectHL => { IndirectHL => {
let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
result = a_value ^ value; (Cycles::new(8), a_value ^ value)
cycles = Cycles::new(8);
} }
} };
flags.update(result == 0, false, false, false); flags.update(result == 0, false, false, false);
cpu.set_flags(flags); cpu.set_flags(flags);
@ -792,29 +767,21 @@ impl Instruction {
Instruction::OR(target) => match target { Instruction::OR(target) => match target {
MATHTarget::Register(reg) => { MATHTarget::Register(reg) => {
// OR r[z] | Bitwise OR register r[z] and register A, store in register A // OR r[z] | Bitwise OR register r[z] and register A, store in register A
use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let a_value = cpu.register(Register::A); let a_value = cpu.register(Register::A);
let cycles: Cycles;
let result;
match reg { let (cycles, result) = match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let value = cpu.register(reg.to_register()); let value = cpu.register(reg.to_register());
result = a_value | value; (Cycles::new(4), a_value | value)
cycles = Cycles::new(4);
} }
InstrRegister::IndirectHL => { IndirectHL => {
let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL)); let value = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
result = a_value | value; (Cycles::new(8), a_value | value)
cycles = Cycles::new(8);
} }
} };
flags.update(result == 0, false, false, false); flags.update(result == 0, false, false, false);
cpu.set_flags(flags); cpu.set_flags(flags);
@ -877,33 +844,37 @@ impl Instruction {
if !flags.z() { if !flags.z() {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);
return Cycles::new(20); Cycles::new(20)
} else {
Cycles::new(8)
} }
Cycles::new(8)
} }
JumpCondition::Zero => { JumpCondition::Zero => {
if flags.z() { if flags.z() {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);
return Cycles::new(20); Cycles::new(20)
} else {
Cycles::new(8)
} }
Cycles::new(8)
} }
JumpCondition::NotCarry => { JumpCondition::NotCarry => {
if !flags.c() { if !flags.c() {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);
return Cycles::new(20); Cycles::new(20)
} else {
Cycles::new(8)
} }
Cycles::new(8)
} }
JumpCondition::Carry => { JumpCondition::Carry => {
if flags.c() { if flags.c() {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr); cpu.set_register_pair(RegisterPair::PC, addr);
return Cycles::new(20); Cycles::new(20)
} else {
Cycles::new(8)
} }
Cycles::new(8)
} }
JumpCondition::Always => { JumpCondition::Always => {
let addr = Self::pop(cpu); let addr = Self::pop(cpu);
@ -917,14 +888,18 @@ impl Instruction {
// LD HL, SP + d | Add SP + d to register HL // LD HL, SP + d | Add SP + d to register HL
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let sum = Self::add_u16_i8(cpu.register_pair(RegisterPair::SP), d, &mut flags); let sum = Self::add_u16_i8(cpu.register_pair(RegisterPair::SP), d, &mut flags);
cpu.set_register_pair(RegisterPair::HL, sum); cpu.set_register_pair(RegisterPair::HL, sum);
cpu.set_flags(flags);
Cycles::new(12) Cycles::new(12)
} }
Instruction::POP(pair) => { Instruction::POP(pair) => {
// POP rp2[p] | Pop from stack into register pair rp2[] // POP rp2[p] | Pop from stack into register pair rp2[]
// Flags are set when we call cpu.set_register_pair(RegisterPair::AF, value); // Flags are set when we call cpu.set_register_pair(RegisterPair::AF, value);
use RegisterPair::*;
match pair { match pair {
RegisterPair::BC | RegisterPair::DE | RegisterPair::HL | RegisterPair::AF => { BC | DE | HL | AF => {
let value = Self::pop(cpu); let value = Self::pop(cpu);
cpu.set_register_pair(pair, value); cpu.set_register_pair(pair, value);
} }
@ -1015,33 +990,37 @@ impl Instruction {
if !flags.z() { if !flags.z() {
Self::push(cpu, pc); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, nn); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles::new(24); Cycles::new(24)
} else {
Cycles::new(12)
} }
Cycles::new(12)
} }
JumpCondition::Zero => { JumpCondition::Zero => {
if flags.z() { if flags.z() {
Self::push(cpu, pc); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, nn); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles::new(24); Cycles::new(24)
} else {
Cycles::new(12)
} }
Cycles::new(12)
} }
JumpCondition::NotCarry => { JumpCondition::NotCarry => {
if !flags.c() { if !flags.c() {
Self::push(cpu, pc); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, nn); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles::new(24); Cycles::new(24)
} else {
Cycles::new(12)
} }
Cycles::new(12)
} }
JumpCondition::Carry => { JumpCondition::Carry => {
if flags.c() { if flags.c() {
Self::push(cpu, pc); Self::push(cpu, pc);
cpu.set_register_pair(RegisterPair::PC, nn); cpu.set_register_pair(RegisterPair::PC, nn);
return Cycles::new(24); Cycles::new(24)
} else {
Cycles::new(12)
} }
Cycles::new(12)
} }
JumpCondition::Always => { JumpCondition::Always => {
Self::push(cpu, pc); Self::push(cpu, pc);
@ -1072,328 +1051,255 @@ impl Instruction {
} }
Instruction::RLC(reg) => { Instruction::RLC(reg) => {
// RLC r[z] | Rotate register r[z] left // RLC r[z] | Rotate register r[z] left
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let msb;
let rot_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, msb, rotated) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
msb = value >> 7; let rotated = value.rotate_left(1);
rot_reg = value.rotate_left(1);
cpu.set_register(register, rot_reg); cpu.set_register(register, rotated);
cycles = Cycles::new(8); (Cycles::new(8), value >> 7, rotated)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
msb = value >> 7; let rotated = value.rotate_left(1);
rot_reg = value.rotate_left(1);
cpu.write_byte(addr, rot_reg); cpu.write_byte(addr, rotated);
cycles = Cycles::new(16); (Cycles::new(16), value >> 7, rotated)
} }
} };
flags.update(rot_reg == 0, false, false, msb == 0x01); flags.update(rotated == 0, false, false, msb == 0x01);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::RRC(reg) => { Instruction::RRC(reg) => {
// RRC r[z] | Rotate Register r[z] right // RRC r[z] | Rotate Register r[z] right
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let lsb;
let rot_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, lsb, rotated) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
lsb = value & 0x01; let rotated = value.rotate_right(1);
rot_reg = value.rotate_right(1);
cpu.set_register(register, rot_reg); cpu.set_register(register, rotated);
cycles = Cycles::new(8); (Cycles::new(8), value & 0x01, rotated)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
lsb = value & 0x01; let rotated = value.rotate_right(1);
rot_reg = value.rotate_right(1);
cpu.write_byte(addr, rot_reg); cpu.write_byte(addr, rotated);
cycles = Cycles::new(16); (Cycles::new(16), value & 0x01, rotated)
} }
} };
flags.update(rot_reg == 0, false, false, lsb == 0x01); flags.update(rotated == 0, false, false, lsb == 0x01);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::RL(reg) => { Instruction::RL(reg) => {
// RL r[z] | Rotate register r[z] left through carry // RL r[z] | Rotate register r[z] left through carry
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let carry;
let rot_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, rotated, carry) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
let (new_reg, new_carry) = Self::rl_thru_carry(value, flags.c()); let (rotated, carry) = Self::rl_thru_carry(value, flags.c());
rot_reg = new_reg;
carry = new_carry;
cpu.set_register(register, rot_reg); cpu.set_register(register, rotated);
cycles = Cycles::new(8); (Cycles::new(8), rotated, carry)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
let (new_reg, new_carry) = Self::rl_thru_carry(value, flags.c()); let (rotated, carry) = Self::rl_thru_carry(value, flags.c());
rot_reg = new_reg;
carry = new_carry;
cpu.write_byte(addr, rot_reg); cpu.write_byte(addr, rotated);
cycles = Cycles::new(16); (Cycles::new(16), rotated, carry)
} }
} };
flags.update(rot_reg == 0, false, false, carry); flags.update(rotated == 0, false, false, carry);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::RR(reg) => { Instruction::RR(reg) => {
// RR r[z] | Rotate register r[z] right through carry // RR r[z] | Rotate register r[z] right through carry
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let carry;
let rot_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, rotated, carry) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
let (new_reg, new_carry) = Self::rr_thru_carry(value, flags.c()); let (rotated, carry) = Self::rr_thru_carry(value, flags.c());
rot_reg = new_reg;
carry = new_carry;
cpu.set_register(register, rot_reg); cpu.set_register(register, rotated);
cycles = Cycles::new(8); (Cycles::new(8), rotated, carry)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
let (new_reg, new_carry) = Self::rr_thru_carry(value, flags.c()); let (rotated, carry) = Self::rr_thru_carry(value, flags.c());
rot_reg = new_reg;
carry = new_carry;
cpu.write_byte(addr, rot_reg); cpu.write_byte(addr, rotated);
cycles = Cycles::new(16); (Cycles::new(16), rotated, carry)
} }
} };
flags.update(rot_reg == 0, false, false, carry); flags.update(rotated == 0, false, false, carry);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::SLA(reg) => { Instruction::SLA(reg) => {
// SLA r[z] | Shift left arithmetic register r[z] // SLA r[z] | Shift left arithmetic register r[z]
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let shift_reg;
let msb;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, msb, shifted) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
msb = (value >> 7) & 0x01; let shifted = value << 1;
shift_reg = value << 1;
cpu.set_register(register, shift_reg); cpu.set_register(register, shifted);
cycles = Cycles::new(8); (Cycles::new(8), (value >> 7) & 0x01, shifted)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
msb = (value >> 7) & 0x01; let shifted = value << 1;
shift_reg = value << 1;
cpu.write_byte(addr, value); cpu.write_byte(addr, value);
cycles = Cycles::new(16); (Cycles::new(16), (value >> 7) & 0x01, shifted)
} }
} };
flags.update(shift_reg == 0, false, false, msb == 0x01); flags.update(shifted == 0, false, false, msb == 0x01);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::SRA(reg) => { Instruction::SRA(reg) => {
// SRA r[z] | Shift right arithmetic register r[z] // SRA r[z] | Shift right arithmetic register r[z]
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let shift_reg;
let lsb;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, lsb, shifted) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
lsb = value & 0x01;
let msb = (value >> 7) & 0x01; let msb = (value >> 7) & 0x01;
shift_reg = (value >> 1) | (msb << 7); // msb is duplicated in this op let shifted = msb << 7 | value >> 1;
cpu.set_register(register, shift_reg); cpu.set_register(register, shifted);
cycles = Cycles::new(8); (Cycles::new(8), value & 0x01, shifted)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
lsb = value & 0x01;
let msb = (value >> 7) & 0x01; let msb = (value >> 7) & 0x01;
shift_reg = (value >> 1) | (msb << 7); // msb is duplicated in this op let shifted = msb << 7 | value >> 1;
cpu.write_byte(addr, value); cpu.write_byte(addr, value);
cycles = Cycles::new(16); (Cycles::new(16), value & 0x01, shifted)
} }
} };
flags.update(shift_reg == 0, false, false, lsb == 0x01); flags.update(shifted == 0, false, false, lsb == 0x01);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::SWAP(reg) => { Instruction::SWAP(reg) => {
// SWAP r[z] | Swap the 4 highest and lowest bits in a byte // SWAP r[z] | Swap the 4 highest and lowest bits in a byte
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let swap_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, swapped) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
swap_reg = Self::swap_bits(value); let swapped = Self::swap_bits(value);
cpu.set_register(register, swap_reg); cpu.set_register(register, swapped);
cycles = Cycles::new(8); (Cycles::new(8), swapped)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
swap_reg = Self::swap_bits(value); let swapped = Self::swap_bits(value);
cpu.write_byte(addr, swap_reg); cpu.write_byte(addr, swapped);
cycles = Cycles::new(16) (Cycles::new(16), swapped)
} }
} };
flags.update(swap_reg == 0, false, false, false); flags.update(swapped == 0, false, false, false);
cpu.set_flags(flags); cpu.set_flags(flags);
cycles cycles
} }
Instruction::SRL(reg) => { Instruction::SRL(reg) => {
// SRL r[z] | Shift right logic register r[z] // SRL r[z] | Shift right logic register r[z]
let mut flags: Flags = *cpu.flags(); use InstrRegister::*;
let lsb;
let shift_reg;
let cycles: Cycles;
match reg { let mut flags: Flags = *cpu.flags();
InstrRegister::B
| InstrRegister::C let (cycles, lsb, shift_reg) = match reg {
| InstrRegister::D B | C | D | E | H | L | A => {
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
lsb = value & 0x01; let shifted = value >> 1;
shift_reg = value >> 1;
cpu.set_register(register, shift_reg); cpu.set_register(register, shifted);
cycles = Cycles::new(8); (Cycles::new(8), value & 0x01, shifted)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
lsb = value & 0x01; let shifted = value >> 1;
shift_reg = value >> 1;
cpu.write_byte(addr, shift_reg); cpu.write_byte(addr, shifted);
cycles = Cycles::new(16); (Cycles::new(16), value & 0x01, shifted)
} }
} };
flags.update(shift_reg == 0, false, false, lsb == 0x01); flags.update(shift_reg == 0, false, false, lsb == 0x01);
cpu.set_flags(flags); cpu.set_flags(flags);
@ -1402,31 +1308,26 @@ impl Instruction {
} }
Instruction::BIT(y, reg) => { Instruction::BIT(y, reg) => {
// BIT y, r[z] | Test y is in register r[z] // BIT y, r[z] | Test y is in register r[z]
use InstrRegister::*;
let mut flags: Flags = *cpu.flags(); let mut flags: Flags = *cpu.flags();
let is_bit_set;
let cycles: Cycles; let (cycles, is_bit_set) = match reg {
match reg { B | C | D | E | H | L | A => {
InstrRegister::B
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
is_bit_set = ((value >> y) & 0x01) == 0x01; let is_bit_set = ((value >> y) & 0x01) == 0x01;
cycles = Cycles::new(8); (Cycles::new(8), is_bit_set)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
is_bit_set = ((value >> y) & 0x01) == 0x01; let is_bit_set = ((value >> y) & 0x01) == 0x01;
cycles = Cycles::new(12); (Cycles::new(12), is_bit_set)
} }
} };
flags.update(!is_bit_set, false, true, flags.c()); flags.update(!is_bit_set, false, true, flags.c());
cpu.set_flags(flags); cpu.set_flags(flags);
@ -1439,21 +1340,17 @@ impl Instruction {
// 00000001 << 3 = 00001000 // 00000001 << 3 = 00001000
// ~00001000 = 11110111 // ~00001000 = 11110111
// value & 11110111 means that only a specific bit will be reset // value & 11110111 means that only a specific bit will be reset
use InstrRegister::*;
match reg { match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
cpu.set_register(register, value & !(1u8 << y)); cpu.set_register(register, value & !(1u8 << y));
Cycles::new(8) Cycles::new(8)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
@ -1467,21 +1364,17 @@ impl Instruction {
// //
// 00000001 << 3 = 00001000 // 00000001 << 3 = 00001000
// value | 00001000 means that only a specific bit will be set // value | 00001000 means that only a specific bit will be set
use InstrRegister::*;
match reg { match reg {
InstrRegister::B B | C | D | E | H | L | A => {
| InstrRegister::C
| InstrRegister::D
| InstrRegister::E
| InstrRegister::H
| InstrRegister::L
| InstrRegister::A => {
let register = reg.to_register(); let register = reg.to_register();
let value = cpu.register(register); let value = cpu.register(register);
cpu.set_register(register, value | (1u8 << y)); cpu.set_register(register, value | (1u8 << y));
Cycles::new(8) Cycles::new(8)
} }
InstrRegister::IndirectHL => { IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL); let addr = cpu.register_pair(RegisterPair::HL);
let value = cpu.read_byte(addr); let value = cpu.read_byte(addr);
@ -1559,12 +1452,9 @@ impl Instruction {
fn add_u16_i8(left: u16, right: i8, flags: &mut Flags) -> u16 { fn add_u16_i8(left: u16, right: i8, flags: &mut Flags) -> u16 {
let (sum, did_overflow) = left.overflowing_add(right as u16); let (sum, did_overflow) = left.overflowing_add(right as u16);
flags.update( // FIXME: Is this more correct?
false, let half_carry = Self::add_u8_half_carry((left >> 8) as u8, right as u8);
false, flags.update(false, false, half_carry, did_overflow);
Self::add_u16_half_carry(left, right as u16),
did_overflow,
);
sum sum
} }
@ -1623,7 +1513,7 @@ impl Instruction {
fn rr_thru_carry(byte: u8, carry: bool) -> (u8, bool) { fn rr_thru_carry(byte: u8, carry: bool) -> (u8, bool) {
let carry_flag = byte & 0x01; // get the LSB of the u8 (which will rotate into the carry bit) let carry_flag = byte & 0x01; // get the LSB of the u8 (which will rotate into the carry bit)
let new_byte = (byte >> 1) | ((carry as u8) << 7); // shift the bit right, and then OR the carry bit in. let new_byte = ((carry as u8) << 7) | (byte >> 1); // shift the bit right, and then OR the carry bit in.
(new_byte, carry_flag == 0x01) (new_byte, carry_flag == 0x01)
} }