diff --git a/MiSTer.vcxproj b/MiSTer.vcxproj index 870f043..5f9a3a9 100644 --- a/MiSTer.vcxproj +++ b/MiSTer.vcxproj @@ -86,6 +86,7 @@ + @@ -135,6 +136,7 @@ + diff --git a/MiSTer.vcxproj.filters b/MiSTer.vcxproj.filters index e8118cd..8c36384 100644 --- a/MiSTer.vcxproj.filters +++ b/MiSTer.vcxproj.filters @@ -142,6 +142,9 @@ Source Files + + Source Files + @@ -285,5 +288,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/file_io.cpp b/file_io.cpp index 7abe7d0..5dddd5e 100644 --- a/file_io.cpp +++ b/file_io.cpp @@ -25,6 +25,7 @@ #include "input.h" #include "miniz_zip.h" #include "scheduler.h" +#include "video.h" #define MIN(a,b) (((a)<(b)) ? (a) : (b)) @@ -766,7 +767,7 @@ void FindStorage(void) device = 0; MiSTer_ini_parse(); device = saveddev; - parse_video_mode(); + video_mode_load(); user_io_send_buttons(1); printf("Waiting for USB...\n"); diff --git a/input.cpp b/input.cpp index 5ee2083..aa12a78 100644 --- a/input.cpp +++ b/input.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "input.h" #include "user_io.h" @@ -16,7 +17,7 @@ #include "cfg.h" #include "fpga_io.h" #include "osd.h" -#include "errno.h" +#include "video.h" #define NUMDEV 20 #define NUMPLAYERS 6 @@ -998,6 +999,8 @@ typedef struct uint8_t has_kbdmap; uint8_t kbdmap[256]; + uint16_t guncal[4]; + int accx, accy; int quirk; @@ -1242,6 +1245,24 @@ void finish_map_setting(int dismiss) } } +void input_lightgun_cal(uint16_t *cal) +{ + FileSaveConfig("wiimote_cal.cfg", cal, 4 * sizeof(uint16_t)); + for (int i = 0; i < NUMDEV; i++) + { + if (input[i].quirk == QUIRK_WIIMOTE) memcpy(input[i].guncal, cal, sizeof(input[i].guncal)); + } +} + +int input_has_lightgun() +{ + for (int i = 0; i < NUMDEV; i++) + { + if (input[i].quirk == QUIRK_WIIMOTE) return 1; + } + return 0; +} + uint16_t get_map_vid() { return (mapping && mapping_dev >= 0) ? input[mapping_dev].vid : 0; @@ -2330,6 +2351,11 @@ int input_test(int getchar) else { input[n].quirk = QUIRK_WIIMOTE; + input[n].guncal[0] = 0; + input[n].guncal[1] = 767; + input[n].guncal[2] = 1; + input[n].guncal[3] = 1023; + FileLoadConfig("wiimote_cal.cfg", input[n].guncal, 4 * sizeof(uint16_t)); } } @@ -2465,7 +2491,6 @@ int input_test(int getchar) input[dev].lightgun = 0; if (absinfo.maximum == 1023 || absinfo.maximum == 767) { - if (user_io_osd_is_visible()) continue; if (ev.code == 16) { ev.value = absinfo.maximum - ev.value; @@ -2597,6 +2622,33 @@ int input_test(int getchar) } } + if (ev.type == EV_ABS && input[i].quirk == QUIRK_WIIMOTE && input[dev].lightgun) + { + menu_lightgun_cb(ev.type, ev.code, ev.value); + + // don't pass IR tracking to OSD + if (user_io_osd_is_visible()) continue; + + if (!ev.code) + { + absinfo.minimum = input[i].guncal[2]; + absinfo.maximum = input[i].guncal[3]; + } + else + { + absinfo.minimum = input[i].guncal[0]; + absinfo.maximum = input[i].guncal[1]; + } + } + + if (ev.type == EV_KEY && user_io_osd_is_visible()) + { + if (input[i].quirk == QUIRK_WIIMOTE) + { + if (menu_lightgun_cb(ev.type, ev.code, ev.value)) continue; + } + } + if(!noabs) input_cb(&ev, &absinfo, i); //sumulate digital directions from analog diff --git a/input.h b/input.h index b835f93..1c201db 100644 --- a/input.h +++ b/input.h @@ -52,4 +52,7 @@ uint32_t get_amiga_code(uint16_t key); uint32_t get_atari_code(uint16_t key); uint32_t get_archie_code(uint16_t key); +int input_has_lightgun(); +void input_lightgun_cal(uint16_t *cal); + #endif diff --git a/menu.cpp b/menu.cpp index eec62d9..d7790ea 100644 --- a/menu.cpp +++ b/menu.cpp @@ -36,6 +36,7 @@ along with this program. If not, see . #include #include #include +#include #include #include "file_io.h" #include "osd.h" @@ -49,6 +50,7 @@ along with this program. If not, see . #include "battery.h" #include "bootcore.h" #include "cheats.h" +#include "video.h" #include "support.h" @@ -111,6 +113,9 @@ enum MENU MENU_BTPAIR, MENU_WMPAIR, MENU_WMPAIR1, + MENU_LGCAL, + MENU_LGCAL1, + MENU_LGCAL2, MENU_CHEATS1, MENU_CHEATS2, @@ -734,6 +739,12 @@ const char* get_rbf_name_bootcore(char *str) static int joymap_first = 0; +static int wm_x = 0; +static int wm_y = 0; +static int wm_ok = 0; +static int wm_side = 0; +static uint16_t wm_pos[4] = {}; + void HandleUI(void) { switch (user_io_core_type()) @@ -816,6 +827,15 @@ void HandleUI(void) { menustate = MENU_WMPAIR; } + else if(input_has_lightgun()) + { + menustate = MENU_LGCAL; + } + break; + + //debug + case KEY_F9: + video_fb_enable(!video_fb_state()); break; // Within the menu the esc key acts as the menu key. problem: @@ -1152,7 +1172,7 @@ void HandleUI(void) while((p[0] == 'H' || p[0] == 'D') && strlen(p)>2) { int flg = (hdmask & (1< 2) { int flg = (hdmask & (1 << getIdx(p))) ? 1 : 0; - if (p[0] == 'H') h = flg; else d = flg; + if (p[0] == 'H') h |= flg; else d |= flg; p += 2; } @@ -1503,22 +1523,22 @@ void HandleUI(void) OsdWrite(n++, s, menusub == 3); } - if (user_io_get_scaler_flt() >= 0) + if (video_get_scaler_flt() >= 0) { OsdWrite(n++); menumask |= 0x60; - sprintf(s, " Scale Filter - %s", config_scaler_msg[user_io_get_scaler_flt() ? 1 : 0]); + sprintf(s, " Scale Filter - %s", config_scaler_msg[video_get_scaler_flt() ? 1 : 0]); OsdWrite(n++, s, menusub == 5); memset(s, 0, sizeof(s)); s[0] = ' '; - if (strlen(user_io_get_scaler_coeff())) strncpy(s+1, user_io_get_scaler_coeff(),25); + if (strlen(video_get_scaler_coeff())) strncpy(s+1, video_get_scaler_coeff(),25); else strcpy(s, " < none >"); while(strlen(s) < 26) strcat(s, " "); strcat(s, " \x16 "); - OsdWrite(n++, s, menusub == 6, !user_io_get_scaler_flt() || !S_ISDIR(getFileType(COEFF_DIR))); + OsdWrite(n++, s, menusub == 6, !video_get_scaler_flt() || !S_ISDIR(getFileType(COEFF_DIR))); } m = 0; @@ -1603,14 +1623,14 @@ void HandleUI(void) break; case 5: - user_io_set_scaler_flt(user_io_get_scaler_flt() ? 0 : 1); + video_set_scaler_flt(video_get_scaler_flt() ? 0 : 1); menustate = MENU_8BIT_SYSTEM1; break; case 6: - if (user_io_get_scaler_flt()) + if (video_get_scaler_flt()) { - sprintf(SelectedPath, COEFF_DIR"/%s", user_io_get_scaler_coeff()); + sprintf(SelectedPath, COEFF_DIR"/%s", video_get_scaler_coeff()); SelectFile(0, SCANO_COEFF, MENU_COEFF_FILE_SELECTED, MENU_8BIT_SYSTEM1); } break; @@ -1809,8 +1829,8 @@ void HandleUI(void) 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); + if (!p) video_set_scaler_coeff(SelectedPath); + else video_set_scaler_coeff(p+1); menustate = MENU_8BIT_SYSTEM1; } break; @@ -2796,7 +2816,7 @@ void HandleUI(void) OsdWrite(m++, " Startup config:"); for (uint i = 0; i < 10; i++) { - const char *info = minimig_GetCfgInfo(i); + const char *info = minimig_get_cfg_info(i); static char name[128]; if (info) @@ -2838,7 +2858,7 @@ void HandleUI(void) if (menusub<10) { OsdDisable(); - minimig_LoadCfg(menusub); + minimig_cfg_load(menusub); menustate = MENU_NONE1; } else @@ -3071,7 +3091,7 @@ void HandleUI(void) if (m) { menustate = MENU_NONE1; - MinimigReset(); + minimig_reset(); } else if(m == 2) { @@ -3107,7 +3127,7 @@ void HandleUI(void) OsdWrite(m++, " Startup config:"); for (uint i = 0; i < 10; i++) { - const char *info = minimig_GetCfgInfo(i); + const char *info = minimig_get_cfg_info(i); static char name[128]; if (info) @@ -3166,7 +3186,7 @@ void HandleUI(void) strncat(minimig_config.info, p, sizeof(minimig_config.info) - strlen(minimig_config.info) - 1); minimig_config.info[sizeof(minimig_config.info) - 1] = 0; - if (menusub<10) minimig_SaveCfg(menusub); + if (menusub<10) minimig_cfg_save(menusub); menustate = MENU_MAIN1; menusub = 9; } @@ -3397,7 +3417,7 @@ void HandleUI(void) break; case MENU_ROMFILE_SELECTED: - SetKickstart(SelectedPath); + minimig_set_kickstart(SelectedPath); menustate = MENU_SETTINGS_MEMORY1; break; @@ -3585,7 +3605,7 @@ void HandleUI(void) OsdWrite(5, s, menusub == 3, 0); OsdWrite(6, "", 0, 0); OsdWrite(7, "", 0, 0); - OsdWrite(8, user_io_minimig_get_adjust() ? " Finish screen adjustment" : " Adjust screen position", menusub == 4, 0); + OsdWrite(8, minimig_get_adjust() ? " Finish screen adjustment" : " Adjust screen position", menusub == 4, 0); OsdWrite(9, "", 0, 0); OsdWrite(10, "", 0, 0); OsdWrite(11, "", 0, 0); @@ -3630,7 +3650,7 @@ void HandleUI(void) else if (menusub == 4) { menustate = MENU_NONE1; - user_io_minimig_set_adjust(!user_io_minimig_get_adjust()); + minimig_set_adjust(minimig_get_adjust() ? 0 : 1); } else if (menusub == 5) { @@ -3816,6 +3836,49 @@ void HandleUI(void) if (CheckTimer(menu_timer)) menustate = MENU_NONE1; break; + case MENU_LGCAL: + helptext = 0; + OsdSetTitle("Wiimote Calibration", 0); + for (int i = 0; i < OsdGetSize(); i++) OsdWrite(i); + OsdWrite(9, " Point Wiimote to the edge"); + OsdWrite(10, " of screen and press"); + OsdWrite(11, " the button B to confirm"); + OsdWrite(OsdGetSize() - 1, " Cancel", menusub == 0, 0); + wm_ok = 0; + wm_side = 0; + memset(wm_pos, 0, sizeof(wm_pos)); + menustate = MENU_LGCAL1; + menusub = 0; + break; + + case MENU_LGCAL1: + if (wm_side < 4) wm_pos[wm_side] = (wm_side < 2) ? wm_y : wm_x; + sprintf(s, " %c%04d%c", (wm_side == 0) ? 17 : 32, (wm_side == 0) ? wm_y : wm_pos[0], (wm_side == 0) ? 16 : 32); + OsdWrite(0, s); + sprintf(s, "%c%04d%c %c%04d%c", (wm_side == 2) ? 17 : 32, (wm_side == 2) ? wm_x : wm_pos[2], (wm_side == 2) ? 16 : 32, + (wm_side == 3) ? 17 : 32, (wm_side == 3) ? wm_x : wm_pos[3], (wm_side == 3) ? 16 : 32); + OsdWrite(7, s); + sprintf(s, " %c%04d%c", (wm_side == 1) ? 17 : 32, (wm_side == 1) ? wm_y : wm_pos[1], (wm_side == 1) ? 16 : 32); + OsdWrite(13, s); + if (menu || select) menustate = MENU_NONE1; + + if (wm_ok == 1) + { + wm_ok = 0; + wm_side++; + } + + if (wm_ok == 2) + { + wm_ok = 0; + if (wm_side == 4) + { + input_lightgun_cal(wm_pos); + menustate = MENU_NONE1; + } + } + break; + case MENU_SCRIPTS_PRE: OsdSetTitle("Warning!!!", 0); helptext = 0; @@ -3880,6 +3943,11 @@ void HandleUI(void) for (int i = 0; i < script_lines; i++) strcpy(script_output[i], ""); script_line=0; script_exited = false; + cpu_set_t set; + CPU_ZERO(&set); + CPU_SET(0, &set); + CPU_SET(1, &set); + sched_setaffinity(0, sizeof(set), &set); script_pipe=popen((parentstate != MENU_BTPAIR) ? getFullPath(SelectedPath) : "/usr/sbin/btpair", "r"); script_file = fileno(script_pipe); fcntl(script_file, F_SETFL, O_NONBLOCK); @@ -3906,6 +3974,10 @@ void HandleUI(void) } else { pclose(script_pipe); + cpu_set_t set; + CPU_ZERO(&set); + CPU_SET(1, &set); + sched_setaffinity(0, sizeof(set), &set); script_exited=true; OsdWrite(OsdGetSize() - 1, " OK", menusub == 0, 0); }; @@ -3919,6 +3991,10 @@ void HandleUI(void) strcat(script_command, (parentstate == MENU_BTPAIR) ? "btpair" : flist_SelectedItem()->d_name); system(script_command); pclose(script_pipe); + cpu_set_t set; + CPU_ZERO(&set); + CPU_SET(1, &set); + sched_setaffinity(0, sizeof(set), &set); script_exited = true; }; @@ -4378,3 +4454,23 @@ void menu_bt_pair() { menustate = MENU_BTPAIR; } + +int menu_lightgun_cb(uint16_t type, uint16_t code, int value) +{ + if (type == EV_ABS) + { + if (code == 0 && value) wm_x = value; + if (code == 1 && value != 1023) wm_y = value; + } + + if (type == EV_KEY) + { + if (code == 0x131 && menustate == MENU_LGCAL1) + { + if (value == 1) wm_ok = 1; + if (value == 0) wm_ok = 2; + return 1; + } + } + return 0; +} diff --git a/menu.h b/menu.h index 2b8f250..3cec841 100644 --- a/menu.h +++ b/menu.h @@ -30,4 +30,6 @@ extern int joy_bcount; void open_joystick_setup(); void menu_bt_pair(); +int menu_lightgun_cb(uint16_t type, uint16_t code, int value); + #endif diff --git a/releases/MiSTer_20190515 b/releases/MiSTer_20190515 new file mode 100644 index 0000000..c0df0ed Binary files /dev/null and b/releases/MiSTer_20190515 differ diff --git a/support/minimig/minimig_boot.cpp b/support/minimig/minimig_boot.cpp index 7245d33..13fe2bf 100644 --- a/support/minimig/minimig_boot.cpp +++ b/support/minimig/minimig_boot.cpp @@ -445,7 +445,7 @@ void BootInit() } minimig_config.kickstart[0] = 0; - minimig_LoadCfg(0); + minimig_cfg_load(0); } void BootPrintEx(const char * str) diff --git a/support/minimig/minimig_config.cpp b/support/minimig/minimig_config.cpp index 600581d..3e9d6da 100644 --- a/support/minimig/minimig_config.cpp +++ b/support/minimig/minimig_config.cpp @@ -267,12 +267,12 @@ static char* GetConfigurationName(int num, int chk) return name+strlen(CONFIG_DIR)+1; } -int minimig_SaveCfg(int num) +int minimig_cfg_save(int num) { return FileSaveConfig(GetConfigurationName(num, 0), &minimig_config, sizeof(minimig_config)); } -const char* minimig_GetCfgInfo(int num) +const char* minimig_get_cfg_info(int num) { char *filename = GetConfigurationName(num, 1); if (!filename) return NULL; @@ -366,7 +366,7 @@ static void ApplyConfiguration(char reloadkickstart) ConfigAutofire(minimig_config.autofire, 0xC); } -int minimig_LoadCfg(int num) +int minimig_cfg_load(int num) { static const char config_id[] = "MNMGCFG0"; char updatekickstart = 0; @@ -486,13 +486,13 @@ int minimig_LoadCfg(int num) return(result); } -void MinimigReset() +void minimig_reset() { ApplyConfiguration(0); user_io_rtc_reset(); } -void SetKickstart(char *name) +void minimig_set_kickstart(char *name) { uint len = strlen(name); if (len > (sizeof(minimig_config.kickstart) - 1)) len = sizeof(minimig_config.kickstart) - 1; @@ -500,3 +500,127 @@ void SetKickstart(char *name) minimig_config.kickstart[len] = 0; force_reload_kickstart = 1; } + +static char minimig_adjust = 0; + +typedef struct +{ + uint32_t mode; + uint32_t hpos; + uint32_t vpos; + uint32_t reserved; +} vmode_adjust_t; + +vmode_adjust_t vmodes_adj[64] = {}; + +static void adjust_vsize(char force) +{ + static uint16_t nres = 0; + spi_uio_cmd_cont(UIO_GET_VMODE); + uint16_t res = spi_w(0); + if ((res & 0x8000) && (nres != res || force)) + { + nres = res; + uint16_t scr_hsize = spi_w(0); + uint16_t scr_vsize = spi_w(0); + DisableIO(); + + printf("\033[1;37mVMODE: resolution: %u x %u, mode: %u\033[0m\n", scr_hsize, scr_vsize, res & 255); + + static int loaded = 0; + if (~loaded) + { + FileLoadConfig("minimig_vadjust.dat", vmodes_adj, sizeof(vmodes_adj)); + loaded = 1; + } + + uint32_t mode = scr_hsize | (scr_vsize << 12) | ((res & 0xFF) << 24); + if (mode) + { + for (uint i = 0; i < sizeof(vmodes_adj) / sizeof(vmodes_adj[0]); i++) + { + if (vmodes_adj[i].mode == mode) + { + spi_uio_cmd_cont(UIO_SET_VPOS); + spi_w(vmodes_adj[i].hpos >> 16); + spi_w(vmodes_adj[i].hpos); + spi_w(vmodes_adj[i].vpos >> 16); + spi_w(vmodes_adj[i].vpos); + printf("\033[1;37mVMODE: set positions: [%u-%u, %u-%u]\033[0m\n", vmodes_adj[i].hpos >> 16, (uint16_t)vmodes_adj[i].hpos, vmodes_adj[i].vpos >> 16, (uint16_t)vmodes_adj[i].vpos); + DisableIO(); + return; + } + } + printf("\033[1;37mVMODE: preset not found.\033[0m\n"); + spi_uio_cmd_cont(UIO_SET_VPOS); spi_w(0); spi_w(0); spi_w(0); spi_w(0); + DisableIO(); + } + } + else + { + DisableIO(); + } +} + +static void store_vsize() +{ + Info("Stored"); + minimig_adjust = 0; + + spi_uio_cmd_cont(UIO_GET_VMODE); + uint16_t res = spi_w(0); + uint16_t scr_hsize = spi_w(0); + uint16_t scr_vsize = spi_w(0); + uint16_t scr_hbl_l = spi_w(0); + uint16_t scr_hbl_r = spi_w(0); + uint16_t scr_vbl_t = spi_w(0); + uint16_t scr_vbl_b = spi_w(0); + DisableIO(); + + printf("\033[1;37mVMODE: store position: [%u-%u, %u-%u]\033[0m\n", scr_hbl_l, scr_hbl_r, scr_vbl_t, scr_vbl_b); + + uint32_t mode = scr_hsize | (scr_vsize << 12) | ((res & 0xFF) << 24); + if (mode) + { + int applied = 0; + int empty = -1; + for (int i = 0; (uint)i < sizeof(vmodes_adj) / sizeof(vmodes_adj[0]); i++) + { + if (vmodes_adj[i].mode == mode) + { + vmodes_adj[i].hpos = (scr_hbl_l << 16) | scr_hbl_r; + vmodes_adj[i].vpos = (scr_vbl_t << 16) | scr_vbl_b; + applied = 1; + } + if (empty < 0 && !vmodes_adj[i].mode) empty = i; + } + + if (!applied && empty >= 0) + { + vmodes_adj[empty].mode = mode; + vmodes_adj[empty].hpos = (scr_hbl_l << 16) | scr_hbl_r; + vmodes_adj[empty].vpos = (scr_vbl_t << 16) | scr_vbl_b; + applied = 1; + } + + if (applied) + { + FileSaveConfig("minimig_vadjust.dat", vmodes_adj, sizeof(vmodes_adj)); + } + } +} + +// 0 - disable +// 1 - enable +// 2 - cancel +void minimig_set_adjust(char n) +{ + if (minimig_adjust && !n) store_vsize(); + minimig_adjust = (n == 1) ? 1 : 0; + if (n == 2) adjust_vsize(1); +} + +char minimig_get_adjust() +{ + return minimig_adjust; +} diff --git a/support/minimig/minimig_config.h b/support/minimig/minimig_config.h index 1a16c9b..612a434 100644 --- a/support/minimig/minimig_config.h +++ b/support/minimig/minimig_config.h @@ -44,11 +44,14 @@ typedef struct extern mm_configTYPE minimig_config; -int minimig_LoadCfg(int num); -int minimig_SaveCfg(int num); -const char* minimig_GetCfgInfo(int num); +int minimig_cfg_load(int num); +int minimig_cfg_save(int num); +const char* minimig_get_cfg_info(int num); -void MinimigReset(); -void SetKickstart(char *name); +void minimig_reset(); +void minimig_set_kickstart(char *name); + +void minimig_set_adjust(char n); +char minimig_get_adjust(); #endif diff --git a/support/snes/snes.cpp b/support/snes/snes.cpp index bb75f24..734cebd 100644 --- a/support/snes/snes.cpp +++ b/support/snes/snes.cpp @@ -177,25 +177,28 @@ uint8_t* snes_get_header(fileTYPE *f) { //DSP1 hdr[1] |= 0x80; } - else if (buf[addr + Mapper] == 0x20 && buf[addr + RomType] == 0x05) - { //DSP2 - hdr[1] |= 0x90; - } - else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0x05 && buf[addr + Company] == 0xb2) - { //DSP3 - hdr[1] |= 0xA0; - } - else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0x03) - { //DSP4 - hdr[1] |= 0xB0; - } + else if (buf[addr + Mapper] == 0x20 && buf[addr + RomType] == 0x05) + { //DSP2 + hdr[1] |= 0x90; + } + else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0x05 && buf[addr + Company] == 0xb2) + { //DSP3 + hdr[1] |= 0xA0; + } + else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0x03) + { //DSP4 + hdr[1] |= 0xB0; + } else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0xf6) - { - //ST010 + { //ST010 hdr[1] |= 0x88; if(buf[addr + RomSize] < 10) hdr[1] |= 0x20; // ST011 //ramsz = 2; } + else if (buf[addr + Mapper] == 0x30 && buf[addr + RomType] == 0x25) + { //OBC1 + hdr[1] |= 0xC0; + } //CX4 4 if (buf[addr + Mapper] == 0x20 && buf[addr + RomType] == 0xf3) @@ -224,7 +227,7 @@ uint8_t* snes_get_header(fileTYPE *f) hdr[1] |= 0x70; } - //1..3,C..F - reserved for other mappers. + //1..3,D..F - reserved for other mappers. hdr[2] = 0; diff --git a/user_io.cpp b/user_io.cpp index 6a9b9ad..c89ea2c 100644 --- a/user_io.cpp +++ b/user_io.cpp @@ -30,6 +30,7 @@ #include "scaler.h" #include "miniz.h" #include "cheats.h" +#include "video.h" #include "support.h" @@ -68,8 +69,6 @@ static bool caps_status = 0; static bool num_status = 0; static bool scrl_status = 0; -static char minimig_adjust = 0; - static char last_filename[1024] = {}; void user_io_store_filename(char *filename) { @@ -533,7 +532,8 @@ void user_io_init(const char *path) { bootcore_init(path); } - parse_video_mode(); + + video_mode_load(); if(strlen(cfg.font)) LoadFont(cfg.font); FileLoadConfig("Volume.dat", &vol_att, 1); vol_att &= 0x1F; @@ -1574,8 +1574,6 @@ void user_io_rtc_reset() static int coldreset_req = 0; -static int adjust_video_mode(uint32_t vtime); -static uint32_t show_video_info(int force); static uint32_t res_timer = 0; void user_io_poll() @@ -2149,15 +2147,9 @@ void user_io_poll() else if(CheckTimer(res_timer)) { res_timer = GetTimer(500); - if (!minimig_adjust) + if (!minimig_get_adjust()) { - uint32_t vtime = show_video_info(0); - if (vtime && cfg.vsync_adjust && !is_menu_core()) - { - adjust_video_mode(vtime); - usleep(100000); - show_video_info(1); - } + video_mode_adjust(); } } @@ -2196,19 +2188,6 @@ char user_io_user_button() return((!user_io_menu_button() && (fpga_get_buttons() & BUTTON_USR)) ? 1 : 0); } -static void adjust_vsize(char force); -static void store_vsize(); -void user_io_minimig_set_adjust(char n) -{ - if (minimig_adjust & !n) store_vsize(); - minimig_adjust = n; -} - -char user_io_minimig_get_adjust() -{ - return minimig_adjust; -} - static void send_keycode(unsigned short key, int press) { if (core_type == CORE_TYPE_MINIMIG2) @@ -2239,11 +2218,11 @@ static void send_keycode(unsigned short key, int press) } code &= 0xff; - if (minimig_adjust) + if (minimig_get_adjust()) { if (code == 0x44) { - store_vsize(); + minimig_set_adjust(0); res_timer = 0; return; } @@ -2252,8 +2231,7 @@ static void send_keycode(unsigned short key, int press) { Info("Canceled"); res_timer = 0; - minimig_adjust = 0; - adjust_vsize(1); + minimig_set_adjust(2); return; } code |= OSD; @@ -2470,7 +2448,7 @@ void user_io_check_reset(unsigned short modifiers, char useKeys) switch (core_type) { case CORE_TYPE_MINIMIG2: - MinimigReset(); + minimig_reset(); break; case CORE_TYPE_ARCHIE: @@ -2714,578 +2692,3 @@ unsigned char user_io_ext_idx(char *name, char* ext) printf("not found! use 0\n"); return 0; } - -struct vmode_t -{ - uint32_t vpar[8]; - double Fpix; -}; - -vmode_t vmodes[] = -{ - { { 1280, 110, 40, 220, 720, 5, 5, 20 }, 74.25 }, //0 - { { 1024, 24, 136, 160, 768, 3, 6, 29 }, 65 }, //1 - { { 720, 16, 62, 60, 480, 9, 6, 30 }, 27 }, //2 - { { 720, 12, 64, 68, 576, 5, 5, 39 }, 27 }, //3 - { { 1280, 48, 112, 248, 1024, 1, 3, 38 }, 108 }, //4 - { { 800, 40, 128, 88, 600, 1, 4, 23 }, 40 }, //5 - { { 640, 16, 96, 48, 480, 10, 2, 33 }, 25.175 }, //6 - { { 1280, 440, 40, 220, 720, 5, 5, 20 }, 74.25 }, //7 - { { 1920, 88, 44, 148, 1080, 4, 5, 36 }, 148.5 }, //8 - { { 1920, 528, 44, 148, 1080, 4, 5, 36 }, 148.5 }, //9 - { { 1366, 70, 143, 213, 768, 3, 3, 24 }, 85.5 }, //10 - { { 1024, 40, 104, 144, 600, 1, 3, 18 }, 48.96 }, //11 -}; -#define VMODES_NUM (sizeof(vmodes) / sizeof(vmodes[0])) - -struct vmode_custom_t -{ - uint32_t item[32]; - double Fpix; -}; - -static vmode_custom_t v_cur = {}, v_def = {}, v_pal = {}, v_ntsc = {}; -static int vmode_def = 0, vmode_pal = 0, vmode_ntsc = 0; - -static uint32_t getPLLdiv(uint32_t div) -{ - if (div & 1) return 0x20000 | (((div / 2) + 1) << 8) | (div / 2); - return ((div / 2) << 8) | (div / 2); -} - -static int findPLLpar(double Fout, uint32_t *pc, uint32_t *pm, double *pko) -{ - uint32_t c = 1; - while ((Fout*c) < 400) c++; - - while (1) - { - double fvco = Fout*c; - uint32_t m = (uint32_t)(fvco / 50); - double ko = ((fvco / 50) - m); - - fvco = ko + m; - fvco *= 50.f; - - if (ko && (ko <= 0.05f || ko >= 0.95f)) - { - printf("Fvco=%f, C=%d, M=%d, K=%f ", fvco, c, m, ko); - if (fvco > 1500.f) - { - printf("-> No exact parameters found\n"); - return 0; - } - printf("-> K is outside allowed range\n"); - c++; - } - else - { - *pc = c; - *pm = m; - *pko = ko; - return 1; - } - } - - //will never reach here - return 0; -} - -static void setPLL(double Fout, vmode_custom_t *v) -{ - double Fpix; - double fvco, ko; - uint32_t m, c; - - printf("Calculate PLL for %.4f MHz:\n", Fout); - - if (!findPLLpar(Fout, &c, &m, &ko)) - { - c = 1; - while ((Fout*c) < 400) c++; - - fvco = Fout*c; - m = (uint32_t)(fvco / 50); - ko = ((fvco / 50) - m); - - //Make sure K is in allowed range. - if (ko <= 0.05f) - { - ko = 0; - } - else if (ko >= 0.95f) - { - m++; - ko = 0; - } - } - - uint32_t k = ko ? (uint32_t)(ko * 4294967296) : 1; - - fvco = ko + m; - fvco *= 50.f; - Fpix = fvco / c; - - printf("Fvco=%f, C=%d, M=%d, K=%f(%u) -> Fpix=%f\n", fvco, c, m, ko, k, Fpix); - - v->item[9] = 4; - v->item[10] = getPLLdiv(m); - v->item[11] = 3; - v->item[12] = 0x10000; - v->item[13] = 5; - v->item[14] = getPLLdiv(c); - v->item[15] = 9; - v->item[16] = 2; - v->item[17] = 8; - v->item[18] = 7; - v->item[19] = 7; - v->item[20] = k; - - v->Fpix = Fpix; -} - -static char scaler_flt_cfg[1024] = { 0 }; -static char new_scaler = 0; - -static void setScaler() -{ - fileTYPE f = {}; - static char filename[1024]; - - 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"); - char *buf = (char*)malloc(f.size+1); - if (buf) - { - memset(buf, 0, f.size + 1); - int size; - if ((size = FileReadAdv(&f, buf, f.size))) - { - spi_uio_cmd_cont(UIO_SET_FLTCOEF); - - char *end = buf + size; - char *pos = buf; - int phase = 0; - while (pos < end) - { - char *st = pos; - while ((pos < end) && *pos && (*pos != 10)) pos++; - *pos = 0; - while (*st == ' ' || *st == '\t' || *st == 13) st++; - if (*st == '#' || *st == ';' || !*st) pos++; - else - { - int c0, c1, c2, c3; - int n = sscanf(st, "%d,%d,%d,%d", &c0, &c1, &c2, &c3); - if (n == 4) - { - printf(" phase %c-%02d: %4d,%4d,%4d,%4d\n", (phase >= 16) ? 'V' : 'H', phase % 16, c0, c1, c2, c3); - //printf("%03X: %03X %03X %03X %03X;\n",phase*4, c0 & 0x1FF, c1 & 0x1FF, c2 & 0x1FF, c3 & 0x1FF); - - spi_w((c0 & 0x1FF) | (((phase * 4) + 0) << 9)); - spi_w((c1 & 0x1FF) | (((phase * 4) + 1) << 9)); - spi_w((c2 & 0x1FF) | (((phase * 4) + 2) << 9)); - spi_w((c3 & 0x1FF) | (((phase * 4) + 3) << 9)); - - phase++; - if (phase >= 32) break; - } - } - } - DisableIO(); - } - - free(buf); - } - } -} - -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; -} - -static char scaler_cfg[128] = { 0 }; - -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() -{ - sprintf(scaler_cfg, "%s_scaler.cfg", user_io_get_core_name_ex()); - 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(vmode_custom_t *v) -{ - loadScalerCfg(); - setScaler(); - - printf("Send HDMI parameters:\n"); - spi_uio_cmd_cont(UIO_SET_VIDEO); - printf("video: "); - for (int i = 1; i <= 8; i++) - { - v_cur.item[i] = v->item[i]; - spi_w(v->item[i]); - printf("%d, ", v->item[i]); - } - printf("\nPLL: "); - for (int i = 9; i < 21; i++) - { - v_cur.item[i] = v->item[i]; - printf("0x%X, ", v->item[i]); - if (i & 1) spi_w(v->item[i] | ((i == 9 && (is_menu_core() ? cfg.menu_pal : (cfg.vsync_adjust == 2))) ? 0x8000 : 0)); - else - { - spi_w(v->item[i]); - spi_w(v->item[i] >> 16); - } - } - - v_cur.Fpix = v->Fpix; - printf("Fpix=%f\n", v->Fpix); - DisableIO(); -} - -static int parse_custom_video_mode(char* vcfg, vmode_custom_t *v) -{ - int khz = 0; - int cnt = 0; - char *orig = vcfg; - while (*vcfg) - { - char *next; - if (cnt == 9 && v->item[0] == 1) - { - double Fpix = khz ? strtoul(vcfg, &next, 0)/1000.f : strtod(vcfg, &next); - if (vcfg == next || (Fpix < 2.f || Fpix > 300.f)) - { - printf("Error parsing video_mode parameter: ""%s""\n", orig); - return -1; - } - - setPLL(Fpix, v); - break; - } - - uint32_t val = strtoul(vcfg, &next, 0); - if (vcfg == next || (*next != ',' && *next)) - { - printf("Error parsing video_mode parameter: ""%s""\n", orig); - return -1; - } - - if (!cnt && val >= 100) - { - v->item[cnt++] = 1; - khz = 1; - } - if (cnt < 32) v->item[cnt] = val; - if (*next == ',') next++; - vcfg = next; - cnt++; - } - - if (cnt == 1) - { - printf("Set predefined video_mode to %d\n", v->item[0]); - return v->item[0]; - } - - if ((v->item[0] == 0 && cnt < 21) || (v->item[0] == 1 && cnt < 9)) - { - printf("Incorrect amount of items in video_mode parameter: %d\n", cnt); - return -1; - } - - if (v->item[0] > 1) - { - printf("Incorrect video_mode parameter\n"); - return -1; - } - - return -2; -} - -static int store_custom_video_mode(char* vcfg, vmode_custom_t *v) -{ - int ret = parse_custom_video_mode(vcfg, v); - if (ret == -2) return 1; - - uint mode = (ret < 0) ? 0 : ret; - if (mode >= VMODES_NUM) mode = 0; - for (int i = 0; i < 8; i++) v->item[i + 1] = vmodes[mode].vpar[i]; - setPLL(vmodes[mode].Fpix, v); - - return ret >= 0; -} - -void parse_video_mode() -{ - vmode_def = store_custom_video_mode(cfg.video_conf, &v_def); - vmode_pal = store_custom_video_mode(cfg.video_conf_pal, &v_pal); - vmode_ntsc = store_custom_video_mode(cfg.video_conf_ntsc, &v_ntsc); - setVideo(&v_def); -} - -static int adjust_video_mode(uint32_t vtime) -{ - printf("\033[1;33madjust_video_mode(%u): vsync_adjust=%d", vtime, cfg.vsync_adjust); - - vmode_custom_t *v = &v_def; - if (vmode_pal && vmode_ntsc) - { - if (vtime > 1800000) - { - printf(", using PAL mode"); - v = &v_pal; - } - else - { - printf(", using NTSC mode"); - v = &v_ntsc; - } - } - - printf(".\033[0m\n"); - - double Fpix = 100 * (v->item[1] + v->item[2] + v->item[3] + v->item[4]) * (v->item[5] + v->item[6] + v->item[7] + v->item[8]); - Fpix /= vtime; - if (Fpix < 2.f || Fpix > 300.f) - { - printf("Estimated Fpix(%.4f MHz) is outside supported range. Canceling auto-adjust.\n", Fpix); - return 0; - } - - setPLL(Fpix, v); - setVideo(v); - user_io_send_buttons(1); - return 1; -} - -typedef struct -{ - uint32_t mode; - uint32_t hpos; - uint32_t vpos; - uint32_t reserved; -} vmode_adjust_t; - -vmode_adjust_t vmodes_adj[64] = {}; - -static void adjust_vsize(char force) -{ - static uint16_t nres = 0; - spi_uio_cmd_cont(UIO_GET_VMODE); - uint16_t res = spi_w(0); - if ((res & 0x8000) && (nres != res || force)) - { - nres = res; - uint16_t scr_hsize = spi_w(0); - uint16_t scr_vsize = spi_w(0); - DisableIO(); - - printf("\033[1;37mVMODE: resolution: %u x %u, mode: %u\033[0m\n", scr_hsize, scr_vsize, res & 255); - - static int loaded = 0; - if (~loaded) - { - FileLoadConfig("minimig_vadjust.dat", vmodes_adj, sizeof(vmodes_adj)); - loaded = 1; - } - - uint32_t mode = scr_hsize | (scr_vsize << 12) | ((res & 0xFF) << 24); - if (mode) - { - for (uint i = 0; i < sizeof(vmodes_adj) / sizeof(vmodes_adj[0]); i++) - { - if (vmodes_adj[i].mode == mode) - { - spi_uio_cmd_cont(UIO_SET_VPOS); - spi_w(vmodes_adj[i].hpos >> 16); - spi_w(vmodes_adj[i].hpos); - spi_w(vmodes_adj[i].vpos >> 16); - spi_w(vmodes_adj[i].vpos); - printf("\033[1;37mVMODE: set positions: [%u-%u, %u-%u]\033[0m\n", vmodes_adj[i].hpos >> 16, (uint16_t)vmodes_adj[i].hpos, vmodes_adj[i].vpos >> 16, (uint16_t)vmodes_adj[i].vpos); - DisableIO(); - return; - } - } - printf("\033[1;37mVMODE: preset not found.\033[0m\n"); - spi_uio_cmd_cont(UIO_SET_VPOS); spi_w(0); spi_w(0); spi_w(0); spi_w(0); - DisableIO(); - } - } - else - { - DisableIO(); - } -} - -static void store_vsize() -{ - Info("Stored"); - minimig_adjust = 0; - - spi_uio_cmd_cont(UIO_GET_VMODE); - uint16_t res = spi_w(0); - uint16_t scr_hsize = spi_w(0); - uint16_t scr_vsize = spi_w(0); - uint16_t scr_hbl_l = spi_w(0); - uint16_t scr_hbl_r = spi_w(0); - uint16_t scr_vbl_t = spi_w(0); - uint16_t scr_vbl_b = spi_w(0); - DisableIO(); - - printf("\033[1;37mVMODE: store position: [%u-%u, %u-%u]\033[0m\n", scr_hbl_l, scr_hbl_r, scr_vbl_t, scr_vbl_b); - - uint32_t mode = scr_hsize | (scr_vsize << 12) | ((res & 0xFF) << 24); - if (mode) - { - int applied = 0; - int empty = -1; - for (int i = 0; (uint)i < sizeof(vmodes_adj) / sizeof(vmodes_adj[0]); i++) - { - if (vmodes_adj[i].mode == mode) - { - vmodes_adj[i].hpos = (scr_hbl_l << 16) | scr_hbl_r; - vmodes_adj[i].vpos = (scr_vbl_t << 16) | scr_vbl_b; - applied = 1; - } - if (empty < 0 && !vmodes_adj[i].mode) empty = i; - } - - if (!applied && empty >= 0) - { - vmodes_adj[empty].mode = mode; - vmodes_adj[empty].hpos = (scr_hbl_l << 16) | scr_hbl_r; - vmodes_adj[empty].vpos = (scr_vbl_t << 16) | scr_vbl_b; - applied = 1; - } - - if (applied) - { - FileSaveConfig("minimig_vadjust.dat", vmodes_adj, sizeof(vmodes_adj)); - } - } -} - -static int api1_5 = 0; -static uint32_t show_video_info(int force) -{ - uint32_t ret = 0; - static uint8_t nres = 0; - spi_uio_cmd_cont(UIO_GET_VRES); - uint8_t res = spi_in(); - if ((nres != res) || force) - { - nres = res; - uint32_t width = spi_w(0) | (spi_w(0) << 16); - uint32_t height = spi_w(0) | (spi_w(0) << 16); - uint32_t htime = spi_w(0) | (spi_w(0) << 16); - uint32_t vtime = spi_w(0) | (spi_w(0) << 16); - uint32_t ptime = spi_w(0) | (spi_w(0) << 16); - uint32_t vtimeh = spi_w(0) | (spi_w(0) << 16); - DisableIO(); - - float vrate = 100000000; - if (vtime) vrate /= vtime; else vrate = 0; - float hrate = 100000; - if (htime) hrate /= htime; else hrate = 0; - - float prate = width * 100; - prate /= ptime; - - printf("\033[1;33mINFO: Video resolution: %u x %u, fHorz = %.1fKHz, fVert = %.1fHz, fPix = %.2fMHz\033[0m\n", width, height, hrate, vrate, prate); - printf("\033[1;33mINFO: Frame time (100MHz counter): VGA = %d, HDMI = %d\033[0m\n", vtime, vtimeh); - - if (vtimeh) api1_5 = 1; - if (hasAPI1_5() && cfg.video_info) - { - static char str[128]; - float vrateh = 100000000; - if (vtimeh) vrateh /= vtimeh; else vrateh = 0; - sprintf(str, "%4dx%-4d %6.2fKHz %4.1fHz\n" \ - "\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\n" \ - "%4dx%-4d %6.2fMHz %4.1fHz", - width, height, hrate, vrate, v_cur.item[1], v_cur.item[5], v_cur.Fpix, vrateh); - Info(str, cfg.video_info * 1000); - } - - uint32_t scrh = v_cur.item[5]; - if (height && scrh) - { - if (cfg.vscale_border) - { - uint32_t border = cfg.vscale_border * 2; - if ((border + 100) > scrh) border = scrh - 100; - scrh -= border; - } - - if (cfg.vscale_mode) - { - uint32_t div = 1 << (cfg.vscale_mode - 1); - uint32_t mag = (scrh*div) / height; - scrh = (height * mag) / div; - } - - if(cfg.vscale_border || cfg.vscale_mode) - { - printf("*** Set vertical scaling to : %d\n", scrh); - spi_uio_cmd16(UIO_SETHEIGHT, scrh); - } - else - { - spi_uio_cmd16(UIO_SETHEIGHT, 0); - } - } - - if (vtime && vtimeh) ret = vtime; - } - else - { - DisableIO(); - } - - adjust_vsize(0); - return ret; -} - -int hasAPI1_5() -{ - return api1_5; -} diff --git a/user_io.h b/user_io.h index 76aa667..cee5d09 100644 --- a/user_io.h +++ b/user_io.h @@ -67,6 +67,8 @@ #define UIO_GET_VMODE 0x2C // Get video mode parameters #define UIO_SET_VPOS 0x2D // Set video positions #define UIO_GET_OSDMASK 0x2E // Get mask +#define UIO_SET_FBUF 0x2F // Set frame buffer for HPS output +#define UIO_WAIT_VSYNC 0x30 // Wait for VSync // codes as used by 8bit for file loading from OSD #define UIO_FILE_TX 0x53 @@ -222,7 +224,6 @@ void user_io_set_joyswap(int swap); int user_io_get_joyswap(); char user_io_osd_is_visible(); void user_io_send_buttons(char); -void parse_video_mode(); void user_io_set_index(unsigned char index); unsigned char user_io_ext_idx(char *, char*); @@ -231,19 +232,9 @@ void user_io_check_reset(unsigned short modifiers, char useKeys); void user_io_rtc_reset(); -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); - -void user_io_minimig_set_adjust(char n); -char user_io_minimig_get_adjust(); - #define HomeDir (is_minimig() ? "Amiga" : is_archie() ? "Archie" : is_menu_core() ? "Scripts" : user_io_get_core_name()) int GetUARTMode(); diff --git a/video.cpp b/video.cpp new file mode 100644 index 0000000..e24608d --- /dev/null +++ b/video.cpp @@ -0,0 +1,635 @@ +#include +#include +#include +#include +#include + +#include "hardware.h" +#include "user_io.h" +#include "spi.h" +#include "cfg.h" +#include "file_io.h" +#include "menu.h" +#include "video.h" + +#include "support.h" + +#define FB_SIZE (1024*1024*8) // 8MB x 3 +#define FB_ADDR (0x20000000 + (32*1024*1024)) // 512mb + 32mb(Core's fb) +#define FB_FMT 2 // 0 - 16bit, 1 - 24bit(not supported), 2 - 32bit +#define FB_HDRSZ (256/(FB_FMT+2)) + +#if(FB_FMT == 2) + static volatile uint32_t *fb_base = 0; +#else + static volatile uint16_t *fb_base = 0; +#endif + +static int fb_enabled = 0; +static int fb_width = 0; +static int fb_height = 0; +static int fb_stride = 0; + +struct vmode_t +{ + uint32_t vpar[8]; + double Fpix; +}; + +vmode_t vmodes[] = +{ + { { 1280, 110, 40, 220, 720, 5, 5, 20 }, 74.25 }, //0 + { { 1024, 24, 136, 160, 768, 3, 6, 29 }, 65 }, //1 + { { 720, 16, 62, 60, 480, 9, 6, 30 }, 27 }, //2 + { { 720, 12, 64, 68, 576, 5, 5, 39 }, 27 }, //3 + { { 1280, 48, 112, 248, 1024, 1, 3, 38 }, 108 }, //4 + { { 800, 40, 128, 88, 600, 1, 4, 23 }, 40 }, //5 + { { 640, 16, 96, 48, 480, 10, 2, 33 }, 25.175 }, //6 + { { 1280, 440, 40, 220, 720, 5, 5, 20 }, 74.25 }, //7 + { { 1920, 88, 44, 148, 1080, 4, 5, 36 }, 148.5 }, //8 + { { 1920, 528, 44, 148, 1080, 4, 5, 36 }, 148.5 }, //9 + { { 1366, 70, 143, 213, 768, 3, 3, 24 }, 85.5 }, //10 + { { 1024, 40, 104, 144, 600, 1, 3, 18 }, 48.96 }, //11 +}; +#define VMODES_NUM (sizeof(vmodes) / sizeof(vmodes[0])) + +struct vmode_custom_t +{ + uint32_t item[32]; + double Fpix; +}; + +static vmode_custom_t v_cur = {}, v_def = {}, v_pal = {}, v_ntsc = {}; +static int vmode_def = 0, vmode_pal = 0, vmode_ntsc = 0; + +static uint32_t getPLLdiv(uint32_t div) +{ + if (div & 1) return 0x20000 | (((div / 2) + 1) << 8) | (div / 2); + return ((div / 2) << 8) | (div / 2); +} + +static int findPLLpar(double Fout, uint32_t *pc, uint32_t *pm, double *pko) +{ + uint32_t c = 1; + while ((Fout*c) < 400) c++; + + while (1) + { + double fvco = Fout*c; + uint32_t m = (uint32_t)(fvco / 50); + double ko = ((fvco / 50) - m); + + fvco = ko + m; + fvco *= 50.f; + + if (ko && (ko <= 0.05f || ko >= 0.95f)) + { + printf("Fvco=%f, C=%d, M=%d, K=%f ", fvco, c, m, ko); + if (fvco > 1500.f) + { + printf("-> No exact parameters found\n"); + return 0; + } + printf("-> K is outside allowed range\n"); + c++; + } + else + { + *pc = c; + *pm = m; + *pko = ko; + return 1; + } + } + + //will never reach here + return 0; +} + +static void setPLL(double Fout, vmode_custom_t *v) +{ + double Fpix; + double fvco, ko; + uint32_t m, c; + + printf("Calculate PLL for %.4f MHz:\n", Fout); + + if (!findPLLpar(Fout, &c, &m, &ko)) + { + c = 1; + while ((Fout*c) < 400) c++; + + fvco = Fout*c; + m = (uint32_t)(fvco / 50); + ko = ((fvco / 50) - m); + + //Make sure K is in allowed range. + if (ko <= 0.05f) + { + ko = 0; + } + else if (ko >= 0.95f) + { + m++; + ko = 0; + } + } + + uint32_t k = ko ? (uint32_t)(ko * 4294967296) : 1; + + fvco = ko + m; + fvco *= 50.f; + Fpix = fvco / c; + + printf("Fvco=%f, C=%d, M=%d, K=%f(%u) -> Fpix=%f\n", fvco, c, m, ko, k, Fpix); + + v->item[9] = 4; + v->item[10] = getPLLdiv(m); + v->item[11] = 3; + v->item[12] = 0x10000; + v->item[13] = 5; + v->item[14] = getPLLdiv(c); + v->item[15] = 9; + v->item[16] = 2; + v->item[17] = 8; + v->item[18] = 7; + v->item[19] = 7; + v->item[20] = k; + + v->Fpix = Fpix; +} + +static char scaler_flt_cfg[1024] = { 0 }; +static char new_scaler = 0; + +static void setScaler() +{ + fileTYPE f = {}; + static char filename[1024]; + + 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"); + char *buf = (char*)malloc(f.size+1); + if (buf) + { + memset(buf, 0, f.size + 1); + int size; + if ((size = FileReadAdv(&f, buf, f.size))) + { + spi_uio_cmd_cont(UIO_SET_FLTCOEF); + + char *end = buf + size; + char *pos = buf; + int phase = 0; + while (pos < end) + { + char *st = pos; + while ((pos < end) && *pos && (*pos != 10)) pos++; + *pos = 0; + while (*st == ' ' || *st == '\t' || *st == 13) st++; + if (*st == '#' || *st == ';' || !*st) pos++; + else + { + int c0, c1, c2, c3; + int n = sscanf(st, "%d,%d,%d,%d", &c0, &c1, &c2, &c3); + if (n == 4) + { + //printf(" phase %c-%02d: %4d,%4d,%4d,%4d\n", (phase >= 16) ? 'V' : 'H', phase % 16, c0, c1, c2, c3); + //printf("%03X: %03X %03X %03X %03X;\n",phase*4, c0 & 0x1FF, c1 & 0x1FF, c2 & 0x1FF, c3 & 0x1FF); + + spi_w((c0 & 0x1FF) | (((phase * 4) + 0) << 9)); + spi_w((c1 & 0x1FF) | (((phase * 4) + 1) << 9)); + spi_w((c2 & 0x1FF) | (((phase * 4) + 2) << 9)); + spi_w((c3 & 0x1FF) | (((phase * 4) + 3) << 9)); + + phase++; + if (phase >= 32) break; + } + } + } + DisableIO(); + } + + free(buf); + } + } +} + +int video_get_scaler_flt() +{ + return new_scaler ? scaler_flt_cfg[0] : -1; +} + +char* video_get_scaler_coeff() +{ + return scaler_flt_cfg + 1; +} + +static char scaler_cfg[128] = { 0 }; + +void video_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 video_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() +{ + sprintf(scaler_cfg, "%s_scaler.cfg", user_io_get_core_name_ex()); + 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 set_video(vmode_custom_t *v, double Fpix) +{ + loadScalerCfg(); + setScaler(); + + printf("Send HDMI parameters:\n"); + spi_uio_cmd_cont(UIO_SET_VIDEO); + printf("video: "); + for (int i = 1; i <= 8; i++) + { + v_cur.item[i] = v->item[i]; + spi_w(v_cur.item[i]); + printf("%d, ", v_cur.item[i]); + } + + for (int i = 9; i < 21; i++) v_cur.item[i] = v->item[i]; + v_cur.Fpix = v->Fpix; + + if(Fpix) setPLL(Fpix, &v_cur); + + printf("\nPLL: "); + for (int i = 9; i < 21; i++) + { + printf("0x%X, ", v_cur.item[i]); + if (i & 1) spi_w(v_cur.item[i] | ((i == 9 && (is_menu_core() ? cfg.menu_pal : (Fpix && cfg.vsync_adjust == 2))) ? 0x8000 : 0)); + else + { + spi_w(v_cur.item[i]); + spi_w(v_cur.item[i] >> 16); + } + } + + printf("Fpix=%f\n", v_cur.Fpix); + DisableIO(); +} + +static int parse_custom_video_mode(char* vcfg, vmode_custom_t *v) +{ + int khz = 0; + int cnt = 0; + char *orig = vcfg; + while (*vcfg) + { + char *next; + if (cnt == 9 && v->item[0] == 1) + { + double Fpix = khz ? strtoul(vcfg, &next, 0)/1000.f : strtod(vcfg, &next); + if (vcfg == next || (Fpix < 2.f || Fpix > 300.f)) + { + printf("Error parsing video_mode parameter: ""%s""\n", orig); + return -1; + } + + setPLL(Fpix, v); + break; + } + + uint32_t val = strtoul(vcfg, &next, 0); + if (vcfg == next || (*next != ',' && *next)) + { + printf("Error parsing video_mode parameter: ""%s""\n", orig); + return -1; + } + + if (!cnt && val >= 100) + { + v->item[cnt++] = 1; + khz = 1; + } + if (cnt < 32) v->item[cnt] = val; + if (*next == ',') next++; + vcfg = next; + cnt++; + } + + if (cnt == 1) + { + printf("Set predefined video_mode to %d\n", v->item[0]); + return v->item[0]; + } + + if ((v->item[0] == 0 && cnt < 21) || (v->item[0] == 1 && cnt < 9)) + { + printf("Incorrect amount of items in video_mode parameter: %d\n", cnt); + return -1; + } + + if (v->item[0] > 1) + { + printf("Incorrect video_mode parameter\n"); + return -1; + } + + return -2; +} + +static int store_custom_video_mode(char* vcfg, vmode_custom_t *v) +{ + int ret = parse_custom_video_mode(vcfg, v); + if (ret == -2) return 1; + + uint mode = (ret < 0) ? 0 : ret; + if (mode >= VMODES_NUM) mode = 0; + for (int i = 0; i < 8; i++) v->item[i + 1] = vmodes[mode].vpar[i]; + setPLL(vmodes[mode].Fpix, v); + + return ret >= 0; +} + +static void fb_init() +{ + if (!fb_base) + { + static int fd; + fb_base = 0; + + if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) return; + +#if(FB_FMT == 2) + fb_base = (volatile uint32_t*)mmap(0, FB_SIZE * 3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, FB_ADDR); +#else + fb_base = (volatile uint16_t*)mmap(0, FB_SIZE * 3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, FB_ADDR); +#endif + if (fb_base == (void *)-1) + { + printf("Unable to mmap FB!\n"); + fb_base = 0; + close(fd); + } + } +} + +void video_mode_load() +{ + fb_init(); + vmode_def = store_custom_video_mode(cfg.video_conf, &v_def); + vmode_pal = store_custom_video_mode(cfg.video_conf_pal, &v_pal); + vmode_ntsc = store_custom_video_mode(cfg.video_conf_ntsc, &v_ntsc); + set_video(&v_def, 0); +} + +static int api1_5 = 0; +int hasAPI1_5() +{ + return api1_5; +} + +static uint32_t show_video_info(int force) +{ + uint32_t ret = 0; + static uint16_t nres = 0; + spi_uio_cmd_cont(UIO_GET_VRES); + uint16_t res = spi_w(0); + if ((nres != res) || force) + { + nres = res; + uint32_t width = spi_w(0) | (spi_w(0) << 16); + uint32_t height = spi_w(0) | (spi_w(0) << 16); + uint32_t htime = spi_w(0) | (spi_w(0) << 16); + uint32_t vtime = spi_w(0) | (spi_w(0) << 16); + uint32_t ptime = spi_w(0) | (spi_w(0) << 16); + uint32_t vtimeh = spi_w(0) | (spi_w(0) << 16); + DisableIO(); + + float vrate = 100000000; + if (vtime) vrate /= vtime; else vrate = 0; + float hrate = 100000; + if (htime) hrate /= htime; else hrate = 0; + + float prate = width * 100; + prate /= ptime; + + printf("\033[1;33mINFO: Video resolution: %u x %u%s, fHorz = %.1fKHz, fVert = %.1fHz, fPix = %.2fMHz\033[0m\n", width, height, (res & 0x100) ? "i" : "", hrate, vrate, prate); + printf("\033[1;33mINFO: Frame time (100MHz counter): VGA = %d, HDMI = %d\033[0m\n", vtime, vtimeh); + + if (vtimeh) api1_5 = 1; + if (hasAPI1_5() && cfg.video_info) + { + static char str[128], res1[16], res2[16]; + float vrateh = 100000000; + if (vtimeh) vrateh /= vtimeh; else vrateh = 0; + sprintf(res1, "%dx%d%s", width, height, (res & 0x100) ? "i" : ""); + sprintf(res2, "%dx%d", v_cur.item[1], v_cur.item[5]); + sprintf(str, "%9s %6.2fKHz %4.1fHz\n" \ + "\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\x81\n" \ + "%9s %6.2fMHz %4.1fHz", + res1, hrate, vrate, res2, v_cur.Fpix, vrateh); + Info(str, cfg.video_info * 1000); + } + + uint32_t scrh = v_cur.item[5]; + if (height && scrh) + { + if (cfg.vscale_border) + { + uint32_t border = cfg.vscale_border * 2; + if ((border + 100) > scrh) border = scrh - 100; + scrh -= border; + } + + if (cfg.vscale_mode) + { + uint32_t div = 1 << (cfg.vscale_mode - 1); + uint32_t mag = (scrh*div) / height; + scrh = (height * mag) / div; + } + + if(cfg.vscale_border || cfg.vscale_mode) + { + printf("Set vertical scaling to : %d\n", scrh); + spi_uio_cmd16(UIO_SETHEIGHT, scrh); + } + else + { + spi_uio_cmd16(UIO_SETHEIGHT, 0); + } + } + + if (vtime && vtimeh) ret = vtime; + } + else + { + DisableIO(); + } + + minimig_set_adjust(2); + return ret; +} + +void video_mode_adjust() +{ + uint32_t vtime = show_video_info(0); + if (vtime && cfg.vsync_adjust && !is_menu_core()) + { + printf("\033[1;33madjust_video_mode(%u): vsync_adjust=%d", vtime, cfg.vsync_adjust); + + int adjust = 1; + vmode_custom_t *v = &v_def; + if (vmode_pal || vmode_ntsc) + { + if (vtime > 1800000) + { + if (vmode_pal) + { + printf(", using PAL mode"); + v = &v_pal; + } + else + { + printf(", PAL mode cannot be used. Using predefined NTSC mode"); + v = &v_ntsc; + adjust = 0; + } + } + else + { + if (vmode_ntsc) + { + printf(", using NTSC mode"); + v = &v_ntsc; + } + else + { + printf(", NTSC mode cannot be used. Using predefined PAL mode"); + v = &v_pal; + adjust = 0; + } + } + } + + printf(".\033[0m\n"); + + double Fpix = 0; + if (adjust) + { + Fpix = 100 * (v->item[1] + v->item[2] + v->item[3] + v->item[4]) * (v->item[5] + v->item[6] + v->item[7] + v->item[8]); + Fpix /= vtime; + if (Fpix < 2.f || Fpix > 300.f) + { + printf("Estimated Fpix(%.4f MHz) is outside supported range. Canceling auto-adjust.\n", Fpix); + Fpix = 0; + } + } + + set_video(v, Fpix); + user_io_send_buttons(1); + usleep(100000); + show_video_info(1); + } +} + +static void fill_fb() +{ + int pos = 0; + for (int y = 0; y < fb_height; y++) + { + pos = y * fb_stride + FB_HDRSZ; + int base_color = (y / 32) & 7; + for (int x = 0; x < fb_width; x++) + { +#if(FB_FMT == 2) + int gray = (256 * x) / fb_width; + uint32_t color = 0; + if (base_color & 1) color |= gray; + if (base_color & 2) color |= gray << 8; + if (base_color & 4) color |= gray << 16; +#else + int gray = (32 * x) / fb_width; + uint16_t color = 0; + if (base_color & 1) color |= gray; + if (base_color & 2) color |= gray << 5; + if (base_color & 4) color |= gray << 10; +#endif + fb_base[pos++] = color; + } + } +} + +void video_fb_enable(int enable) +{ + if (fb_base) + { + int res = spi_uio_cmd_cont(UIO_SET_FBUF); + if (res) + { + if (enable) + { + fb_width = (v_cur.item[1] >= 1440) ? v_cur.item[1] / 2 : v_cur.item[1]; + fb_height = (v_cur.item[5] >= 1080) ? v_cur.item[5] / 2 : v_cur.item[5]; + + printf("Switch to HPS frame buffer\n"); + spi_w(0x8000 | (FB_FMT & 3) << 12); // enable flag, format, fixed height + spi_w((uint16_t)FB_ADDR); // base address low word + spi_w(FB_ADDR >> 16); // base address high word + spi_w(fb_width-1); // frame width + spi_w(fb_height-1); // frame height + spi_w(0); // Aspect ratio X/Y (0 - full screen) + +#if(FB_FMT == 2) + fb_stride = (((fb_width * 4 + 255) / 256) * 256)/4; +#else + fb_stride = (((fb_width * 2 + 255) / 256) * 256)/2; +#endif + + printf("HPS frame buffer: %dx%d, stride = %d items\n", fb_width, fb_height, fb_stride); + + fill_fb(); + } + else + { + printf("Switch to core frame buffer\n"); + spi_w(0); // enable flag + } + fb_enabled = enable; + } + else + { + printf("Core doesn't support HPS frame buffer\n"); + } + + DisableIO(); + } + +} + +int video_fb_state() +{ + return fb_enabled; +} diff --git a/video.h b/video.h new file mode 100644 index 0000000..94ad918 --- /dev/null +++ b/video.h @@ -0,0 +1,17 @@ +#ifndef VIDEO_H +#define VIDEO_H + +int video_get_scaler_flt(); +void video_set_scaler_flt(int n); +char* video_get_scaler_coeff(); +void video_set_scaler_coeff(char *name); + +void video_mode_load(); +void video_mode_adjust(); + +int hasAPI1_5(); + +void video_fb_enable(int enable); +int video_fb_state(); + +#endif // VIDEO_H