Use Rc<RefCell<T>> to have the GameboyAdvance struct hold references to platform video,audio,input combo

Former-commit-id: bfe233a333790fe1bad1038bd553a3fe244e57fa
This commit is contained in:
Michel Heily 2019-12-09 23:37:46 +02:00
parent aee86d85c8
commit 385016f24a
6 changed files with 87 additions and 37 deletions

View file

@ -1,4 +1,7 @@
/// Struct containing everything /// Struct containing everything
use std::cell::RefCell;
use std::rc::Rc;
use super::arm7tdmi::Core; use super::arm7tdmi::Core;
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::gpu::*; use super::gpu::*;
@ -10,28 +13,53 @@ use super::SyncedIoDevice;
use super::super::{AudioInterface, InputInterface, VideoInterface}; use super::super::{AudioInterface, InputInterface, VideoInterface};
pub struct GameBoyAdvance { pub struct GameBoyAdvance<V, A, I>
pub cpu: Core, where
V: VideoInterface,
A: AudioInterface,
I: InputInterface,
{
pub sysbus: Box<SysBus>, pub sysbus: Box<SysBus>,
pub cpu: Core,
video_device: Rc<RefCell<V>>,
audio_device: Rc<RefCell<A>>,
input_device: Rc<RefCell<I>>,
} }
impl GameBoyAdvance { impl<V, A, I> GameBoyAdvance<V, A, I>
pub fn new(cpu: Core, bios_rom: Vec<u8>, gamepak: Cartridge) -> GameBoyAdvance { where
V: VideoInterface,
A: AudioInterface,
I: InputInterface,
{
pub fn new(
cpu: Core,
bios_rom: Vec<u8>,
gamepak: Cartridge,
video_device: Rc<RefCell<V>>,
audio_device: Rc<RefCell<A>>,
input_device: Rc<RefCell<I>>,
) -> GameBoyAdvance<V, A, I> {
let io = IoDevices::new(); let io = IoDevices::new();
GameBoyAdvance { GameBoyAdvance {
cpu: cpu, cpu: cpu,
sysbus: Box::new(SysBus::new(io, bios_rom, gamepak)), sysbus: Box::new(SysBus::new(io, bios_rom, gamepak)),
video_device: video_device,
audio_device: audio_device,
input_device: input_device,
} }
} }
pub fn frame(&mut self, video: &mut VideoInterface, input: &mut InputInterface) { pub fn frame(&mut self) {
self.sysbus.io.keyinput = input.poll(); self.sysbus.io.keyinput = self.input_device.borrow_mut().poll();
while self.sysbus.io.gpu.state != GpuState::VBlank { while self.sysbus.io.gpu.state != GpuState::VBlank {
self.step_new(); self.step();
} }
video.render(self.sysbus.io.gpu.get_framebuffer()); self.video_device
.borrow_mut()
.render(self.sysbus.io.gpu.get_framebuffer());
while self.sysbus.io.gpu.state == GpuState::VBlank { while self.sysbus.io.gpu.state == GpuState::VBlank {
self.step_new(); self.step();
} }
} }
@ -56,7 +84,7 @@ impl GameBoyAdvance {
None None
} }
pub fn step_new(&mut self) { pub fn step(&mut self) {
let mut irqs = IrqBitmask(0); let mut irqs = IrqBitmask(0);
let previous_cycles = self.cpu.cycles; let previous_cycles = self.cpu.cycles;

View file

@ -8,6 +8,7 @@ use crate::core::arm7tdmi::thumb::ThumbInstruction;
use crate::core::arm7tdmi::{Addr, CpuState}; use crate::core::arm7tdmi::{Addr, CpuState};
use crate::core::GBAError; use crate::core::GBAError;
use crate::disass::Disassembler; use crate::disass::Disassembler;
use crate::{AudioInterface, InputInterface, VideoInterface};
use super::palette_view::create_palette_view; use super::palette_view::create_palette_view;
// use super::tile_view::create_tile_view; // use super::tile_view::create_tile_view;
@ -61,7 +62,12 @@ pub enum Command {
TraceToggle(TraceFlags), TraceToggle(TraceFlags),
} }
impl Debugger { impl<V, A, I> Debugger<V, A, I>
where
V: VideoInterface,
A: AudioInterface,
I: InputInterface,
{
pub fn run_command(&mut self, command: Command) { pub fn run_command(&mut self, command: Command) {
use Command::*; use Command::*;
match command { match command {
@ -78,9 +84,9 @@ impl Debugger {
if !self.ctrlc_flag.load(Ordering::SeqCst) { if !self.ctrlc_flag.load(Ordering::SeqCst) {
break; break;
} }
self.gba.step_new(); self.gba.step();
while self.gba.cpu.last_executed.is_none() { while self.gba.cpu.last_executed.is_none() {
self.gba.step_new(); self.gba.step();
} }
let last_executed = self.gba.cpu.last_executed.unwrap(); let last_executed = self.gba.cpu.last_executed.unwrap();
print!( print!(
@ -113,7 +119,7 @@ impl Debugger {
// break; // break;
// } // }
// _ => { // _ => {
// self.gba.step_new(); // self.gba.step();
// } // }
// } // }
// } // }

View file

@ -12,6 +12,8 @@ use colored::*;
use super::core::arm7tdmi::{Addr, Bus, CpuError}; use super::core::arm7tdmi::{Addr, Bus, CpuError};
use super::core::GameBoyAdvance; use super::core::GameBoyAdvance;
use super::{AudioInterface, InputInterface, VideoInterface};
mod parser; mod parser;
use parser::{parse_expr, DerefType, Expr, Value}; use parser::{parse_expr, DerefType, Expr, Value};
@ -46,15 +48,25 @@ impl From<::std::io::Error> for DebuggerError {
type DebuggerResult<T> = Result<T, DebuggerError>; type DebuggerResult<T> = Result<T, DebuggerError>;
pub struct Debugger { pub struct Debugger<V, A, I>
pub gba: GameBoyAdvance, where
V: VideoInterface,
A: AudioInterface,
I: InputInterface,
{
pub gba: GameBoyAdvance<V, A, I>,
running: bool, running: bool,
pub ctrlc_flag: Arc<AtomicBool>, pub ctrlc_flag: Arc<AtomicBool>,
pub previous_command: Option<Command>, pub previous_command: Option<Command>,
} }
impl Debugger { impl<V, A, I> Debugger<V, A, I>
pub fn new(gba: GameBoyAdvance) -> Debugger { where
V: VideoInterface,
A: AudioInterface,
I: InputInterface,
{
pub fn new(gba: GameBoyAdvance<V, A, I>) -> Debugger<V, A, I> {
let ctrlc_flag = Arc::new(AtomicBool::new(true)); let ctrlc_flag = Arc::new(AtomicBool::new(true));
let r = ctrlc_flag.clone(); let r = ctrlc_flag.clone();
ctrlc::set_handler(move || { ctrlc::set_handler(move || {

View file

@ -7,12 +7,12 @@ use rustboyadvance_ng::InputInterface;
extern crate bit; extern crate bit;
use bit::BitIndex; use bit::BitIndex;
pub struct Sdl2Keyboard { pub struct Sdl2Input {
event_pump: EventPump, event_pump: EventPump,
keyinput: u16, keyinput: u16,
} }
impl InputInterface for Sdl2Keyboard { impl InputInterface for Sdl2Input {
fn poll(&mut self) -> u16 { fn poll(&mut self) -> u16 {
for event in self.event_pump.poll_iter() { for event in self.event_pump.poll_iter() {
match event { match event {
@ -56,8 +56,8 @@ fn keycode_to_keypad(keycode: Keycode) -> Option<gba_keypad::Keys> {
} }
} }
pub fn create_keyboard(sdl: &sdl2::Sdl) -> Sdl2Keyboard { pub fn create_keyboard(sdl: &sdl2::Sdl) -> Sdl2Input {
Sdl2Keyboard { Sdl2Input {
event_pump: sdl.event_pump().unwrap(), event_pump: sdl.event_pump().unwrap(),
keyinput: gba_keypad::KEYINPUT_ALL_RELEASED, keyinput: gba_keypad::KEYINPUT_ALL_RELEASED,
} }

View file

@ -1,5 +1,7 @@
extern crate sdl2; extern crate sdl2;
use sdl2::Sdl;
use std::cell::RefCell;
use std::rc::Rc;
use std::path::Path; use std::path::Path;
use std::time; use std::time;
@ -11,9 +13,9 @@ mod audio;
mod keyboard; mod keyboard;
mod video; mod video;
use keyboard::create_keyboard; use audio::{create_audio_player, Sdl2AudioPlayer};
use video::create_video_interface; use keyboard::{create_keyboard, Sdl2Input};
use audio::create_audio_player; use video::{create_video_interface, Sdl2Video};
#[macro_use] #[macro_use]
extern crate rustboyadvance_ng; extern crate rustboyadvance_ng;
@ -41,12 +43,13 @@ fn main() {
let cpu = cpu; let cpu = cpu;
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init().unwrap();
let mut video = create_video_interface(&sdl_context); let video = Rc::new(RefCell::new(create_video_interface(&sdl_context)));
let mut audio = create_audio_player(&sdl_context); let audio = Rc::new(RefCell::new(create_audio_player(&sdl_context)));
let mut keyboard = create_keyboard(&sdl_context); let keyboard = Rc::new(RefCell::new(create_keyboard(&sdl_context)));
let mut fps_counter = FpsCounter::default(); let mut fps_counter = FpsCounter::default();
let mut gba = GameBoyAdvance::new(cpu, bios_bin, cart); let mut gba: GameBoyAdvance<Sdl2Video, Sdl2AudioPlayer, Sdl2Input> =
GameBoyAdvance::new(cpu, bios_bin, cart, video.clone(), audio.clone(), keyboard.clone());
if debug { if debug {
gba.cpu.set_verbose(true); gba.cpu.set_verbose(true);
@ -59,10 +62,11 @@ fn main() {
loop { loop {
let start_time = time::Instant::now(); let start_time = time::Instant::now();
gba.frame(&mut video, &mut keyboard); gba.frame();
if let Some(fps) = fps_counter.tick() { if let Some(fps) = fps_counter.tick() {
let title = format!("{} ({} fps)", rom_name, fps); let title = format!("{} ({} fps)", rom_name, fps);
video.set_window_title(&title); video.borrow_mut().set_window_title(&title);
} }
if !no_framerate_limit { if !no_framerate_limit {

View file

@ -12,19 +12,19 @@ const SCREEN_WIDTH: u32 = DISPLAY_WIDTH as u32;
const SCREEN_HEIGHT: u32 = DISPLAY_HEIGHT as u32; const SCREEN_HEIGHT: u32 = DISPLAY_HEIGHT as u32;
const SCALE: u32 = 3; // TODO control via CLI & support window resize const SCALE: u32 = 3; // TODO control via CLI & support window resize
pub struct Sdl2VideoInterface { pub struct Sdl2Video {
tc: TextureCreator<WindowContext>, tc: TextureCreator<WindowContext>,
canvas: WindowCanvas, canvas: WindowCanvas,
fps_counter: FpsCounter, fps_counter: FpsCounter,
} }
impl Sdl2VideoInterface { impl Sdl2Video {
pub fn set_window_title(&mut self, title: &str) { pub fn set_window_title(&mut self, title: &str) {
self.canvas.window_mut().set_title(&title); self.canvas.window_mut().set_title(&title);
} }
} }
impl VideoInterface for Sdl2VideoInterface { impl VideoInterface for Sdl2Video {
fn render(&mut self, buffer: &[u32]) { fn render(&mut self, buffer: &[u32]) {
let mut texture = self let mut texture = self
.tc .tc
@ -53,7 +53,7 @@ impl VideoInterface for Sdl2VideoInterface {
} }
} }
pub fn create_video_interface(sdl: &Sdl) -> Sdl2VideoInterface { pub fn create_video_interface(sdl: &Sdl) -> Sdl2Video {
let video_subsystem = sdl.video().unwrap(); let video_subsystem = sdl.video().unwrap();
let window = video_subsystem let window = video_subsystem
.window( .window(
@ -69,7 +69,7 @@ pub fn create_video_interface(sdl: &Sdl) -> Sdl2VideoInterface {
canvas.set_draw_color(Color::RGB(0, 0, 0)); canvas.set_draw_color(Color::RGB(0, 0, 0));
canvas.clear(); canvas.clear();
let tc = canvas.texture_creator(); let tc = canvas.texture_creator();
Sdl2VideoInterface { Sdl2Video {
tc: tc, tc: tc,
canvas: canvas, canvas: canvas,
fps_counter: Default::default(), fps_counter: Default::default(),