Skip to content

Commit

Permalink
Regroup all backup-storage-related fields of struct memory into a c…
Browse files Browse the repository at this point in the history
…ommon sub-struct.
  • Loading branch information
Arignir committed Aug 21, 2023
1 parent d4036c7 commit 9ae346e
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 87 deletions.
26 changes: 15 additions & 11 deletions include/gba/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,17 +219,21 @@ struct memory {
uint8_t rom[CART_SIZE];
size_t rom_size;

// Backup Storage
uint8_t *backup_storage_data;
enum backup_storage_types backup_storage_type;
enum backup_storage_sources backup_storage_source;
atomic_bool backup_storage_dirty;

// Flash memory
struct flash flash;

// EEPROM memory
struct eeprom eeprom;
struct {
struct {
// Flash memory
struct flash flash;

// EEPROM memory
struct eeprom eeprom;
} chip;
uint8_t *data;
size_t size;
enum backup_storage_types type;
enum backup_storage_sources source;

atomic_bool dirty;
} backup_storage;

// Prefetch
struct prefetch_buffer pbuffer;
Expand Down
10 changes: 5 additions & 5 deletions source/common/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -360,18 +360,18 @@ app_game_write_backup(
struct app *app
) {
if ( app->file.backup_file
&& app->emulation.gba->memory.backup_storage_data
&& app->emulation.gba->memory.backup_storage_dirty
&& app->emulation.gba->memory.backup_storage.data
&& app->emulation.gba->memory.backup_storage.dirty
) {
fseek(app->file.backup_file, 0, SEEK_SET);
fwrite(
app->emulation.gba->memory.backup_storage_data,
backup_storage_sizes[app->emulation.gba->memory.backup_storage_type],
app->emulation.gba->memory.backup_storage.data,
backup_storage_sizes[app->emulation.gba->memory.backup_storage.type],
1,
app->file.backup_file
);
}
app->emulation.gba->memory.backup_storage_dirty = false;
app->emulation.gba->memory.backup_storage.dirty = false;
}

void
Expand Down
10 changes: 5 additions & 5 deletions source/gba/gba.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ gba_main_loop(
struct message_data *message_data;

message_data = (struct message_data *)message;
memset(gba->memory.backup_storage_data, 0, backup_storage_sizes[gba->memory.backup_storage_type]);
memset(gba->memory.backup_storage.data, 0, backup_storage_sizes[gba->memory.backup_storage.type]);
memcpy(
gba->memory.backup_storage_data,
gba->memory.backup_storage.data,
message_data->data,
min(message_data->size, backup_storage_sizes[gba->memory.backup_storage_type])
min(message_data->size, backup_storage_sizes[gba->memory.backup_storage.type])
);
if (message_data->cleanup) {
message_data->cleanup(message_data->data);
Expand All @@ -165,8 +165,8 @@ gba_main_loop(
if (message_backup_type->type == BACKUP_AUTO_DETECT) {
mem_backup_storage_detect(gba);
} else {
gba->memory.backup_storage_type = message_backup_type->type;
gba->memory.backup_storage_source = BACKUP_SOURCE_MANUAL;
gba->memory.backup_storage.type = message_backup_type->type;
gba->memory.backup_storage.source = BACKUP_SOURCE_MANUAL;
}
mem_backup_storage_init(gba);
break;
Expand Down
20 changes: 9 additions & 11 deletions source/gba/memory/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ mem_reset(
memset(memory->vram, 0, sizeof(memory->vram));
memset(memory->oam, 0, sizeof(memory->oam));
memset(&memory->pbuffer, 0, sizeof(memory->pbuffer));
memset(&memory->flash, 0, sizeof(memory->flash));
memset(&memory->backup_storage.chip.flash, 0, sizeof(memory->backup_storage.chip.flash));
memory->gamepak_bus_in_use = false;
memory->bios_bus = 0;
memory->eeprom.state = EEPROM_STATE_READY;
memory->eeprom.transfer_address = 0;
memory->eeprom.transfer_data = 0;
memory->eeprom.transfer_len = 0;
memory->backup_storage.chip.eeprom.state = EEPROM_STATE_READY;
memory->backup_storage.chip.eeprom.transfer_address = 0;
memory->backup_storage.chip.eeprom.transfer_data = 0;
memory->backup_storage.chip.eeprom.transfer_len = 0;
}

/*
Expand Down Expand Up @@ -333,9 +333,8 @@ mem_openbus_read(
break; \
case CART_REGION_START ... CART_REGION_END: { \
if (unlikely( \
(_addr & (gba)->memory.eeprom.mask) == (gba)->memory.eeprom.range \
&& ((gba)->memory.backup_storage_type == BACKUP_EEPROM_4K \
|| (gba)->memory.backup_storage_type == BACKUP_EEPROM_64K) \
((gba)->memory.backup_storage.type == BACKUP_EEPROM_4K || (gba)->memory.backup_storage.type == BACKUP_EEPROM_64K) \
&& (_addr & (gba)->memory.backup_storage.chip.eeprom.mask) == (gba)->memory.backup_storage.chip.eeprom.range \
)) { \
_ret = mem_eeprom_read8(gba); \
} else if (unlikely(_addr >= GPIO_REG_START && _addr <= GPIO_REG_END && (gba)->gpio.readable)) { \
Expand Down Expand Up @@ -475,9 +474,8 @@ mem_openbus_read(
break; \
}; \
case CART_REGION_START ... CART_REGION_END: { \
if ( (_addr & (gba)->memory.eeprom.mask) == (gba)->memory.eeprom.range \
&& ((gba)->memory.backup_storage_type == BACKUP_EEPROM_4K \
|| (gba)->memory.backup_storage_type == BACKUP_EEPROM_64K) \
if (((gba)->memory.backup_storage.type == BACKUP_EEPROM_4K || (gba)->memory.backup_storage.type == BACKUP_EEPROM_64K) \
&& (_addr & (gba)->memory.backup_storage.chip.eeprom.mask) == (gba)->memory.backup_storage.chip.eeprom.range \
) { \
mem_eeprom_write8((gba), (val) & 1); \
} else if (_addr >= GPIO_REG_START && _addr <= GPIO_REG_END) { \
Expand Down
10 changes: 5 additions & 5 deletions source/gba/memory/storage/eeprom.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mem_eeprom_read8(
) {
struct eeprom *eeprom;

eeprom = &gba->memory.eeprom;
eeprom = &gba->memory.backup_storage.chip.eeprom;

if (eeprom->cmd == EEPROM_CMD_READ) {
if (eeprom->state == EEPROM_STATE_TRANSFER_JUNK) {
Expand Down Expand Up @@ -57,7 +57,7 @@ mem_eeprom_write8(
) {
struct eeprom *eeprom;

eeprom = &gba->memory.eeprom;
eeprom = &gba->memory.backup_storage.chip.eeprom;

switch (eeprom->state) {
case EEPROM_STATE_READY: {
Expand Down Expand Up @@ -96,7 +96,7 @@ mem_eeprom_write8(
eeprom->transfer_data = 0;
for (i = 0; i < 8; ++i) {
eeprom->transfer_data <<= 8;
eeprom->transfer_data |= gba->memory.backup_storage_data[eeprom->transfer_address + i];
eeprom->transfer_data |= gba->memory.backup_storage.data[eeprom->transfer_address + i];
}

break;
Expand All @@ -122,9 +122,9 @@ mem_eeprom_write8(
eeprom->transfer_len = 0;

for (i = 0; i < 8; ++i) {
gba->memory.backup_storage_data[eeprom->transfer_address + i] = (eeprom->transfer_data >> (56 - 8 * i)) & 0xFF;
gba->memory.backup_storage.data[eeprom->transfer_address + i] = (eeprom->transfer_data >> (56 - 8 * i)) & 0xFF;
}
gba->memory.backup_storage_dirty = true;
gba->memory.backup_storage.dirty = true;

eeprom->state = EEPROM_STATE_END;
}
Expand Down
24 changes: 12 additions & 12 deletions source/gba/memory/storage/flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@ mem_flash_read8(
) {
struct flash const *flash;

flash = &gba->memory.flash;
flash = &gba->memory.backup_storage.chip.flash;
addr &= FLASH_MASK;

if (flash->identity_mode) {
/* Use Panasonic (0x1b32) for Flash 64k and Sanyo (0x1362) for Flash 128k. */
if (addr == 0x0) {
return (gba->memory.backup_storage_type == BACKUP_FLASH64 ? 0x32 : 0x62);
return (gba->memory.backup_storage.type == BACKUP_FLASH64 ? 0x32 : 0x62);
} else if (addr == 0x1) {
return (gba->memory.backup_storage_type == BACKUP_FLASH64 ? 0x1b : 0x13);
return (gba->memory.backup_storage.type == BACKUP_FLASH64 ? 0x1b : 0x13);
}
}
return (gba->memory.backup_storage_data[addr + flash->bank * FLASH64_SIZE]);
return (gba->memory.backup_storage.data[addr + flash->bank * FLASH64_SIZE]);
}

void
Expand All @@ -40,7 +40,7 @@ mem_flash_write8(
) {
struct flash *flash;

flash = &gba->memory.flash;
flash = &gba->memory.backup_storage.chip.flash;
addr &= FLASH_MASK;

if (addr == 0x5555 && val == 0xAA && flash->state == FLASH_STATE_READY) {
Expand All @@ -55,14 +55,14 @@ mem_flash_write8(
case FLASH_CMD_PREP_ERASE: flash->state = FLASH_STATE_ERASE; break;
case FLASH_CMD_ERASE_CHIP: {
if (flash->state == FLASH_STATE_ERASE) {
memset(gba->memory.backup_storage_data, 0xFF, backup_storage_sizes[gba->memory.backup_storage_type]);
gba->memory.backup_storage_dirty = true;
memset(gba->memory.backup_storage.data, 0xFF, backup_storage_sizes[gba->memory.backup_storage.type]);
gba->memory.backup_storage.dirty = true;
}
break;
};
case FLASH_CMD_WRITE: flash->state = FLASH_STATE_WRITE; break;
case FLASH_CMD_SET_BANK: {
if (gba->memory.backup_storage_type == BACKUP_FLASH128) {
if (gba->memory.backup_storage.type == BACKUP_FLASH128) {
flash->state = FLASH_STATE_BANK;
}
break;
Expand All @@ -72,12 +72,12 @@ mem_flash_write8(
// Erase the desired sector

addr &= 0xF000;
memset(gba->memory.backup_storage_data + addr + flash->bank * FLASH64_SIZE, 0xFF, 0x1000);
gba->memory.backup_storage_dirty = true;
memset(gba->memory.backup_storage.data + addr + flash->bank * FLASH64_SIZE, 0xFF, 0x1000);
gba->memory.backup_storage.dirty = true;
flash->state = FLASH_STATE_READY;
} else if (flash->state == FLASH_STATE_WRITE) {
gba->memory.backup_storage_data[addr + flash->bank * FLASH64_SIZE] = val;
gba->memory.backup_storage_dirty = true;
gba->memory.backup_storage.data[addr + flash->bank * FLASH64_SIZE] = val;
gba->memory.backup_storage.dirty = true;
flash->state = FLASH_STATE_READY;
} else if (flash->state == FLASH_STATE_BANK && addr == 0x0) {
flash->bank = val;
Expand Down
69 changes: 35 additions & 34 deletions source/gba/memory/storage/storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,60 +58,61 @@ mem_backup_storage_detect(
) {
/* Prioritize the game database. */
if (gba->game_entry) {
gba->memory.backup_storage_type = gba->game_entry->storage;
gba->memory.backup_storage_source = BACKUP_SOURCE_DATABASE;
gba->memory.backup_storage.type = gba->game_entry->storage;
gba->memory.backup_storage.source = BACKUP_SOURCE_DATABASE;
return ;
}

gba->memory.backup_storage_source = BACKUP_SOURCE_AUTO_DETECT;
gba->memory.backup_storage.source = BACKUP_SOURCE_AUTO_DETECT;

/* Auto-detection algorithm are very simple: they look for a bunch of strings in the game's ROM. */
if (array_search(gba->memory.rom, sizeof(gba->memory.rom), "EEPROM_V", 7)) {
logln(HS_INFO, "Detected EEPROM 64K memory.");
logln(HS_WARNING, "If you are having issues with corrupted saves, try EEPROM 8K instead.");
gba->memory.backup_storage_type = BACKUP_EEPROM_64K;
gba->memory.backup_storage.type = BACKUP_EEPROM_64K;
} else if (
array_search(gba->memory.rom, sizeof(gba->memory.rom), "SRAM_V", 5)
|| array_search(gba->memory.rom, sizeof(gba->memory.rom), "SRAM_F_V", 5)
) {
logln(HS_INFO, "Detected SRAM memory");
gba->memory.backup_storage_type = BACKUP_SRAM;
gba->memory.backup_storage.type = BACKUP_SRAM;
} else if (array_search(gba->memory.rom, sizeof(gba->memory.rom), "FLASH1M_V", 8)) {
logln(HS_INFO, "Detected Flash 128 kilobytes / 1 megabit");
gba->memory.backup_storage_type = BACKUP_FLASH128;
gba->memory.backup_storage.type = BACKUP_FLASH128;
} else if (
array_search(gba->memory.rom, sizeof(gba->memory.rom), "FLASH_V", 6)
|| array_search(gba->memory.rom, sizeof(gba->memory.rom), "FLASH512_V", 9)
) {
logln(HS_INFO, "Detected Flash 64 kilobytes / 512 kilobits");
gba->memory.backup_storage_type = BACKUP_FLASH64;
gba->memory.backup_storage.type = BACKUP_FLASH64;
} else {
gba->memory.backup_storage_type = BACKUP_NONE;
gba->memory.backup_storage.type = BACKUP_NONE;
}
}

void
mem_backup_storage_init(
struct gba *gba
) {
free(gba->memory.backup_storage_data);
free(gba->memory.backup_storage.data);

if (gba->memory.backup_storage_type > BACKUP_NONE) {
if (gba->memory.backup_storage.type > BACKUP_NONE) {
logln(
HS_INFO,
"Backup memory is %s%s%s (%s).",
g_light_magenta,
backup_storage_names[gba->memory.backup_storage_type],
backup_storage_names[gba->memory.backup_storage.type],
g_reset,
backup_storage_sources_str[gba->memory.backup_storage_source]
backup_storage_sources_str[gba->memory.backup_storage.source]
);
} else {
logln(HS_INFO, "No backup storage (%s).", backup_storage_sources_str[gba->memory.backup_storage_source]);
logln(HS_INFO, "No backup storage (%s).", backup_storage_sources_str[gba->memory.backup_storage.source]);
}

if ( gba->memory.backup_storage_type == BACKUP_EEPROM_4K
|| gba->memory.backup_storage_type == BACKUP_EEPROM_64K
if ( gba->memory.backup_storage.type == BACKUP_EEPROM_4K
|| gba->memory.backup_storage.type == BACKUP_EEPROM_64K
) {
struct eeprom *eeprom;

/*
** Those are masks applied to the address of any ROM data transfers
Expand All @@ -120,29 +121,29 @@ mem_backup_storage_init(
**
** A data transfer is going to the EEPROM iff (addr & eeprom.mask) == eeprom.range.
*/

eeprom = &gba->memory.backup_storage.chip.eeprom;
if (gba->memory.rom_size > 16 * 1024 * 1024) {
gba->memory.eeprom.mask = 0x01FFFF00;
gba->memory.eeprom.range = 0x01FFFF00;
eeprom->mask = 0x01FFFF00;
eeprom->range = 0x01FFFF00;
} else {
gba->memory.eeprom.mask = 0xFF000000;
gba->memory.eeprom.range = 0x0d000000;
eeprom->mask = 0xFF000000;
eeprom->range = 0x0d000000;
}

if (gba->memory.backup_storage_type == BACKUP_EEPROM_4K) {
gba->memory.eeprom.address_mask = EEPROM_4K_ADDR_MASK;
gba->memory.eeprom.address_len = EEPROM_4K_ADDR_LEN;
if (gba->memory.backup_storage.type == BACKUP_EEPROM_4K) {
eeprom->address_mask = EEPROM_4K_ADDR_MASK;
eeprom->address_len = EEPROM_4K_ADDR_LEN;
} else { // EEPROM_64K
gba->memory.eeprom.address_mask = EEPROM_64K_ADDR_MASK;
gba->memory.eeprom.address_len = EEPROM_64K_ADDR_LEN;
eeprom->address_mask = EEPROM_64K_ADDR_MASK;
eeprom->address_len = EEPROM_64K_ADDR_LEN;
}
}

if (gba->memory.backup_storage_type > BACKUP_NONE) {
gba->memory.backup_storage_data = calloc(1, backup_storage_sizes[gba->memory.backup_storage_type]);
hs_assert(gba->memory.backup_storage_data);
if (gba->memory.backup_storage.type > BACKUP_NONE) {
gba->memory.backup_storage.data = calloc(1, backup_storage_sizes[gba->memory.backup_storage.type]);
hs_assert(gba->memory.backup_storage.data);
} else {
gba->memory.backup_storage_data = NULL;
gba->memory.backup_storage.data = NULL;
}
}

Expand All @@ -151,13 +152,13 @@ mem_backup_storage_read8(
struct gba const *gba,
uint32_t addr
) {
switch (gba->memory.backup_storage_type) {
switch (gba->memory.backup_storage.type) {
case BACKUP_FLASH64:
case BACKUP_FLASH128:
return (mem_flash_read8(gba, addr));
break;
case BACKUP_SRAM:
return (gba->memory.backup_storage_data[addr & SRAM_MASK]);
return (gba->memory.backup_storage.data[addr & SRAM_MASK]);
break;
default:
return (0);
Expand All @@ -170,14 +171,14 @@ mem_backup_storage_write8(
uint32_t addr,
uint8_t val
) {
switch (gba->memory.backup_storage_type) {
switch (gba->memory.backup_storage.type) {
case BACKUP_FLASH64:
case BACKUP_FLASH128:
mem_flash_write8(gba, addr, val);
break;
case BACKUP_SRAM:
gba->memory.backup_storage_data[addr & SRAM_MASK] = val;
gba->memory.backup_storage_dirty = true;
gba->memory.backup_storage.data[addr & SRAM_MASK] = val;
gba->memory.backup_storage.dirty = true;
break;
default:
break;
Expand Down
Loading

0 comments on commit 9ae346e

Please sign in to comment.