Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bus && PPU && Mapper draft implementation #5

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/bus/src/cartridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub struct Cartridge {
mapper_id: u8,
}

//TODO Cartridge is connected to both Main bus and PPU Bus

impl Cartridge {
pub fn new() -> Self {
Cartridge {
Expand All @@ -26,6 +28,12 @@ impl Cartridge {
self.mapper_id = rom.header.mapper_id();
Ok(())
}

pub fn reset(&mut self) {
self.prg_rom.clear();
self.chr_rom.clear();
self.mapper_id = 0;
}
}

#[cfg(test)]
Expand Down Expand Up @@ -62,4 +70,19 @@ mod test {

assert_eq!(cartridge.mapper_id, 0xfe);
}

#[test]
fn test_reset_cartridge() {
let (_tmp_file, filename) = generate_rom(false, 0, 1);
let mut cartridge = Cartridge::new();
cartridge.load(filename.as_str()).expect("Failed loading file");
assert_eq!(&[0xEE as u8; 1 * PRG_ROM_SIZE_FACTOR], &cartridge.prg_rom[..]);
assert_eq!(&[0xDD as u8; 1 * CHR_ROM_SIZE_FACTOR], &cartridge.chr_rom[..]);

cartridge.reset();
assert_eq!(cartridge.prg_rom.len(), 0);
assert_eq!(cartridge.chr_rom.len(), 0);
assert_eq!(cartridge.mapper_id, 0);

}
}
2 changes: 1 addition & 1 deletion src/bus/src/inesformat/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl INESFormat {
pub fn from(filename: &str) -> Result<Self, &str> {
let mut rom = INESFormat::new();
let bytes = rom.read_file(filename).expect("err reading file");
let mut pos = 0 as usize;
let mut pos = 0;

rom.header = Header::from(&bytes).expect("invalid iNES Header");
pos += 16;
Expand Down
2 changes: 1 addition & 1 deletion src/bus/src/inesformat/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Header {
}
}

pub fn from(content: &Vec<u8>) -> Result<Self, &str> {
pub fn from(content: &[u8]) -> Result<Self, &str> {
let mut ret = Header::new();

let magic_const = &content[0..4];
Expand Down
65 changes: 30 additions & 35 deletions src/bus/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cartridge::Cartridge;
use crate::rp2c02::PPU;
use crate::traits::MainBusConnection;

// Notes to myself:
// - Implement some sort of subscribe mechanism that allow components to register their
Expand All @@ -11,6 +12,7 @@ pub mod mos6502;
pub mod rp2c02;
pub mod inesformat;
pub mod cartridge;
pub mod traits;

const RAM_SIZE: u16 = 0x0800; // CPU has a whopping 2KB RAM
// const MAX_ROM_SIZE: usize = (RAM_SIZE - ROM_START_ADDR) as usize;
Expand All @@ -33,15 +35,6 @@ impl Bus {
}
}

pub fn cpu_read_u8(&self, addr: u16, read_only: bool) -> u8 {
if addr <= 0x1FFF {
return self.cpu_ram[(addr & 0x07FF) as usize]
} else if addr >= 0x2000 && addr <= 0x3FFF {
return self.ppu.cpu_read_u8(addr & 0x7, read_only);
}
panic!("invalid memory address requested... aborting")
}

pub fn cpu_read_u8_slice(&self, from: u16, to: u16) -> &[u8] {
if from <= 0x1FFF && to <= 0x1FFF && from < to {
return &self.cpu_ram[((from & 0x07FF) as usize)..((to & 0x07FF) as usize)]
Expand All @@ -50,36 +43,14 @@ impl Bus {
panic!("invalid memory range requested... aborting")
}

pub fn cpu_read_u16(&self, addr: u16, read_only: bool) -> u16 {
let low = self.cpu_read_u8(addr, read_only);
let high = self.cpu_read_u8(addr + 1, read_only);
((high as u16) << 8) | low as u16
}

pub fn cpu_write_u8(&mut self, addr: u16, value: u8) {
if addr <= 0x1FFF {
self.cpu_ram[(addr & 0x07FF) as usize] = value;
} else if addr >= 0x2000 && addr <= 0x3FFF {
self.ppu.cpu_write_u8(addr & 0x7, value);
}else {
panic!("invalid memory address requested... aborting")
}
}

pub fn cpu_write_u16(&mut self, addr: u16, value: u16) {
let low = (value & 0xff) as u8;
let high = ((value >> 8) & 0xff) as u8;
self.cpu_write_u8(addr, low);
self.cpu_write_u8(addr + 1, high);
}

pub fn load_cartridge(&mut self, filename: &str) -> Result<(), &str> {
self.cartridge.load(filename).expect("failed to load cartridge");
Ok(())
}

pub fn reset(&mut self) {
//cpu.reset()
self.cpu_ram = [0; RAM_SIZE as usize + 1];
self.cartridge.reset();
self.system_clock = 0;
}

Expand All @@ -93,10 +64,34 @@ impl Bus {
}
}

impl MainBusConnection for Bus {

fn cpu_read_u8(&self, addr: u16, read_only: bool) -> u8 {
let mut data = 0x0 as u8;
Fixed Show fixed Hide fixed
if addr <= 0x1FFF {
data = self.cpu_ram[(addr & 0x07FF) as usize];
} else if addr >= 0x2000 && addr <= 0x3FFF {
Fixed Show fixed Hide fixed
data = self.ppu.cpu_read_u8(addr & 0x7, read_only);
}
data
// panic!("invalid memory address requested... aborting")
}

fn cpu_write_u8(&mut self, addr: u16, value: u8) {
if addr <= 0x1FFF {
self.cpu_ram[(addr & 0x07FF) as usize] = value;
} else if addr >= 0x2000 && addr <= 0x3FFF {
self.ppu.cpu_write_u8(addr & 0x7, value);
}else {
panic!("invalid memory address requested... aborting")
}
}
}

#[cfg(test)]
mod test{
use super::*;
use std::io::{Write};
use std::io::Write;
use std::os::unix::prelude::*;
use tempfile::NamedTempFile;
use filename::file_name;
Expand Down Expand Up @@ -147,4 +142,4 @@ mod test{
assert_eq!(&[0; RAM_SIZE as usize + 1], &bus.cpu_ram[..]);
}

}
}
13 changes: 7 additions & 6 deletions src/bus/src/mos6502/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
mod opcodes;

pub use crate::Bus;
use opcodes::{parse_instruction, Flags};
use opcodes::{Flags, parse_instruction};
pub use crate::mos6502::opcodes::{AddressingMode, Instruction};
pub use crate::mos6502::opcodes::OPTABLE;
pub use crate::traits::MainBusConnection;

const STACK_PAGE:u16 = 0x0100;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Mos6502 {
pub a: u8,
pub x: u8,
Expand All @@ -33,9 +35,9 @@ impl Mos6502 {
}
}

pub fn reset(&mut self, bus: & Bus) {
pub fn reset(&mut self, bus: &Bus) {
// Get address to set program counter to
self.pc = bus.cpu_read_u16(0xFFFC, false);
self.pc = bus.cpu_read_u16(0xFFFC, true);

// reset regs
self.a = 0;
Expand Down Expand Up @@ -97,8 +99,7 @@ impl Mos6502 {

self.sp += 1;
let addr: u16 = STACK_PAGE | self.sp as u16;
let value = bus.cpu_read_u8(addr, false);
value
bus.cpu_read_u8(addr, false)
}

// Notes to myself
Expand Down
2 changes: 0 additions & 2 deletions src/bus/src/mos6502/opcodes/alu/adc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// use crate::Bus;
// use crate::mos6502::{Mos6502, Instruction, Flags::*};
use super::*;

/// ADC - Add with Carry
Expand Down
2 changes: 1 addition & 1 deletion src/bus/src/mos6502/opcodes/alu/and.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::*;
pub fn and(cpu: &mut Mos6502, inst: Instruction, bus: &mut Bus) -> u8 {
println!("{} -> {:?} was called with cpu: {:?}", inst.name, inst.mode, cpu);
let (fetched, additional_cycle) = cpu.address_mode_fetch(bus, &inst);
cpu.a = cpu.a & fetched;
cpu.a &= fetched;
cpu.write_flag_cond(Zero, cpu.a == 0);
cpu.write_flag_cond(Negative, cpu.a & 0x80 == 0x80 );
cpu.pc += inst.bytes as u16;
Expand Down
2 changes: 1 addition & 1 deletion src/bus/src/mos6502/opcodes/alu/eor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::*;
pub fn eor(cpu: &mut Mos6502, inst: Instruction, bus: &mut Bus) -> u8 {
println!("{} -> {:?} was called with cpu: {:?}", inst.name, inst.mode, cpu);
let (fetched, additional_cycle) = cpu.address_mode_fetch(bus, &inst);
cpu.a = cpu.a ^ fetched;
cpu.a ^= fetched;
cpu.write_flag_cond(Zero, cpu.a == 0);
cpu.write_flag_cond(Negative, cpu.a & 0x80 == 0x80);
cpu.pc += inst.bytes as u16;
Expand Down
7 changes: 5 additions & 2 deletions src/bus/src/mos6502/opcodes/alu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ pub use sta::*;
pub use adc::*;
pub use sbc::*;

#[allow(unused_imports)]
use crate::Bus;
use crate::mos6502::{Mos6502, Instruction, Flags::*};
use crate::mos6502::{Flags::*, Instruction, Mos6502};
#[allow(unused_imports)]
use crate::mos6502::{AddressingMode::*};
#[allow(unused_imports)]
use crate::mos6502::opcodes::{OPTABLE};
use crate::mos6502::opcodes::OPTABLE;
#[allow(unused_imports)]
use crate::traits::MainBusConnection;
2 changes: 1 addition & 1 deletion src/bus/src/mos6502/opcodes/alu/ora.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::*;
pub fn ora(cpu: &mut Mos6502, inst: Instruction, bus: &mut Bus) -> u8 {
println!("{} -> {:?} was called with cpu: {:?}", inst.name, inst.mode, cpu);
let (fetched, additional_cycle) = cpu.address_mode_fetch(bus, &inst);
cpu.a = cpu.a | fetched;
cpu.a |= fetched;
cpu.write_flag_cond(Zero, cpu.a == 0);
cpu.write_flag_cond(Negative, cpu.a & 0x80 == 0x80);
cpu.pc += inst.bytes as u16;
Expand Down
7 changes: 2 additions & 5 deletions src/bus/src/mos6502/opcodes/control/jmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,13 @@ pub fn jmp(cpu: &mut Mos6502, inst: Instruction, bus: &mut Bus) -> u8 {
},
Indirect => {
let addr_ptr = bus.cpu_read_u16(cpu.pc + 1, false);
let addr_abs:u16;

if (addr_ptr & 0xFF) == 0xFF {
// Simulate page boundary hardware bug
addr_abs = ((bus.cpu_read_u8(addr_ptr & 0xFF00, false) as u16) << 8) | bus.cpu_read_u8(addr_ptr, false) as u16;
((bus.cpu_read_u8(addr_ptr & 0xFF00, false) as u16) << 8) | bus.cpu_read_u8(addr_ptr, false) as u16
}else {
// Behave normally
addr_abs = bus.cpu_read_u16(addr_ptr, false);
bus.cpu_read_u16(addr_ptr, false)
}
addr_abs
},
_ => unreachable!("invalid addressing mode for instruction")
};
Expand Down
5 changes: 3 additions & 2 deletions src/bus/src/mos6502/opcodes/control/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ pub use rts::*;
pub use rti::*;

use crate::Bus;
use crate::mos6502::{Mos6502, Instruction, Flags::*};
use crate::mos6502::{Flags::*, Instruction, Mos6502};
#[allow(unused_imports)]
use crate::mos6502::{AddressingMode::*};
#[cfg(test)]
use crate::mos6502::opcodes::{OPTABLE};
use crate::mos6502::opcodes::OPTABLE;
use crate::traits::MainBusConnection;
2 changes: 1 addition & 1 deletion src/bus/src/mos6502/opcodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ pub const OPTABLE: [Instruction;256] = [


pub fn parse_instruction(opcode: u8) -> Instruction<'static> {
OPTABLE[opcode as usize].clone()
OPTABLE[opcode as usize]
}

#[cfg(test)]
Expand Down
5 changes: 3 additions & 2 deletions src/bus/src/mos6502/opcodes/rmw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ pub use rol::*;
pub use ror::*;

use crate::Bus;
use crate::mos6502::{Mos6502, Instruction, Flags::*};
use crate::mos6502::{Flags::*, Instruction, Mos6502};
#[allow(unused_imports)]
use crate::mos6502::{AddressingMode::*};
#[cfg(test)]
use crate::mos6502::opcodes::{OPTABLE};
use crate::mos6502::opcodes::OPTABLE;
use crate::traits::MainBusConnection;
37 changes: 17 additions & 20 deletions src/bus/src/rp2c02/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::traits::{MainBusConnection, PPUBusConnection};

pub struct PPU {
// C: tbl_name[2][1024]
tbl_name: [[u8; 1024]; 2],
Expand All @@ -12,7 +14,14 @@ impl PPU {
}
}

pub fn cpu_read_u8(&self, addr: u16, _read_only: bool) -> u8 {
pub fn clock(&mut self) {
todo!("implement PPU clock")
}

}

impl MainBusConnection for PPU {
fn cpu_read_u8(&self, addr: u16, _read_only: bool) -> u8 {
match addr {
// Control
0x0 => 0,
Expand All @@ -34,13 +43,7 @@ impl PPU {
}
}

pub fn cpu_read_u16(&self, addr: u16, read_only: bool) -> u16 {
let low = self.cpu_read_u8(addr, read_only);
let high = self.cpu_read_u8(addr + 1, read_only);
((high as u16) << 8) | low as u16
}

pub fn cpu_write_u8(&mut self, addr: u16, _value: u8) {
fn cpu_write_u8(&mut self, addr: u16, _value: u8) {
match addr {
// Control
0x0 => {}
Expand All @@ -61,20 +64,14 @@ impl PPU {
_ => panic!("invalid address on PPU"),
};
}
}

pub fn cpu_write_u16(&mut self, addr: u16, value: u16) {
let low = (value & 0xff) as u8;
let high = ((value >> 8) & 0xff) as u8;
self.cpu_write_u8(addr, low);
self.cpu_write_u8(addr + 1, high);
}


pub fn ppu_write_u8(&mut self, _addr: u16, _value: u8) {
panic!("Not implemented yet");
impl PPUBusConnection for PPU {
fn ppu_write_u8(&mut self, _addr: u16, _value: u8) {
unimplemented!()
}

pub fn ppu_read_u8(&mut self, _addr: u16, _read_only: bool) -> u8 {
panic!("Not implemented yet");
fn ppu_read_u8(&mut self, _addr: u16, _read_only: bool) -> u8 {
unimplemented!()
}
}
Loading