From 02e6466e5ce6f8c3183e47c7f034b7048e13bd80 Mon Sep 17 00:00:00 2001 From: CrashOveride95 Date: Mon, 11 Jan 2021 00:46:56 -0500 Subject: [PATCH] SRAM support --- Makefile | 16 +++++++- README.md | 1 + src/game/game_init.c | 13 +++++++ src/game/game_init.h | 5 +++ src/game/nupiinitsram.c | 55 +++++++++++++++++++++++++++ src/game/nupireadwritesram.c | 52 ++++++++++++++++++++++++++ src/game/save_file.c | 72 +++++++++++++++++++++++++++++++----- src/game/sram.h | 30 +++++++++++++++ 8 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 src/game/nupiinitsram.c create mode 100644 src/game/nupireadwritesram.c create mode 100644 src/game/sram.h diff --git a/Makefile b/Makefile index 1d2aa220..29be9114 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,20 @@ COMPILER ?= gcc $(eval $(call validate-option,COMPILER,ido gcc)) +# SAVETYPE - selects the save type +# eep4k - uses EEPROM 4kbit +# eep16k - uses EEPROM 16kbit (There aren't any differences in syntax, but this is provided just in case) +# sram - uses SRAM 256Kbit +SAVETYPE ?= eep4k +$(eval $(call validate-option,SAVETYPE,eep4k eep16k sram)) +ifeq ($(SAVETYPE),eep4k) + DEFINES += EEP=1 EEP4K=1 +else ifeq ($(SAVETYPE),eep16k) + DEFINES += EEP=1 EEP16K=1 +else ifeq ($(SAVETYPE),sram) + DEFINES += SRAM=1 +endif + COMPRESS ?= yay0 $(eval $(call validate-option,COMPRESS,yay0 gzip)) ifeq ($(COMPRESS),gzip) @@ -804,8 +818,6 @@ $(ROM): $(ELF) $(BUILD_DIR)/$(TARGET).objdump: $(ELF) $(OBJDUMP) -D $< > $@ - - .PHONY: all clean distclean default diff test load # with no prerequisites, .SECONDARY causes no intermediate target to be removed .SECONDARY: diff --git a/README.md b/README.md index 1c0650f5..8f53f2bb 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ - It has been edited to allow for the usage of the final "N64 OS" library, version ``2.0L`` - Shindou Rumble Pak code is on for all regions. - Targeting the iQue Player is supported. +- Saving to 32kbyte/256kbit SRAM is supported. - It has been patched with someone2639's shiftable segments patch - Getting HVQM FMV support to work with the game is in progress. - Getting UNFLoader (flashcart USB library) to work with the game is in progress. diff --git a/src/game/game_init.c b/src/game/game_init.c index e3eed8c2..35ec669c 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -26,6 +26,9 @@ #include "usb/usb.h" #include "usb/debug.h" #endif +#ifdef SRAM +#include "sram.h" +#endif #include // FIXME: I'm not sure all of these variables belong in this file, but I don't @@ -38,7 +41,12 @@ struct GfxPool *gGfxPool; OSContStatus gControllerStatuses[4]; OSContPad gControllerPads[4]; u8 gControllerBits; +#ifdef EEP s8 gEepromProbe; +#endif +#ifdef SRAM +s8 gSramProbe; +#endif OSMesgQueue gGameVblankQueue; OSMesgQueue D_80339CB8; OSMesg D_80339CD0; @@ -555,9 +563,14 @@ void init_controllers(void) { gControllers[0].controllerData = &gControllerPads[0]; osContInit(&gSIEventMesgQueue, &gControllerBits, &gControllerStatuses[0]); +#ifdef EEP // strangely enough, the EEPROM probe for save data is done in this function. // save pak detection? gEepromProbe = osEepromProbe(&gSIEventMesgQueue); +#endif +#ifdef SRAM + gSramProbe = nuPiInitSram(); +#endif // loop over the 4 ports and link the controller structs to the appropriate // status and pad. Interestingly, although there are pointers to 3 controllers, diff --git a/src/game/game_init.h b/src/game/game_init.h index 454686ad..f1948718 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -41,7 +41,12 @@ extern Gfx *gDisplayListHead; extern u8 *gGfxPoolEnd; extern struct GfxPool *gGfxPool; extern u8 gControllerBits; +#ifdef EEP extern s8 gEepromProbe; +#endif +#ifdef SRAM +extern s8 gSramProbe; +#endif extern void (*gGoddardVblankCallback)(void); extern struct Controller *gPlayer1Controller; diff --git a/src/game/nupiinitsram.c b/src/game/nupiinitsram.c new file mode 100644 index 00000000..4e1ad1bf --- /dev/null +++ b/src/game/nupiinitsram.c @@ -0,0 +1,55 @@ +/*======================================================================*/ +/* NuSYS */ +/* nupisraminit.c */ +/* */ +/* Copyright (C) 1997, NINTENDO Co,Ltd. */ +/* */ +/*----------------------------------------------------------------------*/ +/* Ver 1.2 98/07/4 Created by Kensaku Ohki(SLANP) */ +/*----------------------------------------------------------------------*/ +/* $Id: nupiinitsram.c,v 1.2 1998/07/11 11:22:46 ohki Exp $ */ +/*======================================================================*/ +#include + +#define SRAM_START_ADDR 0x08000000 +#define SRAM_SIZE 0x8000 +#define SRAM_LATENCY 0x5 +#define SRAM_PULSE 0x0c +#define SRAM_PAGE_SIZE 0xd +#define SRAM_REL_DURATION 0x2 + +OSPiHandle* nuPiSramHandle; +static OSPiHandle SramHandle; + +/*----------------------------------------------------------------------*/ +/* nuPiSramInit - Initialization of handle for SRAM */ +/* Initialize handle for SRAM */ +/* IN: None */ +/* RET: If detected, return 1, otherwise 0 */ +/*----------------------------------------------------------------------*/ +int nuPiInitSram() +{ + if (SramHandle.baseAddress == PHYS_TO_K1(SRAM_START_ADDR)) + return 0; + + /* Fill basic information */ + SramHandle.type = DEVICE_TYPE_SRAM; + SramHandle.baseAddress = PHYS_TO_K1(SRAM_START_ADDR); + + /* Get Domain parameters */ + SramHandle.latency = (u8)SRAM_LATENCY; + SramHandle.pulse = (u8)SRAM_PULSE; + SramHandle.pageSize = (u8)SRAM_PAGE_SIZE; + SramHandle.relDuration = (u8)SRAM_REL_DURATION; + SramHandle.domain = PI_DOMAIN2; + + /* Fill speed and transferInfo to zero */ + SramHandle.speed = 0; + bzero((void *)&(SramHandle.transferInfo), + sizeof(SramHandle.transferInfo)); + + /* Put the SramHandle onto PiTable*/ + osEPiLinkHandle(&SramHandle); + nuPiSramHandle = &SramHandle; + return 1; +} diff --git a/src/game/nupireadwritesram.c b/src/game/nupireadwritesram.c new file mode 100644 index 00000000..9f0a3a90 --- /dev/null +++ b/src/game/nupireadwritesram.c @@ -0,0 +1,52 @@ +/*======================================================================*/ +/* NuSYS */ +/* nupireadsram.c */ +/* */ +/* Copyright (C) 1997, NINTENDO Co,Ltd. */ +/* */ +/*----------------------------------------------------------------------*/ +/* Ver 1.2 98/07/11 Created by Kensaku Ohki(SLANP) */ +/*----------------------------------------------------------------------*/ +/* $Id: nupireadwritesram.c,v 1.3 1999/06/09 02:33:22 ohki Exp $ */ +/*======================================================================*/ +#include + +extern OSPiHandle* nuPiSramHandle; +/*----------------------------------------------------------------------*/ +/* nuPiReadWriteSram - DMA transfers data to and from SRAM. */ +/* The message queue is a local variable so it can be used */ +/* between threads. */ +/* IN: addr SRAM address. */ +/* buf_ptr RDRAM address. */ +/* size Transfer size. */ +/* RET: None */ +/*----------------------------------------------------------------------*/ +int nuPiReadWriteSram(u32 addr, void* buf_ptr, u32 size, s32 flag) +{ + OSIoMesg dmaIoMesgBuf; + OSMesgQueue dmaMesgQ; + OSMesg dmaMesgBuf; + + /* Create the message queue. */ + osCreateMesgQueue(&dmaMesgQ, &dmaMesgBuf, 1); + + dmaIoMesgBuf.hdr.pri = OS_MESG_PRI_NORMAL; + dmaIoMesgBuf.hdr.retQueue = &dmaMesgQ; + dmaIoMesgBuf.dramAddr = buf_ptr; + dmaIoMesgBuf.devAddr = (u32)addr; + dmaIoMesgBuf.size = size; + + if(flag == OS_READ){ + /* Make CPU cache invalid */ + osInvalDCache((void*)buf_ptr, (s32)size); + } else { + /* Write back */ + osWritebackDCache((void*)buf_ptr, (s32)size); + } + osEPiStartDma(nuPiSramHandle, &dmaIoMesgBuf, flag); + + /* Wait for the end */ + (void)osRecvMesg(&dmaMesgQ, &dmaMesgBuf, OS_MESG_BLOCK); + return 0; +} + diff --git a/src/game/save_file.c b/src/game/save_file.c index 02e5bdc8..7e4c7a63 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -11,6 +11,9 @@ #include "level_table.h" #include "course_table.h" #include "rumble_init.h" +#ifdef SRAM +#include "sram.h" +#endif #define MENU_DATA_MAGIC 0x4849 #define SAVE_FILE_MAGIC 0x4441 @@ -43,13 +46,7 @@ s8 gLevelToCourseNumTable[] = { STATIC_ASSERT(ARRAY_COUNT(gLevelToCourseNumTable) == LEVEL_COUNT - 1, "change this array if you are adding levels"); - -// This was probably used to set progress to 100% for debugging, but -// it was removed from the release ROM. -static void stub_save_file_1(void) { - UNUSED s32 pad; -} - +#ifdef EEP /** * Read from EEPROM to a given address. * The EEPROM address is computed using the offset of the destination address from gSaveBuffer. @@ -105,6 +102,65 @@ static s32 write_eeprom_data(void *buffer, s32 size) { return status; } +#endif +#ifdef SRAM +/** + * Read from SRAM to a given address. + * The SRAM address is computed using the offset of the destination address from gSaveBuffer. + * Try at most 4 times, and return 0 on success. On failure, return the status returned from + * nuPiReadSram. It also returns 0 if SRAM isn't loaded correctly in the system. + */ +static s32 read_eeprom_data(void *buffer, s32 size) { + s32 status = 0; + + if (gSramProbe != 0) { + s32 triesLeft = 4; + u32 offset = (u32)((u8 *) buffer - (u8 *) &gSaveBuffer) / 8; + + do { +#if ENABLE_RUMBLE + block_until_rumble_pak_free(); +#endif + triesLeft--; + status = nuPiReadSram(offset, buffer, size); +#if ENABLE_RUMBLE + release_rumble_pak_control(); +#endif + } while (triesLeft > 0 && status != 0); + } + + return status; +} + +/** + * Write data to SRAM. + * The SRAM address is computed using the offset of the source address from gSaveBuffer. + * Try at most 4 times, and return 0 on success. On failure, return the status returned from + * nuPiWriteSram. Unlike read_eeprom_data, return 1 if SRAM isn't loaded. + */ +static s32 write_eeprom_data(void *buffer, s32 size) { + s32 status = 1; + + if (gSramProbe != 0) { + s32 triesLeft = 4; + u32 offset = (u32)((u8 *) buffer - (u8 *) &gSaveBuffer) >> 3; + + do { +#if ENABLE_RUMBLE + block_until_rumble_pak_free(); +#endif + triesLeft--; + status = nuPiWriteSram(offset, buffer, size); +#if ENABLE_RUMBLE + release_rumble_pak_control(); +#endif + } while (triesLeft > 0 && status != 0); + } + + return status; +} +#endif + /** * Sum the bytes in data to data + size - 2. The last two bytes are ignored @@ -329,8 +385,6 @@ void save_file_load_all(void) { break; } } - - stub_save_file_1(); } /** diff --git a/src/game/sram.h b/src/game/sram.h new file mode 100644 index 00000000..7855e067 --- /dev/null +++ b/src/game/sram.h @@ -0,0 +1,30 @@ +#ifndef SRAM_H +#define SRAM_H + + +/*----------------------------------------------------------------------*/ +/* nuPiSramInit - Initialization of handle for SRAM */ +/*----------------------------------------------------------------------*/ +extern int nuPiInitSram(); +/*----------------------------------------------------------------------*/ +/* nuPiReadWriteSram - DMA transfers data to and from SRAM. */ +/* IN: addr SRAM address. */ +/* buf_ptr RDRAM address. */ +/* size Transfer size. */ +/* RET: None */ +/*----------------------------------------------------------------------*/ +extern int nuPiReadWriteSram(u32 addr, void* buf_ptr, u32 size, s32 flag); + +/*----------------------------------------------------------------------*/ +/* nuPiReadSram - Read from SRAM */ +/*----------------------------------------------------------------------*/ +#define nuPiReadSram(addr, buf_ptr, size) \ + nuPiReadWriteSram(addr, buf_ptr, size, OS_READ) + +/*----------------------------------------------------------------------*/ +/* nuPiWriteSram - Write to SRAM */ +/*----------------------------------------------------------------------*/ +#define nuPiWriteSram(addr, buf_ptr, size) \ + nuPiReadWriteSram(addr, buf_ptr, size, OS_WRITE) + +#endif // SRAM_H \ No newline at end of file