some bug fixes

This commit is contained in:
Daniel Bauer
2019-12-26 21:16:25 +01:00
parent 3a78650f99
commit c9e74e00f4
6 changed files with 112 additions and 59 deletions

View File

@@ -16,6 +16,7 @@ use nes::cartridge::*;
use nes::disasm::*; use nes::disasm::*;
use opengl_graphics::OpenGL; use opengl_graphics::OpenGL;
use log::Level; use log::Level;
use failure::Error;
use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush, Scale}; use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush, Scale};
use gfx_device_gl::{Resources,Factory}; use gfx_device_gl::{Resources,Factory};
@@ -25,19 +26,19 @@ const BG_COLOR: [f32; 4] = [0.0, 0.0, 252.0/256.0, 1.0];
// font options // font options
const FT_SIZE_PX: f32 = 11.0; const FT_SIZE_PX: f32 = 11.0;
const FT_COLOR_WHITE: [f32; 4] = [1.0; 4]; const FT_COLOR_WHITE: [f32; 4] = [1.0; 4];
const FT_COLOR_RED: [f32; 4] = [168.0/256.0, 0.0, 32.0/256.0, 1.0]; const FT_COLOR_RED: [f32; 4] = [168.0/256.0, 32.0/256.0, 0.0, 1.0];
const FT_COLOR_GREEN: [f32; 4] = [0.0, 168.0/256.0, 0.0, 1.0]; const FT_COLOR_GREEN: [f32; 4] = [0.0, 168.0/256.0, 0.0, 1.0];
const FT_LINE_DISTANCE: f32 = FT_SIZE_PX * 0.5; const FT_LINE_DISTANCE: f32 = FT_SIZE_PX * 0.5;
lazy_static! { lazy_static! {
static ref FT_SCALE: Scale = Scale::uniform(FT_SIZE_PX); static ref FT_SCALE: Scale = Scale::uniform(FT_SIZE_PX);
} }
fn main() { fn main() -> Result<(), Error> {
simple_logger::init_with_level(Level::Error).unwrap(); simple_logger::init_with_level(Level::Debug).unwrap();
let mut bus = MemoryBus::new(); let mut bus = MemoryBus::new();
let cartridge = Path::new("test_roms/registers.nes"); let cartridge = Path::new("test_roms/nestest.nes");
let cartridge = Cartridge::new(cartridge).unwrap(); let cartridge = Cartridge::new(cartridge)?;
bus.insert_cartrige(cartridge); bus.insert_cartrige(cartridge);
// Load little test program into ram // Load little test program into ram
@@ -55,7 +56,7 @@ fn main() {
// bus.writew(0xfffc, offset); // bus.writew(0xfffc, offset);
// disassemble instructions // disassemble instructions
let disasm = Disasm::disassemble(&bus, 0xe1ff, 0xffff-2).unwrap(); let disasm = Disasm::disassemble(&bus, 0xC000, 0xFFFF).unwrap();
// println!("{:?}", disasm.instructions); // println!("{:?}", disasm.instructions);
// return; // return;
// let disasm = Disasm::disassemble(&[], 0x000).unwrap(); // let disasm = Disasm::disassemble(&[], 0x000).unwrap();
@@ -63,6 +64,8 @@ fn main() {
// Create and reset CPU // Create and reset CPU
let mut cpu: CPU = CPU::new(); let mut cpu: CPU = CPU::new();
cpu.find_pc_addr(&bus); cpu.find_pc_addr(&bus);
cpu.regs.pc = 0xC000;
// return Ok(());
// cpu.reset(&bus); // cpu.reset(&bus);
// Prepare window and drawing resources // Prepare window and drawing resources
@@ -115,6 +118,7 @@ fn main() {
} }
} }
} }
Ok(())
} }
fn render(window: &mut PistonWindow, event: &Event, fn render(window: &mut PistonWindow, event: &Event,
@@ -220,6 +224,15 @@ fn render_cpu(glyphs: &mut GlyphBrush<Resources, Factory>, cpu: &CPU, offset: [f
color: color, color: color,
..Section::default() ..Section::default()
}); });
position.0 += 16.0;
let color = FT_COLOR_WHITE;
glyphs.queue(Section {
text: &format!("{:#06x}", cpu.regs.flags),
scale: *FT_SCALE,
screen_position: position,
color: color,
..Section::default()
});
let cpu_register_texts = [ let cpu_register_texts = [
&format!("A: {0:#x} ({0})", cpu.regs.a), &format!("A: {0:#x} ({0})", cpu.regs.a),
@@ -296,7 +309,7 @@ fn render_memory(glyphs: &mut GlyphBrush<Resources, Factory>, bus: &MemoryBus, o
} }
position_y.1 += FT_LINE_DISTANCE+FT_SIZE_PX * 1.5; position_y.1 += FT_LINE_DISTANCE+FT_SIZE_PX * 1.5;
for page in (0x6000..0x60FF).step_by(16) { for page in (0x2000..0x20FF).step_by(16) {
position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX;
let mut line = format!("{:#06x}:", page); let mut line = format!("{:#06x}:", page);
(0u16..16u16).map(|offset| offset + page) (0u16..16u16).map(|offset| offset + page)

View File

@@ -44,14 +44,14 @@ pub trait Clockable {
// A simple bus giving access to a chunk of memory // A simple bus giving access to a chunk of memory
// and the cartrige // and the cartrige
pub struct MemoryBus { pub struct MemoryBus {
ram: [Byte; 0x07ff], // 2kb ram: [Byte; 0x0800], // 2kb
cartrige: Option<Cartridge> cartrige: Option<Cartridge>
} }
impl MemoryBus { impl MemoryBus {
pub fn new() -> MemoryBus { pub fn new() -> MemoryBus {
MemoryBus { MemoryBus {
ram: [0; 0x07ff], ram: [0; 0x0800],
cartrige: None, cartrige: None,
} }
} }
@@ -65,12 +65,12 @@ impl Memory for MemoryBus {
fn readb(&self, addr: Addr) -> Byte { fn readb(&self, addr: Addr) -> Byte {
if let Some(cartrige) = &self.cartrige { if let Some(cartrige) = &self.cartrige {
if CART_ADDR_RANGE[0] <= addr && addr < CART_ADDR_RANGE[1] { if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] {
return cartrige.readb(addr) return cartrige.readb(addr)
} }
} }
if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] { if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] {
// Ram is 3x mirrored after 07ff // Ram is 3x mirrored after 07ff
return self.ram[(addr & 0x07ff) as usize] return self.ram[(addr & 0x07ff) as usize]
} }
@@ -79,12 +79,12 @@ impl Memory for MemoryBus {
fn writeb(&mut self, addr: Addr, data: Byte) { fn writeb(&mut self, addr: Addr, data: Byte) {
if let Some(cartrige) = &mut self.cartrige { if let Some(cartrige) = &mut self.cartrige {
if CART_ADDR_RANGE[0] <= addr && addr < CART_ADDR_RANGE[1] { if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] {
cartrige.writeb(addr, data) cartrige.writeb(addr, data)
} }
} }
if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] { if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] {
// Ram is 3x mirrored after 07ff // Ram is 3x mirrored after 07ff
self.ram[(addr & 0x07ff) as usize] = data self.ram[(addr & 0x07ff) as usize] = data
} }

View File

@@ -86,6 +86,8 @@ impl Cartridge {
id => bail!("Mapper {:04} not supported", id) id => bail!("Mapper {:04} not supported", id)
}; };
debug!("Cartrige loaded. mapper: {:?}", &mapper);
Ok(Cartridge { Ok(Cartridge {
prg_rom: prg_rom, prg_rom: prg_rom,
chr_rom: chr_rom, chr_rom: chr_rom,

View File

@@ -136,6 +136,11 @@ impl CPU {
} }
} }
fn set_flag_nz(&mut self, val: Byte) {
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) == 0);
}
pub fn get_flag(&self, flag: Byte) -> Byte { pub fn get_flag(&self, flag: Byte) -> Byte {
if self.regs.flags & flag > 0 { if self.regs.flags & flag > 0 {
1 1
@@ -340,9 +345,8 @@ impl CPU {
let val = tmp2.0; let val = tmp2.0;
let overflow = tmp1.1 || tmp2.1; let overflow = tmp1.1 || tmp2.1;
self.set_flag(CARRY, (val & 0xFF) > 255); self.set_flag(CARRY, (val & 0xFF) > 255);
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) == 1);
self.set_flag(OVERFLOW, overflow); self.set_flag(OVERFLOW, overflow);
self.set_flag_nz(val as Byte);
self.regs.a = val as Byte; self.regs.a = val as Byte;
} }
@@ -366,25 +370,44 @@ impl CPU {
unimplemented!() unimplemented!()
} }
fn op_BIT<T: Memory>(&mut self, bus: &T, val: Word) { // bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V);
unimplemented!() // the zeroflag is set to the result of operand AND accumulator.
fn op_BIT<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = self.readb(bus, addr);
self.set_flag(OVERFLOW, (val & OVERFLOW) == 1);
self.set_flag(NEGATIVE, (val & NEGATIVE) == 1);
println!("{:#06x}: {}", addr, val);
println!("{}", (val & self.regs.a));
self.set_flag(ZERO, (val & self.regs.a) == 0);
} }
fn op_BMI<T: Memory>(&mut self, bus: &T, val: Word) { // Jump to address
unimplemented!() fn jump(&mut self, addr: Addr) {
let old_addr = self.regs.pc;
self.regs.pc = addr;
println!("Jumping from {:#x} to {:#x}", old_addr, addr);
} }
// Branch if 0 flag is set
fn op_BNE(&mut self, addr: Word) { // Branch if negative flag is set
if self.get_flag(ZERO) == 0 { fn op_BMI<T: Memory>(&mut self, bus: &T, addr: Addr) {
let old_addr = self.regs.pc; if self.get_flag(NEGATIVE) == 1 {
self.regs.pc = addr; self.jump(addr);
println!("Jumping from {:#x} to {:#x}", old_addr, addr);
} }
} }
fn op_BPL<T: Memory>(&mut self, bus: &T, val: Word) { // Branch if 0 flag is set
unimplemented!() fn op_BNE(&mut self, addr: Addr) {
if self.get_flag(ZERO) == 0 {
self.jump(addr);
}
}
// Branch if negative flag is unset
fn op_BPL<T: Memory>(&mut self, bus: &T, addr: Addr) {
if self.get_flag(NEGATIVE) == 0 {
self.jump(addr);
}
} }
fn op_BRK<T: Memory>(&mut self, bus: &T, val: Word) { fn op_BRK<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -439,15 +462,13 @@ impl CPU {
// Decrement X // Decrement X
fn op_DEX(&mut self) { fn op_DEX(&mut self) {
self.regs.x = self.regs.x.wrapping_sub(1); self.regs.x = self.regs.x.wrapping_sub(1);
self.set_flag(ZERO, self.regs.x == 0); self.set_flag_nz(self.regs.x);
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 = self.regs.y.wrapping_sub(1); self.regs.y = self.regs.y.wrapping_sub(1);
self.set_flag(ZERO, self.regs.y == 0); self.set_flag_nz(self.regs.y);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
} }
fn op_EOR<T: Memory>(&mut self, bus: &T, val: Word) { fn op_EOR<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -458,25 +479,22 @@ impl CPU {
let val = self.readb(bus, addr); let val = self.readb(bus, addr);
let val = val.wrapping_add(1); let val = val.wrapping_add(1);
self.writeb(bus, addr, val); self.writeb(bus, addr, val);
self.set_flag(ZERO, val == 0); self.set_flag_nz(val);
self.set_flag(NEGATIVE, (val & 0x80) != 0)
} }
fn op_INX<T: Memory>(&mut self, bus: &T) { fn op_INX<T: Memory>(&mut self, bus: &T) {
self.regs.x = self.regs.x.wrapping_add(1); self.regs.x = self.regs.x.wrapping_add(1);
self.set_flag(ZERO, self.regs.x == 0); self.set_flag_nz(self.regs.x);
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 = self.regs.y.wrapping_add(1); self.regs.y = self.regs.y.wrapping_add(1);
self.set_flag(ZERO, self.regs.y == 0); self.set_flag_nz(self.regs.y);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
} }
// Jump to address (set pc) // Jump to address (set pc)
fn op_JMP<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_JMP<T: Memory>(&mut self, bus: &T, addr: Word) {
self.regs.pc = addr; self.jump(addr);
} }
// Jump to subroutine (leaves trace on the stack) // Jump to subroutine (leaves trace on the stack)
@@ -486,31 +504,28 @@ impl CPU {
self.regs.sp -= 1; self.regs.sp -= 1;
bus.writeb(STACK_BASE_ADDR + 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.sp -= 1;
self.regs.pc = addr; self.jump(addr);
} }
// Read value from addr into A // Read value from addr into A
fn op_LDA<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_LDA<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr); let val = bus.readb(addr);
self.regs.a = val; self.regs.a = val;
self.set_flag(ZERO, val == 0); self.set_flag_nz(val);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
// Read value from addr into X // Read value from addr into X
fn op_LDX<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_LDX<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr); let val = bus.readb(addr);
self.regs.x = val; self.regs.x = val;
self.set_flag(ZERO, val == 0); self.set_flag_nz(val);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
// Read value from addr into Y // Read value from addr into Y
fn op_LDY<T: Memory>(&mut self, bus: &T, addr: Word) { fn op_LDY<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr); let val = bus.readb(addr);
self.regs.y = val; self.regs.y = val;
self.set_flag(ZERO, val == 0); self.set_flag_nz(val);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
fn op_LSR<T: Memory>(&mut self, bus: &T, val: Word) { fn op_LSR<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -521,8 +536,9 @@ impl CPU {
// does nothing // does nothing
} }
fn op_ORA<T: Memory>(&mut self, bus: &T, val: Word) { fn op_ORA<T: Memory>(&mut self, bus: &T, addr: Addr) {
unimplemented!() self.regs.a |= self.readb(bus, addr);
self.set_flag_nz(self.regs.a);
} }
fn op_PHA<T: Memory>(&mut self, bus: &T, val: Word) { fn op_PHA<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -564,7 +580,12 @@ impl CPU {
} }
fn op_RTS<T: Memory>(&mut self, bus: &T, val: Word) { fn op_RTS<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() self.regs.sp += 1;
let lo = bus.readb(0x0100 + self.regs.sp as Addr);
self.regs.sp += 1;
let hi = bus.readb(0x0100 + self.regs.sp as Addr);
let addr = (hi as Addr) << 8 | lo as Addr;
self.regs.pc = addr + 1;
} }
fn op_SBC<T: Memory>(&mut self, bus: &T, val: Word) { fn op_SBC<T: Memory>(&mut self, bus: &T, val: Word) {

View File

@@ -20,16 +20,22 @@ impl Disasm {
pub fn disassemble(mem: &MemoryBus, start: Addr, stop: Addr) -> Result<Self, Error> { pub fn disassemble(mem: &MemoryBus, start: Addr, stop: Addr) -> Result<Self, Error> {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
let mut addresses = Vec::new(); let mut addresses = Vec::new();
let mut mem_iter = ((start as usize) .. (stop as usize)+1).map({|a| a as Addr}); let mut mem_iter = ((start as usize) .. (stop as usize)).map({|a| a as Addr});
while let Some(addr) = mem_iter.next() { while let Some(addr) = mem_iter.next() {
let opcode = mem.readb(addr); let opcode = mem.readb(addr);
// Decode opcode, default to NOP/IMP to "skip" the byte // Decode opcode, default to NOP/IMP to "skip" the byte
let i = Instruction::decode_op(opcode) let i = Instruction::decode_op(opcode)
.unwrap_or(Instruction::decode_op(0xeau8).unwrap()); .unwrap_or(Instruction::decode_op(0xeau8).unwrap());
// debug!("{:?}", i); // debug!("{:?}", i);
let args = match i.addr_mode { let args = match i.addr_mode {
AddrMode::IMM => format!("#{0:02x} ({0})", mem.readb(mem_iter.next().unwrap())), AddrMode::IMM => {
let val = mem.readb(mem_iter.next().unwrap());
format!("#{0:02x} ({0})", val)
},
AddrMode::ZP0 | AddrMode::ZPX | AddrMode::ZPY => { AddrMode::ZP0 | AddrMode::ZPX | AddrMode::ZPY => {
let rel_addr = mem.readb(mem_iter.next().unwrap()); let rel_addr = mem.readb(mem_iter.next().unwrap());
format!("{:#04x}", rel_addr) format!("{:#04x}", rel_addr)
@@ -58,9 +64,13 @@ impl Disasm {
}; };
let s = format!("{:#06x}: {} {} ({})", addr, i.operation, args, i.addr_mode); let s = format!("{:#06x}: {} {} ({})", addr, i.operation, args, i.addr_mode);
// debug!("{:#06x} {}", addr, &s); // println!("opcode: {:#04x} {:?}", opcode, i);
// println!("{}", &s);
instructions.push(s); instructions.push(s);
addresses.push(addr); addresses.push(addr);
} }
Ok(Disasm { start, stop, instructions, addresses }) Ok(Disasm { start, stop, instructions, addresses })
} }

View File

@@ -16,6 +16,7 @@ pub trait Mapper {
// Cartrige: // Cartrige:
// 0x4000-0xffff -> first 16K // 0x4000-0xffff -> first 16K
// 0xc000-0xffff -> last 16K or mirror or 0x8000-0xbfff // 0xc000-0xffff -> last 16K or mirror or 0x8000-0xbfff
#[derive(Debug)]
pub struct Mapper0 { pub struct Mapper0 {
prg_banks: Byte, prg_banks: Byte,
chr_banks: Byte, chr_banks: Byte,
@@ -29,17 +30,23 @@ impl Mapper0 {
impl Mapper for Mapper0 { impl Mapper for Mapper0 {
fn map_read_addr(&self, addr: Addr) -> Addr { fn map_read_addr(&self, addr: Addr) -> Addr {
if self.prg_banks > 1 { if 0x8000 <= addr && addr <= 0xFFFF {
addr & 0x7fff if self.prg_banks > 1 {
} else { return addr & 0x7fff;
addr & 0x3fff } else {
return addr & 0x3fff;
}
} }
0x0000
} }
fn map_write_addr(&self, addr: Addr) -> Addr { fn map_write_addr(&self, addr: Addr) -> Addr {
if self.prg_banks > 1 { if 0x8000 <= addr && addr <= 0xFFFF {
addr & 0x7fff if self.prg_banks > 1 {
} else { return addr & 0x7fff;
addr & 0x3fff } else {
return addr & 0x3fff;
}
} }
0x0000
} }
} }