#include #include #include "config.h" #include "obj/autoconf.h" #include "clock.h" #include "uart.h" #include "bits.h" #include "power.h" #include "timer.h" #include "ff.h" #include "diskio.h" #include "spi.h" #include "fileops.h" #include "fpga.h" #include "fpga_spi.h" #include "filetypes.h" #include "memory.h" #include "snes.h" #include "led.h" #include "sort.h" #include "cic.h" #include "tests.h" #include "cli.h" #include "sdnative.h" #include "crc.h" #include "smc.h" #include "msu1.h" #include "rtc.h" #include "sysinfo.h" #include "cfg.h" #define EMC0TOGGLE (3<<4) #define MR0R (1<<1) int i; int sd_offload = 0, ff_sd_offload = 0, sd_offload_tgt = 0; int sd_offload_partial = 0; int sd_offload_start_mid = 0; int sd_offload_end_mid = 0; uint16_t sd_offload_partial_start = 0; uint16_t sd_offload_partial_end = 0; volatile enum diskstates disk_state; extern volatile tick_t ticks; extern snes_romprops_t romprops; extern volatile int reset_changed; extern volatile cfg_t CFG; enum system_states { SYS_RTC_STATUS = 0, SYS_LAST_STATUS = 1 }; int main( void ) { uint8_t card_go = 0; uint32_t saved_dir_id; uint32_t mem_dir_id; uint32_t mem_magic; uint8_t cmd = 0; uint64_t btime = 0; uint32_t filesize = 0; uint8_t snes_reset_prev = 0, snes_reset_now = 0, snes_reset_state = 0; uint16_t reset_count = 0; LPC_GPIO2->FIODIR = BV( 4 ) | BV( 5 ); LPC_GPIO1->FIODIR = BV( 23 ) | BV( SNES_CIC_PAIR_BIT ); BITBAND( SNES_CIC_PAIR_REG->FIOSET, SNES_CIC_PAIR_BIT ) = 1; LPC_GPIO0->FIODIR = BV( 16 ); /* connect UART3 on P0[25:26] + SSP0 on P0[15:18] + MAT3.0 on P0[10] */ LPC_PINCON->PINSEL1 = BV( 18 ) | BV( 19 ) | BV( 20 ) | BV( 21 ) /* UART3 */ | BV( 3 ) | BV( 5 ); /* SSP0 (FPGA) except SS */ LPC_PINCON->PINSEL0 = BV( 31 ); /* SSP0 */ /* | BV(13) | BV(15) | BV(17) | BV(19) SSP1 (SD) */ /* pull-down CIC data lines */ LPC_PINCON->PINMODE0 = BV( 0 ) | BV( 1 ) | BV( 2 ) | BV( 3 ); clock_disconnect(); /* Disable clock */ snes_init(); /* Set SNES Reset */ power_init(); /* Enable power block of LPC */ timer_init(); /* Enable internal timer */ uart_init(); /* Configure UART */ fpga_spi_init(); /* Configure FPGA_SPI IOs */ spi_preinit(); /* Initialise SPI IO */ led_init(); /* Initialise LEDs IO */ /* do this last because the peripheral init()s change PCLK dividers */ clock_init(); /* Output FPGA clock */ LPC_PINCON->PINSEL0 |= BV( 20 ) | BV( 21 ); /* MAT3.0 (FPGA clock) */ led_pwm(); /* Enabke PWM on LED (even if not used...) */ sdn_init(); /* SD init */ /* Print banner */ printf( "\n\nsd2snes mk.2\n============\nfw ver.: " CONFIG_VERSION "\ncpu clock: %d Hz\n", CONFIG_CPU_FREQUENCY ); /* Init file manager */ file_init(); /* */ cic_init( 0 ); /* setup timer (fpga clk) */ LPC_TIM3->TCR = 2; LPC_TIM3->CTCR = 0; LPC_TIM3->PR = 0; LPC_TIM3->EMR = EMC0TOGGLE; LPC_TIM3->MCR = MR0R; LPC_TIM3->MR0 = 1; LPC_TIM3->TCR = 1; fpga_init(); fpga_rompgm(); sram_writebyte( 0, SRAM_CMD_ADDR ); while ( 1 ) /* Main loop */ { if ( disk_state == DISK_CHANGED ) { sdn_init(); /* Reinit SD card */ newcard = 1; } load_bootrle( SRAM_MENU_ADDR ); set_saveram_mask( 0xffff ); set_rom_mask( 0x3fffff ); set_mapper( 0x7 ); snes_reset( 0 ); while ( get_cic_state() == CIC_FAIL ) { rdyled( 0 ); readled( 0 ); writeled( 0 ); delay_ms( 500 ); rdyled( 1 ); readled( 1 ); writeled( 1 ); delay_ms( 500 ); } /* Wait for valid card inserted */ card_go = 0; while ( !card_go ) { if ( disk_status( 0 ) & ( STA_NOINIT | STA_NODISK ) ) { snes_bootprint( " No SD Card found! \0" ); while ( disk_status( 0 ) & ( STA_NOINIT | STA_NODISK ) ); delay_ms( 200 ); } file_open( ( uint8_t * )"/sd2snes/menu.bin", FA_READ ); if ( file_status != FILE_OK ) { snes_bootprint( " /sd2snes/menu.bin not found! \0" ); while ( disk_status( 0 ) == RES_OK ); } else { /* Card found ! */ card_go = 1; } file_close(); } snes_bootprint( " Loading ... \0" ); if ( get_cic_state() == CIC_PAIR ) { printf( "PAIR MODE ENGAGED!\n" ); cic_pair( CIC_NTSC, CIC_NTSC ); } rdyled( 1 ); readled( 0 ); writeled( 0 ); /* Load user config */ cfg_load(); cfg_save(); sram_writebyte( cfg_is_last_game_valid(), SRAM_STATUS_ADDR + SYS_LAST_STATUS ); cfg_get_last_game( file_lfn ); sram_writeblock( strrchr( ( const char * )file_lfn, '/' ) + 1, SRAM_LASTGAME_ADDR, 256 ); *fs_path = 0; get_db_id( &saved_dir_id ); mem_dir_id = sram_readlong( SRAM_DIRID ); mem_magic = sram_readlong( SRAM_SCRATCHPAD ); printf( "mem_magic=%lx mem_dir_id=%lx saved_dir_id=%lx\n", mem_magic, mem_dir_id, saved_dir_id ); if ( ( mem_magic != 0x12345678 ) || ( mem_dir_id != saved_dir_id ) || ( newcard ) ) { newcard = 0; /* generate fs footprint (interesting files only) */ uint32_t curr_dir_id = scan_dir( fs_path, NULL, 0, 0 ); printf( "curr dir id = %lx\n", curr_dir_id ); /* files changed or no database found? */ if ( ( get_db_id( &saved_dir_id ) != FR_OK ) || saved_dir_id != curr_dir_id ) { uint32_t endaddr, direndaddr; /* rebuild database */ printf( "saved dir id = %lx\n", saved_dir_id ); printf( "rebuilding database..." ); snes_bootprint( " rebuilding database ... \0" ); curr_dir_id = scan_dir( fs_path, NULL, 1, 0 ); sram_writeblock( &curr_dir_id, SRAM_DB_ADDR, 4 ); sram_readblock( &endaddr, SRAM_DB_ADDR + 4, 4 ); sram_readblock( &direndaddr, SRAM_DB_ADDR + 8, 4 ); printf( "%lx %lx\n", endaddr, direndaddr ); printf( "sorting database..." ); snes_bootprint( " sorting database ... \0" ); sort_all_dir( direndaddr ); printf( "done\n" ); snes_bootprint( " saving database ... \0" ); save_sram( ( uint8_t * )"/sd2snes/sd2snes.db", endaddr - SRAM_DB_ADDR, SRAM_DB_ADDR ); save_sram( ( uint8_t * )"/sd2snes/sd2snes.dir", direndaddr - ( SRAM_DIR_ADDR ), SRAM_DIR_ADDR ); fpga_pgm( ( uint8_t * )"/sd2snes/fpga_base.bit" ); printf( "done\n" ); } else { printf( "saved dir id = %lx\n", saved_dir_id ); printf( "different card, consistent db, loading db...\n" ); fpga_pgm( ( uint8_t * )"/sd2snes/fpga_base.bit" ); load_sram_offload( ( uint8_t * )"/sd2snes/sd2snes.db", SRAM_DB_ADDR ); load_sram_offload( ( uint8_t * )"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR ); } sram_writelong( curr_dir_id, SRAM_DIRID ); sram_writelong( 0x12345678, SRAM_SCRATCHPAD ); } else { snes_bootprint( " same card, loading db... \n" ); fpga_pgm( ( uint8_t * )"/sd2snes/fpga_base.bit" ); load_sram_offload( ( uint8_t * )"/sd2snes/sd2snes.db", SRAM_DB_ADDR ); load_sram_offload( ( uint8_t * )"/sd2snes/sd2snes.dir", SRAM_DIR_ADDR ); } /* cli_loop(); */ /* load menu */ fpga_dspx_reset( 1 ); uart_putc( '(' ); uart_putcrlf(); load_rom( ( uint8_t * )"/sd2snes/menu.bin", SRAM_MENU_ADDR, 0 ); /* force memory size + mapper */ set_rom_mask( 0x3fffff ); set_mapper( 0x7 ); uart_putc( ')' ); uart_putcrlf(); sram_writebyte( 0, SRAM_CMD_ADDR ); snes_bootprint( " same card, loading db... \n" ); if ( ( rtc_state = rtc_isvalid() ) != RTC_OK ) { printf( "RTC invalid!\n" ); sram_writebyte( 0xff, SRAM_STATUS_ADDR + SYS_RTC_STATUS ); set_bcdtime( 0x20120701000000LL ); set_fpga_time( 0x20120701000000LL ); invalidate_rtc(); } else { printf( "RTC valid!\n" ); sram_writebyte( 0x00, SRAM_STATUS_ADDR + SYS_RTC_STATUS ); set_fpga_time( get_bcdtime() ); } sram_memset( SRAM_SYSINFO_ADDR, 13 * 40, 0x20 ); printf( "SNES GO!\n" ); snes_reset( 1 ); fpga_reset_srtc_state(); delay_ms( SNES_RESET_PULSELEN_MS ); sram_writebyte( 32, SRAM_CMD_ADDR ); snes_reset( 0 ); cmd = 0; btime = 0; filesize = 0; printf( "test sram... " ); while ( !sram_reliable() ) { cli_entrycheck(); } printf( "ok\nWaiting command from menu...\n" ); //while(1) { // delay_ms(1000); // printf("Estimated SNES master clock: %ld Hz\n", get_snes_sysclk()); //} //sram_hexdump(SRAM_DB_ADDR, 0x200); //sram_hexdump(SRAM_MENU_ADDR, 0x400); while ( !cmd ) { cmd = menu_main_loop(); printf( "cmd: %d\n", cmd ); switch ( cmd ) { case SNES_CMD_LOADROM: get_selected_name( file_lfn ); printf( "Selected name: %s\n", file_lfn ); cfg_save_last_game( file_lfn ); cfg_set_last_game_valid( 1 ); cfg_save(); filesize = load_rom( file_lfn, SRAM_ROM_ADDR, LOADROM_WITH_SRAM | LOADROM_WITH_RESET ); printf( "Filesize = %lu\n", filesize ); break; case SNES_CMD_SETRTC: /* get time from RAM */ btime = sram_gettime( SRAM_PARAM_ADDR ); /* set RTC */ set_bcdtime( btime ); set_fpga_time( btime ); cmd = 0; /* stay in menu loop */ break; case SNES_CMD_SYSINFO: /* go to sysinfo loop */ sysinfo_loop(); cmd = 0; /* stay in menu loop */ break; case SNES_CMD_LOADSPC: /* load SPC file */ get_selected_name( file_lfn ); printf( "Selected name: %s\n", file_lfn ); filesize = load_spc( file_lfn, SRAM_SPC_DATA_ADDR, SRAM_SPC_HEADER_ADDR ); cmd = 0; /* stay in menu loop */ break; case SNES_CMD_RESET: /* process RESET request from SNES */ printf( "RESET requested by SNES\n" ); snes_reset_pulse(); cmd = 0; /* stay in menu loop */ break; case SNES_CMD_LOADLAST: cfg_get_last_game( file_lfn ); printf( "Selected name: %s\n", file_lfn ); filesize = load_rom( file_lfn, SRAM_ROM_ADDR, LOADROM_WITH_SRAM | LOADROM_WITH_RESET ); break; default: printf( "unknown cmd: %d\n", cmd ); cmd = 0; /* unknown cmd: stay in loop */ break; } } printf( "loaded %lu bytes\n", filesize ); printf( "cmd was %x, going to snes main loop\n", cmd ); if ( romprops.has_msu1 ) { while ( !msu1_loop() ); prepare_reset(); continue; } cmd = 0; snes_reset_prev = 0; snes_reset_now = 0; snes_reset_state = 0; reset_count = 0; while ( fpga_test() == FPGA_TEST_TOKEN ) { cli_entrycheck(); sleep_ms( 250 ); sram_reliable(); printf( "%s ", get_cic_statename( get_cic_state() ) ); if ( reset_changed ) { printf( "reset\n" ); reset_changed = 0; fpga_reset_srtc_state(); } snes_reset_now = get_snes_reset(); if ( snes_reset_now ) { if ( !snes_reset_prev ) { printf( "RESET BUTTON DOWN\n" ); snes_reset_state = 1; reset_count = 0; } } else { if ( snes_reset_prev ) { printf( "RESET BUTTON UP\n" ); snes_reset_state = 0; } } if ( snes_reset_state ) { reset_count++; } else { sram_reliable(); snes_main_loop(); } if ( reset_count > 4 ) { reset_count = 0; prepare_reset(); break; } snes_reset_prev = snes_reset_now; } /* fpga test fail: panic */ if ( fpga_test() != FPGA_TEST_TOKEN ) { led_panic(); } /* else reset */ } }