Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/15khz-rgb-csync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# 15kHz RGB CSYNC Video Output

## Overview

The MEGA65 supports 15kHz RGB video output with composite sync (CSYNC) on the
VGA connector. This mode is designed for connecting to classic CRT monitors
like the Commodore 1084S, 1084S-D2, or any monitor that accepts 15kHz RGB with
composite sync input (commonly via SCART).

In this mode:
- Horizontal sync rate: ~15.6kHz (PAL) or ~15.7kHz (NTSC)
- CSYNC is output on both VGA pin 13 and pin 14 (active low)
- RGB video uses the same pins as standard VGA

The HDMI output continues to operate at 31kHz regardless of this setting.

## Enabling 15kHz Mode

15kHz mode is automatically detected via the VGA DDC pins (pins 12 and 15).
The MEGA65 drives pin 12 (SDA) LOW and senses pin 15 (SCL) with an internal pull-up.
Build a 15kHz cable with a **470Ω resistor** between VGA pins 12 and 15.
(The board has a strong 5V pull-up on pin 15, so a low value resistor is required.)

| Cable Type | VGA Pin 15 State | Video Mode |
|----------------------------------|------------------|--------------------|
| Standard VGA cable | HIGH (pull-up) | Standard 31kHz VGA |
| 15kHz cable with resistor 12-15 | LOW (via resistor)| 15kHz RGB CSYNC |

This detection happens at the hardware level, so 15kHz mode is active from
the very first frame - including the core selection menu and all boot screens.
Works on all MEGA65 board revisions (R3, R4, R5, R6).

## Compatible Monitors

This mode should work with monitors that accept 15kHz RGB with composite sync:
- Commodore 1084S, 1084S-D2
- Sony PVM series (via RGB input)
- Any TV/monitor with SCART RGB input
- Arcade monitors (via appropriate adapter)

At time of writing, this has been tested with a 1084S-D2 using an appropriate
cable.

## VGA to DB-9 RGB Cable Wiring

To connect the MEGA65 VGA output to a Commodore monitor with a DB-9 analog RGB
input (like the 1084S-D2), you need a custom cable with the following wiring:

```
VGA (DB-15 Male) DB-9 RGB (Male)
================ ===============

Pin 1 (Red) <----------------- Pin 3 (Red)
Pin 2 (Green) <----------------- Pin 4 (Green)
Pin 3 (Blue) <----------------- Pin 5 (Blue)
Pin 13 (HSYNC) <----------------- Pin 7 (Composite Sync)

Pin 5 (GND) <----------------- Pin 1 (Ground)
Pin 6 (GND) <----------------- Pin 2 (Ground)
Pin 10 (GND) <----+
+------------ Ground wire

15kHz Auto-Detection:
Pin 12 (SDA) <---[470Ω]---- Pin 15 (SCL)

Not connected:
- DB-9 Pin 6 (Intensity) - not used
- DB-9 Pins 8, 9 - not used

Note: CSYNC is available on both VGA pin 13 (HSYNC) and pin 14 (VSYNC)
for flexibility with different adapters.
```

The 470Ω resistor between VGA pins 12 and 15 enables automatic 15kHz mode detection.
Pin 12 is driven LOW by the MEGA65, and pin 15 has an external 5V pull-up on the board.
When the resistor bridges them, pin 15 is pulled below the logic threshold, enabling 15kHz mode.
Without this resistor, the MEGA65 outputs standard 31kHz VGA.

## Interlace Support for V400 Modes

When 15kHz mode is enabled and the VIC-IV is in V400 mode (e.g., 80x50 text mode),
interlace is automatically enabled. This ensures all 400 vertical lines are
displayed by alternating between odd and even fields on successive frames.

Without interlace, V400 modes would only show every other scanline, resulting in
half the vertical resolution being lost.

The interlace auto-enable only affects the 15kHz VGA output - HDMI output
continues to use progressive scan regardless of this setting.

## Notes

- The 15kHz mode uses the same PAL/NTSC timing as the internal video system,
so PAL regions get 50Hz and NTSC regions get 60Hz output.
- If your monitor loses sync briefly when switching between screens, this is
normal as the video mode stabilizes.
- Interlace mode can also be manually controlled via VIC-IV register `$D031`
bit 0 if needed for other purposes.
28 changes: 28 additions & 0 deletions src/vhdl/machine.vhdl
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ entity machine is
luma : out unsigned(7 downto 0);
chroma : out unsigned(7 downto 0);
composite : out unsigned(7 downto 0);

----------------------------------------------------------------------
-- 15kHz RGB with Composite Sync for retro CRT monitors
----------------------------------------------------------------------
rgb15khz_red : out unsigned(7 downto 0) := (others => '0');
rgb15khz_green : out unsigned(7 downto 0) := (others => '0');
rgb15khz_blue : out unsigned(7 downto 0) := (others => '0');
rgb15khz_csync : out std_logic := '1'; -- Active low composite sync

----------------------------------------------------------------------
-- VGA output
Expand All @@ -161,6 +169,9 @@ entity machine is
lcd_vsync : out std_logic := '0';
pal50_select_out : out std_logic := '0';
vga_blank : out std_logic := '0';

-- 15kHz RGB CSYNC mode selection (active high enables 15kHz mode)
vga_15khz_csync_mode : in std_logic := '0';

vgared : out UNSIGNED (7 downto 0) := x"00";
vgagreen : out UNSIGNED (7 downto 0) := x"00";
Expand Down Expand Up @@ -417,6 +428,10 @@ entity machine is
dipsw : in std_logic_vector(4 downto 0) := (others => '0');
sw : in std_logic_vector(15 downto 0);
btn : in std_logic_vector(4 downto 0);

-- DIP switch 3 directly exposed for 15kHz RGB CSYNC mode control
-- (active high = enable 15kHz mode)
dipsw3_out : out std_logic := '0';

UART_TXD : out std_logic := '1';
RsRx : in std_logic;
Expand Down Expand Up @@ -837,6 +852,7 @@ architecture Behavioral of machine is

signal interlace_mode : std_logic;
signal mono_mode : std_logic;
signal v400_mode : std_logic;

begin

Expand Down Expand Up @@ -881,6 +897,9 @@ begin
-- LED indication for when eth remote control is enabled
-- (requires DIPSW 2 and MEGA+SHIFT+POUND)
eth_load_enabled <= eth_load_enable and dipsw_int(1);

-- Expose DIP switch 3 for 15kHz RGB CSYNC mode control
dipsw3_out <= dipsw_int(3);

-- Latch reset from monitor interface to avoid tripping on glitches
-- But requiring to be low so long causes monitor induced reset to be ignored.
Expand Down Expand Up @@ -1295,6 +1314,8 @@ begin

interlace_mode => interlace_mode,
mono_mode => mono_mode,
v400_mode => v400_mode,
vga_15khz_csync_mode => vga_15khz_csync_mode,

-- Framing information for VIC-IV
x_zero => external_frame_x_zero,
Expand Down Expand Up @@ -1324,6 +1345,12 @@ begin
luma => luma,
chroma => chroma,
composite => composite,

-- 15kHz RGB with composite sync
rgb15khz_red => rgb15khz_red,
rgb15khz_green => rgb15khz_green,
rgb15khz_blue => rgb15khz_blue,
rgb15khz_csync => rgb15khz_csync,

-- And the variations on those signals for the LCD display
lcd_hsync => lcd_hsync,
Expand Down Expand Up @@ -1354,6 +1381,7 @@ begin

interlace_mode => interlace_mode,
mono_mode => mono_mode,
v400_mode => v400_mode,

hypervisor_mode => cpu_hypervisor_mode,

Expand Down
70 changes: 64 additions & 6 deletions src/vhdl/mega65r3.vhdl
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ entity container is
vgared : out UNSIGNED (7 downto 0);
vgagreen : out UNSIGNED (7 downto 0);
vgablue : out UNSIGNED (7 downto 0);
-- VGA DDC pins for 15kHz mode detection
-- VGA DDC pins for 15kHz mode detection
-- 470Ω resistor between pins 12-15 enables 15kHz mode
vga_sda : out std_logic;
vga_scl : in std_logic;

TMDS_data_p : out STD_LOGIC_VECTOR(2 downto 0);
TMDS_data_n : out STD_LOGIC_VECTOR(2 downto 0);
Expand Down Expand Up @@ -473,11 +478,25 @@ architecture Behavioral of container is
signal luma : unsigned(7 downto 0);
signal chroma : unsigned(7 downto 0);
signal composite : unsigned(7 downto 0);

-- 15kHz RGB with composite sync signals
signal rgb15khz_red : unsigned(7 downto 0);
signal rgb15khz_green : unsigned(7 downto 0);
signal rgb15khz_blue : unsigned(7 downto 0);
signal rgb15khz_csync : std_logic;
signal vga_15khz_mode : std_logic := '0';

-- Hardware detection for 15kHz mode via VGA DDC pins
-- SDA driven LOW, SCL sensed - 470Ω resistor between pins 12-15 pulls SCL low
signal vga_15khz_detect : std_logic := '0';

signal eth_load_enable : std_logic;

begin

-- Drive VGA SDA low for 15kHz detection (concurrent assignment)
vga_sda <= '0';

--STARTUPE2:STARTUPBlock--7Series

--XilinxHDLLibrariesGuide,version2012.4
Expand Down Expand Up @@ -896,6 +915,15 @@ begin
chroma => chroma,
composite => composite,

-- 15kHz RGB with composite sync
rgb15khz_red => rgb15khz_red,
rgb15khz_green => rgb15khz_green,
rgb15khz_blue => rgb15khz_blue,
rgb15khz_csync => rgb15khz_csync,

-- 15kHz RGB CSYNC mode control (active high = 15kHz mode)
vga_15khz_csync_mode => vga_15khz_mode,

vsync => v_vsync,
vga_hsync => v_vga_hsync,
hdmi_hsync => v_hdmi_hsync,
Expand Down Expand Up @@ -1078,6 +1106,7 @@ begin

sw => sw,
dipsw => dipsw,
dipsw3_out => open,
-- uart_rx => '1',
btn => (others => '1')

Expand Down Expand Up @@ -1105,7 +1134,12 @@ begin
vdac_blank_n <= '1'; -- was: not (v_hsync or v_vsync);

-- VGA output at full pixel clock
vdac_clk <= pixelclock;
-- In 15kHz mode, use clock27 to match the 15kHz signal source
if vga_15khz_mode = '1' then
vdac_clk <= clock27;
else
vdac_clk <= pixelclock;
end if;

-- Use both real and cartridge IRQ and NMI signals
irq_combined <= irq and irq_out;
Expand All @@ -1129,6 +1163,12 @@ begin

dvi_select <= portp_drive(1);

-- 15kHz RGB CSYNC mode detection via VGA DDC pins
-- SDA (pin 12) driven LOW, SCL (pin 15) sensed
-- 470Ω resistor between pins 12-15 pulls SCL below threshold = 15kHz mode
vga_15khz_detect <= not vga_scl;
vga_15khz_mode <= vga_15khz_detect;

reset_high <= not btncpureset;

btncpureset <= max10_reset_out;
Expand Down Expand Up @@ -1230,11 +1270,29 @@ begin
led <= portp_drive(4);

if rising_edge(pixelclock) then
hsync <= v_vga_hsync;
vsync <= v_vsync;
vgared <= v_red;
vgagreen <= v_green;
vgablue <= v_blue;
-- VGA output selection: 31kHz VGA or 15kHz RGB CSYNC
-- When 15kHz mode is enabled (vga_15khz_mode='1'):
-- - hsync outputs CSYNC (active low composite sync)
-- - vsync is held HIGH (not connected/used in 15kHz mode)
-- - RGB comes from 15kHz raster buffer
-- HDMI output always uses 31kHz signals regardless of VGA mode
if vga_15khz_mode = '1' then
-- 15kHz RGB CSYNC mode for retro CRT monitors
hsync <= rgb15khz_csync; -- CSYNC on VGA pin 13 (active low)
vsync <= rgb15khz_csync; -- CSYNC also on VGA pin 14 for flexibility
vgared <= rgb15khz_red;
vgagreen <= rgb15khz_green;
vgablue <= rgb15khz_blue;
else
-- Standard 31kHz VGA mode
hsync <= v_vga_hsync;
vsync <= v_vsync;
vgared <= v_red;
vgagreen <= v_green;
vgablue <= v_blue;
end if;

-- HDMI output always uses 31kHz (unaffected by VGA mode selection)
hdmired <= v_red;
hdmigreen <= v_green;
hdmiblue <= v_blue;
Expand Down
6 changes: 6 additions & 0 deletions src/vhdl/mega65r3.xdc
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS33} [get_ports fb_fire]

##VGA Connector

# VGA I2C bus - used for 15kHz mode detection
# SDA (pin 12) driven LOW, SCL (pin 15) sensed with pull-up
# If resistor bridges pins 12-15, SCL reads LOW = 15kHz mode
set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports vga_sda]
set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33 PULLUP TRUE} [get_ports vga_scl]

# XXX - Is this needed?
set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports vdac_clk]
set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports vdac_sync_n]
Expand Down
Loading