more operations, better debugging

This commit is contained in:
Daniel Bauer
2019-12-25 19:21:30 +01:00
parent aa889f7e33
commit f56fc05579
3 changed files with 64 additions and 41 deletions

View File

@@ -62,7 +62,9 @@ fn main() {
// Create and reset CPU
let mut cpu: CPU = CPU::new();
cpu.reset(&bus);
cpu.find_pc_addr(&bus);
// cpu.reset(&bus);
// Prepare window and drawing resources
let mut window: PistonWindow = WindowSettings::new("NESemu", [256*3, 240*2])
@@ -192,12 +194,22 @@ fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, offset:
transform,
g
).unwrap();
transform = transform.trans(16.0, 0.0);
color = FT_COLOR_WHITE;
Text::new_color(color, FT_SIZE_PT).draw(
&format!("({:#4x})", cpu.regs.flags),
glyphs,
&c.draw_state,
transform,
g
).unwrap();
let cpu_register_texts = [
&format!("A: {:#x} ({})", cpu.regs.a, cpu.regs.a),
&format!("X: {:#x} ({})", cpu.regs.x, cpu.regs.y),
&format!("Y: {:#x} ({})", cpu.regs.y, cpu.regs.x),
&format!("Stack P: {:#x} ({})", cpu.regs.sp, cpu.regs.sp),
&format!("A: {0:#x} ({0})", cpu.regs.a),
&format!("X: {0:#x} ({0})", cpu.regs.x),
&format!("Y: {0:#x} ({0})", cpu.regs.y),
&format!("Stack P: {0:#x} ({0})", cpu.regs.sp),
&format!("Program P: {:#x}", cpu.regs.pc),
];
@@ -253,7 +265,7 @@ fn render_disasm(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, disasm: &Disasm,
fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &MemoryBus, offset: [f64; 2]) {
let mut transform_y = c.transform.trans(offset[0], offset[1]);
for page in (0x0000..0x00F0).step_by(16) {
for page in (0x0000..0x01FF).step_by(16) {
transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX);
Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw(
&format!("{:#06x}:", page),
@@ -277,7 +289,7 @@ fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &MemoryBus,
}
transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX) * 1.5);
for page in (0x8000..0x80F0).step_by(16) {
for page in (0x6000..0x6030).step_by(16) {
transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX));
Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw(
&format!("{:#06x}:", page),

View File

@@ -22,9 +22,9 @@ impl Registers {
a: 0,
x: 0,
y: 0,
sp: 0,
pc: 0,
flags: 0,
sp: 0x00FD,
pc: 0x0000,
flags: 0x0034,
}
}
}
@@ -36,6 +36,7 @@ impl Debug for Registers {
}
}
pub const STACK_BASE_ADDR: Addr = 0x0100;
pub const CARRY: Byte = 1 << 0;
pub const ZERO: Byte = 1 << 1;
@@ -79,24 +80,25 @@ impl CPU {
}
}
// Brings the CPU to a known state. Resets all registers and flags
// Read location of pc from 0xfffc
pub fn reset<T: Memory>(&mut self, bus: &T) {
// reset registers
self.regs.a = 0;
self.regs.x = 0;
self.regs.y = 0;
self.regs.sp = 0xfd;
self.regs.pc = 0x00;
self.regs.flags = 0x00 | UNUSED;
// sets PC
pub fn find_pc_addr<T: Memory>(&mut self, bus: &T) {
// 0xfffc and 0xfffc+1 stores the location of the first op code (where
// the program starts). Read it and set pc accordingly.
let addr: u16 = 0xfffc;
let lo = bus.readb(addr);
let hi = bus.readb(addr + 1);
self.regs.pc = (hi as u16) << 8 | lo as u16;
debug!("PC after reset: {:#06x}", self.regs.pc);
debug!("PC set to: {:#06x}", self.regs.pc);
}
// Brings the CPU to a known state. Resets all registers and flags
// Read location of pc from 0xfffc
pub fn reset<T: Memory>(&mut self, bus: &T) {
// reset registers
self.regs.sp = self.regs.sp - 3;
self.set_flag(IRQ, true);
self.find_pc_addr(bus);
// A reset takes 8 CPU clocks
self.cycles = 8;
@@ -185,8 +187,8 @@ impl CPU {
Operation::DEY => self.op_DEY(),
Operation::EOR => self.op_EOR(bus, value),
Operation::INC => self.op_INC(bus, value),
Operation::INX => self.op_INX(bus, value),
Operation::INY => self.op_INY(bus, value),
Operation::INX => self.op_INX(bus),
Operation::INY => self.op_INY(bus),
Operation::JMP => self.op_JMP(bus, value),
Operation::JSR => self.op_JSR(bus, value),
Operation::LDA => self.op_LDA(bus, value),
@@ -196,7 +198,7 @@ impl CPU {
Operation::NOP => self.op_NOP(bus, value),
Operation::ORA => self.op_ORA(bus, value),
Operation::PHA => self.op_PHA(bus, value),
Operation::PHP => self.op_PHP(bus, value),
Operation::PHP => self.op_PHP(bus),
Operation::PLA => self.op_PLA(bus, value),
Operation::PLP => self.op_PLP(bus, value),
Operation::ROL => self.op_ROL(bus, value),
@@ -212,7 +214,7 @@ impl CPU {
Operation::STY => self.op_STY(bus, value),
Operation::TAX => self.op_TAX(bus, value),
Operation::TAY => self.op_TAY(bus, value),
Operation::TSX => self.op_TSX(bus, value),
Operation::TSX => self.op_TSX(bus),
Operation::TXA => self.op_TXA(bus, value),
Operation::TXS => self.op_TXS(bus, value),
Operation::TYA => self.op_TYA(bus, value),
@@ -303,7 +305,7 @@ impl CPU {
// 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) {
let mut ind_addr = self.readw_pc(bus);
let mut ind_addr = self.readb_pc(bus) as Word;
ind_addr += self.regs.x as Word;
let lo = ind_addr & 0b00001111;
@@ -322,7 +324,7 @@ impl CPU {
// must be read from the next page. Instead it wraps around and reads from
// the same page!
fn am_IZY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let mut ind_addr = self.readw_pc(bus);
let mut ind_addr = self.readb_pc(bus) as Word;
ind_addr += self.regs.y as Word;
let lo = ind_addr & 0b00001111;
@@ -460,12 +462,16 @@ impl CPU {
unimplemented!()
}
fn op_INX<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!()
fn op_INX<T: Memory>(&mut self, bus: &T) {
self.regs.x += 1;
self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0)
}
fn op_INY<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!()
fn op_INY<T: Memory>(&mut self, bus: &T) {
self.regs.y += 1;
self.set_flag(ZERO, self.regs.y == 0);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
}
// Jump to address (set pc)
@@ -476,9 +482,9 @@ impl CPU {
// Jump to subroutine (leaves trace on the stack)
fn op_JSR<T: Memory>(&mut self, bus: &mut T, addr: Word) {
self.regs.pc -= 1;
bus.writeb(0x0100 + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte);
bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte);
self.regs.sp -= 1;
bus.writeb(0x0100 + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte);
bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte);
self.regs.sp -= 1;
self.regs.pc = addr;
}
@@ -524,18 +530,19 @@ impl CPU {
}
// Write flags to stack
fn op_PHP<T: Memory>(&mut self, bus: &mut T, val: Word) {
fn op_PHP<T: Memory>(&mut self, bus: &mut T) {
let tmp = self.regs.flags | BREAK | UNUSED;
bus.writeb(0x0100 + self.regs.sp as Word, tmp);
bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, tmp);
self.set_flag(BREAK, false);
self.set_flag(UNUSED, false);
self.regs.sp -= 1;
println!("PHP executed");
}
// Read from stack into A
fn op_PLA<T: Memory>(&mut self, bus: &T, val: Word) {
self.regs.sp += 1;
self.regs.a = bus.readb(0x0100 + self.regs.sp as Word);
self.regs.a = bus.readb(STACK_BASE_ADDR + self.regs.sp as Word);
self.set_flag(ZERO, self.regs.a == 0);
self.set_flag(NEGATIVE, (self.regs.a & 0x80) == 1)
}
@@ -606,8 +613,9 @@ impl CPU {
self.set_flag(NEGATIVE, (self.regs.y & 0x80) == 1)
}
fn op_TSX<T: Memory>(&mut self, bus: &T, val: Word) {
self.regs.x = bus.readb(0x0100 + self.regs.sp as Word);
// stack pointer to x
fn op_TSX<T: Memory>(&mut self, bus: &T) {
self.regs.x = self.regs.sp;
self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) == 1)
}

View File

@@ -44,11 +44,14 @@ impl Disasm {
let jmp_addr = Disasm::get_rel_addr(rel_addr, addr+2);
format!("#{:02x} => {:#06x}", rel_addr, jmp_addr)
},
AddrMode::IND | AddrMode::IZX | AddrMode::IZY=> {
AddrMode::IND => {
let addr = mem.readw(mem_iter.next().unwrap());
mem_iter.next().unwrap();
format!("{:#06x}", addr)
},
AddrMode::IZX | AddrMode::IZY => {
let addr = mem.readb(mem_iter.next().unwrap());
format!("{:#06x}", addr)
}
AddrMode::IMP => String::from(""),
_ => bail!("Disassembly of {} not implemented", i.addr_mode),