Skip to content

Commit 8002777

Browse files
authored
Merge pull request #6 from derzz/controller
added controller support for NON SCROLLING games(pacman works)
2 parents 7636d53 + 2028751 commit 8002777

4 files changed

Lines changed: 158 additions & 54 deletions

File tree

src/bus.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use core::panic;
22

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

1517
impl <'a>Bus<'a> {
16-
pub fn new<'call, F>(rom: Rom, gameloop_callback: F) -> Bus<'call> where F: FnMut(&PPU) + 'call,{
18+
pub fn new<'call, F>(rom: Rom, gameloop_callback: F) -> Bus<'call> where F: FnMut(&PPU, &mut Controller) + 'call,{
1719
let ppu = PPU::new(rom.chr_rom, rom.screen_mirroring);
1820
Bus {
1921
cpu_vram: [0; 2048],
2022
prg_rom: rom.prg_rom,
2123
ppu: ppu,
2224
cycles: 7, // Starting with 7 clock cycles
2325
gameloop_callback: Box::from(gameloop_callback),
26+
controller1: Controller::new()
2427
}
2528
}
2629
fn read_prg_rom(&self, mut addr: u16) -> u8 {
@@ -38,7 +41,7 @@ impl <'a>Bus<'a> {
3841
self.cycles += cycles as usize;
3942
let new_frame = self.ppu.tick(cycles * 3);
4043
if new_frame {
41-
(self.gameloop_callback)(&self.ppu);
44+
(self.gameloop_callback)(&self.ppu, &mut self.controller1);
4245
}
4346
}
4447

@@ -79,8 +82,17 @@ impl Mem for Bus<'_> {
7982
let mirror_down_addr = addr & 0x2007;
8083
self.mem_read(mirror_down_addr)
8184
}
82-
0x4000..=0x4017 => {
83-
// Ignore APU and joypads
85+
0x4000..=0x4015 => {
86+
// Ignoring APU
87+
0
88+
}
89+
90+
0x4016 =>{
91+
self.controller1.read()
92+
}
93+
94+
0x4017 =>{
95+
// Controller 2
8496
0
8597
}
8698
PROGRAM_RAM..=PROGRAM_RAM_END => self.read_prg_rom(addr),
@@ -136,11 +148,11 @@ impl Mem for Bus<'_> {
136148
}
137149

138150
0x4016 => {
139-
// ignore joypad 1;
151+
self.controller1.write(data);
140152
}
141153

142154
0x4017 => {
143-
// ignore joypad 2
155+
// ignore controller 2
144156
}
145157
_ => {
146158
println!("Ignoring mem write-access at {}", addr);

src/controller.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// If strobe is off, it will read controller input from highest to lowest bit
2+
// If strobe is on, it will read the states from the previous inputs and the state of the first button
3+
4+
use bitflags::bitflags;
5+
6+
bitflags!{
7+
#[derive(Copy, Clone, Debug)]
8+
pub struct ControllerButton: u8{
9+
const RIGHT = 0b1000_0000;
10+
const LEFT = 0b0100_0000;
11+
const DOWN = 0b0010_0000;
12+
const UP = 0b0001_0000;
13+
const START = 0b0000_1000;
14+
const SELECT = 0b0000_0100;
15+
const B = 0b0000_0010;
16+
const A = 0b0000_0001;
17+
}
18+
}
19+
20+
pub struct Controller{
21+
strobe: bool, // Determines if we are writing input or leaving the read
22+
button_index: u8,
23+
button_status: ControllerButton
24+
}
25+
26+
impl Controller{
27+
pub fn new() -> Self {
28+
Controller{
29+
strobe: false,
30+
button_index: 0,
31+
button_status: ControllerButton::from_bits_truncate(0b0000_0000),
32+
}
33+
}
34+
35+
pub fn write(&mut self, data: u8){
36+
println!("writing controller!");
37+
self.strobe = data & 1 == 1;
38+
if self.strobe{
39+
println!("resetting strobe!");
40+
// Starts at the first index
41+
self.button_index = 0
42+
}
43+
}
44+
45+
pub fn read(&mut self) -> u8{
46+
println!("reading controller!");
47+
if self.button_index > 7{
48+
return 1; // Indicates that there isn't anything left ot read
49+
}
50+
let response = (self.button_status.bits() & (1 << self.button_index)) >> self.button_index;
51+
if !self.strobe && self.button_index <= 7{
52+
self.button_index += 1; // Increments the index for the next read
53+
}
54+
println!("Response is {:x}", response);
55+
response
56+
}
57+
58+
pub fn set_button_pressed_status(&mut self, button: ControllerButton, input: bool){
59+
println!("Set status to {:?}", button);
60+
self.button_status.set(button, input);
61+
}
62+
}

src/lib.rs

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub mod trace;
88
pub mod frame;
99
pub mod palette;
1010
pub mod render;
11-
11+
pub mod controller;
1212

1313
use cpu::*;
1414

@@ -29,50 +29,52 @@ macro_rules! print_title {
2929
};
3030
}
3131

32-
pub fn run_nestest_and_capture() -> Vec<String> {
33-
let sdl_context = sdl2::init().unwrap();
34-
let video_subsystem = sdl_context.video().unwrap();
35-
let window = video_subsystem
36-
.window("Snake game", (32.0 * 10.0) as u32, (32.0 * 10.0) as u32)
37-
.position_centered()
38-
.build()
39-
.unwrap();
4032

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

45-
let creator = canvas.texture_creator();
46-
let mut texture = creator
47-
.create_texture_target(PixelFormatEnum::RGB24, 32, 32)
48-
.unwrap();
49-
canvas.set_scale(3.0, 3.0).unwrap();
50-
let game_bytes = std::fs::read("nestest.nes").unwrap();
51-
let rom = Rom::new(&game_bytes).unwrap();
52-
let mut frame = Frame::new();
53-
let bus = Bus::new(rom, move |ppu:&PPU|{
54-
render::render(ppu, &mut frame);
55-
texture.update(None, &frame.data, 265 * 3).unwrap();
43+
// let mut canvas = window.into_canvas().present_vsync().build().unwrap();
44+
// let mut event_pump = sdl_context.event_pump().unwrap();
45+
// canvas.set_scale(3.0, 3.0).unwrap();
5646

57-
canvas.copy(&texture, None, None).unwrap();
47+
// let creator = canvas.texture_creator();
48+
// let mut texture = creator
49+
// .create_texture_target(PixelFormatEnum::RGB24, 32, 32)
50+
// .unwrap();
51+
// canvas.set_scale(3.0, 3.0).unwrap();
52+
// let game_bytes = std::fs::read("nestest.nes").unwrap();
53+
// let rom = Rom::new(&game_bytes).unwrap();
54+
// let mut frame = Frame::new();
55+
// let bus = Bus::new(rom, move |ppu:&PPU|{
56+
// render::render(ppu, &mut frame);
57+
// texture.update(None, &frame.data, 265 * 3).unwrap();
5858

59-
canvas.present();
60-
for event in event_pump.poll_iter() {
61-
match event {
62-
Event::Quit { .. }
63-
| Event::KeyDown {
64-
keycode: Some(Keycode::Escape),
65-
..
66-
} => std::process::exit(0),
67-
_ => { /* do nothing */ }
68-
}
69-
}
70-
});
71-
let mut cpu = CPU::new(bus);
72-
cpu.reset();
73-
let mut output = Vec::new();
74-
cpu.run_with_callback(|cpu| {
75-
output.push(trace(cpu));
76-
});
77-
output
78-
}
59+
// canvas.copy(&texture, None, None).unwrap();
60+
61+
// canvas.present();
62+
// for event in event_pump.poll_iter() {
63+
// match event {
64+
// Event::Quit { .. }
65+
// | Event::KeyDown {
66+
// keycode: Some(Keycode::Escape),
67+
// ..
68+
// } => std::process::exit(0),
69+
// _ => { /* do nothing */ }
70+
// }
71+
// }
72+
// });
73+
// let mut cpu = CPU::new(bus);
74+
// cpu.reset();
75+
// let mut output = Vec::new();
76+
// cpu.run_with_callback(|cpu| {
77+
// output.push(trace(cpu));
78+
// });
79+
// output
80+
// }

src/main.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::HashMap;
2+
use nes::controller::{self, ControllerButton};
13
use nes::cpu::*;
24

35
use nes::frame::Frame;
@@ -12,6 +14,7 @@ use sdl2::pixels::PixelFormatEnum;
1214
use nes::bus::Bus;
1315

1416
fn main() {
17+
// Setting up screen and scaling
1518
let sdl_context = sdl2::init().unwrap();
1619
let video_subsystem = sdl_context.video().unwrap();
1720
let window = video_subsystem
@@ -37,12 +40,24 @@ fn main() {
3740
// .filter_level(log::LevelFilter::Debug)
3841
// .init();
3942

40-
let game_bytes = std::fs::read("roms/smb.nes").unwrap();
43+
// Setting up controllers
44+
let mut input_map = HashMap::new();
45+
input_map.insert(Keycode::Down, ControllerButton::DOWN);
46+
input_map.insert(Keycode::Up, ControllerButton::UP);
47+
input_map.insert(Keycode::Right, ControllerButton::RIGHT);
48+
input_map.insert(Keycode::Left, ControllerButton::LEFT);
49+
input_map.insert(Keycode::X, ControllerButton::B);
50+
input_map.insert(Keycode::Z, ControllerButton::A);
51+
input_map.insert(Keycode::Return, ControllerButton::START);
52+
input_map.insert(Keycode::Space, ControllerButton::SELECT);
53+
54+
// Game loading and CPU setup
55+
let game_bytes = std::fs::read("roms/pacman.nes").unwrap();
4156
let rom = Rom::new(&game_bytes).unwrap();
4257

4358
let mut frame = Frame::new();
4459

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

@@ -56,7 +71,20 @@ fn main() {
5671
keycode: Some(Keycode::Escape),
5772
..
5873
} => std::process::exit(0),
59-
_ => { /* do nothing */ }
74+
Event::KeyDown { keycode, .. } => {
75+
if let Some(key) = input_map.get(&keycode.unwrap_or(Keycode::Ampersand)) {
76+
println!("Pressed button!");
77+
controller.set_button_pressed_status(*key, true);
78+
}
79+
}
80+
Event::KeyUp { keycode, .. } => {
81+
if let Some(key) = input_map.get(&keycode.unwrap_or(Keycode::Ampersand)) {
82+
println!("Released button!");
83+
controller.set_button_pressed_status(*key, false);
84+
}
85+
}
86+
87+
_ => { /* do nothing */ }
6088
}
6189
}
6290
});

0 commit comments

Comments
 (0)