123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- /* sd2snes - SD card based universal cartridge for the SNES
- Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
- AVR firmware portion
- Inspired by and based on code from sd2iec, written by Ingo Korb et al.
- See sdcard.c|h, config.h.
- FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
- see ff.c|h.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License only.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- memory.c: RAM operations
- */
- #include "config.h"
- #include "uart.h"
- #include "fpga.h"
- #include "crc.h"
- #include "crc32.h"
- #include "ff.h"
- #include "fileops.h"
- #include "spi.h"
- #include "fpga_spi.h"
- #include "led.h"
- #include "smc.h"
- #include "memory.h"
- #include "snes.h"
- #include "timer.h"
- #include "rle.h"
- #include "diskio.h"
- #include "snesboot.h"
- #include "msu1.h"
- #include <string.h>
- char* hex = "0123456789ABCDEF";
- extern snes_romprops_t romprops;
- void sram_hexdump(uint32_t addr, uint32_t len) {
- static uint8_t buf[16];
- uint32_t ptr;
- for(ptr=0; ptr < len; ptr += 16) {
- sram_readblock((void*)buf, ptr+addr, 16);
- uart_trace(buf, 0, 16, addr);
- }
- }
- void sram_writebyte(uint8_t val, uint32_t addr) {
- printf("WriteB %8Xh @%08lXh\n", val, addr);
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98); /* WRITE */
- FPGA_TX_BYTE(val);
- FPGA_WAIT_RDY();
- FPGA_DESELECT();
- }
- uint8_t sram_readbyte(uint32_t addr) {
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88); /* READ */
- FPGA_WAIT_RDY();
- uint8_t val = FPGA_RX_BYTE();
- FPGA_DESELECT();
- //printf(" ReadB %8Xh @%08lXh\n", val, addr);
- return val;
- }
- void sram_writeshort(uint16_t val, uint32_t addr) {
- printf("WriteS %8Xh @%08lXh\n", val, addr);
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98); /* WRITE */
- FPGA_TX_BYTE(val&0xff);
- FPGA_WAIT_RDY();
- FPGA_TX_BYTE((val>>8)&0xff);
- FPGA_WAIT_RDY();
- FPGA_DESELECT();
- }
- void sram_writelong(uint32_t val, uint32_t addr) {
- printf("WriteL %8lXh @%08lXh\n", val, addr);
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98); /* WRITE */
- FPGA_TX_BYTE(val&0xff);
- FPGA_WAIT_RDY();
- FPGA_TX_BYTE((val>>8)&0xff);
- FPGA_WAIT_RDY();
- FPGA_TX_BYTE((val>>16)&0xff);
- FPGA_WAIT_RDY();
- FPGA_TX_BYTE((val>>24)&0xff);
- FPGA_WAIT_RDY();
- FPGA_DESELECT();
- }
- uint16_t sram_readshort(uint32_t addr) {
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88);
- FPGA_WAIT_RDY();
- uint32_t val = FPGA_RX_BYTE();
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<8);
- FPGA_DESELECT();
- //printf(" ReadS %8lXh @%08lXh\n", val, addr);
- return val;
- }
- uint32_t sram_readlong(uint32_t addr) {
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88);
- FPGA_WAIT_RDY();
- uint32_t val = FPGA_RX_BYTE();
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<8);
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<16);
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<24);
- FPGA_DESELECT();
- //printf(" ReadL %8lXh @%08lXh\n", val, addr);
- return val;
- }
- void sram_readlongblock(uint32_t* buf, uint32_t addr, uint16_t count) {
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88);
- uint16_t i=0;
- while(i<count) {
- FPGA_WAIT_RDY();
- uint32_t val = (uint32_t)FPGA_RX_BYTE()<<24;
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<16);
- FPGA_WAIT_RDY();
- val |= ((uint32_t)FPGA_RX_BYTE()<<8);
- FPGA_WAIT_RDY();
- val |= FPGA_RX_BYTE();
- buf[i++] = val;
- }
- FPGA_DESELECT();
- }
- void sram_readblock(void* buf, uint32_t addr, uint16_t size) {
- uint16_t count=size;
- uint8_t* tgt = buf;
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88); /* READ */
- while(count--) {
- FPGA_WAIT_RDY();
- *(tgt++) = FPGA_RX_BYTE();
- }
- FPGA_DESELECT();
- }
- void sram_readstrn(void* buf, uint32_t addr, uint16_t size) {
- uint16_t count=size;
- uint8_t* tgt = buf;
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88); /* READ */
- while(count--) {
- FPGA_WAIT_RDY();
- if(!(*(tgt++) = FPGA_RX_BYTE())) break;
- }
- FPGA_DESELECT();
- }
- void sram_writeblock(void* buf, uint32_t addr, uint16_t size) {
- printf("WriteZ %08lX -> %08lX [%d]\n", addr, addr+size, size);
- uint16_t count=size;
- uint8_t* src = buf;
- set_mcu_addr(addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98); /* WRITE */
- while(count--) {
- FPGA_TX_BYTE(*src++);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- }
- uint32_t load_rom(uint8_t* filename, uint32_t base_addr, uint8_t flags) {
- UINT bytes_read;
- DWORD filesize, read_size = 0;
- UINT count=0;
- tick_t ticksstart, ticks_total=0;
- ticksstart=getticks();
- printf("%s\n", filename);
- file_open(filename, FA_READ);
- if(file_res) {
- uart_putc('?');
- uart_putc(0x30+file_res);
- return 0;
- }
- filesize = file_handle.fsize;
- smc_id(&romprops);
- file_close();
- /* reconfigure FPGA if necessary */
- if(romprops.fpga_conf) {
- printf("reconfigure FPGA with %s...\n", romprops.fpga_conf);
- fpga_pgm((uint8_t*)romprops.fpga_conf);
- }
- set_mcu_addr(base_addr);
- file_open(filename, FA_READ);
- ff_sd_offload=1;
- sd_offload_tgt=0;
- f_lseek(&file_handle, romprops.offset);
- for(;;) {
- ff_sd_offload=1;
- sd_offload_tgt=0;
- bytes_read = file_read();
- read_size += bytes_read;
- if (file_res || !bytes_read) break;
- if(!(count++ % 512)) {
- uart_putc('.');
- }
- }
- file_close();
- printf("Read %ld [%08lX] bytes...\n", read_size, read_size);
- set_mapper(romprops.mapper_id);
- printf("rom header map: %02x; mapper id: %d\n", romprops.header.map, romprops.mapper_id);
- ticks_total=getticks()-ticksstart;
- printf("%u ticks total\n", ticks_total);
- if(romprops.mapper_id==3) {
- printf("BSX Flash cart image\n");
- printf("attempting to load BSX BIOS /sd2snes/bsxbios.bin...\n");
- load_sram_offload((uint8_t*)"/sd2snes/bsxbios.bin", 0x800000);
- printf("attempting to load BS data file /sd2snes/bsxpage.bin...\n");
- load_sram_offload((uint8_t*)"/sd2snes/bsxpage.bin", 0x900000);
- printf("Type: %02x\n", romprops.header.destcode);
- set_bsx_regs(0xc0, 0x3f);
- uint16_t rombase;
- if(romprops.header.ramsize & 1) {
- rombase = 0xff00;
- // set_bsx_regs(0x36, 0xc9);
- } else {
- rombase = 0x7f00;
- // set_bsx_regs(0x34, 0xcb);
- }
- sram_writebyte(0x33, rombase+0xda);
- sram_writebyte(0x00, rombase+0xd4);
- sram_writebyte(0xfc, rombase+0xd5);
- set_fpga_time(0x0220110301180530LL);
- }
- if(romprops.has_dspx || romprops.has_cx4) {
- printf("DSPx game. Loading firmware image %s...\n", romprops.dsp_fw);
- load_dspx(romprops.dsp_fw, romprops.fpga_features);
- /* fallback to DSP1B firmware if DSP1.bin is not present */
- if(file_res && romprops.dsp_fw == DSPFW_1) {
- load_dspx(DSPFW_1B, romprops.fpga_features);
- }
- if(file_res) {
- snes_menu_errmsg(MENU_ERR_NODSP, (void*)romprops.dsp_fw);
- }
- }
- uint32_t rammask;
- uint32_t rommask;
- while(filesize > (romprops.romsize_bytes + romprops.offset)) {
- romprops.romsize_bytes <<= 1;
- }
- if(romprops.header.ramsize == 0) {
- rammask = 0;
- } else {
- rammask = romprops.ramsize_bytes - 1;
- }
- rommask = romprops.romsize_bytes - 1;
- if (rommask >= SRAM_SAVE_ADDR)
- rommask = SRAM_SAVE_ADDR - 1;
-
- printf("ramsize=%x rammask=%lx\nromsize=%x rommask=%lx\n", romprops.header.ramsize, rammask, romprops.header.romsize, rommask);
- set_saveram_mask(rammask);
- set_rom_mask(rommask);
- readled(0);
- if(flags & LOADROM_WITH_SRAM) {
- if(romprops.ramsize_bytes) {
- strcpy(strrchr((char*)filename, (int)'.'), ".srm");
- printf("SRM file: %s\n", filename);
- load_sram(filename, SRAM_SAVE_ADDR);
- } else {
- printf("No SRAM\n");
- }
- }
- printf("check MSU...");
- if(msu1_check(filename)) {
- romprops.fpga_features |= FEAT_MSU1;
- romprops.has_msu1 = 1;
- } else {
- romprops.has_msu1 = 0;
- }
- printf("done\n");
- romprops.fpga_features |= FEAT_SRTC;
- romprops.fpga_features |= FEAT_213F;
- fpga_set_213f(romprops.region);
- fpga_set_features(romprops.fpga_features);
- if(flags & LOADROM_WITH_RESET) {
- fpga_dspx_reset(1);
- snes_reset_pulse();
- fpga_dspx_reset(0);
- }
- return (uint32_t)filesize;
- }
- uint32_t load_spc(uint8_t* filename, uint32_t spc_data_addr, uint32_t spc_header_addr) {
- DWORD filesize;
- UINT bytes_read;
- uint8_t data;
- UINT j;
- printf("%s\n", filename);
- file_open(filename, FA_READ); /* Open SPC file */
- if(file_res) return 0;
- filesize = file_handle.fsize;
- if (filesize < 65920) { /* At this point, we care about filesize only */
- file_close(); /* since SNES decides if it is an SPC file */
- sram_writebyte(0, spc_header_addr); /* If file is too small, destroy previous SPC header */
- return 0;
- }
- set_mcu_addr(spc_data_addr);
- f_lseek(&file_handle, 0x100L); /* Load 64K data segment */
- for(;;) {
- bytes_read = file_read();
- if (file_res || !bytes_read) break;
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for(j=0; j<bytes_read; j++) {
- FPGA_TX_BYTE(file_buf[j]);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- }
- file_close();
- file_open(filename, FA_READ); /* Reopen SPC file to reset file_getc state*/
- set_mcu_addr(spc_header_addr);
- f_lseek(&file_handle, 0x0L); /* Load 256 bytes header */
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for (j = 0; j < 256; j++) {
- data = file_getc();
- FPGA_TX_BYTE(data);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- file_close();
- file_open(filename, FA_READ); /* Reopen SPC file to reset file_getc state*/
- set_mcu_addr(spc_header_addr+0x100);
- f_lseek(&file_handle, 0x10100L); /* Load 128 DSP registers */
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for (j = 0; j < 128; j++) {
- data = file_getc();
- FPGA_TX_BYTE(data);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- file_close(); /* Done ! */
- /* clear echo buffer to avoid artifacts */
- uint8_t esa = sram_readbyte(spc_header_addr+0x100+0x6d);
- uint8_t edl = sram_readbyte(spc_header_addr+0x100+0x7d);
- uint8_t flg = sram_readbyte(spc_header_addr+0x100+0x6c);
- if(!(flg & 0x20) && (edl & 0x0f)) {
- int echo_start = esa << 8;
- int echo_length = (edl & 0x0f) << 11;
- printf("clearing echo buffer %04x-%04x...\n", echo_start, echo_start+echo_length-1);
- sram_memset(spc_data_addr+echo_start, echo_length, 0);
- }
- return (uint32_t)filesize;
- }
- uint32_t load_sram_offload(uint8_t* filename, uint32_t base_addr) {
- set_mcu_addr(base_addr);
- UINT bytes_read;
- DWORD filesize;
- file_open(filename, FA_READ);
- filesize = file_handle.fsize;
- if(file_res) return 0;
- for(;;) {
- ff_sd_offload=1;
- sd_offload_tgt=0;
- bytes_read = file_read();
- if (file_res || !bytes_read) break;
- }
- file_close();
- return (uint32_t)filesize;
- }
- uint32_t load_sram(uint8_t* filename, uint32_t base_addr) {
- set_mcu_addr(base_addr);
- UINT bytes_read;
- DWORD filesize;
- file_open(filename, FA_READ);
- filesize = file_handle.fsize;
- if(file_res) {
- printf("load_sram: could not open %s, res=%d\n", filename, file_res);
- return 0;
- }
- for(;;) {
- bytes_read = file_read();
- if (file_res || !bytes_read) break;
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for(int j=0; j<bytes_read; j++) {
- FPGA_TX_BYTE(file_buf[j]);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- }
- file_close();
- return (uint32_t)filesize;
- }
- uint32_t load_sram_rle(uint8_t* filename, uint32_t base_addr) {
- uint8_t data;
- set_mcu_addr(base_addr);
- DWORD filesize;
- file_open(filename, FA_READ);
- filesize = file_handle.fsize;
- if(file_res) return 0;
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for(;;) {
- data = rle_file_getc();
- if (file_res || file_status) break;
- FPGA_TX_BYTE(data);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- file_close();
- return (uint32_t)filesize;
- }
- uint32_t load_bootrle(uint32_t base_addr) {
- uint8_t data;
- set_mcu_addr(base_addr);
- DWORD filesize = 0;
- rle_mem_init(bootrle, sizeof(bootrle));
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for(;;) {
- data = rle_mem_getc();
- if(rle_state) break;
- FPGA_TX_BYTE(data);
- FPGA_WAIT_RDY();
- filesize++;
- }
- FPGA_DESELECT();
- return (uint32_t)filesize;
- }
- void save_sram(uint8_t* filename, uint32_t sram_size, uint32_t base_addr) {
- uint32_t count = 0;
- //uint32_t num = 0;
- FPGA_DESELECT();
- file_open(filename, FA_CREATE_ALWAYS | FA_WRITE);
- if(file_res) {
- uart_putc(0x30+file_res);
- }
- while(count<sram_size) {
- set_mcu_addr(base_addr+count);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88); /* read */
- for(int j=0; j<sizeof(file_buf); j++) {
- FPGA_WAIT_RDY();
- file_buf[j] = FPGA_RX_BYTE();
- count++;
- }
- FPGA_DESELECT();
- /*num = */file_write();
- if(file_res) {
- uart_putc(0x30+file_res);
- }
- }
- file_close();
- }
- uint32_t calc_sram_crc(uint32_t base_addr, uint32_t size) {
- uint8_t data;
- uint32_t count;
- uint32_t crc;
- crc=0;
- crc_valid=1;
- set_mcu_addr(base_addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88);
- for(count=0; count<size; count++) {
- FPGA_WAIT_RDY();
- data = FPGA_RX_BYTE();
- if(get_snes_reset()) {
- crc_valid = 0;
- break;
- }
- crc += crc32_update(crc, data);
- }
- FPGA_DESELECT();
- return crc;
- }
- uint8_t sram_reliable() {
- uint16_t score=0;
- uint32_t val;
- uint8_t result = 0;
- /*while(score<SRAM_RELIABILITY_SCORE) {
- if(sram_readlong(SRAM_SCRATCHPAD)==val) {
- score++;
- } else {
- set_pwr_led(0);
- score=0;
- }
- } */
- for(uint16_t i = 0; i < SRAM_RELIABILITY_SCORE; i++) {
- val=sram_readlong(SRAM_SCRATCHPAD);
- if(val==0x12345678) {
- score++;
- } //else {
- //printf("i=%d val=%08lX\n", i, val);
- //}
- }
- if(score<SRAM_RELIABILITY_SCORE) {
- result = 0;
- /* dprintf("score=%d\n", score); */
- } else {
- result = 1;
- }
- rdyled(result);
- return result;
- }
- void sram_memset(uint32_t base_addr, uint32_t len, uint8_t val) {
- set_mcu_addr(base_addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x98);
- for(uint32_t i=0; i<len; i++) {
- FPGA_TX_BYTE(val);
- FPGA_WAIT_RDY();
- }
- FPGA_DESELECT();
- }
- uint64_t sram_gettime(uint32_t base_addr) {
- set_mcu_addr(base_addr);
- FPGA_SELECT();
- FPGA_TX_BYTE(0x88);
- uint8_t data;
- uint64_t result = 0LL;
- /* 1st nibble is the century - 10 (binary)
- 4th nibble is the month (binary)
- all other fields are BCD */
- for(int i=0; i<12; i++) {
- FPGA_WAIT_RDY();
- data = FPGA_RX_BYTE();
- data &= 0xf;
- switch(i) {
- case 0:
- result = (result << 4) | ((data / 10) + 1);
- result = (result << 4) | (data % 10);
- break;
- case 3:
- result = (result << 4) | ((data / 10));
- result = (result << 4) | (data % 10);
- break;
- default:
- result = (result << 4) | data;
- }
- }
- FPGA_DESELECT();
- return result & 0x00ffffffffffffffLL;
- }
- void load_dspx(const uint8_t *filename, uint8_t coretype) {
- UINT bytes_read;
- //DWORD filesize;
- uint16_t word_cnt;
- uint8_t wordsize_cnt = 0;
- uint16_t sector_remaining = 0;
- uint16_t sector_cnt = 0;
- uint16_t pgmsize = 0;
- uint16_t datsize = 0;
- uint32_t pgmdata = 0;
- uint16_t datdata = 0;
- if(coretype & FEAT_ST0010) {
- datsize = 1536;
- pgmsize = 2048;
- } else if (coretype & FEAT_DSPX) {
- datsize = 1024;
- pgmsize = 2048;
- } else if (coretype & FEAT_CX4) {
- datsize = 0;
- pgmsize = 1024; /* Cx4 data ROM */
- } else {
- printf("load_dspx: unknown core (%02x)!\n", coretype);
- }
- file_open((uint8_t*)filename, FA_READ);
- /*filesize = file_handle.fsize;*/
- if(file_res) {
- printf("Could not read %s: error %d\n", filename, file_res);
- return;
- }
- fpga_reset_dspx_addr();
- for(word_cnt = 0; word_cnt < pgmsize;) {
- if(!sector_remaining) {
- bytes_read = file_read();
- sector_remaining = bytes_read;
- sector_cnt = 0;
- }
- pgmdata = (pgmdata << 8) | file_buf[sector_cnt];
- sector_cnt++;
- wordsize_cnt++;
- sector_remaining--;
- if(wordsize_cnt == 3){
- wordsize_cnt = 0;
- word_cnt++;
- fpga_write_dspx_pgm(pgmdata);
- }
- }
- wordsize_cnt = 0;
- if(coretype & FEAT_ST0010) {
- file_seek(0xc000);
- sector_remaining = 0;
- }
- for(word_cnt = 0; word_cnt < datsize;) {
- if(!sector_remaining) {
- bytes_read = file_read();
- sector_remaining = bytes_read;
- sector_cnt = 0;
- }
- datdata = (datdata << 8) | file_buf[sector_cnt];
- sector_cnt++;
- wordsize_cnt++;
- sector_remaining--;
- if(wordsize_cnt == 2){
- wordsize_cnt = 0;
- word_cnt++;
- fpga_write_dspx_dat(datdata);
- }
- }
- fpga_reset_dspx_addr();
- file_close();
- }
|