diff --git a/vhdl/RGBtoHDMI.ucf b/vhdl/RGBtoHDMI.ucf index 64d98ba2..b0c2893c 100644 --- a/vhdl/RGBtoHDMI.ucf +++ b/vhdl/RGBtoHDMI.ucf @@ -6,7 +6,7 @@ NET "sp_clk" BUFG=CLK; # 96MHz clock domain NET "clk" TNM_NET = clk_period_grp_1; -TIMESPEC TS_clk_period_1 = PERIOD "clk_period_grp_1" 10.4ns HIGH; +TIMESPEC TS_clk_period_1 = PERIOD "clk_period_grp_1" 5.2ns HIGH; # 10MHz clock domain #NET "sp_clk" TNM_NET = clk_period_grp_2; @@ -14,23 +14,25 @@ TIMESPEC TS_clk_period_1 = PERIOD "clk_period_grp_1" 10.4ns HIGH; NET "clk" LOC = "P43"; # input gpio21 (gclk) -NET "R0" LOC = "P32"; # input -NET "G0" LOC = "P31"; # input -NET "B0" LOC = "P30"; # input -NET "R1" LOC = "P34"; # input -NET "G1" LOC = "P36"; # input -NET "B1" LOC = "P37"; # input -NET "csync_in" LOC = "P23"; # input +NET "R3_I" LOC = "P32"; # input +NET "G3_I" LOC = "P31"; # input +NET "B3_I" LOC = "P30"; # input +NET "R2_I" LOC = "P34"; # input +NET "G2_I" LOC = "P36"; # input +NET "B2_I" LOC = "P37"; # input +NET "R1_I" LOC = "P39"; # input (was gpio26) +NET "G1_I" LOC = "P40"; # input (was gpio19) +NET "B1_I" LOC = "P38"; # input (was gpio16) +NET "R0_I" LOC = "P21"; # input (was gpio27) +NET "G0_I" LOC = "P42"; # input (was gpio25) +NET "B0_I" LOC = "P18"; # input (was gpio24) + +NET "csync_I" LOC = "P23"; # input NET "version" LOC = "P33"; # input gpio18 (gsr) -NET "SW1" LOC = "P38"; # input gpio16 (connects to sw1) -NET "SW2" LOC = "P39"; # input gpio26 (connects to sw2) -NET "SW3" LOC = "P40"; # input gpio19 (connects to sw3) -NET "vsync_in" LOC = "P41"; # input (connects to vsync) +NET "vsync_I" LOC = "P41"; # input (connects to vsync) NET "analog" LOC = "P19"; # input gpio22 -NET "mode7_in" LOC = "P42"; # input gpio25 (connects to LED2, driven from Pi) -NET "mux" LOC = "P18"; # input gpio24 NET "sp_clk" LOC = "P44"; # input gpio20 (gclk) NET "sp_data" LOC = "P7"; # input gpio0 (input only) NET "sp_clken" LOC = "P6"; # input gpio1 (input only) @@ -51,8 +53,6 @@ NET "quad(11)" LOC = "P1"; # output gpio13 NET "psync" LOC = "P22"; # output gpio17 NET "csync" LOC = "P20"; # output gpio23 -NET "LED1" LOC = "P21"; # input gpio27 (connects to LED1, driven from Pi) - NET "quad(0)" SLOW; NET "quad(1)" SLOW; NET "quad(2)" SLOW; diff --git a/vhdl/RGBtoHDMI.vhdl b/vhdl/RGBtoHDMI.vhdl index a5263e23..54a20203 100644 --- a/vhdl/RGBtoHDMI.vhdl +++ b/vhdl/RGBtoHDMI.vhdl @@ -1,5 +1,5 @@ ---------------------------------------------------------------------------------- --- Engineer: David Banks +-- Engineer: David Banks & Ian Bradbury -- -- Create Date: 15/7/2018 -- Module Name: RGBtoHDMI CPLD @@ -19,20 +19,25 @@ entity RGBtoHDMI is ); Port ( -- From RGB Connector - R0: in std_logic; - G0: in std_logic; - B0: in std_logic; - R1: in std_logic; - G1: in std_logic; - B1: in std_logic; - csync_in: in std_logic; - vsync_in: in std_logic; + R3_I: in std_logic; + G3_I: in std_logic; + B3_I: in std_logic; + R2_I: in std_logic; + G2_I: in std_logic; + B2_I: in std_logic; + R1_I: in std_logic; + G1_I: in std_logic; + B1_I: in std_logic; + R0_I: in std_logic; + G0_I: in std_logic; + B0_I: in std_logic; + + csync_I: in std_logic; + vsync_I: in std_logic; analog: inout std_logic; -- From Pi clk: in std_logic; - mode7_in: in std_logic; - mux: in std_logic; sp_clk: in std_logic; sp_clken: in std_logic; sp_data: in std_logic; @@ -43,19 +48,12 @@ entity RGBtoHDMI is csync: out std_logic; -- User interface - version: in std_logic; - SW1: in std_logic; - SW2: in std_logic; - SW3: in std_logic; - - LED1: in std_logic -- allow it to be driven from the Pi + version: in std_logic ); end RGBtoHDMI; architecture Behavorial of RGBtoHDMI is - subtype counter_type is unsigned(7 downto 0); - -- Version number: Design_Major_Minor -- Design: 0 = BBC CPLD -- 1 = Alternative CPLD @@ -63,12 +61,10 @@ architecture Behavorial of RGBtoHDMI is -- 3 = six bit CPLD (if required); -- 4 = RGB CPLD (TTL) -- C = RGB CPLD (Analog) - constant VERSION_NUM_BBC : std_logic_vector(11 downto 0) := x"066"; - constant VERSION_NUM_RGB_TTL : std_logic_vector(11 downto 0) := x"477"; - constant VERSION_NUM_RGB_ANALOG : std_logic_vector(11 downto 0) := x"C77"; - -- Sampling points - constant INIT_SAMPLING_POINTS : std_logic_vector(23 downto 0) := "000000011011011011011011"; + constant VERSION_NUM_BBC : std_logic_vector(11 downto 0) := x"067"; + constant VERSION_NUM_RGB_TTL : std_logic_vector(11 downto 0) := x"478"; + constant VERSION_NUM_RGB_ANALOG : std_logic_vector(11 downto 0) := x"C78"; signal shift_R : std_logic_vector(3 downto 0); signal shift_G : std_logic_vector(3 downto 0); @@ -91,34 +87,11 @@ architecture Behavorial of RGBtoHDMI is -- 4. Handles double buffering of alternative quad pixels (bit 5) -- -- At the moment we don't count pixels with the line, the Pi does that + + subtype counter_type is unsigned(7 downto 0); + signal counter : counter_type; - -- Sample point register; - -- - -- In Mode 7 each pixel lasts 8 clocks (96MHz / 12MHz). The original - -- pixel clock is a regenerated 6Mhz clock, and both edges are used. - -- Due to the way it is generated, there are three distinct phases, - -- each with different rising/falling edge speeds, hence six sampling - -- points are used. - -- - -- In Modes 0..6 each pixel lasts 6 clocks (96MHz / 16MHz). The original - -- pixel clock is a clean 16Mhz clock, so only one sample point is needed. - -- To achieve this, all six values are set to be the same. This minimises - -- the logic in the CPLD. - signal sp_reg : std_logic_vector(23 downto 0) := INIT_SAMPLING_POINTS; - - -- Break out of sp_reg - signal invert : std_logic; - signal rate : std_logic_vector(1 downto 0); - signal delay : unsigned(1 downto 0); - signal half : std_logic; - signal offset_A : std_logic_vector(2 downto 0); - signal offset_B : std_logic_vector(2 downto 0); - signal offset_C : std_logic_vector(2 downto 0); - signal offset_D : std_logic_vector(2 downto 0); - signal offset_E : std_logic_vector(2 downto 0); - signal offset_F : std_logic_vector(2 downto 0); - -- Pipelined offset mux output signal offset : std_logic_vector(2 downto 0); @@ -133,9 +106,8 @@ architecture Behavorial of RGBtoHDMI is -- RGB Input Mux signal old_mux : std_logic; - signal mode7 : std_logic; - signal mux_sync : std_logic; - + signal mux_sync : std_logic; + signal R : std_logic; signal G : std_logic; signal B : std_logic; @@ -143,12 +115,42 @@ architecture Behavorial of RGBtoHDMI is signal clamp_int : std_logic; signal clamp_enable : std_logic; -begin - old_mux <= mux when not(SupportAnalog) else '0'; + -- Sample point register; + -- + -- In Mode 7 each pixel lasts 8 clocks (96MHz / 12MHz). The original + -- pixel clock is a regenerated 6Mhz clock, and both edges are used. + -- Due to the way it is generated, there are three distinct phases, + -- each with different rising/falling edge speeds, hence six sampling + -- points are used. + -- + -- In Modes 0..6 each pixel lasts 6 clocks (96MHz / 16MHz). The original + -- pixel clock is a clean 16Mhz clock, so only one sample point is needed. + -- To achieve this, all six values are set to be the same. This minimises + -- the logic in the CPLD. - R <= R1 when old_mux = '1' else R0; - G <= G1 when old_mux = '1' else G0; - B <= B1 when old_mux = '1' else B0; + -- Sampling points + constant INIT_SAMPLING_POINTS : std_logic_vector(23 downto 0) := "000000011011011011011011"; + + signal sp_reg : std_logic_vector(23 downto 0) := INIT_SAMPLING_POINTS; + + -- Break out of sp_reg + signal offset_A : std_logic_vector(2 downto 0); + signal offset_B : std_logic_vector(2 downto 0); + signal offset_C : std_logic_vector(2 downto 0); + signal offset_D : std_logic_vector(2 downto 0); + signal offset_E : std_logic_vector(2 downto 0); + signal offset_F : std_logic_vector(2 downto 0); + signal half : std_logic; + signal delay : unsigned(1 downto 0); + signal rate : std_logic_vector(1 downto 0); + signal divider : std_logic; + +begin + old_mux <= B0_I when not(SupportAnalog) else '0'; -- B0_I used to be mux_in from Pi GPIO + + R <= R2_I when old_mux = '1' else R3_I; + G <= G2_I when old_mux = '1' else G3_I; + B <= B2_I when old_mux = '1' else B3_I; offset_A <= sp_reg(2 downto 0); offset_B <= sp_reg(5 downto 3); @@ -159,8 +161,7 @@ begin half <= sp_reg(18); delay <= unsigned(sp_reg(20 downto 19)); rate <= sp_reg(22 downto 21); - invert <= sp_reg(23) when not(SupportAnalog) else '0'; - mode7 <= mode7_in when not(SupportAnalog) else sp_reg(23); + divider <= sp_reg(23); -- Shift the bits in LSB first process(sp_clk) @@ -177,8 +178,7 @@ begin if rising_edge(clk) then -- synchronize CSYNC to the sampling clock - -- if link fitted sync is inverted. If +ve vsync connected to link & +ve hsync to S then generate -ve composite sync - csync1 <= csync_in xor invert; + csync1 <= csync_I; -- De-glitch CSYNC -- csync1 is the possibly glitchy input @@ -201,24 +201,17 @@ begin if last = '0' and csync2 = '1' then if rate(1) = '1' then counter(7 downto 3) <= "10" & delay & "0"; - if half = '1' then - counter(2 downto 0) <= "000"; - elsif mode7 = '1' then - counter(2 downto 0) <= "100"; - else - counter(2 downto 0) <= "011"; - end if; else counter(7 downto 3) <= "110" & delay; - if half = '1' then - counter(2 downto 0) <= "000"; - elsif mode7 = '1' then - counter(2 downto 0) <= "100"; - else - counter(2 downto 0) <= "011"; - end if; end if; - elsif mode7 = '1' or counter(2 downto 0) /= 5 then + if half = '1' then + counter(2 downto 0) <= "000"; + elsif divider = '1' then + counter(2 downto 0) <= "100"; + else + counter(2 downto 0) <= "011"; + end if; + elsif divider = '1' or counter(2 downto 0) /= 5 then if counter(counter'left) = '1' then counter <= counter + 1; else @@ -238,7 +231,7 @@ begin else -- so index offset changes at the same time counter wraps 7->0 -- so index offset changes at the same time counter wraps ->0 - if (mode7 = '0' and counter(2 downto 0) = 4) or (mode7 = '1' and counter(2 downto 0) = 6) then + if (divider = '0' and counter(2 downto 0) = 4) or (divider = '1' and counter(2 downto 0) = 6) then case index is when "000" => index <= "001"; @@ -281,37 +274,53 @@ begin -- R Sample/shift register if sample = '1' then - if rate = "01" then - shift_R <= R1 & R0 & shift_R(3 downto 2); -- double + if rate = "01" and sp_data = '0' then + shift_R <= R2_I & R3_I & shift_R(3 downto 2); -- 6 bpp + elsif rate = "00" and sp_data = '1' then + shift_R <= R1_I & G2_I & B3_I & B3_I; -- 9 bpp + elsif rate /= "00" and sp_data = '1' then + shift_R <= R1_I & G2_I & B3_I & B0_I; -- 12 bpp else - shift_R <= R & shift_R(3 downto 1); + shift_R <= R3_I & shift_R(3 downto 1); -- 3 bpp end if; end if; -- G Sample/shift register if sample = '1' then - if rate = "01" then - shift_G <= G1 & G0 & shift_G(3 downto 2); -- double + if rate = "01" and sp_data = '0' then + shift_G <= G2_I & G3_I & shift_G(3 downto 2); -- 6 bpp + elsif rate = "00" and sp_data = '1' then + shift_G <= R2_I & G3_I & G3_I & B1_I; -- 9 bpp + elsif rate /= "00" and sp_data = '1' then + shift_G <= R2_I & G3_I & G0_I & B1_I; -- 12 bpp else - shift_G <= G & shift_G(3 downto 1); + shift_G <= G3_I & shift_G(3 downto 1); -- 3 bpp end if; end if; -- B Sample/shift register if sample = '1' then - if rate = "01" then - shift_B <= B1 & B0 & shift_B(3 downto 2); -- double + if rate = "01" and sp_data = '0' then + shift_B <= B2_I & B3_I & shift_B(3 downto 2); -- 6 bpp + elsif rate = "00" and sp_data = '1' then + shift_B <= R3_I & R3_I & vsync_I & B2_I; -- 9 bpp with G1 on vsync_I + elsif rate /= "00" and sp_data = '1' then + shift_B <= R3_I & R0_I & G1_I & B2_I; -- 12 bpp else - shift_B <= B & shift_B(3 downto 1); + shift_B <= B3_I & shift_B(3 downto 1); -- 3 bpp end if; end if; -- Pipeline when to update the quad if counter(counter'left) = '0' and ( - (rate = "00" and counter(4 downto 0) = 0) or -- normal - (rate = "01" and counter(3 downto 0) = 0) or -- double - (rate = "10" and counter(5 downto 0) = 0) or -- subsample even - (rate = "11" and counter(5 downto 0) = 32)) then -- subsample odd + (rate = "00" and sp_data = '0' and counter(4 downto 0) = 0) or -- 3bpp + (rate = "01" and sp_data = '0' and counter(3 downto 0) = 0) or -- 6bpp + (rate = "00" and sp_data = '1' and counter(2 downto 0) = 0) or -- 9bpp + (rate = "01" and sp_data = '1' and counter(2 downto 0) = 0) or -- 12bpp + (rate = "10" and sp_data = '0' and counter(5 downto 0) = 0) or -- subsample even 3bpp + (rate = "11" and sp_data = '0' and counter(5 downto 0) = 32) or -- subsample odd 3bpp + (rate = "10" and sp_data = '1' and counter(3 downto 0) = 0) or -- subsample even 12bpp + (rate = "11" and sp_data = '1' and counter(3 downto 0) = 8)) then -- subsample odd 12bpp -- toggle is asserted in cycle 1 toggle <= '1'; else @@ -348,30 +357,32 @@ begin end if; -- Output a skewed version of psync - if version = '0' then - psync <= vsync_in; - elsif counter(counter'left) = '1' then + if counter(counter'left) = '1' then psync <= '0'; - elsif counter(3 downto 0) = 3 then -- comparing with N gives N-1 cycles of skew - if rate = "00" then - psync <= counter(5); -- normal - elsif rate = "01" then - psync <= counter(4); -- double - elsif counter(5) = rate(0) then + elsif counter(2 downto 0) = 2 then -- comparing with N gives N-1 cycles of skew + if rate = "00" and sp_data = '0' then + psync <= counter(5); -- 3bpp + elsif rate = "01" and sp_data = '0' then + psync <= counter(4); -- 6bpp + elsif rate = "00" and sp_data = '1' then + psync <= counter(3); -- 9bpp one edge for every pixel + elsif rate = "01" and sp_data = '1' then + psync <= counter(3); -- 12 bpp one edge for every pixel + elsif sp_data = '0' and rate(0) = counter(5) then psync <= counter(6); -- subsample + elsif sp_data = '1' and rate(0) = counter(3) then + psync <= counter(4); -- subsample end if; end if; - end if; end process; csync <= csync2; -- output the registered version to save a macro-cell analog_additions: if SupportAnalog generate - -- csync2 is cleaned but delayed so OR with csync1 to remove delay on trailing edge of sync pulse - -- spdata is overloaded as clamp on/off + -- csync2 is cleaned but delayed so OR with csync1 to remove delay on trailing edge of sync pulse + -- spdata is overloaded as clamp on/off clamp_int <= not(csync1 or csync2) and sp_data; - analog <= 'Z' when version = '0' else clamp_int; end generate;