diff --git a/bsx.cpp b/bsx.cpp index 2b4454e3..a4c81ab8 100644 --- a/bsx.cpp +++ b/bsx.cpp @@ -218,6 +218,10 @@ struct SBSX_RTC { + int year; + int month; + int dayweek; + int day; int hours; int minutes; int seconds; @@ -893,6 +897,105 @@ void S9xSetBSX (uint8 byte, uint32 address) } } +void S9xBSXSetStream1 (uint8 count) +{ + if (BSX.sat_stream1.is_open()) BSX.sat_stream1.close(); //If Stream1 already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream1.clear(); + BSX.sat_stream1.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream1.good()) + { + BSX.sat_stream1.seekg(0, BSX.sat_stream1.end); + long str1size = BSX.sat_stream1.tellg(); + BSX.sat_stream1.seekg(0, BSX.sat_stream1.beg); + float QueueSize = str1size / 22.; + BSX.PPU[0x218A - BSXPPUBASE] = (uint8)(ceil(QueueSize)); + BSX.PPU[0x218D - BSXPPUBASE] = 0; + BSX.sat_stream1_first = TRUE; + BSX.sat_stream1_loaded = TRUE; + } + else + { + BSX.sat_stream1_loaded = FALSE; + } +} + +void S9xBSXSetStream2 (uint8 count) +{ + if (BSX.sat_stream2.is_open()) BSX.sat_stream2.close(); //If Stream1 already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream2.clear(); + BSX.sat_stream2.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream2.good()) + { + BSX.sat_stream2.seekg(0, BSX.sat_stream2.end); + long str2size = BSX.sat_stream2.tellg(); + BSX.sat_stream2.seekg(0, BSX.sat_stream2.beg); + float QueueSize = str2size / 22.; + BSX.PPU[0x2190 - BSXPPUBASE] = (uint8)(ceil(QueueSize)); + BSX.PPU[0x2193 - BSXPPUBASE] = 0; + BSX.sat_stream2_first = TRUE; + BSX.sat_stream2_loaded = TRUE; + } + else + { + BSX.sat_stream2_loaded = FALSE; + } +} + +uint8 S9xBSXGetRTC (void) +{ + //Get Time + time_t t; + struct tm *tmr; + + time(&t); + tmr = localtime(&t); + + BSX.test2192[0] = 0x00; + BSX.test2192[1] = 0x00; + BSX.test2192[2] = 0x00; + BSX.test2192[3] = 0x00; + BSX.test2192[4] = 0x10; + BSX.test2192[5] = 0x01; + BSX.test2192[6] = 0x01; + BSX.test2192[7] = 0x00; + BSX.test2192[8] = 0x00; + BSX.test2192[9] = 0x00; + BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec; + BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min; + BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour; + BSX.test2192[13] = BSX_RTC.dayweek = (tmr->tm_wday) + 1; + BSX.test2192[14] = BSX_RTC.day = tmr->tm_mday; + BSX.test2192[15] = BSX_RTC.month = (tmr->tm_mon) + 1; + BSX_RTC.year = tmr->tm_year + 1900; + BSX.test2192[16] = (BSX_RTC.year) & 0xFF; + BSX.test2192[17] = (BSX_RTC.year) >> 8; + + t = BSX.test2192[BSX.out_index++]; + + if (BSX.out_index > 22) + BSX.out_index = 0; + + return t; +} + uint8 S9xGetBSXPPU (uint16 address) { uint8 t; @@ -900,95 +1003,255 @@ uint8 S9xGetBSXPPU (uint16 address) // known read registers switch (address) { - // Test register low? (r/w) + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) case 0x2188: t = BSX.PPU[0x2188 - BSXPPUBASE]; break; - // Test register high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x2189: t = BSX.PPU[0x2189 - BSXPPUBASE]; break; + // Prefix Count (R) case 0x218A: - t = BSX.PPU[0x218A - BSXPPUBASE]; + if (!BSX.sat_pf_latch1_enable || !BSX.sat_dt_latch1_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.PPU[0x218A - BSXPPUBASE] <= 0) + { + BSX.sat_stream1_count++; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (!BSX.sat_stream1_loaded && (BSX.sat_stream1_count - 1) > 0) + { + BSX.sat_stream1_count = 1; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (BSX.sat_stream1_loaded) + t = BSX.PPU[0x218A - BSXPPUBASE]; + else + t = 0; break; + // Prefix Latch (R/W) + case 0x218B: + if (BSX.sat_pf_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218B - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream1_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream1_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream1_first = FALSE; + } + + BSX.PPU[0x218A - BSXPPUBASE]--; + + if (BSX.PPU[0x218A - BSXPPUBASE] == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x218B - BSXPPUBASE] = temp; + } + + BSX.PPU[0x218D - BSXPPUBASE] |= BSX.PPU[0x218B - BSXPPUBASE]; + t = BSX.PPU[0x218B - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) case 0x218C: - t = BSX.PPU[0x218C - BSXPPUBASE]; + if (BSX.sat_dt_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218C - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream1_loaded) + { + if (BSX.sat_stream1.eof()) + BSX.PPU[0x218C - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x218C - BSXPPUBASE] = BSX.sat_stream1.get(); + } + t = BSX.PPU[0x218C - BSXPPUBASE]; + } + else + { + t = 0; + } break; - // Transmission number low? (r/w) + // OR gate (R) + case 0x218D: + t = BSX.PPU[0x218D - BSXPPUBASE]; + BSX.PPU[0x218D - BSXPPUBASE] = 0; + break; + + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) case 0x218E: t = BSX.PPU[0x218E - BSXPPUBASE]; break; - // Transmission number high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x218F: t = BSX.PPU[0x218F - BSXPPUBASE]; break; - // Status register? (r) + // Prefix Count (R) case 0x2190: - t = BSX.PPU[0x2190 - BSXPPUBASE]; + if (!BSX.sat_pf_latch2_enable || !BSX.sat_dt_latch2_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.PPU[0x2190 - BSXPPUBASE] <= 0) + { + BSX.sat_stream2_count++; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (!BSX.sat_stream2_loaded && (BSX.sat_stream2_count - 1) > 0) + { + BSX.sat_stream2_count = 1; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (BSX.sat_stream2_loaded) + t = BSX.PPU[0x2190 - BSXPPUBASE]; + else + t = 0; break; - // Data register? (r/w) + // Prefix Latch (R/W) + case 0x2191: + if (BSX.sat_pf_latch2_enable) + { + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2191 - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream2_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream2_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream2_first = FALSE; + } + + BSX.PPU[0x2190 - BSXPPUBASE]--; + + if (BSX.PPU[0x2190 - BSXPPUBASE] == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x2191 - BSXPPUBASE] = temp; + } + + BSX.PPU[0x2193 - BSXPPUBASE] |= BSX.PPU[0x2191 - BSXPPUBASE]; + t = BSX.PPU[0x2191 - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) case 0x2192: - // t = BSX.PPU[0x2192 - BSXPPUBASE]; - - // test - t = BSX.test2192[BSX.out_index++]; - if (BSX.out_index == 32) - BSX.out_index = 0; - - BSX_RTC.ticks++; - if (BSX_RTC.ticks >= 1000) + if (BSX.sat_dt_latch2_enable) { - BSX_RTC.ticks = 0; - BSX_RTC.seconds++; + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2192 - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream2_loaded) + { + if (BSX.sat_stream2.eof()) + BSX.PPU[0x2192 - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x2192 - BSXPPUBASE] = BSX.sat_stream2.get(); + } + t = BSX.PPU[0x2192 - BSXPPUBASE]; } - if (BSX_RTC.seconds >= 60) + else { - BSX_RTC.seconds = 0; - BSX_RTC.minutes++; + t = 0; } - if (BSX_RTC.minutes >= 60) - { - BSX_RTC.minutes = 0; - BSX_RTC.hours++; - } - if (BSX_RTC.hours >= 24) - BSX_RTC.hours = 0; - - BSX.test2192[10] = BSX_RTC.seconds; - BSX.test2192[11] = BSX_RTC.minutes; - BSX.test2192[12] = BSX_RTC.hours; - break; - // Transmission status? (r/w) + // OR gate (R) case 0x2193: - // Data ready when bits 2/3 clear? - t = BSX.PPU[0x2193 - BSXPPUBASE] & ~0x0C; + t = BSX.PPU[0x2193 - BSXPPUBASE]; + BSX.PPU[0x2193 - BSXPPUBASE] = 0; break; - // Reset? (r/w) + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] case 0x2194: t = BSX.PPU[0x2194 - BSXPPUBASE]; break; - // Unknown (r) + // Unknown + case 0x2195: + t = BSX.PPU[0x2195 - BSXPPUBASE]; + break; + + // Satellaview Status (R) case 0x2196: t = BSX.PPU[0x2196 - BSXPPUBASE]; break; - // Unknown (r/w) + // Soundlink Settings (R/W) case 0x2197: t = BSX.PPU[0x2197 - BSXPPUBASE]; break; - // Modem protocol? (r/w) + // Serial I/O - Serial Number (R/W) + case 0x2198: + t = BSX.PPU[0x2198 - BSXPPUBASE]; + break; + + // Serial I/O - Unknown (R/W) case 0x2199: t = BSX.PPU[0x2199 - BSXPPUBASE]; break; @@ -1006,78 +1269,82 @@ void S9xSetBSXPPU (uint8 byte, uint16 address) // known write registers switch (address) { - // Test register low? (r/w) + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) case 0x2188: + if (BSX.PPU[0x2188 - BSXPPUBASE] == byte) + { + BSX.sat_stream1_count = 0; + } BSX.PPU[0x2188 - BSXPPUBASE] = byte; break; - // Test register high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x2189: - BSX.PPU[0x2189 - BSXPPUBASE] = byte; - break; - - case 0x218A: - BSX.PPU[0x218A - BSXPPUBASE] = byte; + if (BSX.PPU[0x2188 - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream1_count = 0; + } + BSX.PPU[0x2189 - BSXPPUBASE] = byte & 0x3F; break; + // Prefix Latch (R/W) case 0x218B: - BSX.PPU[0x218B - BSXPPUBASE] = byte; + BSX.sat_pf_latch1_enable = (byte != 0); break; + // Data Latch (R/W) case 0x218C: - BSX.PPU[0x218C - BSXPPUBASE] = byte; + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch1_enable = (byte != 0); break; - // Transmission number low? (r/w) + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) case 0x218E: + if (BSX.PPU[0x218E - BSXPPUBASE] == byte) + { + BSX.sat_stream2_count = 0; + } BSX.PPU[0x218E - BSXPPUBASE] = byte; break; - // Transmission number high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x218F: - BSX.PPU[0x218F - BSXPPUBASE] = byte; - - // ? - BSX.PPU[0x218E - BSXPPUBASE] >>= 1; - BSX.PPU[0x218E - BSXPPUBASE] = BSX.PPU[0x218F - BSXPPUBASE] - BSX.PPU[0x218E - BSXPPUBASE]; - BSX.PPU[0x218F - BSXPPUBASE] >>= 1; - - BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? + if (BSX.PPU[0x218F - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream2_count = 0; + } + BSX.PPU[0x218F - BSXPPUBASE] = byte & 0x3F; break; - // Strobe assert? (w) + // Prefix Latch (R/W) case 0x2191: - BSX.PPU[0x2191 - BSXPPUBASE] = byte; - BSX.out_index = 0; + BSX.sat_pf_latch2_enable = (byte != 0); break; - // Data register? (r/w) + // Data Latch (R/W) case 0x2192: - BSX.PPU[0x2192 - BSXPPUBASE] = 0x01; // ? - BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch2_enable = (byte != 0); break; - // Transmission status? (r/w) - case 0x2193: - BSX.PPU[0x2193 - BSXPPUBASE] = byte; - break; - - // Reset? (r/w) + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] case 0x2194: - BSX.PPU[0x2194 - BSXPPUBASE] = byte; + BSX.PPU[0x2194 - BSXPPUBASE] = byte & 0x0F; break; - // Unknown (r/w) + // Soundlink Settings (R/W) case 0x2197: BSX.PPU[0x2197 - BSXPPUBASE] = byte; break; - - // Modem protocol? (r/w) - case 0x2199: - // Lots of modem strings written here when - // connection is lost or no uplink established - BSX.PPU[0x2199 - BSXPPUBASE] = byte; - break; } } @@ -1196,7 +1463,7 @@ void S9xInitBSX (void) { MapROM = NULL; FlashROM = Memory.ROM; - + /* time_t t; struct tm *tmr; @@ -1211,6 +1478,7 @@ void S9xInitBSX (void) #ifdef BSX_DEBUG printf("BS: Current Time: %02d:%02d:%02d\n", BSX_RTC.hours, BSX_RTC.minutes, BSX_RTC.seconds); #endif + */ SNESGameFixes.SRAMInitialValue = 0x00; } } @@ -1243,6 +1511,14 @@ void S9xResetBSX (void) BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; BSX.MMC[0x0E] = 0x80; + // stream reset + BSX.sat_pf_latch1_enable, BSX.sat_dt_latch1_enable = FALSE; + BSX.sat_pf_latch2_enable, BSX.sat_dt_latch2_enable = FALSE; + + BSX.sat_stream1_loaded, BSX.sat_stream2_loaded = FALSE; + BSX.sat_stream1_first, BSX.sat_stream2_first = FALSE; + BSX.sat_stream1_count, BSX.sat_stream2_count = 0; + BSX_Map(); } diff --git a/bsx.h b/bsx.h index ac5a2906..56a04ec1 100644 --- a/bsx.h +++ b/bsx.h @@ -213,6 +213,16 @@ struct SBSX bool flash_gsr; bool flash_bsr; bool flash_cmd_done; + + std::ifstream sat_stream1; + std::ifstream sat_stream2; + + bool sat_pf_latch1_enable, sat_dt_latch1_enable; + bool sat_pf_latch2_enable, sat_dt_latch2_enable; + + bool sat_stream1_loaded, sat_stream2_loaded; + bool sat_stream1_first, sat_stream2_first; + uint8 sat_stream1_count, sat_stream2_count; }; extern struct SBSX BSX; diff --git a/display.h b/display.h index 8b61c3fa..a6a67f84 100644 --- a/display.h +++ b/display.h @@ -207,6 +207,7 @@ enum s9x_getdirtype IPS_DIR, BIOS_DIR, LOG_DIR, + SAT_DIR, LAST_DIR }; diff --git a/win32/wconfig.cpp b/win32/wconfig.cpp index 0b4e6ee9..41319ce6 100644 --- a/win32/wconfig.cpp +++ b/win32/wconfig.cpp @@ -953,6 +953,7 @@ void WinRegisterConfigItems() AddStringC("Dir:SRAM", GUI.SRAMFileDir, _MAX_PATH, ".\\Saves", "directory where battery saves will be created and loaded from"); AddStringC("Dir:Patches", GUI.PatchDir, _MAX_PATH, ".\\Cheats", "directory in which ROM patches (.ips files) and cheats (.cht files) will be looked for"); AddStringC("Dir:Bios", GUI.BiosDir, _MAX_PATH, ".\\BIOS", "directory where BIOS files (such as \"BS-X.bios\") will be located"); + AddStringC("Dir:SatData", GUI.SatDir, _MAX_PATH, ".\\SatData", "directory where Satellaview Signal Data files will be located"); AddBoolC("Dir:Lock", GUI.LockDirectories, false, "true to prevent Snes9x from changing configured directories when you browse to a new location"); #define ADD(n) AddString("Rom:RecentGame" #n, GUI.RecentGames[n-1], MAX_PATH, "") ADD(1); ADD(2); ADD(3); ADD(4); ADD(5); ADD(6); ADD(7); ADD(8); diff --git a/win32/win32.cpp b/win32/win32.cpp index 9c278da6..e239a2e5 100644 --- a/win32/win32.cpp +++ b/win32/win32.cpp @@ -353,6 +353,10 @@ const TCHAR *S9xGetDirectoryT (enum s9x_getdirtype dirtype) rv = GUI.FreezeFileDir; break; + case SAT_DIR: + rv = GUI.SatDir; + break; + case ROMFILENAME_DIR: { static TCHAR filename [PATH_MAX]; lstrcpy(filename, _tFromChar(Memory.ROMFilename)); diff --git a/win32/wlanguage.h b/win32/wlanguage.h index 50735f57..b53c33f9 100644 --- a/win32/wlanguage.h +++ b/win32/wlanguage.h @@ -580,6 +580,7 @@ Nintendo is a trade mark.") #define SETTINGS_OPTION_DIRECTORY_SRAM TEXT("SRAM") #define SETTINGS_OPTION_DIRECTORY_PATCHESANDCHEATS TEXT("Patch&Cheat") #define SETTINGS_OPTION_DIRECTORY_BIOS TEXT("BIOS files") +#define SETTINGS_OPTION_DIRECTORY_SATDATA TEXT("Satellaview") // Misc. diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp index b4de0412..bb90b186 100644 --- a/win32/wsnes9x.cpp +++ b/win32/wsnes9x.cpp @@ -5089,7 +5089,7 @@ INT_PTR CALLBACK DlgAboutProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) } INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { - static TCHAR paths[8][MAX_PATH]; + static TCHAR paths[9][MAX_PATH]; static int which = 0; switch(msg) { @@ -5140,6 +5140,8 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_PATCHESANDCHEATS); lstrcpy(paths[inum++],GUI.BiosDir); SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_BIOS); + lstrcpy(paths[inum++],GUI.SatDir); + SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_ADDSTRING,0,(LPARAM)(LPCTSTR)SETTINGS_OPTION_DIRECTORY_SATDATA); SendDlgItemMessage(hDlg,IDC_DIRCOMBO,CB_SETCURSEL,(WPARAM)0,0); SetDlgItemText(hDlg, IDC_CUSTOM_FOLDER_FIELD, paths[0]); @@ -5202,6 +5204,7 @@ INT_PTR CALLBACK DlgEmulatorProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lPar lstrcpy(GUI.SRAMFileDir,paths[inum++]); lstrcpy(GUI.PatchDir,paths[inum++]); lstrcpy(GUI.BiosDir,paths[inum++]); + lstrcpy(GUI.SatDir,paths[inum++]); GUI.InactivePause = (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_INACTIVE_PAUSE)); GUI.CustomRomOpen = (BST_CHECKED==IsDlgButtonChecked(hDlg, IDC_CUSTOMROMOPEN)); diff --git a/win32/wsnes9x.h b/win32/wsnes9x.h index 69376def..1f96737b 100644 --- a/win32/wsnes9x.h +++ b/win32/wsnes9x.h @@ -394,6 +394,7 @@ struct sGUI { TCHAR SRAMFileDir [_MAX_PATH]; TCHAR PatchDir [_MAX_PATH]; TCHAR BiosDir [_MAX_PATH]; + TCHAR SatDir [_MAX_PATH]; bool LockDirectories; TCHAR RecentGames [MAX_RECENT_GAMES_LIST_SIZE][MAX_PATH];