diff --git a/src/bootldr/config.h b/src/bootldr/config.h index daef0d4..a53859c 100644 --- a/src/bootldr/config.h +++ b/src/bootldr/config.h @@ -5,6 +5,8 @@ // #define DEBUG_IRQ // #define DEBUG_MSU1 +// #define DEBUG_UART + #ifdef DEBUG_UART #define DBG_UART #else diff --git a/src/bootldr/iap.c b/src/bootldr/iap.c index 5df5e2d..3fce3e9 100644 --- a/src/bootldr/iap.c +++ b/src/bootldr/iap.c @@ -151,6 +151,7 @@ FLASH_RES flash_file(uint8_t *filename) { uint32_t res; + writeled(1); DBG_BL printf("erasing flash...\n"); if((res = iap_prepare_for_write(FW_START / 0x1000, FLASH_SECTORS)) != CMD_SUCCESS) { DBG_BL printf("error %ld while preparing for erase\n", res); @@ -172,7 +173,6 @@ FLASH_RES flash_file(uint8_t *filename) { : (flash_addr >> 12); DBG_BL printf("current_sec=%d flash_addr=%08lx\n", current_sec, flash_addr); DBG_UART uart_putc('.'); - toggle_rdy_led(); if(current_sec < (FW_START / 0x1000)) return ERR_FLASH; if((res = iap_prepare_for_write(current_sec, current_sec)) != CMD_SUCCESS) { DBG_BL printf("error %ld while preparing sector %d for write\n", res, current_sec); @@ -188,6 +188,7 @@ FLASH_RES flash_file(uint8_t *filename) { DBG_UART uart_putc('X'); return ERR_FILECHK; } + writeled(0); } else { DBG_UART uart_putc('n'); DBG_BL printf("flash content is ok, no version mismatch, no forced upgrade. No need to flash\n"); diff --git a/src/bootldr/main.c b/src/bootldr/main.c index 604b584..438604e 100644 --- a/src/bootldr/main.c +++ b/src/bootldr/main.c @@ -45,7 +45,7 @@ int main(void) { DBG_UART uart_init(); led_init(); readled(0); - rdyled(0); + rdyled(1); writeled(0); /* do this last because the peripheral init()s change PCLK dividers */ clock_init(); @@ -63,9 +63,11 @@ DBG_BL printf("PCONP=%lx\n", LPC_SC->PCONP); FLASH_RES res = flash_file((uint8_t*)"/sd2snes/firmware.img"); if(res == ERR_FLASHPREP || res == ERR_FLASHERASE || res == ERR_FLASH) { + rdyled(0); writeled(1); } if(res == ERR_FILEHD || res == ERR_FILECHK) { + rdyled(0); readled(1); } DBG_BL printf("flash result = %d\n", res); diff --git a/src/flash.script b/src/flash.script index 916fd81..969235c 100644 --- a/src/flash.script +++ b/src/flash.script @@ -6,7 +6,7 @@ #flash info 0 reset init -flash write_image erase unlock obj/firmware.img 8192 +flash write_image erase unlock obj/firmware.img 12288 reset run shutdown diff --git a/src/fpga_spi.c b/src/fpga_spi.c index 83a344a..210de95 100644 --- a/src/fpga_spi.c +++ b/src/fpga_spi.c @@ -74,6 +74,11 @@ eg 0x20111210094816 is 2011-12-10, 9:48:16 E6 ssrr set/reset BS-X status register [7:0] E7 - reset SRTC state + E8 - reset DSP program and data ROM write pointers + E9 hhmmllxxxx write+incr. DSP program ROM (xxxx=dummy writes) + EA hhllxxxx write+incr. DSP data ROM (xxxx=dummy writes) + EB - put DSP into reset + EC - release DSP from reset F0 - receive test token (to see if FPGA is alive) F1 - receive status (16bit, MSB first), see below @@ -345,3 +350,39 @@ void fpga_reset_srtc_state() { FPGA_TX_BYTE(0x00); FPGA_DESELECT(); } + +void fpga_reset_dspx_addr() { + FPGA_SELECT(); + FPGA_TX_BYTE(0xe8); + FPGA_TX_BYTE(0x00); + FPGA_TX_BYTE(0x00); + FPGA_DESELECT(); +} + +void fpga_write_dspx_pgm(uint32_t data) { + FPGA_SELECT(); + FPGA_TX_BYTE(0xe9); + FPGA_TX_BYTE((data>>16)&0xff); + FPGA_TX_BYTE((data>>8)&0xff); + FPGA_TX_BYTE((data)&0xff); + FPGA_TX_BYTE(0x00); + FPGA_TX_BYTE(0x00); + FPGA_DESELECT(); +} + +void fpga_write_dspx_dat(uint16_t data) { + FPGA_SELECT(); + FPGA_TX_BYTE(0xea); + FPGA_TX_BYTE((data>>8)&0xff); + FPGA_TX_BYTE((data)&0xff); + FPGA_TX_BYTE(0x00); + FPGA_TX_BYTE(0x00); + FPGA_DESELECT(); +} + +void fpga_dspx_reset(uint8_t reset) { + FPGA_SELECT(); + FPGA_TX_BYTE(reset ? 0xeb : 0xec); + FPGA_TX_BYTE(0x00); + FPGA_DESELECT(); +} diff --git a/src/fpga_spi.h b/src/fpga_spi.h index 69fdaaf..fc06d5b 100644 --- a/src/fpga_spi.h +++ b/src/fpga_spi.h @@ -75,5 +75,8 @@ uint32_t get_snes_sysclk(void); void set_bsx_regs(uint8_t set, uint8_t reset); void set_fpga_time(uint64_t time); void fpga_reset_srtc_state(void); - +void fpga_reset_dspx_addr(void); +void fpga_write_dspx_pgm(uint32_t data); +void fpga_write_dspx_dat(uint16_t data); +void fpga_dspx_reset(uint8_t reset); #endif diff --git a/src/led.c b/src/led.c index f6ac11a..2a8a1c6 100644 --- a/src/led.c +++ b/src/led.c @@ -4,6 +4,7 @@ #include "bits.h" #include "timer.h" #include "led.h" +#include "cli.h" static uint8_t led_bright[16]={255,253,252,251,249,247,244,239,232,223,210,191,165,127,74,0}; @@ -92,6 +93,7 @@ void led_panic() { LPC_GPIO2->FIODIR &= ~(BV(4) | BV(5)); LPC_GPIO1->FIODIR &= ~BV(23); delay_ms(350); + cli_entrycheck(); } } diff --git a/src/lpc1754.ld b/src/lpc1754.ld index a470fba..69ac4e6 100644 --- a/src/lpc1754.ld +++ b/src/lpc1754.ld @@ -10,7 +10,7 @@ ENTRY(_start) MEMORY { - flash (rx) : ORIGIN = 0x00002100, LENGTH = 0x1df00 /* leave room for bootldr + metadata */ + flash (rx) : ORIGIN = 0x00003100, LENGTH = 0x1cf00 /* leave room for bootldr + metadata */ ram (rwx) : ORIGIN = 0x10000000, LENGTH = 0x04000 ahbram (rwx) : ORIGIN = 0x2007C000, LENGTH = 0x04000 } diff --git a/src/main.c b/src/main.c index d1cae23..26f6776 100644 --- a/src/main.c +++ b/src/main.c @@ -131,7 +131,7 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); snes_bootprint(" Loading ... \0"); if(get_cic_state() == CIC_PAIR) { printf("PAIR MODE ENGAGED!\n"); - cic_pair(CIC_PAL, CIC_NTSC); + cic_pair(CIC_NTSC, CIC_NTSC); } rdyled(1); readled(0); @@ -189,6 +189,7 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); /* load menu */ fpga_pgm((uint8_t*)"/sd2snes/fpga_base.bit"); + fpga_dspx_reset(1); uart_putc('('); load_rom((uint8_t*)"/sd2snes/menu.bin", SRAM_MENU_ADDR); /* force memory size + mapper */ @@ -224,7 +225,7 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); uint32_t filesize=0; sram_writebyte(32, SRAM_CMD_ADDR); printf("test sram\n"); - while(!sram_reliable()); + while(!sram_reliable()) cli_entrycheck(); printf("ok\n"); sram_hexdump(SRAM_DIR_ADDR, 0x300); //while(1) { @@ -237,13 +238,14 @@ sram_hexdump(SRAM_DIR_ADDR, 0x300); cmd=menu_main_loop(); // cmd = 1; printf("cmd: %d\n", cmd); - sleep_ms(50); + sleep_ms(500); uart_putc('-'); switch(cmd) { case SNES_CMD_LOADROM: get_selected_name(file_lfn); set_mcu_ovr(1); -// strcpy((char*)file_lfn, "/bs3-1.smc"); +// strcpy((char*)file_lfn, "/mon.smc"); + printf("Selected name: %s\n", file_lfn); filesize = load_rom(file_lfn, SRAM_ROM_ADDR); if(romprops.ramsize_bytes) { @@ -257,6 +259,7 @@ sram_hexdump(SRAM_DIR_ADDR, 0x300); snes_reset(1); delay_ms(10); snes_reset(0); + fpga_dspx_reset(0); break; case SNES_CMD_SETRTC: /* get time from RAM */ diff --git a/src/memory.c b/src/memory.c index cf9fd91..e0eaae1 100644 --- a/src/memory.c +++ b/src/memory.c @@ -229,6 +229,10 @@ ticks_total=getticks()-ticksstart; sram_writebyte(0xfc, rombase+0xd5); set_fpga_time(0x0220110301180530LL); } + if(romprops.mapper_id == 4 || romprops.mapper_id == 5) { + printf("DSPx game. Loading firmware image %s...\n", romprops.necdsp_fw); + load_dspx(romprops.necdsp_fw); + } uint32_t rammask; uint32_t rommask; @@ -448,3 +452,67 @@ uint64_t sram_gettime(uint32_t base_addr) { FPGA_DESELECT(); return result & 0x00ffffffffffffffLL; } + +void load_dspx(const uint8_t *filename) { + 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 = 2048; + uint16_t datsize = 1024; + uint32_t pgmdata = 0; + uint16_t datdata = 0; + 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); + printf("%06lx ", pgmdata&0xffffff); + } + } + + wordsize_cnt = 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); + printf("%04x ",datdata&0xffff); + } + } + + fpga_reset_dspx_addr(); + + file_close(); + +} diff --git a/src/memory.h b/src/memory.h index 2d10125..b0327c4 100644 --- a/src/memory.h +++ b/src/memory.h @@ -49,6 +49,7 @@ uint32_t load_sram(uint8_t* filename, uint32_t base_addr); uint32_t load_sram_offload(uint8_t* filename, uint32_t base_addr); uint32_t load_sram_rle(uint8_t* filename, uint32_t base_addr); uint32_t load_bootrle(uint32_t base_addr); +void load_dspx(const uint8_t* filename); void sram_hexdump(uint32_t addr, uint32_t len); uint8_t sram_readbyte(uint32_t addr); uint16_t sram_readshort(uint32_t addr); diff --git a/src/smc.c b/src/smc.c index 7abc95d..2efd898 100644 --- a/src/smc.c +++ b/src/smc.c @@ -28,9 +28,16 @@ #include "config.h" #include "uart.h" #include "smc.h" +#include "string.h" snes_romprops_t romprops; +const uint8_t* DSPFW_1 = (uint8_t*)"/sd2snes/dsp1.bin"; +const uint8_t* DSPFW_1B = (uint8_t*)"/sd2snes/dsp1b.bin"; +const uint8_t* DSPFW_2 = (uint8_t*)"/sd2snes/dsp2.bin"; +const uint8_t* DSPFW_3 = (uint8_t*)"/sd2snes/dsp3.bin"; +const uint8_t* DSPFW_4 = (uint8_t*)"/sd2snes/dsp4.bin"; + uint32_t hdr_addr[6] = {0xffb0, 0x101b0, 0x7fb0, 0x81b0, 0x40ffb0, 0x4101b0}; uint8_t countAllASCII(uint8_t* data, int size) { uint8_t res = 0; @@ -77,7 +84,6 @@ uint8_t checkChksum(uint16_t cchk, uint16_t chk) { void smc_id(snes_romprops_t* props) { uint8_t score, maxscore=1, score_idx=2; /* assume LoROM */ - snes_header_t* header = &(props->header); for(uint8_t num = 0; num < 6; num++) { @@ -122,7 +128,7 @@ void smc_id(snes_romprops_t* props) { const uint8_t n15 = header->map; if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) { - if(header->fixed_33 == 0x33 || header->fixed_33 == 0xff) { + if(header->licensee == 0x33 || header->licensee == 0xff) { props->mapper_id = 0; /*XXX do this properly */ props->ramsize_bytes = 0x8000; @@ -135,15 +141,44 @@ void smc_id(snes_romprops_t* props) { } } switch(header->map & 0xef) { + case 0x21: /* HiROM */ - props->mapper_id = 0; + if(header->map == 0x31 && (header->carttype == 0x03 || header->carttype == 0x05)) { + props->mapper_id = 4; /* DSPx HiROM */ + props->necdsp_fw = DSPFW_1B; + } else { + props->mapper_id = 0; /* regular HiROM */ + } break; + case 0x20: /* LoROM */ - props->mapper_id = 1; + if ((header->map == 0x20 && header->carttype == 0x03) || + (header->map == 0x30 && header->carttype == 0x05 && header->licensee != 0xb2)) { + props->mapper_id = 5; + // Pilotwings uses DSP1 instead of DSP1B + if(!memcmp(header->name, "PILOTWINGS", 10)) { + props->necdsp_fw = DSPFW_1; + } else { + props->necdsp_fw = DSPFW_1B; + } + } else if (header->map == 0x20 && header->carttype == 0x05) { + props->mapper_id = 5; /* DSPx LoROM */ + props->necdsp_fw = DSPFW_2; + } else if (header->map == 0x30 && header->carttype == 0x05 && header->licensee == 0xb2) { + props->mapper_id = 5; /* DSPx LoROM */ + props->necdsp_fw = DSPFW_3; + } else if (header->map == 0x30 && header->carttype == 0x03) { + props->mapper_id = 5; /* DSPx LoROM */ + props->necdsp_fw = DSPFW_4; + } else { + props->mapper_id = 1; /* regular LoROM */ + } break; + case 0x25: /* ExHiROM */ props->mapper_id = 2; break; + case 0x22: /* ExLoROM */ if(file_handle.fsize > 0x400200) { props->mapper_id = 6; /* SO96 */ @@ -151,6 +186,7 @@ void smc_id(snes_romprops_t* props) { props->mapper_id = 4; } break; + default: /* invalid/unsupported mapper, use header location */ switch(score_idx) { case 0: @@ -194,7 +230,7 @@ uint8_t smc_headerscore(snes_header_t* header) { score += countAllASCII(header->gamecode, sizeof(header->gamecode)); score += isFixed(header->fixed_00, sizeof(header->fixed_00), 0x00); score += countAllJISX0201(header->name, sizeof(header->name)); - score += 3*isFixed(&header->fixed_33, sizeof(header->fixed_33), 0x33); + score += 3*isFixed(&header->licensee, sizeof(header->licensee), 0x33); score += checkChksum(header->cchk, header->chk); return score; } diff --git a/src/smc.h b/src/smc.h index 7893a04..ee516d6 100644 --- a/src/smc.h +++ b/src/smc.h @@ -40,7 +40,7 @@ typedef struct _snes_header { uint8_t romsize; /* 0xD7 */ uint8_t ramsize; /* 0xD8 */ uint8_t destcode; /* 0xD9 */ - uint8_t fixed_33; /* 0xDA */ + uint8_t licensee; /* 0xDA */ uint8_t ver; /* 0xDB */ uint16_t cchk; /* 0xDC */ uint16_t chk; /* 0xDE */ @@ -53,6 +53,7 @@ typedef struct _snes_romprops { uint32_t expramsize_bytes; /* ExpRAM size in bytes */ uint32_t ramsize_bytes; /* CartRAM size in bytes */ uint32_t romsize_bytes; /* ROM size in bytes (rounded up) */ + const uint8_t* necdsp_fw; /* NEC DSP ROM filename */ snes_header_t header; /* original header from ROM image */ } snes_romprops_t; diff --git a/src/snes.c b/src/snes.c index 8b05970..99014aa 100644 --- a/src/snes.c +++ b/src/snes.c @@ -60,6 +60,7 @@ void prepare_reset() { snes_reset(0); while(get_snes_reset()); snes_reset(1); + fpga_dspx_reset(1); delay_ms(200); }