Skip to content
Snippets Groups Projects
state.rs 24.6 KiB
Newer Older
use std::{
    convert::TryInto,
    fmt::{self, Display, Formatter},
    fs::File,
    io::{Cursor, Read, Seek, SeekFrom, Write},
    mem::size_of,
use crate::{gb::GameBoy, info::Info};

pub trait Serialize {
    fn save(&mut self, buffer: &mut Vec<u8>);
    fn load(&mut self, data: &mut Cursor<Vec<u8>>);
}
pub trait State {
    fn from_gb(gb: &mut GameBoy) -> Self;
    fn to_gb(&self, gb: &mut GameBoy) -> Result<(), String>;
João Magalhães's avatar
João Magalhães committed
#[derive(Default)]
pub struct BeesState {
    footer: BeesFooter,
    name: BeesName,
    info: BeesInfo,
    core: BeesCore,
    mbc: BeesMbc,
impl BeesState {
    pub fn description(&self, column_length: usize) -> String {
        let emulator_l = format!("{:width$}", "Emulator", width = column_length);
        let title_l: String = format!("{:width$}", "Title", width = column_length);
        let version_l: String = format!("{:width$}", "Version", width = column_length);
        let model_l: String = format!("{:width$}", "Model", width = column_length);
        let ram_l: String = format!("{:width$}", "RAM", width = column_length);
        let vram_l: String = format!("{:width$}", "VRAM", width = column_length);
            "{}  {}\n{}  {}\n{}  {}.{}\n{}  {}\n{}  {}\n{}  {}\n",
            emulator_l,
            self.name.name,
            title_l,
            self.info.title(),
            version_l,
            self.core.major,
            self.core.minor,
            model_l,
            self.core.model,
            ram_l,
            self.core.ram.size,
            vram_l,
            self.core.vram.size,

    pub fn verify(&self) -> Result<(), String> {
João Magalhães's avatar
João Magalhães committed
        self.footer.verify()?;
        self.core.verify()?;
    /// Dumps the core data into the provided buffer and returns.
    /// This will effectively populate the majority of the save
    /// file with the core emulator contents.
    fn dump_core(&mut self, buffer: &mut Vec<u8>) -> u32 {
        let mut offset = 0x0000_u32;

        let mut buffers = vec![
            &mut self.core.ram,
            &mut self.core.vram,
            &mut self.core.mbc_ram,
            &mut self.core.oam,
            &mut self.core.hram,
            &mut self.core.background_palettes,
            &mut self.core.object_palettes,
        ];

        for item in buffers.iter_mut() {
            item.offset = offset;
            buffer.write_all(&item.buffer).unwrap();
            offset += item.size;
impl Serialize for BeesState {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.footer.start_offset = self.dump_core(buffer);
        self.name.save(buffer);
        self.info.save(buffer);
        self.core.save(buffer);
        self.mbc.save(buffer);
        self.end.save(buffer);
        self.footer.save(buffer);
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        // moves the cursor to the end of the file
        // to read the footer, and then places the
        // the cursor in the start of the BEES data
        // according to the footer information
        data.seek(SeekFrom::End(-8)).unwrap();
        self.footer.load(data);
        data.seek(SeekFrom::Start(self.footer.start_offset as u64))
            .unwrap();

        loop {
            // reads the block information and then moves the cursor
            // back to the original position to be able to re-read the
            // block data
            // @TODO: may read only the Block header that should suffice
            // fo the verification we're doing and should save us some cycles
            let block = BeesBlock::from_data(data);
            let offset = -((block.header.size as usize + size_of::<u32>() * 2) as i64);
            data.seek(SeekFrom::Current(offset)).unwrap();

            println!("{}", block.magic().as_str());

            match block.magic().as_str() {
                "NAME" => self.name = BeesName::from_data(data),
                "INFO" => self.info = BeesInfo::from_data(data),
                "CORE" => self.core = BeesCore::from_data(data),
                "MBC " => self.mbc = BeesMbc::from_data(data),
                "END " => self.end = BeesBlock::from_data(data),
                _ => { BeesBlock::from_data(data); }
    }
}

impl State for BeesState {
    fn from_gb(gb: &mut GameBoy) -> Self {
            footer: BeesFooter::default(),
            name: BeesName::from_gb(gb),
            info: BeesInfo::from_gb(gb),
            core: BeesCore::from_gb(gb),
            mbc: BeesMbc::from_gb(gb),
João Magalhães's avatar
João Magalhães committed
            end: BeesBlock::from_magic(String::from("END ")),
    fn to_gb(&self, gb: &mut GameBoy) -> Result<(), String> {
        self.verify()?;
        self.name.to_gb(gb)?;
        self.info.to_gb(gb)?;
        self.core.to_gb(gb)?;
        self.mbc.to_gb(gb)?;
}

impl Display for BeesState {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description(9))
pub struct BeesBlockHeader {
impl BeesBlockHeader {
    pub fn new(magic: String, size: u32) -> Self {
        Self { magic, size }
    }
}

impl Serialize for BeesBlockHeader {
    fn save(&mut self, buffer: &mut Vec<u8>) {
João Magalhães's avatar
João Magalhães committed
        buffer.write_all(self.magic.as_bytes()).unwrap();
        buffer.write_all(&self.size.to_le_bytes()).unwrap();
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
        self.magic = String::from_utf8(Vec::from(buffer)).unwrap();
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.size = u32::from_le_bytes(buffer);
impl Default for BeesBlockHeader {
    fn default() -> Self {
        Self::new(String::from("    "), 0)
    }
}

pub struct BeesBlock {
    header: BeesBlockHeader,
    buffer: Vec<u8>,
}

impl BeesBlock {
    pub fn new(header: BeesBlockHeader, buffer: Vec<u8>) -> Self {
        Self { header, buffer }
    }

    pub fn from_magic(magic: String) -> Self {
        Self::new(BeesBlockHeader::new(magic, 0), vec![])
    }

    pub fn from_data(data: &mut Cursor<Vec<u8>>) -> Self {
        let mut instance = Self::default();
        instance.header.load(data);
        let mut buffer = vec![0x00; instance.header.size as usize];
        data.read_exact(&mut buffer).unwrap();
        instance.buffer = buffer;
        instance
    }

    pub fn magic(&self) -> &String {
        &self.header.magic
    }

    pub fn is_end(&self) -> bool {
        self.magic() == "END "
    }
}

impl Serialize for BeesBlock {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.header.save(buffer);
        buffer.write_all(&self.buffer).unwrap();
    }

    fn load(&mut self, _data: &mut Cursor<Vec<u8>>) {
        todo!()
    }
}

impl Default for BeesBlock {
    fn default() -> Self {
        Self::new(BeesBlockHeader::default(), vec![])
    }
}

pub struct BeesBuffer {
    buffer: Vec<u8>,
}

impl BeesBuffer {
    pub fn new(size: u32, offset: u32, buffer: Vec<u8>) -> Self {
        Self {
            size,
            offset,
            buffer,
        }
    }

    /// Fills the buffer with new data and updating the size
    /// value accordingly.
    fn fill_buffer(&mut self, data: &[u8]) {
        self.size = data.len() as u32;
        self.buffer = data.to_vec();
    }

    /// Loads the internal buffer structure with the provided
    /// data according to the size and offset defined.
    fn load_buffer(&self, data: &mut Cursor<Vec<u8>>) -> Vec<u8> {
        let mut buffer = vec![0x00; self.size as usize];
        let position = data.position();
        data.seek(SeekFrom::Start(self.offset as u64)).unwrap();
        data.read_exact(&mut buffer).unwrap();
        data.set_position(position);
        buffer
    }
impl Serialize for BeesBuffer {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        buffer.write_all(&self.size.to_le_bytes()).unwrap();
        buffer.write_all(&self.offset.to_le_bytes()).unwrap();
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.size = u32::from_le_bytes(buffer);
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.offset = u32::from_le_bytes(buffer);
        self.buffer = self.load_buffer(data);
    }
}

impl Default for BeesBuffer {
    fn default() -> Self {
        Self::new(0, 0, vec![])
pub struct BeesFooter {
    start_offset: u32,
    magic: u32,
impl BeesFooter {
    pub fn new(start_offset: u32, magic: u32) -> Self {
        Self {
            start_offset,
            magic,
        }
    }

    pub fn verify(&self) -> Result<(), String> {
        if self.magic != 0x53534542 {
            return Err(String::from("Invalid magic"));
        }
        Ok(())
    }
}

impl Serialize for BeesFooter {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        buffer.write_all(&self.start_offset.to_le_bytes()).unwrap();
        buffer.write_all(&self.magic.to_le_bytes()).unwrap();
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.start_offset = u32::from_le_bytes(buffer);
        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.magic = u32::from_le_bytes(buffer);
    }
}

impl Default for BeesFooter {
    fn default() -> Self {
        Self::new(0x00, 0x53534542)
    }
}

pub struct BeesName {
    header: BeesBlockHeader,
    name: String,
impl BeesName {
    pub fn new(name: String) -> Self {
        Self {
            header: BeesBlockHeader::new(String::from("NAME"), name.len() as u32),
            name,
        }
    }

    pub fn from_data(data: &mut Cursor<Vec<u8>>) -> Self {
        let mut instance = Self::default();
        instance.load(data);
        instance
    }
}

impl Serialize for BeesName {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.header.save(buffer);
        buffer.write_all(self.name.as_bytes()).unwrap();
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        self.header.load(data);
        let mut buffer = vec![0x00; self.header.size as usize];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.name = String::from_utf8(buffer).unwrap();
impl State for BeesName {
    fn from_gb(_gb: &mut GameBoy) -> Self {
        Self::new(format!("{} v{}", Info::name(), Info::version()))
    fn to_gb(&self, _gb: &mut GameBoy) -> Result<(), String> {
        Ok(())
    }
impl Default for BeesName {
    fn default() -> Self {
        Self::new(String::from(""))
    }
}

pub struct BeesInfo {
    header: BeesBlockHeader,
    title: [u8; 16],
    checksum: [u8; 2],
impl BeesInfo {
    pub fn new(title: &[u8], checksum: &[u8]) -> Self {
        Self {
            header: BeesBlockHeader::new(
                String::from("INFO"),
                title.len() as u32 + checksum.len() as u32,
            ),
            title: title.try_into().unwrap(),
            checksum: checksum.try_into().unwrap(),
        }
    }
    pub fn from_data(data: &mut Cursor<Vec<u8>>) -> Self {
        let mut instance = Self::default();
        instance.load(data);
        instance
    }

    pub fn title(&self) -> String {
        String::from(
            String::from_utf8(Vec::from(&self.title[..]))
                .unwrap()
                .trim_matches(char::from(0))
                .trim(),
        )
impl Serialize for BeesInfo {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.header.save(buffer);
        buffer.write_all(&self.title).unwrap();
        buffer.write_all(&self.checksum).unwrap();
    }
    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        self.header.load(data);
        data.read_exact(&mut self.title).unwrap();
        data.read_exact(&mut self.checksum).unwrap();
    }
}

impl State for BeesInfo {
    fn from_gb(gb: &mut GameBoy) -> Self {
        Self::new(
            &gb.cartridge_i().rom_data()[0x134..=0x143],
            &gb.cartridge_i().rom_data()[0x14e..=0x14f],
        )
    }
    fn to_gb(&self, gb: &mut GameBoy) -> Result<(), String> {
        if self.title() != gb.rom_i().title() {
            return Err(format!(
                "Invalid ROM loaded, expected '{}' (len {}) got '{}' (len {})",
                self.title(),
                self.title().len(),
                gb.rom_i().title(),
                gb.rom_i().title().len(),
            ));
        }
        Ok(())
    }
impl Default for BeesInfo {
    fn default() -> Self {
        Self::new(&[0_u8; 16], &[0_u8; 2])
    }
}

pub struct BeesCore {
    header: BeesBlockHeader,
    model: String,
    pc: u16,
    af: u16,
    bc: u16,
    de: u16,
    hl: u16,
    sp: u16,
    // 0 = running; 1 = halted; 2 = stopped
    io_registers: [u8; 128],
    ram: BeesBuffer,
    vram: BeesBuffer,
    mbc_ram: BeesBuffer,
    oam: BeesBuffer,
    hram: BeesBuffer,
    background_palettes: BeesBuffer,
    object_palettes: BeesBuffer,
impl BeesCore {
João Magalhães's avatar
João Magalhães committed
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        model: String,
        pc: u16,
        af: u16,
        bc: u16,
        de: u16,
        hl: u16,
        sp: u16,
        ime: bool,
        ie: u8,
        execution_mode: u8,
        io_registers: [u8; 128],
    ) -> Self {
        Self {
            header: BeesBlockHeader::new(
                String::from("CORE"),
                ((size_of::<u16>() * 2)
                    + size_of::<u32>()
                    + (size_of::<u16>() * 6)
                    + (size_of::<u8>() * 4)
                    + (size_of::<u8>() * 128)
                    + ((size_of::<u32>() + size_of::<u32>()) * 7)) as u32,
            ),
            major: 1,
            minor: 1,
            model,
            pc,
            af,
            bc,
            de,
            hl,
            sp,
João Magalhães's avatar
João Magalhães committed
            execution_mode,
            _padding: 0,
            ram: BeesBuffer::default(),
            vram: BeesBuffer::default(),
            mbc_ram: BeesBuffer::default(),
            oam: BeesBuffer::default(),
            hram: BeesBuffer::default(),
            background_palettes: BeesBuffer::default(),
            object_palettes: BeesBuffer::default(),
        }
    }

    pub fn from_data(data: &mut Cursor<Vec<u8>>) -> Self {
        let mut instance = Self::default();
        instance.load(data);
        instance
    }

    pub fn verify(&self) -> Result<(), String> {
        if self.header.magic != "CORE" {
            return Err(String::from("Invalid magic"));
        if self.oam.size != 0xa0 {
            return Err(String::from("Invalid OAM size"));
        }
        if self.hram.size != 0x7f {
            return Err(String::from("Invalid HRAM size"));
        }
        Ok(())

    /// Obtains the BEES (GAme Boy) model string using the
    /// provided GameBoy instance.
    fn bees_model(gb: &GameBoy) -> String {
        let mut buffer = [0x00_u8; 4];

        if gb.is_dmg() {
        } else if gb.is_cgb() {
            buffer[0] = b'C';
        } else if gb.is_sgb() {
            buffer[0] = b'S';
        } else if gb.is_cgb() {
            buffer[1] = b'C';
        } else if gb.is_sgb() {
            buffer[1] = b'N';
        buffer[2] = b' ';
        buffer[3] = b' ';

        String::from_utf8(Vec::from(buffer)).unwrap()
    }
impl Serialize for BeesCore {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.header.save(buffer);

        buffer.write_all(&self.major.to_le_bytes()).unwrap();
        buffer.write_all(&self.minor.to_le_bytes()).unwrap();

        buffer.write_all(self.model.as_bytes()).unwrap();

        buffer.write_all(&self.pc.to_le_bytes()).unwrap();
        buffer.write_all(&self.af.to_le_bytes()).unwrap();
        buffer.write_all(&self.bc.to_le_bytes()).unwrap();
        buffer.write_all(&self.de.to_le_bytes()).unwrap();
        buffer.write_all(&self.hl.to_le_bytes()).unwrap();
        buffer.write_all(&self.sp.to_le_bytes()).unwrap();

        buffer.write_all(&(self.ime as u8).to_le_bytes()).unwrap();
        buffer.write_all(&self.ie.to_le_bytes()).unwrap();
        buffer
            .write_all(&self.execution_mode.to_le_bytes())
            .unwrap();
        buffer.write_all(&self._padding.to_le_bytes()).unwrap();

        buffer.write_all(&self.io_registers).unwrap();

        self.ram.save(buffer);
        self.vram.save(buffer);
        self.mbc_ram.save(buffer);
        self.oam.save(buffer);
        self.hram.save(buffer);
        self.background_palettes.save(buffer);
        self.object_palettes.save(buffer);
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        self.header.load(data);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.major = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.minor = u16::from_le_bytes(buffer);

        let mut buffer = [0x00; 4];
        data.read_exact(&mut buffer).unwrap();
        self.model = String::from_utf8(Vec::from(buffer)).unwrap();

        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.pc = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.af = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.bc = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.de = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.hl = u16::from_le_bytes(buffer);
        let mut buffer = [0x00; 2];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.sp = u16::from_le_bytes(buffer);

        let mut buffer = [0x00; 1];
        data.read_exact(&mut buffer).unwrap();
        self.ime = buffer[0] != 0;
        let mut buffer = [0x00; 1];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.ie = u8::from_le_bytes(buffer);
        let mut buffer = [0x00; 1];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self.execution_mode = u8::from_le_bytes(buffer);
        let mut buffer = [0x00; 1];
        data.read_exact(&mut buffer).unwrap();
João Magalhães's avatar
João Magalhães committed
        self._padding = u8::from_le_bytes(buffer);

        data.read_exact(&mut self.io_registers).unwrap();

        self.ram.load(data);
        self.vram.load(data);
        self.mbc_ram.load(data);
        self.oam.load(data);
        self.hram.load(data);
        self.background_palettes.load(data);
        self.object_palettes.load(data);
    }
impl State for BeesCore {
    fn from_gb(gb: &mut GameBoy) -> Self {
        let mut core = Self::new(
            Self::bees_model(gb),
            gb.cpu_i().pc(),
            gb.cpu_i().af(),
            gb.cpu_i().bc(),
            gb.cpu_i().de(),
            gb.cpu_i().hl(),
            gb.cpu_i().sp(),
            gb.cpu_i().ime(),
            gb.mmu_i().ie,
            0,
            // @TODO: these registers cannot be totally retrieved
            // because of that some audio noise exists
            gb.mmu().read_many(0xff00, 128).try_into().unwrap(),
        core.ram.fill_buffer(gb.mmu().ram());
        core.vram.fill_buffer(&gb.mmu().read_many(0x8000, 0x2000));
        core.mbc_ram.fill_buffer(gb.rom_i().ram_data());
        core.oam.fill_buffer(&gb.mmu().read_many(0xfe00, 0x00a0));
        core.hram.fill_buffer(&gb.mmu().read_many(0xff80, 0x007f));
    fn to_gb(&self, gb: &mut GameBoy) -> Result<(), String> {
        gb.cpu().set_pc(self.pc);
        gb.cpu().set_af(self.af);
        gb.cpu().set_bc(self.bc);
        gb.cpu().set_de(self.de);
        gb.cpu().set_hl(self.hl);
        gb.cpu().set_sp(self.sp);

        gb.cpu().set_ime(self.ime);
        gb.mmu().ie = self.ie;

        gb.mmu().write_many(0xff00, &self.io_registers);

        gb.mmu().set_ram(self.ram.buffer.to_vec());
        gb.mmu().write_many(0x8000, &self.vram.buffer);
        gb.rom().set_ram_data(&self.mbc_ram.buffer);
        gb.mmu().write_many(0xfe00, &self.oam.buffer);
        gb.mmu().write_many(0xff80, &self.hram.buffer);
        //@TODO the background palettes are missing - CGB only
        //@TODO the object palettes are missing - CGB only
}

impl Default for BeesCore {
    fn default() -> Self {
        Self::new(
            String::from("GD  "),
            0x0000_u16,
            0x0000_u16,
            0x0000_u16,
            0x0000_u16,
            0x0000_u16,
            0x0000_u16,
            false,
            0x00,
            0,
            [0x00; 128],
pub struct BeesMbrRegister {
    address: u16,
    value: u8,
}

impl BeesMbrRegister {
    pub fn new(address: u16, value: u8) -> Self {
        Self { address, value }
    }
}

pub struct BeesMbc {
    header: BeesBlockHeader,
    registers: Vec<BeesMbrRegister>,
}

impl BeesMbc {
    pub fn new(registers: Vec<BeesMbrRegister>) -> Self {
        Self {
            header: BeesBlockHeader::new(
                String::from("MBC "),
                ((size_of::<u8>() + size_of::<u16>()) * registers.len()) as u32,
            ),
            registers,
        }
    }

    pub fn from_data(data: &mut Cursor<Vec<u8>>) -> Self {
        let mut instance = Self::default();
        instance.load(data);
        instance
    }
}

impl Serialize for BeesMbc {
    fn save(&mut self, buffer: &mut Vec<u8>) {
        self.header.save(buffer);
        for register in self.registers.iter() {
            buffer.write_all(&register.address.to_le_bytes()).unwrap();
            buffer.write_all(&register.value.to_le_bytes()).unwrap();
        }
    }

    fn load(&mut self, data: &mut Cursor<Vec<u8>>) {
        self.header.load(data);
        for _ in 0..(self.header.size / 3) {
            let mut buffer = [0x00; 2];
            data.read_exact(&mut buffer).unwrap();
            let address = u16::from_le_bytes(buffer);
            let mut buffer = [0x00; 1];
            data.read_exact(&mut buffer).unwrap();
            let value = u8::from_le_bytes(buffer);
            self.registers.push(BeesMbrRegister::new(address, value));
        }
    }
}

impl State for BeesMbc {
    fn from_gb(gb: &mut GameBoy) -> Self {
        let mut registers = vec![];
        match gb.cartridge().rom_type().mbc_type() {
            crate::rom::MbcType::NoMbc => (),
            crate::rom::MbcType::Mbc1 => {
                registers.push(BeesMbrRegister::new(0x0000, if gb.rom().ram_enabled() { 0x0a_u8 } else { 0x00_u8 }));
                registers.push(BeesMbrRegister::new(0x2000, gb.rom().rom_bank()));
                registers.push(BeesMbrRegister::new(0x4000, gb.rom().ram_bank()));
                registers.push(BeesMbrRegister::new(0x6000, 0x00_u8));
            }
            crate::rom::MbcType::Mbc2 => todo!(),
            crate::rom::MbcType::Mbc3 => todo!(),
            crate::rom::MbcType::Mbc5 => todo!(),
            crate::rom::MbcType::Mbc6 => unimplemented!(),
            crate::rom::MbcType::Mbc7 => unimplemented!(),
            crate::rom::MbcType::Unknown => unimplemented!(),

        Self::new(registers)
    }

    fn to_gb(&self, gb: &mut GameBoy) -> Result<(), String> {
        for register in self.registers.iter() {
            gb.mmu().write(register.address, register.value);
        }
        Ok(())
    }
}

impl Default for BeesMbc {
    fn default() -> Self {
        Self::new(vec![])
    }
}

pub fn save_state_file(file_path: &str, gb: &mut GameBoy) {
    let mut file = File::create(file_path).unwrap();
    let data = save_state(gb);
    file.write_all(&data).unwrap();
pub fn save_state(gb: &mut GameBoy) -> Vec<u8> {
    let mut data: Vec<u8> = vec![];
    BeesState::from_gb(gb).save(&mut data);
pub fn load_state_file(file_path: &str, gb: &mut GameBoy) -> Result<(), String> {
    let mut file = File::open(file_path).unwrap();
    let mut data = vec![];
    file.read_to_end(&mut data).unwrap();
    load_state(&data, gb)?;
    Ok(())
pub fn load_state(data: &[u8], gb: &mut GameBoy) -> Result<(), String> {
    let mut state = BeesState::default();
    state.load(&mut Cursor::new(data.to_vec()));
    state.to_gb(gb)?;
    print!("{}", state);