diff --git a/MiSTer.ini b/MiSTer.ini
index 0d16ab8..8ef73f9 100644
--- a/MiSTer.ini
+++ b/MiSTer.ini
@@ -17,6 +17,13 @@ vscale_border=0 ; set vertical border for TVs cutting the upper/bottom pa
rbf_hide_datecode=0 ; 1 - hides datecodes from rbf file names. Press F2 for quick temporary toggle
menu_pal=0 ; 1 - PAL mode for menu core
+; lastcore - Autoboot the last loaded core (corename autosaved in CONFIG/lastcore.dat) first found on the SD/USB
+; lastexactcore - Autoboot the last loaded exact core (corename_yyyymmdd.rbf autosaved in CONFIG/lastcore.dat) first found on the SD/USB
+; corename - Autoboot first corename_*.rbf found on the SD/USB
+; corename_yyyymmdd.rbf - Autoboot first corename_yyyymmdd.rbf found on the SD/USB
+;bootcore=lastcore ; uncomment to autoboot a core, as the last loaded core.
+bootcore_timeout=10 ; 10-30 timeout before autoboot, comment for autoboot without timeout.
+
; USER button emulation by keybaord. Usually it's reset button.
; 0 - lctrl+lalt+ralt (lctrl+lgui+rgui on keyrah)
; 1 - lctrl+lgui+rgui
diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj
index 926e0f2..b10acb1 100644
--- a/MiSTer.vcxproj
+++ b/MiSTer.vcxproj
@@ -49,6 +49,7 @@
+
@@ -84,6 +85,7 @@
+
diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters
index f000c72..ac1508b 100644
--- a/MiSTer.vcxproj.filters
+++ b/MiSTer.vcxproj.filters
@@ -127,6 +127,9 @@
Source Files\miniz
+
+ Source Files
+
@@ -258,5 +261,8 @@
Header Files\miniz
+
+ Header Files
+
\ No newline at end of file
diff --git a/bootcore.cpp b/bootcore.cpp
new file mode 100644
index 0000000..5a02541
--- /dev/null
+++ b/bootcore.cpp
@@ -0,0 +1,240 @@
+// bootcore.cpp
+// 2019, Aitor Gomez Garcia (spark2k06@gmail.com)
+// Thanks to Sorgelig and BBond007 for their help and advice in the development of this feature.
+
+#include "file_io.h"
+#include "cfg.h"
+#include "fpga_io.h"
+#include
+#include
+#include
+#include
+
+int16_t btimeout;
+char bootcoretype[64];
+
+bool isExactcoreName(char *path)
+{
+ char *spl = strrchr(path, '.');
+ return (spl && !strcmp(spl, ".rbf"));
+}
+
+char *getcoreName(char *path)
+{
+ char *spl = strrchr(path, '.');
+ if (spl && !strcmp(spl, ".rbf"))
+ {
+ *spl = '\0';
+ }
+ else
+ {
+ return NULL;
+ }
+ if ((spl = strrchr(path, '/')) != NULL)
+ {
+ path = spl + 1;
+ }
+ if ((spl = strrchr(path, '_')) != NULL)
+ {
+ *spl = 0;
+ }
+
+ return path;
+}
+
+char *getcoreExactName(char *path)
+{
+ char *spl;
+ if ((spl = strrchr(path, '/')) != NULL)
+ {
+ path = spl + 1;
+ }
+
+ return path;
+}
+
+char *replaceStr(const char *str, const char *oldstr, const char *newstr)
+{
+ char *result;
+ int i, cnt = 0;
+ int newstrlen = strlen(newstr);
+ int oldstrlen = strlen(oldstr);
+
+ for (i = 0; str[i] != '\0'; i++)
+ {
+ if (strstr(&str[i], oldstr) == &str[i])
+ {
+ cnt++;
+ i += oldstrlen - 1;
+ }
+ }
+
+ result = new char[i + cnt * (newstrlen - oldstrlen) + 1];
+
+ i = 0;
+ while (*str)
+ {
+ if (strstr(str, oldstr) == str)
+ {
+ strcpy(&result[i], newstr);
+ i += newstrlen;
+ str += oldstrlen;
+ }
+ else
+ result[i++] = *str++;
+ }
+
+ result[i] = '\0';
+ return result;
+}
+
+char* loadLastcore()
+{
+ char full_path[2100];
+ char path[256] = { CONFIG_DIR"/" };
+ strcat(path, "lastcore.dat");
+ sprintf(full_path, "%s/%s", getRootDir(), path);
+ FILE *fd = fopen(full_path, "r");
+ if (!fd)
+ {
+ return NULL;
+ }
+ fseek(fd, 0L, SEEK_END);
+ long size = ftell(fd);
+
+ fseek(fd, 0L, SEEK_SET);
+ char *lastcore = new char[size + 1];
+
+ int ret = fread(lastcore, sizeof(char), size, fd);
+ fclose(fd);
+ if (ret == size)
+ {
+ return lastcore;
+ }
+ delete[] lastcore;
+ return NULL;
+
+}
+
+char *findCore(const char *name, char *coreName, int indent)
+{
+ char *spl;
+ DIR *dir;
+ struct dirent *entry;
+
+ if (!(dir = opendir(name)))
+ {
+ return NULL;
+ }
+
+
+ char *indir;
+ char* path = new char[256];
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_type == DT_DIR) {
+ if (entry->d_name[0] != '_')
+ continue;
+ snprintf(path, 256, "%s/%s", name, entry->d_name);
+ indir = findCore(path, coreName, indent + 2);
+ if (indir != NULL)
+ {
+ closedir(dir);
+ delete[] path;
+ return indir;
+ }
+ }
+ else {
+ snprintf(path, 256, "%s/%s", name, entry->d_name);
+ if (strstr(path, coreName) != NULL) {
+ spl = strrchr(path, '.');
+ if (spl && !strcmp(spl, ".rbf"))
+ {
+ closedir(dir);
+ return path;
+ }
+ }
+ }
+ }
+ closedir(dir);
+ delete[] path;
+ return NULL;
+}
+
+void bootcore_init(const char *path)
+{
+ MiSTer_ini_parse();
+ if (cfg.bootcore[0] == '\0')
+ {
+ return;
+ }
+
+ char *auxpointer;
+ char auxstr[256];
+ char bootcore[256];
+ bool is_lastcore;
+ const char *rootdir = getRootDir();
+ cfg.bootcore_timeout = cfg.bootcore_timeout * 10;
+ btimeout = cfg.bootcore_timeout;
+ strcpy(bootcore, cfg.bootcore);
+
+ is_lastcore = (!strcmp(cfg.bootcore, "lastcore") || !strcmp(cfg.bootcore, "lastexactcore"));
+
+ if (is_lastcore)
+ {
+ strcpy(bootcoretype, cfg.bootcore);
+ auxpointer = loadLastcore();
+ if (auxpointer != NULL)
+ {
+ strcpy(bootcore, auxpointer);
+ delete[] auxpointer;
+ }
+ }
+ else
+ {
+ strcpy(bootcoretype, isExactcoreName(cfg.bootcore) ? "exactcorename" : "corename");
+ }
+
+ auxpointer = findCore(rootdir, bootcore, 0);
+ if (auxpointer != NULL)
+ {
+ strcpy(bootcore, auxpointer);
+ delete[] auxpointer;
+
+ sprintf(auxstr, "%s/", rootdir);
+ auxpointer = replaceStr(bootcore, auxstr, "");
+ if (auxpointer != NULL)
+ {
+ strcpy(bootcore, auxpointer);
+ delete[] auxpointer;
+
+ if (path[0] == '\0')
+ {
+ if (!cfg.bootcore_timeout)
+ {
+ fpga_load_rbf(bootcore);
+ }
+
+ strcpy(cfg.bootcore, strcmp(bootcore, "menu.rbf") ? bootcore : "");
+ return;
+ }
+ }
+ }
+
+ if (is_lastcore && path[0] != '\0')
+ {
+
+ strcpy(auxstr, path);
+ auxpointer = !strcmp(cfg.bootcore, "lastexactcore") ? getcoreExactName(auxstr) : getcoreName(auxstr);
+
+ if (auxpointer != NULL)
+ {
+ if (strcmp(bootcore, auxpointer))
+ {
+ FileSaveConfig("lastcore.dat", (char*)auxpointer, strlen(auxpointer));
+ }
+ }
+ }
+ strcpy(cfg.bootcore, "");
+
+}
+
diff --git a/bootcore.h b/bootcore.h
new file mode 100644
index 0000000..e86c891
--- /dev/null
+++ b/bootcore.h
@@ -0,0 +1,18 @@
+// bootcore.h
+// 2019, Aitor Gomez Garcia (spark2k06@gmail.com)
+// Thanks to Sorgelig and BBond007 for their help and advice in the development of this feature.
+
+#ifndef __BOOTCORE_H__
+#define __BOOTCORE_H__
+
+char *getcoreName(char *path);
+char *getcoreExactName(char *path);
+char *replaceStr(const char *str, const char *oldstr, const char *newstr);
+char *loadLastcore();
+char *findCore(const char *name, char *coreName, int indent);
+void bootcore_init(const char *path);
+
+extern char bootcoretype[64];
+extern int16_t btimeout;
+
+#endif // __BOOTCORE_H__
\ No newline at end of file
diff --git a/cfg.cpp b/cfg.cpp
index b45cf4b..db33bdc 100644
--- a/cfg.cpp
+++ b/cfg.cpp
@@ -46,6 +46,8 @@ const ini_var_t ini_vars[] = {
{ "VSCALE_BORDER", (void*)(&(cfg.vscale_border)), UINT8, 0, 100, 1 },
{ "RBF_HIDE_DATECODE", (void*)(&(cfg.rbf_hide_datecode)), UINT8, 0, 1, 1 },
{ "MENU_PAL", (void*)(&(cfg.menu_pal)), UINT8, 0, 1, 1 },
+ { "BOOTCORE", (void*)(&(cfg.bootcore)), STRING, 0, sizeof(cfg.bootcore) - 1, 1 },
+ { "BOOTCORE_TIMEOUT", (void*)(&(cfg.bootcore_timeout)), INT8, 10, 30, 1 },
};
// mist ini config
diff --git a/cfg.h b/cfg.h
index c061ea7..f787321 100644
--- a/cfg.h
+++ b/cfg.h
@@ -32,6 +32,8 @@ typedef struct {
uint8_t vscale_border;
uint8_t rbf_hide_datecode;
uint8_t menu_pal;
+ int16_t bootcore_timeout;
+ char bootcore[256];
char video_conf[1024];
char video_conf_pal[1024];
char video_conf_ntsc[1024];
diff --git a/file_io.cpp b/file_io.cpp
index 4ba6235..413f401 100644
--- a/file_io.cpp
+++ b/file_io.cpp
@@ -737,7 +737,6 @@ void FindStorage(void)
{
int saveddev = device;
device = 0;
- MiSTer_ini_parse();
device = saveddev;
parse_video_mode();
user_io_send_buttons(1);
diff --git a/fpga_io.cpp b/fpga_io.cpp
index cf6608b..0e48815 100644
--- a/fpga_io.cpp
+++ b/fpga_io.cpp
@@ -516,7 +516,7 @@ int fpga_load_rbf(const char *name, const char *cfg)
}
}
close(rbf);
- app_restart(!strcasecmp(name, "menu.rbf") ? NULL : path);
+ app_restart(!strcasecmp(name, "menu.rbf") ? "menu.rbf" : path);
return ret;
}
diff --git a/main.cpp b/main.cpp
index 4978076..a9fd5a9 100644
--- a/main.cpp
+++ b/main.cpp
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include "input.h"
#include "fpga_io.h"
#include "scheduler.h"
+#include "bootcore.h"
const char *version = "$VER:HPS" VDATE;
@@ -65,6 +66,7 @@ int main(int argc, char *argv[])
}
FindStorage();
+ bootcore_init(argc > 1 ? argv[1] : "");
user_io_init((argc > 1) ? argv[1] : "");
scheduler_init();
diff --git a/menu.cpp b/menu.cpp
index 4deb103..2dc6965 100644
--- a/menu.cpp
+++ b/menu.cpp
@@ -47,6 +47,7 @@ along with this program. If not, see .
#include "cfg.h"
#include "input.h"
#include "battery.h"
+#include "bootcore.h"
#include "support.h"
@@ -643,6 +644,26 @@ static void MenuWrite(unsigned char n, const char *s, unsigned char invert, unsi
OsdWriteOffset(row, s, invert, stipple, 0, (row == 0 && firstmenu) ? 17 : (row == (OsdGetSize()-1) && !arrow) ? 16 : 0, 0);
}
+const char* get_rbf_name_bootcore(char *str)
+{
+ if (!strlen(cfg.bootcore)) return "";
+ char *p = strrchr(str, '/');
+ if (!p) return str;
+
+ char *spl = strrchr(p + 1, '.');
+ if (spl && !strcmp(spl, ".rbf"))
+ {
+ *spl = 0;
+ }
+ else
+ {
+ return NULL;
+ }
+ return p + 1;
+
+
+}
+
void HandleUI(void)
{
switch (user_io_core_type())
@@ -689,6 +710,11 @@ void HandleUI(void)
plus = false;
minus = false;
+ if (c && c != KEY_F12 && cfg.bootcore[0] != '\0')
+ {
+ cfg.bootcore[0] = '\0';
+ }
+
switch (c)
{
case KEY_F12:
@@ -3556,8 +3582,35 @@ void HandleUI(void)
if (!rtc_timer || CheckTimer(rtc_timer))
{
- rtc_timer = GetTimer(1000);
+ rtc_timer = GetTimer(cfg.bootcore[0] != '\0' ? 100 : 1000);
char str[64] = { 0 };
+ char straux[64];
+
+ if (cfg.bootcore[0] != '\0')
+ {
+ if (btimeout >= 10)
+ {
+ sprintf(str, " Bootcore -> %s", bootcoretype);
+ OsdWrite(13, str, 0, 0);
+ strcpy(straux, cfg.bootcore);
+ sprintf(str, " %s", get_rbf_name_bootcore(straux));
+ PrintFileName(str, 14, (32 * btimeout) / cfg.bootcore_timeout);
+ sprintf(str, " Press any key to cancel");
+ OsdWrite(15, str, 0, 0);
+ btimeout--;
+ if (btimeout < 10)
+ {
+ OsdWrite(13, "", 0, 0);
+ strcpy(straux, cfg.bootcore);
+ sprintf(str, " %s", get_rbf_name_bootcore(straux));
+ PrintFileName(str, 14, 0);
+ sprintf(str, " Loading...");
+ OsdWrite(15, str, 1, 0);
+ fpga_load_rbf(cfg.bootcore);
+ }
+ }
+ }
+
sprintf(str, " MiSTer ");
time_t t = time(NULL);
@@ -3624,6 +3677,54 @@ void ScrollLongName(void)
ScrollText(flist_iSelectedEntry()-flist_iFirstEntry(), flist_SelectedItem()->d_name, 2, len, max_len, 1);
}
+void PrintFileName(char *name, int row, int maxinv)
+{
+ int len;
+
+ char s[40];
+ s[32] = 0; // set temporary string length to OSD line length
+
+ len = strlen(name); // get name length
+ memset(s, ' ', 32); // clear line buffer
+ char *p = 0;
+ if ((fs_Options & SCANO_CORES) && len > 9 && !strncmp(name + len - 9, "_20", 3))
+ {
+ p = name + len - 6;
+ len -= 9;
+ }
+
+ if (len > 28)
+ {
+ len = 27; // trim display length if longer than 30 characters
+ s[28] = 22;
+ }
+ strncpy(s + 1, name, len); // display only name
+
+ if (!cfg.rbf_hide_datecode && (fs_Options & SCANO_CORES))
+ {
+ if (p)
+ {
+ int n = 19;
+ s[n++] = ' ';
+ s[n++] = p[0];
+ s[n++] = p[1];
+ s[n++] = '.';
+ s[n++] = p[2];
+ s[n++] = p[3];
+ s[n++] = '.';
+ s[n++] = p[4];
+ s[n++] = p[5];
+ }
+ else
+ {
+ strcpy(&s[19], " --.--.--");
+ }
+ }
+
+ OsdWrite(row, s, 1, 0, 0, maxinv);
+
+}
+
// print directory contents
void PrintDirectory(void)
{
diff --git a/menu.h b/menu.h
index d271d3e..d625b83 100644
--- a/menu.h
+++ b/menu.h
@@ -13,6 +13,7 @@ extern const char *config_chipset_msg[];
void HandleUI(void);
void menu_key_set(unsigned int c);
+void PrintFileName(char *name, int row, int maxinv);
void PrintDirectory(void);
void ScrollLongName(void);
diff --git a/osd.cpp b/osd.cpp
index 1f0913b..fdbcf2b 100644
--- a/osd.cpp
+++ b/osd.cpp
@@ -200,13 +200,13 @@ void OsdSetArrow(int a)
arrow = a;
}
-void OsdWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char usebg)
+void OsdWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char usebg, int maxinv)
{
- OsdWriteOffset(n, s, invert, stipple, 0, 0, usebg);
+ OsdWriteOffset(n, s, invert, stipple, 0, 0, usebg, maxinv);
}
// write a null-terminated string to the OSD buffer starting at line
-void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char offset, char leftchar, char usebg)
+void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, char offset, char leftchar, char usebg, int maxinv)
{
//printf("OsdWriteOffset(%d)\n", n);
unsigned short i;
@@ -237,6 +237,7 @@ void OsdWriteOffset(unsigned char n, const char *s, unsigned char invert, unsign
// send all characters in string to OSD
while (1)
{
+ if (invert && i / 8 >= maxinv) invert = 0;
if (i == 0 && (n < osd_size))
{ // Render sidestripe
unsigned char j;
diff --git a/osd.h b/osd.h
index 3e05fae..ef61620 100644
--- a/osd.h
+++ b/osd.h
@@ -68,8 +68,8 @@
/*functions*/
void OsdSetTitle(const char *s, int arrow = 0); // arrow > 0 = display right arrow in bottom right, < 0 = display left arrow
void OsdSetArrow(int arrow);
-void OsdWrite(unsigned char n, const char *s="", unsigned char inver=0, unsigned char stipple=0, char usebg = 0);
-void OsdWriteOffset(unsigned char n, const char *s, unsigned char inver, unsigned char stipple, char offset, char leftchar, char usebg = 0); // Used for scrolling "Exit" text downwards...
+void OsdWrite(unsigned char n, const char *s="", unsigned char inver=0, unsigned char stipple=0, char usebg = 0, int maxinv = 32);
+void OsdWriteOffset(unsigned char n, const char *s, unsigned char inver, unsigned char stipple, char offset, char leftchar, char usebg = 0, int maxinv = 32); // Used for scrolling "Exit" text downwards...
void OsdClear(void);
void OsdEnable(unsigned char mode);
void InfoEnable(int x, int y, int width, int height);
diff --git a/user_io.cpp b/user_io.cpp
index aca522e..2683b4a 100644
--- a/user_io.cpp
+++ b/user_io.cpp
@@ -500,7 +500,6 @@ void user_io_init(const char *path)
user_io_8bit_set_status(UIO_STATUS_RESET, UIO_STATUS_RESET);
}
- MiSTer_ini_parse();
parse_video_mode();
FileLoadConfig("Volume.dat", &vol_att, 1);
vol_att &= 0x1F;