use crate::{ModeSource, StereoMode, SyncDefinition, VideoMode};
pub fn vic_to_mode(vic: u8) -> Option<VideoMode> {
let (w, h, r, interlaced, hfp, hsw, vfp, vsw, vpos, hpos, pixel_clock_khz): (
u16,
u16,
u16,
bool,
u16,
u16,
u16,
u16,
bool,
bool,
u32,
) = match vic {
1 => (640, 480, 60, false, 16, 96, 10, 2, false, false, 25175),
2 => (720, 480, 60, false, 16, 62, 9, 6, false, false, 27000),
3 => (720, 480, 60, false, 16, 62, 9, 6, false, false, 27000),
4 => (1280, 720, 60, false, 110, 40, 5, 5, true, true, 74250),
5 => (1920, 1080, 60, true, 88, 44, 2, 5, true, true, 74250),
6 => (1440, 480, 60, true, 38, 124, 4, 3, false, false, 27000),
7 => (1440, 480, 60, true, 38, 124, 4, 3, false, false, 27000),
8 => (1440, 240, 60, false, 38, 124, 4, 3, false, false, 27000),
9 => (1440, 240, 60, false, 38, 124, 4, 3, false, false, 27000),
10 => (2880, 480, 60, true, 76, 248, 4, 3, false, false, 54000),
11 => (2880, 480, 60, true, 76, 248, 4, 3, false, false, 54000),
12 => (2880, 240, 60, false, 76, 248, 4, 3, false, false, 54000),
13 => (2880, 240, 60, false, 76, 248, 4, 3, false, false, 54000),
14 => (1440, 480, 60, false, 32, 124, 9, 6, false, false, 54000),
15 => (1440, 480, 60, false, 32, 124, 9, 6, false, false, 54000),
16 => (1920, 1080, 60, false, 88, 44, 4, 5, true, true, 148500),
17 => (720, 576, 50, false, 12, 64, 5, 5, false, false, 27000),
18 => (720, 576, 50, false, 12, 64, 5, 5, false, false, 27000),
19 => (1280, 720, 50, false, 440, 40, 5, 5, true, true, 74250),
20 => (1920, 1080, 50, true, 528, 44, 2, 5, true, true, 74250),
21 => (1440, 576, 50, true, 24, 126, 2, 3, false, false, 27000),
22 => (1440, 576, 50, true, 24, 126, 2, 3, false, false, 27000),
23 => (1440, 288, 50, false, 24, 126, 2, 3, false, false, 27000),
24 => (1440, 288, 50, false, 24, 126, 2, 3, false, false, 27000),
25 => (2880, 576, 50, true, 48, 252, 2, 3, false, false, 54000),
26 => (2880, 576, 50, true, 48, 252, 2, 3, false, false, 54000),
27 => (2880, 288, 50, false, 48, 252, 2, 3, false, false, 54000),
28 => (2880, 288, 50, false, 48, 252, 2, 3, false, false, 54000),
29 => (1440, 576, 50, false, 24, 128, 5, 5, false, false, 54000),
30 => (1440, 576, 50, false, 24, 128, 5, 5, false, false, 54000),
31 => (1920, 1080, 50, false, 528, 44, 4, 5, true, true, 148500),
32 => (1920, 1080, 24, false, 638, 44, 4, 5, true, true, 74250),
33 => (1920, 1080, 25, false, 528, 44, 4, 5, true, true, 74250),
34 => (1920, 1080, 30, false, 88, 44, 4, 5, true, true, 74250),
35 => (2880, 480, 60, false, 64, 248, 9, 6, false, false, 108000),
36 => (2880, 480, 60, false, 64, 248, 9, 6, false, false, 108000),
37 => (2880, 576, 50, false, 48, 256, 5, 5, false, false, 108000),
38 => (2880, 576, 50, false, 48, 256, 5, 5, false, false, 108000),
39 => (1920, 1080, 50, true, 32, 168, 23, 5, false, true, 72000),
40 => (1920, 1080, 100, true, 528, 44, 2, 5, true, true, 148500),
41 => (1280, 720, 100, false, 440, 40, 5, 5, true, true, 148500),
42 => (720, 576, 100, false, 12, 64, 5, 5, false, false, 54000),
43 => (720, 576, 100, false, 12, 64, 5, 5, false, false, 54000),
44 => (1440, 576, 100, true, 24, 126, 2, 3, false, false, 54000),
45 => (1440, 576, 100, true, 24, 126, 2, 3, false, false, 54000),
46 => (1920, 1080, 120, true, 88, 44, 2, 5, true, true, 148500),
47 => (1280, 720, 120, false, 110, 40, 5, 5, true, true, 148500),
48 => (720, 480, 120, false, 16, 62, 9, 6, false, false, 54000),
49 => (720, 480, 120, false, 16, 62, 9, 6, false, false, 54000),
50 => (1440, 480, 120, true, 38, 124, 4, 3, false, false, 54000),
51 => (1440, 480, 120, true, 38, 124, 4, 3, false, false, 54000),
52 => (720, 576, 200, false, 12, 64, 5, 5, false, false, 108000),
53 => (720, 576, 200, false, 12, 64, 5, 5, false, false, 108000),
54 => (1440, 576, 200, true, 24, 126, 2, 3, false, false, 108000),
55 => (1440, 576, 200, true, 24, 126, 2, 3, false, false, 108000),
56 => (720, 480, 240, false, 16, 62, 9, 6, false, false, 108000),
57 => (720, 480, 240, false, 16, 62, 9, 6, false, false, 108000),
58 => (1440, 480, 240, true, 38, 124, 4, 3, false, false, 108000),
59 => (1440, 480, 240, true, 38, 124, 4, 3, false, false, 108000),
60 => (1280, 720, 24, false, 1760, 40, 5, 5, true, true, 59400),
61 => (1280, 720, 25, false, 2420, 40, 5, 5, true, true, 74250),
62 => (1280, 720, 30, false, 1760, 40, 5, 5, true, true, 74250),
63 => (1920, 1080, 120, false, 88, 44, 4, 5, true, true, 297000),
64 => (1920, 1080, 100, false, 528, 44, 4, 5, true, true, 297000),
65 => (1280, 720, 24, false, 1760, 40, 5, 5, true, true, 59400), 66 => (1280, 720, 25, false, 2420, 40, 5, 5, true, true, 74250), 67 => (1280, 720, 30, false, 1760, 40, 5, 5, true, true, 74250), 68 => (1280, 720, 50, false, 440, 40, 5, 5, true, true, 74250), 69 => (1280, 720, 60, false, 110, 40, 5, 5, true, true, 74250), 70 => (1280, 720, 100, false, 440, 40, 5, 5, true, true, 148500), 71 => (1280, 720, 120, false, 110, 40, 5, 5, true, true, 148500),
72 => (1920, 1080, 24, false, 638, 44, 4, 5, true, true, 74250), 73 => (1920, 1080, 25, false, 528, 44, 4, 5, true, true, 74250), 74 => (1920, 1080, 30, false, 88, 44, 4, 5, true, true, 74250), 75 => (1920, 1080, 50, false, 528, 44, 4, 5, true, true, 148500), 76 => (1920, 1080, 60, false, 88, 44, 4, 5, true, true, 148500), 77 => (1920, 1080, 100, false, 528, 44, 4, 5, true, true, 297000), 78 => (1920, 1080, 120, false, 88, 44, 4, 5, true, true, 297000),
79 => (1680, 720, 24, false, 1360, 40, 5, 5, true, true, 59400),
80 => (1680, 720, 25, false, 1228, 40, 5, 5, true, true, 59400),
81 => (1680, 720, 30, false, 700, 40, 5, 5, true, true, 59400),
82 => (1680, 720, 50, false, 260, 40, 5, 5, true, true, 82500),
83 => (1680, 720, 60, false, 260, 40, 5, 5, true, true, 99000),
84 => (1680, 720, 100, false, 60, 40, 5, 5, true, true, 165000),
85 => (1680, 720, 120, false, 60, 40, 5, 5, true, true, 198000),
86 => (2560, 1080, 24, false, 998, 44, 4, 5, true, true, 99000),
87 => (2560, 1080, 25, false, 448, 44, 4, 5, true, true, 90000),
88 => (2560, 1080, 30, false, 768, 44, 4, 5, true, true, 118800),
89 => (2560, 1080, 50, false, 548, 44, 4, 5, true, true, 185625),
90 => (2560, 1080, 60, false, 248, 44, 4, 5, true, true, 198000),
91 => (2560, 1080, 100, false, 218, 44, 4, 5, true, true, 371250),
92 => (2560, 1080, 120, false, 548, 44, 4, 5, true, true, 495000),
93 | 103 => (3840, 2160, 24, false, 1276, 88, 8, 10, true, true, 297000),
94 | 104 => (3840, 2160, 25, false, 1056, 88, 8, 10, true, true, 297000),
95 | 105 => (3840, 2160, 30, false, 176, 88, 8, 10, true, true, 297000),
96 | 106 => (3840, 2160, 50, false, 1056, 88, 8, 10, true, true, 594000),
97 | 107 => (3840, 2160, 60, false, 176, 88, 8, 10, true, true, 594000),
98 => (4096, 2160, 24, false, 1020, 88, 8, 10, true, true, 297000),
99 => (4096, 2160, 25, false, 968, 88, 8, 10, true, true, 297000),
100 => (4096, 2160, 30, false, 88, 88, 8, 10, true, true, 297000),
101 => (4096, 2160, 50, false, 968, 88, 8, 10, true, true, 594000),
102 => (4096, 2160, 60, false, 88, 88, 8, 10, true, true, 594000),
108 | 109 => (1280, 720, 48, false, 960, 40, 5, 5, true, true, 90000),
110 => (1680, 720, 48, false, 810, 40, 5, 5, true, true, 99000),
111 | 112 => (1920, 1080, 48, false, 638, 44, 4, 5, true, true, 148500),
113 => (2560, 1080, 48, false, 998, 44, 4, 5, true, true, 198000),
114 | 116 => (3840, 2160, 48, false, 1276, 88, 8, 10, true, true, 594000),
115 => (4096, 2160, 48, false, 1020, 88, 8, 10, true, true, 594000),
117 | 119 => (3840, 2160, 100, false, 1056, 88, 8, 10, true, true, 1188000),
118 | 120 => (3840, 2160, 120, false, 176, 88, 8, 10, true, true, 1188000),
121 => (5120, 2160, 24, false, 1996, 88, 8, 10, true, true, 396000),
122 => (5120, 2160, 25, false, 1696, 88, 8, 10, true, true, 396000),
123 => (5120, 2160, 30, false, 664, 88, 8, 10, true, true, 396000),
124 => (5120, 2160, 48, false, 746, 88, 8, 10, true, true, 742500),
125 => (5120, 2160, 50, false, 1096, 88, 8, 10, true, true, 742500),
126 => (5120, 2160, 60, false, 164, 88, 8, 10, true, true, 742500),
127 => (5120, 2160, 100, false, 1096, 88, 8, 10, true, true, 1485000),
193 => (5120, 2160, 120, false, 164, 88, 8, 10, true, true, 1485000),
194 | 202 => (
7680, 4320, 24, false, 2552, 176, 16, 20, true, true, 1188000,
),
195 | 203 => (
7680, 4320, 25, false, 2352, 176, 16, 20, true, true, 1188000,
),
196 | 204 => (7680, 4320, 30, false, 552, 176, 16, 20, true, true, 1188000),
197 | 205 => (
7680, 4320, 48, false, 2552, 176, 16, 20, true, true, 2376000,
),
198 | 206 => (
7680, 4320, 50, false, 2352, 176, 16, 20, true, true, 2376000,
),
199 | 207 => (7680, 4320, 60, false, 552, 176, 16, 20, true, true, 2376000),
200 | 208 => (
7680, 4320, 100, false, 2112, 176, 16, 20, true, true, 4752000,
),
201 | 209 => (
7680, 4320, 120, false, 352, 176, 16, 20, true, true, 4752000,
),
210 => (
10240, 4320, 24, false, 1492, 176, 16, 20, true, true, 1485000,
),
211 => (
10240, 4320, 25, false, 2492, 176, 16, 20, true, true, 1485000,
),
212 => (
10240, 4320, 30, false, 288, 176, 16, 20, true, true, 1485000,
),
213 => (
10240, 4320, 48, false, 1492, 176, 16, 20, true, true, 2970000,
),
214 => (
10240, 4320, 50, false, 2492, 176, 16, 20, true, true, 2970000,
),
215 => (
10240, 4320, 60, false, 288, 176, 16, 20, true, true, 2970000,
),
216 => (
10240, 4320, 100, false, 2192, 176, 16, 20, true, true, 5940000,
),
217 => (
10240, 4320, 120, false, 288, 176, 16, 20, true, true, 5940000,
),
218 => (4096, 2160, 100, false, 800, 88, 8, 10, true, true, 1188000),
219 => (4096, 2160, 120, false, 88, 88, 8, 10, true, true, 1188000),
_ => return None,
};
Some(
VideoMode::new(w, h, r, interlaced)
.with_detailed_timing(
pixel_clock_khz,
hfp,
hsw,
vfp,
vsw,
0,
0,
StereoMode::None,
Some(SyncDefinition::DigitalSeparate {
v_sync_positive: vpos,
h_sync_positive: hpos,
}),
)
.with_source(ModeSource::Vic(vic)),
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RefreshRate;
#[test]
fn test_vic1_640x480p60() {
let mode = vic_to_mode(1).unwrap();
assert_eq!(mode.width, 640);
assert_eq!(mode.height, 480);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(60)));
assert!(!mode.interlaced);
assert_eq!(mode.h_front_porch, 16);
assert_eq!(mode.h_sync_width, 96);
assert_eq!(mode.v_front_porch, 10);
assert_eq!(mode.v_sync_width, 2);
assert_eq!(mode.pixel_clock_khz, Some(25175));
assert_eq!(mode.source, Some(ModeSource::Vic(1)));
}
#[test]
fn test_vic16_1080p60() {
let mode = vic_to_mode(16).unwrap();
assert_eq!(mode.width, 1920);
assert_eq!(mode.height, 1080);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(60)));
assert!(!mode.interlaced);
assert!(matches!(
mode.sync,
Some(SyncDefinition::DigitalSeparate {
v_sync_positive: true,
h_sync_positive: true
})
));
assert_eq!(mode.pixel_clock_khz, Some(148500));
}
#[test]
fn test_vic5_1080i60_interlaced() {
let mode = vic_to_mode(5).unwrap();
assert_eq!(mode.width, 1920);
assert_eq!(mode.height, 1080);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(60)));
assert!(mode.interlaced);
assert_eq!(mode.pixel_clock_khz, Some(74250));
}
#[test]
fn test_vic63_1080p120() {
let mode = vic_to_mode(63).unwrap();
assert_eq!(mode.width, 1920);
assert_eq!(mode.height, 1080);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(120)));
assert!(!mode.interlaced);
assert_eq!(mode.pixel_clock_khz, Some(297000));
}
#[test]
fn test_vic0_is_none() {
assert!(vic_to_mode(0).is_none());
}
#[test]
fn test_vic220_is_none() {
assert!(vic_to_mode(220).is_none());
}
#[test]
fn test_all_vics_1_to_64_are_some() {
for vic in 1..=64 {
assert!(vic_to_mode(vic).is_some(), "VIC {vic} returned None");
}
}
#[test]
fn test_extended_vics_are_some() {
for vic in 65..=127 {
assert!(vic_to_mode(vic).is_some(), "VIC {vic} returned None");
}
assert!(vic_to_mode(193).is_some());
for vic in 194..=219 {
assert!(vic_to_mode(vic).is_some(), "VIC {vic} returned None");
}
}
#[test]
fn test_vic93_4k_uhd_24() {
let mode = vic_to_mode(93).unwrap();
assert_eq!(mode.width, 3840);
assert_eq!(mode.height, 2160);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(24)));
assert!(!mode.interlaced);
assert_eq!(mode.pixel_clock_khz, Some(297000));
}
#[test]
fn test_vic97_4k_uhd_60() {
let mode = vic_to_mode(97).unwrap();
assert_eq!(mode.width, 3840);
assert_eq!(mode.height, 2160);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(60)));
assert!(!mode.interlaced);
assert_eq!(mode.pixel_clock_khz, Some(594000));
}
#[test]
fn test_vic103_aliases_93() {
let m93 = vic_to_mode(93).unwrap();
let m103 = vic_to_mode(103).unwrap();
assert_eq!(m93.width, m103.width);
assert_eq!(m93.height, m103.height);
assert_eq!(m93.refresh_rate, m103.refresh_rate);
assert_eq!(m93.pixel_clock_khz, m103.pixel_clock_khz);
assert_eq!(m93.source, Some(ModeSource::Vic(93)));
assert_eq!(m103.source, Some(ModeSource::Vic(103)));
}
#[test]
fn test_vic217_10k_120() {
let mode = vic_to_mode(217).unwrap();
assert_eq!(mode.width, 10240);
assert_eq!(mode.height, 4320);
assert_eq!(mode.refresh_rate, Some(RefreshRate::integral(120)));
assert_eq!(mode.pixel_clock_khz, Some(5940000));
}
}