mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-28 13:34:14 +01:00
64drive support (#27)
<!--- Provide a general summary of your changes in the Title above --> ## Description This PR implements 64drive support ## Motivation and Context Goal of this PR is to support more devices <!--- What does this sample do? What problem does it solve? --> <!--- If it fixes/closes/resolves an open issue, please link to the issue here --> ## How Has This Been Tested? Not tested at all <!-- (if applicable) --> <!--- Please describe in detail how you tested your sample/changes. --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> ## Screenshots <!-- (if appropriate): --> ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [x] My code follows the code style of this project. - [x] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. <!--- It would be nice if you could sign off your contribution by replacing the name with your GitHub user name and GitHub email contact. --> Signed-off-by: GITHUB_USER <GITHUB_USER_EMAIL>
This commit is contained in:
parent
b15be6467b
commit
fc2f3aa42c
2
Makefile
2
Makefile
@ -16,6 +16,8 @@ SRCS = \
|
|||||||
boot/boot.c \
|
boot/boot.c \
|
||||||
boot/crc32.c \
|
boot/crc32.c \
|
||||||
boot/reboot.S \
|
boot/reboot.S \
|
||||||
|
flashcart/64drive/64drive_ll.c \
|
||||||
|
flashcart/64drive/64drive.c \
|
||||||
flashcart/flashcart_utils.c \
|
flashcart/flashcart_utils.c \
|
||||||
flashcart/flashcart.c \
|
flashcart/flashcart.c \
|
||||||
flashcart/sc64/sc64_ll.c \
|
flashcart/sc64/sc64_ll.c \
|
||||||
|
@ -23,10 +23,13 @@ An open source menu for N64 flashcarts.
|
|||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
|
### 64drive
|
||||||
|
Ensure the cart has the latest [firmware](https://64drive.retroactive.be/support.php) installed.
|
||||||
|
Download the latest `menu.bin` file from the releases page, then put it in the root directory of your SD card.
|
||||||
|
|
||||||
### SC64
|
### SC64
|
||||||
Ensure the cart is running the latest [firmware](https://github.com/Polprzewodnikowy/SummerCart64/releases/latest).
|
Ensure the cart has the latest [firmware](https://github.com/Polprzewodnikowy/SummerCart64/releases/latest) installed.
|
||||||
Download the `sc64menu.n64` ROM from the latest action run assets.
|
Download the latest `sc64menu.n64` file from the releases page, then put it in the root directory of your SD card.
|
||||||
Add it to the root folder on your SD card.
|
|
||||||
|
|
||||||
### ED64 & ED64P
|
### ED64 & ED64P
|
||||||
Currently not supported, but there is an aim to do so.
|
Currently not supported, but there is an aim to do so.
|
||||||
|
271
src/flashcart/64drive/64drive.c
Normal file
271
src/flashcart/64drive/64drive.c
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <fatfs/ff.h>
|
||||||
|
#include <libdragon.h>
|
||||||
|
|
||||||
|
#include "utils/fs.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
|
||||||
|
#include "../flashcart_utils.h"
|
||||||
|
#include "64drive_ll.h"
|
||||||
|
#include "64drive.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define ROM_ADDRESS (0x10000000)
|
||||||
|
#define SAVE_ADDRESS_DEV_A (0x13FE0000)
|
||||||
|
#define SAVE_ADDRESS_DEV_A_PKST2 (0x11606560)
|
||||||
|
#define SAVE_ADDRESS_DEV_B (0x1FFC0000)
|
||||||
|
|
||||||
|
#define SUPPORTED_FPGA_REVISION (205)
|
||||||
|
|
||||||
|
|
||||||
|
static d64_device_variant_t device_variant = DEVICE_VARIANT_UNKNOWN;
|
||||||
|
static d64_save_type_t current_save_type = SAVE_TYPE_NONE;
|
||||||
|
|
||||||
|
|
||||||
|
static flashcart_error_t d64_init (void) {
|
||||||
|
uint16_t fpga_revision;
|
||||||
|
uint32_t bootloader_version;
|
||||||
|
|
||||||
|
if (d64_ll_enable_extended_mode(false)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_get_version(&device_variant, &fpga_revision, &bootloader_version)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpga_revision < SUPPORTED_FPGA_REVISION) {
|
||||||
|
return FLASHCART_ERROR_OUTDATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_enable_save_writeback(false)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_set_save_type(SAVE_TYPE_NONE)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_save_type = SAVE_TYPE_NONE;
|
||||||
|
|
||||||
|
if (d64_ll_enable_cartrom_writes(true)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_set_persistent_variable_storage(false, 0, 0)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_deinit (void) {
|
||||||
|
if (d64_ll_enable_cartrom_writes(false)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_load_rom (char *rom_path, flashcart_progress_callback_t *progress) {
|
||||||
|
FIL fil;
|
||||||
|
UINT br;
|
||||||
|
|
||||||
|
if (f_open(&fil, strip_sd_prefix(rom_path), FA_READ) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
fix_file_size(&fil);
|
||||||
|
|
||||||
|
size_t rom_size = f_size(&fil);
|
||||||
|
|
||||||
|
if (rom_size > MiB(64)) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t sdram_size = MiB(64);
|
||||||
|
|
||||||
|
size_t chunk_size = MiB(1);
|
||||||
|
for (int offset = 0; offset < sdram_size; offset += chunk_size) {
|
||||||
|
size_t block_size = MIN(sdram_size - offset, chunk_size);
|
||||||
|
if (f_read(&fil, (void *) (ROM_ADDRESS + offset), block_size, &br) != FR_OK) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
if (progress) {
|
||||||
|
progress(f_tell(&fil) / (float) (f_size(&fil)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f_tell(&fil) != rom_size) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_close(&fil) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_load_file (char *file_path, uint32_t rom_offset, uint32_t file_offset) {
|
||||||
|
FIL fil;
|
||||||
|
UINT br;
|
||||||
|
|
||||||
|
if (f_open(&fil, strip_sd_prefix(file_path), FA_READ) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
fix_file_size(&fil);
|
||||||
|
|
||||||
|
size_t file_size = f_size(&fil) - file_offset;
|
||||||
|
|
||||||
|
if (file_size > (MiB(64) - rom_offset)) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_lseek(&fil, file_offset) != FR_OK) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_read(&fil, (void *) (ROM_ADDRESS + rom_offset), file_size, &br) != FR_OK) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
if (br != file_size) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_close(&fil) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_load_save (char *save_path) {
|
||||||
|
uint8_t eeprom_contents[2048] __attribute__((aligned(8)));
|
||||||
|
FIL fil;
|
||||||
|
UINT br;
|
||||||
|
|
||||||
|
if (f_open(&fil, strip_sd_prefix(save_path), FA_READ) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t save_size = f_size(&fil);
|
||||||
|
|
||||||
|
bool is_eeprom_save = (current_save_type == SAVE_TYPE_EEPROM_4K || current_save_type == SAVE_TYPE_EEPROM_16K);
|
||||||
|
|
||||||
|
void *address = (void *) (SAVE_ADDRESS_DEV_B);
|
||||||
|
if (is_eeprom_save) {
|
||||||
|
address = eeprom_contents;
|
||||||
|
} else if (device_variant == DEVICE_VARIANT_A) {
|
||||||
|
address = (void *) (SAVE_ADDRESS_DEV_A);
|
||||||
|
if (current_save_type == SAVE_TYPE_FLASHRAM_PKST2) {
|
||||||
|
address = (void *) (SAVE_ADDRESS_DEV_A_PKST2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_read(&fil, address, save_size, &br) != FR_OK) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_eeprom_save) {
|
||||||
|
if (d64_ll_write_eeprom_contents(eeprom_contents)) {
|
||||||
|
f_close(&fil);
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f_close(&fil) != FR_OK) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (br != save_size) {
|
||||||
|
return FLASHCART_ERROR_LOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_set_save_type (flashcart_save_type_t save_type) {
|
||||||
|
d64_save_type_t type;
|
||||||
|
|
||||||
|
switch (save_type) {
|
||||||
|
case FLASHCART_SAVE_TYPE_NONE:
|
||||||
|
type = SAVE_TYPE_NONE;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_EEPROM_4K:
|
||||||
|
type = SAVE_TYPE_EEPROM_4K;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_EEPROM_16K:
|
||||||
|
type = SAVE_TYPE_EEPROM_16K;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_SRAM:
|
||||||
|
type = SAVE_TYPE_SRAM;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_SRAM_BANKED:
|
||||||
|
type = SAVE_TYPE_SRAM_BANKED;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_SRAM_128K:
|
||||||
|
// NOTE: 64drive doesn't support 128 kiB SRAM save type, fallback to 32 kiB SRAM save type
|
||||||
|
type = SAVE_TYPE_SRAM;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_FLASHRAM:
|
||||||
|
type = SAVE_TYPE_FLASHRAM;
|
||||||
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2:
|
||||||
|
type = (device_variant == DEVICE_VARIANT_A) ? SAVE_TYPE_FLASHRAM_PKST2 : SAVE_TYPE_FLASHRAM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return FLASHCART_ERROR_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_enable_save_writeback(false)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_set_save_type(type)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_save_type = type;
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static flashcart_error_t d64_set_save_writeback (uint32_t *sectors) {
|
||||||
|
if (d64_ll_write_save_writeback_lba_list(sectors)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d64_ll_enable_save_writeback(true)) {
|
||||||
|
return FLASHCART_ERROR_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLASHCART_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static flashcart_t flashcart_d64 = {
|
||||||
|
.init = d64_init,
|
||||||
|
.deinit = d64_deinit,
|
||||||
|
.load_rom = d64_load_rom,
|
||||||
|
.load_file = d64_load_file,
|
||||||
|
.load_save = d64_load_save,
|
||||||
|
.set_save_type = d64_set_save_type,
|
||||||
|
.set_save_writeback = d64_set_save_writeback,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
flashcart_t *d64_get_flashcart (void) {
|
||||||
|
return &flashcart_d64;
|
||||||
|
}
|
24
src/flashcart/64drive/64drive.h
Normal file
24
src/flashcart/64drive/64drive.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @file 64drive.h
|
||||||
|
* @brief 64drive flashcart support
|
||||||
|
* @ingroup flashcart
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLASHCART_64DRIVE_H__
|
||||||
|
#define FLASHCART_64DRIVE_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include "../flashcart.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup 64drive
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
flashcart_t *d64_get_flashcart (void);
|
||||||
|
|
||||||
|
/** @} */ /* 64drive */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
110
src/flashcart/64drive/64drive_ll.c
Normal file
110
src/flashcart/64drive/64drive_ll.c
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
#include <libdragon.h>
|
||||||
|
|
||||||
|
#include "../flashcart_utils.h"
|
||||||
|
#include "64drive_ll.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CI_STATUS_BUSY (1 << 12)
|
||||||
|
|
||||||
|
#define DEVICE_VARIANT_MASK (0xFFFF)
|
||||||
|
#define FPGA_REVISION_MASK (0xFFFF)
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CMD_ID_SET_SAVE_TYPE = 0xD0,
|
||||||
|
CMD_ID_DISABLE_SAVE_WRITEBACK = 0xD1,
|
||||||
|
CMD_ID_ENABLE_SAVE_WRITEBACK = 0xD2,
|
||||||
|
CMD_ID_DISABLE_BYTESWAP_ON_LOAD = 0xE0,
|
||||||
|
CMD_ID_ENABLE_BYTESWAP_ON_LOAD = 0xE1,
|
||||||
|
CMD_ID_ENABLE_CARTROM_WRITES = 0xF0,
|
||||||
|
CMD_ID_DISABLE_CARTROM_WRITES = 0xF1,
|
||||||
|
CMD_ID_ENABLE_EXTENDED_MODE = 0xF8,
|
||||||
|
CMD_ID_DISABLE_EXTENDED_MODE = 0xF9,
|
||||||
|
} d64_ci_cmd_id_t;
|
||||||
|
|
||||||
|
|
||||||
|
static d64_regs_t *d64_regs = D64_REGS;
|
||||||
|
|
||||||
|
|
||||||
|
static bool d64_ll_ci_wait (void) {
|
||||||
|
int timeout = 0;
|
||||||
|
do {
|
||||||
|
if (timeout++ >= 0x10000) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (io_read((uint32_t) (&d64_regs->STATUS)) & CI_STATUS_BUSY);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool d64_ll_ci_cmd (d64_ci_cmd_id_t id) {
|
||||||
|
io_write((uint32_t) (&d64_regs->COMMAND), id);
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool d64_ll_get_version (d64_device_variant_t *device_variant, uint16_t *fpga_revision, uint32_t *bootloader_version) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*device_variant = (d64_device_variant_t) (io_read((uint32_t) (&d64_regs->VARIANT)) & DEVICE_VARIANT_MASK);
|
||||||
|
*fpga_revision = (io_read((uint32_t) (&d64_regs->REVISION)) & FPGA_REVISION_MASK);
|
||||||
|
*bootloader_version = io_read((uint32_t) (&d64_regs->PERSISTENT));
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_set_persistent_variable_storage (bool quick_reboot, d64_tv_type_t force_tv_type, uint8_t cic_seed) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
io_write((uint32_t) (&d64_regs->PERSISTENT), (quick_reboot << 16) | ((force_tv_type & 0x03) << 8) | (cic_seed & 0xFF));
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_set_save_type (d64_save_type_t save_type) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
io_write((uint32_t) (&d64_regs->BUFFER), save_type);
|
||||||
|
return d64_ll_ci_cmd(CMD_ID_SET_SAVE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_enable_save_writeback (bool enabled) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return d64_ll_ci_cmd(enabled ? CMD_ID_ENABLE_SAVE_WRITEBACK : CMD_ID_DISABLE_SAVE_WRITEBACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_enable_cartrom_writes (bool enabled) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return d64_ll_ci_cmd(enabled ? CMD_ID_ENABLE_CARTROM_WRITES : CMD_ID_DISABLE_CARTROM_WRITES);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_enable_extended_mode (bool enabled) {
|
||||||
|
d64_ll_ci_wait();
|
||||||
|
if (enabled) {
|
||||||
|
io_write((uint32_t) (&D64_REGS->COMMAND), CMD_ID_ENABLE_EXTENDED_MODE);
|
||||||
|
} else {
|
||||||
|
io_write((uint32_t) (&D64_REGS_EXT->COMMAND), CMD_ID_DISABLE_EXTENDED_MODE);
|
||||||
|
}
|
||||||
|
d64_regs = enabled ? D64_REGS_EXT : D64_REGS;
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_write_eeprom_contents (void *contents) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pi_dma_write_data(contents, d64_regs->EEPROM, 2048);
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool d64_ll_write_save_writeback_lba_list (void *list) {
|
||||||
|
if (d64_ll_ci_wait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pi_dma_write_data(list, d64_regs->WRITEBACK, 1024);
|
||||||
|
return d64_ll_ci_wait();
|
||||||
|
}
|
99
src/flashcart/64drive/64drive_ll.h
Normal file
99
src/flashcart/64drive/64drive_ll.h
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/**
|
||||||
|
* @file 64drive_ll.h
|
||||||
|
* @brief 64drive flashcart low level access
|
||||||
|
* @ingroup flashcart
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FLASHCART_64DRIVE_LL_H__
|
||||||
|
#define FLASHCART_64DRIVE_LL_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup 64drive
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t BUFFER[512];
|
||||||
|
uint32_t STATUS;
|
||||||
|
uint32_t __unused_1;
|
||||||
|
uint32_t COMMAND;
|
||||||
|
uint32_t __unused_2;
|
||||||
|
uint32_t LBA;
|
||||||
|
uint32_t __unused_3;
|
||||||
|
uint32_t LENGTH;
|
||||||
|
uint32_t __unused_4;
|
||||||
|
uint32_t RESULT;
|
||||||
|
|
||||||
|
uint32_t __unused_5[49];
|
||||||
|
|
||||||
|
uint32_t SDRAM_SIZE;
|
||||||
|
uint32_t MAGIC;
|
||||||
|
uint32_t VARIANT;
|
||||||
|
uint32_t PERSISTENT;
|
||||||
|
uint32_t BUTTON_UPGRADE;
|
||||||
|
uint32_t REVISION;
|
||||||
|
|
||||||
|
uint32_t __unused_6[64];
|
||||||
|
|
||||||
|
uint32_t USB_COMMAND_STATUS;
|
||||||
|
uint32_t USB_PARAM_RESULT[2];
|
||||||
|
|
||||||
|
uint32_t __unused_7[5];
|
||||||
|
|
||||||
|
uint32_t WIFI_COMMAND_STATUS;
|
||||||
|
uint32_t WIFI_PARAM_RESULT[2];
|
||||||
|
|
||||||
|
uint32_t __unused_8[757];
|
||||||
|
|
||||||
|
uint8_t EEPROM[2048];
|
||||||
|
uint32_t WRITEBACK[256];
|
||||||
|
} d64_regs_t;
|
||||||
|
|
||||||
|
#define D64_REGS_BASE (0x18000000UL)
|
||||||
|
#define D64_REGS_BASE_EXT (0x1F800000UL)
|
||||||
|
#define D64_REGS ((d64_regs_t *) D64_REGS_BASE)
|
||||||
|
#define D64_REGS_EXT ((d64_regs_t *) D64_REGS_BASE_EXT)
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DEVICE_VARIANT_UNKNOWN = 0x0000,
|
||||||
|
DEVICE_VARIANT_A = 0x4100,
|
||||||
|
DEVICE_VARIANT_B = 0x4200,
|
||||||
|
} d64_device_variant_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TV_TYPE_PAL = 0,
|
||||||
|
TV_TYPE_NTSC = 1,
|
||||||
|
TV_TYPE_MPAL = 2,
|
||||||
|
TV_TYPE_UNKNOWN = 3,
|
||||||
|
} d64_tv_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SAVE_TYPE_NONE,
|
||||||
|
SAVE_TYPE_EEPROM_4K,
|
||||||
|
SAVE_TYPE_EEPROM_16K,
|
||||||
|
SAVE_TYPE_SRAM,
|
||||||
|
SAVE_TYPE_FLASHRAM,
|
||||||
|
SAVE_TYPE_SRAM_BANKED,
|
||||||
|
SAVE_TYPE_FLASHRAM_PKST2,
|
||||||
|
} d64_save_type_t;
|
||||||
|
|
||||||
|
|
||||||
|
bool d64_ll_get_version (d64_device_variant_t *device_variant, uint16_t *fpga_revision, uint32_t *bootloader_version);
|
||||||
|
bool d64_ll_set_persistent_variable_storage (bool quick_reboot, d64_tv_type_t force_tv_type, uint8_t cic_seed);
|
||||||
|
bool d64_ll_set_save_type (d64_save_type_t save_type);
|
||||||
|
bool d64_ll_enable_save_writeback (bool enabled);
|
||||||
|
bool d64_ll_enable_cartrom_writes (bool enabled);
|
||||||
|
bool d64_ll_enable_extended_mode (bool enabled);
|
||||||
|
bool d64_ll_write_eeprom_contents (void *contents);
|
||||||
|
bool d64_ll_write_save_writeback_lba_list (void *list);
|
||||||
|
|
||||||
|
/** @} */ /* 64drive */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
49
src/flashcart/64drive/README.md
Normal file
49
src/flashcart/64drive/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
## 64drive developer notes
|
||||||
|
|
||||||
|
### Official documentation
|
||||||
|
|
||||||
|
http://64drive.retroactive.be/64drive_hardware_spec.pdf
|
||||||
|
|
||||||
|
|
||||||
|
### Save location offset in SDRAM
|
||||||
|
|
||||||
|
| Type | HW1 | HW2 |
|
||||||
|
| ---------------------------- | ------------ | ------------ |
|
||||||
|
| SRAM | `0x03FE0000` | `0x0FFC0000` |
|
||||||
|
| FlashRAM | `0x03FE0000` | `0x0FFC0000` |
|
||||||
|
| SRAM banked | `0x03FE0000` | `0x0FFC0000` |
|
||||||
|
| FlashRAM (Pokemon Stadium 2) | `0x01606560` | `0x0FFC0000` |
|
||||||
|
|
||||||
|
EEPROM save types are stored in separate memory inside FPGA, rest of the save types are stored inside SDRAM memory.
|
||||||
|
EEPROM save types need manual load as this memory space can't be written with "Read multiple sectors to SDRAM" command.
|
||||||
|
|
||||||
|
|
||||||
|
### "Persistent variable storage" register
|
||||||
|
|
||||||
|
| Bits | Meaning |
|
||||||
|
| --------- | ---------------------------------------------------------- |
|
||||||
|
| `[31:17]` | _Unused_ |
|
||||||
|
| `[16]` | Reset behavior: `0` - boot to menu / `1` - quick boot game |
|
||||||
|
| `[15:10]` | _Unused_ |
|
||||||
|
| `[9:8]` | Force TV type |
|
||||||
|
| `[7:0]` | CIC seed |
|
||||||
|
|
||||||
|
It's used by the bootloader to quickly load game without running menu again.
|
||||||
|
Should contain bootloader version but it's zeroed if ROM wasn't ran through bootloader (e.g. ROM was loaded via USB).
|
||||||
|
|
||||||
|
|
||||||
|
### "Enable/disable save writeback" command
|
||||||
|
|
||||||
|
Does not work when USB cable is connected - writeback is forced to be in disabled state.
|
||||||
|
Curiously, official 64drive menu never calls this command, save writeback might be enabled by default.
|
||||||
|
|
||||||
|
|
||||||
|
### "Enable/disable byteswap on load" command
|
||||||
|
|
||||||
|
Annoyingly, this command affects both loading single sector into the buffer and loading multiple sectors to the SDRAM.
|
||||||
|
|
||||||
|
|
||||||
|
### "Enable/disable extended address mode" command
|
||||||
|
|
||||||
|
As of latest available firmware version 2.05 this command is not implemented.
|
||||||
|
Documentation specifies it's supported on firmwares 2.06+ but this version (or anything newer) was never published.
|
@ -8,6 +8,8 @@
|
|||||||
#include "utils/utils.h"
|
#include "utils/utils.h"
|
||||||
|
|
||||||
#include "flashcart.h"
|
#include "flashcart.h"
|
||||||
|
|
||||||
|
#include "64drive/64drive.h"
|
||||||
#include "sc64/sc64.h"
|
#include "sc64/sc64.h"
|
||||||
|
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ static const size_t SAVE_SIZE[__FLASHCART_SAVE_TYPE_END] = {
|
|||||||
KiB(96),
|
KiB(96),
|
||||||
KiB(128),
|
KiB(128),
|
||||||
KiB(128),
|
KiB(128),
|
||||||
|
KiB(128),
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t save_writeback_sectors[SAVE_WRITEBACK_MAX_SECTORS] __attribute__((aligned(8)));
|
static uint32_t save_writeback_sectors[SAVE_WRITEBACK_MAX_SECTORS] __attribute__((aligned(8)));
|
||||||
@ -58,7 +61,7 @@ flashcart_error_t flashcart_init (void) {
|
|||||||
int (* libcart_init) (void);
|
int (* libcart_init) (void);
|
||||||
flashcart_t *(* get) (void);
|
flashcart_t *(* get) (void);
|
||||||
} flashcarts[CART_MAX] = {
|
} flashcarts[CART_MAX] = {
|
||||||
{ CART_CI, ci_init, NULL }, // 64drive
|
{ CART_CI, ci_init, d64_get_flashcart }, // 64drive
|
||||||
{ CART_SC, sc_init, sc64_get_flashcart }, // SC64
|
{ CART_SC, sc_init, sc64_get_flashcart }, // SC64
|
||||||
{ CART_EDX, edx_init, NULL }, // Series X EverDrive-64
|
{ CART_EDX, edx_init, NULL }, // Series X EverDrive-64
|
||||||
{ CART_ED, ed_init, NULL }, // Original EverDrive-64
|
{ CART_ED, ed_init, NULL }, // Original EverDrive-64
|
||||||
|
@ -32,6 +32,7 @@ typedef enum {
|
|||||||
FLASHCART_SAVE_TYPE_SRAM_BANKED,
|
FLASHCART_SAVE_TYPE_SRAM_BANKED,
|
||||||
FLASHCART_SAVE_TYPE_SRAM_128K,
|
FLASHCART_SAVE_TYPE_SRAM_128K,
|
||||||
FLASHCART_SAVE_TYPE_FLASHRAM,
|
FLASHCART_SAVE_TYPE_FLASHRAM,
|
||||||
|
FLASHCART_SAVE_TYPE_FLASHRAM_PKST2,
|
||||||
__FLASHCART_SAVE_TYPE_END
|
__FLASHCART_SAVE_TYPE_END
|
||||||
} flashcart_save_type_t;
|
} flashcart_save_type_t;
|
||||||
|
|
||||||
|
@ -311,6 +311,9 @@ static flashcart_error_t sc64_set_save_type (flashcart_save_type_t save_type) {
|
|||||||
case FLASHCART_SAVE_TYPE_FLASHRAM:
|
case FLASHCART_SAVE_TYPE_FLASHRAM:
|
||||||
type = SAVE_TYPE_FLASHRAM;
|
type = SAVE_TYPE_FLASHRAM;
|
||||||
break;
|
break;
|
||||||
|
case FLASHCART_SAVE_TYPE_FLASHRAM_PKST2:
|
||||||
|
type = SAVE_TYPE_FLASHRAM;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return FLASHCART_ERROR_ARGS;
|
return FLASHCART_ERROR_ARGS;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
|||||||
const char *firmware_message = (
|
const char *firmware_message = (
|
||||||
"Minimum supported versions:\n"
|
"Minimum supported versions:\n"
|
||||||
"EverDrive-64: ?\n"
|
"EverDrive-64: ?\n"
|
||||||
"64drive: ?\n"
|
"64drive: 2.05\n"
|
||||||
"SC64: 2.16.0"
|
"SC64: 2.16.0"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user