Poke_Transporter_GB/source/save.cpp
Remnants of Forgotten Disney eb87ab3c03 Inital implementation of Save.C
2023-12-03 14:22:04 -06:00

229 lines
7.0 KiB
C++

//Created by Lorenzooone https://github.com/Lorenzooone/Pokemon-Gen3-to-Gen-X
#include "base_include.h"
#include "save.h"
#include <stddef.h>
#include "useful_qualifiers.h"
#include "timing_basic.h"
#include "delays.h"
#define IS_FLASH 1
#define SAVE_POS SRAM
#define BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0xAA; *((vu8*)(SAVE_POS+0x2AAA)) = 0x55;
#define FLASH_WRITE_CMD BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0xA0;
#define FLASH_BANK_CMD BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0xB0;
#define FLASH_ERASE_SECTOR_BASE_CMD BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0x80; BASE_FLASH_CMD
#define FLASH_TERM_CMD *((vu8*)(SAVE_POS+0x5555)) = 0xF0;
#define FLASH_ENTER_MAN_CMD BASE_FLASH_CMD *((vu8*)(SAVE_POS+0x5555)) = 0x90;
#define FLASH_EXIT_MAN_CMD BASE_FLASH_CMD FLASH_TERM_CMD FLASH_TERM_CMD
#define ID_TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(28)
#define TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(10)
#define ERASE_TIMEOUT_CYCLES CLOCK_CYCLES_PER_MS(2000)
#define ERASED_BYTE 0xFF
#define BANK_SIZE 0x10000
#define NUM_BANKS 2
#define MACRONIX_MAN_ID 0xC2
#define SANYO_MAN_ID 0x62
#define DEFAULT_MAN_ID 0
#define ERASE_SECTOR_FINAL_CMD 0x30
#if IS_FLASH
#define BANK_LIMIT BANK_SIZE
#else
#define BANK_LIMIT (NUM_BANKS * BANK_SIZE)
#endif
static uintptr_t bank_check(uintptr_t);
static size_t sanitize_save_size(uintptr_t, size_t);
static u8 read_direct_single_byte_save(uintptr_t);
static void write_direct_single_byte_save(uintptr_t, u8);
u8 current_bank;
u8 is_macronix;
IWRAM_CODE void init_bank() {
REG_WAITCNT &= NON_SRAM_MASK;
REG_WAITCNT |= SRAM_READING_VALID_WAITCYCLES;
current_bank = NUM_BANKS;
is_macronix = 0;
#if IS_FLASH
FLASH_ENTER_MAN_CMD
delay_cycles(ID_TIMEOUT_CYCLES);
u8 man_id = *((vu8*)SAVE_POS);
if((man_id == MACRONIX_MAN_ID) || (man_id == SANYO_MAN_ID) || (man_id == DEFAULT_MAN_ID))
is_macronix = 1;
FLASH_EXIT_MAN_CMD
delay_cycles(ID_TIMEOUT_CYCLES);
#endif
}
IWRAM_CODE uintptr_t bank_check(uintptr_t address) {
address %= (NUM_BANKS * BANK_SIZE);
#if IS_FLASH
u8 bank = address / BANK_SIZE;
address %= BANK_SIZE;
if(bank != current_bank) {
FLASH_BANK_CMD
*((vu8*)SAVE_POS) = bank;
current_bank = bank;
}
#endif
return address;
}
IWRAM_CODE void erase_sector(uintptr_t address) {
address = bank_check(address);
address >>= SECTOR_SIZE_BITS;
address <<= SECTOR_SIZE_BITS;
u8 failed = 1;
vu8* save_data = (vu8*)SAVE_POS;
for(size_t i = 0; failed && (i < 3); i++) {
#if IS_FLASH
FLASH_ERASE_SECTOR_BASE_CMD
save_data[address] = ERASE_SECTOR_FINAL_CMD;
#else
for(size_t j = 0; j < SECTOR_SIZE; j++)
save_data[address+(SECTOR_SIZE-1)-j] = ERASED_BYTE;
#endif
delay_cycles_until(ERASE_TIMEOUT_CYCLES, &save_data[address], 0xFF, SRAM_ACCESS_CYCLES);
failed = 0;
for(size_t j = 0; j < SECTOR_SIZE; j++)
if(read_direct_single_byte_save(address+j) != ERASED_BYTE) {
failed = 1;
break;
}
if(is_macronix && failed)
FLASH_TERM_CMD
}
}
IWRAM_CODE u8 read_direct_single_byte_save(uintptr_t address) {
return *(vu8*)(SAVE_POS+address);
}
IWRAM_CODE void write_direct_single_byte_save(uintptr_t address, u8 data) {
vu8* save_data = (vu8*)SAVE_POS;
for(int i = 0; (i < 3) && save_data[address] != data; i++) {
#if IS_FLASH
FLASH_WRITE_CMD
#endif
save_data[address] = data;
delay_cycles_until(TIMEOUT_CYCLES, &save_data[address], data, SRAM_ACCESS_CYCLES);
if(is_macronix && (save_data[address] != data))
FLASH_TERM_CMD
}
}
IWRAM_CODE u8 read_byte_save(uintptr_t address) {
address = bank_check(address);
return read_direct_single_byte_save(address);
}
IWRAM_CODE u16 read_short_save(uintptr_t address) {
u16 data_out = 0;
copy_save_to_ram(address, (u8*)&data_out, sizeof(u16));
return data_out;
}
IWRAM_CODE u32 read_int_save(uintptr_t address) {
u32 data_out = 0;
copy_save_to_ram(address, (u8*)&data_out, sizeof(u32));
return data_out;
}
IWRAM_CODE void write_byte_save(uintptr_t address, u8 data) {
address = bank_check(address);
write_direct_single_byte_save(address, data);
}
IWRAM_CODE void write_short_save(uintptr_t address, u16 data) {
u16 data_in = data;
copy_ram_to_save((u8*)&data_in, address, sizeof(u16));
}
IWRAM_CODE void write_int_save(uintptr_t address, u32 data) {
u32 data_in = data;
copy_ram_to_save((u8*)&data_in, address, sizeof(u32));
}
IWRAM_CODE size_t sanitize_save_size(uintptr_t address, size_t size) {
address %= NUM_BANKS * BANK_SIZE;
if((address + size) > (NUM_BANKS * BANK_SIZE))
size = (NUM_BANKS * BANK_SIZE) - address;
return size;
}
IWRAM_CODE void copy_save_to_ram(uintptr_t address, u8* destination, size_t size) {
// Sanitize size
size = sanitize_save_size(address, size);
address = bank_check(address);
size_t num_banks = (address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - address;
for(size_t i = 0; i < inner_size; i++)
destination[i] = read_direct_single_byte_save(address + i);
if(n != (num_banks - 1)) {
address = bank_check(address + inner_size);
destination += inner_size;
size -= inner_size;
}
}
}
IWRAM_CODE void copy_ram_to_save(u8* base_address, uintptr_t save_address, size_t size) {
// Sanitize size
size = sanitize_save_size(save_address, size);
save_address = bank_check(save_address);
size_t num_banks = (save_address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - save_address;
for(size_t i = 0; i < inner_size; i++)
write_direct_single_byte_save(save_address + i, base_address[i]);
if(n != (num_banks - 1)) {
save_address = bank_check(save_address + inner_size);
base_address += inner_size;
size -= inner_size;
}
}
}
IWRAM_CODE u8 is_save_correct(u8* base_address, uintptr_t save_address, size_t size) {
// Sanitize size
size = sanitize_save_size(save_address, size);
save_address = bank_check(save_address);
size_t num_banks = (save_address + size + BANK_SIZE - 1) / BANK_SIZE;
for(size_t n = 0; n < num_banks; n++) {
size_t inner_size = size;
if(n != (num_banks - 1))
inner_size = BANK_SIZE - save_address;
for(size_t i = 0; i < inner_size; i++)
if(read_direct_single_byte_save(save_address + i) != base_address[i])
return 0;
if(n != (num_banks - 1)) {
save_address = bank_check(save_address + inner_size);
base_address += inner_size;
size -= inner_size;
}
}
return 1;
}