1use ambassador::{delegatable_trait, Delegate};
2use serde::{Deserialize, Serialize};
3
4use crate::{interface::Color, mbc::create_mbc, util::to_si_bytesize};
5
6#[delegatable_trait]
7pub trait Bus {
8 fn tick(&mut self);
9 fn stop(&mut self);
10 fn read(&mut self, addr: u16) -> u8;
11 fn read_immutable(&mut self, addr: u16) -> Option<u8>;
12 fn write(&mut self, addr: u16, data: u8);
13}
14
15#[delegatable_trait]
16pub trait Vram {
17 fn vram(&self) -> &[u8];
18 fn vram_mut(&mut self) -> &mut [u8];
19 fn vram_lock(&self) -> bool;
20 fn set_vram_lock(&mut self, lock: bool);
21}
22
23#[delegatable_trait]
24pub trait Oam {
25 fn oam(&self) -> &[u8];
26 fn oam_mut(&mut self) -> &mut [u8];
27 fn oam_lock(&self) -> bool;
28 fn set_oam_lock(&mut self, lock: bool);
29}
30
31#[delegatable_trait]
32pub trait ExternalRam {
33 fn external_ram(&self) -> &[u8];
34 fn external_ram_mut(&mut self) -> &mut [u8];
35}
36
37#[delegatable_trait]
38pub trait Ppu {
39 fn read_ppu(&mut self, addr: u16) -> u8;
40 fn write_ppu(&mut self, addr: u16, data: u8);
41 fn mode(&self) -> crate::ppu::Mode;
42}
43
44#[delegatable_trait]
45pub trait Apu {
46 fn apu(&self) -> &crate::apu::Apu;
47 fn apu_mut(&mut self) -> &mut crate::apu::Apu;
48}
49
50#[delegatable_trait]
51pub trait Rom {
52 fn rom(&self) -> &crate::rom::Rom;
53 fn rom_mut(&mut self) -> &mut crate::rom::Rom;
54}
55
56#[delegatable_trait]
57pub trait Model {
58 fn model(&self) -> crate::config::Model;
59 fn running_mode(&self) -> RunningMode;
60 fn set_running_mode(&mut self, mode: RunningMode);
61}
62
63#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize)]
64pub enum RunningMode {
65 Cgb,
66 Dmg,
67 Pgb1,
68 Pgb2,
69}
70
71impl RunningMode {
72 pub fn is_cgb(&self) -> bool {
73 matches!(self, RunningMode::Cgb)
74 }
75}
76
77#[delegatable_trait]
78pub trait InterruptFlag {
79 fn interrupt_enable(&mut self) -> u8;
80 fn set_interrupt_enable(&mut self, data: u8);
81 fn interrupt_flag(&mut self) -> u8;
82 fn set_interrupt_flag(&mut self, data: u8);
83 fn stall_cpu(&mut self, cycle: usize);
84 fn check_stall_cpu(&mut self) -> bool;
85 fn wake(&mut self);
86 fn check_wake(&mut self) -> bool;
87
88 fn set_interrupt_flag_bit(&mut self, bit: usize) {
89 let new_flag = self.interrupt_flag() | (1 << bit);
90 self.set_interrupt_flag(new_flag);
91 }
92 fn clear_interrupt_flag_bit(&mut self, bit: usize) {
93 let new_flag = self.interrupt_flag() & !(1 << bit);
94 self.set_interrupt_flag(new_flag);
95 }
96}
97
98impl Context {
99 pub fn new(
100 model: crate::config::Model,
101 rom: crate::rom::Rom,
102 boot_rom: &Option<Vec<u8>>,
103 backup_ram: Option<Vec<u8>>,
104 dmg_palette: &[Color; 4],
105 ) -> Self {
106 let io = crate::io::Io::new();
107
108 let mut backup_ram = backup_ram;
109 let internal_ram = if rom.cartridge_type.has_internal_ram() {
110 let mut dmy = None;
111 std::mem::swap(&mut dmy, &mut backup_ram);
112 dmy
113 } else {
114 None
115 };
116 let mbc = create_mbc(&rom, internal_ram);
117 let bus = crate::bus::Bus::new(model, mbc, boot_rom, io);
118 let vram_size = if model.is_cgb() { 0x4000 } else { 0x2000 };
119 let running_mode = if model.is_cgb() {
120 RunningMode::Cgb
121 } else {
122 RunningMode::Dmg
123 };
124
125 let external_ram = if let Some(ram) = backup_ram {
126 if !rom.cartridge_type.has_battery {
127 panic!("Trying to load backup RAM even cartridge has no battery backup RAM");
128 }
129 if ram.len() != rom.ram_size as usize {
130 panic!(
131 "Loading backup RAM size does not match ROM's info: {} != {}",
132 to_si_bytesize(ram.len() as _),
133 to_si_bytesize(rom.ram_size as _)
134 );
135 }
136 ram
137 } else {
138 vec![0; rom.ram_size as usize]
139 };
140
141 Self {
142 cpu: crate::cpu::Cpu::new(),
143 inner: InnerContext0 {
144 bus,
145 inner: InnerContext1 {
146 rom,
147 ppu: crate::ppu::Ppu::new(dmg_palette),
148 apu: crate::apu::Apu::new(),
149 inner: InnerContext2 {
150 model,
151 running_mode,
152 vram: vec![0; vram_size],
153 vram_lock: false,
154 oam: vec![0; 0xA0],
155 oam_lock: false,
156 external_ram,
157 interrupt_enable: 0,
158 interrupt_flag: 0,
159 stall_cpu: 0,
160 wake: false,
161 },
162 },
163 },
164 }
165 }
166
167 pub fn backup_ram(&self) -> Option<Vec<u8>> {
168 if self.rom().ram_size > 0 && self.rom().cartridge_type.has_battery {
169 Some(self.external_ram().to_vec())
170 } else {
171 None
172 }
173 }
174}
175
176#[derive(Serialize, Deserialize, Delegate)]
177#[delegate(Rom, target = "inner")]
178#[delegate(Ppu, target = "inner")]
179#[delegate(Apu, target = "inner")]
180#[delegate(Model, target = "inner")]
181#[delegate(Vram, target = "inner")]
182#[delegate(Oam, target = "inner")]
183#[delegate(ExternalRam, target = "inner")]
184#[delegate(InterruptFlag, target = "inner")]
185pub struct Context {
186 pub cpu: crate::cpu::Cpu,
187 #[serde(flatten)]
188 pub inner: InnerContext0,
189}
190
191#[derive(Serialize, Deserialize, Delegate)]
192#[delegate(Rom, target = "inner")]
193#[delegate(Ppu, target = "inner")]
194#[delegate(Apu, target = "inner")]
195#[delegate(Model, target = "inner")]
196#[delegate(Vram, target = "inner")]
197#[delegate(Oam, target = "inner")]
198#[delegate(ExternalRam, target = "inner")]
199#[delegate(InterruptFlag, target = "inner")]
200pub struct InnerContext0 {
201 pub bus: crate::bus::Bus,
202 #[serde(flatten)]
203 pub inner: InnerContext1,
204}
205
206impl Bus for InnerContext0 {
207 fn tick(&mut self) {
208 self.bus.tick(&mut self.inner);
209 let speed = self.bus.current_speed();
210 for _ in 0..if speed == 0 { 4 } else { 2 } {
211 self.inner.ppu.tick(&mut self.inner.inner);
212 self.inner.apu.tick();
213 }
214 self.bus.io().serial().tick(&mut self.inner);
215 self.bus.io().tick(&mut self.inner);
216 }
217
218 fn stop(&mut self) {
219 self.bus.stop();
220 }
221
222 fn read(&mut self, addr: u16) -> u8 {
223 self.bus.read(&mut self.inner, addr)
224 }
225
226 fn read_immutable(&mut self, addr: u16) -> Option<u8> {
227 self.bus.read_immutable(&mut self.inner, addr)
228 }
229
230 fn write(&mut self, addr: u16, data: u8) {
231 self.bus.write(&mut self.inner, addr, data)
232 }
233}
234
235#[derive(Serialize, Deserialize, Delegate)]
236#[delegate(Model, target = "inner")]
237#[delegate(Vram, target = "inner")]
238#[delegate(Oam, target = "inner")]
239#[delegate(ExternalRam, target = "inner")]
240#[delegate(InterruptFlag, target = "inner")]
241pub struct InnerContext1 {
242 #[serde(skip)]
243 pub rom: crate::rom::Rom,
244 pub ppu: crate::ppu::Ppu,
245 pub apu: crate::apu::Apu,
246 #[serde(flatten)]
247 pub inner: InnerContext2,
248}
249
250impl Rom for InnerContext1 {
251 fn rom(&self) -> &crate::rom::Rom {
252 &self.rom
253 }
254 fn rom_mut(&mut self) -> &mut crate::rom::Rom {
255 &mut self.rom
256 }
257}
258
259impl Ppu for InnerContext1 {
260 fn read_ppu(&mut self, addr: u16) -> u8 {
261 self.ppu.read(&self.inner, addr)
262 }
263 fn write_ppu(&mut self, addr: u16, data: u8) {
264 self.ppu.write(&self.inner, addr, data)
265 }
266 fn mode(&self) -> crate::ppu::Mode {
267 self.ppu.mode()
268 }
269}
270
271impl Apu for InnerContext1 {
272 fn apu(&self) -> &crate::apu::Apu {
273 &self.apu
274 }
275 fn apu_mut(&mut self) -> &mut crate::apu::Apu {
276 &mut self.apu
277 }
278}
279
280#[derive(Serialize, Deserialize)]
281pub struct InnerContext2 {
282 model: crate::config::Model,
283 running_mode: RunningMode,
284 #[serde(with = "serde_bytes")]
285 vram: Vec<u8>,
286 vram_lock: bool,
287 #[serde(with = "serde_bytes")]
288 oam: Vec<u8>,
289 oam_lock: bool,
290 #[serde(with = "serde_bytes")]
291 external_ram: Vec<u8>,
292 interrupt_enable: u8,
293 interrupt_flag: u8,
294 stall_cpu: usize,
295 wake: bool,
296}
297
298impl Model for InnerContext2 {
299 fn model(&self) -> crate::config::Model {
300 self.model
301 }
302 fn running_mode(&self) -> RunningMode {
303 self.running_mode
304 }
305 fn set_running_mode(&mut self, mode: RunningMode) {
306 self.running_mode = mode;
307 }
308}
309
310impl Vram for InnerContext2 {
311 fn vram(&self) -> &[u8] {
312 &self.vram
313 }
314 fn vram_mut(&mut self) -> &mut [u8] {
315 &mut self.vram
316 }
317 fn vram_lock(&self) -> bool {
318 self.vram_lock
319 }
320 fn set_vram_lock(&mut self, lock: bool) {
321 self.vram_lock = lock;
322 }
323}
324
325impl Oam for InnerContext2 {
326 fn oam(&self) -> &[u8] {
327 &self.oam
328 }
329 fn oam_mut(&mut self) -> &mut [u8] {
330 &mut self.oam
331 }
332 fn oam_lock(&self) -> bool {
333 self.oam_lock
334 }
335 fn set_oam_lock(&mut self, lock: bool) {
336 self.oam_lock = lock;
337 }
338}
339
340impl ExternalRam for InnerContext2 {
341 fn external_ram(&self) -> &[u8] {
342 &self.external_ram
343 }
344 fn external_ram_mut(&mut self) -> &mut [u8] {
345 &mut self.external_ram
346 }
347}
348
349impl InterruptFlag for InnerContext2 {
350 fn interrupt_enable(&mut self) -> u8 {
351 self.interrupt_enable
352 }
353 fn set_interrupt_enable(&mut self, data: u8) {
354 self.interrupt_enable = data;
355 }
356 fn interrupt_flag(&mut self) -> u8 {
357 self.interrupt_flag
358 }
359 fn set_interrupt_flag(&mut self, data: u8) {
360 self.interrupt_flag = data;
361 }
362 fn stall_cpu(&mut self, cycle: usize) {
363 self.stall_cpu += cycle;
364 }
365 fn check_stall_cpu(&mut self) -> bool {
366 if self.stall_cpu > 0 {
367 self.stall_cpu -= 1;
368 true
369 } else {
370 false
371 }
372 }
373 fn wake(&mut self) {
374 self.wake = true;
375 }
376 fn check_wake(&mut self) -> bool {
377 let ret = self.wake;
378 self.wake = false;
379 ret
380 }
381}