restructed

This commit is contained in:
Daniel Bauer
2019-12-27 11:10:43 +01:00
parent 6e315d6cc1
commit b2fad73cc5

View File

@@ -37,15 +37,17 @@ impl Debug for Registers {
} }
pub const STACK_BASE_ADDR: Addr = 0x0100; pub const STACK_BASE_ADDR: Addr = 0x0100;
pub const LO: Addr = 0x00FF;
pub const HI: Addr = 0xFFFF;
pub const CARRY: Byte = 1 << 0; pub const CARRY: Byte = 1 << 0; // 0000 0001 0x01
pub const ZERO: Byte = 1 << 1; pub const ZERO: Byte = 1 << 1; // 0000 0010 0x02
pub const IRQ: Byte = 1 << 2; pub const IRQ: Byte = 1 << 2; // 0000 0100 0x04
pub const DECIMAL: Byte = 1 << 3; pub const DECIMAL: Byte = 1 << 3; // 0000 1000 0x08
pub const BREAK: Byte = 1 << 4; pub const BREAK: Byte = 1 << 4; // 0001 0000 0x10
pub const UNUSED: Byte = 1 << 5; pub const UNUSED: Byte = 1 << 5; // 0010 0000 0x20
pub const OVERFLOW: Byte = 1 << 6; pub const OVERFLOW: Byte = 1 << 6; // 0100 0000 0x40
pub const NEGATIVE: Byte = 1 << 7; pub const NEGATIVE: Byte = 1 << 7; // 1000 0000 0x80
pub struct CPU { pub struct CPU {
pub regs: Registers, pub regs: Registers,
@@ -130,6 +132,36 @@ impl CPU {
val val
} }
// Pop a byte from the SP
fn popb_sp<T: Memory>(&mut self, bus: &T) -> Byte {
self.regs.sp += 1;
let val = self.readb(bus, STACK_BASE_ADDR + self.regs.sp as Word);
val
}
// Pop a word from the stack
fn popw_sp<T: Memory>(&mut self, bus: &T) -> Word {
let hi = self.popb_sp(bus);
let lo = self.popb_sp(bus);
(hi << 8) as Word & lo as Word
}
// Push a byte to the SP.
fn pushb_sp<T: Memory>(&mut self, bus: &mut T, val: Byte) {
self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, val);
self.regs.sp -= 1;
}
// push a word to the stack, lo first, hi second
fn pushw_sp<T: Memory>(&mut self, bus: &mut T, val: Word) {
let lo = ((val >> 8) & LO) as Byte;
let hi = (val & LO) as Byte;
self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, lo);
self.regs.sp -= 1;
self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, hi);
self.regs.sp -= 1;
}
// Set the flag with the corresponding mask // Set the flag with the corresponding mask
fn set_flag(&mut self, flag: Byte, val: bool) { fn set_flag(&mut self, flag: Byte, val: bool) {
if val { if val {
@@ -154,7 +186,6 @@ impl CPU {
// Jump to address // Jump to address
fn jump(&mut self, addr: Addr) { fn jump(&mut self, addr: Addr) {
let old_addr = self.regs.pc;
self.regs.pc = addr; self.regs.pc = addr;
} }
@@ -256,19 +287,19 @@ impl CPU {
// Absolute address on zero page // Absolute address on zero page
fn am_ZP0<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_ZP0<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readb_pc(bus); let addr = self.readb_pc(bus);
(0x00ff & addr as Word, false) (LO & addr as Word, false)
} }
// Absolute address on zero page with x offset // Absolute address on zero page with x offset
fn am_ZPX<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_ZPX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readb_pc(bus) + self.regs.x; let addr = self.readb_pc(bus) + self.regs.x;
(0x00ff & addr as Word , false) (LO & addr as Word , false)
} }
// Absolute address on zero page with y offset // Absolute address on zero page with y offset
fn am_ZPY<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_ZPY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readb_pc(bus) + self.regs.y; let addr = self.readb_pc(bus) + self.regs.y;
(0x00ff & addr as Word, false) (LO & addr as Word, false)
} }
// Absolute address. Next 2 bytes of pc are the address // Absolute address. Next 2 bytes of pc are the address
@@ -283,7 +314,8 @@ impl CPU {
let tmp_addr = self.readw_pc(bus); let tmp_addr = self.readw_pc(bus);
let addr = tmp_addr + self.regs.x as Word; let addr = tmp_addr + self.regs.x as Word;
(addr, addr & 0xFF00 != tmp_addr & 0xF00) let page_cross = addr & HI != tmp_addr & HI;
(addr, page_cross)
} }
// Absolute address with offset. Next 2 bytes of pc are the address // Absolute address with offset. Next 2 bytes of pc are the address
@@ -292,18 +324,23 @@ impl CPU {
let tmp_addr = self.readw_pc(bus); let tmp_addr = self.readw_pc(bus);
let addr = tmp_addr + self.regs.y as Word; let addr = tmp_addr + self.regs.y as Word;
(addr, addr & 0xFF00 != tmp_addr & 0xF00) let page_cross = addr & HI != tmp_addr & HI;
(addr, page_cross)
} }
// Relative addressing. Only used for branching. The next byte on the // Relative addressing. Only used for branching. The next byte on the
// pc is a signed offset from the current pc location // pc is a signed offset from the current pc location
fn am_REL<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_REL<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let rel_addr = self.readb_pc(bus) as Word; let rel_addr = self.readb_pc(bus) as Word;
if rel_addr < 0x80 { let base_addr = self.regs.pc;
(self.regs.pc + rel_addr, false)
// If rel_addr > 0x8000, we substract 256 to make a negative jump
let addr = if rel_addr < 128 {
base_addr + rel_addr
} else { } else {
(self.regs.pc + rel_addr - 256, false) base_addr + rel_addr - 256
} };
(addr, false)
} }
// 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
@@ -312,29 +349,32 @@ impl CPU {
// 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_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 ind_addr = self.readw_pc(bus);
// page boundary bug // page boundary bug: If LO is 0x00FF, we are at the page border
let lo = ind_addr & 0b00001111; // and need to wrap around. So hi is fetched from 0x0000 instead of
if lo == 0x00FF { // 0x0100
ind_addr -= 0x00FF; let addr = if ind_addr & LO == 0x00FF {
} let lo = self.readb(bus, ind_addr);
let hi_addr = ind_addr - 0x00FF;
let hi = self.readb(bus, hi_addr);
((hi << 8) as Word | lo as Word)
} else { // normal behaviour
self.readw(bus, ind_addr)
};
let addr = bus.readw(ind_addr);
(addr, false) (addr, false)
} }
// the next 8 bits + x are an address. This address stores the real address // the next 8 bits + x are an address on the zero page. 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
// must be read from the next page. Instead it wraps around and reads from
// the same page!
fn am_IZX<T: Memory>(&mut self, bus: &T) -> (Word, bool) { fn am_IZX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let mut ind_addr = self.readb_pc(bus) as Word; let ind_addr = self.readb_pc(bus);
ind_addr += self.regs.x as Word;
let addr = bus.readw(ind_addr & 0x00FF); // since its a zero page addr, we are only interested in low
(addr, false) let addr = ind_addr.wrapping_add(self.regs.x);
(addr as Word, false)
} }
// the next 8 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
@@ -343,10 +383,12 @@ impl CPU {
// 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 tmp_addr = self.readb_pc(bus) as Word; let ind_addr = self.readb_pc(bus);
let addr = self.readw(bus, tmp_addr & 0x00FF);
(addr, addr & 0xFF00 != tmp_addr & 0xF00) // since its a zero page addr, we are only interested in low
let addr = ind_addr.wrapping_add(self.regs.y);
(addr as Word, false)
} }
// Operations // Operations