diff --git a/MiSTer.ini b/MiSTer.ini index 1be54d5..e83e484 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -109,6 +109,13 @@ video_info=0 ; modes as a base even for 50Hz systems. vsync_adjust=0 +; Subcarrier generator for composite video output on VGA_VS pin (AA24). +; 0 - disabled (default, safe mode) +; 1 - enabled (frequency determined by ntsc_mode setting) +; Works with regular analog video only - not with direct video. +; For external RGB to NTSC encoders: requires vga_mode=rgb, composite_sync=1, forced_scandoubler=0. +subcarrier=0 + ; If your monitor doesn't support either very low (NTSC monitors may not support PAL) or ; very high (PAL monitors may not support NTSC) then you can set refresh_min and/or refresh_max ; parameters, so vsync_adjust won't be applied for refreshes outside specified. diff --git a/cfg.cpp b/cfg.cpp index 6134a36..fe00eef 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -48,6 +48,7 @@ static const ini_var_t ini_vars[] = { "VIDEO_MODE_NTSC", (void*)(cfg.video_conf_ntsc), STRING, 0, sizeof(cfg.video_conf_ntsc) - 1 }, { "VIDEO_INFO", (void*)(&(cfg.video_info)), UINT8, 0, 10 }, { "VSYNC_ADJUST", (void*)(&(cfg.vsync_adjust)), UINT8, 0, 2 }, + { "SUBCARRIER", (void*)(&(cfg.subcarrier)), UINT8, 0, 1 }, { "HDMI_AUDIO_96K", (void*)(&(cfg.hdmi_audio_96k)), UINT8, 0, 1 }, { "DVI_MODE", (void*)(&(cfg.dvi_mode)), UINT8, 0, 1 }, { "HDMI_LIMITED", (void*)(&(cfg.hdmi_limited)), UINT8, 0, 2 }, @@ -581,6 +582,7 @@ void cfg_parse() cfg.rumble = 1; cfg.wheel_force = 50; cfg.dvi_mode = 2; + cfg.subcarrier = 0; cfg.lookahead = 2; cfg.hdr = 0; cfg.hdr_max_nits = 1000; diff --git a/cfg.h b/cfg.h index 11906cf..8d330dc 100644 --- a/cfg.h +++ b/cfg.h @@ -25,6 +25,7 @@ typedef struct { float refresh_max; uint8_t controller_info; uint8_t vsync_adjust; + uint8_t subcarrier; uint8_t kbd_nomouse; uint8_t mouse_throttle; uint8_t bootscreen; diff --git a/video.cpp b/video.cpp index 07d063c..a10970b 100644 --- a/video.cpp +++ b/video.cpp @@ -2842,7 +2842,8 @@ bool video_mode_select(uint32_t vtime, vmode_custom_t* out_mode) static void set_yc_mode() { - if (cfg.vga_mode_int >= 2) + // Enable YC for S-Video/CVBS modes, or subcarrier for CXA2075 encoders + if (cfg.vga_mode_int >= 2 || (cfg.subcarrier && cfg.vga_mode_int == 0 && cfg.csync && !cfg.forced_scandoubler)) { float fps = current_video_info.vtime ? (100000000.f / current_video_info.vtime) : 0.f; int pal = fps < 55.f; @@ -2875,12 +2876,28 @@ static void set_yc_mode() } spi_uio_cmd_cont(UIO_SET_YC_PAR); - spi_w(((pal || cfg.ntsc_mode) ? 4 : 0) | ((cfg.vga_mode_int == 3) ? 3 : 1)); + // For traditional S-Video/CVBS modes, enable YC processing + // For subcarrier-only modes (RGB+subcarrier or direct video), keep yc_en=0 + bool is_subcarrier_only = (cfg.subcarrier && (cfg.direct_video || (cfg.vga_mode_int == 0 && cfg.csync && !cfg.forced_scandoubler))); + uint16_t yc_config; + if (is_subcarrier_only) { + // Subcarrier-only: RGB mode with just PAL flag, yc_en=0 + yc_config = ((pal || cfg.ntsc_mode) ? 4 : 0); + } else { + // Traditional YC modes: enable YC processing + yc_config = ((pal || cfg.ntsc_mode) ? 4 : 0) | ((cfg.vga_mode_int == 3) ? 3 : 1); + } + printf("Sending YC config to FPGA: 0x%02X (pal_en=%d, cvbs=%d, yc_en=%d)\n", yc_config, (yc_config >> 2) & 1, (yc_config >> 1) & 1, yc_config & 1); + spi_w(yc_config); spi_w(PHASE_INC); spi_w(PHASE_INC >> 16); spi_w(PHASE_INC >> 32); spi_w(COLORBURST_RANGE); spi_w(COLORBURST_RANGE >> 16); + // Case 6: Send subcarrier enable flag + uint16_t subcarrier_enable = (cfg.subcarrier && cfg.vga_mode_int == 0 && cfg.csync && !cfg.forced_scandoubler) ? 1 : 0; + printf("Sending subcarrier enable to FPGA: %d\n", subcarrier_enable); + spi_w(subcarrier_enable); DisableIO(); } else