diff --git a/snes/const.a65 b/snes/const.a65 index 3bbfa415..e17bd3bf 100644 --- a/snes/const.a65 +++ b/snes/const.a65 @@ -188,6 +188,7 @@ last_win_w .byt 60 text_ellipse .byt 127, 128, 0 text_mm_file .byt "File Browser", 0 text_mm_last .byt "Recent games", 0 +text_mm_favorites .byt "Favorite games", 0 mtext_mm_cfg .byt "Configuration", 0 mtext_mm_sysinfo .byt "System Information", 0 mtext_cfg_time .byt "Set Clock", 0 @@ -232,6 +233,7 @@ mtext_chip_gsu_speed .byt "SuperFX speed", 0 mtext_chip_msu1_volume_boost .byt "MSU-1 volume boost", 0 mdesc_mm_last .byt "Show up to 10 most recently played games", 0 +mdesc_mm_favorites .byt "Show up to 10 favorite games", 0 mdesc_mm_cfg .byt "Configure the sd2snes", 0 mdesc_mm_sysinfo .byt "Info about FW version, SD Card, SNES, CIC", 127, 128, 0 mdesc_cfg_time .byt "Set the date and time", 0 @@ -279,11 +281,19 @@ mdesc_cx4_speed_normal .byt "Run at approx. original speed", 0 mdesc_gsu_speed_fast .byt "Run as fast as possible", 0 mdesc_gsu_speed_normal .byt "Run at approx. original speed", 0 +text_filesel_selected_file .byt "Selected file", 0 +text_filesel_context_add_to_favorites .byt "Add to favorites", 0 +mdesc_filesel_context_add_to_favorites .byt "Add the selected file to favorites", 0 + +text_filesel_favorites_context_remove_from_favorites .byt "Remove from favorites", 0 +mdesc_filesel_favorites_context_remove_from_favorites .byt "Remove the selected file from favorites", 0 + text_statusbar_play .byt "A:Play B:Back X:Menu", 0 -text_statusbar_keys .byt "A:Select B:Back X:Menu", 0 +text_statusbar_keys .byt "A:Select B:Back X:Menu Y:Context", 0 text_statusbar_spc .byt "B:Back", 0 text_statusbar_menu .byt "A:Select B:Back", 0 text_last .byt "Recent games", 0 +text_favorite .byt "Favorite games", 0 text_system .byt "CPU/PPU1/PPU2: a/b/c VMode: x0Hz",0 text_on_p1 .byt "On: P1", 0 diff --git a/snes/data.a65 b/snes/data.a65 index 7604f3af..a82a07ee 100644 --- a/snes/data.a65 +++ b/snes/data.a65 @@ -87,6 +87,7 @@ mm_sel .byt 0 ;-- num_recent_games .byt 0 recent_sel .byt 0 +num_favorite_games .byt 0 ;----------menu layout/system constants listdisp .word 0 ; number of displayable list entries @@ -96,6 +97,7 @@ testvar .word 0,0,0,0 listsel_sel .byt 0 listsel_step .byt 0 listsel_max .byt 0 +listsel_pickbutton .byt 0 ;----------hdma tables in WRAM (must be stable when cartridge is cut off) hdma_pal .byt 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/snes/filesel.a65 b/snes/filesel.a65 index e62bdf1e..edf034f3 100644 --- a/snes/filesel.a65 +++ b/snes/filesel.a65 @@ -134,6 +134,8 @@ filesel_updates: bne key_a lda pad_x bne key_x + lda pad_y + bne key_y lda pad_l bne key_l lda pad_r @@ -160,6 +162,9 @@ key_a key_x jsr filesel_key_x bra fileselupd_out +key_y + jsr filesel_key_y + bra fileselupd_out key_select jsr filesel_key_select bra fileselupd_out @@ -482,6 +487,7 @@ filesel_key_a: rts filesel_key_select: + jsl select_favorite_file rts filesel_key_start: @@ -774,6 +780,90 @@ filesel_key_x: jsr mainmenu rts +filesel_key_y: + jsr open_context_menu + rts + +open_context_menu: + rep #$20 : .al + lda filesel_sel + and #$00ff + asl + asl + tay + sep #$20 : .as + iny + iny + iny + lda [dirptr_addr], y + cmp #TYPE_ROM + beq ctx_is_file + cmp #TYPE_SPC + beq ctx_is_spc + cmp #TYPE_SUBDIR + beq ctx_is_dir + cmp #TYPE_PARENT + beq ctx_is_parent +open_context_menu_cont + rts +ctx_is_file +; "save" selected file path to MCU_PARAM in case we need to send it there later + dey + rep #$20 : .al + lda [dirptr_addr], y + and #$00ff + sta @MCU_PARAM+6 + dey + dey + lda [dirptr_addr], y + sta @MCU_PARAM+4 + lda #!FILESEL_CWD + sta @MCU_PARAM + sep #$20 : .as + lda #^FILESEL_CWD + sta @MCU_PARAM+2 + lda #$00 + sta @MCU_PARAM+3 + jsr filesel_contextmenu_file + bra open_context_menu_cont +ctx_is_parent + bra open_context_menu_cont +ctx_is_dir + bra open_context_menu_cont +ctx_is_spc + bra open_context_menu_cont + +add_selected_file_to_favorites: +; have MCU save the file to the favorites list +; the file path should already have been saved to MCU_PARAM before calling +; this routine + php + phb + sep #$20 : .as + lda #$01 + jsr hide_cursor + jsr draw_loading_window + jsr waitblank + lda #$00 + sta @SNES_CMD + lda #CMD_ADD_FAVORITE_ROM + sta @MCU_CMD +; wait for ACK/NACK +- lda @SNES_CMD + cmp #$55 +; success + beq + + cmp #$aa +; failure + beq + + bra - ++ lda #$55 + sta @MCU_CMD + jsr pop_window + plb + plp + rtl + setup_224: php rep #$30 : .xl : .al @@ -894,6 +984,7 @@ select_last_file: bne - lda #$01 sta listsel_step + stz listsel_pickbutton jsr menu_select sta @MCU_PARAM cmp #$ff @@ -905,6 +996,115 @@ select_last_file: plp rtl +select_favorite_file: +; shows a window with a list of favorite games + php + sep #$20 : .as + rep #$10 : .xl + lda @ST_NUM_FAVORITE_GAMES + sta num_favorite_games + bne + + plp + rtl ++ lda #^text_favorite + sta window_tbank + ldx #!text_favorite + stx window_taddr + lda @last_win_x + sta window_x + inc + inc + pha + lda @last_win_y + sta window_y + inc + pha + lda @last_win_w + sta window_w + lda @ST_NUM_FAVORITE_GAMES + inc + inc + sta window_h + jsr push_window + lda num_favorite_games + sta listsel_max + jsr draw_window + stz print_pal + lda #^FAVORITE_GAMES + ldx #!FAVORITE_GAMES + sta print_bank + stx print_src + stz print_pal + pla + sta print_y + pla + sta print_x +- lda #56 + sta print_count + jsr hiprint + inc print_src+1 + inc print_y + dec num_favorite_games + bne - + lda #$01 + sta listsel_step + sta listsel_pickbutton + jsr menu_select + sta @MCU_PARAM ; store selected item index in mcu param + cmp #$ff ; if no selected item, do nothing + beq select_favorite_file_done + lda listsel_pickbutton + cmp #$00 ; if button A was pressed + beq select_favorite_file_play + cmp #$01 ; if button Y was pressed + beq select_favorite_file_context_menu + bra select_favorite_file_done ; unknown button was pressed +select_favorite_file_play + sep #$20 : .as + lda #CMD_LOADFAVORITE + jsr game_handshake + bra select_favorite_file_done +select_favorite_file_context_menu + jsr filesel_favorites_contextmenu + jsr pop_window + plp + jmp select_favorite_file ; return to favorite list after closing the ctx menu +select_favorite_file_done + jsr pop_window + plp + rtl + +remove_selected_favorite_file: +; have MCU remove the file from the favorites list +; the list index of the file should already have been saved to MCU_PARAM before +; calling this routine + php + phb + sep #$20 : .as + lda #$01 + jsr hide_cursor + jsr draw_loading_window + jsr waitblank + lda #$00 + sta @SNES_CMD + lda #CMD_REMOVE_FAVORITE_ROM + sta @MCU_CMD + ; wait for ACK/NACK + - lda @SNES_CMD + cmp #$55 + ; success + beq + + cmp #$aa + ; failure + beq + + bra - + + lda #$55 + sta @MCU_CMD + jsr pop_window + plb + plp + rtl + scroll_direntry_clean: lda #$01 sta direntry_xscroll_state diff --git a/snes/memmap.i65 b/snes/memmap.i65 index ace9639d..59622d60 100644 --- a/snes/memmap.i65 +++ b/snes/memmap.i65 @@ -59,12 +59,14 @@ #define SYSINFO_BLK $FF1200 #define LAST_GAME $FF1420 #define WRAM_BAK $FF2000 +#define FAVORITE_GAMES $FF4000 #define CMD_LOADROM $01 /* shortcut - load ROM with default settings */ #define CMD_SETRTC $02 #define CMD_SYSINFO $03 #define CMD_LOADLAST $04 #define CMD_LOADSPC $05 +#define CMD_LOADFAVORITE $06 #define CMD_SET_ALLOW_PAIR $07 #define CMD_SET_VIDMODE_GAME $08 #define CMD_SET_VIDMODE_MENU $09 @@ -77,6 +79,8 @@ #define CMD_SELECTROM $10 /* TODO WIP */ #define CMD_RUNROM $11 /* TODO WIP - ROM must first be selected by SELECTROM */ #define CMD_LED_BRIGHTNESS $12 +#define CMD_ADD_FAVORITE_ROM $13 +#define CMD_REMOVE_FAVORITE_ROM $14 #define CMD_SAVESTATE $40 #define CMD_LOADSTATE $41 #define CMD_MCU_RDY $55 @@ -133,6 +137,7 @@ #define ST_RTC_VALID ST_MCU_ADDR+$0000 #define ST_NUM_RECENT_GAMES ST_MCU_ADDR+$0001 #define ST_PAIRMODE ST_MCU_ADDR+$0002 +#define ST_NUM_FAVORITE_GAMES ST_MCU_ADDR+$0003 #define ST_IS_U16 ST_SNES_ADDR+$0000 #define ST_U16_CFG ST_SNES_ADDR+$0001 @@ -141,6 +146,7 @@ #define MTYPE_FUNC $01 #define MTYPE_SUBMENU $02 #define MTYPE_VALUE $03 +#define MTYPE_FUNC_CLOSE $04 #define OPTTYPE_NONE $00 #define OPTTYPE_BYTE $01 diff --git a/snes/menu.a65 b/snes/menu.a65 index cc046ce2..831bc6b8 100644 --- a/snes/menu.a65 +++ b/snes/menu.a65 @@ -31,6 +31,60 @@ mainmenu: jsr pop_window rts +filesel_contextmenu_file: + sep #$20 : .as + rep #$10 : .xl + lda #$02 + sta window_x + lda #$09 + sta window_y + lda #60 + sta window_w + lda #18 + sta window_h + jsr push_window + jsr window_greyout + lda #$06 + sta window_x + lda #$0b + sta window_y + phb + lda #^menu_enttab_filesel_context_file + pha + plb + ldx #!menu_enttab_filesel_context_file + jsr show_menu + plb + jsr pop_window + rts + +filesel_favorites_contextmenu: + sep #$20 : .as + rep #$10 : .xl + lda #$02 + sta window_x + lda #$09 + sta window_y + lda #60 + sta window_w + lda #18 + sta window_h + jsr push_window + jsr window_greyout + lda #$06 + sta window_x + lda #$0b + sta window_y + phb + lda #^menu_enttab_filesel_favorites_context + pha + plb + ldx #!menu_enttab_filesel_favorites_context + jsr show_menu + plb + jsr pop_window + rts + ; menu_select: ; helper routine to select a list entry ; window and list items must be printed in advance @@ -39,9 +93,14 @@ mainmenu: ; window_x, window_y, window_w, window_h: for select bar setup ; listsel_max: number of list entries to select from ; listsel_step: spacing between list entries (y text lines) +; listsel_pickbutton: if 00, only allow button A to select an item, +; if 01, allow button A and Y to select an item ; -; return value: index of selected item in A +; return value: index of selected item in A, ; or #$FF if no item was selected +; listsel_pickbutton = 00 if button A was used, +; listsel_pickbutton = 01 if button Y was used, +; listsel_pickbutton = FF if button B (cancel) was used menu_select: php sep #$20 : rep #$10 : .as : .xl @@ -80,9 +139,11 @@ menu_select_loop1 lda pad_down bne menu_select_down lda pad_a - bne menu_select_item + bne menu_select_button_a + lda pad_y + bne menu_select_button_y lda pad_b - bne menu_select_none + bne menu_select_button_b bra menu_select_loop1 menu_select_up lda listsel_sel @@ -104,11 +165,22 @@ menu_select_down adc listsel_step sta bar_yl bra menu_select_loop1 -menu_select_item +menu_select_button_a ; always allow button a + lda #$00 + sta listsel_pickbutton lda listsel_sel bra menu_select_exit -menu_select_none +menu_select_button_y ; check if we should allow button y + lda listsel_pickbutton + cmp #$01 + bne menu_select_loop1 + lda #$01 + sta listsel_pickbutton + lda listsel_sel + bra menu_select_exit +menu_select_button_b ; cancel lda #$ff + sta listsel_pickbutton menu_select_exit plp rts @@ -188,6 +260,7 @@ show_menu: lda w_numentries sta listsel_max show_menu_loop: + stz listsel_pickbutton jsr menu_select_noinit cmp #$ff beq show_menu_out @@ -210,6 +283,8 @@ show_menu_loop: beq show_menu_submenu cmp #MTYPE_FUNC beq show_menu_func + cmp #MTYPE_FUNC_CLOSE + beq show_menu_func_close cmp #MTYPE_VALUE bne show_menu_cont jmp show_menu_editvalue @@ -300,6 +375,29 @@ show_menu_func_cont: ply jmp show_menu_cont +show_menu_func_close: + phy + jsr push_window + jsr window_greyout + ply + phk + per show_menu_func_close_cont-1 + rep #$20 : .al + lda [w_menu_addr], y + tax + sep #$20 : .as + iny + iny + lda [w_menu_addr], y + pha + phx + rtl +show_menu_func_close_cont: + phy + jsr pop_window + ply + jmp show_menu_out + show_menu_editvalue: phy phb @@ -1398,4 +1496,4 @@ menu_tab_edit_value_dialogs: .word menu_value_dialog_kv8 .word menu_value_dialog_kv16 .word menu_value_dialog_file -.word menu_value_dialog_time \ No newline at end of file +.word menu_value_dialog_time diff --git a/snes/menudata.a65 b/snes/menudata.a65 index de226a9d..80e1a9a3 100644 --- a/snes/menudata.a65 +++ b/snes/menudata.a65 @@ -22,6 +22,7 @@ ; 01 function call ; 02 submenu ; 03 value setting +; 04 function call where the menu should be closed upon return ; data types: ; 00 no parameter @@ -67,6 +68,19 @@ menu_enttab_mm: .byt 0,0,0 .byt 0,0,0 + .byt MTYPE_FUNC + .word !text_mm_favorites + .byt ^text_mm_favorites + .word !select_favorite_file-1 + .byt ^select_favorite_file-1 + .byt 0 + .byt 0,0,0 + .word !mdesc_mm_favorites + .byt ^mdesc_mm_favorites + .byt 0,0,0 + .byt 0,0,0 + .byt 0,0,0 + .byt MTYPE_FUNC .word !mtext_mm_sysinfo .byt ^mtext_mm_sysinfo @@ -608,7 +622,7 @@ menu_enttab_ingame: .byt ^(mfunc_chg_brightness-1) .byt 0,0,0 .byt 0,0,0 - + .byt MTYPE_VALUE .word !mtext_ingame_resetpatch .byt ^mtext_ingame_resetpatch @@ -728,6 +742,49 @@ menu_enttab_scic: .byt ^(mfunc_isenabled_scic-1) .byt 0 + +menu_enttab_filesel_context_file: +; HEADER + .byt 1 ; listsel_step=1 + .word !text_filesel_selected_file ; window title + .byt ^text_filesel_selected_file ; for this menu +; ENTRIES + .byt MTYPE_FUNC_CLOSE + .word !text_filesel_context_add_to_favorites + .byt ^text_filesel_context_add_to_favorites + .word !add_selected_file_to_favorites-1 + .byt ^add_selected_file_to_favorites-1 + .byt 0 + .byt 0,0,0 + .word !mdesc_filesel_context_add_to_favorites + .byt ^mdesc_filesel_context_add_to_favorites + .byt 0,0,0 + .byt 0,0,0 + .byt 0,0,0 + + .byt 0 + +menu_enttab_filesel_favorites_context: +; HEADER + .byt 1 ; listsel_step=1 + .word !text_filesel_selected_file ; window title + .byt ^text_filesel_selected_file ; for this menu +; ENTRIES + .byt MTYPE_FUNC_CLOSE + .word !text_filesel_favorites_context_remove_from_favorites + .byt ^text_filesel_favorites_context_remove_from_favorites + .word !remove_selected_favorite_file-1 + .byt ^remove_selected_favorite_file-1 + .byt 0 + .byt 0,0,0 + .word !mdesc_filesel_favorites_context_remove_from_favorites + .byt ^mdesc_filesel_favorites_context_remove_from_favorites + .byt 0,0,0 + .byt 0,0,0 + .byt 0,0,0 + + .byt 0 + mfunc_set_bsx_time: php sep #$20 : .as diff --git a/src/cfg.c b/src/cfg.c index 7481bb36..ffa8c602 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -362,6 +362,140 @@ void cfg_dump_recent_games_for_snes(uint32_t address) { file_close(); } +int cfg_validity_check_favorite_games() { + int err = 0, index, index_max, write_indices[10], rewrite_favoritefile = 0; + TCHAR fntmp[10][256]; + file_open(FAVORITES_FILE, FA_READ); + if(file_status == FILE_ERR) { + return 0; + } + for(index = 0; index < 10 && !f_eof(&file_handle); index++) { + f_gets(fntmp[index], 255, &file_handle); + } + if(!f_eof(&file_handle)) + index_max = 10; + else + index_max = index; + file_close(); + for(index = 0; index < index_max; index++) { + file_open((uint8_t*)fntmp[index], FA_READ); + write_indices[index] = file_status; + if(file_status != FILE_OK) + rewrite_favoritefile = 1; + file_close(); + } + if(rewrite_favoritefile) { + f_rename ((TCHAR*)FAVORITES_FILE, (TCHAR*)FAVORITES_FILE_BAK); + file_open(FAVORITES_FILE, FA_CREATE_ALWAYS | FA_WRITE); + for(index = 0; index < index_max; index++) { + if(write_indices[index] == FILE_OK) { + err = f_puts(fntmp[index], &file_handle); + err = f_putc(0, &file_handle); + } + } + file_close(); + } + return err; +} + +int cfg_add_favorite_game(uint8_t *fn) { + int err = 0, index, index2, found = 0, foundindex = 0, written = 0; + TCHAR fqfn[256]; + TCHAR fntmp[10][256]; + file_open(FAVORITES_FILE, FA_READ); + fqfn[0] = 0; + if(fn[0] != '/') { + strncpy(fqfn, (const char*)file_path, 256); + fqfn[255] = 0; + } + strncat(fqfn, (const char*)fn, 256 - strlen(fqfn) - 1); + for(index = 0; index < 10; index++) { + f_gets(fntmp[index], 255, &file_handle); + if((*fntmp[index] == 0) || (*fntmp[index] == '\n')) { + break; /* last entry found */ + } + if(!strncasecmp((TCHAR*)fqfn, fntmp[index], 255)) { + found = 1; /* file already in list */ + foundindex = index; + } + } + file_close(); + + if(index > 9 + found) { + //List is full and game is not already in list, refuse to add it + return 1; + } + + file_open(FAVORITES_FILE, FA_CREATE_ALWAYS | FA_WRITE); + /* always put new entry on top of list */ + err = f_puts((const TCHAR*)fqfn, &file_handle); + err = f_putc(0, &file_handle); + written++; + if(index > 9 + found) index = 9 + found; /* truncate oldest entry */ + /* allow number of destination entries to be the same as source in case + * we're only moving a previous entry to top */ + for(index2 = 0; index2 < index; index2++) { + if(found && (index2 == foundindex)){ + continue; /* omit found entry here to prevent dupe */ + } + err = f_puts(fntmp[index2], &file_handle); + err = f_putc(0, &file_handle); + written++; + } + file_close(); + return err; +} + +int cfg_remove_favorite_game(uint8_t index_to_remove) { + int err = 0, index, index2, written = 0; + TCHAR fntmp[10][256]; + + // Load current favorites list into memory + file_open(FAVORITES_FILE, FA_READ); + for(index = 0; index < 10; index++) { + f_gets(fntmp[index], 255, &file_handle); + if((*fntmp[index] == 0) || (*fntmp[index] == '\n')) { + break; /* last entry found */ + } + } + file_close(); + + //Write back all favorites except the one at index_to_remove + file_open(FAVORITES_FILE, FA_CREATE_ALWAYS | FA_WRITE); + for(index2 = 0; index2 < index; index2++) { + if(index2 == index_to_remove){ + continue; + } + err = f_puts(fntmp[index2], &file_handle); + err = f_putc(0, &file_handle); + written++; + } + file_close(); + return err; +} + +int cfg_get_favorite_game(uint8_t *fn, uint8_t index) { + int err = 0; + file_open(FAVORITES_FILE, FA_READ); + do { + f_gets((TCHAR*)fn, 255, &file_handle); + } while (index--); + file_close(); + return err; +} + +void cfg_dump_favorite_games_for_snes(uint32_t address) { + TCHAR fntmp[256]; + int index; + file_open(FAVORITES_FILE, FA_READ); + for(index = 0; index < 10 && !f_eof(&file_handle); index++) { + f_gets(fntmp, 255, &file_handle); + sram_writestrn(strrchr((const char*)fntmp, '/')+1, address+256*index, 256); + } + STM.num_favorite_games = index; + file_close(); +} + /* make binary config available to menu */ void cfg_load_to_menu() { sram_writeblock(&CFG, SRAM_MENU_CFG_ADDR, sizeof(cfg_t)); diff --git a/src/cfg.h b/src/cfg.h index 5a36f4b4..a3f96626 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -6,6 +6,8 @@ #define CFG_FILE ("/sd2snes/config.yml") #define LAST_FILE ((const uint8_t*)"/sd2snes/lastgame.cfg") #define LAST_FILE_BAK ((const uint8_t*)"/sd2snes/~lastgame.cfg") +#define FAVORITES_FILE ((const uint8_t*)"/sd2snes/favorites.cfg") +#define FAVORITES_FILE_BAK ((const uint8_t*)"/sd2snes/~favorites.cfg") #define CFG_VIDMODE_MENU ("VideoModeMenu") #define CFG_VIDMODE_GAME ("VideoModeGame") @@ -99,6 +101,12 @@ int cfg_add_last_game(uint8_t *fn); int cfg_get_last_game(uint8_t *fn, uint8_t index); void cfg_dump_recent_games_for_snes(uint32_t address); +int cfg_validity_check_favorite_games(void); +int cfg_add_favorite_game(uint8_t *fn); +int cfg_remove_favorite_game(uint8_t index_to_remove); +int cfg_get_favorite_game(uint8_t *fn, uint8_t index); +void cfg_dump_favorite_games_for_snes(uint32_t address); + void cfg_load_to_menu(void); void cfg_get_from_menu(void); diff --git a/src/main.c b/src/main.c index 12c8bb4b..171e0995 100644 --- a/src/main.c +++ b/src/main.c @@ -167,9 +167,11 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); cfg_load(); cfg_save(); cfg_validity_check_recent_games(); + cfg_validity_check_favorite_games(); } if(fpga_config != FPGA_BASE) fpga_pgm((uint8_t*)FPGA_BASE); cfg_dump_recent_games_for_snes(SRAM_LASTGAME_ADDR); + cfg_dump_favorite_games_for_snes(SRAM_FAVORITEGAMES_ADDR); led_set_brightness(CFG.led_brightness); /* load menu */ @@ -298,6 +300,12 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); cfg_add_last_game(file_lfn); filesize = load_rom(file_lfn, SRAM_ROM_ADDR, LOADROM_WITH_SRAM | LOADROM_WITH_RESET | LOADROM_WAIT_SNES); break; + case SNES_CMD_LOADFAVORITE: + cfg_get_favorite_game(file_lfn, snes_get_mcu_param() & 0xff); + printf("Selected name: %s\n", file_lfn); + cfg_add_last_game(file_lfn); + filesize = load_rom(file_lfn, SRAM_ROM_ADDR, LOADROM_WITH_SRAM | LOADROM_WITH_RESET | LOADROM_WAIT_SNES); + break; /* case SNES_CMD_SET_ALLOW_PAIR: cfg_set_pair_mode_allowed(snes_get_mcu_param() & 0xff); break; @@ -336,6 +344,20 @@ printf("PCONP=%lx\n", LPC_SC->PCONP); led_set_brightness(CFG.led_brightness); cmd=0; break; + case SNES_CMD_ADD_FAVORITE_ROM: + get_selected_name(file_lfn); + printf("Selected name: %s\n", file_lfn); + cfg_add_favorite_game(file_lfn); + cfg_dump_favorite_games_for_snes(SRAM_FAVORITEGAMES_ADDR); + status_load_to_menu(); + cmd=0; /* stay in menu loop */ + break; + case SNES_CMD_REMOVE_FAVORITE_ROM: + cfg_remove_favorite_game(snes_get_mcu_param() & 0xff); + cfg_dump_favorite_games_for_snes(SRAM_FAVORITEGAMES_ADDR); + status_load_to_menu(); + cmd=0; /* stay in menu loop */ + break; case SNES_CMD_LOAD_CHT: /* load cheats */ cmd=0; /* stay in menu loop */ diff --git a/src/memory.h b/src/memory.h index e5db2300..0c39a058 100644 --- a/src/memory.h +++ b/src/memory.h @@ -58,6 +58,7 @@ extern char current_filename[]; #define SRAM_SNES_STATUS_ADDR (0xFF1110L) #define SRAM_SYSINFO_ADDR (0xFF1200L) #define SRAM_LASTGAME_ADDR (0xFF1420L) +#define SRAM_FAVORITEGAMES_ADDR (0xFF4000L) #define SRAM_SCRATCHPAD (0xFFFF00L) #define SRAM_DIRID (0xFFFFF0L) #define SRAM_RELIABILITY_SCORE (0x100) diff --git a/src/snes.c b/src/snes.c index 1cb39fa5..a43263dc 100644 --- a/src/snes.c +++ b/src/snes.c @@ -61,7 +61,8 @@ volatile int reset_pressed; mcu_status_t STM = { .rtc_valid = 0xff, .num_recent_games = 0, - .pairmode = 0 + .pairmode = 0, + .num_favorite_games = 0 }; snes_status_t STS = { diff --git a/src/snes.h b/src/snes.h index b6ff3ea5..8830ea3b 100644 --- a/src/snes.h +++ b/src/snes.h @@ -27,39 +27,42 @@ #ifndef SNES_H #define SNES_H -#define SNES_CMD_LOADROM (0x01) -#define SNES_CMD_SETRTC (0x02) -#define SNES_CMD_SYSINFO (0x03) -#define SNES_CMD_LOADLAST (0x04) -#define SNES_CMD_LOADSPC (0x05) -#define SNES_CMD_SET_ALLOW_PAIR (0x07) -#define SNES_CMD_SET_VIDMODE_GAME (0x08) -#define SNES_CMD_SET_VIDMODE_MENU (0x09) -#define SNES_CMD_READDIR (0x0a) -#define SNES_CMD_FPGA_RECONF (0x0b) -#define SNES_CMD_LOAD_CHT (0x0c) -#define SNES_CMD_SAVE_CHT (0x0d) -#define SNES_CMD_SAVE_CFG (0x0e) -#define SNES_CMD_LED_BRIGHTNESS (0x12) - -#define SNES_CMD_SAVESTATE (0x40) -#define SNES_CMD_LOADSTATE (0x41) - -#define SNES_CMD_RESET (0x80) -#define SNES_CMD_RESET_TO_MENU (0x81) -#define SNES_CMD_ENABLE_CHEATS (0x82) -#define SNES_CMD_DISABLE_CHEATS (0x83) -#define SNES_CMD_KILL_NMIHOOK (0x84) -#define SNES_CMD_TEMP_KILL_NMIHOOK (0x85) -#define SNES_CMD_RESET_LOOP_FAIL (0x88) -#define SNES_CMD_RESET_LOOP_PASS (0x89) -#define SNES_CMD_RESET_LOOP_TIMEOUT (0x8A) -#define SNES_CMD_COMBO_TRANSITION (0x90) - -#define SNES_CMD_GAMELOOP (0xff) - -#define MCU_CMD_RDY (0x55) -#define MCU_CMD_ERR (0xaa) +#define SNES_CMD_LOADROM (0x01) +#define SNES_CMD_SETRTC (0x02) +#define SNES_CMD_SYSINFO (0x03) +#define SNES_CMD_LOADLAST (0x04) +#define SNES_CMD_LOADSPC (0x05) +#define SNES_CMD_LOADFAVORITE (0x06) +#define SNES_CMD_SET_ALLOW_PAIR (0x07) +#define SNES_CMD_SET_VIDMODE_GAME (0x08) +#define SNES_CMD_SET_VIDMODE_MENU (0x09) +#define SNES_CMD_READDIR (0x0a) +#define SNES_CMD_FPGA_RECONF (0x0b) +#define SNES_CMD_LOAD_CHT (0x0c) +#define SNES_CMD_SAVE_CHT (0x0d) +#define SNES_CMD_SAVE_CFG (0x0e) +#define SNES_CMD_LED_BRIGHTNESS (0x12) +#define SNES_CMD_ADD_FAVORITE_ROM (0x13) +#define SNES_CMD_REMOVE_FAVORITE_ROM (0x14) + +#define SNES_CMD_SAVESTATE (0x40) +#define SNES_CMD_LOADSTATE (0x41) + +#define SNES_CMD_RESET (0x80) +#define SNES_CMD_RESET_TO_MENU (0x81) +#define SNES_CMD_ENABLE_CHEATS (0x82) +#define SNES_CMD_DISABLE_CHEATS (0x83) +#define SNES_CMD_KILL_NMIHOOK (0x84) +#define SNES_CMD_TEMP_KILL_NMIHOOK (0x85) +#define SNES_CMD_RESET_LOOP_FAIL (0x88) +#define SNES_CMD_RESET_LOOP_PASS (0x89) +#define SNES_CMD_RESET_LOOP_TIMEOUT (0x8a) +#define SNES_CMD_COMBO_TRANSITION (0x90) + +#define SNES_CMD_GAMELOOP (0xff) + +#define MCU_CMD_RDY (0x55) +#define MCU_CMD_ERR (0xaa) #define MENU_ERR_OK (0x0) #define MENU_ERR_FS (0x1) @@ -114,6 +117,7 @@ typedef struct __attribute__ ((__packed__)) _mcu_status { uint8_t rtc_valid; uint8_t num_recent_games; uint8_t pairmode; + uint8_t num_favorite_games; } mcu_status_t; typedef struct __attribute__ ((__packed__)) _snes_status { diff --git a/verilog/sd2snes_sa1/main.v b/verilog/sd2snes_sa1/main.v index 0ef19cbb..8091340f 100644 --- a/verilog/sd2snes_sa1/main.v +++ b/verilog/sd2snes_sa1/main.v @@ -180,7 +180,7 @@ reg SNES_reset_strobe = 0; reg free_strobe = 0; reg ram_free_strobe = 0; -wire [23:0] SNES_ADDR = SNES_ADDRr[0]; //(SNES_ADDRr[6] & SNES_ADDRr[5]); +wire [23:0] SNES_ADDR = SNES_ADDRr[1] & SNES_ADDRr[0]; //(SNES_ADDRr[6] & SNES_ADDRr[5]); //wire [23:0] SNES_ADDR_early = SNES_ADDRr[0]; wire [7:0] SNES_PA = SNES_PAr[0]; //(SNES_PAr[6] & SNES_PAr[5]); wire [7:0] SNES_DATA_IN = (SNES_DATAr[3] & SNES_DATAr[2]);