super_sabicom/
lib.rs

1pub mod bus;
2pub mod cartridge;
3pub mod consts;
4pub mod context;
5pub mod cpu;
6pub mod dsp;
7pub mod ppu;
8pub mod rom;
9pub mod spc;
10
11use crate::context::Context;
12pub use crate::rom::Rom;
13
14use meru_interface::EmulatorCore;
15use schemars::JsonSchema;
16use serde::{Deserialize, Serialize};
17use thiserror::Error;
18
19pub struct Snes {
20    pub ctx: Context,
21}
22
23impl Snes {
24    pub fn new(rom: Rom, backup: Option<&[u8]>) -> Self {
25        Self {
26            ctx: Context::from_rom(rom, backup),
27        }
28    }
29}
30
31#[derive(Default, JsonSchema, Serialize, Deserialize)]
32pub struct Config {}
33
34#[derive(Error, Debug)]
35pub enum Error {
36    #[error("{0}")]
37    RomError(#[from] rom::RomError),
38    #[error("deserialize failed: {0}")]
39    DeserializeFailed(#[from] bincode::Error),
40}
41
42const CORE_INFO: meru_interface::CoreInfo = meru_interface::CoreInfo {
43    system_name: "SNES (Super Sabicom)",
44    abbrev: "snes",
45    file_extensions: &["sfc", "smc", "swc", "fig"],
46};
47
48impl EmulatorCore for Snes {
49    type Config = Config;
50    type Error = Error;
51
52    fn core_info() -> &'static meru_interface::CoreInfo {
53        &CORE_INFO
54    }
55
56    fn try_from_file(
57        data: &[u8],
58        backup: Option<&[u8]>,
59        _config: &Self::Config,
60    ) -> Result<Self, Self::Error> {
61        Ok(Snes::new(rom::Rom::from_bytes(&data)?, backup))
62    }
63
64    fn game_info(&self) -> Vec<(String, String)> {
65        use context::Cartridge;
66        let rom = self.ctx.cartridge().rom();
67        let header = &rom.header;
68        let game_code = header.game_code.map_or_else(
69            || "N/A".to_string(),
70            |b| String::from_utf8_lossy(&b).to_string(),
71        );
72        vec![
73            ("Title".into(), header.title.clone()),
74            ("Game Code".into(), game_code),
75            ("Speed".into(), format!("{:?}", header.speed)),
76            ("Map Mode".into(), format!("{:?}", header.map_mode)),
77            ("Chipset".into(), format!("{}", header.chipset)),
78            ("ROM Size".into(), format!("{}", header.rom_size)),
79            ("File Size".into(), format!("{}", rom.rom.len())),
80            ("SRAM Size".into(), format!("{}", header.sram_size)),
81            ("Country".into(), format!("{}", header.country)),
82            ("Developer ID".into(), format!("{}", header.developer_id)),
83            ("Rom Version".into(), format!("{}", header.rom_version)),
84        ]
85    }
86
87    fn set_config(&mut self, _config: &Self::Config) {}
88
89    fn exec_frame(&mut self, render_graphics: bool) {
90        use context::*;
91
92        self.ctx.spc_mut().clear_audio_buffer();
93        self.ctx.ppu_mut().set_render_graphics(render_graphics);
94
95        let start_frame = self.ctx.ppu().frame();
96
97        while start_frame == self.ctx.ppu().frame() {
98            self.ctx.exec_one();
99            self.ctx.ppu_tick();
100            self.ctx.spc_tick();
101            self.ctx.bus_tick();
102        }
103    }
104
105    fn reset(&mut self) {
106        use context::Cartridge;
107
108        let rom = self.ctx.cartridge().rom().clone();
109        let backup = self.backup();
110
111        self.ctx = Context::from_rom(rom, backup.as_deref());
112    }
113
114    fn frame_buffer(&self) -> &meru_interface::FrameBuffer {
115        use context::Ppu;
116        self.ctx.ppu().frame_buffer()
117    }
118
119    fn audio_buffer(&self) -> &meru_interface::AudioBuffer {
120        use context::Spc;
121        self.ctx.spc().audio_buffer()
122    }
123
124    fn default_key_config() -> meru_interface::KeyConfig {
125        use meru_interface::key_assign::*;
126
127        let controller = vec![
128            ("A", any!(keycode!(X), pad_button!(0, East))),
129            ("B", any!(keycode!(Z), pad_button!(0, South))),
130            ("X", any!(keycode!(S), pad_button!(0, North))),
131            ("Y", any!(keycode!(A), pad_button!(0, West))),
132            ("L", any!(keycode!(Q), pad_button!(0, LeftTrigger))),
133            ("R", any!(keycode!(W), pad_button!(0, RightTrigger))),
134            ("Start", any!(keycode!(Return), pad_button!(0, Start))),
135            ("Select", any!(keycode!(LShift), pad_button!(0, Select))),
136            ("Up", any!(keycode!(Up), pad_button!(0, DPadUp))),
137            ("Down", any!(keycode!(Down), pad_button!(0, DPadDown))),
138            ("Left", any!(keycode!(Left), pad_button!(0, DPadLeft))),
139            ("Right", any!(keycode!(Right), pad_button!(0, DPadRight))),
140        ];
141
142        let empty = vec![
143            ("A", KeyAssign::default()),
144            ("B", KeyAssign::default()),
145            ("X", KeyAssign::default()),
146            ("Y", KeyAssign::default()),
147            ("L", KeyAssign::default()),
148            ("R", KeyAssign::default()),
149            ("Start", KeyAssign::default()),
150            ("Select", KeyAssign::default()),
151            ("Up", KeyAssign::default()),
152            ("Down", KeyAssign::default()),
153            ("Left", KeyAssign::default()),
154            ("Right", KeyAssign::default()),
155        ];
156
157        meru_interface::KeyConfig {
158            controllers: vec![controller, empty.clone(), empty.clone(), empty]
159                .into_iter()
160                .map(|kvs| {
161                    kvs.into_iter()
162                        .map(|(key, assign)| (key.to_string(), assign))
163                        .collect()
164                })
165                .collect(),
166        }
167    }
168
169    fn set_input(&mut self, input: &meru_interface::InputData) {
170        use context::Bus;
171        self.ctx.bus_mut().set_input(input);
172    }
173
174    fn backup(&self) -> Option<Vec<u8>> {
175        use context::Cartridge;
176        self.ctx.cartridge().backup()
177    }
178
179    fn save_state(&self) -> Vec<u8> {
180        bincode::serialize(&self.ctx).unwrap()
181    }
182
183    fn load_state(&mut self, data: &[u8]) -> Result<(), Self::Error> {
184        use context::Cartridge;
185
186        let mut ctx: Context = bincode::deserialize(data)?;
187
188        // Restore ROM and memory mapping
189        ctx.cartridge_mut().restore(self.ctx.cartridge_mut());
190
191        self.ctx = ctx;
192
193        Ok(())
194    }
195}