diff --git a/Makefile b/Makefile index 08baa96..8dcfe03 100644 --- a/Makefile +++ b/Makefile @@ -20,11 +20,12 @@ SHARPMZ_SRC = $(wildcard ./support/sharpmz/*.cpp) ARCHIE_SRC = $(wildcard ./support/archie/*.cpp) ST_SRC = $(wildcard ./support/st/*.cpp) X86_SRC = $(wildcard ./support/x86/*.cpp) +SNES_SRC = $(wildcard ./support/snes/*.cpp) -VPATH = ./:./support/minimig:./support/sharpmz:./support/archie:./support/st:./support/x86 +VPATH = ./:./support/minimig:./support/sharpmz:./support/archie:./support/st:./support/x86:./support/snes -OBJ = $(SRC:.c=.o) $(SRC2:.cpp=.o) $(MINIMIG_SRC:.cpp=.o) $(SHARPMZ_SRC:.cpp=.o) $(ARCHIE_SRC:.cpp=.o) $(ST_SRC:.cpp=.o) $(X86_SRC:.cpp=.o) -DEP = $(SRC:.c=.d) $(SRC2:.cpp=.d) $(MINIMIG_SRC:.cpp=.d) $(SHARPMZ_SRC:.cpp=.d) $(ARCHIE_SRC:.cpp=.d) $(ST_SRC:.cpp=.d) $(X86_SRC:.cpp=.d) +OBJ = $(SRC:.c=.o) $(SRC2:.cpp=.o) $(MINIMIG_SRC:.cpp=.o) $(SHARPMZ_SRC:.cpp=.o) $(ARCHIE_SRC:.cpp=.o) $(ST_SRC:.cpp=.o) $(X86_SRC:.cpp=.o) $(SNES_SRC:.cpp=.o) +DEP = $(SRC:.c=.d) $(SRC2:.cpp=.d) $(MINIMIG_SRC:.cpp=.d) $(SHARPMZ_SRC:.cpp=.d) $(ARCHIE_SRC:.cpp=.d) $(ST_SRC:.cpp=.d) $(X86_SRC:.cpp=.d) $(SNES_SRC:.cpp=.d) CFLAGS = $(DFLAGS) -c -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DVDATE=\"`date +"%y%m%d"`\" LFLAGS = -lc -lstdc++ -lrt diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index df594ec..941417f 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -63,6 +63,7 @@ + @@ -99,6 +100,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index 09646dd..3b13493 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -91,6 +91,9 @@ Source Files + + Source Files + @@ -195,5 +198,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/coeff_nn.txt b/coeff_nn.txt index 85d40cc..418dc3f 100644 --- a/coeff_nn.txt +++ b/coeff_nn.txt @@ -4,37 +4,37 @@ # Near Neighbor # horizontal coefficients - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 # vertical coefficients - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 - 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 128, 0, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 + 0, 0, 128, 0 diff --git a/file_io.cpp b/file_io.cpp index 9c05728..eb1d813 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -65,7 +65,7 @@ int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute) char *p = strrchr(full_path, '/'); strcpy(file->name, (mode == -1) ? full_path : p+1); - file->fd = (mode == -1) ? shm_open("/vtrd", O_CREAT | O_RDWR | O_TRUNC, 0777) : open(full_path, mode); + file->fd = (mode == -1) ? shm_open("/vtrd", O_CREAT | O_RDWR | O_TRUNC, 0777) : open(full_path, mode, 0777); if (file->fd <= 0) { if(!mute) printf("FileOpenEx(open) File:%s, error: %d.\n", full_path, file->fd); @@ -100,6 +100,15 @@ int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute) return 1; } +__off64_t FileGetSize(fileTYPE *file) +{ + if (file->fd <= 0) return 0; + + struct stat64 st; + int ret = fstat64(file->fd, &st); + return (ret < 0) ? 0 : st.st_size; +} + int FileOpen(fileTYPE *file, const char *name, char mute) { return FileOpenEx(file, name, O_RDONLY, mute); @@ -330,6 +339,16 @@ int FileCanWrite(const char *name) return ((st.st_mode & S_IWUSR) != 0); } +uint32_t getFileType(const char *name) +{ + sprintf(full_path, "%s/%s", getRootDir(), name); + + struct stat64 st; + if (stat64(full_path, &st)) return 0; + + return st.st_mode; +} + static int device = 0; static int usbnum = 0; const char *getStorageDir(int dev) diff --git a/file_io.h b/file_io.h index b094c88..f1bf899 100644 --- a/file_io.h +++ b/file_io.h @@ -13,6 +13,7 @@ typedef struct int type; __off64_t size; __off64_t offset; + char path[1024]; char name[261]; } fileTYPE; @@ -34,6 +35,7 @@ dirent* flist_SelectedItem(); #define SCANO_DIR 1 // include subdirectories #define SCANO_UMOUNT 2 // allow backspace key #define SCANO_CORES 4 // only include subdirectories with prefix '_' +#define SCANO_COEFF 8 void FindStorage(); int getStorage(int from_setting); @@ -44,6 +46,8 @@ int FileOpenEx(fileTYPE *file, const char *name, int mode, char mute = 0); int FileOpen(fileTYPE *file, const char *name, char mute = 0); void FileClose(fileTYPE *file); +__off64_t FileGetSize(fileTYPE *file); + int FileSeek(fileTYPE *file, __off64_t offset, int origin); int FileSeekLBA(fileTYPE *file, uint32_t offset); @@ -76,4 +80,8 @@ const char *getStorageDir(int dev); const char *getRootDir(); const char *getFullPath(const char *name); +uint32_t getFileType(const char *name); + +#define COEFF_DIR "filters" + #endif diff --git a/fpga_io.cpp b/fpga_io.cpp index a4ee7bc..c0c2c86 100644 --- a/fpga_io.cpp +++ b/fpga_io.cpp @@ -602,6 +602,8 @@ void reboot(int cold) sync(); fpga_core_reset(1); + usleep(500000); + writel(cold ? 0 : 0x1, &reset_regs->tstscratch); writel(2, &reset_regs->ctrl); while (1); diff --git a/input.cpp b/input.cpp index 5804505..f635f26 100644 --- a/input.cpp +++ b/input.cpp @@ -971,7 +971,7 @@ typedef struct { uint16_t vid, pid; char led; - char last_l, last_r, last_u, last_d; + char last_x, last_y; // last x & y axis bitmasks for each alternative directional control scheme (DPAD, Analog pad etc.) char has_map; uint32_t map[32]; @@ -1755,7 +1755,7 @@ static void input_cb(struct input_event *ev, struct input_absinfo *absinfo, int } } - if (ev->code == input[dev].map[16]) + if (ev->code == input[dev].mmap[16]) { if (ev->value <= 1) joy_digital((user_io_get_kbdemu() == EMU_JOY0) ? 0 : 1, 0, ev->value, 16); return; @@ -1917,6 +1917,42 @@ static void getVidPid(int num, uint16_t* vid, uint16_t* pid) static struct pollfd pool[NUMDEV + 1]; +// Translate axis values to key events of specific codes. +// Only binary key press /release logic is supported, any value not 0 is considered +// a key press, value 0 is key release. +static void send_axis_key_event(int dev, int code1, int code2, int value1, int value2, int last1, int last2) { + struct input_event ev; + //note: key events do not require input_absinfo values + + ev.type = EV_KEY; + //send key releases first + // value1 unset but previously set + if (!value1 && last1) { + ev.code = code1; + ev.value = 0; + input_cb(&ev, 0, dev); + } + // value2 unset but previously set + if (!value2 && last2) { + ev.code = code2; + ev.value = 0; + input_cb(&ev, 0, dev); + } + //send key presses afterwards, but only if previously not set + if (value1 && !last1) + { + ev.code = code1; + ev.value = 1; + input_cb(&ev, 0, dev); + } else //either one or another, not both directions at the same time + if (value2 && !last2) + { + ev.code = code2; + ev.value = 1; + input_cb(&ev, 0, dev); + } +} + int input_test(int getchar) { static char cur_leds = 0; @@ -2058,8 +2094,12 @@ int input_test(int getchar) char l, r, u, d; l = r = u = d = 0; uint16_t offset = 0; + char offset_mask1, offset_mask2; + if (ev.code < 16) offset += 4; if (ev.code < 2) offset += 4; + offset_mask1 = (1 << (offset >> 1)); // 01XX + offset_mask2 = (2 << (offset >> 1)); // 10XX uint16_t base_axis = !user_io_get_joy_transl() ? 0 : ~ev.code; uint16_t extra_axis = 2; @@ -2071,21 +2111,13 @@ int input_test(int getchar) if ((ev.code < 16) ? ev.value < center - treshold : ev.value == -1) l = 1; if ((ev.code < 16) ? ev.value > center + treshold : ev.value == 1) r = 1; - ev.type = EV_KEY; - if (input[i].last_l != l) - { - ev.code = KEY_EMU_LEFT + offset; - ev.value = l; - input_cb(&ev, &absinfo, i); - input[i].last_l = l; - } - - if (input[i].last_r != r) - { - ev.code = KEY_EMU_RIGHT + offset; - ev.value = r; - input_cb(&ev, &absinfo, i); - input[i].last_r = r; + // left or right pressed or now released but previously pressed (for specific controller offset) + if (l || r || (input[i].last_x & (offset_mask1 | offset_mask2))) { + send_axis_key_event(i, KEY_EMU_LEFT + offset, KEY_EMU_RIGHT + offset, l, r, input[i].last_x & offset_mask1, input[i].last_x & offset_mask2); + if (l) input[i].last_x |= offset_mask1; + else input[i].last_x &= ~offset_mask1; + if (r) input[i].last_x |= offset_mask2; + else input[i].last_x &= ~offset_mask2; } } @@ -2103,21 +2135,13 @@ int input_test(int getchar) if ((ev.code < 16) ? ev.value < center - treshold : ev.value == -1) u = 1; if ((ev.code < 16) ? ev.value > center + treshold : ev.value == 1) d = 1; - ev.type = EV_KEY; - if (input[i].last_u != u) - { - ev.code = KEY_EMU_UP + offset; - ev.value = u; - input_cb(&ev, &absinfo, i); - input[i].last_u = u; - } - - if (input[i].last_d != d) - { - ev.code = KEY_EMU_DOWN + offset; - ev.value = d; - input_cb(&ev, &absinfo, i); - input[i].last_d = d; + // up or down pressed or now released but previously pressed (for specific controller offset) + if (u || d || (input[i].last_y & (offset_mask1 | offset_mask2))) { + send_axis_key_event(i, KEY_EMU_UP + offset, KEY_EMU_DOWN + offset, u, d, input[i].last_y & offset_mask1, input[i].last_y & offset_mask2); + if (u) input[i].last_y |= offset_mask1; + else input[i].last_y &= ~offset_mask1; + if (d) input[i].last_y |= offset_mask2; + else input[i].last_y &= ~offset_mask2; } } diff --git a/menu.cpp b/menu.cpp index fbbff5e..fcb6143 100644 --- a/menu.cpp +++ b/menu.cpp @@ -127,6 +127,9 @@ enum MENU MENU_8BIT_MAIN_IMAGE_SELECTED, MENU_8BIT_SYSTEM1, MENU_8BIT_SYSTEM2, + MENU_COEFF_FILE_SELECTED, + MENU_8BIT_INFO, + MENU_8BIT_INFO2, MENU_8BIT_ABOUT1, MENU_8BIT_ABOUT2 }; @@ -162,6 +165,7 @@ const char *config_button_turbo_choice_msg[] = { "A only", "B only", "A & B" }; const char *joy_button_map[] = { "RIGHT", "LEFT", "DOWN", "UP", "BUTTON 1", "BUTTON 2", "BUTTON 3", "BUTTON 4", "KBD TOGGLE", "BUTTON OSD" }; const char *config_stereo_msg[] = { "0%", "25%", "50%", "100%" }; const char *config_uart_msg[] = { " None", " PPP", " Console", " USBMIDI", "USBMIDI-38K" }; +const char *config_scaler_msg[] = { "Internal","Custom" }; char joy_bnames[12][32]; int joy_bcount = 0; @@ -280,6 +284,10 @@ static void SelectFile(const char* pFileExt, unsigned char Options, unsigned cha } pFileExt = "RBF"; } + else if (Options & SCANO_COEFF) + { + pFileExt = "TXT"; + } else { if (strncasecmp(HomeDir, SelectedPath, strlen(HomeDir))) strcpy(SelectedPath, HomeDir); @@ -539,7 +547,7 @@ void printSysInfo() sysinfo_timer = GetTimer(2000); struct battery_data_t bat; int hasbat = getBattery(0, &bat); - int n = 10; + int n = is_menu_core() ? 10 : 5; char str[40]; OsdWrite(n++, info_top, 0, 0); @@ -614,7 +622,7 @@ int firstmenu = 0; int adjvisible; char lastrow[256]; -void MenuWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple, int arrow = 0) +void MenuWrite(unsigned char n, const char *s, unsigned char invert, unsigned char stipple = 0, int arrow = 0) { int row = n - firstmenu; @@ -867,7 +875,7 @@ void HandleUI(void) /******************************************************************/ case MENU_ARCHIE_MAIN1: - OsdSetTitle(user_io_get_core_name(), OSD_ARROW_RIGHT); + OsdSetTitle(user_io_get_core_name(), OSD_ARROW_RIGHT | OSD_ARROW_LEFT); menumask = 0x3f; OsdWrite(0, "", 0, 0); @@ -959,6 +967,11 @@ void HandleUI(void) menustate = MENU_8BIT_SYSTEM1; menusub = 0; } + else if (left) + { + menustate = MENU_8BIT_INFO; + menusub = 0; + } break; case MENU_ARCHIE_MAIN_FILE_SELECTED: // file successfully selected @@ -1116,7 +1129,7 @@ void HandleUI(void) for (; entry < OsdGetSize() - 1; entry++) MenuWrite(entry, "", 0, 0); // exit row - MenuWrite(entry, STD_EXIT, menusub == selentry, 0, OSD_ARROW_RIGHT); + MenuWrite(entry, STD_EXIT, menusub == selentry, 0, OSD_ARROW_RIGHT | OSD_ARROW_LEFT); menusub_last = selentry; menumask = (menumask << 1) | 1; @@ -1237,6 +1250,11 @@ void HandleUI(void) menustate = MENU_8BIT_SYSTEM1; menusub = 0; } + else if (left) + { + menustate = MENU_8BIT_INFO; + menusub = 0; + } break; case MENU_8BIT_MAIN_FILE_SELECTED: @@ -1260,52 +1278,76 @@ void HandleUI(void) break; case MENU_8BIT_SYSTEM1: - OsdSetSize(16); - helptext = 0; - menumask = 0xf7; - reboot_req = 0; - - OsdSetTitle("System", OSD_ARROW_LEFT); - menustate = MENU_8BIT_SYSTEM2; - parentstate = MENU_8BIT_SYSTEM1; - - s[0] = 0; - m = 0; - if(user_io_get_uart_mode()) { - int mode = 0; - struct stat filestat; - if (!stat("/tmp/uartmode1", &filestat)) mode = 1; - if (!stat("/tmp/uartmode2", &filestat)) mode = 2; - if (!stat("/tmp/uartmode3", &filestat)) mode = 3; - if (!stat("/tmp/uartmode4", &filestat)) mode = 4; - - menumask |= 8; - sprintf(s, " UART connection %s", config_uart_msg[mode]); - OsdWrite(3, s, menusub == 3, 0); - } - else - { - OsdWrite(m++, "", 0, 0); - } + OsdSetSize(16); + helptext = 0; + menumask = 0x7C7; + reboot_req = 0; - OsdWrite(m++, " Core \x16", menusub == 0, 0); - OsdWrite(m++, " Define joystick buttons \x16", menusub == 1, 0); - OsdWrite(m++, " Button/Key remap for game \x16", menusub == 2, 0); - OsdWrite(4, "", 0, 0); + OsdSetTitle("System", OSD_ARROW_LEFT); + menustate = MENU_8BIT_SYSTEM2; + parentstate = MENU_8BIT_SYSTEM1; - m = 0; - if (user_io_core_type() == CORE_TYPE_MINIMIG2) - { - m = 1; - menumask &= ~0x20; + s[0] = 0; + m = 0; + if (user_io_get_uart_mode()) + { + int mode = 0; + struct stat filestat; + if (!stat("/tmp/uartmode1", &filestat)) mode = 1; + if (!stat("/tmp/uartmode2", &filestat)) mode = 2; + if (!stat("/tmp/uartmode3", &filestat)) mode = 3; + if (!stat("/tmp/uartmode4", &filestat)) mode = 4; + + menumask |= 8; + sprintf(s, " UART connection %s", config_uart_msg[mode]); + OsdWrite(3, s, menusub == 3, 0); + } + else + { + OsdWrite(m++, "", 0, 0); + } + + OsdWrite(m++, " Core \x16", menusub == 0, 0); + OsdWrite(m++, " Define joystick buttons \x16", menusub == 1, 0); + OsdWrite(m++, " Button/Key remap for game \x16", menusub == 2, 0); + OsdWrite(4, "", 0, 0); + + m = 0; + if (user_io_core_type() == CORE_TYPE_MINIMIG2) + { + m = 1; + menumask &= ~0x80; + } + + OsdWrite(5); + int n = 6; + if (user_io_get_scaler_flt() >= 0) + { + menumask |= 0x30; + OsdWrite(n++, " HDMI Scaler:"); + sprintf(s, " \x16 Filter - %s", config_scaler_msg[user_io_get_scaler_flt() ? 1 : 0]); + OsdWrite(n++, s, menusub == 4); + + memset(s, 0, sizeof(s)); + strcpy(s, " \x16 "); + if (strlen(user_io_get_scaler_coeff())) strncat(s, user_io_get_scaler_coeff(), 22); + else strcat(s, ""); + + OsdWrite(n++, s, menusub == 5, !user_io_get_scaler_flt() || !S_ISDIR(getFileType(COEFF_DIR))); + OsdWrite(n++); + } + + OsdWrite(n++, m ? " Reset the core" : " Reset settings", menusub == 6, user_io_core_type() == CORE_TYPE_ARCHIE); + OsdWrite(n++, m ? "" : " Save settings", menusub == 7, 0); + OsdWrite(n++); + OsdWrite(n++, " Reboot (hold \x16 cold reboot)", menusub == 8); + OsdWrite(n++, " About", menusub == 9); + + while(n < 15) OsdWrite(n++); + OsdWrite(15, STD_EXIT, menusub == 10); + sysinfo_timer = 0; } - OsdWrite(5, m ? " Reset the core" : " Reset settings", menusub == 4, user_io_core_type() == CORE_TYPE_ARCHIE); - OsdWrite(6, m ? "" : " Save settings", menusub == 5, 0); - OsdWrite(7, "", 0, 0); - OsdWrite(8, " Reboot (hold \x16 cold reboot)", menusub == 6, 0); - OsdWrite(9, " About", menusub == 7, 0); - sysinfo_timer = 0; break; case MENU_8BIT_SYSTEM2: @@ -1374,6 +1416,19 @@ void HandleUI(void) } break; case 4: + user_io_set_scaler_flt(user_io_get_scaler_flt() ? 0 : 1); + menustate = MENU_8BIT_SYSTEM1; + break; + + case 5: + if (user_io_get_scaler_flt()) + { + sprintf(SelectedPath, COEFF_DIR"/%s", user_io_get_scaler_coeff()); + SelectFile(0, SCANO_COEFF, MENU_COEFF_FILE_SELECTED, MENU_8BIT_SYSTEM1); + } + break; + + case 6: if (user_io_core_type() != CORE_TYPE_ARCHIE) { menustate = MENU_RESET1; @@ -1385,7 +1440,7 @@ void HandleUI(void) menusub = 0; } break; - case 5: + case 7: // Save settings menustate = MENU_8BIT_MAIN1; menusub = 0; @@ -1408,7 +1463,7 @@ void HandleUI(void) if (is_x86_core()) x86_config_save(); } break; - case 6: + case 8: { reboot_req = 1; @@ -1420,10 +1475,13 @@ void HandleUI(void) OsdWrite(8, p, menusub == 6, 0); } break; - case 7: + case 9: menustate = MENU_8BIT_ABOUT1; menusub = 0; break; + default: + menustate = MENU_NONE1; + break; } } else if (left) @@ -1454,8 +1512,63 @@ void HandleUI(void) } if(!hold_cnt && reboot_req) fpga_load_rbf("menu.rbf"); + break; + case MENU_COEFF_FILE_SELECTED: + { + char *p = strrchr(SelectedPath, '/'); + if (!p) user_io_set_scaler_coeff(SelectedPath); + else user_io_set_scaler_coeff(p+1); + menustate = MENU_8BIT_SYSTEM1; + } + break; + + case MENU_8BIT_INFO: + OsdSetSize(16); + helptext = 0; + menumask = 1; + menustate = MENU_8BIT_INFO2; + parentstate = MENU_8BIT_INFO; + OsdSetTitle("System", OSD_ARROW_RIGHT); + + for (int i = 0; i < OsdGetSize() - 1; i++) OsdWrite(i, "", 0, 0); + OsdWrite(3, " Information"); + OsdWrite(15, STD_EXIT, menusub == 0, 0, OSD_ARROW_RIGHT); + break; + + case MENU_8BIT_INFO2: printSysInfo(); + if (select || menu) + { + menustate = MENU_NONE1; + break; + } + else if (right) + { + // go back to core requesting this menu + switch (user_io_core_type()) { + case CORE_TYPE_MINIMIG2: + menusub = 0; + menustate = MENU_MAIN1; + break; + case CORE_TYPE_MIST: + menusub = 5; + menustate = MENU_MIST_MAIN1; + break; + case CORE_TYPE_ARCHIE: + menusub = 0; + menustate = MENU_ARCHIE_MAIN1; + break; + case CORE_TYPE_8BIT: + menusub = 0; + menustate = MENU_8BIT_MAIN1; + break; + case CORE_TYPE_SHARPMZ: + menusub = menusub_last; + menustate = sharpmz_default_ui_state(); + break; + } + } break; case MENU_JOYDIGMAP: @@ -2088,7 +2201,7 @@ void HandleUI(void) /******************************************************************/ case MENU_MAIN1: menumask = 0xFF0; // b01110000 Floppy turbo, Harddisk options & Exit. - OsdSetTitle("Minimig", OSD_ARROW_RIGHT); + OsdSetTitle("Minimig", OSD_ARROW_RIGHT | OSD_ARROW_LEFT); helptext = helptexts[HELPTEXT_MAIN]; OsdWrite(0, "", 0, 0); @@ -2243,6 +2356,11 @@ void HandleUI(void) menustate = MENU_8BIT_SYSTEM1; menusub = 0; } + else if (left) + { + menustate = MENU_8BIT_INFO; + menusub = 0; + } break; case MENU_FILE_SELECTED: // file successfully selected diff --git a/osd.h b/osd.h index c7abbff..21eb11e 100644 --- a/osd.h +++ b/osd.h @@ -66,9 +66,9 @@ #include /*functions*/ -void OsdSetTitle(const char *s, int arrow); // arrow > 0 = display right arrow in bottom right, < 0 = display left arrow +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, unsigned char stipple, char usebg = 0); +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 OsdClear(void); void OsdEnable(unsigned char mode); diff --git a/releases/MiSTer_20181116 b/releases/MiSTer_20181116 new file mode 100644 index 0000000..c2f3ae6 Binary files /dev/null and b/releases/MiSTer_20181116 differ diff --git a/releases/MiSTer_20181121 b/releases/MiSTer_20181121 new file mode 100644 index 0000000..c759ca1 Binary files /dev/null and b/releases/MiSTer_20181121 differ diff --git a/releases/MiSTer_20181129 b/releases/MiSTer_20181129 new file mode 100644 index 0000000..85261c1 Binary files /dev/null and b/releases/MiSTer_20181129 differ diff --git a/support.h b/support.h index a0373ad..73ce1d9 100644 --- a/support.h +++ b/support.h @@ -15,4 +15,7 @@ #include "support/st/st_tos.h" // X86 support -#include "support/x86/x86.h" \ No newline at end of file +#include "support/x86/x86.h" + +// SNES support +#include "support/snes/snes.h" diff --git a/support/snes/snes.cpp b/support/snes/snes.cpp new file mode 100644 index 0000000..0f897e8 --- /dev/null +++ b/support/snes/snes.cpp @@ -0,0 +1,160 @@ + +#include +#include +#include +#include + +#include "../../file_io.h" + +static uint8_t hdr[512]; + +enum HeaderField { + CartName = 0x00, + Mapper = 0x15, + RomType = 0x16, + RomSize = 0x17, + RamSize = 0x18, + CartRegion = 0x19, + Company = 0x1a, + Version = 0x1b, + Complement = 0x1c, //inverse checksum + Checksum = 0x1e, + ResetVector = 0x3c, +}; + +static uint32_t score_header(const uint8_t *data, uint32_t size, uint32_t addr) +{ + if (size < addr + 64) return 0; //image too small to contain header at this location? + int score = 0; + + uint16_t resetvector = data[addr + ResetVector] | (data[addr + ResetVector + 1] << 8); + uint16_t checksum = data[addr + Checksum] | (data[addr + Checksum + 1] << 8); + uint16_t complement = data[addr + Complement] | (data[addr + Complement + 1] << 8); + + uint8_t resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset + uint8_t mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit + + //$00:[0000-7fff] contains uninitialized RAM and MMIO. + //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. + if (resetvector < 0x8000) return 0; + + //some images duplicate the header in multiple locations, and others have completely + //invalid header information that cannot be relied upon. + //below code will analyze the first opcode executed at the specified reset vector to + //determine the probability that this is the correct header. + + //most likely opcodes + if (resetop == 0x78 //sei + || resetop == 0x18 //clc (clc; xce) + || resetop == 0x38 //sec (sec; xce) + || resetop == 0x9c //stz $nnnn (stz $4200) + || resetop == 0x4c //jmp $nnnn + || resetop == 0x5c //jml $nnnnnn + ) score += 8; + + //plausible opcodes + if (resetop == 0xc2 //rep #$nn + || resetop == 0xe2 //sep #$nn + || resetop == 0xad //lda $nnnn + || resetop == 0xae //ldx $nnnn + || resetop == 0xac //ldy $nnnn + || resetop == 0xaf //lda $nnnnnn + || resetop == 0xa9 //lda #$nn + || resetop == 0xa2 //ldx #$nn + || resetop == 0xa0 //ldy #$nn + || resetop == 0x20 //jsr $nnnn + || resetop == 0x22 //jsl $nnnnnn + ) score += 4; + + //implausible opcodes + if (resetop == 0x40 //rti + || resetop == 0x60 //rts + || resetop == 0x6b //rtl + || resetop == 0xcd //cmp $nnnn + || resetop == 0xec //cpx $nnnn + || resetop == 0xcc //cpy $nnnn + ) score -= 4; + + //least likely opcodes + if (resetop == 0x00 //brk #$nn + || resetop == 0x02 //cop #$nn + || resetop == 0xdb //stp + || resetop == 0x42 //wdm + || resetop == 0xff //sbc $nnnnnn,x + ) score -= 8; + + //at times, both the header and reset vector's first opcode will match ... + //fallback and rely on info validity in these cases to determine more likely header. + + //a valid checksum is the biggest indicator of a valid header. + if ((checksum + complement) == 0xffff && (checksum != 0) && (complement != 0)) score += 4; + + if (addr == 0x007fc0 && mapper == 0x20) score += 2; //0x20 is usually LoROM + if (addr == 0x00ffc0 && mapper == 0x21) score += 2; //0x21 is usually HiROM + if (addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually SDD1 + if (addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM + + if (data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header + if (data[addr + RomType] < 0x08) score++; + if (data[addr + RomSize] < 0x10) score++; + if (data[addr + RamSize] < 0x08) score++; + if (data[addr + CartRegion] < 14) score++; + + if (score < 0) score = 0; + return score; +} + +static uint32_t find_header(const uint8_t *data, uint32_t size) +{ + uint32_t score_lo = score_header(data, size, 0x007fc0); + uint32_t score_hi = score_header(data, size, 0x00ffc0); + uint32_t score_ex = score_header(data, size, 0x40ffc0); + if (score_ex) score_ex += 4; //favor ExHiROM on images > 32mbits + + if (score_lo >= score_hi && score_lo >= score_ex) + { + return score_lo ? 0x007fc0 : 0; + } + else if (score_hi >= score_ex) + { + return score_hi ? 0x00ffc0 : 0; + } + + return score_ex ? 0x40ffc0 : 0; +} + +uint8_t* snes_get_header(fileTYPE *f) +{ + memset(hdr, 0, sizeof(hdr)); + uint8_t *buf = (uint8_t*)malloc(f->size); + if (buf) + { + FileSeekLBA(f, 0); + if (FileReadAdv(f, buf, f->size)) + { + uint32_t addr = find_header(buf, f->size); + if (addr) + { + uint8_t romsz = buf[addr + RomSize]; + uint8_t ramsz = buf[addr + RamSize]; + if (romsz >= 0x10) romsz = 0; + if (ramsz >= 0x08) ramsz = 0; + hdr[0] = (ramsz << 4) | romsz; + + hdr[1] = (addr == 0x00ffc0) ? 1 : (addr == 0x40ffc0) ? 5 : 0; //LHRom type + + hdr[2] = buf[addr + RomType]; + + if ((buf[addr + CartRegion] >= 0x02 && buf[addr + CartRegion] <= 0x0C) || buf[addr + CartRegion] == 0x11) + { //PAL Regions + hdr[3] |= 1; + } + + *(uint32_t*)(&hdr[4]) = addr; + } + } + FileSeekLBA(f, 0); + free(buf); + } + return hdr; +} diff --git a/support/snes/snes.h b/support/snes/snes.h new file mode 100644 index 0000000..8651d4e --- /dev/null +++ b/support/snes/snes.h @@ -0,0 +1,6 @@ +#ifndef SNES_H +#define SNES_H + +uint8_t* snes_get_header(fileTYPE *f); + +#endif diff --git a/user_io.cpp b/user_io.cpp index f59bd15..161ca63 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -152,6 +152,13 @@ char is_x86_core() return (is_x86_type == 1); } +static int is_snes_type = 0; +char is_snes_core() +{ + if (!is_snes_type) is_snes_type = strcasecmp(core_name, "SNES") ? 2 : 1; + return (is_snes_type == 1); +} + char is_cpc_core() { return !strcasecmp(core_name, "amstrad"); @@ -858,7 +865,7 @@ void user_io_set_index(unsigned char index) DisableFpga(); } -int user_io_file_mount(char *name, unsigned char index) +int user_io_file_mount(char *name, unsigned char index, char pre) { int writable = 0; int ret = 0; @@ -876,10 +883,18 @@ int user_io_file_mount(char *name, unsigned char index) if (!ret) { - writable = 0; sd_image[index].size = 0; printf("Failed to open file %s\n", name); - printf("Eject image from %d slot\n", index); + if (pre) + { + writable = 1; + printf("Will be created upon write\n"); + } + else + { + writable = 0; + printf("Eject image from %d slot\n", index); + } } else { @@ -891,17 +906,26 @@ int user_io_file_mount(char *name, unsigned char index) // send mounted image size first then notify about mounting EnableIO(); spi8(UIO_SET_SDINFO); + + __off64_t size = sd_image[index].size; + if (!ret && pre) + { + size = -1; + sd_image[index].type = 2; + strcpy(sd_image[index].path, name); + } + if (io_ver) { - spi_w((uint16_t)(sd_image[index].size)); - spi_w((uint16_t)(sd_image[index].size>>16)); - spi_w((uint16_t)(sd_image[index].size>>32)); - spi_w((uint16_t)(sd_image[index].size>>48)); + spi_w((uint16_t)(size)); + spi_w((uint16_t)(size>>16)); + spi_w((uint16_t)(size>>32)); + spi_w((uint16_t)(size>>48)); } else { - spi32le(sd_image[index].size); - spi32le(sd_image[index].size>>32); + spi32le(size); + spi32le(size>>32); } DisableIO(); @@ -1243,6 +1267,17 @@ int user_io_file_tx(const char* name, unsigned char index, char opensave, char m } else { + if (is_snes_core()) + { + printf("Load SNES ROM.\n"); + uint8_t* buf = snes_get_header(&f); + hexdump(buf, 16, 0); + EnableFpga(); + spi8(UIO_FILE_TX_DAT); + spi_write(buf, 512, fio_size); + DisableFpga(); + } + while (bytes2send) { printf("."); @@ -1268,7 +1303,7 @@ int user_io_file_tx(const char* name, unsigned char index, char opensave, char m char *p = strrchr((char*)buf, '.'); if (!p) p = (char*)buf + strlen(name); strcpy(p, ".sav"); - user_io_file_mount((char*)buf); + user_io_file_mount((char*)buf, 0, 1); } // signal end of transmission @@ -1630,6 +1665,7 @@ void user_io_poll() { //printf("SD WR %d on %d\n", lba, disk); + int done = 0; buffer_lba[disk] = lba; // Fetch sector data from FPGA ... @@ -1637,15 +1673,43 @@ void user_io_poll() spi_block_read(buffer[disk], fio_size); DisableIO(); - // ... and write it to disk - int done = 0; - if ((sd_image[disk].size>>9)>lba) + if (sd_image[disk].type == 2 && !lba) { - diskled_on(); - if (FileSeekLBA(&sd_image[disk], lba)) + //Create the file + if (FileOpenEx(&sd_image[disk], sd_image[disk].path, O_CREAT | O_RDWR | O_SYNC)) { - if (FileWriteSec(&sd_image[disk], buffer[disk])) done = 1; + diskled_on(); + if (FileWriteSec(&sd_image[disk], buffer[disk])) + { + sd_image[disk].size = 512; + done = 1; + } + } + else + { + printf("Error in creating file: %s\n", sd_image[disk].path); + } + } + else + { + // ... and write it to disk + __off64_t size = sd_image[disk].size>>9; + if (size && size>=lba) + { + diskled_on(); + if (FileSeekLBA(&sd_image[disk], lba)) + { + if (FileWriteSec(&sd_image[disk], buffer[disk])) + { + done = 1; + if (size == lba) + { + size++; + sd_image[disk].size = size << 9; + } + } + } } } @@ -1681,7 +1745,6 @@ void user_io_poll() //Even after error we have to provide the block to the core //Give an empty block. if (!done) memset(buffer[disk], 0, sizeof(buffer[disk])); - buffer_lba[disk] = lba; } @@ -1710,6 +1773,11 @@ void user_io_poll() } } if(done) buffer_lba[disk] = lba + 1; + + if (sd_image[disk].type == 2) + { + buffer_lba[disk] = -1; + } } } @@ -2579,11 +2647,25 @@ static void setPLL(double Fout) vitems[20] = k; } -static void setScalerCoeff() +static char scaler_flt_cfg[1024] = { 0 }; +static char new_scaler = 0; + +static void setScaler() { fileTYPE f = { 0 }; static char filename[1024]; - sprintf(filename, "%s/coeff.txt", HomeDir); + + if (!spi_uio_cmd_cont(UIO_SET_FLTNUM)) + { + DisableIO(); + return; + } + + new_scaler = 1; + spi8(scaler_flt_cfg[0]); + DisableIO(); + sprintf(filename, COEFF_DIR"/%s", scaler_flt_cfg + 1); + if (FileOpen(&f, filename)) { printf("Read scaler coefficients\n"); @@ -2594,7 +2676,7 @@ static void setScalerCoeff() int size; if (size = FileReadAdv(&f, buf, f.size)) { - spi_uio_cmd_cont(UIO_SET_VIPCOEF); + spi_uio_cmd_cont(UIO_SET_FLTCOEF); char *end = buf + size; char *pos = buf; @@ -2633,9 +2715,44 @@ static void setScalerCoeff() } } +int user_io_get_scaler_flt() +{ + return new_scaler ? scaler_flt_cfg[0] : -1; +} + +char* user_io_get_scaler_coeff() +{ + return scaler_flt_cfg + 1; +} + +void user_io_set_scaler_flt(int n) +{ + scaler_flt_cfg[0] = (char)n; + FileSaveConfig("scaler.cfg", &scaler_flt_cfg, sizeof(scaler_flt_cfg)); + spi_uio_cmd8(UIO_SET_FLTNUM, scaler_flt_cfg[0]); + spi_uio_cmd(UIO_SET_FLTCOEF); +} + +void user_io_set_scaler_coeff(char *name) +{ + strcpy(scaler_flt_cfg + 1, name); + FileSaveConfig("scaler.cfg", &scaler_flt_cfg, sizeof(scaler_flt_cfg)); + setScaler(); + user_io_send_buttons(1); +} + +static void loadScalerCfg() +{ + if (!FileLoadConfig("scaler.cfg", &scaler_flt_cfg, sizeof(scaler_flt_cfg) - 1) || scaler_flt_cfg[0]>4) + { + memset(scaler_flt_cfg, 0, sizeof(scaler_flt_cfg)); + } +} + static void setVideo() { - setScalerCoeff(); + loadScalerCfg(); + setScaler(); printf("Send HDMI parameters:\n"); spi_uio_cmd_cont(UIO_SET_VIDEO); diff --git a/user_io.h b/user_io.h index 6773d8c..c31e69a 100644 --- a/user_io.h +++ b/user_io.h @@ -62,7 +62,8 @@ #define UIO_SETHEIGHT 0x27 // Set scaled vertical resolution (to reduce scaling artefacts) #define UIO_GETUARTFLG 0x28 // Get UART_FLG_* #define UIO_GET_STATUS 0x29 // Update status from the core -#define UIO_SET_VIPCOEF 0x2A // Set Scaler coefficients +#define UIO_SET_FLTCOEF 0x2A // Set Scaler polyphase coefficients +#define UIO_SET_FLTNUM 0x2B // Set Scaler predefined filter // codes as used by 8bit for file loading from OSD #define UIO_FILE_TX 0x53 @@ -188,13 +189,14 @@ void user_io_serial_tx(char *, uint16_t); char *user_io_8bit_get_string(char); unsigned long user_io_8bit_set_status(unsigned long, unsigned long); int user_io_file_tx(const char* name, unsigned char index = 0, char opensave = 0, char mute = 0, char composite = 0); -int user_io_file_mount(char *name, unsigned char index = 0); +int user_io_file_mount(char *name, unsigned char index = 0, char pre = 0); char user_io_dip_switch1(void); char user_io_serial_status(serial_status_t *, uint8_t); char *user_io_get_core_name(); const char *user_io_get_core_name_ex(); char is_menu_core(); char is_x86_core(); +char is_snes_core(); char has_menu(); int user_io_get_kbdemu(); @@ -234,6 +236,11 @@ int hasAPI1_5(); const char* get_rbf_dir(); const char* get_rbf_name(); +int user_io_get_scaler_flt(); +char* user_io_get_scaler_coeff(); +void user_io_set_scaler_flt(int n); +void user_io_set_scaler_coeff(char *name); + #define HomeDir (is_minimig() ? "Amiga" : is_archie() ? "Archie" : user_io_get_core_name()) #endif // USER_IO_H