From f34013d053535c615b23a8c903ea4b35a2d42781 Mon Sep 17 00:00:00 2001 From: devwizard <53394095+devwizard64@users.noreply.github.com> Date: Sun, 7 May 2023 00:26:44 -0700 Subject: [PATCH] Add SC64 SD card support --- Makefile.common | 3 +- mupen64plus-core/src/main/rom.c | 10 +- mupen64plus-core/src/memory/m64p_memory.c | 45 ++++ mupen64plus-core/src/pi/pi_controller.c | 97 ++++++++- mupen64plus-core/src/pi/pi_controller.h | 2 + mupen64plus-core/src/pi/summercart.c | 242 ++++++++++++++++++++++ mupen64plus-core/src/pi/summercart.h | 27 +++ 7 files changed, 418 insertions(+), 8 deletions(-) create mode 100644 mupen64plus-core/src/pi/summercart.c create mode 100644 mupen64plus-core/src/pi/summercart.h diff --git a/Makefile.common b/Makefile.common index 90f5a0421..06664b9bc 100644 --- a/Makefile.common +++ b/Makefile.common @@ -187,7 +187,8 @@ SOURCES_C += \ $(CORE_DIR)/src/pi/sram.c \ $(CORE_DIR)/src/pi/flashram.c \ $(CORE_DIR)/src/pi/cart_rom.c \ - $(CORE_DIR)/src/pi/is_viewer.c + $(CORE_DIR)/src/pi/is_viewer.c \ + $(CORE_DIR)/src/pi/summercart.c # $(CORE_DIR)/src/api/debugger.c \ # $(CORE_DIR)/src/main/ini_reader.c \ diff --git a/mupen64plus-core/src/main/rom.c b/mupen64plus-core/src/main/rom.c index 1d3d18f72..7ba48c00a 100644 --- a/mupen64plus-core/src/main/rom.c +++ b/mupen64plus-core/src/main/rom.c @@ -174,20 +174,20 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size) /* Clear Byte-swapped flag, since ROM is now deleted. */ g_MemHasBeenBSwapped = 0; /* allocate new buffer for ROM and copy into this buffer */ - g_rom_size = size; - g_rom = (unsigned char *) malloc(size); + g_rom_size = size > 0x4000000 ? size : 0x4000000; + g_rom = (unsigned char *) malloc(g_rom_size); alternate_vi_timing = 0; g_vi_refresh_rate = DEFAULT_COUNT_PER_SCANLINE; if (g_rom == NULL) return M64ERR_NO_MEMORY; memcpy(g_rom, romimage, size); - swap_rom(g_rom, &imagetype, g_rom_size); + swap_rom(g_rom, &imagetype, size); memcpy(&ROM_HEADER, g_rom, sizeof(m64p_rom_header)); /* Calculate MD5 hash */ md5_init(&state); - md5_append(&state, (const md5_byte_t*)g_rom, g_rom_size); + md5_append(&state, (const md5_byte_t*)g_rom, size); md5_finish(&state, digest); for ( i = 0; i < 16; ++i ) sprintf(buffer+i*2, "%02X", digest[i]); @@ -413,7 +413,7 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size) DebugMessage(M64MSG_INFO, "MD5: %s", ROM_SETTINGS.MD5); DebugMessage(M64MSG_INFO, "CRC: %x %x", sl(ROM_HEADER.CRC1), sl(ROM_HEADER.CRC2)); DebugMessage(M64MSG_INFO, "Imagetype: %s", buffer); - DebugMessage(M64MSG_INFO, "Rom size: %d bytes (or %d Mb or %d Megabits)", g_rom_size, g_rom_size/1024/1024, g_rom_size/1024/1024*8); + DebugMessage(M64MSG_INFO, "Rom size: %d bytes (or %d Mb or %d Megabits)", size, size/1024/1024, size/1024/1024*8); DebugMessage(M64MSG_VERBOSE, "ClockRate = %x", sl(ROM_HEADER.ClockRate)); DebugMessage(M64MSG_INFO, "Version: %x", sl(ROM_HEADER.Release)); if(sl(ROM_HEADER.Manufacturer_ID) == 'N') diff --git a/mupen64plus-core/src/memory/m64p_memory.c b/mupen64plus-core/src/memory/m64p_memory.c index 47974676a..6d72c3a5a 100644 --- a/mupen64plus-core/src/memory/m64p_memory.c +++ b/mupen64plus-core/src/memory/m64p_memory.c @@ -41,6 +41,7 @@ #include "../dd/dd_controller.h" #include "../pi/is_viewer.h" +#include "../pi/summercart.h" #ifdef DBG #include "../debugger/dbg_types.h" @@ -1046,6 +1047,46 @@ static void write_isvd(void) { writed(write_is_viewer, NULL, mupencoreaddress, cpu_dword); } +static void read_screg(void) +{ + readw(read_summercart_regs, &g_dev.pi, mupencoreaddress, rdword); +} + +static void read_scregb(void) +{ + readb(read_summercart_regs, &g_dev.pi, mupencoreaddress, rdword); +} + +static void read_scregh(void) +{ + readh(read_summercart_regs, &g_dev.pi, mupencoreaddress, rdword); +} + +static void read_scregd(void) +{ + readd(read_summercart_regs, &g_dev.pi, mupencoreaddress, rdword); +} + +static void write_screg(void) +{ + writew(write_summercart_regs, &g_dev.pi, mupencoreaddress, cpu_word); +} + +static void write_scregb(void) +{ + writeb(write_summercart_regs, &g_dev.pi, mupencoreaddress, cpu_byte); +} + +static void write_scregh(void) +{ + writeh(write_summercart_regs, &g_dev.pi, mupencoreaddress, cpu_hword); +} + +static void write_scregd(void) +{ + writed(write_summercart_regs, &g_dev.pi, mupencoreaddress, cpu_dword); +} + #ifdef DBG static int memtype[0x10000]; static void (*saved_readmemb[0x10000])(void); @@ -1395,6 +1436,10 @@ void poweron_memory(void) /* map IS-Viewer */ map_region(0xb3ff, M64P_MEM_NOTHING, RW(isv)); + + /* map SummerCart64 */ + map_region(0x9fff, M64P_MEM_NOTHING, RW(screg)); + map_region(0xbfff, M64P_MEM_NOTHING, RW(screg)); } static void map_region_t(uint16_t region, int type) diff --git a/mupen64plus-core/src/pi/pi_controller.c b/mupen64plus-core/src/pi/pi_controller.c index 0051235d2..af2684622 100644 --- a/mupen64plus-core/src/pi/pi_controller.c +++ b/mupen64plus-core/src/pi/pi_controller.c @@ -111,6 +111,71 @@ static void dma_pi_read(struct pi_controller *pi) dma_write_flashram(pi); } } + else if (pi->regs[PI_CART_ADDR_REG] >= 0x10000000 + && pi->regs[PI_CART_ADDR_REG] < 0x14000000) + { + //CART ROM + length = (pi->regs[PI_RD_LEN_REG] & 0xFFFFFF) + 1; + i = (pi->regs[PI_CART_ADDR_REG] - 0x10000000); + + length = (i + length) > pi->cart_rom.rom_size ? + (pi->cart_rom.rom_size - i) : length; + length = (pi->regs[PI_DRAM_ADDR_REG] + length) > 0x7FFFFF ? + (0x7FFFFF - pi->regs[PI_DRAM_ADDR_REG]) : length; + + if (i > pi->cart_rom.rom_size || pi->regs[PI_DRAM_ADDR_REG] > 0x7FFFFF || !pi->summercart.cfg_rom_write) + { + /* mark both DMA and IO as busy */ + pi->regs[PI_STATUS_REG] |= + PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY; + + /* schedule end of dma interrupt event */ + cp0_update_count(); + add_interrupt_event(PI_INT, length / 8); + + return; + } + + dram_address = pi->regs[PI_DRAM_ADDR_REG]; + rom_address = (pi->regs[PI_CART_ADDR_REG] - 0x10000000); + dram = (uint8_t*)pi->ri->rdram.dram; + rom = pi->cart_rom.rom; + + for (i = 0; i < length; ++i) + rom[(rom_address + i) ^ S8] = dram[(dram_address + i) ^ S8]; + } + else if (pi->regs[PI_CART_ADDR_REG] >= 0x1ffe0000 + && pi->regs[PI_CART_ADDR_REG] < 0x1fff0000) + { + //SC64 BUFFER + length = (pi->regs[PI_RD_LEN_REG] & 0xFFFFFF) + 1; + i = (pi->regs[PI_CART_ADDR_REG] - 0x1ffe0000); + + length = (i + length) > 8192 ? (8192 - i) : length; + length = (pi->regs[PI_DRAM_ADDR_REG] + length) > 0x7FFFFF ? + (0x7FFFFF - pi->regs[PI_DRAM_ADDR_REG]) : length; + + if (i > 8192 || pi->regs[PI_DRAM_ADDR_REG] > 0x7FFFFF || !pi->summercart.unlock) + { + /* mark both DMA and IO as busy */ + pi->regs[PI_STATUS_REG] |= + PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY; + + /* schedule end of dma interrupt event */ + cp0_update_count(); + add_interrupt_event(PI_INT, length / 8); + + return; + } + + dram_address = pi->regs[PI_DRAM_ADDR_REG]; + rom_address = (pi->regs[PI_CART_ADDR_REG] - 0x1ffe0000); + dram = (uint8_t*)pi->ri->rdram.dram; + rom = pi->summercart.buffer; + + for (i = 0; i < length; ++i) + rom[(rom_address + i) ^ S8] = dram[(dram_address + i) ^ S8]; + } else { DebugMessage(M64MSG_WARNING, "Unknown dma read at 0x%08X in dma_pi_read()", pi->regs[PI_CART_ADDR_REG]); @@ -223,7 +288,7 @@ static void dma_pi_write(struct pi_controller *pi) } /* XXX: why need special treatment ? */ - if (pi->regs[PI_CART_ADDR_REG] >= 0x1fc00000) /* for paper mario */ + if (pi->regs[PI_CART_ADDR_REG] >= 0x1fc00000 && pi->regs[PI_CART_ADDR_REG] < 0x1fd00000) /* for paper mario */ { /* mark DMA as busy */ pi->regs[PI_STATUS_REG] |= PI_STATUS_DMA_BUSY; @@ -259,6 +324,33 @@ static void dma_pi_write(struct pi_controller *pi) dram = (uint8_t*)pi->ri->rdram.dram; rom = pi->dd_rom.rom; } + else if (pi->regs[PI_CART_ADDR_REG] >= 0x1ffe0000 && pi->regs[PI_CART_ADDR_REG] < 0x1fff0000) + { + /* SC64 BUFFER */ + length = (pi->regs[PI_WR_LEN_REG] & 0xFFFFFE) + 2; + i = (pi->regs[PI_CART_ADDR_REG] - 0x1ffe0000); + length = (i + length) > 8192 ? (8192 - i) : length; + length = (pi->regs[PI_DRAM_ADDR_REG] + length) > 0x7FFFFF ? + (0x7FFFFF - pi->regs[PI_DRAM_ADDR_REG]) : length; + + if (i > 8192 || pi->regs[PI_DRAM_ADDR_REG] > 0x7FFFFF || !pi->summercart.unlock) + { + /* mark both DMA and IO as busy */ + pi->regs[PI_STATUS_REG] |= + PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY; + + /* schedule end of dma interrupt event */ + cp0_update_count(); + add_interrupt_event(PI_INT, length / 8); + + return; + } + + dram_address = pi->regs[PI_DRAM_ADDR_REG]; + rom_address = (pi->regs[PI_CART_ADDR_REG] - 0x1ffe0000); + dram = (uint8_t*)pi->ri->rdram.dram; + rom = pi->summercart.buffer; + } else { /* CART ROM */ @@ -328,6 +420,7 @@ void init_pi(struct pi_controller* pi, init_dd_rom(&pi->dd_rom, ddrom, ddrom_size); init_flashram(&pi->flashram, flashram_user_data, flashram_save, flashram_data); init_sram(&pi->sram, sram_user_data, sram_save, sram_data); + init_summercart(&pi->summercart); pi->use_flashram = 0; @@ -344,7 +437,7 @@ void poweron_pi(struct pi_controller* pi) poweron_dd_rom(&pi->dd_rom); poweron_flashram(&pi->flashram); poweron_is_viewer(); - + poweron_summercart(&pi->summercart); } /* Reads a word from the PI MMIO register space. */ diff --git a/mupen64plus-core/src/pi/pi_controller.h b/mupen64plus-core/src/pi/pi_controller.h index 4051e9970..754060a1e 100644 --- a/mupen64plus-core/src/pi/pi_controller.h +++ b/mupen64plus-core/src/pi/pi_controller.h @@ -29,6 +29,7 @@ #include "flashram.h" #include "sram.h" #include "../dd/dd_rom.h" +#include "summercart.h" #ifndef PI_REG #define PI_REG(a) ((a & 0xffff) >> 2) @@ -63,6 +64,7 @@ struct pi_controller struct flashram flashram; struct sram sram; struct dd_rom dd_rom; + struct summercart summercart; int use_flashram; diff --git a/mupen64plus-core/src/pi/summercart.c b/mupen64plus-core/src/pi/summercart.c new file mode 100644 index 000000000..c2a6487fe --- /dev/null +++ b/mupen64plus-core/src/pi/summercart.c @@ -0,0 +1,242 @@ +#include "pi_controller.h" + +#define M64P_CORE_PROTOTYPES 1 +#include "../memory/memory.h" + +#include +#include +#include + +static uint8_t* summercart_sd_addr(struct pi_controller* pi, size_t size) +{ + uint32_t addr = pi->summercart.data0 & 0x1fffffff; + if (addr >= 0x1ffe0000 && addr+size < 0x1ffe0000+8192) + { + return pi->summercart.buffer + (addr - 0x1ffe0000); + } + if (addr >= 0x10000000 && addr+size < 0x10000000+0x4000000) + { + return pi->cart_rom.rom + (addr - 0x10000000); + } + return NULL; +} + +static uint32_t summercart_sd_init(struct pi_controller* pi) +{ + FILE* fp; + if (!pi->summercart.sd_path) return 0x40000000; + if (!(fp = fopen(pi->summercart.sd_path, "rb"))) return 0x40000000; + fseek(fp, 0, SEEK_END); + pi->summercart.sd_size = ftell(fp); + fclose(fp); + return 0; +} + +static uint32_t summercart_sd_read(struct pi_controller* pi) +{ + size_t i; + FILE* fp; + uint8_t* ptr; + long offset = 512 * pi->summercart.sd_sector; + size_t size = 512 * pi->summercart.data1; + if (offset+size > pi->summercart.sd_size) return 0x40000000; + if (!(ptr = summercart_sd_addr(pi, size))) return 0x40000000; + if (!(fp = fopen(pi->summercart.sd_path, "rb"))) return 0x40000000; + fseek(fp, offset, SEEK_SET); + for (i = 0; i < size; ++i) + { + int c = fgetc(fp); + if (c < 0) + { + fclose(fp); + return 0x40000000; + } + ptr[i^pi->summercart.sd_byteswap^S8] = c; + } + fclose(fp); + return 0; +} + +static uint32_t summercart_sd_write(struct pi_controller* pi) +{ + size_t i; + FILE* fp; + uint8_t* ptr; + long offset = 512 * pi->summercart.sd_sector; + size_t size = 512 * pi->summercart.data1; + if (offset+size > pi->summercart.sd_size) return 0x40000000; + if (!(ptr = summercart_sd_addr(pi, size))) return 0x40000000; + if (!(fp = fopen(pi->summercart.sd_path, "r+b"))) return 0x40000000; + fseek(fp, offset, SEEK_SET); + for (i = 0; i < size; ++i) + { + int c = fputc(ptr[i^S8], fp); + if (c < 0) + { + fclose(fp); + return 0x40000000; + } + } + fclose(fp); + return 0; +} + +void init_summercart(struct summercart* summercart) +{ + summercart->sd_path = getenv("PL_SD_CARD_IMAGE"); +} + +void poweron_summercart(struct summercart* summercart) +{ + memset(summercart->buffer, 0, 8192); + summercart->sd_size = -1; + summercart->status = 0; + summercart->data0 = 0; + summercart->data1 = 0; + summercart->sd_sector = 0; + summercart->cfg_rom_write = 0; + summercart->sd_byteswap = 0; + summercart->unlock = 0; + summercart->lock_seq = 0; +} + +int read_summercart_regs(void* opaque, uint32_t address, uint32_t* value) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + uint32_t addr = address & 0xFFFF; + + *value = 0; + + if (!pi->summercart.unlock) return 0; + + switch (address & 0xFFFF) + { + case 0x00: *value = pi->summercart.status; break; + case 0x04: *value = pi->summercart.data0; break; + case 0x08: *value = pi->summercart.data1; break; + case 0x0C: *value = 0x53437632; break; + } + + return 0; +} + +int write_summercart_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask) +{ + struct pi_controller* pi = (struct pi_controller*)opaque; + uint32_t addr = address & 0xFFFF; + + if (addr == 0x10) + { + switch (value & mask) + { + case 0xFFFFFFFF: + pi->summercart.unlock = 0; + break; + case 0x5F554E4C: + if (pi->summercart.lock_seq == 0) + { + pi->summercart.lock_seq = 2; + } + break; + case 0x4F434B5F: + if (pi->summercart.lock_seq == 2) + { + pi->summercart.unlock = 1; + pi->summercart.lock_seq = 0; + } + break; + default: + pi->summercart.lock_seq = 0; + break; + } + return 0; + } + + if (!pi->summercart.unlock) return 0; + + switch (addr) + { + case 0x00: + pi->summercart.status = 0; + switch (value & mask) + { + case 'c': + switch (pi->summercart.data0) + { + case 1: + pi->summercart.data1 = pi->summercart.cfg_rom_write; + break; + case 3: + pi->summercart.data1 = 0; + break; + case 6: + pi->summercart.data1 = 0; + break; + default: + pi->summercart.status = 0x40000000; + break; + } + break; + case 'C': + switch (pi->summercart.data0) + { + case 1: + if (pi->summercart.data1) + { + pi->summercart.data1 = pi->summercart.cfg_rom_write; + pi->summercart.cfg_rom_write = 1; + } + else + { + pi->summercart.data1 = pi->summercart.cfg_rom_write; + pi->summercart.cfg_rom_write = 0; + } + break; + default: + pi->summercart.status = 0x40000000; + break; + } + break; + case 'i': + switch (pi->summercart.data1) + { + case 0: + break; + case 1: + pi->summercart.status = summercart_sd_init(pi); + break; + case 4: + pi->summercart.sd_byteswap = 1; + break; + case 5: + pi->summercart.sd_byteswap = 0; + break; + default: + pi->summercart.status = 0x40000000; + break; + } + break; + case 'I': + pi->summercart.sd_sector = pi->summercart.data0; + break; + case 's': + pi->summercart.status = summercart_sd_read(pi); + break; + case 'S': + pi->summercart.status = summercart_sd_write(pi); + break; + default: + pi->summercart.status = 0x40000000; + break; + } + break; + case 0x04: + pi->summercart.data0 = value & mask; + break; + case 0x08: + pi->summercart.data1 = value & mask; + break; + } + + return 0; +} diff --git a/mupen64plus-core/src/pi/summercart.h b/mupen64plus-core/src/pi/summercart.h new file mode 100644 index 000000000..d687ae25c --- /dev/null +++ b/mupen64plus-core/src/pi/summercart.h @@ -0,0 +1,27 @@ +#ifndef M64P_PI_SUMMERCART_H +#define M64P_PI_SUMMERCART_H + +#include +#include + +struct summercart +{ + uint8_t buffer[8192]; + const char *sd_path; + long sd_size; + uint32_t status; + uint32_t data0; + uint32_t data1; + uint32_t sd_sector; + char cfg_rom_write; + char sd_byteswap; + char unlock; + char lock_seq; +}; + +void init_summercart(struct summercart* summercart); +void poweron_summercart(struct summercart* summercart); +int read_summercart_regs(void* opaque, uint32_t address, uint32_t* value); +int write_summercart_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask); + +#endif