cpu bugs, wrapping adds/subs

This commit is contained in:
Daniel Bauer
2019-12-25 20:02:40 +01:00
parent f56fc05579
commit 6a6ea79a62

View File

@@ -146,8 +146,8 @@ impl CPU {
fn run_instruction<T: Memory>(&mut self, bus: &mut T, i: &Instruction) -> u8 { fn run_instruction<T: Memory>(&mut self, bus: &mut T, i: &Instruction) -> u8 {
let (value, page_cross) = match &i.addr_mode { let (value, page_cross) = match &i.addr_mode {
AddrMode::IMP => self.am_IMP(bus), AddrMode::IMP => self.am_IMP(),
AddrMode::IMM => self.am_IMM(bus), AddrMode::IMM => self.am_IMM(),
AddrMode::ZP0 => self.am_ZP0(bus), AddrMode::ZP0 => self.am_ZP0(bus),
AddrMode::ZPX => self.am_ZPX(bus), AddrMode::ZPX => self.am_ZPX(bus),
AddrMode::ZPY => self.am_ZPY(bus), AddrMode::ZPY => self.am_ZPY(bus),
@@ -170,15 +170,15 @@ impl CPU {
Operation::BEQ => self.op_BEQ(bus, value), Operation::BEQ => self.op_BEQ(bus, value),
Operation::BIT => self.op_BIT(bus, value), Operation::BIT => self.op_BIT(bus, value),
Operation::BMI => self.op_BMI(bus, value), Operation::BMI => self.op_BMI(bus, value),
Operation::BNE => self.op_BNE(bus, value), Operation::BNE => self.op_BNE(value),
Operation::BPL => self.op_BPL(bus, value), Operation::BPL => self.op_BPL(bus, value),
Operation::BRK => self.op_BRK(bus, value), Operation::BRK => self.op_BRK(bus, value),
Operation::BVC => self.op_BVC(bus, value), Operation::BVC => self.op_BVC(bus, value),
Operation::BVS => self.op_BVS(bus, value), Operation::BVS => self.op_BVS(bus, value),
Operation::CLC => self.op_CLC(), Operation::CLC => self.op_CLC(),
Operation::CLD => self.op_CLD(bus, value), Operation::CLD => self.op_CLD(),
Operation::CLI => self.op_CLI(bus, value), Operation::CLI => self.op_CLI(),
Operation::CLV => self.op_CLV(bus, value), Operation::CLV => self.op_CLV(),
Operation::CMP => self.op_CMP(bus, value), Operation::CMP => self.op_CMP(bus, value),
Operation::CPX => self.op_CPX(bus, value), Operation::CPX => self.op_CPX(bus, value),
Operation::CPY => self.op_CPY(bus, value), Operation::CPY => self.op_CPY(bus, value),
@@ -208,7 +208,7 @@ impl CPU {
Operation::SBC => self.op_SBC(bus, value), Operation::SBC => self.op_SBC(bus, value),
Operation::SEC => self.op_SEC(bus, value), Operation::SEC => self.op_SEC(bus, value),
Operation::SED => self.op_SED(bus, value), Operation::SED => self.op_SED(bus, value),
Operation::SEI => self.op_SEI(bus, value), Operation::SEI => self.op_SEI(),
Operation::STA => self.op_STA(bus, value), Operation::STA => self.op_STA(bus, value),
Operation::STX => self.op_STX(bus, value), Operation::STX => self.op_STX(bus, value),
Operation::STY => self.op_STY(bus, value), Operation::STY => self.op_STY(bus, value),
@@ -228,12 +228,12 @@ impl CPU {
} }
// Implied aka no target // Implied aka no target
fn am_IMP<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_IMP(&mut self) -> (Word, bool) {
(0, false) (0, false)
} }
// Immediate, next byte comes from pc // Immediate, next byte comes from pc
fn am_IMM<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_IMM(&mut self) -> (Word, bool) {
let addr = self.regs.pc; let addr = self.regs.pc;
self.regs.pc += 1; self.regs.pc += 1;
(addr, false) (addr, false)
@@ -271,14 +271,20 @@ impl CPU {
(addr, false) (addr, false)
} }
// additional cycle on page wrap
fn am_ABX<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_ABX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readw_pc(bus) + self.regs.x as Word; let tmp_addr = self.readw_pc(bus);
(addr, false) let addr = tmp_addr + self.regs.x as Word;
(addr, addr & 0xFF00 != tmp_addr & 0xF00)
} }
// additional cycle on page wrap
fn am_ABY<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_ABY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readw_pc(bus) + self.regs.y as Word; let tmp_addr = self.readw_pc(bus);
(addr, false) let addr = tmp_addr + self.regs.y as Word;
(addr, addr & 0xFF00 != tmp_addr & 0xF00)
} }
// the next 16 bits are an address. This address stores the real address // the next 16 bits are an address. This address stores the real address
@@ -289,17 +295,17 @@ impl CPU {
fn am_IND<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_IND<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let mut ind_addr = self.readw_pc(bus); let mut ind_addr = self.readw_pc(bus);
// page boundary bug
let lo = ind_addr & 0b00001111; let lo = ind_addr & 0b00001111;
if lo == 0x00FF { if lo == 0x00FF {
ind_addr -= 0x00FF; ind_addr -= 0x00FF;
} }
let addr = bus.readw(ind_addr); let addr = bus.readw(ind_addr);
(addr, false) (addr, false)
} }
// the next 16 bits + x are an address. This address stores the real address // the next 8 bits + x are an address. This address stores the real address
// that is used for the operation. // that is used for the operation.
// Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte // Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte
// must be read from the next page. Instead it wraps around and reads from // must be read from the next page. Instead it wraps around and reads from
@@ -308,33 +314,20 @@ impl CPU {
let mut ind_addr = self.readb_pc(bus) as Word; let mut ind_addr = self.readb_pc(bus) as Word;
ind_addr += self.regs.x as Word; ind_addr += self.regs.x as Word;
let lo = ind_addr & 0b00001111; let addr = bus.readw(ind_addr & 0x00FF);
if lo == 0x00FF {
ind_addr -= 0x00FF;
}
let addr = bus.readw(ind_addr);
(addr, false) (addr, false)
} }
// the next 16 bits + y are an address. This address stores the real address // the next 8 bits + y are an address. This address stores the real address
// that is used for the operation. // that is used for the operation.
// Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte // Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte
// must be read from the next page. Instead it wraps around and reads from // must be read from the next page. Instead it wraps around and reads from
// the same page! // the same page!
fn am_IZY<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_IZY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let mut ind_addr = self.readb_pc(bus) as Word; let mut tmp_addr = self.readb_pc(bus) as Word;
ind_addr += self.regs.y as Word; let addr = self.readw(bus, tmp_addr & 0x00FF);
let lo = ind_addr & 0b00001111; (addr, addr & 0xFF00 != tmp_addr & 0xF00)
if lo == 0x00FF {
ind_addr -= 0x00FF;
}
let addr = bus.readw(ind_addr);
(addr, false)
} }
// Operations // Operations
@@ -342,12 +335,15 @@ impl CPU {
// Add to A // Add to A
fn op_ADC<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_ADC<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = self.readb(bus, addr) as Word; let val = self.readb(bus, addr) as Word;
let tmp = (self.regs.a as Word) + val + (self.get_flag(CARRY) as Word); let tmp1 = (self.regs.a as Word).overflowing_add(val);
self.set_flag(CARRY, (tmp & 0xFF) > 255); let tmp2 = tmp1.0.overflowing_add(self.get_flag(CARRY) as Word);
self.set_flag(ZERO, tmp == 0); let val = tmp2.0;
self.set_flag(NEGATIVE, (tmp & 0x80) == 1); let overflow = tmp1.1 || tmp2.1;
self.set_flag(OVERFLOW, !(((self.regs.a as Word) ^ tmp) & !((self.regs.a as Word) ^ val) & 0x80) == 1); self.set_flag(CARRY, (val & 0xFF) > 255);
self.regs.a = tmp as Byte; self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) == 1);
self.set_flag(OVERFLOW, overflow);
self.regs.a = val as Byte;
} }
fn op_AND<T: Memory>(&mut self, bus: &T, val: Word) { fn op_AND<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -378,8 +374,8 @@ impl CPU {
unimplemented!() unimplemented!()
} }
// Jump if 0 // Branch if 0 flag is set
fn op_BNE<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_BNE(&mut self, addr: Word) {
if self.get_flag(ZERO) == 0 { if self.get_flag(ZERO) == 0 {
let old_addr = self.regs.pc; let old_addr = self.regs.pc;
self.regs.pc = addr; self.regs.pc = addr;
@@ -409,18 +405,18 @@ impl CPU {
} }
// clear decimal flag // clear decimal flag
fn op_CLD<T: Memory>(&mut self, bus: &T, val: Word) { fn op_CLD(&mut self) {
self.set_flag(DECIMAL, false); self.set_flag(DECIMAL, false);
} }
// clear IRQ // clear IRQ
fn op_CLI<T: Memory>(&mut self, bus: &T, val: Word) { fn op_CLI(&mut self) {
self.set_flag(IRQ, false); self.set_flag(IRQ, false);
} }
// clear Overflow // clear Overflow
fn op_CLV<T: Memory>(&mut self, bus: &T, val: Word) { fn op_CLV(&mut self) {
self.set_flag(OVERFLOW, false); self.set_flag(OVERFLOW, false);
} }
@@ -442,14 +438,14 @@ impl CPU {
// Decrement X // Decrement X
fn op_DEX(&mut self) { fn op_DEX(&mut self) {
self.regs.x -= 1; self.regs.x = self.regs.x.wrapping_sub(1);
self.set_flag(ZERO, self.regs.x == 0); self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0) self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0)
} }
// Decrement Y // Decrement Y
fn op_DEY(&mut self) { fn op_DEY(&mut self) {
self.regs.y -= 1; self.regs.y = self.regs.y.wrapping_sub(1);
self.set_flag(ZERO, self.regs.y == 0); self.set_flag(ZERO, self.regs.y == 0);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
} }
@@ -463,13 +459,13 @@ impl CPU {
} }
fn op_INX<T: Memory>(&mut self, bus: &T) { fn op_INX<T: Memory>(&mut self, bus: &T) {
self.regs.x += 1; self.regs.x = self.regs.x.wrapping_add(1);
self.set_flag(ZERO, self.regs.x == 0); self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0) self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0)
} }
fn op_INY<T: Memory>(&mut self, bus: &T) { fn op_INY<T: Memory>(&mut self, bus: &T) {
self.regs.y += 1; self.regs.y = self.regs.y.wrapping_add(1);
self.set_flag(ZERO, self.regs.y == 0); self.set_flag(ZERO, self.regs.y == 0);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
} }
@@ -580,7 +576,7 @@ impl CPU {
} }
// set irq flag // set irq flag
fn op_SEI<T: Memory>(&mut self, bus: &T, val: Word) { fn op_SEI(&mut self) {
self.set_flag(IRQ, true); self.set_flag(IRQ, true);
} }