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 opengl_graphics::OpenGL;
use log::Level;
use failure::Error;
use gfx_glyph::{Section, GlyphBrushBuilder,GlyphBrush, Scale};
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
const FT_SIZE_PX: f32 = 11.0;
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_LINE_DISTANCE: f32 = FT_SIZE_PX * 0.5;
lazy_static! {
static ref FT_SCALE: Scale = Scale::uniform(FT_SIZE_PX);
}
fn main() {
simple_logger::init_with_level(Level::Error).unwrap();
fn main() -> Result<(), Error> {
simple_logger::init_with_level(Level::Debug).unwrap();
let mut bus = MemoryBus::new();
let cartridge = Path::new("test_roms/registers.nes");
let cartridge = Cartridge::new(cartridge).unwrap();
let cartridge = Path::new("test_roms/nestest.nes");
let cartridge = Cartridge::new(cartridge)?;
bus.insert_cartrige(cartridge);
// Load little test program into ram
@@ -55,7 +56,7 @@ fn main() {
// bus.writew(0xfffc, offset);
// disassemble instructions
let disasm = Disasm::disassemble(&bus, 0xe1ff, 0xffff-2).unwrap();
let disasm = Disasm::disassemble(&bus, 0xC000, 0xFFFF).unwrap();
// println!("{:?}", disasm.instructions);
// return;
// let disasm = Disasm::disassemble(&[], 0x000).unwrap();
@@ -63,6 +64,8 @@ fn main() {
// Create and reset CPU
let mut cpu: CPU = CPU::new();
cpu.find_pc_addr(&bus);
cpu.regs.pc = 0xC000;
// return Ok(());
// cpu.reset(&bus);
// Prepare window and drawing resources
@@ -115,6 +118,7 @@ fn main() {
}
}
}
Ok(())
}
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,
..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 = [
&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;
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;
let mut line = format!("{:#06x}:", 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
// and the cartrige
pub struct MemoryBus {
ram: [Byte; 0x07ff], // 2kb
ram: [Byte; 0x0800], // 2kb
cartrige: Option<Cartridge>
}
impl MemoryBus {
pub fn new() -> MemoryBus {
MemoryBus {
ram: [0; 0x07ff],
ram: [0; 0x0800],
cartrige: None,
}
}
@@ -65,12 +65,12 @@ impl Memory for MemoryBus {
fn readb(&self, addr: Addr) -> Byte {
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)
}
}
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
return self.ram[(addr & 0x07ff) as usize]
}
@@ -79,12 +79,12 @@ impl Memory for MemoryBus {
fn writeb(&mut self, addr: Addr, data: Byte) {
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)
}
}
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
self.ram[(addr & 0x07ff) as usize] = data
}

View File

@@ -86,6 +86,8 @@ impl Cartridge {
id => bail!("Mapper {:04} not supported", id)
};
debug!("Cartrige loaded. mapper: {:?}", &mapper);
Ok(Cartridge {
prg_rom: prg_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 {
if self.regs.flags & flag > 0 {
1
@@ -340,9 +345,8 @@ impl CPU {
let val = tmp2.0;
let overflow = tmp1.1 || tmp2.1;
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_nz(val as Byte);
self.regs.a = val as Byte;
}
@@ -366,25 +370,44 @@ impl CPU {
unimplemented!()
}
fn op_BIT<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!()
// bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V);
// 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) {
unimplemented!()
// Jump to address
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) {
if self.get_flag(ZERO) == 0 {
let old_addr = self.regs.pc;
self.regs.pc = addr;
println!("Jumping from {:#x} to {:#x}", old_addr, addr);
// Branch if negative flag is set
fn op_BMI<T: Memory>(&mut self, bus: &T, addr: Addr) {
if self.get_flag(NEGATIVE) == 1 {
self.jump(addr);
}
}
fn op_BPL<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!()
// Branch if 0 flag is set
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) {
@@ -439,15 +462,13 @@ impl CPU {
// Decrement X
fn op_DEX(&mut self) {
self.regs.x = self.regs.x.wrapping_sub(1);
self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0)
self.set_flag_nz(self.regs.x);
}
// Decrement Y
fn op_DEY(&mut self) {
self.regs.y = self.regs.y.wrapping_sub(1);
self.set_flag(ZERO, self.regs.y == 0);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
self.set_flag_nz(self.regs.y);
}
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 = val.wrapping_add(1);
self.writeb(bus, addr, val);
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0)
self.set_flag_nz(val);
}
fn op_INX<T: Memory>(&mut self, bus: &T) {
self.regs.x = self.regs.x.wrapping_add(1);
self.set_flag(ZERO, self.regs.x == 0);
self.set_flag(NEGATIVE, (self.regs.x & 0x80) != 0)
self.set_flag_nz(self.regs.x);
}
fn op_INY<T: Memory>(&mut self, bus: &T) {
self.regs.y = self.regs.y.wrapping_add(1);
self.set_flag(ZERO, self.regs.y == 0);
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
self.set_flag_nz(self.regs.y);
}
// Jump to address (set pc)
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)
@@ -486,31 +504,28 @@ impl CPU {
self.regs.sp -= 1;
bus.writeb(STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte);
self.regs.sp -= 1;
self.regs.pc = addr;
self.jump(addr);
}
// Read value from addr into A
fn op_LDA<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr);
self.regs.a = val;
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
self.set_flag_nz(val);
}
// Read value from addr into X
fn op_LDX<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr);
self.regs.x = val;
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
self.set_flag_nz(val);
}
// Read value from addr into Y
fn op_LDY<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = bus.readb(addr);
self.regs.y = val;
self.set_flag(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0);
self.set_flag_nz(val);
}
fn op_LSR<T: Memory>(&mut self, bus: &T, val: Word) {
@@ -521,8 +536,9 @@ impl CPU {
// does nothing
}
fn op_ORA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!()
fn op_ORA<T: Memory>(&mut self, bus: &T, addr: Addr) {
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) {
@@ -564,7 +580,12 @@ impl CPU {
}
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) {

View File

@@ -20,16 +20,22 @@ impl Disasm {
pub fn disassemble(mem: &MemoryBus, start: Addr, stop: Addr) -> Result<Self, Error> {
let mut instructions = 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() {
let opcode = mem.readb(addr);
// Decode opcode, default to NOP/IMP to "skip" the byte
let i = Instruction::decode_op(opcode)
.unwrap_or(Instruction::decode_op(0xeau8).unwrap());
// debug!("{:?}", i);
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 => {
let rel_addr = mem.readb(mem_iter.next().unwrap());
format!("{:#04x}", rel_addr)
@@ -58,9 +64,13 @@ impl Disasm {
};
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);
addresses.push(addr);
}
Ok(Disasm { start, stop, instructions, addresses })
}

View File

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