cartrige, mapper, bus

This commit is contained in:
Daniel Bauer
2019-12-25 12:44:58 +01:00
parent 0f73777413
commit 41acfe2743
6 changed files with 427 additions and 111 deletions

View File

@@ -8,10 +8,10 @@ mod nes;
use std::path::Path; use std::path::Path;
use piston_window::*; use piston_window::*;
use gfx_core::Device;
use nes::types::*; use nes::types::*;
use nes::cpu::*; use nes::cpu::*;
use nes::bus::*; use nes::bus::*;
use nes::cartridge::*;
use nes::disasm::*; use nes::disasm::*;
use opengl_graphics::OpenGL; use opengl_graphics::OpenGL;
use log::Level; use log::Level;
@@ -34,22 +34,26 @@ fn get_glyphs(window: &mut PistonWindow) -> Glyphs {
fn main() { fn main() {
simple_logger::init_with_level(Level::Debug).unwrap(); simple_logger::init_with_level(Level::Debug).unwrap();
let cartridge = Path::new("test_roms/registers.nes");
let cartridge = Cartridge::new(cartridge).unwrap();
let mut bus = MemoryBus::new(); let mut bus = MemoryBus::new();
bus.insert_cartrige(cartridge);
// Load little test program into ram // Load little test program into ram
let test_prog: [Byte; 28] = [0xA2, 0x0A, 0x8E, 0x00, 0x00, 0xA2, 0x03, 0x8E, 0x01, 0x00, 0xAC, 0x00, 0x00, 0xA9, // let test_prog: [Byte; 28] = [0xA2, 0x0A, 0x8E, 0x00, 0x00, 0xA2, 0x03, 0x8E, 0x01, 0x00, 0xAC, 0x00, 0x00, 0xA9,
0x00, 0x18, 0x6D, 0x01, 0x00, 0x88, 0xD0, 0xFA, 0x8D, 0x02, 0x00, 0xEA, 0xEA, 0xEA]; // 0x00, 0x18, 0x6D, 0x01, 0x00, 0x88, 0xD0, 0xFA, 0x8D, 0x02, 0x00, 0xEA, 0xEA, 0xEA];
let offset: Addr = 0x8000; // let offset: Addr = 0x8000;
for i in 0..test_prog.len() { // for i in 0..test_prog.len() {
let addr = (i as Addr) + offset; // let addr = (i as Addr) + offset;
bus.writeb(addr, test_prog[i]) // bus.writeb(addr, test_prog[i])
} // }
// // hint program location to processor
// bus.writew(0xfffc, offset);
// disassemble instructions // disassemble instructions
let disasm = Disasm::disassemble(&test_prog, offset).unwrap(); // let disasm = Disasm::disassemble(&test_prog, offset).unwrap();
let disasm = Disasm::disassemble(&[], 0x000).unwrap();
// hint program location to processor
bus.writew(0xfffc, offset);
// Create and reset CPU // Create and reset CPU
let mut cpu: CPU = CPU::new(); let mut cpu: CPU = CPU::new();
@@ -83,7 +87,7 @@ fn main() {
} }
} }
fn render(window: &mut PistonWindow, event: &Event, glyphs: &mut Glyphs, cpu: &CPU, bus: &dyn Bus, disasm: &Disasm) { fn render(window: &mut PistonWindow, event: &Event, glyphs: &mut Glyphs, cpu: &CPU, bus: &MemoryBus, disasm: &Disasm) {
window.draw_2d(event, |c, g, d| { window.draw_2d(event, |c, g, d| {
clear([0.0, 0.0, 1.0, 1.0], g); clear([0.0, 0.0, 1.0, 1.0], g);
@@ -225,7 +229,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: &dyn Bus, offset: [f64; 2]) { 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]); let mut transform_y = c.transform.trans(offset[0], offset[1]);
for page in (0x0000..0x00F0).step_by(16) { for page in (0x0000..0x00F0).step_by(16) {
transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX); transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX);

View File

@@ -3,3 +3,5 @@ pub mod cpu;
pub mod bus; pub mod bus;
pub mod types; pub mod types;
pub mod disasm; pub mod disasm;
pub mod cartridge;
pub mod mappers;

View File

@@ -1,65 +1,136 @@
use crate::nes::types::*; use crate::nes::types::*;
use crate::nes::cartridge::Cartridge;
// Generic interface describing a Bus const RAM_ADDR_RANGE: [Addr; 2] = [0x0000, 0x1fff];
pub trait Bus { const RAM_PHYS_RANGE: [Addr; 2] = [0x0000, 0x07ff];
const CART_ADDR_RANGE: [Addr; 2] = [0x4020, 0xffff];
// Generic interface for a device allowing to read/write memory
pub trait Memory {
fn readb(&self, addr: Addr) -> Byte; fn readb(&self, addr: Addr) -> Byte;
fn readw(&self, addr: Addr) -> Word;
fn writeb(&mut self, addr: Addr, data: Byte); fn writeb(&mut self, addr: Addr, data: Byte);
fn writew(&mut self, addr: Addr, data: Word); fn readw(&self, addr: Addr) -> Word {
let lo = self.readb(addr);
let hi = self.readb(addr+1);
(hi as Word) << 8 | lo as Word
}
fn writew(&mut self, addr: Addr, data: Word) {
self.writeb(addr, data as Byte);
self.writeb(addr + 1, (data >> 8) as Byte);
}
} }
// Impl by devices to access the Bus // Impl by devices to access the Bus
pub trait BusDevice { pub trait BusDevice {
fn readb<T: Bus>(&self, bus: &T, addr: Addr) -> Byte { fn readb<T: Memory>(&self, bus: &T, addr: Addr) -> Byte {
bus.readb(addr) bus.readb(addr)
} }
fn readw<T: Bus>(&self, bus: &T, addr: Addr) -> Word { fn readw<T: Memory>(&self, bus: &T, addr: Addr) -> Word {
bus.readw(addr) bus.readw(addr)
} }
fn writeb<T: Bus>(&mut self, bus: &mut T, addr: Addr, data: Byte) { fn writeb<T: Memory>(&mut self, bus: &mut T, addr: Addr, data: Byte) {
bus.writeb(addr, data) bus.writeb(addr, data)
} }
} }
// Impl by devices to do stuff on bus clock // Impl by devices to do stuff on bus clock
pub trait Clockable { pub trait Clockable {
fn clock<T: Bus>(&mut self, bus: &mut T); fn clock<T: Memory>(&mut self, bus: &mut T);
} }
// A simple bus giving access to a chunk of memory // A simple bus giving access to a chunk of memory
// and the cartrige
pub struct MemoryBus { pub struct MemoryBus {
ram: [Byte; 0xFFFF] ram: [Byte; 0x07ff], // 2kb
cartrige: Option<Cartridge>
} }
impl MemoryBus { impl MemoryBus {
pub fn new() -> MemoryBus { pub fn new() -> MemoryBus {
MemoryBus { MemoryBus {
ram: [0; 0xFFFF] ram: [0; 0x07ff],
cartrige: None,
}
}
pub fn insert_cartrige(&mut self, cartrige: Cartridge) {
self.cartrige = Some(cartrige);
}
}
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] {
return cartrige.readb(addr)
}
}
if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] {
// Ram is 3x mirrored after 07ff
return self.ram[(addr & 0x07ff) as usize]
}
0x0000 // generic response
}
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] {
cartrige.writeb(addr, data)
}
}
if RAM_ADDR_RANGE[0] <= addr && addr < RAM_ADDR_RANGE[1] {
// Ram is 3x mirrored after 07ff
self.ram[(addr & 0x07ff) as usize] = data
} }
} }
} }
impl Bus for MemoryBus {
fn readb(&self, addr: Addr) -> Byte { #[cfg(test)]
self.ram[addr as usize] mod tests {
use super::*;
#[test]
fn test_consts() {
assert_eq!(RAM_ADDR_RANGE[1] - RAM_ADDR_RANGE[0] + 1, 2048*4);
assert_eq!(RAM_PHYS_RANGE[1] - RAM_PHYS_RANGE[0] + 1, 2048);
} }
fn readw(&self, addr: Addr) -> Word { #[test]
let lo = self.readb(addr); fn test_read_write_ram() {
let hi = self.readb(addr+1); let mut bus = MemoryBus::new();
(hi as Word) << 8 | lo as Word
// read/write to ram addr
bus.writeb(0x0000, 1);
assert_eq!(1, bus.readb(0x0000));
assert_eq!(1, bus.readb(0x0800));
// read/write to mirrored ram
bus.writeb(0x0801, 2);
assert_eq!(2, bus.readb(0x0801));
assert_eq!(2, bus.readb(0x0001));
} }
fn writeb(&mut self, addr: Addr, data: Byte) { #[test]
self.ram[addr as usize] = data; fn test_read_write_cartrige() {
let mut bus = MemoryBus::new();
// read/write non-existant to cartrige
bus.writeb(0x4030, 3);
assert_eq!(0, bus.readb(0x4030));
let cartrige = Cartridge::dummy();
bus.insert_cartrige(cartrige);
bus.writeb(0x4030, 3);
assert_eq!(3, bus.readb(0x4030));
} }
fn writew(&mut self, addr: Addr, data: Word) {
self.writeb(addr, data as Byte);
self.writeb(addr + 1, (data >> 8) as Byte);
}
} }

193
src/nes/cartridge.rs Normal file
View File

@@ -0,0 +1,193 @@
use crate::nes::mappers::*;
use crate::nes::bus::Memory;
use failure::Error;
use std::io::prelude::*;
use std::fs::File;
use crate::nes::types::*;
use std::path::Path;
use std::io::SeekFrom;
#[derive(Debug)]
struct Header {
prg_rom_chunks: Byte, // 16K chunks
chr_rom_chunks: Byte, // 8K chunks
mapper1: Byte,
mapper2: Byte,
prg_ram_size: Byte,
tv1: Byte,
tv2: Byte
}
impl Header {
fn new(f: &mut File) -> Result<Self, Error> {
f.seek(SeekFrom::Start(0))?;
// assert NES "NES"
f.seek(SeekFrom::Start(4))?;
let mut rom_sizes = [0; 2]; // prg size in 16K and chr size in 8K
f.read_exact(&mut rom_sizes)?;
let mut flags = [0; 5];
f.read_exact(&mut flags)?;
// Unused
f.seek(SeekFrom::Current(5));
Ok(Header {
prg_rom_chunks: rom_sizes[0],
chr_rom_chunks: rom_sizes[1],
mapper1: flags[0],
mapper2: flags[1],
prg_ram_size: flags[2],
tv1: flags[3],
tv2: flags[4],
})
}
pub fn has_trainer(&self) -> bool {
self.mapper1 & (1 << 2) != 0
}
pub fn get_mapper_id(&self) -> Byte {
let hi = (self.mapper2 >> 4) << 4;
let lo = self.mapper1 >> 4;
hi | lo
}
}
pub struct Cartridge {
prg_rom: Vec<Byte>,
chr_rom: Vec<Byte>,
mapper: Box<dyn Mapper>,
}
impl Cartridge {
pub fn new(path: &Path) -> Result<Self, Error> {
let mut f = File::open(path)?;
let header = Header::new(&mut f)?;
debug!("{:?}", header);
let mut current_pos = 0;
current_pos = f.seek(SeekFrom::Start(16))?;
if header.has_trainer() {
current_pos = f.seek(SeekFrom::Current(512))?;
}
let mut prg_rom = vec!(0; header.prg_rom_chunks as usize * 16384);
f.read_exact(&mut prg_rom)?;
let mut chr_rom = vec!(0; header.chr_rom_chunks as usize * 8192);
f.read_exact(&mut chr_rom)?;
let mapper = match header.get_mapper_id() {
0 => { Mapper0::new(header.prg_rom_chunks, header.chr_rom_chunks) }
id => bail!("Mapper {:04} not supported", id)
};
Ok(Cartridge {
prg_rom: prg_rom,
chr_rom: chr_rom,
mapper: Box::new(mapper)
})
}
pub fn dummy() -> Self {
Cartridge {
prg_rom: vec![0; 16384],
chr_rom: vec![0; 8192],
mapper: Box::new(Mapper0::new(1, 1))
}
}
}
impl Memory for Cartridge {
fn readb(&self, addr: Addr) -> Byte {
let mapped_addr = self.mapper.map_read_addr(addr);
self.prg_rom[mapped_addr as usize]
}
fn writeb(&mut self, addr: Addr, data: Byte) {
let mapped_addr = self.mapper.map_write_addr(addr);
self.prg_rom[mapped_addr as usize] = data;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_get_mapper_id() {
let header = Header {
prg_rom_chunks: 1,
chr_rom_chunks: 1,
mapper1: 0x00,
mapper2: 0x00,
prg_ram_size: 0x00,
tv1: 0x00,
tv2: 0x00
};
assert_eq!(0, header.get_mapper_id());
let header = Header {
prg_rom_chunks: 1,
chr_rom_chunks: 1,
mapper1: 0x10,
mapper2: 0x00,
prg_ram_size: 0x00,
tv1: 0x00,
tv2: 0x00
};
assert_eq!(1, header.get_mapper_id());
let header = Header {
prg_rom_chunks: 1,
chr_rom_chunks: 1,
mapper1: 0xff,
mapper2: 0xff,
prg_ram_size: 0x00,
tv1: 0x00,
tv2: 0x00
};
assert_eq!(255, header.get_mapper_id());
}
#[test]
fn test_header_has_trainer() {
let header = Header {
prg_rom_chunks: 1,
chr_rom_chunks: 1,
mapper1: (1 << 2),
mapper2: 0x00,
prg_ram_size: 0x00,
tv1: 0x00,
tv2: 0x00
};
assert!(header.has_trainer());
let header = Header {
prg_rom_chunks: 1,
chr_rom_chunks: 1,
mapper1: 0x00,
mapper2: 0x00,
prg_ram_size: 0x00,
tv1: 0x00,
tv2: 0x00
};
assert!(!header.has_trainer());
}
#[test]
fn test_cartridge_new() {
let path = Path::new("test_roms/registers.nes");
Cartridge::new(&path).unwrap();
}
}

View File

@@ -57,7 +57,7 @@ impl BusDevice for CPU { }
// A cpu is clockable // A cpu is clockable
impl Clockable for CPU { impl Clockable for CPU {
fn clock<T: Bus>(&mut self, bus: &mut T) { fn clock<T: Memory>(&mut self, bus: &mut T) {
if self.cycles == 0 { if self.cycles == 0 {
let opcode = self.readb_pc(bus); let opcode = self.readb_pc(bus);
self.curr_op = opcode; self.curr_op = opcode;
@@ -81,7 +81,7 @@ impl CPU {
// Brings the CPU to a known state. Resets all registers and flags // Brings the CPU to a known state. Resets all registers and flags
// Read location of pc from 0xfffc // Read location of pc from 0xfffc
pub fn reset<T: Bus>(&mut self, bus: &T) { pub fn reset<T: Memory>(&mut self, bus: &T) {
// reset registers // reset registers
self.regs.a = 0; self.regs.a = 0;
self.regs.x = 0; self.regs.x = 0;
@@ -96,6 +96,7 @@ impl CPU {
let lo = bus.readb(addr); let lo = bus.readb(addr);
let hi = bus.readb(addr + 1); let hi = bus.readb(addr + 1);
self.regs.pc = (hi as u16) << 8 | lo as u16; self.regs.pc = (hi as u16) << 8 | lo as u16;
debug!("PC after reset: {:#06x}", self.regs.pc);
// A reset takes 8 CPU clocks // A reset takes 8 CPU clocks
self.cycles = 8; self.cycles = 8;
@@ -110,14 +111,14 @@ impl CPU {
} }
// read the next opcode and increment pc // read the next opcode and increment pc
fn readb_pc<T: Bus>(&mut self, bus: &T) -> Byte { fn readb_pc<T: Memory>(&mut self, bus: &T) -> Byte {
let val = self.readb(bus, self.regs.pc); let val = self.readb(bus, self.regs.pc);
self.regs.pc += 1; self.regs.pc += 1;
val val
} }
// read whole Word from pc // read whole Word from pc
fn readw_pc<T: Bus>(&mut self, bus: &T) -> Word { fn readw_pc<T: Memory>(&mut self, bus: &T) -> Word {
let val = self.readw(bus, self.regs.pc); let val = self.readw(bus, self.regs.pc);
self.regs.pc += 2; self.regs.pc += 2;
val val
@@ -141,7 +142,7 @@ impl CPU {
} }
} }
fn run_instruction<T: Bus>(&mut self, bus: &mut T, i: &Instruction) -> u8 { fn run_instruction<T: Memory>(&mut self, bus: &mut T, i: &Instruction) -> u8 {
let (value, page_cross) = match &i.addr_mode { let (value, page_cross) = match &i.addr_mode {
AddrMode::IMP => self.am_IMP(bus), AddrMode::IMP => self.am_IMP(bus),
AddrMode::IMM => self.am_IMM(bus), AddrMode::IMM => self.am_IMM(bus),
@@ -225,30 +226,30 @@ impl CPU {
} }
// Implied aka no target // Implied aka no target
fn am_IMP<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_IMP<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
(0, false) (0, false)
} }
// Immediate, next byte comes from pc // Immediate, next byte comes from pc
fn am_IMM<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_IMM<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.regs.pc; let addr = self.regs.pc;
self.regs.pc += 1; self.regs.pc += 1;
(addr, false) (addr, false)
} }
fn am_ZP0<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ZP0<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_ZPX<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ZPX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_ZPY<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ZPY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_REL<T: Bus>(&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 { if rel_addr < 0x80 {
(self.regs.pc + rel_addr, false) (self.regs.pc + rel_addr, false)
@@ -257,33 +258,33 @@ impl CPU {
} }
} }
fn am_ABS<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ABS<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
let addr = self.readw_pc(bus); let addr = self.readw_pc(bus);
(addr, false) (addr, false)
} }
fn am_ABX<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ABX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_ABY<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_ABY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_IND<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_IND<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_IZX<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_IZX<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
fn am_IZY<T: Bus>(&mut self, bus: &T) -> (Word, bool) { fn am_IZY<T: Memory>(&mut self, bus: &T) -> (Word, bool) {
unimplemented!() unimplemented!()
} }
// Operations // Operations
fn op_ADC<T: Bus>(&mut self, bus: &T, addr: Word) { fn op_ADC<T: Memory>(&mut self, bus: &T, addr: Word) {
let val = self.readb(bus, addr) as Word; let val = self.readb(bus, addr) as Word;
let tmp = (self.regs.a as Word) + val + (self.get_flag(CARRY) as Word); let tmp = (self.regs.a as Word) + val + (self.get_flag(CARRY) as Word);
self.set_flag(CARRY, (tmp & 0xFF) > 255); self.set_flag(CARRY, (tmp & 0xFF) > 255);
@@ -293,35 +294,35 @@ impl CPU {
self.regs.a = tmp as Byte; self.regs.a = tmp as Byte;
} }
fn op_AND<T: Bus>(&mut self, bus: &T, val: Word) { fn op_AND<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_ASL<T: Bus>(&mut self, bus: &T, val: Word) { fn op_ASL<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BCC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BCC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BCS<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BCS<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BEQ<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BEQ<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BIT<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BIT<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BMI<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BMI<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BNE<T: Bus>(&mut self, bus: &T, addr: Word) { fn op_BNE<T: Memory>(&mut self, bus: &T, addr: Word) {
if self.get_flag(ZERO) == 0 { if self.get_flag(ZERO) == 0 {
let old_addr = self.regs.pc; let old_addr = self.regs.pc;
self.regs.pc = addr; self.regs.pc = addr;
@@ -329,19 +330,19 @@ impl CPU {
} }
} }
fn op_BPL<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BPL<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BRK<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BRK<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BVC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BVC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_BVS<T: Bus>(&mut self, bus: &T, val: Word) { fn op_BVS<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
@@ -349,31 +350,31 @@ impl CPU {
self.set_flag(CARRY, false); self.set_flag(CARRY, false);
} }
fn op_CLD<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CLD<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_CLI<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CLI<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_CLV<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CLV<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_CMP<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CMP<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_CPX<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CPX<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_CPY<T: Bus>(&mut self, bus: &T, val: Word) { fn op_CPY<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_DEC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_DEC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
@@ -389,144 +390,144 @@ impl CPU {
self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0) self.set_flag(NEGATIVE, (self.regs.y & 0x80) != 0)
} }
fn op_EOR<T: Bus>(&mut self, bus: &T, val: Word) { fn op_EOR<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_INC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_INC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_INX<T: Bus>(&mut self, bus: &T, val: Word) { fn op_INX<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_INY<T: Bus>(&mut self, bus: &T, val: Word) { fn op_INY<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_JMP<T: Bus>(&mut self, bus: &T, val: Word) { fn op_JMP<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_JSR<T: Bus>(&mut self, bus: &T, val: Word) { fn op_JSR<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_LDA<T: Bus>(&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(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0); self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
fn op_LDX<T: Bus>(&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(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0); self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
fn op_LDY<T: Bus>(&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(ZERO, val == 0);
self.set_flag(NEGATIVE, (val & 0x80) != 0); self.set_flag(NEGATIVE, (val & 0x80) != 0);
} }
fn op_LSR<T: Bus>(&mut self, bus: &T, val: Word) { fn op_LSR<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_NOP<T: Bus>(&mut self, bus: &T, val: Word) { fn op_NOP<T: Memory>(&mut self, bus: &T, val: Word) {
// does nothing // does nothing
} }
fn op_ORA<T: Bus>(&mut self, bus: &T, val: Word) { fn op_ORA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_PHA<T: Bus>(&mut self, bus: &T, val: Word) { fn op_PHA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_PHP<T: Bus>(&mut self, bus: &T, val: Word) { fn op_PHP<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_PLA<T: Bus>(&mut self, bus: &T, val: Word) { fn op_PLA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_PLP<T: Bus>(&mut self, bus: &T, val: Word) { fn op_PLP<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_ROL<T: Bus>(&mut self, bus: &T, val: Word) { fn op_ROL<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_ROR<T: Bus>(&mut self, bus: &T, val: Word) { fn op_ROR<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_RTI<T: Bus>(&mut self, bus: &T, val: Word) { fn op_RTI<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_RTS<T: Bus>(&mut self, bus: &T, val: Word) { fn op_RTS<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_SBC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_SBC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_SEC<T: Bus>(&mut self, bus: &T, val: Word) { fn op_SEC<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_SED<T: Bus>(&mut self, bus: &T, val: Word) { fn op_SED<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_SEI<T: Bus>(&mut self, bus: &T, val: Word) { fn op_SEI<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_STA<T: Bus>(&mut self, bus: &mut T, addr: Word) { fn op_STA<T: Memory>(&mut self, bus: &mut T, addr: Word) {
self.writeb(bus, addr, self.regs.a) self.writeb(bus, addr, self.regs.a)
} }
fn op_STX<T: Bus>(&mut self, bus: &mut T, addr: Word) { fn op_STX<T: Memory>(&mut self, bus: &mut T, addr: Word) {
self.writeb(bus, addr, self.regs.x) self.writeb(bus, addr, self.regs.x)
} }
fn op_STY<T: Bus>(&mut self, bus: &mut T, addr: Word) { fn op_STY<T: Memory>(&mut self, bus: &mut T, addr: Word) {
self.writeb(bus, addr, self.regs.y) self.writeb(bus, addr, self.regs.y)
} }
fn op_TAX<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TAX<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_TAY<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TAY<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_TSX<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TSX<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_TXA<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TXA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_TXS<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TXS<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
fn op_TYA<T: Bus>(&mut self, bus: &T, val: Word) { fn op_TYA<T: Memory>(&mut self, bus: &T, val: Word) {
unimplemented!() unimplemented!()
} }
} }

45
src/nes/mappers.rs Normal file
View File

@@ -0,0 +1,45 @@
use crate::nes::types::*;
pub trait Mapper {
fn map_read_addr(&self, addr: Addr) -> Addr;
fn map_write_addr(&self, addr: Addr) -> Addr;
}
// Mapper 0
// prg rom: 16K or 32K
// chr rom: 8K
// All banks are fixed:
// CPU:
// 0x8000 - 0xbfff // first 16k
// 0xc000 - 0xffff // second 16k
//
// Cartrige:
// 0x4000-0xffff -> first 16K
// 0xc000-0xffff -> last 16K or mirror or 0x8000-0xbfff
pub struct Mapper0 {
prg_banks: Byte,
chr_banks: Byte,
}
impl Mapper0 {
pub fn new(prg_banks: Byte, chr_banks: Byte) -> Self {
Mapper0 { prg_banks, chr_banks }
}
}
impl Mapper for Mapper0 {
fn map_read_addr(&self, addr: Addr) -> Addr {
if self.prg_banks > 1 {
addr & 0x7fff
} else {
addr & 0x3fff
}
}
fn map_write_addr(&self, addr: Addr) -> Addr {
if self.prg_banks > 1 {
addr & 0x7fff
} else {
addr & 0x3fff
}
}
}