1mod apu;
6mod cartridges;
7mod clock;
8mod cpu;
9mod joypad;
10mod memory;
11mod mmu;
12mod ppu;
13mod serial;
14mod timer;
15
16use std::cell::RefCell;
17use std::path::Path;
18use std::rc::Rc;
19
20use crate::memory::Memory;
21
22pub struct Dimensions {
24 pub width: usize,
25 pub height: usize,
26}
27
28#[derive(Clone, Copy)]
33pub enum GameboyButton {
34 Right,
35 Left,
36 Up,
37 Down,
38 A,
39 B,
40 Select,
41 Start,
42}
43
44impl From<GameboyButton> for joypad::JoypadKey {
45 fn from(value: GameboyButton) -> joypad::JoypadKey {
46 match value {
47 GameboyButton::A => joypad::JoypadKey::A,
48 GameboyButton::B => joypad::JoypadKey::B,
49 GameboyButton::Right => joypad::JoypadKey::Right,
50 GameboyButton::Left => joypad::JoypadKey::Left,
51 GameboyButton::Up => joypad::JoypadKey::Up,
52 GameboyButton::Down => joypad::JoypadKey::Down,
53 GameboyButton::Select => joypad::JoypadKey::Select,
54 GameboyButton::Start => joypad::JoypadKey::Start,
55 }
56 }
57}
58
59pub struct Gameboy {
65 mmu: Rc<RefCell<mmu::Mmu>>,
66 cpu: cpu::RealTimeCpu,
67}
68
69impl Gameboy {
70 pub fn new(rom: Vec<u8>, save_path: impl AsRef<Path>, skip_checks: bool) -> Gameboy {
73 let cartridge = cartridges::new(rom, save_path, skip_checks);
74 let cartridge_mode = cartridge.get_mode();
75 let mmu = Rc::new(RefCell::new(mmu::Mmu::new(cartridge)));
76 let cpu = cpu::RealTimeCpu::new(cartridge_mode, mmu.clone());
77 Gameboy { mmu, cpu }
78 }
79
80 pub fn shutdown(&mut self) {
82 self.save();
83 }
84
85 pub fn try_enable_audio(&mut self) -> bool {
87 let apu = apu::Apu::new();
88 self.mmu.borrow_mut().apu = apu;
89 self.mmu.borrow().apu.is_some()
90 }
91
92 pub fn step(&mut self) -> u32 {
94 if self.mmu.borrow().get_byte(self.cpu.cpu.registers.pc) == 0x10 {
95 self.mmu.borrow_mut().perform_speed_switch();
96 }
97 let cycles = self.cpu.run();
98 self.mmu.borrow_mut().run_cycles(cycles);
99 cycles
100 }
101
102 pub fn save(&mut self) {
104 self.mmu.borrow_mut().cartridge.save();
105 }
106
107 pub fn get_rom_title(&self) -> String {
109 self.mmu.borrow().cartridge.get_title()
110 }
111
112 pub fn get_screen_dimensions(&self) -> Dimensions {
121 Dimensions {
122 width: ppu::SCREEN_WIDTH,
123 height: ppu::SCREEN_HEIGHT,
124 }
125 }
126
127 pub fn has_screen_updated(&mut self) -> bool {
130 let result = self.mmu.borrow().ppu.vblank;
131 self.mmu.borrow_mut().ppu.vblank = false;
132 result
133 }
134
135 pub fn get_screen_data(&self) -> [ppu::Pixel; ppu::SCREEN_WIDTH * ppu::SCREEN_HEIGHT] {
149 self.mmu.borrow().ppu.data
150 }
151
152 pub fn can_take_input(&mut self) -> bool {
154 self.cpu.flip()
155 }
156
157 pub fn handle_keydown(&mut self, button: GameboyButton) {
159 self.mmu.borrow_mut().joypad.keydown(button.into());
160 }
161
162 pub fn handle_keyup(&mut self, button: GameboyButton) {
164 self.mmu.borrow_mut().joypad.keyup(button.into());
165 }
166}