some bug fixes
This commit is contained in:
27
src/main.rs
27
src/main.rs
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user