Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
26 changes: 19 additions & 7 deletions src/bus.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use core::panic;

use crate::controller::Controller;
use crate::cpu::Mem;
use crate::ppu::PPU;
use crate::rom::Rom;
Expand All @@ -9,18 +10,20 @@ pub struct Bus<'call> {
prg_rom: Vec<u8>,
pub ppu: PPU,
pub cycles: usize, // Contains total amount of cpu cycles
gameloop_callback: Box<dyn FnMut(&PPU) + 'call> // Box, pointer to heap ddata is managed by the box
gameloop_callback: Box<dyn FnMut(&PPU, &mut Controller) + 'call>, // Box, pointer to heap ddata is managed by the box
controller1: Controller
}

impl <'a>Bus<'a> {
pub fn new<'call, F>(rom: Rom, gameloop_callback: F) -> Bus<'call> where F: FnMut(&PPU) + 'call,{
pub fn new<'call, F>(rom: Rom, gameloop_callback: F) -> Bus<'call> where F: FnMut(&PPU, &mut Controller) + 'call,{
let ppu = PPU::new(rom.chr_rom, rom.screen_mirroring);
Bus {
cpu_vram: [0; 2048],
prg_rom: rom.prg_rom,
ppu: ppu,
cycles: 7, // Starting with 7 clock cycles
gameloop_callback: Box::from(gameloop_callback),
controller1: Controller::new()
}
}
fn read_prg_rom(&self, mut addr: u16) -> u8 {
Expand All @@ -38,7 +41,7 @@ impl <'a>Bus<'a> {
self.cycles += cycles as usize;
let new_frame = self.ppu.tick(cycles * 3);
if new_frame {
(self.gameloop_callback)(&self.ppu);
(self.gameloop_callback)(&self.ppu, &mut self.controller1);
}
}

Expand Down Expand Up @@ -79,8 +82,17 @@ impl Mem for Bus<'_> {
let mirror_down_addr = addr & 0x2007;
self.mem_read(mirror_down_addr)
}
0x4000..=0x4017 => {
// Ignore APU and joypads
0x4000..=0x4015 => {
// Ignoring APU
0
}

0x4016 =>{
self.controller1.read()
}

0x4017 =>{
// Controller 2
0
}
PROGRAM_RAM..=PROGRAM_RAM_END => self.read_prg_rom(addr),
Expand Down Expand Up @@ -136,11 +148,11 @@ impl Mem for Bus<'_> {
}

0x4016 => {
// ignore joypad 1;
self.controller1.write(data);
}

0x4017 => {
// ignore joypad 2
// ignore controller 2
}
_ => {
println!("Ignoring mem write-access at {}", addr);
Expand Down
62 changes: 62 additions & 0 deletions src/controller.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// If strobe is off, it will read controller input from highest to lowest bit
// If strobe is on, it will read the states from the previous inputs and the state of the first button

use bitflags::bitflags;

bitflags!{
#[derive(Copy, Clone, Debug)]
pub struct ControllerButton: u8{
const RIGHT = 0b1000_0000;
const LEFT = 0b0100_0000;
const DOWN = 0b0010_0000;
const UP = 0b0001_0000;
const START = 0b0000_1000;
const SELECT = 0b0000_0100;
const B = 0b0000_0010;
const A = 0b0000_0001;
}
}

pub struct Controller{
strobe: bool, // Determines if we are writing input or leaving the read
button_index: u8,
button_status: ControllerButton
}

impl Controller{
pub fn new() -> Self {
Controller{
strobe: false,
button_index: 0,
button_status: ControllerButton::from_bits_truncate(0b0000_0000),
}
}

pub fn write(&mut self, data: u8){
println!("writing controller!");
self.strobe = data & 1 == 1;
if self.strobe{
println!("resetting strobe!");
// Starts at the first index
self.button_index = 0
}
}

pub fn read(&mut self) -> u8{
println!("reading controller!");
if self.button_index > 7{
return 1; // Indicates that there isn't anything left ot read
}
let response = (self.button_status.bits() & (1 << self.button_index)) >> self.button_index;
if !self.strobe && self.button_index <= 7{
self.button_index += 1; // Increments the index for the next read
}
println!("Response is {:x}", response);
response
}

pub fn set_button_pressed_status(&mut self, button: ControllerButton, input: bool){
println!("Set status to {:?}", button);
self.button_status.set(button, input);
}
}
90 changes: 46 additions & 44 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod trace;
pub mod frame;
pub mod palette;
pub mod render;

pub mod controller;

use cpu::*;

Expand All @@ -29,50 +29,52 @@ macro_rules! print_title {
};
}

pub fn run_nestest_and_capture() -> Vec<String> {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
.window("Snake game", (32.0 * 10.0) as u32, (32.0 * 10.0) as u32)
.position_centered()
.build()
.unwrap();

let mut canvas = window.into_canvas().present_vsync().build().unwrap();
let mut event_pump = sdl_context.event_pump().unwrap();
canvas.set_scale(3.0, 3.0).unwrap();
// Used with NES test, removing for now due to polishing state of ppu and controllers
// pub fn run_nestest_and_capture() -> Vec<String> {
// let sdl_context = sdl2::init().unwrap();
// let video_subsystem = sdl_context.video().unwrap();
// let window = video_subsystem
// .window("Snake game", (32.0 * 10.0) as u32, (32.0 * 10.0) as u32)
// .position_centered()
// .build()
// .unwrap();

let creator = canvas.texture_creator();
let mut texture = creator
.create_texture_target(PixelFormatEnum::RGB24, 32, 32)
.unwrap();
canvas.set_scale(3.0, 3.0).unwrap();
let game_bytes = std::fs::read("nestest.nes").unwrap();
let rom = Rom::new(&game_bytes).unwrap();
let mut frame = Frame::new();
let bus = Bus::new(rom, move |ppu:&PPU|{
render::render(ppu, &mut frame);
texture.update(None, &frame.data, 265 * 3).unwrap();
// let mut canvas = window.into_canvas().present_vsync().build().unwrap();
// let mut event_pump = sdl_context.event_pump().unwrap();
// canvas.set_scale(3.0, 3.0).unwrap();

canvas.copy(&texture, None, None).unwrap();
// let creator = canvas.texture_creator();
// let mut texture = creator
// .create_texture_target(PixelFormatEnum::RGB24, 32, 32)
// .unwrap();
// canvas.set_scale(3.0, 3.0).unwrap();
// let game_bytes = std::fs::read("nestest.nes").unwrap();
// let rom = Rom::new(&game_bytes).unwrap();
// let mut frame = Frame::new();
// let bus = Bus::new(rom, move |ppu:&PPU|{
// render::render(ppu, &mut frame);
// texture.update(None, &frame.data, 265 * 3).unwrap();

canvas.present();
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => std::process::exit(0),
_ => { /* do nothing */ }
}
}
});
let mut cpu = CPU::new(bus);
cpu.reset();
let mut output = Vec::new();
cpu.run_with_callback(|cpu| {
output.push(trace(cpu));
});
output
}
// canvas.copy(&texture, None, None).unwrap();

// canvas.present();
// for event in event_pump.poll_iter() {
// match event {
// Event::Quit { .. }
// | Event::KeyDown {
// keycode: Some(Keycode::Escape),
// ..
// } => std::process::exit(0),
// _ => { /* do nothing */ }
// }
// }
// });
// let mut cpu = CPU::new(bus);
// cpu.reset();
// let mut output = Vec::new();
// cpu.run_with_callback(|cpu| {
// output.push(trace(cpu));
// });
// output
// }
34 changes: 31 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::HashMap;
use nes::controller::{self, ControllerButton};
use nes::cpu::*;

use nes::frame::Frame;
Expand All @@ -12,6 +14,7 @@ use sdl2::pixels::PixelFormatEnum;
use nes::bus::Bus;

fn main() {
// Setting up screen and scaling
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
Expand All @@ -37,12 +40,24 @@ fn main() {
// .filter_level(log::LevelFilter::Debug)
// .init();

let game_bytes = std::fs::read("roms/smb.nes").unwrap();
// Setting up controllers
let mut input_map = HashMap::new();
input_map.insert(Keycode::Down, ControllerButton::DOWN);
input_map.insert(Keycode::Up, ControllerButton::UP);
input_map.insert(Keycode::Right, ControllerButton::RIGHT);
input_map.insert(Keycode::Left, ControllerButton::LEFT);
input_map.insert(Keycode::X, ControllerButton::B);
input_map.insert(Keycode::Z, ControllerButton::A);
input_map.insert(Keycode::Return, ControllerButton::START);
input_map.insert(Keycode::Space, ControllerButton::SELECT);

// Game loading and CPU setup
let game_bytes = std::fs::read("roms/pacman.nes").unwrap();
let rom = Rom::new(&game_bytes).unwrap();

let mut frame = Frame::new();

let bus = Bus::new(rom, move |ppu:&PPU|{
let bus = Bus::new(rom, move |ppu:&PPU, controller: &mut controller::Controller|{
render::render(ppu, &mut frame);
texture.update(None, &frame.data, 256 * 3).unwrap();

Expand All @@ -56,7 +71,20 @@ fn main() {
keycode: Some(Keycode::Escape),
..
} => std::process::exit(0),
_ => { /* do nothing */ }
Event::KeyDown { keycode, .. } => {
if let Some(key) = input_map.get(&keycode.unwrap_or(Keycode::Ampersand)) {
println!("Pressed button!");
controller.set_button_pressed_status(*key, true);
}
}
Event::KeyUp { keycode, .. } => {
if let Some(key) = input_map.get(&keycode.unwrap_or(Keycode::Ampersand)) {
println!("Released button!");
controller.set_button_pressed_status(*key, false);
}
}

_ => { /* do nothing */ }
}
}
});
Expand Down
Loading