From 36e48b1746c670bbe601cdc69d713aab08ce2c23 Mon Sep 17 00:00:00 2001 From: Kim Johnsson Date: Mon, 2 Mar 2020 11:03:42 +0100 Subject: [PATCH 1/2] Basic Favorite games list, with context menu in the file selector to add games (#134) Context menu is accessed with the Y button Favorites list is accessed with the SELECT button or via the main menu Adds new menu option type FUNC_CLOSE, which closes the current menu after RTL Extends menu_select to support multiple buttons to select an item --- snes/const.a65 | 12 ++- snes/data.a65 | 2 + snes/filesel.a65 | 200 ++++++++++++++++++++++++++++++++++++++++++++++ snes/memmap.i65 | 6 ++ snes/menu.a65 | 110 +++++++++++++++++++++++-- snes/menudata.a65 | 59 +++++++++++++- src/cfg.c | 134 +++++++++++++++++++++++++++++++ src/cfg.h | 8 ++ src/main.c | 22 +++++ src/memory.h | 1 + src/snes.c | 3 +- src/snes.h | 4 + 12 files changed, 552 insertions(+), 9 deletions(-) diff --git a/snes/const.a65 b/snes/const.a65 index 47697020..7b6b8add 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 @@ -220,6 +221,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 @@ -255,10 +257,18 @@ 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_statusbar_keys .byt "A:Select B:Back X:Menu", 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_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 .byt "On", 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 c83410a3..caf40673 100644 --- a/snes/memmap.i65 +++ b/snes/memmap.i65 @@ -55,12 +55,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 @@ -73,6 +75,8 @@ #define CMD_SELECTROM $10 #define CMD_RUNROM $11 /* 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_MCU_RDY $55 #define CMD_RESET $80 #define CMD_RESET_TO_MENU $81 @@ -111,6 +115,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 @@ -119,6 +124,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 cea9d931..f1321740 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 @@ -475,7 +489,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 @@ -543,6 +557,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 b4fd1e1e..676582d8 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -281,6 +281,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 d2ec8cbf..2ce93eab 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") @@ -73,6 +75,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 256eab2a..5ac834cf 100644 --- a/src/main.c +++ b/src/main.c @@ -155,9 +155,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 */ @@ -286,6 +288,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; @@ -324,6 +332,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 1d1b5860..b36a9bfe 100644 --- a/src/memory.h +++ b/src/memory.h @@ -54,6 +54,7 @@ #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 2e2b4b91..f9c31895 100644 --- a/src/snes.c +++ b/src/snes.c @@ -56,7 +56,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 f977ff03..e4af449b 100644 --- a/src/snes.h +++ b/src/snes.h @@ -32,6 +32,7 @@ #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) @@ -41,6 +42,8 @@ #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_RESET (0x80) #define SNES_CMD_RESET_TO_MENU (0x81) #define SNES_CMD_ENABLE_CHEATS (0x82) @@ -100,6 +103,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 { From 4ba3e816f01720659107564023e83f556f150071 Mon Sep 17 00:00:00 2001 From: ikari Date: Mon, 24 Aug 2020 18:05:36 +0200 Subject: [PATCH 2/2] [SA1] glitch-filter address lines as done on other cores This should avoid accidental yielding of SNES IRAM cycles to the MCU that caused graphical glitches. --- verilog/sd2snes_sa1/main.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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]);