feat: clock bus on instruction read-write
Some checks failed
continuous-integration/drone/push Build is failing

Commit also includes general work towards passing mem-timings.

Note: while cpu_instrs.gb passes, instr_timing.gb and mem_timing.gb both
are stuck in infinite loops (Currently, it seems like a timing issue).
This is a major regression that hopefully shouldn't last for too long.
This commit is contained in:
2021-08-14 00:10:51 -05:00
parent 0637b771e3
commit 8625bec059
9 changed files with 332 additions and 219 deletions

View File

@@ -8,7 +8,7 @@ use self::table::{
register,
};
use self::table::{Group1RegisterPair, Group2RegisterPair, Group3RegisterPair, Register};
use crate::bus::BusIo;
use crate::bus::{Bus, BusIo};
use crate::cpu::{Cpu, Flags, HaltState, ImeState, Register as CpuRegister, RegisterPair};
#[allow(clippy::upper_case_acronyms)]
@@ -120,14 +120,15 @@ impl Instruction {
Instruction::LD(target, src) => match (target, src) {
(LDTarget::IndirectImmediateWord, LDSource::SP) => {
// LD (u16), SP | Store stack pointer in byte at 16-bit register
let word = cpu.imm_word();
cpu.write_word(word, cpu.register_pair(RegisterPair::SP));
let addr = Self::imm_word(cpu);
let sp = cpu.register_pair(RegisterPair::SP);
Self::write_word(&mut cpu.bus, addr, sp);
Cycle::new(20)
}
(LDTarget::Group1(pair), LDSource::ImmediateWord) => {
// LD r16, u16 | Store u16 in 16-bit register
use Group1RegisterPair::*;
let word = cpu.imm_word();
let word = Self::imm_word(cpu);
match pair {
BC | DE | HL | SP => cpu.set_register_pair(pair.as_register_pair(), word),
@@ -141,16 +142,16 @@ impl Instruction {
match pair {
Group2RegisterPair::BC | Group2RegisterPair::DE => {
let addr = cpu.register_pair(pair.as_register_pair());
cpu.write_byte(addr, acc);
Self::write_byte(&mut cpu.bus, addr, acc);
}
Group2RegisterPair::IncrementHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, acc);
Self::write_byte(&mut cpu.bus, addr, acc);
cpu.set_register_pair(RegisterPair::HL, addr + 1);
}
Group2RegisterPair::DecrementHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, acc);
Self::write_byte(&mut cpu.bus, addr, acc);
cpu.set_register_pair(RegisterPair::HL, addr - 1);
}
}
@@ -161,18 +162,18 @@ impl Instruction {
match pair {
Group2RegisterPair::BC | Group2RegisterPair::DE => {
let addr = cpu.register_pair(pair.as_register_pair());
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
}
Group2RegisterPair::IncrementHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
cpu.set_register_pair(RegisterPair::HL, addr + 1);
}
Group2RegisterPair::DecrementHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
cpu.set_register_pair(RegisterPair::HL, addr - 1);
}
@@ -182,7 +183,7 @@ impl Instruction {
(LDTarget::Register(reg), LDSource::ImmediateByte) => {
// LD r8, u8 | Store u8 in 8-bit register
use Register::*;
let right = cpu.imm_byte();
let right = Self::imm_byte(cpu);
match reg {
A | B | C | D | E | H | L => {
@@ -191,7 +192,7 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, right);
Self::write_byte(&mut cpu.bus, addr, right);
Cycle::new(12)
}
}
@@ -199,12 +200,14 @@ impl Instruction {
(LDTarget::IoWithC, LDSource::A) => {
// LD (0xFF00 + C), A | Store accumulator in byte at address 0xFF00 + C
let addr = 0xFF00 + cpu.register(CpuRegister::C) as u16;
cpu.write_byte(addr, cpu.register(CpuRegister::A));
let acc = cpu.register(CpuRegister::A);
Self::write_byte(&mut cpu.bus, addr, acc);
Cycle::new(8)
}
(LDTarget::A, LDSource::IoWithC) => {
// LD A, (0xFF00 + C) | Store byte at 0xFF00 + C in register A
let byte = cpu.read_byte(0xFF00 + cpu.register(CpuRegister::C) as u16);
let addr = 0xFF00 + cpu.register(CpuRegister::C) as u16;
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
Cycle::new(8)
}
@@ -223,14 +226,14 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, right);
Self::write_byte(&mut cpu.bus, addr, right);
Cycle::new(8)
}
}
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let right = cpu.read_byte(addr);
let right = Self::read_byte(&mut cpu.bus, addr);
match target {
B | C | D | E | H | L | A => {
@@ -246,32 +249,34 @@ impl Instruction {
}
(LDTarget::IoWithImmediateOffset, LDSource::A) => {
// LD (0xFF00 + u8), A | Store accumulator in byte at address 0xFF00 + u8
let offset = cpu.imm_byte();
cpu.write_byte(0xFF00 + (offset as u16), cpu.register(CpuRegister::A));
let addr = 0xFF00 + Self::imm_byte(cpu) as u16;
let acc = cpu.register(CpuRegister::A);
Self::write_byte(&mut cpu.bus, addr, acc);
Cycle::new(12)
}
(LDTarget::A, LDSource::IoWithImmediateOffset) => {
// LD A, (0xFF00 + u8) | Store byte at address 0xFF00 + u8 in accumulator
let offset = cpu.imm_byte();
let byte = cpu.read_byte(0xFF00 + (offset as u16));
let addr = 0xFF00 + Self::imm_byte(cpu) as u16;
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
Cycle::new(12)
}
(LDTarget::SP, LDSource::HL) => {
// LD SP, HL | Store HL in stack pointer
cpu.set_register_pair(RegisterPair::SP, cpu.register_pair(RegisterPair::HL));
Cycle::new(8)
Cycle::new(8) // performs an internal operation that takes 4 cycles
}
(LDTarget::IndirectImmediateWord, LDSource::A) => {
// LD (u16), A | Store accumulator in byte at 16-bit register
let word = cpu.imm_word();
cpu.write_byte(word, cpu.register(CpuRegister::A));
let addr = Self::imm_word(cpu);
let acc = cpu.register(CpuRegister::A);
Self::write_byte(&mut cpu.bus, addr, acc);
Cycle::new(16)
}
(LDTarget::A, LDSource::IndirectImmediateWord) => {
// LD A, (u16) | Store byte at 16-bit register in accumulator
let addr = cpu.imm_word();
let byte = cpu.read_byte(addr);
let addr = Self::imm_word(cpu);
let byte = Self::read_byte(&mut cpu.bus, addr);
cpu.set_register(CpuRegister::A, byte);
Cycle::new(16)
}
@@ -283,14 +288,14 @@ impl Instruction {
// JR i8 | Add i8 bytes from program counter
let flags: Flags = *cpu.flags();
let byte = cpu.imm_byte(); // Note: This modifies the PC we access immediately after
let byte = Self::imm_byte(cpu) as i8; // Note: This modifies the PC we access immediately after
let pc = cpu.register_pair(RegisterPair::PC);
let addr = pc.wrapping_add(byte as i8 as u16);
let addr = pc.wrapping_add(byte as u16);
match cond {
JumpCondition::NotZero => {
if !flags.z() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(12)
} else {
Cycle::new(8)
@@ -298,7 +303,7 @@ impl Instruction {
}
JumpCondition::Zero => {
if flags.z() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(12)
} else {
Cycle::new(8)
@@ -306,7 +311,7 @@ impl Instruction {
}
JumpCondition::NotCarry => {
if !flags.c() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(12)
} else {
Cycle::new(8)
@@ -314,14 +319,14 @@ impl Instruction {
}
JumpCondition::Carry => {
if flags.c() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(12)
} else {
Cycle::new(8)
}
}
JumpCondition::Always => {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(12)
}
}
@@ -329,6 +334,7 @@ impl Instruction {
Instruction::ADD(target, src) => match (target, src) {
(AddTarget::HL, AddSource::Group1(pair)) => {
// ADD HL, r16 | Add 16-bit register to HL
// FIXME: Memory Timings are not properly emulated for this instruction
use Group1RegisterPair::*;
let mut flags: Flags = *cpu.flags();
@@ -359,7 +365,7 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let right = cpu.read_byte(addr);
let right = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(8), Self::add(left, right, &mut flags))
}
};
@@ -370,10 +376,11 @@ impl Instruction {
}
(AddTarget::SP, AddSource::ImmediateSignedByte) => {
// ADD SP, i8 | Add i8 to stack pointer
// FIXME: Memory Timings are not properly emulated for this instruction
let mut flags: Flags = *cpu.flags();
let left = cpu.register_pair(RegisterPair::SP);
let sum = Self::add_u16_i8(left, cpu.imm_byte() as i8, &mut flags);
let sum = Self::add_u16_i8(left, Self::imm_byte(cpu) as i8, &mut flags);
cpu.set_register_pair(RegisterPair::SP, sum);
cpu.set_flags(flags);
Cycle::new(16)
@@ -383,7 +390,7 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register(CpuRegister::A);
let sum = Self::add(left, cpu.imm_byte(), &mut flags);
let sum = Self::add(left, Self::imm_byte(cpu), &mut flags);
cpu.set_register(CpuRegister::A, sum);
cpu.set_flags(flags);
Cycle::new(8)
@@ -405,7 +412,8 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, Self::inc(cpu.read_byte(addr), &mut flags));
let left = Self::read_byte(&mut cpu.bus, addr);
Self::write_byte(&mut cpu.bus, addr, Self::inc(left, &mut flags));
Cycle::new(12)
}
};
@@ -415,6 +423,7 @@ impl Instruction {
AllRegisters::Group1(pair) => {
// INC r16 | Increment 16-bit register
// Note: No flags are set with this version of the INC instruction
// FIXME: Memory Timings are not properly emulated for this instruction
use Group1RegisterPair::*;
match pair {
@@ -443,7 +452,8 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
cpu.write_byte(addr, Self::dec(cpu.read_byte(addr), &mut flags));
let left = Self::read_byte(&mut cpu.bus, addr);
Self::write_byte(&mut cpu.bus, addr, Self::dec(left, &mut flags));
Cycle::new(12)
}
};
@@ -452,6 +462,7 @@ impl Instruction {
}
AllRegisters::Group1(pair) => {
// DEC r16 | Decrement Register Pair
// FIXME: Memory Timings are not properly emulated for this instruction
use Group1RegisterPair::*;
match pair {
@@ -578,12 +589,10 @@ impl Instruction {
Instruction::HALT => {
// HALT | Enter CPU low power consumption mode until interrupt occurs
use HaltState::*;
let req = cpu.read_byte(0xFF0F);
let enabled = cpu.read_byte(0xFFFF);
let halt_state = match *cpu.ime() {
ImeState::Enabled => ImeEnabled,
_ if req & enabled != 0 => SomePending,
_ if cpu.int_request() & cpu.int_enable() != 0 => SomePending,
_ => NonePending,
};
cpu.halt(halt_state);
@@ -604,7 +613,8 @@ impl Instruction {
(Cycle::new(4), sum)
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
let sum = Self::add_with_carry_bit(left, right, flags.c(), &mut flags);
(Cycle::new(8), sum)
}
@@ -618,7 +628,7 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register(CpuRegister::A);
let right = cpu.imm_byte();
let right = Self::imm_byte(cpu);
let sum = Self::add_with_carry_bit(left, right, flags.c(), &mut flags);
cpu.set_register(CpuRegister::A, sum);
cpu.set_flags(flags);
@@ -639,7 +649,8 @@ impl Instruction {
(Cycle::new(4), Self::sub(left, right, &mut flags))
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(8), Self::sub(left, right, &mut flags))
}
};
@@ -652,7 +663,7 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register(CpuRegister::A);
let right = cpu.imm_byte();
let right = Self::imm_byte(cpu);
cpu.set_register(CpuRegister::A, Self::sub(left, right, &mut flags));
cpu.set_flags(flags);
Cycle::new(8)
@@ -673,7 +684,8 @@ impl Instruction {
(Cycle::new(4), diff)
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
let diff = Self::sub_with_carry(left, right, flags.c(), &mut flags);
(Cycle::new(8), diff)
}
@@ -687,7 +699,8 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register(CpuRegister::A);
let diff = Self::sub_with_carry(left, cpu.imm_byte(), flags.c(), &mut flags);
let right = Self::imm_byte(cpu);
let diff = Self::sub_with_carry(left, right, flags.c(), &mut flags);
cpu.set_register(CpuRegister::A, diff);
cpu.set_flags(flags);
Cycle::new(8)
@@ -704,7 +717,8 @@ impl Instruction {
(Cycle::new(4), left & cpu.register(reg.cpu_register()))
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(8), left & right)
}
};
@@ -714,7 +728,7 @@ impl Instruction {
}
AluSource::ImmediateByte => {
// AND u8 | Perform bitwise AND on accumulator and u8
let acc = cpu.register(CpuRegister::A) & cpu.imm_byte();
let acc = cpu.register(CpuRegister::A) & Self::imm_byte(cpu);
cpu.set_register(CpuRegister::A, acc);
cpu.update_flags(acc == 0, false, true, false);
Cycle::new(8)
@@ -731,7 +745,8 @@ impl Instruction {
(Cycle::new(4), left ^ cpu.register(reg.cpu_register()))
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(8), left ^ right)
}
};
@@ -741,7 +756,7 @@ impl Instruction {
}
AluSource::ImmediateByte => {
// XOR u8 | Perform bitwise XOR on accumulator and u8
let acc = cpu.register(CpuRegister::A) ^ cpu.imm_byte();
let acc = cpu.register(CpuRegister::A) ^ Self::imm_byte(cpu);
cpu.set_register(CpuRegister::A, acc);
cpu.update_flags(acc == 0, false, false, false);
Cycle::new(8)
@@ -758,7 +773,8 @@ impl Instruction {
(Cycle::new(4), left | cpu.register(reg.cpu_register()))
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(8), left | right)
}
};
@@ -768,7 +784,7 @@ impl Instruction {
}
AluSource::ImmediateByte => {
// OR u8 | Perform bitwise OR on accumulator and u8
let acc = cpu.register(CpuRegister::A) | cpu.imm_byte();
let acc = cpu.register(CpuRegister::A) | Self::imm_byte(cpu);
cpu.set_register(CpuRegister::A, acc);
cpu.update_flags(acc == 0, false, false, false);
Cycle::new(8)
@@ -788,7 +804,8 @@ impl Instruction {
Cycle::new(4)
}
IndirectHL => {
let right = cpu.read_byte(cpu.register_pair(RegisterPair::HL));
let addr = cpu.register_pair(RegisterPair::HL);
let right = Self::read_byte(&mut cpu.bus, addr);
let _ = Self::sub(left, right, &mut flags);
Cycle::new(8)
}
@@ -801,7 +818,7 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register(CpuRegister::A);
let _ = Self::sub(left, cpu.imm_byte(), &mut flags);
let _ = Self::sub(left, Self::imm_byte(cpu), &mut flags);
cpu.set_flags(flags);
Cycle::new(8)
}
@@ -811,48 +828,57 @@ impl Instruction {
let mut flags: Flags = *cpu.flags();
let left = cpu.register_pair(RegisterPair::SP);
let sum = Self::add_u16_i8(left, cpu.imm_byte() as i8, &mut flags);
let sum = Self::add_u16_i8(left, Self::imm_byte(cpu) as i8, &mut flags);
cpu.set_register_pair(RegisterPair::HL, sum);
cpu.set_flags(flags);
cpu.bus.clock(); // FIXME: Is this in the right place?
Cycle::new(12)
}
Instruction::RET(cond) => {
// RET cond | Return from subroutine if condition is true
// RET | Return from subroutine
let flags: &Flags = cpu.flags();
let flags: Flags = *cpu.flags();
match cond {
JumpCondition::NotZero => {
cpu.bus.clock(); // internal branch decision
if !flags.z() {
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(20)
} else {
Cycle::new(8)
}
}
JumpCondition::Zero => {
cpu.bus.clock(); // internal branch decision
if flags.z() {
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(20)
} else {
Cycle::new(8)
}
}
JumpCondition::NotCarry => {
cpu.bus.clock(); // internal branch decision
if !flags.c() {
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(20)
} else {
Cycle::new(8)
}
}
JumpCondition::Carry => {
cpu.bus.clock(); // internal branch decision
if flags.c() {
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(20)
} else {
Cycle::new(8)
@@ -860,7 +886,7 @@ impl Instruction {
}
JumpCondition::Always => {
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
}
}
@@ -880,7 +906,7 @@ impl Instruction {
Instruction::RETI => {
// RETI | Return from subroutine, then enable interrupts
let addr = Self::pop(cpu);
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
cpu.set_ime(ImeState::Enabled);
Cycle::new(16)
}
@@ -896,12 +922,12 @@ impl Instruction {
// JP u16 | Store u16 in program counter
let flags: Flags = *cpu.flags();
let addr = cpu.imm_word();
let addr = Self::imm_word(cpu);
match cond {
JumpCondition::NotZero => {
if !flags.z() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
} else {
Cycle::new(12)
@@ -909,7 +935,7 @@ impl Instruction {
}
JumpCondition::Zero => {
if flags.z() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
} else {
Cycle::new(12)
@@ -917,7 +943,7 @@ impl Instruction {
}
JumpCondition::NotCarry => {
if !flags.c() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
} else {
Cycle::new(12)
@@ -925,14 +951,14 @@ impl Instruction {
}
JumpCondition::Carry => {
if flags.c() {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
} else {
Cycle::new(12)
}
}
JumpCondition::Always => {
cpu.set_register_pair(RegisterPair::PC, addr);
Self::jump(cpu, addr);
Cycle::new(16)
}
}
@@ -953,12 +979,13 @@ impl Instruction {
// CALL u16 | Push PC on the stack then store u16 in program counter
let flags: Flags = *cpu.flags();
let addr = cpu.imm_word();
let addr = Self::imm_word(cpu);
let return_addr = cpu.register_pair(RegisterPair::PC);
match cond {
JumpCondition::NotZero => {
if !flags.z() {
cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr);
Cycle::new(24)
@@ -968,6 +995,7 @@ impl Instruction {
}
JumpCondition::Zero => {
if flags.z() {
cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr);
Cycle::new(24)
@@ -977,6 +1005,7 @@ impl Instruction {
}
JumpCondition::NotCarry => {
if !flags.c() {
cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr);
Cycle::new(24)
@@ -986,6 +1015,7 @@ impl Instruction {
}
JumpCondition::Carry => {
if flags.c() {
cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr);
Cycle::new(24)
@@ -994,6 +1024,7 @@ impl Instruction {
}
}
JumpCondition::Always => {
cpu.bus.clock(); // internal branch decision
Self::push(cpu, return_addr);
cpu.set_register_pair(RegisterPair::PC, addr);
Cycle::new(24)
@@ -1004,6 +1035,8 @@ impl Instruction {
// PUSH r16 | Push r16 onto the stack
use Group3RegisterPair::*;
cpu.bus.clock(); // internal
match pair {
BC | DE | HL | AF => {
let word = cpu.register_pair(pair.as_register_pair());
@@ -1030,9 +1063,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let rotated = byte.rotate_left(1);
cpu.write_byte(addr, rotated);
Self::write_byte(&mut cpu.bus, addr, rotated);
(Cycle::new(16), byte >> 7, rotated)
}
};
@@ -1053,9 +1086,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let rotated = byte.rotate_right(1);
cpu.write_byte(addr, rotated);
Self::write_byte(&mut cpu.bus, addr, rotated);
(Cycle::new(16), byte & 0x01, rotated)
}
};
@@ -1078,9 +1111,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let (rotated, carry) = Self::rl_thru_carry(byte, flags.c());
cpu.write_byte(addr, rotated);
Self::write_byte(&mut cpu.bus, addr, rotated);
(Cycle::new(16), rotated, carry)
}
};
@@ -1103,9 +1136,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let (rotated, carry) = Self::rr_thru_carry(byte, flags.c());
cpu.write_byte(addr, rotated);
Self::write_byte(&mut cpu.bus, addr, rotated);
(Cycle::new(16), rotated, carry)
}
};
@@ -1126,9 +1159,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let shifted = byte << 1;
cpu.write_byte(addr, shifted);
Self::write_byte(&mut cpu.bus, addr, shifted);
(Cycle::new(16), (byte >> 7) & 0x01, shifted)
}
};
@@ -1149,9 +1182,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let shifted = ((byte >> 7) & 0x01) << 7 | byte >> 1;
cpu.write_byte(addr, shifted);
Self::write_byte(&mut cpu.bus, addr, shifted);
(Cycle::new(16), byte & 0x01, shifted)
}
};
@@ -1172,8 +1205,8 @@ impl Instruction {
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let swapped = Self::swap_bits(cpu.read_byte(addr));
cpu.write_byte(addr, swapped);
let swapped = Self::swap_bits(Self::read_byte(&mut cpu.bus, addr));
Self::write_byte(&mut cpu.bus, addr, swapped);
(Cycle::new(16), swapped)
}
};
@@ -1194,9 +1227,9 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
let shifted = byte >> 1;
cpu.write_byte(addr, shifted);
Self::write_byte(&mut cpu.bus, addr, shifted);
(Cycle::new(16), byte & 0x01, shifted)
}
};
@@ -1216,7 +1249,7 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
let byte = Self::read_byte(&mut cpu.bus, addr);
(Cycle::new(12), ((byte >> bit) & 0x01) == 0x01)
}
};
@@ -1239,8 +1272,8 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
cpu.write_byte(addr, byte & !(1 << bit));
let byte = Self::read_byte(&mut cpu.bus, addr);
Self::write_byte(&mut cpu.bus, addr, byte & !(1 << bit));
Cycle::new(16)
}
}
@@ -1258,8 +1291,8 @@ impl Instruction {
}
IndirectHL => {
let addr = cpu.register_pair(RegisterPair::HL);
let byte = cpu.read_byte(addr);
cpu.write_byte(addr, byte | (1u8 << bit));
let byte = Self::read_byte(&mut cpu.bus, addr);
Self::write_byte(&mut cpu.bus, addr, byte | (1u8 << bit));
Cycle::new(16)
}
}
@@ -1269,14 +1302,14 @@ impl Instruction {
/// PUSHes a u16 onto the stack
///
/// Mutates the stack pointer and the stack
/// Mutates the stack pointer and the stack (8 cycles)
fn push(cpu: &mut Cpu, value: u16) {
let mut sp = cpu.register_pair(RegisterPair::SP);
sp -= 1;
cpu.write_byte(sp, (value >> 8) as u8);
Self::write_byte(&mut cpu.bus, sp, (value >> 8) as u8);
sp -= 1;
cpu.write_byte(sp, value as u8);
Self::write_byte(&mut cpu.bus, sp, value as u8);
cpu.set_register_pair(RegisterPair::SP, sp);
}
@@ -1284,12 +1317,13 @@ impl Instruction {
/// POPs a u16 from the stack
///
/// Mutates the stack pointer and returns the u16 which was popped from the stack
/// (8 cycles)
fn pop(cpu: &mut Cpu) -> u16 {
let mut sp = cpu.register_pair(RegisterPair::SP);
let low = cpu.read_byte(sp);
let low = Self::read_byte(&mut cpu.bus, sp);
sp += 1;
let high = cpu.read_byte(sp);
let high = Self::read_byte(&mut cpu.bus, sp);
sp += 1;
cpu.set_register_pair(RegisterPair::SP, sp);
@@ -1441,11 +1475,68 @@ impl Instruction {
}
pub(crate) fn reset(cpu: &mut Cpu, vector: u8) -> Cycle {
cpu.bus.clock(); // internal
let addr = cpu.register_pair(RegisterPair::PC);
Self::push(cpu, addr);
cpu.set_register_pair(RegisterPair::PC, vector as u16);
Cycle::new(16)
}
/// Read u8 from memory (4 cycles)
fn read_byte(bus: &mut Bus, addr: u16) -> u8 {
let byte = bus.read_byte(addr);
bus.clock();
byte
}
/// Write u8 to memory (4 cycles)
fn write_byte(bus: &mut Bus, addr: u16, byte: u8) {
bus.write_byte(addr, byte);
bus.clock();
}
/// Write u16 to memory (8 cycles)
fn write_word(bus: &mut Bus, addr: u16, word: u16) {
Self::write_byte(bus, addr, word as u8);
Self::write_byte(bus, addr + 1, (word >> 8) as u8);
}
/// Read u16 from memory (8 cycles)
fn read_word(bus: &mut Bus, addr: u16) -> u16 {
// Must preserve the order, can't one-line this.
let low = Self::read_byte(bus, addr);
let high = Self::read_byte(bus, addr + 1);
(high as u16) << 8 | low as u16
}
/// Fetch u16 from memory, increment the program counter by two
/// (8 cycles)
fn imm_word(cpu: &mut Cpu) -> u16 {
let pc = cpu.register_pair(RegisterPair::PC);
let word = Self::read_word(&mut cpu.bus, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 2);
word
}
/// Fetch u8 from memory, increment the program counter by one
/// (4 cycles)
fn imm_byte(cpu: &mut Cpu) -> u8 {
let pc = cpu.register_pair(RegisterPair::PC);
let byte = Self::read_byte(&mut cpu.bus, pc);
cpu.set_register_pair(RegisterPair::PC, pc + 1);
byte
}
/// Set program counter to Address.
///
/// This is explicitly meant to emulate the exact behaviour of JP, JR RET, RETI and CALL
/// (4 cycles)
fn jump(cpu: &mut Cpu, addr: u16) {
cpu.set_register_pair(RegisterPair::PC, addr);
cpu.bus.clock();
}
}
impl Instruction {