fix: call opcode now pushes correct address onto stack
This commit is contained in:
parent
c0b8b8bda2
commit
386a780a6f
28
src/cpu.rs
28
src/cpu.rs
|
@ -91,29 +91,19 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
pub fn dbg_read_byte(&self, addr: u16) -> u8 {
|
pub fn read_imm_byte(&mut self, addr: u16) -> u8 {
|
||||||
|
self.inc_pc();
|
||||||
self.bus.read_byte(addr)
|
self.bus.read_byte(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dbg_write_byte(&mut self, addr: u16, byte: u8) {
|
pub fn read_imm_word(&mut self, addr: u16) -> u16 {
|
||||||
self.bus.write_byte(addr, byte);
|
self.inc_pc();
|
||||||
}
|
self.inc_pc();
|
||||||
|
|
||||||
pub fn dbg_read_word(&self, addr: u16) -> u16 {
|
|
||||||
self.bus.read_word(addr)
|
self.bus.read_word(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dbg_write_word(&mut self, addr: u16, word: u16) {
|
|
||||||
self.bus.write_word(addr, word)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cpu {
|
|
||||||
pub fn read_byte(&mut self, addr: u16) -> u8 {
|
pub fn read_byte(&mut self, addr: u16) -> u8 {
|
||||||
let byte = self.bus.read_byte(addr);
|
self.bus.read_byte(addr)
|
||||||
self.inc_pc();
|
|
||||||
|
|
||||||
byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_byte(&mut self, addr: u16, byte: u8) {
|
pub fn write_byte(&mut self, addr: u16, byte: u8) {
|
||||||
|
@ -121,11 +111,7 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_word(&mut self, addr: u16) -> u16 {
|
pub fn read_word(&mut self, addr: u16) -> u16 {
|
||||||
let word = self.bus.read_word(addr);
|
self.bus.read_word(addr)
|
||||||
self.inc_pc();
|
|
||||||
self.inc_pc();
|
|
||||||
|
|
||||||
word
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_word(&mut self, addr: u16, word: u16) {
|
pub fn write_word(&mut self, addr: u16, word: u16) {
|
||||||
|
|
|
@ -1021,12 +1021,13 @@ impl Instruction {
|
||||||
// CALL cc[y], nn | Store nn on the stack, then store nn in the program coutner if cond is met
|
// CALL cc[y], nn | Store nn on the stack, then store nn in the program coutner if cond is met
|
||||||
// CALL nn | Store nn on the stack, then store nn in the program counter
|
// CALL nn | Store nn on the stack, then store nn in the program counter
|
||||||
let flags: Flags = cpu.register(Register::Flag).into();
|
let flags: Flags = cpu.register(Register::Flag).into();
|
||||||
|
let pc = cpu.register_pair(RegisterPair::PC);
|
||||||
|
|
||||||
match cond {
|
match cond {
|
||||||
JumpCondition::NotZero => {
|
JumpCondition::NotZero => {
|
||||||
if !flags.z {
|
if !flags.z {
|
||||||
Self::push(cpu, nn);
|
Self::push(cpu, nn);
|
||||||
cpu.set_register_pair(RegisterPair::PC, nn);
|
cpu.set_register_pair(RegisterPair::PC, pc + 1);
|
||||||
return Cycles(24);
|
return Cycles(24);
|
||||||
}
|
}
|
||||||
Cycles(12)
|
Cycles(12)
|
||||||
|
@ -1034,7 +1035,7 @@ impl Instruction {
|
||||||
JumpCondition::Zero => {
|
JumpCondition::Zero => {
|
||||||
if flags.z {
|
if flags.z {
|
||||||
Self::push(cpu, nn);
|
Self::push(cpu, nn);
|
||||||
cpu.set_register_pair(RegisterPair::PC, nn);
|
cpu.set_register_pair(RegisterPair::PC, pc + 1);
|
||||||
return Cycles(24);
|
return Cycles(24);
|
||||||
}
|
}
|
||||||
Cycles(12)
|
Cycles(12)
|
||||||
|
@ -1042,7 +1043,7 @@ impl Instruction {
|
||||||
JumpCondition::NotCarry => {
|
JumpCondition::NotCarry => {
|
||||||
if !flags.c {
|
if !flags.c {
|
||||||
Self::push(cpu, nn);
|
Self::push(cpu, nn);
|
||||||
cpu.set_register_pair(RegisterPair::PC, nn);
|
cpu.set_register_pair(RegisterPair::PC, pc + 1);
|
||||||
return Cycles(24);
|
return Cycles(24);
|
||||||
}
|
}
|
||||||
Cycles(12)
|
Cycles(12)
|
||||||
|
@ -1050,14 +1051,14 @@ impl Instruction {
|
||||||
JumpCondition::Carry => {
|
JumpCondition::Carry => {
|
||||||
if flags.c {
|
if flags.c {
|
||||||
Self::push(cpu, nn);
|
Self::push(cpu, nn);
|
||||||
cpu.set_register_pair(RegisterPair::PC, nn);
|
cpu.set_register_pair(RegisterPair::PC, pc + 1);
|
||||||
return Cycles(24);
|
return Cycles(24);
|
||||||
}
|
}
|
||||||
Cycles(12)
|
Cycles(12)
|
||||||
}
|
}
|
||||||
JumpCondition::Always => {
|
JumpCondition::Always => {
|
||||||
Self::push(cpu, nn);
|
Self::push(cpu, nn);
|
||||||
cpu.set_register_pair(RegisterPair::PC, nn);
|
cpu.set_register_pair(RegisterPair::PC, pc + 1);
|
||||||
Cycles(24)
|
Cycles(24)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1509,12 +1510,10 @@ impl Instruction {
|
||||||
fn push(cpu: &mut Cpu, value: u16) {
|
fn push(cpu: &mut Cpu, value: u16) {
|
||||||
let mut sp = cpu.register_pair(RegisterPair::SP);
|
let mut sp = cpu.register_pair(RegisterPair::SP);
|
||||||
|
|
||||||
// FIXME: Are these debug functions really necessary?
|
|
||||||
|
|
||||||
sp -= 1;
|
sp -= 1;
|
||||||
cpu.dbg_write_byte(sp, (value >> 8) as u8);
|
cpu.write_byte(sp, (value >> 8) as u8);
|
||||||
sp -= 1;
|
sp -= 1;
|
||||||
cpu.dbg_write_byte(sp, value as u8);
|
cpu.write_byte(sp, value as u8);
|
||||||
|
|
||||||
cpu.set_register_pair(RegisterPair::SP, sp);
|
cpu.set_register_pair(RegisterPair::SP, sp);
|
||||||
}
|
}
|
||||||
|
@ -1525,11 +1524,9 @@ impl Instruction {
|
||||||
fn pop(cpu: &mut Cpu) -> u16 {
|
fn pop(cpu: &mut Cpu) -> u16 {
|
||||||
let mut sp = cpu.register_pair(RegisterPair::SP);
|
let mut sp = cpu.register_pair(RegisterPair::SP);
|
||||||
|
|
||||||
// FIXME: Are these debug functions really necessary?
|
let low = cpu.read_byte(sp);
|
||||||
|
|
||||||
let low = cpu.dbg_read_byte(sp);
|
|
||||||
sp += 1;
|
sp += 1;
|
||||||
let high = cpu.dbg_read_byte(sp);
|
let high = cpu.read_byte(sp);
|
||||||
sp += 1;
|
sp += 1;
|
||||||
|
|
||||||
cpu.set_register_pair(RegisterPair::SP, sp);
|
cpu.set_register_pair(RegisterPair::SP, sp);
|
||||||
|
@ -1664,16 +1661,16 @@ impl Instruction {
|
||||||
(0, 0, _, 0, _) => Self::NOP, // NOP
|
(0, 0, _, 0, _) => Self::NOP, // NOP
|
||||||
(0, 0, _, 1, _) => Self::LD(
|
(0, 0, _, 1, _) => Self::LD(
|
||||||
// LD (nn), SP
|
// LD (nn), SP
|
||||||
LDTarget::ByteAtAddress(cpu.read_word(pc)),
|
LDTarget::ByteAtAddress(cpu.read_imm_word(pc)),
|
||||||
LDTarget::RegisterPair(RegisterPair::SP),
|
LDTarget::RegisterPair(RegisterPair::SP),
|
||||||
),
|
),
|
||||||
(0, 0, _, 2, _) => Self::STOP, // STOP
|
(0, 0, _, 2, _) => Self::STOP, // STOP
|
||||||
(0, 0, _, 3, _) => Self::JR(JumpCondition::Always, cpu.read_byte(pc) as i8), // JR d
|
(0, 0, _, 3, _) => Self::JR(JumpCondition::Always, cpu.read_imm_byte(pc) as i8), // JR d
|
||||||
(0, 0, _, 4..=7, _) => Self::JR(Table::cc(y - 4), cpu.read_byte(pc) as i8), // JR cc[y - 4], d
|
(0, 0, _, 4..=7, _) => Self::JR(Table::cc(y - 4), cpu.read_imm_byte(pc) as i8), // JR cc[y - 4], d
|
||||||
(0, 1, 0, _, _) => Self::LD(
|
(0, 1, 0, _, _) => Self::LD(
|
||||||
// LD rp[p], nn
|
// LD rp[p], nn
|
||||||
LDTarget::RegisterPair(Table::rp(p)),
|
LDTarget::RegisterPair(Table::rp(p)),
|
||||||
LDTarget::ImmediateWord(cpu.read_word(pc)),
|
LDTarget::ImmediateWord(cpu.read_imm_word(pc)),
|
||||||
),
|
),
|
||||||
(0, 1, 1, _, _) => Self::ADD(
|
(0, 1, 1, _, _) => Self::ADD(
|
||||||
// ADD HL, rp[p]
|
// ADD HL, rp[p]
|
||||||
|
@ -1739,7 +1736,7 @@ impl Instruction {
|
||||||
(0, 6, _, _, _) => Self::LD(
|
(0, 6, _, _, _) => Self::LD(
|
||||||
// LD r[y], n
|
// LD r[y], n
|
||||||
LDTarget::Register(Table::r(y)),
|
LDTarget::Register(Table::r(y)),
|
||||||
LDTarget::ImmediateByte(cpu.read_byte(pc)),
|
LDTarget::ImmediateByte(cpu.read_imm_byte(pc)),
|
||||||
),
|
),
|
||||||
(0, 7, _, 0, _) => Self::RLCA,
|
(0, 7, _, 0, _) => Self::RLCA,
|
||||||
(0, 7, _, 1, _) => Self::RRCA,
|
(0, 7, _, 1, _) => Self::RRCA,
|
||||||
|
@ -1759,20 +1756,20 @@ impl Instruction {
|
||||||
(3, 0, _, 0..=3, _) => Self::RET(Table::cc(y)), // RET cc[y]
|
(3, 0, _, 0..=3, _) => Self::RET(Table::cc(y)), // RET cc[y]
|
||||||
(3, 0, _, 4, _) => Self::LD(
|
(3, 0, _, 4, _) => Self::LD(
|
||||||
// LD (0xFF00 + n), A
|
// LD (0xFF00 + n), A
|
||||||
LDTarget::ByteAtAddressWithOffset(cpu.read_byte(pc)),
|
LDTarget::ByteAtAddressWithOffset(cpu.read_imm_byte(pc)),
|
||||||
LDTarget::Register(InstrRegister::A),
|
LDTarget::Register(InstrRegister::A),
|
||||||
),
|
),
|
||||||
(3, 0, _, 5, _) => Self::ADD(
|
(3, 0, _, 5, _) => Self::ADD(
|
||||||
// ADD SP, d
|
// ADD SP, d
|
||||||
MATHTarget::RegisterPair(RegisterPair::SP),
|
MATHTarget::RegisterPair(RegisterPair::SP),
|
||||||
MATHTarget::ImmediateByte(cpu.read_byte(pc)),
|
MATHTarget::ImmediateByte(cpu.read_imm_byte(pc)),
|
||||||
),
|
),
|
||||||
(3, 0, _, 6, _) => Self::LD(
|
(3, 0, _, 6, _) => Self::LD(
|
||||||
// LD A, (0xFF00 + n)
|
// LD A, (0xFF00 + n)
|
||||||
LDTarget::Register(InstrRegister::A),
|
LDTarget::Register(InstrRegister::A),
|
||||||
LDTarget::ByteAtAddressWithOffset(cpu.read_byte(pc)),
|
LDTarget::ByteAtAddressWithOffset(cpu.read_imm_byte(pc)),
|
||||||
),
|
),
|
||||||
(3, 0, _, 7, _) => Self::LDHL(cpu.read_byte(pc) as i8), // LD HL, SP + d
|
(3, 0, _, 7, _) => Self::LDHL(cpu.read_imm_byte(pc) as i8), // LD HL, SP + d
|
||||||
(3, 1, 0, _, _) => Self::POP(Table::rp2(p)), // POP rp2[p]
|
(3, 1, 0, _, _) => Self::POP(Table::rp2(p)), // POP rp2[p]
|
||||||
(3, 1, 1, _, 0) => Self::RET(JumpCondition::Always), // RET
|
(3, 1, 1, _, 0) => Self::RET(JumpCondition::Always), // RET
|
||||||
(3, 1, 1, _, 1) => Self::RETI,
|
(3, 1, 1, _, 1) => Self::RETI,
|
||||||
|
@ -1789,7 +1786,7 @@ impl Instruction {
|
||||||
(3, 2, _, 0..=3, _) => Self::JP(
|
(3, 2, _, 0..=3, _) => Self::JP(
|
||||||
// JP cc[y], nn
|
// JP cc[y], nn
|
||||||
Table::cc(y),
|
Table::cc(y),
|
||||||
JPTarget::ImmediateWord(cpu.read_word(pc)),
|
JPTarget::ImmediateWord(cpu.read_imm_word(pc)),
|
||||||
),
|
),
|
||||||
(3, 2, _, 4, _) => Self::LD(
|
(3, 2, _, 4, _) => Self::LD(
|
||||||
// LD (0xFF00 + C) ,A
|
// LD (0xFF00 + C) ,A
|
||||||
|
@ -1798,7 +1795,7 @@ impl Instruction {
|
||||||
),
|
),
|
||||||
(3, 2, _, 5, _) => Self::LD(
|
(3, 2, _, 5, _) => Self::LD(
|
||||||
// LD (nn), A
|
// LD (nn), A
|
||||||
LDTarget::ByteAtAddress(cpu.read_word(pc)),
|
LDTarget::ByteAtAddress(cpu.read_imm_word(pc)),
|
||||||
LDTarget::Register(InstrRegister::A),
|
LDTarget::Register(InstrRegister::A),
|
||||||
),
|
),
|
||||||
(3, 2, _, 6, _) => Self::LD(
|
(3, 2, _, 6, _) => Self::LD(
|
||||||
|
@ -1809,12 +1806,12 @@ impl Instruction {
|
||||||
(3, 2, _, 7, _) => Self::LD(
|
(3, 2, _, 7, _) => Self::LD(
|
||||||
// LD A, (nn)
|
// LD A, (nn)
|
||||||
LDTarget::Register(InstrRegister::A),
|
LDTarget::Register(InstrRegister::A),
|
||||||
LDTarget::ByteAtAddress(cpu.read_word(pc)),
|
LDTarget::ByteAtAddress(cpu.read_imm_word(pc)),
|
||||||
),
|
),
|
||||||
(3, 3, _, 0, _) => Self::JP(
|
(3, 3, _, 0, _) => Self::JP(
|
||||||
// JP nn
|
// JP nn
|
||||||
JumpCondition::Always,
|
JumpCondition::Always,
|
||||||
JPTarget::ImmediateWord(cpu.read_word(pc)),
|
JPTarget::ImmediateWord(cpu.read_imm_word(pc)),
|
||||||
),
|
),
|
||||||
(3, 3, _, 1, _) => unreachable!("This is the 0xCB Prefix"),
|
(3, 3, _, 1, _) => unreachable!("This is the 0xCB Prefix"),
|
||||||
// (3, 3, _, 2, _) => unreachable!(), ("removed" in documentation)
|
// (3, 3, _, 2, _) => unreachable!(), ("removed" in documentation)
|
||||||
|
@ -1823,12 +1820,12 @@ impl Instruction {
|
||||||
// (3, 3, _, 5, _) => unreachable!(), ("removed" in documentation)
|
// (3, 3, _, 5, _) => unreachable!(), ("removed" in documentation)
|
||||||
(3, 3, _, 6, _) => Self::DI,
|
(3, 3, _, 6, _) => Self::DI,
|
||||||
(3, 3, _, 7, _) => Self::EI,
|
(3, 3, _, 7, _) => Self::EI,
|
||||||
(3, 4, _, 0..=3, _) => Self::CALL(Table::cc(y), cpu.read_word(pc)), // CALL cc[y], nn
|
(3, 4, _, 0..=3, _) => Self::CALL(Table::cc(y), cpu.read_imm_word(pc)), // CALL cc[y], nn
|
||||||
// (3, 4, _, 4..=7, _) => unreachable!(), ("removed" in documentation)
|
// (3, 4, _, 4..=7, _) => unreachable!(), ("removed" in documentation)
|
||||||
(3, 5, 0, _, _) => Self::PUSH(Table::rp2(p)), // PUSH rp2[p]
|
(3, 5, 0, _, _) => Self::PUSH(Table::rp2(p)), // PUSH rp2[p]
|
||||||
(3, 5, 1, _, 0) => Self::CALL(JumpCondition::Always, cpu.read_word(pc)), // CALL nn
|
(3, 5, 1, _, 0) => Self::CALL(JumpCondition::Always, cpu.read_imm_word(pc)), // CALL nn
|
||||||
// (3, 5, 1, _, 1..=3) => unreachable!(), ("removed" in documentation)
|
// (3, 5, 1, _, 1..=3) => unreachable!(), ("removed" in documentation)
|
||||||
(3, 6, _, _, _) => Table::x3_alu(y, cpu.read_byte(pc)),
|
(3, 6, _, _, _) => Table::x3_alu(y, cpu.read_imm_byte(pc)),
|
||||||
(3, 7, _, _, _) => Self::RST(y * 8), // RST n
|
(3, 7, _, _, _) => Self::RST(y * 8), // RST n
|
||||||
_ => panic!(
|
_ => panic!(
|
||||||
"Unknown Opcode: {:#x?}\n x: {}, z: {}, q: {}, y: {}, p: {}",
|
"Unknown Opcode: {:#x?}\n x: {}, z: {}, q: {}, y: {}, p: {}",
|
||||||
|
@ -1839,7 +1836,7 @@ impl Instruction {
|
||||||
|
|
||||||
fn from_prefixed_byte(cpu: &mut Cpu) -> Self {
|
fn from_prefixed_byte(cpu: &mut Cpu) -> Self {
|
||||||
let pc = cpu.register_pair(RegisterPair::PC);
|
let pc = cpu.register_pair(RegisterPair::PC);
|
||||||
let opcode = cpu.read_byte(pc); // FIXME: Should the PC be incremented here?
|
let opcode = cpu.read_imm_byte(pc); // FIXME: Should the PC be incremented here?
|
||||||
|
|
||||||
// https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html
|
// https://gb-archive.github.io/salvage/decoding_gbz80_opcodes/Decoding%20Gamboy%20Z80%20Opcodes.html
|
||||||
let x = (opcode >> 6) & 0b00000011;
|
let x = (opcode >> 6) & 0b00000011;
|
||||||
|
|
Loading…
Reference in New Issue