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}