mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
GB RTC saving (#857)
* GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * GB RTC saving * more
This commit is contained in:
+104
-10
@@ -1,5 +1,6 @@
|
||||
use crate::device;
|
||||
|
||||
use std::io::Write;
|
||||
const MBC3_RTC_SECONDS: usize = 0;
|
||||
const MBC3_RTC_MINUTES: usize = 1;
|
||||
const MBC3_RTC_HOURS: usize = 2;
|
||||
@@ -21,7 +22,7 @@ pub struct GbCart {
|
||||
pub latch: bool,
|
||||
pub rtc_regs: [u8; MBC3_RTC_REGS_COUNT],
|
||||
pub rtc_regs_latch: [u8; MBC3_RTC_REGS_COUNT],
|
||||
pub current_time: i64,
|
||||
pub rtc_timestamp: i64,
|
||||
pub last_time: i64,
|
||||
}
|
||||
|
||||
@@ -35,9 +36,98 @@ pub enum CartType {
|
||||
MBC5RamBatt,
|
||||
}
|
||||
|
||||
fn update_rtc_regs(cart: &mut device::controller::gbcart::GbCart) {
|
||||
let mut diff = cart.current_time - cart.last_time;
|
||||
cart.last_time = cart.current_time;
|
||||
pub fn init(gb_cart: &mut device::controller::gbcart::GbCart, rom: &[u8], ram: &[u8]) {
|
||||
gb_cart.rom = rom.to_vec();
|
||||
let offset;
|
||||
match ram.len() % 8192 {
|
||||
44 => {
|
||||
offset = ram.len() - 44;
|
||||
gb_cart.ram = ram[..ram.len() - 44].to_vec();
|
||||
gb_cart.rtc_timestamp =
|
||||
i32::from_le_bytes(ram[offset + 40..offset + 44].try_into().unwrap()) as i64;
|
||||
}
|
||||
48 => {
|
||||
offset = ram.len() - 48;
|
||||
gb_cart.ram = ram[..ram.len() - 48].to_vec();
|
||||
gb_cart.rtc_timestamp =
|
||||
i64::from_le_bytes(ram[offset + 40..offset + 48].try_into().unwrap());
|
||||
}
|
||||
_ => {
|
||||
gb_cart.ram = ram.to_vec();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
gb_cart.rtc_regs[MBC3_RTC_SECONDS] =
|
||||
u32::from_le_bytes(ram[offset..offset + 4].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs[MBC3_RTC_MINUTES] =
|
||||
u32::from_le_bytes(ram[offset + 4..offset + 8].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs[MBC3_RTC_HOURS] =
|
||||
u32::from_le_bytes(ram[offset + 8..offset + 12].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs[MBC3_RTC_DAYS_L] =
|
||||
u32::from_le_bytes(ram[offset + 12..offset + 16].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs[MBC3_RTC_DAYS_H] =
|
||||
u32::from_le_bytes(ram[offset + 16..offset + 20].try_into().unwrap()) as u8;
|
||||
|
||||
gb_cart.rtc_regs_latch[MBC3_RTC_SECONDS] =
|
||||
u32::from_le_bytes(ram[offset + 20..offset + 24].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs_latch[MBC3_RTC_MINUTES] =
|
||||
u32::from_le_bytes(ram[offset + 24..offset + 28].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs_latch[MBC3_RTC_HOURS] =
|
||||
u32::from_le_bytes(ram[offset + 28..offset + 32].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs_latch[MBC3_RTC_DAYS_L] =
|
||||
u32::from_le_bytes(ram[offset + 32..offset + 36].try_into().unwrap()) as u8;
|
||||
gb_cart.rtc_regs_latch[MBC3_RTC_DAYS_H] =
|
||||
u32::from_le_bytes(ram[offset + 36..offset + 40].try_into().unwrap()) as u8;
|
||||
}
|
||||
|
||||
pub fn save(
|
||||
gb_cart: &mut device::controller::gbcart::GbCart,
|
||||
elapsed_time: i64,
|
||||
ram_path: &std::string::String,
|
||||
) {
|
||||
update_rtc_regs(gb_cart, elapsed_time);
|
||||
|
||||
if let Ok(file) = std::fs::File::create(ram_path) {
|
||||
let mut f = std::io::BufWriter::new(file);
|
||||
f.write_all(&gb_cart.ram).unwrap();
|
||||
|
||||
if gb_cart.cart_type == CartType::MBC3RamBattRtc {
|
||||
f.write_all(&(gb_cart.rtc_regs[MBC3_RTC_SECONDS] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs[MBC3_RTC_MINUTES] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs[MBC3_RTC_HOURS] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs[MBC3_RTC_DAYS_L] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs[MBC3_RTC_DAYS_H] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
|
||||
f.write_all(&(gb_cart.rtc_regs_latch[MBC3_RTC_SECONDS] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs_latch[MBC3_RTC_MINUTES] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs_latch[MBC3_RTC_HOURS] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs_latch[MBC3_RTC_DAYS_L] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
f.write_all(&(gb_cart.rtc_regs_latch[MBC3_RTC_DAYS_H] as u32).to_le_bytes())
|
||||
.unwrap();
|
||||
|
||||
let timestamp = gb_cart.rtc_timestamp.saturating_add(elapsed_time);
|
||||
f.write_all(×tamp.to_le_bytes()).unwrap();
|
||||
|
||||
f.flush().unwrap();
|
||||
}
|
||||
} else {
|
||||
eprintln!("Error saving TransferPak RAM to {ram_path}");
|
||||
}
|
||||
}
|
||||
|
||||
fn update_rtc_regs(cart: &mut device::controller::gbcart::GbCart, elapsed_time: i64) {
|
||||
let mut diff = elapsed_time - cart.last_time;
|
||||
cart.last_time = elapsed_time;
|
||||
|
||||
if diff > 0 {
|
||||
cart.rtc_regs[MBC3_RTC_SECONDS] += (diff % 60) as u8;
|
||||
@@ -154,6 +244,7 @@ fn write_mbc3(
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
elapsed_time: i64,
|
||||
) {
|
||||
let value = pif_ram[data + size - 1];
|
||||
if address < 0x2000 {
|
||||
@@ -169,7 +260,7 @@ fn write_mbc3(
|
||||
} else if address < 0x8000 {
|
||||
if cart.cart_type == CartType::MBC3RamBattRtc {
|
||||
if !cart.latch && (value & 0x1) != 0 {
|
||||
update_rtc_regs(cart);
|
||||
update_rtc_regs(cart, elapsed_time);
|
||||
cart.rtc_regs_latch = cart.rtc_regs;
|
||||
}
|
||||
cart.latch = (value & 0x1) != 0;
|
||||
@@ -196,6 +287,7 @@ fn read_mbc3(
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
elapsed_time: i64,
|
||||
) {
|
||||
if address < 0x4000 {
|
||||
let banked_address = address & 0x3FFF;
|
||||
@@ -225,7 +317,7 @@ fn read_mbc3(
|
||||
pif_ram[data + i] = cart.rtc_regs_latch[cart.ram_bank as usize - 0x8];
|
||||
}
|
||||
} else {
|
||||
update_rtc_regs(cart);
|
||||
update_rtc_regs(cart, elapsed_time);
|
||||
for i in 0..size {
|
||||
pif_ram[data + i] = cart.rtc_regs[cart.ram_bank as usize - 0x8];
|
||||
}
|
||||
@@ -306,6 +398,7 @@ pub fn read(
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
elapsed_time: i64,
|
||||
) {
|
||||
if !cart.enabled {
|
||||
for i in 0..size {
|
||||
@@ -315,8 +408,8 @@ pub fn read(
|
||||
}
|
||||
match cart.cart_type {
|
||||
CartType::MBC1RamBatt => read_mbc1(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBatt => read_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBattRtc => read_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBatt => read_mbc3(pif_ram, cart, address, data, size, elapsed_time),
|
||||
CartType::MBC3RamBattRtc => read_mbc3(pif_ram, cart, address, data, size, elapsed_time),
|
||||
CartType::MBC5RamBatt => read_mbc5(pif_ram, cart, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
@@ -328,14 +421,15 @@ pub fn write(
|
||||
address: u16,
|
||||
data: usize,
|
||||
size: usize,
|
||||
elapsed_time: i64,
|
||||
) {
|
||||
if !cart.enabled {
|
||||
return;
|
||||
}
|
||||
match cart.cart_type {
|
||||
CartType::MBC1RamBatt => write_mbc1(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBatt => write_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBattRtc => write_mbc3(pif_ram, cart, address, data, size),
|
||||
CartType::MBC3RamBatt => write_mbc3(pif_ram, cart, address, data, size, elapsed_time),
|
||||
CartType::MBC3RamBattRtc => write_mbc3(pif_ram, cart, address, data, size, elapsed_time),
|
||||
CartType::MBC5RamBatt => write_mbc5(pif_ram, cart, address, data, size),
|
||||
_ => panic!("Unsupported cart type"),
|
||||
}
|
||||
|
||||
@@ -52,13 +52,13 @@ pub fn read(device: &mut device::Device, channel: usize, address: u16, data: usi
|
||||
}
|
||||
}
|
||||
0xC..=0xF => {
|
||||
pak.cart.current_time = device.vi.elapsed_time as i64;
|
||||
device::controller::gbcart::read(
|
||||
&mut device.pif.ram,
|
||||
&mut pak.cart,
|
||||
0x4000 * pak.bank + (address & 0x7fff) - 0x4000,
|
||||
data,
|
||||
size,
|
||||
device.vi.elapsed_time as i64,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
@@ -119,13 +119,13 @@ pub fn write(device: &mut device::Device, channel: usize, address: u16, data: us
|
||||
}
|
||||
}
|
||||
0xC..=0xF => {
|
||||
pak.cart.current_time = device.vi.elapsed_time as i64;
|
||||
device::controller::gbcart::write(
|
||||
&device.pif.ram,
|
||||
&mut pak.cart,
|
||||
0x4000 * pak.bank + (address & 0x7fff) - 0x4000,
|
||||
data,
|
||||
size,
|
||||
device.vi.elapsed_time as i64,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
|
||||
+6
-8
@@ -185,8 +185,7 @@ async fn main() -> std::io::Result<()> {
|
||||
&& let Ok(rom) = std::fs::read(&device.ui.config.input.gb_rom_path[i])
|
||||
&& let Ok(ram) = std::fs::read(&device.ui.config.input.gb_ram_path[i])
|
||||
{
|
||||
device.transferpaks[i].cart.rom = rom;
|
||||
device.transferpaks[i].cart.ram = ram;
|
||||
device::controller::gbcart::init(&mut device.transferpaks[i].cart, &rom, &ram);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,13 +237,12 @@ async fn main() -> std::io::Result<()> {
|
||||
if device.ui.config.input.transfer_pak[i]
|
||||
&& !device.ui.config.input.gb_ram_path[i].is_empty()
|
||||
&& !device.transferpaks[i].cart.ram.is_empty()
|
||||
&& let Err(e) = tokio::fs::write(
|
||||
&device.ui.config.input.gb_ram_path[i],
|
||||
&device.transferpaks[i].cart.ram,
|
||||
)
|
||||
.await
|
||||
{
|
||||
eprintln!("Error writing GB RAM: {}", e);
|
||||
device::controller::gbcart::save(
|
||||
&mut device.transferpaks[i].cart,
|
||||
device.vi.elapsed_time as i64,
|
||||
&device.ui.config.input.gb_ram_path[i],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user