Repository: hamsternz/Artix-7-HDMI-processing Branch: master Commit: 8fd6a5add930 Files: 34 Total size: 356.9 KB Directory structure: gitextract_5_dt_ehf/ ├── Artix-7-HDMI-processing.xpr ├── README.txt ├── constraints/ │ └── NexysVideo.xdc ├── src/ │ ├── alignment_detect.vhd │ ├── audio_meters.vhd │ ├── audio_to_db.vhd │ ├── conversion_to_RGB.vhd │ ├── deserialiser_1_to_10.vhd │ ├── detect_interlace.vhd │ ├── dvid_output.vhd │ ├── edge_enhance.vhd │ ├── edid_rom.vhd │ ├── expand_422_to_444.vhd │ ├── extract_audio_samples.vhd │ ├── extract_video_infopacket_data.vhd │ ├── guidelines.vhd │ ├── hdmi_design.vhd │ ├── hdmi_input.vhd │ ├── hdmi_io.vhd │ ├── input_channel.vhd │ ├── line_delay.vhd │ ├── pixel_processing.vhd │ ├── serialiser_10_to_1.vhd │ ├── symbol_dump.vhd │ ├── tmds_decoder.vhd │ └── tmds_encoder.vhd └── test_bench/ ├── hdmi_test_generator/ │ ├── hdmi_ouput_test.vhd │ ├── minimal_hdmi_symbols.vhd │ ├── serializers.vhd │ ├── vga_clocking.vhd │ └── vga_gen.vhd ├── tb_audio_to_db.vhd ├── tb_convert_yCbCr_to_RGB.vhd └── tb_hdmi_decode.vhd ================================================ FILE CONTENTS ================================================ ================================================ FILE: Artix-7-HDMI-processing.xpr ================================================ ================================================ FILE: README.txt ================================================ README file for Artix 7 HDMI processing ======================================= Hi! This is my design for receiving HDMI input, then extracting the video data, the Video Inforframe and audio samples, then using that to display audio db meters on the top corner of the screen. Currently for simplicity the output is only DVID. Features -------- Supports HDMI formats: -720p@50 - 720p@60, - 1080i (with a bug) - 1080p@50 - 1080p@60 and others.... Colourspaces / formats: - RGB 444 - YCbCr 444 - YCbCr 422 New feature 10-AUG-2015! ----------------------- Switch 0 will turn real-time edge detect off and on. New feature 6-AUG-2015! ----------------------- Switch 1 will turn guidelines off and on. Will only show in 1080p 1080i and 720p resolutions. Supported Boards ---------------- - Digilent Nexys Video Sources tested with: - Western Digital HD Live - HP Laptop Sinks tested with: - Viewsonic Monitor - AOC Monitor - Vivo TV Known issues: - Currently extracts only two channels of audio - Does not adjust PLL settings for input clock, so the PLL is run slightly out of spec. - Image may re-sync once after a few seconds if symbol errors are seen. - There are timings errors, as generating 148.5MHz HDMI using the Artix-7 chip is actually out of spec. Expect seven failing paths and about 20ns of negative slack. ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- ================================================ FILE: constraints/NexysVideo.xdc ================================================ #------------------------------------------------------------------------------------ # HDMI and clock Constraints for the Digilent Nexys Video FPGA development board. #------------------------------------------------------------------------------------ ##Clock Signal set_property -dict { PACKAGE_PIN R4 IOSTANDARD LVCMOS33 } [get_ports { clk100 }]; create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports clk100] ##HDMI in create_clock -add -name hdmi_clk -period 6.7 -waveform {0 5} [get_ports hdmi_rx_clk_p] set_property -dict { PACKAGE_PIN AA5 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_cec }]; #IO_L10P_T1_34 Sch=hdmi_rx_cec set_property -dict { PACKAGE_PIN W4 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_clk_n }]; #IO_L12N_T1_MRCC_34 Sch=hdmi_rx_clk_n set_property -dict { PACKAGE_PIN V4 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_clk_p }]; #IO_L12P_T1_MRCC_34 Sch=hdmi_rx_clk_p set_property -dict { PACKAGE_PIN AB12 IOSTANDARD LVCMOS25 } [get_ports { hdmi_rx_hpa }]; #IO_L7N_T1_13 Sch=hdmi_rx_hpa set_property -dict { PACKAGE_PIN Y4 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_scl }]; #IO_L11P_T1_SRCC_34 Sch=hdmi_rx_scl set_property -dict { PACKAGE_PIN AB5 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_sda }]; #IO_L10N_T1_34 Sch=hdmi_rx_sda set_property -dict { PACKAGE_PIN R3 IOSTANDARD LVCMOS33 } [get_ports { hdmi_rx_txen }]; #IO_L3P_T0_DQS_34 Sch=hdmi_rx_txen set_property -dict { PACKAGE_PIN AA3 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_n[0] }]; #IO_L9N_T1_DQS_34 Sch=hdmi_rx_n[0] set_property -dict { PACKAGE_PIN Y3 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_p[0] }]; #IO_L9P_T1_DQS_34 Sch=hdmi_rx_p[0] set_property -dict { PACKAGE_PIN Y2 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_n[1] }]; #IO_L4N_T0_34 Sch=hdmi_rx_n[1] set_property -dict { PACKAGE_PIN W2 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_p[1] }]; #IO_L4P_T0_34 Sch=hdmi_rx_p[1] set_property -dict { PACKAGE_PIN V2 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_n[2] }]; #IO_L2N_T0_34 Sch=hdmi_rx_n[2] set_property -dict { PACKAGE_PIN U2 IOSTANDARD TMDS_33 } [get_ports { hdmi_rx_p[2] }]; #IO_L2P_T0_34 Sch=hdmi_rx_p[2] ##HDMI out set_property -dict { PACKAGE_PIN AA4 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_cec }]; #IO_L11N_T1_SRCC_34 Sch=hdmi_tx_cec set_property -dict { PACKAGE_PIN U1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_clk_n }]; #IO_L1N_T0_34 Sch=hdmi_tx_clk_n set_property -dict { PACKAGE_PIN T1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_clk_p }]; #IO_L1P_T0_34 Sch=hdmi_tx_clk_p set_property -dict { PACKAGE_PIN AB13 IOSTANDARD LVCMOS25 } [get_ports { hdmi_tx_hpd }]; #IO_L3N_T0_DQS_13 Sch=hdmi_tx_hpd set_property -dict { PACKAGE_PIN U3 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_rscl }]; #IO_L6P_T0_34 Sch=hdmi_tx_rscl set_property -dict { PACKAGE_PIN V3 IOSTANDARD LVCMOS33 } [get_ports { hdmi_tx_rsda }]; #IO_L6N_T0_VREF_34 Sch=hdmi_tx_rsda set_property -dict { PACKAGE_PIN Y1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_n[0] }]; #IO_L5N_T0_34 Sch=hdmi_tx_n[0] set_property -dict { PACKAGE_PIN W1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_p[0] }]; #IO_L5P_T0_34 Sch=hdmi_tx_p[0] set_property -dict { PACKAGE_PIN AB1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_n[1] }]; #IO_L7N_T1_34 Sch=hdmi_tx_n[1] set_property -dict { PACKAGE_PIN AA1 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_p[1] }]; #IO_L7P_T1_34 Sch=hdmi_tx_p[1] set_property -dict { PACKAGE_PIN AB2 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_n[2] }]; #IO_L8N_T1_34 Sch=hdmi_tx_n[2] set_property -dict { PACKAGE_PIN AB3 IOSTANDARD TMDS_33 } [get_ports { hdmi_tx_p[2] }]; #IO_L8P_T1_34 Sch=hdmi_tx_p[2] # DEBUG on JA set_property -dict { PACKAGE_PIN AB22 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[0] }]; #IO_L10N_T1_D15_14 Sch=ja[1] set_property -dict { PACKAGE_PIN AB21 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[1] }]; #IO_L10P_T1_D14_14 Sch=ja[2] set_property -dict { PACKAGE_PIN AB20 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[2] }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ja[3] set_property -dict { PACKAGE_PIN AB18 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[3] }]; #IO_L17N_T2_A13_D29_14 Sch=ja[4] set_property -dict { PACKAGE_PIN Y21 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[4] }]; #IO_L9P_T1_DQS_14 Sch=ja[7] set_property -dict { PACKAGE_PIN AA21 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[5] }]; #IO_L8N_T1_D12_14 Sch=ja[8] set_property -dict { PACKAGE_PIN AA20 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[6] }]; #IO_L8P_T1_D11_14 Sch=ja[9] set_property -dict { PACKAGE_PIN AA18 IOSTANDARD LVCMOS33 } [get_ports { debug_pmod[7] }]; #IO_L17P_T2_A14_D30_14 Sch=ja[10 ##Switches set_property -dict { PACKAGE_PIN E22 IOSTANDARD LVCMOS25 } [get_ports { sw[0] }]; #IO_L22P_T3_16 Sch=sw[0] set_property -dict { PACKAGE_PIN F21 IOSTANDARD LVCMOS25 } [get_ports { sw[1] }]; #IO_25_16 Sch=sw[1] set_property -dict { PACKAGE_PIN G21 IOSTANDARD LVCMOS25 } [get_ports { sw[2] }]; #IO_L24P_T3_16 Sch=sw[2] set_property -dict { PACKAGE_PIN G22 IOSTANDARD LVCMOS25 } [get_ports { sw[3] }]; #IO_L24N_T3_16 Sch=sw[3] set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS25 } [get_ports { sw[4] }]; #IO_L6P_T0_15 Sch=sw[4] set_property -dict { PACKAGE_PIN J16 IOSTANDARD LVCMOS25 } [get_ports { sw[5] }]; #IO_0_15 Sch=sw[5] set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS25 } [get_ports { sw[6] }]; #IO_L19P_T3_A22_15 Sch=sw[6] set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS25 } [get_ports { sw[7] }]; #IO_25_15 Sch=sw[7] ##LEDs set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS25 } [get_ports { led[0] }]; #IO_L15P_T2_DQS_13 Sch=led[0] set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS25 } [get_ports { led[1] }]; #IO_L15N_T2_DQS_13 Sch=led[1] set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS25 } [get_ports { led[2] }]; #IO_L17P_T2_13 Sch=led[2] set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS25 } [get_ports { led[3] }]; #IO_L17N_T2_13 Sch=led[3] set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS25 } [get_ports { led[4] }]; #IO_L14N_T2_SRCC_13 Sch=led[4] set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS25 } [get_ports { led[5] }]; #IO_L16N_T2_13 Sch=led[5] set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS25 } [get_ports { led[6] }]; #IO_L16P_T2_13 Sch=led[6] set_property -dict { PACKAGE_PIN Y13 IOSTANDARD LVCMOS25 } [get_ports { led[7] }]; #IO_L5P_T0_13 Sch=led[7] ##UART set_property -dict { PACKAGE_PIN AA19 IOSTANDARD LVCMOS33 } [get_ports { rs232_tx }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=uart_rx_out ================================================ FILE: src/alignment_detect.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field '0'); signal signal_quality : unsigned(27 downto 0) := (others => '0'); signal holdoff : unsigned(9 downto 0) := (others => '0'); signal error_seen : std_logic := '0'; signal idelay_ce : std_logic := '0'; signal idelay_count : std_logic_vector(4 downto 0) := (others => '0'); signal symbol_sync_i : std_logic := '0'; begin delay_count <= idelay_count; delay_ce <= idelay_ce; detect_alignment_proc: process(clk) begin ------------------------------------------------------------- -- If there are a dozen or so symbol errors in at a rate of -- greater than 1 in a million then advance the delay and -- if that wraps then assert the bitslip signal ------------------------------------------------------------- if rising_edge(clk) then ----------------------------------- -- See if an error has been seen -- -- Holdoff gives a few cycles for -- bitslips and delay changes to -- take effect. ----------------------------------- error_seen <= '0'; if holdoff = 0 then if invalid_symbol = '1' then error_seen <= '1'; end if; else holdoff <= holdoff-1; end if; --------------------------------------------- -- Keep track of valid symbol count vs errors -- -- Each error increase the count by a million, -- each valid sysmbol decreases the count by -- one. So after 12 errors it will cause us to -- change bitslip or delay settings, but it will -- take 7 million cycles until the high four -- bits are zeros (and the link considered OK) ----------------------------------------------- bitslip <= '0'; idelay_ce <= '0'; if error_seen = '1' then if signal_quality(27 downto 24) = x"F" then ------------------------------------------ -- Enough errors to cause us to loose sync -- (if we had it!) ------------------------------------------ symbol_sync_i <= '0'; -------------------------------------- -- Hold off acting on any more errors -- while we adjust the delay or bitslip -------------------------------------- holdoff <= (others => '1'); ----------------------- -- Bitslip if required ----------------------- if unsigned(idelay_count) = 31 then bitslip <= '1'; end if; ------------------------------------------------------------------- -- And adjust the delay setting (will wrap to 0 when bitslipping) ------------------------------------------------------------------- idelay_count <= std_logic_vector(unsigned(idelay_count)+1); idelay_ce <= '1'; ------------------------------------------------------------------- -- It will need 4M good symbols to avoid adjusting the timing again ------------------------------------------------------------------- signal_quality(27 downto 24) <= x"4"; else signal_quality <= signal_quality + x"100000"; -- add a million if there is a symbol error end if; else ----------------------------------------------- -- Count down by one, as we are one symbol -- closer to having a valid stream ----------------------------------------------- if signal_quality(27 downto 24) > 0 then signal_quality <= signal_quality - 1; -- add a million if there is a symvole error; end if; end if; ------------------------------------ -- if we have counted down about 3M -- symbols without any symbol errors -- being seen then we are in sync ------------------------------------ if signal_quality(27 downto 24) = "0000" then symbol_sync <= '1'; end if; end if; end process; end Behavioral; ================================================ FILE: src/audio_meters.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: audio_meters - Behavioral -- -- Description: Insert audio level meters on a video stream. -- -- Will need to make allowances for interlaced sources! ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity audio_meters is Port ( clk : in STD_LOGIC; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0); ------------------------------------- -- Audio Levels ------------------------------------- signal audio_channel : in std_logic_vector(2 downto 0); signal audio_de : in std_logic; signal audio_level : in std_logic_vector(5 downto 0) ); end audio_meters; architecture Behavioral of audio_meters is signal col_count : unsigned(11 downto 0); signal line_count : unsigned(11 downto 0); signal last_hsync : std_logic := '0'; signal last_vsync : std_logic := '0'; signal last_blank : std_logic := '0'; signal mid_blank : std_logic; signal mid_hsync : std_logic; signal mid_vsync : std_logic; signal mid_red : std_logic_vector(7 downto 0); signal mid_green : std_logic_vector(7 downto 0); signal mid_blue : std_logic_vector(7 downto 0); signal bar_draw : std_logic; signal bar_col : unsigned(6 downto 0); -- 0-127 signal bar_line : unsigned(5 downto 0); -- 0-63 type a_level is array (0 to 7) of unsigned(5 downto 0); signal levels : a_level; type a_peak is array (0 to 7) of unsigned(7 downto 0); signal peaks : a_peak; signal pending_drop : std_logic := '0'; signal drop_index : unsigned(2 downto 0) := (others => '0'); signal u_sample : unsigned(5 downto 0) := (others => '0'); signal level : unsigned(5 downto 0); signal peak : unsigned(5 downto 0); begin level_proc: process(clk) begin if rising_edge(clk) then ------------------------------------------------- -- Update the peak level, or if pending_drop is -- set then drop the peak and level by 1 every -- frame. -- -- This causes 'peak' to fall at 1/4th the speed -- of 'level', but makes for inconsistent -- behaviour depending on frame rate :-( ------------------------------------------------- if audio_de = '1' then if levels(to_integer(unsigned(audio_channel))) < unsigned(audio_level) then levels(to_integer(unsigned(audio_channel))) <= unsigned(audio_level); end if; if peaks(to_integer(unsigned(audio_channel))) < unsigned(audio_level &"00") then peaks(to_integer(unsigned(audio_channel))) <= unsigned(audio_level & "00"); end if; else if pending_drop = '1' then if levels(to_integer(drop_index)) > 0 then levels(to_integer(drop_index)) <= levels(to_integer(drop_index))-1; end if; if peaks(to_integer(drop_index)) > 0 then peaks(to_integer(drop_index)) <= peaks(to_integer(drop_index))-1; end if; if drop_index = "000" then pending_drop <= '0'; end if; drop_index <= drop_index-1; end if; end if; -- Signal to reduce (drop' the levels of the meters once each frame (of field for interlaced sources if last_vsync = '0' and in_vsync = '1' then pending_drop <= '1'; drop_index <= (others => '1'); end if; end if; end process; video_proc: process(clk) begin if rising_edge(clk) then out_blank <= mid_blank; out_hsync <= mid_hsync; out_vsync <= mid_vsync; out_red <= mid_red; out_green <= mid_green; out_blue <= mid_blue; if bar_draw = '1' then if bar_col(3 downto 1) /= "000" and bar_col(3 downto 1) /= "111" then if peak > bar_line then if peak > 60 then out_red(out_red'high) <= '1'; else out_green(out_green'high) <= '1'; end if; end if; if level = bar_line then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; end if; end if; ----------------------------------------------------------------------------- -- the mid_* signals contain the video with the box drawn to house the meters ----------------------------------------------------------------------------- mid_blank <= in_blank; mid_hsync <= in_hsync; mid_vsync <= in_vsync; mid_red <= in_red; mid_green <= in_green; mid_blue <= in_blue; -------------------------------------------------- -- For working out if we need to draw colour bars -------------------------------------------------- bar_draw <= '0'; bar_col <= unsigned(col_count(6 downto 0))-1; bar_line <= to_unsigned(64,6)-unsigned(line_count(5 downto 0)); ----------------------------------------------------------------------------- -- Retreive the levels for the bar. There is an -- off-by-one error hidden by the bar boarder. ----------------------------------------------------------------------------- level <= levels(to_integer(col_count(6 downto 4))); peak <= peaks(to_integer(col_count(6 downto 4)))(7 downto 2); ------------------------------------------------------- -- Halve the intensity of the area where the meters are. ------------------------------------------------------- if col_count > 0 and col_count < 129 and line_count > 0 and line_count < 65 then bar_draw <= '1'; end if; if col_count > 0 and col_count < 129 and line_count > 0 and line_count < 65 then mid_red <= "0" & in_red(in_red'high downto 1); mid_green <= "0" & in_green(in_green'high downto 1); mid_blue <= "0" & in_blue(in_blue'high downto 1); end if; -- Draw bounding box left/right sides if (col_count = 0 or col_count = 129) and line_count < 66 then mid_red <= (others => '1'); mid_green <= (others => '1'); mid_blue <= (others => '1'); end if; -- Draw bounding box top/bottom sides if (line_count = 0 or line_count = 65) and col_count < 130 then mid_red <= (others => '1'); mid_green <= (others => '1'); mid_blue <= (others => '1'); end if; -- Increment the column count on when active pixels are seen if in_blank = '0' then col_count <= col_count + 1; end if; -- The end of active video is used to increment the line count if last_blank = '0' and in_blank = '1' then if is_interlaced = '1' then line_count <= line_count + 2; else line_count <= line_count + 1; end if; col_count <= (others => '0'); end if; -- Reset the line count on falling vsync if last_vsync = '1' and in_vsync = '0' then if is_interlaced = '1' and is_second_field = '1' then line_count <= (0 => '1', others => '0'); else line_count <= (others => '0'); end if; end if; -- remember the hsync and vsync values last_vsync <= in_vsync; last_hsync <= in_hsync; last_blank <= in_blank; end if; end process; end Behavioral; ================================================ FILE: src/audio_to_db.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: audio_to_db - Behavioral -- -- Description: Calcuate the approximate DB level of an audio signal, with a -- return of 63 indicating 0db, (e.g. 3 = -60fb) -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity audio_to_db is Port ( clk : in STD_LOGIC; in_channel : in STD_LOGIC_VECTOR (2 downto 0); in_de : in STD_LOGIC; in_sample : in STD_LOGIC_VECTOR (23 downto 0); out_channel : out STD_LOGIC_VECTOR (2 downto 0); out_de : out STD_LOGIC; out_level : out STD_LOGIC_VECTOR (5 downto 0)); end audio_to_db; architecture Behavioral of audio_to_db is signal s7_sample : unsigned (23 downto 0); signal s7_de : STD_LOGIC; signal s7_channel : STD_LOGIC_VECTOR (2 downto 0); signal s7_level : unsigned( 7 downto 0); signal s6_sample : unsigned (23 downto 0); signal s6_de : STD_LOGIC; signal s6_channel : STD_LOGIC_VECTOR (2 downto 0); signal s6_level : unsigned( 7 downto 0); signal s5_sample : unsigned (23 downto 0); signal s5_de : STD_LOGIC; signal s5_channel : STD_LOGIC_VECTOR (2 downto 0); signal s5_level : unsigned( 7 downto 0); signal s4_sample : unsigned (23 downto 0); signal s4_de : STD_LOGIC; signal s4_channel : STD_LOGIC_VECTOR (2 downto 0); signal s4_level : unsigned( 7 downto 0); signal s3_sample : unsigned (23 downto 0); signal s3_de : STD_LOGIC; signal s3_channel : STD_LOGIC_VECTOR (2 downto 0); signal s3_level : unsigned( 7 downto 0); signal s2_sample : unsigned (23 downto 0); signal s2_de : STD_LOGIC; signal s2_channel : STD_LOGIC_VECTOR (2 downto 0); signal s2_level : unsigned( 7 downto 0); signal s1_sample : unsigned (23 downto 0); signal s1_de : STD_LOGIC; signal s1_channel : STD_LOGIC_VECTOR (2 downto 0); begin process(clk) begin if rising_edge(clk) then out_channel <= s7_channel; out_de <= s7_de; if s7_level(7 downto 6) = "00" then out_level <= std_logic_vector(to_unsigned(63,6)-s7_level(5 downto 0)); else out_level <= (others => '0'); end if; -- Finally the last stage to get a db level s7_channel <= s6_channel; s7_de <= s6_de; if s6_sample(22 downto 15) < 72 then s7_level <= s6_level + 5; elsif s6_sample(22 downto 15) < 81 then s7_level <= s6_level + 4; elsif s6_sample(22 downto 15) < 91 then s7_level <= s6_level + 3; elsif s6_sample(22 downto 15) < 102 then s7_level <= s6_level + 2; elsif s6_sample(22 downto 15) < 114 then s7_level <= s6_level + 1; else s7_level <= s6_level + 1; end if; -- Stage 5 - shift up 2 bits if needed(bit 23 of sample will be 0) s6_channel <= s5_channel; s6_de <= s5_de; if s5_sample(23 downto 22) = "00" then s6_sample <= s5_sample(22 downto 0) & "0"; s6_level <= s5_level + to_unsigned(6,8); else s6_sample <= s5_sample; s6_level <= s5_level; end if; -- Stage 5 - shift up 2 bits if needed(bit 23 of sample will be 0) s5_channel <= s4_channel; s5_de <= s4_de; if s4_sample(23 downto 21) = "000" then s5_sample <= s4_sample(21 downto 0) & "00"; s5_level <= s4_level + to_unsigned(12,8); else s5_sample <= s4_sample; s5_level <= s4_level; end if; -- Stage 4 - shift up 4 bits if needed(bit 23 of sample will be 0) s4_channel <= s3_channel; s4_de <= s3_de; if s3_sample(23 downto 19) = "00000" then s4_sample <= s3_sample(19 downto 0) & "0000"; s4_level <= s3_level + to_unsigned(24,8); else s4_sample <= s3_sample; s4_level <= s3_level; end if; -- Stage 3 - shift up 4 bits if needed(bit 23 of sample will be 0) s3_channel <= s2_channel; s3_de <= s2_de; if s2_sample(23 downto 19) = "00000" then s3_sample <= s2_sample(19 downto 0) & "0000"; s3_level <= s2_level + to_unsigned(24,8); else s3_sample <= s2_sample; s3_level <= s2_level; end if; -- Stage 2 - shift up 4 bits if needed(bit 23 of sample will be 0) s2_channel <= s1_channel; s2_de <= s1_de; if s1_sample(23 downto 19) = "00000" then s2_sample <= s1_sample(19 downto 0) & "0000"; s2_level <= to_unsigned(24,8); else s2_sample <= s1_sample; s2_level <= to_unsigned(0,8); end if; --- Stage 1 - remove any sign. s1_channel <= in_channel; s1_de <= in_de; if in_sample(23) = '1' then s1_sample <= to_unsigned(0,24) - unsigned(in_sample); else s1_sample <= unsigned(in_sample); end if; end if; end process; end Behavioral; ================================================ FILE: src/conversion_to_RGB.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: conversion_YCbCr_to_RGB - Behavioral -- -- Description: Convert from RGB, studio level RGB or YCbCr to full range RGB -- -- Designed to take the same amount of time regardless of conversion -- being performed. ---------------------------------------------------------------------------------- -- When using 12-bit studio range inputs and the HD colourspace -- -- R = (Y-64)*1.164 + (Cb-2048) *0.090 + (Cr-2048)*1.793 -- G = (Y-64)*1.164 - (Cb-2048) *0.213 - (Cr-2048)*0.533 -- B = (Y-64)*1.164 + (Cb-2048) *2.112 + (Cr-2048)*0.000 -- -- To avoid the problems with signed/unsigned multiplication this -- has been rearranged to -- -- R = Y*1.164 + Cb*0.090 + Cr*1.793 - 64*1.164 - 2048*0.090 - 2048*1.793 -- G = Y*1.164 - Cb*0.213 - Cr*0.533 - 64*1.164 + 2048*0.213 + 2048*0.533 -- B = Y*1.164 + Cb*2.112 + Cr*0.000 - 64*1.164 - 2048*2.112 - 2048*0.000 -- -- And then all the decimals have been scaled by 4096 This then only requires -- five multipliers (as two are zero and three others are identical. ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity conversion_to_RGB is port ( clk : in std_Logic; input_is_YCbCr : in std_Logic; input_is_sRGB : in std_Logic; ------------------------ in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_U : in std_logic_vector(11 downto 0); -- B or Cb in_V : in std_logic_vector(11 downto 0); -- G or Y in_W : in std_logic_vector(11 downto 0); -- R or Cr ------------------------ out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_R : out std_logic_vector(11 downto 0); out_G : out std_logic_vector(11 downto 0); out_B : out std_logic_vector(11 downto 0)); end entity; architecture Behavioral of conversion_to_RGB is ------------------------------ -- For the pipeline ------------------------------ signal s1_blank : std_logic; signal s1_hsync : std_logic; signal s1_vsync : std_logic; signal s1_U : std_logic_vector(12 downto 0); -- B or Cb, plus underflow guard bit signal s1_V : std_logic_vector(12 downto 0); -- G or Y, plus underflow guard bit signal s1_W : std_logic_vector(12 downto 0); -- R or Cr, plus underflow guard bit signal s2_blank : std_logic; signal s2_hsync : std_logic; signal s2_vsync : std_logic; signal s2_U : std_logic_vector(12 downto 0); -- B or Cb, plus overflow guard bit signal s2_V : std_logic_vector(12 downto 0); -- G or Y, plus overflow guard bit signal s2_W : std_logic_vector(12 downto 0); -- R or Cr, plus overflow guard bit ------------------------------ -- For Calculation ------------------------------ signal a : unsigned(26 downto 0) := (others => '0'); signal b : unsigned(26 downto 0) := (others => '0'); signal c : unsigned(26 downto 0) := (others => '0'); signal d : unsigned(26 downto 0) := (others => '0'); signal e : unsigned(26 downto 0) := (others => '0'); signal R_raw : unsigned(26 downto 0) := (others => '0'); signal G_raw : unsigned(26 downto 0) := (others => '0'); signal B_raw : unsigned(26 downto 0) := (others => '0'); begin clk_proc: process(clk) begin if rising_edge(clk) then ----------------------------------------------- -- Step 3: clamp the result ----------------------------------------------- out_blank <= s2_blank; out_hsync <= s2_hsync; out_vsync <= s2_vsync; if input_is_YCbCr = '0' then -- trap overflows form prior stage if s2_U(s2_U'high) = '0' then out_B <= s2_U(s2_U'high-1 downto 0); else out_B <= (others => '1'); end if; if s2_V(s2_V'high) = '0' then out_G <= s2_V(s2_V'high-1 downto 0); else out_G <= (others => '1'); end if; if s2_W(s2_W'high) = '0' then out_R <= s2_W(s2_W'high-1 downto 0); else out_R <= (others => '1'); end if; else case R_raw(R_raw'high-1 downto R_raw'high-2) is when "00" => out_R <= std_logic_vector(R_raw(R_raw'high-3 downto R_raw'high-14)); -- In range when "01" => out_R <= (others => '1'); -- Overflow when others => out_R <= (others => '0'); -- Underflow end case; case G_raw(G_raw'high-1 downto G_raw'high-2) is when "00" => out_G <= std_logic_vector(G_raw(G_raw'high-3 downto G_raw'high-14)); -- In range when "01" => out_G <= (others => '1'); -- Overflow when others => out_G <= (others => '0'); -- Underflow end case; case B_raw(B_raw'high-1 downto B_raw'high-2) is when "00" => out_B <= std_logic_vector(B_raw(B_raw'high-3 downto B_raw'high-14)); -- In range when "01" => out_B <= (others => '1'); -- Overflow when others => out_B <= (others => '0'); -- Underflow end case; end if; ------------------------------------------------- -- Step 2: Add the partial results and remove the -- offset introduced by the use of studio range ------------------------------------------------- s2_blank <= s1_blank; s2_hsync <= s1_hsync; s2_vsync <= s1_vsync; if input_is_sRGB = '1' then -- Trap underflows from prior stage if s1_U(s1_U'high) = '0' then s2_U <= std_logic_vector(unsigned(s1_U) + unsigned(s1_U(s1_U'high downto 5))); else s2_U <= (others => '0'); end if; if s1_V(s1_V'high) = '0' then s2_V <= std_logic_vector(unsigned(s1_V) + unsigned(s1_V(s1_V'high downto 5))); else s2_V <= (others => '0'); end if; if s1_W(s1_W'high) = '0' then s2_W <= std_logic_vector(unsigned(s1_W) + unsigned(s1_W(s1_W'high downto 5))); else s2_W <= (others => '0'); end if; else s2_U <= s1_U; s2_V <= s1_V; s2_W <= s1_W; end if; R_raw <= a + d - to_unsigned(4767*256 + 0*2048 + 7344*2048, 27); G_raw <= a - b - e + to_unsigned(-4767*256 + 872*2048 + 2183*2048, 27); B_raw <= a + c - to_unsigned(4767*256 + 8650*2048 + 0*2048, 27); ------------------------------------------------- -- Step 1: Multiply the incoming values by the -- Conversion coefficients ------------------------------------------------- s1_blank <= in_blank; s1_hsync <= in_hsync; s1_vsync <= in_vsync; if input_is_sRGB = '1' then s1_U <= std_logic_vector(unsigned('0' & in_U) - 256); s1_V <= std_logic_vector(unsigned('0' & in_V) - 256); s1_W <= std_logic_vector(unsigned('0' & in_W) - 256); else s1_U <= '0' & in_U; s1_V <= '0' & in_V; s1_W <= '0' & in_W; end if; a <= unsigned(in_V) * to_unsigned(4767,15); -- 1.164 * 2^12 b <= unsigned(in_U) * to_unsigned( 872,15); -- 0.213 * 2^12 c <= unsigned(in_U) * to_unsigned(8650,15); -- 2.112 * 2^12 d <= unsigned(in_W) * to_unsigned(7344,15); -- 1.793 * 2^12 e <= unsigned(in_W) * to_unsigned(2183,15); -- 0.533 * 2^12 end if; end process; end architecture; ================================================ FILE: src/deserialiser_1_to_10.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: deserialiser_1_to_10 - Behavioral -- -- Description: A 10-to-1 deserialiser for the Artix 7 -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.ALL; library UNISIM; use UNISIM.VComponents.all; entity deserialiser_1_to_10 is Port ( clk_mgmt : in std_logic; delay_ce : in std_logic; delay_count : in std_logic_vector (4 downto 0); ce : in STD_LOGIC; clk : in std_logic; clk_x1 : in std_logic; bitslip : in std_logic; clk_x5 : in std_logic; serial : in std_logic; reset : in std_logic; data : out std_logic_vector (9 downto 0)); end deserialiser_1_to_10; architecture Behavioral of deserialiser_1_to_10 is signal delayed : std_logic := '0'; signal shift1 : std_logic := '0'; signal shift2 : std_logic := '0'; signal clkb : std_logic := '1'; attribute IODELAY_GROUP : STRING; attribute IODELAY_GROUP of IDELAYE2_inst: label is "idelay_group"; begin IDELAYE2_inst : IDELAYE2 generic map ( CINVCTRL_SEL => "FALSE", DELAY_SRC => "DATAIN", HIGH_PERFORMANCE_MODE => "TRUE", IDELAY_TYPE => "VAR_LOAD", IDELAY_VALUE => 0, PIPE_SEL => "FALSE", REFCLK_FREQUENCY => 200.0, SIGNAL_PATTERN => "DATA" ) port map ( DATAIN => serial, IDATAIN => '0', DATAOUT => delayed, -- CNTVALUEOUT => open, C => clk, CE => delay_ce, CINVCTRL => '0', CNTVALUEIN => delay_count, INC => '0', LD => '1', LDPIPEEN => '0', REGRST => '0' ); clkb <= not clk_x5; ISERDESE2_master : ISERDESE2 generic map ( DATA_RATE => "DDR", DATA_WIDTH => 10, DYN_CLKDIV_INV_EN => "FALSE", DYN_CLK_INV_EN => "FALSE", INIT_Q1 => '0', INIT_Q2 => '0', INIT_Q3 => '0', INIT_Q4 => '0', INTERFACE_TYPE => "NETWORKING", IOBDELAY => "IFD", NUM_CE => 1, OFB_USED => "FALSE", SERDES_MODE => "MASTER", SRVAL_Q1 => '0', SRVAL_Q2 => '0', SRVAL_Q3 => '0', SRVAL_Q4 => '0' ) port map ( O => open, Q1 => data(9), Q2 => data(8), Q3 => data(7), Q4 => data(6), Q5 => data(5), Q6 => data(4), Q7 => data(3), Q8 => data(2), SHIFTOUT1 => shift1, SHIFTOUT2 => shift2, BITSLIP => bitslip, CE1 => ce, CE2 => '1', CLKDIVP => '0', CLK => clk_x5, CLKB => clkb, CLKDIV => clk_x1, OCLK => '0', DYNCLKDIVSEL => '0', DYNCLKSEL => '0', D => '0', DDLY => delayed, OFB => '0', OCLKB => '0', RST => reset, SHIFTIN1 => '0', SHIFTIN2 => '0' ); ISERDESE2_slave : ISERDESE2 generic map ( DATA_RATE => "DDR", DATA_WIDTH => 10, DYN_CLKDIV_INV_EN => "FALSE", DYN_CLK_INV_EN => "FALSE", INIT_Q1 => '0', INIT_Q2 => '0', INIT_Q3 => '0', INIT_Q4 => '0', INTERFACE_TYPE => "NETWORKING", IOBDELAY => "IFD", NUM_CE => 1, OFB_USED => "FALSE", SERDES_MODE => "SLAVE", SRVAL_Q1 => '0', SRVAL_Q2 => '0', SRVAL_Q3 => '0', SRVAL_Q4 => '0' ) port map ( O => open, Q1 => open, Q2 => open, Q3 => data(1), Q4 => data(0), Q5 => open, Q6 => open, Q7 => open, Q8 => open, SHIFTOUT1 => open, SHIFTOUT2 => open, BITSLIP => bitslip, CE1 => ce, CE2 => '1', CLKDIVP => '0', CLK => CLK_x5, CLKB => clkb, CLKDIV => clk_x1, OCLK => '0', DYNCLKDIVSEL => '0', DYNCLKSEL => '0', D => '0', DDLY => '0', OFB => '0', OCLKB => '0', RST => reset, SHIFTIN1 => shift1, SHIFTIN2 => shift2 ); end Behavioral; ================================================ FILE: src/detect_interlace.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: detect_interlace - Behavioral -- -- Description: Detect if the source is interlaced, and report what field is -- being processed -- -- Will need to make allowances for interlaced sources! ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity detect_interlace is Port ( clk : in STD_LOGIC; hsync : in std_logic; vsync : in std_logic; is_interlaced : out std_logic; is_second_field : out std_logic); end entity; architecture Behavioral of detect_interlace is signal last_vsync : std_logic := '0'; signal last_hsync : std_logic := '0'; signal first_quarter : unsigned(11 downto 0) := (others => '0'); signal last_quarter : unsigned(11 downto 0) := (others => '0'); signal hcount : unsigned(11 downto 0) := (others => '0'); signal last_vsync_pos : unsigned(11 downto 0) := (others => '0'); signal second_field : std_logic := '0'; begin clk_proc: process(clk) begin if rising_edge(clk) then if last_vsync = '0' and vsync = '1' then is_second_field <= '0'; if hcount > first_quarter and hcount < last_quarter then -- The second field of an interlaced -- frame is indicated when the vsync is -- asserted in the middle of the scan line. -- -- Also add a little check for a misbehaving source if last_vsync_pos /= hcount then is_interlaced <= '1'; is_second_field <= '1'; second_field <= '1'; else is_interlaced <= '1'; is_second_field <= '1'; second_field <= '1'; end if; else -- If we see two 'field 1's in a row we -- switch back to indicating an -- uninterlaced source if second_field = '0' then is_interlaced <= '0'; end if; is_second_field <= '0'; second_field <= '0'; end if; last_vsync_pos <= hcount; else end if; if last_hsync = '0' and hsync = '1' then hcount <= (others => '0'); first_quarter <= "00" & hcount(11 downto 2); last_quarter <= hcount+1-hcount(11 downto 2); else hcount <= hcount +1; end if; last_vsync <= vsync; last_hsync <= hsync; end if; end process; end architecture; ================================================ FILE: src/dvid_output.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: DVID_output - Behavioral -- -- Description: Convert a stream of pixels into a DVID output -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity DVID_output is Port ( pixel_clk : in std_logic; -- Driven by BUFG pixel_io_clk_x1 : in std_logic; -- Driven by BUFIO pixel_io_clk_x5 : in std_logic; -- Driven by BUFIO -- VGA Signals vga_blank : in std_logic; vga_hsync : in std_logic; vga_vsync : in std_logic; vga_red : in std_logic_vector(7 downto 0); vga_blue : in std_logic_vector(7 downto 0); vga_green : in std_logic_vector(7 downto 0); data_valid : in std_logic; --- DVI-D out tmds_out_clk : out std_logic; tmds_out_ch0 : out std_logic; tmds_out_ch1 : out std_logic; tmds_out_ch2 : out std_logic ); end DVID_output; architecture Behavioral of DVID_output is component tmds_encoder is Port ( clk : in std_logic; data : in std_logic_vector (7 downto 0); c : in std_logic_vector (1 downto 0); blank : in std_logic; encoded : out std_logic_vector (9 downto 0)); end component; component serialiser_10_to_1 is Port ( clk : in std_logic; clk_x5 : in std_logic; reset : in std_logic; data : in std_logic_vector (9 downto 0); serial : out std_logic); end component; signal c0_tmds_symbol : std_logic_vector (9 downto 0); signal c1_tmds_symbol : std_logic_vector (9 downto 0); signal c2_tmds_symbol : std_logic_vector (9 downto 0); signal reset_sr : std_logic_vector (2 downto 0) := (others => '1'); signal reset : std_logic := '1'; begin reset <= reset_sr(0); process(pixel_clk, data_valid) begin if data_valid = '0' then reset_sr <= (others => '1'); elsif rising_edge(pixel_clk) then reset_sr <= '0' & reset_sr(reset_sr'high downto 1); end if; end process; --------------------- -- TMDS Encoders --------------------- c0_tmds: tmds_encoder port map ( clk => pixel_clk, data => vga_blue, c(1) => vga_vsync, c(0) => vga_hsync, blank => vga_blank, encoded => c0_tmds_symbol); c1_tmds: tmds_encoder port map ( clk => pixel_clk, data => vga_green, c => (others => '0'), blank => vga_blank, encoded => c1_tmds_symbol); c2_tmds: tmds_encoder port map ( clk => pixel_clk, data => vga_red, c => (others => '0'), blank => vga_blank, encoded => c2_tmds_symbol); --------------------- -- Output serializers --------------------- ser_ch0: serialiser_10_to_1 port map ( clk => pixel_io_clk_x1, clk_x5 => pixel_io_clk_x5, reset => reset, data => c0_tmds_symbol, serial => tmds_out_ch0); ser_ch1: serialiser_10_to_1 port map ( clk => pixel_io_clk_x1, clk_x5 => pixel_io_clk_x5, reset => reset, data => c1_tmds_symbol, serial => tmds_out_ch1); ser_ch2: serialiser_10_to_1 port map ( clk => pixel_io_clk_x1, clk_x5 => pixel_io_clk_x5, reset => reset, data => c2_tmds_symbol, serial => tmds_out_ch2); ser_clk: serialiser_10_to_1 Port map ( clk => pixel_io_clk_x1, clk_x5 => pixel_io_clk_x5, reset => reset, data => "0000011111", serial => tmds_out_clk); end Behavioral; ================================================ FILE: src/edge_enhance.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: edge_enhance - Behavioral -- -- Description: Video edge enhancement -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity edge_enhance is Port ( clk : in STD_LOGIC; enable_feature : in std_logic; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0)); end edge_enhance; architecture Behavioral of edge_enhance is component line_delay is Port ( clk : in STD_LOGIC; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0)); end component; type a_bits is array(0 to 8) of std_logic; type a_component is array(0 to 8) of std_logic_vector(7 downto 0); signal blanks : a_bits; signal hsyncs : a_bits; signal vsyncs : a_bits; signal reds : a_component; signal greens : a_component; signal blues : a_component; signal bypass_1_blank : std_logic := '0'; signal bypass_1_hsync : std_logic := '0'; signal bypass_1_vsync : std_logic := '0'; signal bypass_1_red : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_1_blue : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_1_green : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_2_blank : std_logic := '0'; signal bypass_2_hsync : std_logic := '0'; signal bypass_2_vsync : std_logic := '0'; signal bypass_2_red : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_2_blue : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_2_green : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_3_blank : std_logic := '0'; signal bypass_3_hsync : std_logic := '0'; signal bypass_3_vsync : std_logic := '0'; signal bypass_3_red : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_3_blue : std_logic_vector(7 downto 0) := (others => '0'); signal bypass_3_green : std_logic_vector(7 downto 0) := (others => '0'); signal sobel_3_hsync : std_logic := '0'; signal sobel_3_blank : std_logic := '0'; signal sobel_3_vsync : std_logic := '0'; signal sobel_3_red : unsigned(12 downto 0) := (others => '0'); signal sobel_3_green : unsigned(12 downto 0) := (others => '0'); signal sobel_3_blue : unsigned(12 downto 0) := (others => '0'); signal sobel_2_hsync : std_logic := '0'; signal sobel_2_blank : std_logic := '0'; signal sobel_2_vsync : std_logic := '0'; signal sobel_2_red_x : unsigned(11 downto 0) := (others => '0'); signal sobel_2_red_y : unsigned(11 downto 0) := (others => '0'); signal sobel_2_green_x : unsigned(11 downto 0) := (others => '0'); signal sobel_2_green_y : unsigned(11 downto 0) := (others => '0'); signal sobel_2_blue_x : unsigned(11 downto 0) := (others => '0'); signal sobel_2_blue_y : unsigned(11 downto 0) := (others => '0'); signal sobel_1_hsync : std_logic := '0'; signal sobel_1_blank : std_logic := '0'; signal sobel_1_vsync : std_logic := '0'; signal sobel_1_red_left : unsigned(11 downto 0) := (others => '0'); signal sobel_1_red_right : unsigned(11 downto 0) := (others => '0'); signal sobel_1_red_top : unsigned(11 downto 0) := (others => '0'); signal sobel_1_red_bottom : unsigned(11 downto 0) := (others => '0'); signal sobel_1_green_left : unsigned(11 downto 0) := (others => '0'); signal sobel_1_green_right : unsigned(11 downto 0) := (others => '0'); signal sobel_1_green_top : unsigned(11 downto 0) := (others => '0'); signal sobel_1_green_bottom : unsigned(11 downto 0) := (others => '0'); signal sobel_1_blue_left : unsigned(11 downto 0) := (others => '0'); signal sobel_1_blue_right : unsigned(11 downto 0) := (others => '0'); signal sobel_1_blue_top : unsigned(11 downto 0) := (others => '0'); signal sobel_1_blue_bottom : unsigned(11 downto 0) := (others => '0'); begin blanks(0) <= in_blank; hsyncs(0) <= in_hsync; vsyncs(0) <= in_vsync; reds(0) <= in_red; greens(0) <= in_green; blues(0) <= in_blue; i_line_delay_1: line_delay Port map ( clk => clk, in_blank => blanks(0), in_hsync => hsyncs(0), in_vsync => vsyncs(0), in_red => reds(0), in_green => greens(0), in_blue => blues(0), out_blank => blanks(3), out_hsync => hsyncs(3), out_vsync => vsyncs(3), out_red => reds(3), out_green => greens(3), out_blue => blues(3) ); i_line_delay_2: line_delay Port map ( clk => clk, in_blank => blanks(3), in_hsync => hsyncs(3), in_vsync => vsyncs(3), in_red => reds(3), in_green => greens(3), in_blue => blues(3), out_blank => blanks(6), out_hsync => hsyncs(6), out_vsync => vsyncs(6), out_red => reds(6), out_green => greens(6), out_blue => blues(6) ); process(clk) begin if rising_edge(clk) then if enable_feature = '1' then out_hsync <= sobel_3_hsync; out_blank <= sobel_3_blank; out_vsync <= sobel_3_vsync; if sobel_3_red(12 downto 12) = "0" then out_red <= std_logic_vector(sobel_3_red(11 downto 4)); else out_red <= (others => '1'); end if; if sobel_3_green(12 downto 12) = "0" then out_green <= std_logic_vector(sobel_3_green(11 downto 4)); else out_green <= (others => '1'); end if; if sobel_3_blue(12 downto 12) = "0" then out_blue <= std_logic_vector(sobel_3_blue(11 downto 4)); else out_blue <= (others => '1'); end if; else out_hsync <= bypass_3_hsync; out_blank <= bypass_3_blank; out_vsync <= bypass_3_vsync; out_red <= bypass_3_red; out_blue <= bypass_3_blue; out_green <= bypass_3_green; end if; -------------------------------------- -- For if we eed to bypass the feature -------------------------------------- bypass_3_blank <= bypass_2_blank; bypass_3_hsync <= bypass_2_hsync; bypass_3_vsync <= bypass_2_vsync; bypass_3_red <= bypass_2_red; bypass_3_blue <= bypass_2_blue; bypass_3_green <= bypass_2_green; bypass_2_blank <= bypass_1_blank; bypass_2_hsync <= bypass_1_hsync; bypass_2_vsync <= bypass_1_vsync; bypass_2_red <= bypass_1_red; bypass_2_blue <= bypass_1_blue; bypass_2_green <= bypass_1_green; bypass_1_blank <= blanks(4); bypass_1_hsync <= hsyncs(4); bypass_1_vsync <= vsyncs(4); bypass_1_red <= reds(4); bypass_1_blue <= blues(4); bypass_1_green <= greens(4); ---------------------------------- --- Calculating the Sobel operator ---------------------------------- sobel_3_blank <= sobel_2_blank; sobel_3_hsync <= sobel_2_hsync; sobel_3_vsync <= sobel_2_vsync; sobel_3_red <= ("0" & sobel_2_red_x) + sobel_2_red_y; sobel_3_green <= ("0" & sobel_2_green_x) + sobel_2_green_y; sobel_3_blue <= ("0" & sobel_2_blue_x) + sobel_2_blue_y; -- For the red channel sobel_2_blank <= sobel_1_blank; sobel_2_hsync <= sobel_1_hsync; sobel_2_vsync <= sobel_1_vsync; if sobel_1_red_left > sobel_1_red_right then sobel_2_red_x <= sobel_1_red_left - sobel_1_red_right; else sobel_2_red_x <= sobel_1_red_right - sobel_1_red_left; end if; if sobel_1_red_top > sobel_1_red_bottom then sobel_2_red_y <= sobel_1_red_top - sobel_1_red_bottom; else sobel_2_red_y <= sobel_1_red_bottom - sobel_1_red_top; end if; -- For the green channel if sobel_1_green_left > sobel_1_green_right then sobel_2_green_x <= sobel_1_green_left - sobel_1_green_right; else sobel_2_green_x <= sobel_1_green_right - sobel_1_green_left; end if; if sobel_1_green_top > sobel_1_green_bottom then sobel_2_green_y <= sobel_1_green_top - sobel_1_green_bottom; else sobel_2_green_y <= sobel_1_green_bottom - sobel_1_green_top; end if; -- For the blue channel if sobel_1_blue_left > sobel_1_blue_right then sobel_2_blue_x <= sobel_1_blue_left - sobel_1_blue_right; else sobel_2_blue_x <= sobel_1_blue_right - sobel_1_blue_left; end if; if sobel_1_blue_top > sobel_1_blue_bottom then sobel_2_blue_y <= sobel_1_blue_top - sobel_1_blue_bottom; else sobel_2_blue_y <= sobel_1_blue_bottom - sobel_1_blue_top; end if; -- Now for the first stage; sobel_1_blank <= blanks(4); sobel_1_hsync <= hsyncs(4); sobel_1_vsync <= vsyncs(4); -- For the red channel sobel_1_red_left <= ("000" & unsigned(reds(0)) & "0") + ("0000" & unsigned(reds(0))) + ("000" & unsigned(reds(3)) & "0") + ("0" & unsigned(reds(3)) & "000") + ("000" & unsigned(reds(6)) & "0") + ("0000" & unsigned(reds(6))); sobel_1_red_right <= ("000" & unsigned(reds(2)) & "0") + ("0000" & unsigned(reds(2))) + ("000" & unsigned(reds(5)) & "0") + ("0" & unsigned(reds(5)) & "000") + ("000" & unsigned(reds(8)) & "0") + ("0000" & unsigned(reds(8))); sobel_1_red_top <= ("000" & unsigned(reds(2)) & "0") + ("0000" & unsigned(reds(2))) + ("000" & unsigned(reds(1)) & "0") + ("0" & unsigned(reds(1)) & "000") + ("000" & unsigned(reds(0)) & "0") + ("0000" & unsigned(reds(0))); sobel_1_red_bottom <= ("000" & unsigned(reds(6)) & "0") + ("0000" & unsigned(reds(6))) + ("000" & unsigned(reds(7)) & "0") + ("0" & unsigned(reds(7)) & "000") + ("000" & unsigned(reds(8)) & "0") + ("0000" & unsigned(reds(8))); -- For the green channel sobel_1_green_left <= ("000" & unsigned(greens(0)) & "0") + ("0000" & unsigned(greens(0))) + ("000" & unsigned(greens(3)) & "0") + ("0" & unsigned(greens(3)) & "000") + ("000" & unsigned(greens(6)) & "0") + ("0000" & unsigned(greens(6))); sobel_1_green_right <= ("000" & unsigned(greens(2)) & "0") + ("0000" & unsigned(greens(2))) + ("000" & unsigned(greens(5)) & "0") + ("0" & unsigned(greens(5)) & "000") + ("000" & unsigned(greens(8)) & "0") + ("0000" & unsigned(greens(8))); sobel_1_green_top <= ("000" & unsigned(greens(2)) & "0") + ("0000" & unsigned(greens(2))) + ("000" & unsigned(greens(1)) & "0") + ("0" & unsigned(greens(1)) & "000") + ("000" & unsigned(greens(0)) & "0") + ("0000" & unsigned(greens(0))); sobel_1_green_bottom <= ("000" & unsigned(greens(6)) & "0") + ("0000" & unsigned(greens(6))) + ("000" & unsigned(greens(7)) & "0") + ("0" & unsigned(greens(7)) & "000") + ("000" & unsigned(greens(8)) & "0") + ("0000" & unsigned(greens(8))); -- For the blue channel sobel_1_blue_left <= ("000" & unsigned(blues(0)) & "0") + ("0000" & unsigned(blues(0))) + ("000" & unsigned(blues(3)) & "0") + ("0" & unsigned(blues(3)) & "000") + ("000" & unsigned(blues(6)) & "0") + ("0000" & unsigned(blues(6))); sobel_1_blue_right <= ("000" & unsigned(blues(2)) & "0") + ("0000" & unsigned(blues(2))) + ("000" & unsigned(blues(5)) & "0") + ("0" & unsigned(blues(5)) & "000") + ("000" & unsigned(blues(8)) & "0") + ("0000" & unsigned(blues(8))); sobel_1_blue_top <= ("000" & unsigned(blues(2)) & "0") + ("0000" & unsigned(blues(2))) + ("000" & unsigned(blues(1)) & "0") + ("0" & unsigned(blues(1)) & "000") + ("000" & unsigned(blues(0)) & "0") + ("0000" & unsigned(blues(0))); sobel_1_blue_bottom <= ("000" & unsigned(blues(6)) & "0") + ("0000" & unsigned(blues(6))) + ("000" & unsigned(blues(7)) & "0") + ("0" & unsigned(blues(7)) & "000") + ("000" & unsigned(blues(8)) & "0") + ("0000" & unsigned(blues(8))); -------------------------------------------------------------------- -- Copy over the short chains that gives us a 3x3 matrix to work with --------------------------------------------------------------------- -- The bottom row blanks(1) <= blanks(0); hsyncs(1) <= hsyncs(0); vsyncs(1) <= vsyncs(0); reds(1) <= reds(0); greens(1) <= greens(0); blues(1) <= blues(0); blanks(2) <= blanks(1); hsyncs(2) <= hsyncs(1); vsyncs(2) <= vsyncs(1); reds(2) <= reds(1); greens(2) <= greens(1); blues(2) <= blues(1); -- The middle row blanks(4) <= blanks(3); hsyncs(4) <= hsyncs(3); vsyncs(4) <= vsyncs(3); reds(4) <= reds(3); greens(4) <= greens(3); blues(4) <= blues(3); blanks(5) <= blanks(4); hsyncs(5) <= hsyncs(4); vsyncs(5) <= vsyncs(4); reds(5) <= reds(4); greens(5) <= greens(4); blues(5) <= blues(4); -- The top row blanks(7) <= blanks(6); hsyncs(7) <= hsyncs(6); vsyncs(7) <= vsyncs(6); reds(7) <= reds(6); greens(7) <= greens(6); blues(7) <= blues(6); blanks(8) <= blanks(7); hsyncs(8) <= hsyncs(7); vsyncs(8) <= vsyncs(7); reds(8) <= reds(7); greens(8) <= greens(7); blues(8) <= blues(7); end if; end process; end Behavioral; ================================================ FILE: src/edid_rom.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: edid_rom - Behavioral -- -- Description: A simple EDID ROM, configured for 1920x1080@60Hz, HDMI format. -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; library UNISIM; use UNISIM.VComponents.all; entity edid_rom is port ( clk : in std_logic; sclk_raw : in std_logic; sdat_raw : inout std_logic := 'Z'; edid_debug : out std_logic_vector(2 downto 0) := (others => '0') ); end entity; architecture Behavioral of edid_rom is type a_edid_rom is array (0 to 255) of std_logic_vector(7 downto 0); signal edid_rom : a_edid_rom := ( ------- BASE EDID Bytes 0 to 35 ----------------------------- -- Header x"00",x"FF",x"FF",x"FF",x"FF",x"FF",x"FF",x"00", -- EISA ID - Manufacturer, Product, x"04",x"43", x"07",x"f2", -- EISA ID -Serial x"01",x"00",x"00",x"00", -- Model/year x"FF", x"11", -- EDID Version x"01", x"04", ------------------------------------ ------------------------------------ -- Digital Video using DVI, 8 bits --- x"81", -- Checksum 0xB6 ------------------------------------ -- Digital Video using HDMI, 8 bits x"A2", -- Checksum 0x95 ------------------------------------ -- Aspect ratio, flag, gamma x"4f", x"00", x"78", ------------------------------------ -- Features x"3E", -- Display x,y Chromaticity V Breaks here! x"EE", x"91", x"a3", x"54", x"4c", x"99", x"26", x"0f", x"50", x"54", -- Established timings x"20", x"00", x"00", -- Standard timings x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", x"01", ------- End of BASE EDID --------------------------------- ----- 18 byte data block 1080p -------- -- Pixel clock x"02",x"3A", -- Horizontal 1920 with 280 blanking x"80", x"18", x"71", -- Vertical 1080 with 45 lines blanking x"38", x"2D", x"40", -- Horizontal front porch x"58",x"2C", -- Vertical front porch x"04",x"05", -- Horizontal and vertical image size x"0f", x"48", x"42", -- Horizontal and vertical boarder x"00", x"00", -- Options (non-interlaces, not 3D, syncs...) x"1E", ----- 18 byte data block 1080i -------- -- Pixel clock x"01",x"1D", -- Horizontal 1920 with 280 blanking x"80", x"18", x"71", -- Vertical 1080 with 45 lines blanking x"1C", x"16", x"20", -- Horizontal front porch x"58",x"2C", -- Vertical front porch -- SEEMS WRONG! x"25",x"00", -- Horizontal and vertical image size x"0f", x"48", x"42", -- Horizontal and vertical boarder x"00", x"00", -- Options (non-interlaces, not 3D, syncs...) x"9E", ----- 18 byte data block 720p -------- -- Pixel clock x"01",x"1D", -- Horizontal 1920 with 280 blanking x"00", x"72", x"51", -- Vertical 1080 with 45 lines blanking x"D0", x"1E", x"20", -- Horizontal front porch x"6E",x"28", -- Vertical front porch -- SEEMS WRONG! x"55",x"00", -- Horizontal and vertical image size x"0f", x"48", x"42", -- Horizontal and vertical boarder x"00", x"00", -- Options (non-interlaces, not 3D, syncs...) x"1E", ----- 18 byte data block 720p -------- -- Monitor name ASCII descriptor x"00", x"00", x"00", x"FC", x"00", -- ASCII name - "ABC LCD47w[lf] " x"48", x"61", x"6D", x"73", x"74", x"65", x"72", x"6B", x"73", x"0A", x"20", x"20", x"20", ----- End of EDID block -- Extension flag & checksum x"01", x"74", x"02", x"03", x"18", x"72", x"47", x"90", x"85", x"04", x"03", x"02", x"07", x"06", x"23", x"09", x"07", x"07", x"83", x"01", x"00", x"00", x"65", x"03", x"0C", x"00", x"10", x"00", x"8E", x"0A", x"D0", x"8A", x"20", x"E0", x"2d", x"10", x"10", x"3E", x"96", x"00", x"1F", x"09", x"00", x"00", x"00", x"18", x"8E", x"0A", x"D0", x"8A", x"20", x"E0", x"2D", x"10", x"10", x"3E", x"96", x"00", x"04", x"03", x"00", x"00", x"00", x"18", x"8E", x"0A", x"A0", x"14", x"51", x"F0", x"16", x"00", x"26", x"7C", x"43", x"00", x"1F", x"09", x"00", x"00", x"00", x"98", x"8E", x"0A", x"A0", x"14", x"51", x"F0", x"16", x"00", x"26", x"7C", x"43", x"00", x"04", x"03", x"00", x"00", x"00", x"98", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"00", x"C9" ); signal sclk_delay : std_logic_vector(2 downto 0); signal sdat_delay : unsigned(6 downto 0); type t_state is ( state_idle, -- States to support writing the device's address state_start, state_dev7, state_dev6, state_dev5, state_dev4, state_dev3, state_dev2, state_dev1, state_dev0, -- States to support writing the address state_ack_device_write, state_addr7, state_addr6, state_addr5, state_addr4, state_addr3, state_addr2, state_addr1, state_addr0, state_addr_ack, -- States to support the selector device state_selector_ack_device_write, state_selector_addr7, state_selector_addr6, state_selector_addr5, state_selector_addr4, state_selector_addr3, state_selector_addr2, state_selector_addr1, state_selector_addr0, state_selector_addr_ack, -- States to support reading from the the EDID ROM state_ack_device_read, state_read7, state_read6, state_read5, state_read4, state_read3, state_read2, state_read1, state_read0, state_read_ack); signal state : t_state := state_idle; signal data_out_sr : std_logic_vector(7 downto 0) := (others => '1'); signal data_shift_reg : std_logic_vector(7 downto 0) := (others => '0'); signal addr_reg : unsigned(7 downto 0) := (others => '0'); signal selector_reg : unsigned(7 downto 0) := (others => '0'); signal data_to_send : std_logic_vector(7 downto 0) := (others => '0'); signal data_out_delay : std_logic_vector(7 downto 0) := (others => '0'); signal PULL_LOW : std_logic := '0'; signal sdat_input : std_logic := '0'; signal sdat_delay_last : std_logic := '0'; begin i_IOBUF: IOBUF generic map ( DRIVE => 12, IOSTANDARD => "DEFAULT", SLEW => "SLOW") port map ( O => sdat_input, -- Buffer output IO => sdat_raw, -- Buffer inout port (connect directly to top-level port) I => '0', -- Buffer input T => data_out_sr(data_out_sr'high) -- 3-state enable input, high=input, low=output ); edid_debug(0) <= std_logic(sdat_delay(sdat_delay'high)); edid_debug(1) <= sclk_raw; process(clk) begin if rising_edge(clk) then -- falling edge on SDAT while sclk is held high = START condition if sclk_delay(1) = '1' and sclk_delay(0) = '1' and sdat_delay_last = '1' and sdat_delay(sdat_delay'high) = '0' then state <= state_start; edid_debug(2) <= '1'; end if; -- rising edge on SDAT while sclk is held high = STOP condition if sclk_delay(1) = '1' and sclk_delay(0) = '1' and sdat_delay_last = '0' and sdat_delay(sdat_delay'high) = '1' then state <= state_idle; selector_reg <= (others => '0'); edid_debug(2) <= '0'; end if; -- rising edge on SCLK - usually a data bit if sclk_delay(1) = '1' and sclk_delay(0) = '0' then -- Move data into a shift register data_shift_reg <= data_shift_reg(data_shift_reg'high-1 downto 0) & std_logic(sdat_delay(sdat_delay'high)); end if; -- falling edge on SCLK - time to change state if sclk_delay(1) = '0' and sclk_delay(0) = '1' then data_out_sr <= data_out_sr(data_out_sr'high-1 downto 0) & '1'; -- Add Pull up case state is when state_start => state <= state_dev7; when state_dev7 => state <= state_dev6; when state_dev6 => state <= state_dev5; when state_dev5 => state <= state_dev4; when state_dev4 => state <= state_dev3; when state_dev3 => state <= state_dev2; when state_dev2 => state <= state_dev1; when state_dev1 => state <= state_dev0; when state_dev0 => if data_shift_reg = x"A1" then state <= state_ack_device_read; data_out_sr(data_out_sr'high) <= '0'; -- Send Slave ACK elsif data_shift_reg = x"A0" then state <= state_ack_device_write; data_out_sr(data_out_sr'high) <= '0'; -- Send Slave ACK elsif data_shift_reg = x"60" then state <= state_selector_ack_device_write; data_out_sr(data_out_sr'high) <= '0'; -- Send Slave ACK else state <= state_idle; end if; when state_ack_device_write => state <= state_addr7; when state_addr7 => state <= state_addr6; when state_addr6 => state <= state_addr5; when state_addr5 => state <= state_addr4; when state_addr4 => state <= state_addr3; when state_addr3 => state <= state_addr2; when state_addr2 => state <= state_addr1; when state_addr1 => state <= state_addr0; when state_addr0 => state <= state_addr_ack; addr_reg <= unsigned(data_shift_reg); data_out_sr(data_out_sr'high) <= '0'; -- Send Slave ACK when state_addr_ack => state <= state_idle; -- SLave ACK and ignore any written data ------------------------------------ -- Process the write to the selector ------------------------------------ when state_selector_ack_device_write => state <= state_selector_addr7; when state_selector_addr7 => state <= state_selector_addr6; when state_selector_addr6 => state <= state_selector_addr5; when state_selector_addr5 => state <= state_selector_addr4; when state_selector_addr4 => state <= state_selector_addr3; when state_selector_addr3 => state <= state_selector_addr2; when state_selector_addr2 => state <= state_selector_addr1; when state_selector_addr1 => state <= state_selector_addr0; when state_selector_addr0 => state <= state_selector_addr_ack; selector_reg <= unsigned(data_shift_reg(7 downto 0)); data_out_sr(data_out_sr'high) <= '0'; -- Send Slave ACK when state_selector_addr_ack => state <= state_idle; -- SLave ACK and ignore any written data ------------------------- when state_ack_device_read => state <= state_read7; data_out_sr <= edid_rom(to_integer(addr_reg)); when state_read7 => state <= state_read6; when state_read6 => state <= state_read5; when state_read5 => state <= state_read4; when state_read4 => state <= state_read3; when state_read3 => state <= state_read2; when state_read2 => state <= state_read1; when state_read1 => state <= state_read0; when state_read0 => state <= state_read_ack; when state_read_ack => if sdat_delay(sdat_delay'high) = '0' then state <= state_read7; data_out_sr <= edid_rom(to_integer(addr_reg+1)); else state <= state_idle; end if; addr_reg <= addr_reg+1; when others => state <= state_idle; end case; end if; sdat_delay_last <= sdat_delay(sdat_delay'high); -- Synchronisers for SCLK and SDAT sclk_delay <= sclk_raw & sclk_delay(sclk_delay'high downto 1); -- Resolve any 'Z' state in simulation - make it pull up. if sdat_input = '0' then if sdat_delay(sdat_delay'high) = '1' then sdat_delay <= sdat_delay - 1; else sdat_delay <= (others => '0'); end if; else if sdat_delay(sdat_delay'high) = '0' then sdat_delay <= sdat_delay + 1; else sdat_delay <= (others => '1'); end if; end if; end if; end process; end architecture; ================================================ FILE: src/expand_422_to_444.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: expand_422_to_444 - Behavioral -- -- Description: Convert incoming 422 data to 444 -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity expand_422_to_444 is Port ( clk : in STD_LOGIC; input_is_422 : in std_logic; ------------------ -- Incoming pixels ------------------ in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_ch2 : in std_logic_vector(7 downto 0); in_ch1 : in std_logic_vector(7 downto 0); in_ch0 : in std_logic_vector(7 downto 0); ------------------- -- Processed pixels ------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_U : out std_logic_vector(11 downto 0); -- B or Cb out_V : out std_logic_vector(11 downto 0); -- G or Y out_W : out std_logic_vector(11 downto 0) -- R or Cr ); end expand_422_to_444; architecture Behavioral of expand_422_to_444 is signal in_blank_1 : std_logic := '0'; signal in_hsync_1 : std_logic := '0'; signal in_vsync_1 : std_logic := '0'; signal in_ch0_1 : std_logic_vector(7 downto 0) := (others => '0'); signal in_ch1_1 : std_logic_vector(7 downto 0) := (others => '0'); signal in_ch2_1 : std_logic_vector(7 downto 0) := (others => '0'); signal in_blank_2 : std_logic := '0'; signal in_hsync_2 : std_logic := '0'; signal in_vsync_2 : std_logic := '0'; signal in_ch0_2 : std_logic_vector(7 downto 0) := (others => '0'); signal in_ch1_2 : std_logic_vector(7 downto 0) := (others => '0'); signal in_ch2_2 : std_logic_vector(7 downto 0) := (others => '0'); signal first_of_pair : std_logic := '0'; begin process(clk) begin if rising_edge(clk) then if input_is_422 = '1' then ------------------------------------------------------ -- For 422, copy the chroma values between pixel pairs ------------------------------------------------------ out_blank <= in_blank_1; out_hsync <= in_hsync_1; out_vsync <= in_vsync_1; if in_blank_1 = '1' then first_of_pair <= '1'; out_U <= in_ch2_1 & in_ch0_1(7 downto 4); -- Cb out_V <= in_ch1_1 & in_ch0_1(3 downto 0); -- Y out_W <= in_ch2_1 & in_ch0_1(7 downto 4); -- Cr else if first_of_pair = '1' then -- Take Cr from the next pixel first_of_pair <= '0'; out_U <= in_ch2_1 & in_ch0_1(7 downto 4); -- Cb out_V <= in_ch1_1 & in_ch0_1(3 downto 0); -- Y out_W <= in_ch2 & in_ch0 (7 downto 4); -- Cr else -- Take Cb from the prior pixel first_of_pair <= '1'; out_U <= in_ch2_2 & in_ch0_2(7 downto 4); -- Cb out_V <= in_ch1_1 & in_ch0_1(3 downto 0); -- Y out_W <= in_ch2_1 & in_ch0_1(7 downto 4); -- Cr end if; end if; else ------------------------------------------------------ -- Minimal processing for 422 (either RGB or YCbCr) ------------------------------------------------------ out_blank <= in_blank_1; out_hsync <= in_hsync_1; out_vsync <= in_vsync_1; out_U <= in_ch0_1 & "0000"; -- B or Cb out_V <= in_ch1_1 & "0000"; -- G or Y out_W <= in_ch2_1 & "0000"; -- R or Cr end if; -- Remember the pixel for two cycles in_blank_1 <= in_blank; in_hsync_1 <= in_hsync; in_vsync_1 <= in_vsync; in_ch0_1 <= in_ch0; in_ch1_1 <= in_ch1; in_ch2_1 <= in_ch2; in_blank_2 <= in_blank_1; in_hsync_2 <= in_hsync_1; in_vsync_2 <= in_vsync_1; in_ch0_2 <= in_ch0_1; in_ch1_2 <= in_ch1_1; in_ch2_2 <= in_ch2_1; end if; end process; end Behavioral; ================================================ FILE: src/extract_audio_samples.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: extract_audio_samples - Behavioral -- -- Description: Extract audio data from the HDMI ADP data stream -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity extract_audio_samples is Port ( clk : in STD_LOGIC; adp_data_valid : in STD_LOGIC; adp_header_bit : in STD_LOGIC; adp_frame_bit : in STD_LOGIC; adp_subpacket0_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket1_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket2_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket3_bits : in STD_LOGIC_VECTOR (1 downto 0); audio_de : out STD_LOGIC; audio_channel : out STD_LOGIC_VECTOR (2 downto 0); audio_sample : out STD_LOGIC_VECTOR (23 downto 0) ); end extract_audio_samples; architecture Behavioral of extract_audio_samples is signal header_bits : STD_LOGIC_VECTOR (31 downto 0); signal frame_bits : STD_LOGIC_VECTOR (31 downto 0); signal subpacket0_bits : STD_LOGIC_VECTOR (63 downto 0); signal subpacket1_bits : STD_LOGIC_VECTOR (63 downto 0); signal subpacket2_bits : STD_LOGIC_VECTOR (63 downto 0); signal subpacket3_bits : STD_LOGIC_VECTOR (63 downto 0); signal grab_other_channel : std_logic := '0'; begin process(clk) begin if rising_edge(clk) then ----------------------------------------------- -- Move the incoming bits into a shift register ----------------------------------------------- header_bits <= adp_header_bit & header_bits(header_bits'high downto 1); frame_bits <= (adp_frame_bit and adp_data_valid) & frame_bits(frame_bits'high downto 1); subpacket0_bits <= adp_subpacket0_bits & subpacket0_bits(subpacket0_bits'high downto 2); subpacket1_bits <= adp_subpacket1_bits & subpacket1_bits(subpacket1_bits'high downto 2); subpacket2_bits <= adp_subpacket2_bits & subpacket2_bits(subpacket2_bits'high downto 2); subpacket3_bits <= adp_subpacket3_bits & subpacket3_bits(subpacket3_bits'high downto 2); audio_de <= '0'; if grab_other_channel = '1' then audio_de <= header_bits(7); audio_channel <= "001"; audio_sample <= subpacket0_bits(45 downto 22); grab_other_channel <= '0'; end if; if frame_bits = x"FFFFFFFE" then ------------------------------------------------ -- Check the packet type as being audio samples ------------------------------------------------ if header_bits(7 downto 0) = x"02" then audio_de <= header_bits(8); audio_channel <= "000"; audio_sample <= subpacket0_bits(23 downto 0); grab_other_channel <= '1'; end if; end if; end if; end process; end Behavioral; ================================================ FILE: src/extract_video_infopacket_data.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: extract_video_infopacket_data - Behavioral -- -- Description: Extract a couple of fields from the video infopacket, allowin use -- to correctly convert the incoming pixels into RGB 444 for internal -- processing. -- -- Bits 14:13 indicate the colour space and 444 vs 422. -- Bits 27:26 indicate if the pixels are studio level (16-240) -- or full range (0-255) -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity extract_video_infopacket_data is Port ( clk : in STD_LOGIC; adp_data_valid : in STD_LOGIC; adp_header_bit : in STD_LOGIC; adp_frame_bit : in STD_LOGIC; adp_subpacket0_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket1_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket2_bits : in STD_LOGIC_VECTOR (1 downto 0); adp_subpacket3_bits : in STD_LOGIC_VECTOR (1 downto 0); input_is_YCbCr : out STD_LOGIC; input_is_422 : out STD_LOGIC; input_is_sRGB : out STD_LOGIC); end extract_video_infopacket_data; architecture Behavioral of extract_video_infopacket_data is -- For this usage, we are only interested in four bits that are all in the first -- 16 transfers of the 32-bit packets signal header_bits : STD_LOGIC_VECTOR (15 downto 0); signal frame_bits : STD_LOGIC_VECTOR (15 downto 0); signal subpacket0_bits : STD_LOGIC_VECTOR (31 downto 0); signal updated : std_logic := '0'; begin process(clk) begin if rising_edge(clk) then if adp_data_valid = '1' then ----------------------------------------------- -- Move the incoming bits into a shift register ----------------------------------------------- header_bits <= adp_header_bit & header_bits(header_bits'high downto 1); frame_bits <= adp_frame_bit & frame_bits(frame_bits'high downto 1); subpacket0_bits <= adp_subpacket0_bits & subpacket0_bits(subpacket0_bits'high downto 2); updated <= '1'; end if; ---------------------------------------------------- -- The 0 in frame bits indicates the start of packet ---------------------------------------------------- if updated = '1' and frame_bits = x"FFFE" then -- 82 is the type of packet, 02 is the version if header_bits = x"0282" then case subpacket0_bits(14 downto 13) is when "00" => input_is_YCbCr <= '0'; input_is_422 <= '0'; when "01" => input_is_YCbCr <= '1'; input_is_422 <= '1'; when "10" => input_is_YCbCr <= '1'; input_is_422 <= '0'; when others => NULL; end case; case subpacket0_bits(27 downto 26) is when "01" => input_is_sRGB <= '1'; when others => input_is_sRGB <= '0'; end case; end if; end if; end if; end process; end Behavioral; ================================================ FILE: src/guidelines.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: guidelines - Behavioral -- -- Description: When enabled, put guidelines on the screen -- -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity guidelines is Port ( clk : in STD_LOGIC; enable_feature : in std_logic; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0)); end guidelines; architecture Behavioral of guidelines is signal hcount : unsigned(11 downto 0) := (others => '0'); signal vcount : unsigned(11 downto 0) := (others => '0'); signal h_size : unsigned(11 downto 0) := (others => '0'); signal v_size : unsigned(11 downto 0) := (others => '0'); signal last_blank : std_logic := '0'; signal last_vsync : std_logic := '0'; begin process(clk) begin if rising_edge(clk) then out_blank <= in_blank; out_hsync <= in_hsync; out_vsync <= in_vsync; out_red <= in_red; out_green <= in_green; out_blue <= in_blue; if enable_feature = '1' then if h_size = 1280 then if hcount = 426 or hcount = 854 then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; end if; if h_size = 1920 then if hcount = 640 or hcount = 1280 then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; end if; if v_size = 720 then if vcount = 240 or vcount = 480 then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; end if; if v_size = 1080 then if is_interlaced = '0' and (vcount = 360 or vcount = 720) then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; if is_interlaced = '1' and (vcount = 180 or vcount = 360) then out_red <= (others => '1'); out_green <= (others => '1'); out_blue <= (others => '1'); end if; end if; end if; ------------------------------------------------------------- -- Count the number of lines in a frame (not field!!!) ------------------------------------------------------------- if last_blank = '0' and in_blank = '1' then vcount <= vcount + 1; end if; ------------------------------------------------------------- -- Use the falling edge of VSYNC to to capture the number of -- lines on the screen, as the rising edge is where the -- interaced field is detected and can be a bit unstable. ------------------------------------------------------------- if in_vsync = '0' and last_vsync = '1' and is_second_field = '0'then vcount <= (others => '0'); v_size <= vcount; end if; ------------------------------------------------------------- -- Count the width of the frame ------------------------------------------------------------- if in_blank = '1' then if hcount /= 0 then h_size <= hcount; end if; hcount <= (others => '0'); else hcount <= hcount + 1; end if; last_blank <= in_blank; last_vsync <= in_vsync; if enable_feature = '1' and in_blank = '0' then end if; end if; end process; end Behavioral; ================================================ FILE: src/hdmi_design.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Create Date: 22.07.2015 21:10:34 -- Module Name: hdmi_design - Behavioral -- Project Name: -- -- Description: Top level of a video processing design -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; library UNISIM; use UNISIM.VComponents.all; entity hdmi_design is Port ( clk100 : in STD_LOGIC; -- Control signals led : out std_logic_vector(7 downto 0) :=(others => '0'); sw : in std_logic_vector(7 downto 0) :=(others => '0'); debug_pmod : out std_logic_vector(7 downto 0) :=(others => '0'); --HDMI input signals hdmi_rx_cec : inout std_logic; hdmi_rx_hpa : out std_logic; hdmi_rx_scl : in std_logic; hdmi_rx_sda : inout std_logic; hdmi_rx_txen : out std_logic; hdmi_rx_clk_n : in std_logic; hdmi_rx_clk_p : in std_logic; hdmi_rx_n : in std_logic_vector(2 downto 0); hdmi_rx_p : in std_logic_vector(2 downto 0); --- HDMI out hdmi_tx_cec : inout std_logic; hdmi_tx_clk_n : out std_logic; hdmi_tx_clk_p : out std_logic; hdmi_tx_hpd : in std_logic; hdmi_tx_rscl : inout std_logic; hdmi_tx_rsda : inout std_logic; hdmi_tx_p : out std_logic_vector(2 downto 0); hdmi_tx_n : out std_logic_vector(2 downto 0); -- For dumping symbols rs232_tx : out std_logic ); end hdmi_design; architecture Behavioral of hdmi_design is component hdmi_io is Port ( clk100 : in STD_LOGIC; ------------------------------- -- Control signals ------------------------------- clock_locked : out std_logic; data_synced : out std_logic; debug : out std_logic_vector(7 downto 0); ------------------------------- --HDMI input signals ------------------------------- hdmi_rx_cec : inout std_logic; hdmi_rx_hpa : out std_logic; hdmi_rx_scl : in std_logic; hdmi_rx_sda : inout std_logic; hdmi_rx_txen : out std_logic; hdmi_rx_clk_n : in std_logic; hdmi_rx_clk_p : in std_logic; hdmi_rx_n : in std_logic_vector(2 downto 0); hdmi_rx_p : in std_logic_vector(2 downto 0); ------------- -- HDMI out ------------- hdmi_tx_cec : inout std_logic; hdmi_tx_clk_n : out std_logic; hdmi_tx_clk_p : out std_logic; hdmi_tx_hpd : in std_logic; hdmi_tx_rscl : inout std_logic; hdmi_tx_rsda : inout std_logic; hdmi_tx_p : out std_logic_vector(2 downto 0); hdmi_tx_n : out std_logic_vector(2 downto 0); pixel_clk : out std_logic; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_hdmi_detected : out std_logic; in_blank : out std_logic; in_hsync : out std_logic; in_vsync : out std_logic; in_red : out std_logic_vector(7 downto 0); in_green : out std_logic_vector(7 downto 0); in_blue : out std_logic_vector(7 downto 0); is_interlaced : out std_logic; is_second_field : out std_logic; ------------------------------------- -- Audio Levels ------------------------------------- audio_channel : out std_logic_vector(2 downto 0); audio_de : out std_logic; audio_sample : out std_logic_vector(23 downto 0); ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : in std_logic; out_hsync : in std_logic; out_vsync : in std_logic; out_red : in std_logic_vector(7 downto 0); out_green : in std_logic_vector(7 downto 0); out_blue : in std_logic_vector(7 downto 0); ----------------------------------- -- For symbol dump or retransmit ----------------------------------- symbol_sync : out std_logic; -- indicates a fixed reference point in the frame. symbol_ch0 : out std_logic_vector(9 downto 0); symbol_ch1 : out std_logic_vector(9 downto 0); symbol_ch2 : out std_logic_vector(9 downto 0) ); end component; signal symbol_sync : std_logic; signal symbol_ch0 : std_logic_vector(9 downto 0); signal symbol_ch1 : std_logic_vector(9 downto 0); signal symbol_ch2 : std_logic_vector(9 downto 0); component pixel_processing is Port ( clk : in STD_LOGIC; switches : in std_logic_vector(7 downto 0); ------------------ -- Incoming pixels ------------------ in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ------------------- -- Processed pixels ------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0); ------------------------------------- -- Audio samples for metering ------------------------------------- audio_channel : in std_logic_vector(2 downto 0); audio_de : in std_logic; audio_sample : in std_logic_vector(23 downto 0) ); end component; component symbol_dump is port ( clk : in std_logic; clk100 : in std_logic; symbol_sync : in std_logic; -- indicates a fixed reference point in the frame. symbol_ch0 : in std_logic_vector(9 downto 0); symbol_ch1 : in std_logic_vector(9 downto 0); symbol_ch2 : in std_logic_vector(9 downto 0); rs232_tx : out std_logic); end component; signal pixel_clk : std_logic; signal in_blank : std_logic; signal in_hsync : std_logic; signal in_vsync : std_logic; signal in_red : std_logic_vector(7 downto 0); signal in_green : std_logic_vector(7 downto 0); signal in_blue : std_logic_vector(7 downto 0); signal is_interlaced : std_logic; signal is_second_field : std_logic; signal out_blank : std_logic; signal out_hsync : std_logic; signal out_vsync : std_logic; signal out_red : std_logic_vector(7 downto 0); signal out_green : std_logic_vector(7 downto 0); signal out_blue : std_logic_vector(7 downto 0); signal audio_channel : std_logic_vector(2 downto 0); signal audio_de : std_logic; signal audio_sample : std_logic_vector(23 downto 0); signal debug : std_logic_vector(7 downto 0); begin debug_pmod <= debug; led <= debug; i_hdmi_io: hdmi_io port map ( clk100 => clk100, --------------------- -- Control signals --------------------- clock_locked => open, data_synced => open, debug => debug, --------------------- -- HDMI input signals --------------------- hdmi_rx_cec => hdmi_rx_cec, hdmi_rx_hpa => hdmi_rx_hpa, hdmi_rx_scl => hdmi_rx_scl, hdmi_rx_sda => hdmi_rx_sda, hdmi_rx_txen => hdmi_rx_txen, hdmi_rx_clk_n => hdmi_rx_clk_n, hdmi_rx_clk_p => hdmi_rx_clk_p, hdmi_rx_p => hdmi_rx_p, hdmi_rx_n => hdmi_rx_n, ---------------------- -- HDMI output signals ---------------------- hdmi_tx_cec => hdmi_tx_cec, hdmi_tx_clk_n => hdmi_tx_clk_n, hdmi_tx_clk_p => hdmi_tx_clk_p, hdmi_tx_hpd => hdmi_tx_hpd, hdmi_tx_rscl => hdmi_tx_rscl, hdmi_tx_rsda => hdmi_tx_rsda, hdmi_tx_p => hdmi_tx_p, hdmi_tx_n => hdmi_tx_n, pixel_clk => pixel_clk, ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank => in_blank, in_hsync => in_hsync, in_vsync => in_vsync, in_red => in_red, in_green => in_green, in_blue => in_blue, is_interlaced => is_interlaced, is_second_field => is_second_field, ----------------------------------- -- For symbol dump or retransmit ----------------------------------- audio_channel => audio_channel, audio_de => audio_de, audio_sample => audio_sample, ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank => out_blank, out_hsync => out_hsync, out_vsync => out_vsync, out_red => out_red, out_green => out_green, out_blue => out_blue, symbol_sync => symbol_sync, symbol_ch0 => symbol_ch0, symbol_ch1 => symbol_ch1, symbol_ch2 => symbol_ch2 ); i_processing: pixel_processing Port map ( clk => pixel_clk, switches => sw, ------------------ -- Incoming pixels ------------------ in_blank => in_blank, in_hsync => in_hsync, in_vsync => in_vsync, in_red => in_red, in_green => in_green, in_blue => in_blue, is_interlaced => is_interlaced, is_second_field => is_second_field, audio_channel => audio_channel, audio_de => audio_de, audio_sample => audio_sample, ------------------- -- Processed pixels ------------------- out_blank => out_blank, out_hsync => out_hsync, out_vsync => out_vsync, out_red => out_red, out_green => out_green, out_blue => out_blue ); -- Swap to this if you want to capture the HDMI symbols -- and send them up the RS232 port --rs232_tx <= '1'; i_symbol_dump: symbol_dump port map ( clk => pixel_clk, clk100 => clk100, symbol_sync => symbol_sync, symbol_ch0 => symbol_ch0, symbol_ch1 => symbol_ch1, symbol_ch2 => symbol_ch2, rs232_tx => rs232_tx); end Behavioral; ================================================ FILE: src/hdmi_input.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: hdmi_input - Behavioral -- -- Description: Decode the video data out of an incoming HDMI data stream. -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity hdmi_input is Port ( system_clk : in std_logic; debug : out std_logic_vector(5 downto 0); hdmi_detected : out std_logic; pixel_clk : out std_logic; -- Driven by BUFG pixel_io_clk_x1 : out std_logic; -- Driven by BUFFIO pixel_io_clk_x5 : out std_logic; -- Driven by BUFFIO -- HDMI input signals hdmi_in_clk : in std_logic; hdmi_in_ch0 : in std_logic; hdmi_in_ch1 : in std_logic; hdmi_in_ch2 : in std_logic; -- Status pll_locked : out std_logic; symbol_sync : out std_logic; -- Raw data signals raw_blank : out std_logic; raw_hsync : out std_logic; raw_vsync : out std_logic; raw_ch0 : out std_logic_vector(7 downto 0); raw_ch1 : out std_logic_vector(7 downto 0); raw_ch2 : out std_logic_vector(7 downto 0); -- ADP data adp_data_valid : out std_logic; adp_header_bit : out std_logic; adp_frame_bit : out std_logic; adp_subpacket0_bits : out std_logic_vector(1 downto 0); adp_subpacket1_bits : out std_logic_vector(1 downto 0); adp_subpacket2_bits : out std_logic_vector(1 downto 0); adp_subpacket3_bits : out std_logic_vector(1 downto 0); -- For later reuse symbol_ch0 : out std_logic_vector(9 downto 0); symbol_ch1 : out std_logic_vector(9 downto 0); symbol_ch2 : out std_logic_vector(9 downto 0) ); end hdmi_input; architecture Behavioral of hdmi_input is component input_channel is Port ( clk_mgmt : in STD_LOGIC; clk : in STD_LOGIC; clk_x1 : in STD_LOGIC; clk_x5 : in STD_LOGIC; serial : in STD_LOGIC; reset : in STD_LOGIC; ce : in STD_LOGIC; invalid_symbol : out std_logic; symbol : out std_logic_vector (9 downto 0); ctl_valid : out std_logic; ctl : out std_logic_vector (1 downto 0); terc4_valid : out std_logic; terc4 : out std_logic_vector (3 downto 0); guardband_valid : out std_logic; guardband : out std_logic_vector (0 downto 0); data_valid : out std_logic; data : out std_logic_vector (7 downto 0); symbol_sync : out STD_LOGIC); end component; signal clk_pixel_raw : std_logic; component alignment_detect is Port ( clk : in STD_LOGIC; invalid_symbol : in STD_LOGIC; delay_count : out STD_LOGIC_VECTOR(4 downto 0); delay_ce : out STD_LOGIC; bitslip : out STD_LOGIC; symbol_sync : out STD_LOGIC); end component; signal clk_pixel : std_logic; signal clk_pixel_x1 : std_logic; signal clk_pixel_x5 : std_logic; signal clk_pixel_x1_raw : std_logic; signal clk_pixel_x5_raw : std_logic; signal clk_200_raw : std_logic; signal clk_200 : std_logic; signal clkfb_1 : std_logic; signal clkfb_2 : std_logic; signal locked : std_logic; signal reset : std_logic; signal ser_reset : std_logic; signal ser_ce : std_logic; ------------------------------------------------------------- -- The raw 10-bit received symbols ------------------------------------------------------------- signal ch0_symbol : std_logic_vector(9 downto 0); signal ch1_symbol : std_logic_vector(9 downto 0); signal ch2_symbol : std_logic_vector(9 downto 0); ------------------------------------------------------------- -- For the decoded TMDS data ------------------------------------------------------------- signal ch0_invalid_symbol : std_logic; signal ch0_ctl_valid : std_logic; signal ch0_ctl : std_logic_vector(1 downto 0); signal ch0_terc4_valid : std_logic; signal ch0_terc4 : std_logic_vector (3 downto 0); signal ch0_data_valid : std_logic; signal ch0_data : std_logic_vector(7 downto 0); signal ch0_guardband_valid : std_logic; signal ch0_guardband : std_logic_vector (0 downto 0); signal ch0_delay_count : std_logic_vector (4 downto 0); signal ch0_delay_ce : STD_LOGIC; signal ch0_bitslip : STD_LOGIC; signal ch0_symbol_sync : STD_LOGIC; signal ch0_invalid_symbol_1 : std_logic; signal ch0_ctl_valid_1 : std_logic; signal ch0_ctl_1 : std_logic_vector(1 downto 0); signal ch0_terc4_valid_1 : std_logic; signal ch0_terc4_1 : std_logic_vector (3 downto 0); signal ch0_data_valid_1 : std_logic; signal ch0_data_1 : std_logic_vector(7 downto 0); signal ch1_invalid_symbol : std_logic; signal ch1_ctl_valid : std_logic; signal ch1_ctl : std_logic_vector(1 downto 0); signal ch1_terc4_valid : std_logic; signal ch1_terc4 : std_logic_vector (3 downto 0); signal ch1_data_valid : std_logic; signal ch1_data : std_logic_vector(7 downto 0); signal ch1_guardband_valid : std_logic; signal ch1_guardband : std_logic_vector (0 downto 0); signal ch1_delay_count : std_logic_vector (4 downto 0); signal ch1_delay_ce : STD_LOGIC; signal ch1_bitslip : STD_LOGIC; signal ch1_symbol_sync : STD_LOGIC; signal ch1_invalid_symbol_1 : std_logic; signal ch1_ctl_valid_1 : std_logic; signal ch1_ctl_1 : std_logic_vector(1 downto 0); signal ch1_terc4_valid_1 : std_logic; signal ch1_terc4_1 : std_logic_vector (3 downto 0); signal ch1_data_valid_1 : std_logic; signal ch1_data_1 : std_logic_vector(7 downto 0); signal ch2_invalid_symbol : std_logic; signal ch2_ctl_valid : std_logic; signal ch2_ctl : std_logic_vector(1 downto 0); signal ch2_terc4_valid : std_logic; signal ch2_terc4 : std_logic_vector (3 downto 0); signal ch2_data_valid : std_logic; signal ch2_data : std_logic_vector(7 downto 0); signal ch2_guardband_valid : std_logic; signal ch2_guardband : std_logic_vector (0 downto 0); signal ch2_delay_count : std_logic_vector (4 downto 0); signal ch2_delay_ce : STD_LOGIC; signal ch2_bitslip : STD_LOGIC; signal ch2_symbol_sync : STD_LOGIC; signal ch2_invalid_symbol_1 : std_logic; signal ch2_ctl_valid_1 : std_logic; signal ch2_ctl_1 : std_logic_vector(1 downto 0); signal ch2_terc4_valid_1 : std_logic; signal ch2_terc4_1 : std_logic_vector (3 downto 0); signal ch2_data_valid_1 : std_logic; signal ch2_data_1 : std_logic_vector(7 downto 0); signal reset_counter : unsigned(7 downto 0) := (others => '1'); signal vdp_prefix_detect : std_logic_vector(7 downto 0) := (others => '0'); signal vdp_guardband_detect : std_logic := '0'; signal vdp_prefix_seen : std_logic := '0'; signal in_vdp : std_logic := '0'; signal adp_prefix_detect : std_logic_vector(7 downto 0) := (others => '0'); signal adp_guardband_detect : std_logic := '0'; signal adp_prefix_seen : std_logic := '0'; signal in_adp : std_logic := '0'; signal dvid_mode : std_logic := '0'; signal last_was_ctl : std_logic := '0'; signal in_dvid : std_logic := '0'; signal symbol_sync_i : std_logic := '0'; begin pll_locked <= locked; symbol_sync <= symbol_sync_i; reset <= std_logic(reset_counter(reset_counter'high)); symbol_ch0 <= ch0_symbol; symbol_ch1 <= ch1_symbol; symbol_ch2 <= ch2_symbol; debug <= ch2_invalid_symbol & ch1_invalid_symbol & ch0_invalid_symbol & dvid_mode & locked & symbol_sync_i; -------------------------------------------- -- a 200MHz clock for the IDELAY reference -------------------------------------------- clk_MMCME2_BASE_inst : MMCME2_BASE generic map ( BANDWIDTH => "OPTIMIZED", -- Jitter programming (OPTIMIZED, HIGH, LOW) DIVCLK_DIVIDE => 1, -- Master division value (1-106) CLKFBOUT_MULT_F => 8.0, -- Multiply value for all CLKOUT (2.000-64.000). CLKFBOUT_PHASE => 0.0, -- Phase offset in degrees of CLKFB (-360.000-360.000). CLKIN1_PERIOD => 10.0, -- Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128) CLKOUT0_DIVIDE_F => 4.0, -- Divide amount for CLKOUT0 (1.000-128.000). CLKOUT1_DIVIDE => 1, CLKOUT2_DIVIDE => 1, CLKOUT3_DIVIDE => 1, CLKOUT4_DIVIDE => 1, CLKOUT5_DIVIDE => 1, CLKOUT6_DIVIDE => 1, -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99). CLKOUT0_DUTY_CYCLE => 0.5, CLKOUT1_DUTY_CYCLE => 0.5, CLKOUT2_DUTY_CYCLE => 0.5, CLKOUT3_DUTY_CYCLE => 0.5, CLKOUT4_DUTY_CYCLE => 0.5, CLKOUT5_DUTY_CYCLE => 0.5, CLKOUT6_DUTY_CYCLE => 0.5, -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000). CLKOUT0_PHASE => 0.0, CLKOUT1_PHASE => 0.0, CLKOUT2_PHASE => 0.0, CLKOUT3_PHASE => 0.0, CLKOUT4_PHASE => 0.0, CLKOUT5_PHASE => 0.0, CLKOUT6_PHASE => 0.0, CLKOUT4_CASCADE => FALSE, -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) REF_JITTER1 => 0.0, -- Reference input jitter in UI (0.000-0.999). STARTUP_WAIT => FALSE -- Delays DONE until MMCM is locked (FALSE, TRUE) ) port map ( -- Clock Outputs: 1-bit (each) output: User configurable clock outputs CLKOUT0 => clk_200_raw, -- 1-bit output: CLKOUT0 CLKOUT0B => open, -- 1-bit output: Inverted CLKOUT0 CLKOUT1 => open, -- 1-bit output: CLKOUT1 CLKOUT1B => open, -- 1-bit output: Inverted CLKOUT1 CLKOUT2 => open, -- 1-bit output: CLKOUT2 CLKOUT2B => open, -- 1-bit output: Inverted CLKOUT2 CLKOUT3 => open, -- 1-bit output: CLKOUT3 CLKOUT3B => open, -- 1-bit output: Inverted CLKOUT3 CLKOUT4 => open, -- 1-bit output: CLKOUT4 CLKOUT5 => open, -- 1-bit output: CLKOUT5 CLKOUT6 => open, -- 1-bit output: CLKOUT6 -- Feedback Clocks: 1-bit (each) output: Clock feedback ports CLKFBOUT => clkfb_1, -- 1-bit output: Feedback clock CLKFBOUTB => open, -- 1-bit output: Inverted CLKFBOUT -- Status Ports: 1-bit (each) output: MMCM status ports LOCKED => open, -- 1-bit output: LOCK -- Clock Inputs: 1-bit (each) input: Clock input CLKIN1 => system_clk, -- 1-bit input: Clock -- Control Ports: 1-bit (each) input: MMCM control ports PWRDWN => '0', -- 1-bit input: Power-down RST => '0', -- 1-bit input: Reset -- Feedback Clocks: 1-bit (each) input: Clock feedback ports CLKFBIN => clkfb_1 -- 1-bit input: Feedback clock ); i_BUFG: BUFG PORT MAP ( I => clk_200_raw, O => clk_200 ); ------------------------------ -- Input Delay reference -- -- These are tied to the delay instances -- by the IODELAY_GROUP attribute. -------------------------------------------- IDELAYCTRL_inst : IDELAYCTRL port map ( RDY => open, -- 1-bit output: Ready output REFCLK => clk_200, -- 1-bit input: Reference clock input RST => '0' -- 1-bit input: Active high reset input ); -------------------------------- -- MMCM driven by the HDMI clock -------------------------------- hdmi_MMCME2_BASE_inst : MMCME2_BASE generic map ( BANDWIDTH => "OPTIMIZED", -- Jitter programming (OPTIMIZED, HIGH, LOW) DIVCLK_DIVIDE => 1, -- Master division value (1-106) CLKFBOUT_MULT_F => 5.0, -- Multiply value for all CLKOUT (2.000-64.000). CLKFBOUT_PHASE => 0.0, -- Phase offset in degrees of CLKFB (-360.000-360.000). CLKIN1_PERIOD => 12.5, --1000.0/148.5, -- Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). -- CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128) CLKOUT0_DIVIDE_F => 5.0, -- Divide amount for CLKOUT0 (1.000-128.000). CLKOUT1_DIVIDE => 5, CLKOUT2_DIVIDE => 1, CLKOUT3_DIVIDE => 1, CLKOUT4_DIVIDE => 1, CLKOUT5_DIVIDE => 1, CLKOUT6_DIVIDE => 1, -- CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99). CLKOUT0_DUTY_CYCLE => 0.5, CLKOUT1_DUTY_CYCLE => 0.5, CLKOUT2_DUTY_CYCLE => 0.5, CLKOUT3_DUTY_CYCLE => 0.5, CLKOUT4_DUTY_CYCLE => 0.5, CLKOUT5_DUTY_CYCLE => 0.5, CLKOUT6_DUTY_CYCLE => 0.5, -- CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000). CLKOUT0_PHASE => 0.0, CLKOUT1_PHASE => 0.0, CLKOUT2_PHASE => 0.0, CLKOUT3_PHASE => 0.0, CLKOUT4_PHASE => 0.0, CLKOUT5_PHASE => 0.0, CLKOUT6_PHASE => 0.0, CLKOUT4_CASCADE => FALSE, -- Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) REF_JITTER1 => 0.0, -- Reference input jitter in UI (0.000-0.999). STARTUP_WAIT => FALSE -- Delays DONE until MMCM is locked (FALSE, TRUE) ) port map ( -- Clock Outputs: 1-bit (each) output: User configurable clock outputs CLKOUT0 => clk_pixel_raw, -- 1-bit output: CLKOUT0 CLKOUT0B => open, -- 1-bit output: Inverted CLKOUT0 CLKOUT1 => clk_pixel_x1_raw, -- 1-bit output: CLKOUT1 CLKOUT1B => open, -- 1-bit output: Inverted CLKOUT1 CLKOUT2 => clk_pixel_x5_raw, -- 1-bit output: CLKOUT2 CLKOUT2B => open, -- 1-bit output: Inverted CLKOUT2 CLKOUT3 => open, -- 1-bit output: CLKOUT3 CLKOUT3B => open, -- 1-bit output: Inverted CLKOUT3 CLKOUT4 => open, -- 1-bit output: CLKOUT4 CLKOUT5 => open, -- 1-bit output: CLKOUT5 CLKOUT6 => open, -- 1-bit output: CLKOUT6 -- Feedback Clocks: 1-bit (each) output: Clock feedback ports CLKFBOUT => clkfb_2, -- 1-bit output: Feedback clock CLKFBOUTB => open, -- 1-bit output: Inverted CLKFBOUT -- Status Ports: 1-bit (each) output: MMCM status ports LOCKED => locked, -- 1-bit output: LOCK -- Clock Inputs: 1-bit (each) input: Clock input CLKIN1 => hdmi_in_clk, -- 1-bit input: Clock -- Control Ports: 1-bit (each) input: MMCM control ports PWRDWN => '0', -- 1-bit input: Power-down RST => '0', -- 1-bit input: Reset -- Feedback Clocks: 1-bit (each) input: Clock feedback ports CLKFBIN => clkfb_2 -- 1-bit input: Feedback clock ); ---------------------------------- -- Force the highest speed clock -- through the IO clock buffer -- (this is only rated for 600MHz!) ----------------------------------- BUFIO_x5_inst : BUFIO port map ( I => clk_pixel_x5_raw, -- 1-bit input: Clock input (connect to an IBUF or BUFMR). O => clk_pixel_x5 -- 1-bit output: Clock output (connect to I/O clock loads). ); BUFIO_x1_inst : BUFG port map ( I => clk_pixel_x1_raw, -- 1-bit input: Clock input (connect to an IBUF or BUFMR). O => clk_pixel_x1 -- 1-bit output: Clock output (connect to I/O clock loads). ); BUFIO_inst : BUFG port map ( I => clk_pixel_raw, -- 1-bit input: Clock input (connect to an IBUF or BUFMR). O => clk_pixel -- 1-bit output: Clock output (connect to I/O clock loads). ); pixel_clk <= clk_pixel; pixel_io_clk_x1 <= clk_pixel_x1; pixel_io_clk_x5 <= clk_pixel_x5; ch0: input_channel Port map ( clk_mgmt => system_clk, clk => clk_pixel, ce => ser_ce, clk_x1 => clk_pixel_x1, clk_x5 => clk_pixel_x5, serial => hdmi_in_ch0, invalid_symbol => ch0_invalid_symbol, symbol => ch0_symbol, ctl_valid => ch0_ctl_valid, ctl => ch0_ctl, terc4_valid => ch0_terc4_valid, terc4 => ch0_terc4, guardband_valid => ch0_guardband_valid, guardband => ch0_guardband, data_valid => ch0_data_valid, data => ch0_data, reset => ser_reset, symbol_sync => ch0_symbol_sync); ch1: input_channel Port map ( clk_mgmt => system_clk, clk => clk_pixel, ce => ser_ce, clk_x1 => clk_pixel_x1, clk_x5 => clk_pixel_x5, serial => hdmi_in_ch1, symbol => ch1_symbol, invalid_symbol => ch1_invalid_symbol, ctl_valid => ch1_ctl_valid, ctl => ch1_ctl, terc4_valid => ch1_terc4_valid, terc4 => ch1_terc4, guardband_valid => ch1_guardband_valid, guardband => ch1_guardband, data_valid => ch1_data_valid, data => ch1_data, reset => ser_reset, symbol_sync => ch1_symbol_sync); ch2: input_channel Port map ( clk_mgmt => system_clk, clk => clk_pixel, ce => ser_ce, clk_x1 => clk_pixel_x1, clk_x5 => clk_pixel_x5, serial => hdmi_in_ch2, invalid_symbol => ch2_invalid_symbol, symbol => ch2_symbol, ctl_valid => ch2_ctl_valid, ctl => ch2_ctl, terc4_valid => ch2_terc4_valid, terc4 => ch2_terc4, guardband_valid => ch2_guardband_valid, guardband => ch2_guardband, data_valid => ch2_data_valid, data => ch2_data, reset => ser_reset, symbol_sync => ch2_symbol_sync); symbol_sync_i <= ch0_symbol_sync and ch1_symbol_sync and ch2_symbol_sync; hdmi_detected <= not dvid_mode; hdmi_section_decode: process(clk_pixel) begin if rising_edge(clk_pixel) then ------------------------------------------------------------------- -- Output the values depending on what sort of data block we are in ------------------------------------------------------------------- if ch0_ctl_valid = '1' and ch1_ctl_valid = '1' and ch2_ctl_valid = '1' then ------------------------------------------------------------------- -- As soon as we see avalid CTL symbols we are no longer in the -- video or aux data period it doesn't have any trailing guard band ------------------------------------------------------------------- in_vdp <= '0'; in_adp <= '0'; in_dvid <= '0'; raw_vsync <= ch0_ctl(1); raw_hsync <= ch0_ctl(0); raw_blank <= '1'; raw_ch2 <= (others => '0'); raw_ch1 <= (others => '0'); raw_ch0 <= (others => '0'); last_was_ctl <= '1'; adp_data_valid <= '0'; else last_was_ctl <= '0'; adp_data_valid <= '0'; if in_vdp = '1' then raw_vsync <= '0'; raw_hsync <= '0'; raw_blank <= '0'; raw_ch2 <= ch2_data; raw_ch1 <= ch1_data; raw_ch0 <= ch0_data; if ch2_invalid_symbol = '1' or ch2_invalid_symbol = '1' or ch2_invalid_symbol = '1' then raw_ch2 <= x"EF"; raw_ch1 <= x"16"; raw_ch0 <= x"16"; end if; elsif in_dvid = '1' then -- In the Video data period raw_vsync <= '0'; raw_hsync <= '0'; raw_blank <= '0'; raw_ch2 <= ch2_data; raw_ch1 <= ch1_data; raw_ch0 <= ch0_data; elsif in_adp = '1' then -- In the Aux Data Period Period raw_vsync <= ch0_terc4(1); raw_hsync <= ch0_terc4(0); raw_blank <= '1'; raw_ch0 <= (others => '0'); raw_ch1 <= (others => '0'); raw_ch2 <= (others => '0'); -- ADP data extraction adp_data_valid <= '1'; adp_header_bit <= ch0_terc4(2); adp_frame_bit <= ch0_terc4(3); adp_subpacket0_bits <= ch2_terc4(0) & ch1_terc4(0); adp_subpacket1_bits <= ch2_terc4(1) & ch1_terc4(1); adp_subpacket2_bits <= ch2_terc4(2) & ch1_terc4(2); adp_subpacket3_bits <= ch2_terc4(3) & ch1_terc4(3); end if; end if; ------------------------------------------------------------ -- We need to detect 8 ADP or VDP prefix characters in a row ------------------------------------------------------------ vdp_prefix_detect <= vdp_prefix_detect(6 downto 0) & '0'; vdp_prefix_seen <= '0'; if ch0_ctl_valid = '1' and ch1_ctl_valid = '1' and ch1_ctl_valid = '1' then if ch1_ctl = "01" and ch2_ctl = "00" then vdp_prefix_detect(0) <= '1'; if vdp_prefix_detect = "01111111" then vdp_prefix_seen <= '1'; end if; end if; end if; --------------------------------------------- -- See if we can detect the ADP guardband -- -- The ADP guardband includes HSYNC and VSYNC -- encoded in TERC4 coded in Ch0. --------------------------------------------- adp_prefix_detect <= adp_prefix_detect(6 downto 0) & '0'; adp_prefix_seen <= '0'; if ch0_ctl_valid = '1' and ch1_ctl_valid = '1' and ch1_ctl_valid = '1' then if ch1_ctl = "01" and ch2_ctl = "01" then adp_prefix_detect(0) <= '1'; if adp_prefix_detect = "01111111" then adp_prefix_seen <= '1'; end if; end if; end if; --------------------------------------------- -- See if we can detect the ADP guardband -- -- The ADP guardband includes HSYNC and VSYNC -- encoded in TERC4 coded in Ch0 - annoying! --------------------------------------------- adp_guardband_detect <= '0'; if in_vdp = '0' and ch0_terc4_valid = '1' and ch1_guardband_valid = '1' and ch1_guardband_valid = '1' then if ch0_terc4(3 downto 2) = "11" and ch1_guardband = "0" and ch2_guardband = "0" then raw_vsync <= ch0_terc4(1); raw_hsync <= ch0_terc4(0); adp_guardband_detect <= adp_prefix_seen; in_adp <= adp_guardband_detect AND (not in_adp) and (not in_vdp); end if; end if; ----------------------------------------- -- See if we can detect the VDP guardband -- This is pretty nices as the guard ----------------------------------------- vdp_guardband_detect <= '0'; if ch0_guardband_valid = '1' and ch1_guardband_valid = '1' and ch2_guardband_valid = '1' then -- TERC Coded for the VDP guard band. if ch0_guardband = "1" and ch1_guardband = "0" and ch2_guardband = "1" then vdp_guardband_detect <= vdp_prefix_seen; in_vdp <= vdp_guardband_detect AND (not in_adp) and (not in_vdp); dvid_mode <= '0'; end if; end if; -------------------------------- -- Is this some DVID video data? -------------------------------- if dvid_mode = '1' and last_was_ctl = '1' and ch0_data_valid = '1' and ch1_data_valid = '1' and ch2_data_valid = '1' then in_dvid <= '1'; end if; ------------------------------------------------------------- -- Is this an un-announced video data? If so we receiving -- DVI-D data, and not HDMI ------------------------------------------------------------- if ch0_data_valid = '1' and ch1_data_valid = '1' and ch2_data_valid = '1' and last_was_ctl = '1' and vdp_prefix_seen = '0' and adp_prefix_seen = '0' then dvid_mode <= '1'; end if; ch0_invalid_symbol_1 <= ch0_invalid_symbol; ch0_ctl_valid_1 <= ch0_ctl_valid; ch0_ctl_1 <= ch0_ctl; ch0_terc4_valid_1 <= ch0_terc4_valid; ch0_terc4_1 <= ch0_terc4; ch0_data_1 <= ch0_data; ch1_invalid_symbol_1 <= ch1_invalid_symbol; ch1_ctl_valid_1 <= ch1_ctl_valid; ch1_ctl_1 <= ch1_ctl; ch1_terc4_valid_1 <= ch1_terc4_valid; ch1_terc4_1 <= ch1_terc4; ch1_data_1 <= ch1_data; ch2_invalid_symbol_1 <= ch2_invalid_symbol; ch2_ctl_valid_1 <= ch2_ctl_valid; ch2_ctl_1 <= ch2_ctl; ch2_terc4_valid_1 <= ch2_terc4_valid; ch2_terc4_1 <= ch2_terc4; ch2_data_valid_1 <= ch2_data_valid; ch2_data_1 <= ch2_data; end if; end process; ------------------------------------------ -- Reset the receivers if PLL lock is lost ------------------------------------------ reset_proc: process(system_clk) begin if rising_edge(system_clk) then if locked = '1' then if reset_counter > 0 then reset_counter <= reset_counter-1; end if; else reset_counter <= (others => '1'); end if; end if; end process; reset_proc2: process(clk_pixel) begin if rising_edge(clk_pixel) then ser_reset <= reset_counter(reset_counter'high); ser_ce <= not ser_reset; end if; end process; end Behavioral; ================================================ FILE: src/hdmi_io.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field '0'); begin pixel_clk <= pixel_clk_i; hdmi_rx_hpa <= '1'; hdmi_rx_txen <= '1'; hdmi_rx_cec <= 'Z'; debug(7) <= raw_hsync; debug(6) <= raw_vsync; debug(5) <= is_second_field_i; debug(4) <= is_interlaced_i; debug(3 downto 0) <= (others => '0'); i_edid_rom: edid_rom port map ( clk => clk100, sclk_raw => hdmi_rx_scl, sdat_raw => hdmi_rx_sda, edid_debug => open); --------------------- -- Input buffers --------------------- in_clk_buf: IBUFDS generic map ( IOSTANDARD => "TMDS_33") port map ( I => hdmi_rx_clk_p, IB => hdmi_rx_clk_n, O => tmds_in_clk); in_rx0_buf: IBUFDS generic map ( IOSTANDARD => "TMDS_33") port map ( I => hdmi_rx_p(0), IB => hdmi_rx_n(0), O => tmds_in_ch0); in_rx1_buf: IBUFDS generic map ( IOSTANDARD => "TMDS_33") port map ( I => hdmi_rx_p(1), IB => hdmi_rx_n(1), O => tmds_in_ch1); in_rx2_buf: IBUFDS generic map ( IOSTANDARD => "TMDS_33") port map ( I => hdmi_rx_p(2), IB => hdmi_rx_n(2), O => tmds_in_ch2); i_hdmi_input : hdmi_input port map ( system_clk => clk100, debug => open, -- Pixel and serializer clocks pixel_clk => pixel_clk_i, pixel_io_clk_x1 => pixel_io_clk_x1, pixel_io_clk_x5 => pixel_io_clk_x5, --- HDMI input signals hdmi_in_clk => tmds_in_clk, hdmi_in_ch0 => tmds_in_ch0, hdmi_in_ch1 => tmds_in_ch1, hdmi_in_ch2 => tmds_in_ch2, -- are the HDMI symbols in sync? symbol_sync => data_synced, pll_locked => clock_locked, -- VGA internal Signals hdmi_detected => in_hdmi_detected, raw_blank => raw_blank, raw_hsync => raw_hsync, raw_vsync => raw_vsync, raw_ch2 => raw_ch2, raw_ch1 => raw_ch1, raw_ch0 => raw_ch0, -- ADP data adp_data_valid => adp_data_valid, adp_header_bit => adp_header_bit, adp_frame_bit => adp_frame_bit, adp_subpacket0_bits => adp_subpacket0_bits, adp_subpacket1_bits => adp_subpacket1_bits, adp_subpacket2_bits => adp_subpacket2_bits, adp_subpacket3_bits => adp_subpacket3_bits, -- For later reuse symbol_ch0 => symbol_ch0, symbol_ch1 => symbol_ch1, symbol_ch2 => symbol_ch2 ); ------------------------------------- -- If the input data is in 422 format -- then convert it to 12-bit 444 data ------------------------------------- i_expand_422_to_444: expand_422_to_444 Port map ( clk => pixel_clk_i, input_is_422 => input_is_422, ------------------ -- Incoming raw data ------------------ in_blank => raw_blank, in_hsync => raw_hsync, in_vsync => raw_vsync, in_ch2 => raw_ch2, in_ch1 => raw_ch1, in_ch0 => raw_ch0, ------------------- -- Processed pixels ------------------- out_blank => fourfourfour_blank, out_hsync => fourfourfour_hsync, out_vsync => fourfourfour_vsync, out_U => fourfourfour_U, out_V => fourfourfour_V, out_W => fourfourfour_W ); is_interlaced <= is_interlaced_i; is_second_field <= is_second_field_i; i_detect_interlace: detect_interlace Port map ( clk => pixel_clk_i, hsync => raw_hsync, vsync => raw_vsync, is_interlaced => is_interlaced_i, is_second_field => is_second_field_i); i_conversion_to_RGB: conversion_to_RGB port map ( clk => pixel_clk_i, ------------------------ input_is_YCbCr => input_is_YCbCr, input_is_sRGB => input_is_sRGB, in_blank => fourfourfour_blank, in_hsync => fourfourfour_hsync, in_vsync => fourfourfour_vsync, in_U => fourfourfour_U, in_V => fourfourfour_V, in_W => fourfourfour_W, ------------------------ out_blank => rgb_blank, out_hsync => rgb_hsync, out_vsync => rgb_vsync, out_R => rgb_R, out_G => rgb_G, out_B => rgb_B ); ----------------------------------------- -- Colour space conversion yet to be done ----------------------------------------- in_blank <= rgb_blank; in_hsync <= rgb_hsync; in_vsync <= rgb_vsync; in_blue <= rgb_B(11 downto 4); in_green <= rgb_G(11 downto 4); in_red <= rgb_R(11 downto 4); ------------------------------------------------ -- Processing the non-video data #1 -- Extracting the Video Infopacket data we need -- to correctly convert the video data ------------------------------------------------ i_extract_video_infopacket_data: extract_video_infopacket_data port map ( clk => pixel_clk_i, -- ADP data adp_data_valid => adp_data_valid, adp_header_bit => adp_header_bit, adp_frame_bit => adp_frame_bit, adp_subpacket0_bits => adp_subpacket0_bits, adp_subpacket1_bits => adp_subpacket1_bits, adp_subpacket2_bits => adp_subpacket2_bits, adp_subpacket3_bits => adp_subpacket3_bits, -- The stuff we need input_is_YCbCr => input_is_YCbCr, input_is_422 => input_is_422, input_is_sRGB => input_is_sRGB ); ------------------------------------------------ -- Processing the non-video data #2 -- Extracting the Audio samples so we can display -- level menters on the screen ------------------------------------------------ i_extract_audio_samples: extract_audio_samples PORT MAP ( clk => pixel_clk_i, -- ADP data adp_data_valid => adp_data_valid, adp_header_bit => adp_header_bit, adp_frame_bit => adp_frame_bit, adp_subpacket0_bits => adp_subpacket0_bits, adp_subpacket1_bits => adp_subpacket1_bits, adp_subpacket2_bits => adp_subpacket2_bits, adp_subpacket3_bits => adp_subpacket3_bits, -- The stuff we need audio_de => audio_de, audio_channel => audio_channel, audio_sample => audio_sample); ------------------------------------------------ -- Outputting video data ----------------------------------------------- i_DVID_output: DVID_output port map ( pixel_clk => pixel_clk_i, pixel_io_clk_x1 => pixel_io_clk_x1, pixel_io_clk_x5 => pixel_io_clk_x5, data_valid => '1', -- VGA Signals vga_blank => out_blank, vga_hsync => out_hsync, vga_vsync => out_vsync, vga_red => out_red, vga_blue => out_blue, vga_green => out_green, --- HDMI out tmds_out_clk => tmds_out_clk, tmds_out_ch0 => tmds_out_ch0, tmds_out_ch1 => tmds_out_ch1, tmds_out_ch2 => tmds_out_ch2 ); ----------------------------- -- Other HDMI control signals ----------------------------- hdmi_tx_rsda <= 'Z'; hdmi_tx_cec <= 'Z'; hdmi_tx_rscl <= '1'; ----------------- -- Output buffers ----------------- out_clk_buf: OBUFDS generic map ( IOSTANDARD => "TMDS_33", SLEW => "FAST") port map ( O => hdmi_tx_clk_p, OB => hdmi_tx_clk_n, I => tmds_out_clk); out_tx0_buf: OBUFDS generic map ( IOSTANDARD => "TMDS_33", SLEW => "FAST") port map ( O => hdmi_tx_p(0), OB => hdmi_tx_n(0), I => tmds_out_ch0); out_tx1_buf: OBUFDS generic map ( IOSTANDARD => "TMDS_33", SLEW => "FAST") port map ( O => hdmi_tx_p(1), OB => hdmi_tx_n(1), I => tmds_out_ch1); out_tx2_buf: OBUFDS generic map ( IOSTANDARD => "TMDS_33", SLEW => "FAST") port map ( O => hdmi_tx_p(2), OB => hdmi_tx_n(2), I => tmds_out_ch2); -- Detect when VSYNC is held high for 8 cycles, so we can synchronise the capture of symbols process(pixel_clk_i) begin if rising_edge(pixel_clk_i) then if detect_sr = "11111111" and raw_vsync = '0' then symbol_sync <= '1'; else symbol_sync <= '0'; end if; detect_sr <= detect_sr(6 downto 0) & raw_vsync; end if; end process; end Behavioral; ================================================ FILE: src/input_channel.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Create Date: 30.07.2015 23:11:34 -- Module Name: input_channel - Behavioral -- -- Description: Receiving one of the three HDMI input channels. and decoding -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity input_channel is Port ( clk_mgmt : in STD_LOGIC; clk : in STD_LOGIC; clk_x1 : in STD_LOGIC; clk_x5 : in STD_LOGIC; serial : in STD_LOGIC; reset : in std_logic; ce : in STD_LOGIC; invalid_symbol : out std_logic; symbol : out std_logic_vector (9 downto 0); ctl_valid : out std_logic; ctl : out std_logic_vector (1 downto 0); terc4_valid : out std_logic; terc4 : out std_logic_vector (3 downto 0); guardband_valid : out std_logic; guardband : out std_logic_vector (0 downto 0); data_valid : out std_logic; data : out std_logic_vector (7 downto 0); symbol_sync : out STD_LOGIC); end input_channel; architecture Behavioral of input_channel is component deserialiser_1_to_10 is Port ( clk_mgmt : in std_logic; delay_ce : in std_logic; delay_count : in std_logic_vector (4 downto 0); ce : in STD_LOGIC; clk : in std_logic; clk_x1 : in std_logic; bitslip : in std_logic; clk_x5 : in std_logic; reset : in std_logic; serial : in std_logic; data : out std_logic_vector (9 downto 0)); end component; component TMDS_decoder is Port ( clk : in std_logic; symbol : in std_logic_vector (9 downto 0); invalid_symbol : out std_logic; ctl_valid : out std_logic; ctl : out std_logic_vector (1 downto 0); terc4_valid : out std_logic; terc4 : out std_logic_vector (3 downto 0); guardband_valid : out std_logic; guardband : out std_logic_vector (0 downto 0); data_valid : out std_logic; data : out std_logic_vector (7 downto 0)); end component; component alignment_detect is Port ( clk : in STD_LOGIC; invalid_symbol : in STD_LOGIC; delay_count : out STD_LOGIC_VECTOR(4 downto 0); delay_ce : out STD_LOGIC; bitslip : out STD_LOGIC; symbol_sync : out STD_LOGIC); end component; signal delay_count : std_logic_vector (4 downto 0); signal delay_ce : STD_LOGIC; signal bitslip : STD_LOGIC; signal symbol_sync_i : STD_LOGIC; signal symbol_i : std_logic_vector (9 downto 0); signal invalid_symbol_i: STD_LOGIC; begin symbol <= symbol_i; i_deser: deserialiser_1_to_10 port map ( clk_mgmt => clk_mgmt, delay_ce => delay_ce, delay_count => delay_count, ce => ce, clk => clk, clk_x1 => clk_x1, bitslip => bitslip, clk_x5 => clk_x5, reset => reset, serial => serial, data => symbol_i); i_decoder: tmds_decoder port map ( clk => clk, symbol => symbol_i, invalid_symbol => invalid_symbol_i, ctl_valid => ctl_valid, ctl => ctl, terc4_valid => terc4_valid, terc4 => terc4, guardband_valid => guardband_valid, guardband => guardband, data_valid => data_valid, data => data ); invalid_symbol <= invalid_symbol_i; i_alignment_detect: alignment_detect port map ( clk => clk, invalid_symbol => invalid_symbol_i, delay_count => delay_count, delay_ce => delay_ce, bitslip => bitslip, symbol_sync => symbol_sync); end Behavioral; ================================================ FILE: src/line_delay.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: line_delay - Behavioral -- -- Description: Delay the video signal by one line, as measured by the rising -- edge on hsync. This module works for line lengths of between -- around 510 and around 2500 (needed for 640x480 through -- 1920x1080. -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity line_delay is Port ( clk : in STD_LOGIC; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0)); end line_delay; architecture Behavioral of line_delay is type mem_block is array (0 to 511) of std_logic_vector(26 downto 0); signal mem_0 : mem_block := (others => (others => '0')); signal mem_1 : mem_block := (others => (others => '0')); signal mem_2 : mem_block := (others => (others => '0')); signal mem_3 : mem_block := (others => (others => '0')); signal mem_4 : mem_block := (others => (others => '0')); signal wr_addr : unsigned(8 downto 0) := (others =>'1'); signal offset_0 : unsigned(8 downto 0) := (others =>'1'); signal offset_1 : unsigned(8 downto 0) := (others =>'1'); signal offset_2 : unsigned(8 downto 0) := (others =>'1'); signal offset_3 : unsigned(8 downto 0) := (others =>'1'); signal offset_4 : unsigned(8 downto 0) := (others =>'1'); signal width : unsigned(11 downto 0) := (others =>'0'); signal line_count : unsigned(11 downto 0) := (others =>'0'); signal last_hsync : std_logic := '0'; signal mid_0 : std_logic_vector(26 downto 0) := (others =>'0'); signal mid_1 : std_logic_vector(26 downto 0) := (others =>'0'); signal mid_2 : std_logic_vector(26 downto 0) := (others =>'0'); signal mid_3 : std_logic_vector(26 downto 0) := (others =>'0'); begin process(clk) variable mem_4_out : std_logic_vector(26 downto 0); variable temp : unsigned(11 downto 0) := (others =>'1'); begin if rising_edge(clk) then ------------------------------------------------ -- Retreive the value from the end of the delay -- and break out the signals ------------------------------------------------ mem_4_out := mem_4(to_integer(wr_addr+offset_4)); out_red <= mem_4_out(26 downto 19); out_green <= mem_4_out(18 downto 11); out_blue <= mem_4_out(10 downto 3); out_blank <= mem_4_out(2); out_hsync <= mem_4_out(1); out_vsync <= mem_4_out(0); ------------------------------------------------- -- Move everything through the five memory blocks ------------------------------------------------- mem_4(to_integer(wr_addr)) <= mid_3; mid_3 <= mem_3(to_integer(wr_addr+offset_3)); mem_3(to_integer(wr_addr)) <= mid_2; mid_2 <= mem_2(to_integer(wr_addr+offset_2)); mem_2(to_integer(wr_addr)) <= mid_1; mid_1 <= mem_1(to_integer(wr_addr+offset_1)); mem_1(to_integer(wr_addr)) <= mid_0; mid_0 <= mem_0(to_integer(wr_addr+offset_0)); mem_0(to_integer(wr_addr)) <= in_red & in_green & in_blue & in_blank & in_hsync & in_vsync; wr_addr <= wr_addr - 1; if in_hsync = '1' and last_hsync ='0' then width <= line_count; line_count <= (others => '0'); else line_count <=line_count + 1; end if; ------------------------------------------------------------- -- Update the offsets every cycle, not that we really need to -- This improves the timing as we have less logic ------------------------------------------------------------- offset_0 <= to_unsigned(508,9); temp := width-512+0; offset_1 <= temp(10 downto 2); temp := width-512+1; offset_2 <= temp(10 downto 2); temp := width-512+2; offset_3 <= temp(10 downto 2); temp := width-512+3; offset_4 <= temp(10 downto 2); last_hsync <= in_hsync; end if; end process; end Behavioral; ================================================ FILE: src/pixel_processing.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: pixel_processing - Behavioral -- -- Description: Where you can do processing on the raw pixel data -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity pixel_processing is Port ( clk : in STD_LOGIC; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0); ------------------------------------ -- Audio only comes in.. ------------------------------------ audio_channel : in std_logic_vector(2 downto 0); audio_de : in std_logic; audio_sample : in std_logic_vector(23 downto 0); ---------------------------------- -- Controls ---------------------------------- switches : in std_logic_vector(7 downto 0) ); end pixel_processing; architecture Behavioral of pixel_processing is component audio_to_db is Port ( clk : in STD_LOGIC; in_channel : in STD_LOGIC_VECTOR (2 downto 0); in_de : in STD_LOGIC; in_sample : in STD_LOGIC_VECTOR (23 downto 0); out_channel : out STD_LOGIC_VECTOR (2 downto 0); out_de : out STD_LOGIC; out_level : out STD_LOGIC_VECTOR (5 downto 0)); end component; signal level_channel : std_logic_vector(2 downto 0); signal level_de : std_logic; signal level : std_logic_vector(5 downto 0); component audio_meters is Port ( clk : in STD_LOGIC; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0); ------------------------------------- -- Audio Levels ------------------------------------- signal audio_channel : in std_logic_vector(2 downto 0); signal audio_de : in std_logic; signal audio_level : in std_logic_vector(5 downto 0) ); end component; component edge_enhance is Port ( clk : in STD_LOGIC; enable_feature : in std_logic; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0) ); end component; component guidelines is Port ( clk : in STD_LOGIC; enable_feature : in std_logic; ------------------------------- -- VGA data recovered from HDMI ------------------------------- in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_red : in std_logic_vector(7 downto 0); in_green : in std_logic_vector(7 downto 0); in_blue : in std_logic_vector(7 downto 0); is_interlaced : in std_logic; is_second_field : in std_logic; ----------------------------------- -- VGA data to be converted to HDMI ----------------------------------- out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_red : out std_logic_vector(7 downto 0); out_green : out std_logic_vector(7 downto 0); out_blue : out std_logic_vector(7 downto 0) ); end component; signal b_blank : std_logic; signal b_hsync : std_logic; signal b_vsync : std_logic; signal b_red : std_logic_vector(7 downto 0); signal b_green : std_logic_vector(7 downto 0); signal b_blue : std_logic_vector(7 downto 0); signal c_blank : std_logic; signal c_hsync : std_logic; signal c_vsync : std_logic; signal c_red : std_logic_vector(7 downto 0); signal c_green : std_logic_vector(7 downto 0); signal c_blue : std_logic_vector(7 downto 0); begin i_audio_to_db: audio_to_db port map ( clk => clk, in_channel => audio_channel, in_de => audio_de, in_sample => audio_sample, out_channel => level_channel, out_de => level_de, out_level => level ); i_edge_enhance: edge_enhance Port map ( clk => clk, enable_feature => switches(0), in_blank => in_blank, in_hsync => in_hsync, in_vsync => in_vsync, in_red => in_red, in_green => in_green, in_blue => in_blue, out_blank => b_blank, out_hsync => b_hsync, out_vsync => b_vsync, out_red => b_red, out_green => b_green, out_blue => b_blue ); i_audio_meters: audio_meters Port map ( clk => clk, in_blank => b_blank, in_hsync => b_hsync, in_vsync => b_vsync, in_red => b_red, in_green => b_green, in_blue => b_blue, is_interlaced => is_interlaced, is_second_field => is_second_field, out_blank => c_blank, out_hsync => c_hsync, out_vsync => c_vsync, out_red => c_red, out_green => c_green, out_blue => c_blue, audio_channel => level_channel, audio_de => level_de, audio_level => level ); i_guidelines: guidelines Port map ( clk => clk, enable_feature => switches(1), in_blank => c_blank, in_hsync => c_hsync, in_vsync => c_vsync, in_red => c_red, in_green => c_green, in_blue => c_blue, is_interlaced => is_interlaced, is_second_field => is_second_field, out_blank => out_blank, out_hsync => out_hsync, out_vsync => out_vsync, out_red => out_red, out_green => out_green, out_blue => out_blue ); end Behavioral; ================================================ FILE: src/serialiser_10_to_1.vhd ================================================ ---------------------------------------------------------------------------------- -- File: serialiser_10_to_1.vhd -- -- Engineer: Mike Field -- -- Module Name: serialiser_10_to_1 - Behavioral -- -- Description: Using the OSERDESE2 as a 10:1 serialiser, using a x1 and x5 -- clocks (using DDR outputs). -- -- The tricky bit is that reset needs to be asserted, and then CE asserted -- after the reset or it will not simulate correctly (outputs show as 'X') -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; library UNISIM; use UNISIM.VComponents.all; entity serialiser_10_to_1 is Port ( clk : in STD_LOGIC; clk_x5 : in STD_LOGIC; data : in STD_LOGIC_VECTOR (9 downto 0); reset : in std_logic; serial : out STD_LOGIC); end serialiser_10_to_1; architecture Behavioral of serialiser_10_to_1 is signal shift1 : std_logic := '0'; signal shift2 : std_logic := '0'; signal ce_delay : std_logic_vector(7 downto 0) := (others => '0'); signal reset_delay : std_logic_vector(7 downto 0) := (others => '0'); begin master_serdes : OSERDESE2 generic map ( DATA_RATE_OQ => "DDR", -- DDR, SDR DATA_RATE_TQ => "DDR", -- DDR, BUF, SDR DATA_WIDTH => 10, -- Parallel data width (2-8,10,14) INIT_OQ => '1', -- Initial value of OQ output (1'b0,1'b1) INIT_TQ => '1', -- Initial value of TQ output (1'b0,1'b1) SERDES_MODE => "MASTER", -- MASTER, SLAVE SRVAL_OQ => '0', -- OQ output value when SR is used (1'b0,1'b1) SRVAL_TQ => '0', -- TQ output value when SR is used (1'b0,1'b1) TBYTE_CTL => "FALSE", -- Enable tristate byte operation (FALSE, TRUE) TBYTE_SRC => "FALSE", -- Tristate byte source (FALSE, TRUE) TRISTATE_WIDTH => 1 -- 3-state converter width (1,4) ) port map ( OFB => open, -- 1-bit output: Feedback path for data OQ => serial, -- 1-bit output: Data path output -- SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) SHIFTOUT1 => open, SHIFTOUT2 => open, TBYTEOUT => open, -- 1-bit output: Byte group tristate TFB => open, -- 1-bit output: 3-state control TQ => open, -- 1-bit output: 3-state control CLK => clk_x5, -- 1-bit input: High speed clock CLKDIV => clk, -- 1-bit input: Divided clock -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) D1 => data(0), D2 => data(1), D3 => data(2), D4 => data(3), D5 => data(4), D6 => data(5), D7 => data(6), D8 => data(7), OCE => '1', --ce_delay(0), -- 1-bit input: Output data clock enable RST => reset, -- 1-bit input: Reset -- SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) SHIFTIN1 => SHIFT1, SHIFTIN2 => SHIFT2, -- T1 - T4: 1-bit (each) input: Parallel 3-state inputs T1 => '0', T2 => '0', T3 => '0', T4 => '0', TBYTEIN => '0', -- 1-bit input: Byte group tristate TCE => '0' -- 1-bit input: 3-state clock enable ); slave_serdes : OSERDESE2 generic map ( DATA_RATE_OQ => "DDR", -- DDR, SDR DATA_RATE_TQ => "DDR", -- DDR, BUF, SDR DATA_WIDTH => 10, -- Parallel data width (2-8,10,14) INIT_OQ => '1', -- Initial value of OQ output (1'b0,1'b1) INIT_TQ => '1', -- Initial value of TQ output (1'b0,1'b1) SERDES_MODE => "SLAVE", -- MASTER, SLAVE SRVAL_OQ => '0', -- OQ output value when SR is used (1'b0,1'b1) SRVAL_TQ => '0', -- TQ output value when SR is used (1'b0,1'b1) TBYTE_CTL => "FALSE", -- Enable tristate byte operation (FALSE, TRUE) TBYTE_SRC => "FALSE", -- Tristate byte source (FALSE, TRUE) TRISTATE_WIDTH => 1 -- 3-state converter width (1,4) ) port map ( OFB => open, -- 1-bit output: Feedback path for data OQ => open, -- 1-bit output: Data path output -- SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) SHIFTOUT1 => shift1, SHIFTOUT2 => shift2, TBYTEOUT => open, -- 1-bit output: Byte group tristate TFB => open, -- 1-bit output: 3-state control TQ => open, -- 1-bit output: 3-state control CLK => clk_x5, -- 1-bit input: High speed clock CLKDIV => clk, -- 1-bit input: Divided clock -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) D1 => '0', D2 => '0', D3 => data(8), D4 => data(9), D5 => '0', D6 => '0', D7 => '0', D8 => '0', OCE => '1', --ce_delay(0), -- 1-bit input: Output data clock enable RST => reset, -- 1-bit input: Reset -- SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) SHIFTIN1 => '0', SHIFTIN2 => '0', -- T1 - T4: 1-bit (each) input: Parallel 3-state inputs T1 => '0', T2 => '0', T3 => '0', T4 => '0', TBYTEIN => '0', -- 1-bit input: Byte group tristate TCE => '0' -- 1-bit input: 3-state clock enable ); delay_ce: process(clk_x5) begin if rising_edge(clk_x5) then ce_delay <= not reset & ce_delay(ce_delay'high downto 1); end if; end process; end Behavioral; ================================================ FILE: src/symbol_dump.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: symbol_dump - Behavioral -- -- Description: Create a trace of HDMI symbols - a 1024 word memory block is filled -- and then transmitted over rs232. Then refilled again, but this time -- waiting an extra 1024 cycles from when symbol_sync is asserted. -- -- If the video source is paused, then the entire frame can be capbured -- (excluding ADP data periods, which might get broken on the boundary. -- -- The captured data can then be analysed by hand or used to drive -- simulations. -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity symbol_dump is Port ( clk : in STD_LOGIC; clk100 : in STD_LOGIC; symbol_sync : in STD_LOGIC; symbol_ch0 : in STD_LOGIC_VECTOR (9 downto 0); symbol_ch1 : in STD_LOGIC_VECTOR (9 downto 0); symbol_ch2 : in STD_LOGIC_VECTOR (9 downto 0); rs232_tx : out STD_LOGIC); end symbol_dump; architecture Behavioral of symbol_dump is type array_hex is array(0 to 15) of std_logic_vector(9 downto 0); signal hex : array_hex := ( "1001100000", "1001100010", "1001100100", "1001100110", "1001101000", "1001101010", "1001101100", "1001101110", "1001110000", "1001110010", "1010000010", "1010000100", "1010000110", "1010001000", "1010001010", "1010001100"); type array_memory is array(0 to 1023) of std_logic_vector(29 downto 0); signal memory : array_memory := (others => (others =>'0')); signal position : unsigned(23 downto 0) := (others => '0'); signal capture_point : unsigned(23 downto 0) := (others => '0'); signal write_address : unsigned(9 downto 0) := (others => '0'); signal write_enable : std_logic := '0'; signal write_data : std_logic_vector(29 downto 0) := (others => '0'); --- For signaling into the 100MHz domain signal ready_to_send : std_logic := '0'; signal ready_to_send_meta : std_logic := '0'; signal ready_to_send_synced : std_logic := '0'; --- For signaling into the pixel clock domain signal sending_data : std_logic := '0'; signal sending_data_meta : std_logic := '0'; signal sending_data_synced : std_logic := '0'; signal rd_address : unsigned(9 downto 0) := (others => '0'); signal rd_data : std_logic_vector(29 downto 0) := (others => '0'); signal tx_data : std_logic_vector(89 downto 0) := (others => '1'); signal tx_count : unsigned(7 downto 0) := (others => '0'); signal baud_counter : unsigned(12 downto 0) := (others => '0'); signal baud_counter_max : unsigned(12 downto 0) := to_unsigned(100000000/115200,13); begin process(clk) begin if rising_edge(clk) then if write_enable = '1' then memory(to_integer(write_address)) <= symbol_ch2 & symbol_ch1 & symbol_ch0; end if; -- track where we are in the frame. if symbol_sync = '1' then position <= (others => '0'); else position <= position+1; end if; -- If we are capturing remember where we have got up to -- and see if we have captured our full amount. if write_enable = '1' then capture_point <= position; write_data <= symbol_ch2 & symbol_ch1 & symbol_ch0; write_data <= symbol_ch2 & symbol_ch1 & symbol_ch0; if write_address = 1023 then write_enable <= '0'; ready_to_send <= '1'; end if; write_address <= write_address+1; end if; -- Do we start capturing at this point? -- (write address resets itself to 0, so we don't -- have to do it here) if position = capture_point and ready_to_send = '0' and sending_data_synced = '0' then write_enable <= '1'; end if; -- Do we need to re-arm ready for the next capture if sending_data_synced = '1' then ready_to_send <= '0'; end if; -- Bring data_sent into this clock domain sending_data_synced <= sending_data_meta; sending_data_meta <= sending_data; end if; end process; process(clk100) begin if rising_edge(clk100) then if baud_counter = 0 then rs232_tx <= tx_data(0); tx_data <= '1' & tx_data(89 downto 1); baud_counter <= baud_counter_max; if(tx_count > 0) then tx_count <= tx_count-1; end if; else baud_counter <= baud_counter -1; end if; if sending_data = '1' or ready_to_send_synced = '1' then if tx_count = 0 then tx_data(89 downto 80) <= hex(to_integer(unsigned(rd_data( 3 downto 0)))); tx_data(79 downto 70) <= hex(to_integer(unsigned(rd_data( 7 downto 4)))); tx_data(69 downto 60) <= hex(to_integer(unsigned(rd_data(11 downto 8)))); tx_data(59 downto 50) <= hex(to_integer(unsigned(rd_data(15 downto 12)))); tx_data(49 downto 40) <= hex(to_integer(unsigned(rd_data(19 downto 16)))); tx_data(39 downto 30) <= hex(to_integer(unsigned(rd_data(23 downto 20)))); tx_data(29 downto 20) <= hex(to_integer(unsigned(rd_data(27 downto 24)))); tx_data(19 downto 10) <= hex(to_integer(unsigned(rd_data(29 downto 28)))); tx_data( 9 downto 0) <= "1000010100"; -- New line tx_count <= to_unsigned(90,8); rd_data <= memory(to_integer(rd_address)); rd_address <= rd_address+1; if rd_address = 1023 then sending_data <= '0'; else sending_data <= '1'; end if; end if; end if; -- Bring the ready to send signal into this clock domain ready_to_send_synced <= ready_to_send_meta; ready_to_send_meta <= ready_to_send; end if; end process; end Behavioral; ================================================ FILE: src/tmds_decoder.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Create Date: 10.07.2015 20:06:49 -- Design Name: -- Module Name: TMDS_decoder - Behavioral -- -- Description: Decoding for TMDS encoded symbols. This performs the conversion -- using a table lookup for simplicity -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity TMDS_decoder is Port ( clk : in std_logic; symbol : in std_logic_vector (9 downto 0); invalid_symbol : out std_logic; ctl_valid : out std_logic; ctl : out std_logic_vector (1 downto 0); terc4_valid : out std_logic; terc4 : out std_logic_vector (3 downto 0); guardband_valid : out std_logic; guardband : out std_logic_vector (0 downto 0); data_valid : out std_logic; data : out std_logic_vector (7 downto 0)); end TMDS_decoder; architecture Behavioral of TMDS_decoder is signal lookup : std_logic_vector (8 downto 0); begin decode_ctl: process(clk) begin if rising_edge(clk) then ------------------ -- TMDS data bytes if lookup(8) = '1' then data_valid <= '1'; data <= lookup(7 downto 0); else data_valid <= '0'; end if; ------------ -- CTL codes if lookup(8 downto 7) = "01" then ctl_valid <= '1'; ctl <= lookup(1 downto 0); else ctl_valid <= '0'; end if; ------------------------------ -- All other codes are invalid ------------------------------ if lookup(8 downto 7) = "00" then invalid_symbol <= '1'; else invalid_symbol <= '0'; end if; terc4_valid <= '0'; guardband_valid <= '0'; if lookup(8) = '1' then ------------------------- -- Decode the guard bands ------------------------- case lookup(7 downto 0) is when x"55" => guardband_valid <= '1'; guardband <= "0"; when x"AB" => guardband_valid <= '1'; guardband <= "1"; when others => null; end case; ------------------------- -- Decode TERC4 data ------------------------- case lookup(7 downto 0) is when x"5B" => terc4_valid <= '1'; terc4 <= "0000";-- "1010011100" TERC4 0000 when x"5A" => terc4_valid <= '1'; terc4 <= "0001"; -- "1001100011" TERC4 0001 when x"D3" => terc4_valid <= '1'; terc4 <= "0010"; -- "1011100100" TERC4 0010 when x"D9" => terc4_valid <= '1'; terc4 <= "0011"; -- "1011100010" TERC4 0011 when x"93" => terc4_valid <= '1'; terc4 <= "0100"; -- "0101110001" TERC4 0100 when x"22" => terc4_valid <= '1'; terc4 <= "0101"; -- "0100011110" TERC4 0101 when x"92" => terc4_valid <= '1'; terc4 <= "0110"; -- "0110001110" TERC4 0110 when x"44" => terc4_valid <= '1'; terc4 <= "0111"; -- "0100111100" TERC4 0111 when x"AB" => terc4_valid <= '1'; terc4 <= "1000"; -- "1011001100" TERC4 1000 & HDMI Guard band (video C0 and Video C2) when x"4B" => terc4_valid <= '1'; terc4 <= "1001"; -- "0100111001" TERC4 1001 when x"A4" => terc4_valid <= '1'; terc4 <= "1010"; -- "0110011100" TERC4 1010 when x"B5" => terc4_valid <= '1'; terc4 <= "1011"; -- "1011000110" TERC4 1011 when x"6D" => terc4_valid <= '1'; terc4 <= "1100"; -- "1010001110" TERC4 1100 when x"6C" => terc4_valid <= '1'; terc4 <= "1101"; -- "1001110001" TERC4 1101 when x"A5" => terc4_valid <= '1'; terc4 <= "1110"; -- "0101100011" TERC4 1110 when x"BA" => terc4_valid <= '1'; terc4 <= "1111"; -- "1011000011" TERC4 1111 when others => null; end case; end if; ------------------------------------------------------------- -- Convert the incoming signal to something we can decode -- -- For data symbols -- ---------------- -- bit 8 - 1 -- Data word flage -- bits 7:0 - xxxxxxxx - Data value -- -- For CTL symbols -- --------------- -- bit 8 - 0 - Data word flage -- bit 7 - 1 - CTL Indicator -- bits 6:2 - X - Ignored -- bits 1:0 - xx - CTL value -- -- For Invalid symbols -- ------------------- -- bit 8 - 0 - Data word flage -- bit 7 - 0 - TERC4 Inicated -- bit 6 - 0 - CTL Indicator -- bit 5 - 0 - Guard band indicator -- bits 4:0 - X - Unused -- ------------------------------------------------------------- case symbol is -- DVI-D Data sybmols -- Data 00 when "1111111111" => lookup <= "100000000"; when "0100000000" => lookup <= "100000000"; -- Data 01 when "0111111111" => lookup <= "100000001"; when "1100000000" => lookup <= "100000001"; -- Data 02 when "0111111110" => lookup <= "100000010"; when "1100000001" => lookup <= "100000010"; -- Data 03 when "1111111110" => lookup <= "100000011"; when "0100000001" => lookup <= "100000011"; -- Data 04 when "0111111100" => lookup <= "100000100"; when "1100000011" => lookup <= "100000100"; -- Data 05 when "1111111100" => lookup <= "100000101"; when "0100000011" => lookup <= "100000101"; -- Data 06 when "1111111101" => lookup <= "100000110"; when "0100000010" => lookup <= "100000110"; -- Data 07 when "0111111101" => lookup <= "100000111"; when "1100000010" => lookup <= "100000111"; -- Data 08 when "0111111000" => lookup <= "100001000"; when "1100000111" => lookup <= "100001000"; -- Data 09 when "1111111000" => lookup <= "100001001"; when "0100000111" => lookup <= "100001001"; -- Data 0a when "1111111001" => lookup <= "100001010"; when "0100000110" => lookup <= "100001010"; -- Data 0b when "0111111001" => lookup <= "100001011"; when "1100000110" => lookup <= "100001011"; -- Data 0c when "1111111011" => lookup <= "100001100"; when "0100000100" => lookup <= "100001100"; -- Data 0d when "0111111011" => lookup <= "100001101"; when "1100000100" => lookup <= "100001101"; -- Data 0e when "0111111010" => lookup <= "100001110"; when "1100000101" => lookup <= "100001110"; -- Data 0f when "1111111010" => lookup <= "100001111"; when "0100000101" => lookup <= "100001111"; -- Data 10 when "0111110000" => lookup <= "100010000"; -- Data 11 when "0100001111" => lookup <= "100010001"; -- Data 12 when "1111110001" => lookup <= "100010010"; when "0100001110" => lookup <= "100010010"; -- Data 13 when "0111110001" => lookup <= "100010011"; when "1100001110" => lookup <= "100010011"; -- Data 14 when "1111110011" => lookup <= "100010100"; when "0100001100" => lookup <= "100010100"; -- Data 15 when "0111110011" => lookup <= "100010101"; when "1100001100" => lookup <= "100010101"; -- Data 16 when "0111110010" => lookup <= "100010110"; when "1100001101" => lookup <= "100010110"; -- Data 17 when "1111110010" => lookup <= "100010111"; when "0100001101" => lookup <= "100010111"; -- Data 18 when "1111110111" => lookup <= "100011000"; when "0100001000" => lookup <= "100011000"; -- Data 19 when "0111110111" => lookup <= "100011001"; when "1100001000" => lookup <= "100011001"; -- Data 1a when "0111110110" => lookup <= "100011010"; when "1100001001" => lookup <= "100011010"; -- Data 1b when "1111110110" => lookup <= "100011011"; when "0100001001" => lookup <= "100011011"; -- Data 1c when "0111110100" => lookup <= "100011100"; when "1100001011" => lookup <= "100011100"; -- Data 1d when "1111110100" => lookup <= "100011101"; when "0100001011" => lookup <= "100011101"; -- Data 1e when "1001011111" => lookup <= "100011110"; when "0010100000" => lookup <= "100011110"; -- Data 1f when "0001011111" => lookup <= "100011111"; when "1010100000" => lookup <= "100011111"; -- Data 20 when "1100011111" => lookup <= "100100000"; when "0111100000" => lookup <= "100100000"; -- Data 21 when "0100011111" => lookup <= "100100001"; when "1111100000" => lookup <= "100100001"; -- Data 22 when "0100011110" => lookup <= "100100010"; -- TERC4 0101 -- Data 23 when "0111100001" => lookup <= "100100011"; -- Data 24 when "1111100011" => lookup <= "100100100"; when "0100011100" => lookup <= "100100100"; -- Data 25 when "0111100011" => lookup <= "100100101"; when "1100011100" => lookup <= "100100101"; -- Data 26 when "0111100010" => lookup <= "100100110"; -- Data 27 when "0100011101" => lookup <= "100100111"; -- Data 28 when "1111100111" => lookup <= "100101000"; when "0100011000" => lookup <= "100101000"; -- Data 29 when "0111100111" => lookup <= "100101001"; when "1100011000" => lookup <= "100101001"; -- Data 2a when "0111100110" => lookup <= "100101010"; when "1100011001" => lookup <= "100101010"; -- Data 2b when "1111100110" => lookup <= "100101011"; when "0100011001" => lookup <= "100101011"; -- Data 2c when "0111100100" => lookup <= "100101100"; -- Data 2d when "0100011011" => lookup <= "100101101"; -- Data 2e when "1001001111" => lookup <= "100101110"; when "0010110000" => lookup <= "100101110"; -- Data 2f when "0001001111" => lookup <= "100101111"; when "1010110000" => lookup <= "100101111"; -- Data 30 when "1111101111" => lookup <= "100110000"; when "0100010000" => lookup <= "100110000"; -- Data 31 when "0111101111" => lookup <= "100110001"; when "1100010000" => lookup <= "100110001"; -- Data 32 when "0111101110" => lookup <= "100110010"; when "1100010001" => lookup <= "100110010"; -- Data 33 when "1111101110" => lookup <= "100110011"; when "0100010001" => lookup <= "100110011"; -- Data 34 when "0111101100" => lookup <= "100110100"; when "1100010011" => lookup <= "100110100"; -- Data 35 when "1111101100" => lookup <= "100110101"; when "0100010011" => lookup <= "100110101"; -- Data 36 when "1001000111" => lookup <= "100110110"; -- Data 37 when "1010111000" => lookup <= "100110111"; -- Data 38 when "0111101000" => lookup <= "100111000"; -- Data 39 when "0100010111" => lookup <= "100111001"; -- Data 3a when "0010111100" => lookup <= "100111010"; when "1001000011" => lookup <= "100111010"; -- Data 3b when "1010111100" => lookup <= "100111011"; when "0001000011" => lookup <= "100111011"; -- Data 3c when "0010111110" => lookup <= "100111100"; when "1001000001" => lookup <= "100111100"; -- Data 3d when "1010111110" => lookup <= "100111101"; when "0001000001" => lookup <= "100111101"; -- Data 3e when "1010111111" => lookup <= "100111110"; when "0001000000" => lookup <= "100111110"; -- Data 3f when "0010111111" => lookup <= "100111111"; when "1001000000" => lookup <= "100111111"; -- Data 40 when "1100111111" => lookup <= "101000000"; when "0111000000" => lookup <= "101000000"; -- Data 41 when "0100111111" => lookup <= "101000001"; when "1111000000" => lookup <= "101000001"; -- Data 42 when "0100111110" => lookup <= "101000010"; when "1111000001" => lookup <= "101000010"; -- Data 43 when "1100111110" => lookup <= "101000011"; when "0111000001" => lookup <= "101000011"; -- Data 44 when "0100111100" => lookup <= "101000100"; -- TERC4 0111 -- Data 45 when "0111000011" => lookup <= "101000101"; -- Data 46 when "1100111101" => lookup <= "101000110"; when "0111000010" => lookup <= "101000110"; -- Data 47 when "0100111101" => lookup <= "101000111"; when "1111000010" => lookup <= "101000111"; -- Data 48 when "1111000111" => lookup <= "101001000"; when "0100111000" => lookup <= "101001000"; -- Data 49 when "0111000111" => lookup <= "101001001"; when "1100111000" => lookup <= "101001001"; -- Data 4a when "0111000110" => lookup <= "101001010"; -- Data 4b when "0100111001" => lookup <= "101001011"; -- TERC4 1001 -- Data 4c when "1100111011" => lookup <= "101001100"; when "0111000100" => lookup <= "101001100"; -- Data 4d when "0100111011" => lookup <= "101001101"; when "1111000100" => lookup <= "101001101"; -- Data 4e when "1001101111" => lookup <= "101001110"; when "0010010000" => lookup <= "101001110"; -- Data 4f when "0001101111" => lookup <= "101001111"; when "1010010000" => lookup <= "101001111"; -- Data 50 when "1111001111" => lookup <= "101010000"; when "0100110000" => lookup <= "101010000"; -- Data 51 when "0111001111" => lookup <= "101010001"; when "1100110000" => lookup <= "101010001"; -- Data 52 when "0111001110" => lookup <= "101010010"; when "1100110001" => lookup <= "101010010"; -- Data 53 when "1111001110" => lookup <= "101010011"; when "0100110001" => lookup <= "101010011"; -- Data 54 when "0111001100" => lookup <= "101010100"; -- Data 55 when "0100110011" => lookup <= "101010101"; -- HDMI Guard band (video C1, data C1 & C2) -- Data 56 when "1001100111" => lookup <= "101010110"; when "0010011000" => lookup <= "101010110"; -- Data 57 when "0001100111" => lookup <= "101010111"; when "1010011000" => lookup <= "101010111"; -- Data 58 when "1100110111" => lookup <= "101011000"; when "0111001000" => lookup <= "101011000"; -- Data 59 when "0100110111" => lookup <= "101011001"; when "1111001000" => lookup <= "101011001"; -- Data 5a when "1001100011" => lookup <= "101011010"; -- TERC4 0001 -- Data 5b when "1010011100" => lookup <= "101011011"; -- TERC4 0000 -- Data 5c when "0010011110" => lookup <= "101011100"; when "1001100001" => lookup <= "101011100"; -- Data 5d when "1010011110" => lookup <= "101011101"; when "0001100001" => lookup <= "101011101"; -- Data 5e when "1010011111" => lookup <= "101011110"; when "0001100000" => lookup <= "101011110"; -- Data 5f when "0010011111" => lookup <= "101011111"; when "1001100000" => lookup <= "101011111"; -- Data 60 when "1111011111" => lookup <= "101100000"; when "0100100000" => lookup <= "101100000"; -- Data 61 when "0111011111" => lookup <= "101100001"; when "1100100000" => lookup <= "101100001"; -- Data 62 when "0111011110" => lookup <= "101100010"; when "1100100001" => lookup <= "101100010"; -- Data 63 when "1111011110" => lookup <= "101100011"; when "0100100001" => lookup <= "101100011"; -- Data 64 when "0111011100" => lookup <= "101100100"; when "1100100011" => lookup <= "101100100"; -- Data 65 when "1111011100" => lookup <= "101100101"; when "0100100011" => lookup <= "101100101"; -- Data 66 when "1001110111" => lookup <= "101100110"; when "0010001000" => lookup <= "101100110"; -- Data 67 when "0001110111" => lookup <= "101100111"; when "1010001000" => lookup <= "101100111"; -- Data 68 when "0111011000" => lookup <= "101101000"; -- Data 69 when "0100100111" => lookup <= "101101001"; -- Data 6a when "1001110011" => lookup <= "101101010"; when "0010001100" => lookup <= "101101010"; -- Data 6b when "0001110011" => lookup <= "101101011"; when "1010001100" => lookup <= "101101011"; -- Data 6c when "1001110001" => lookup <= "101101100"; -- TERC4 1101 -- Data 6d when "1010001110" => lookup <= "101101101"; -- TERC4 1100 -- Data 6e when "1010001111" => lookup <= "101101110"; when "0001110000" => lookup <= "101101110"; -- Data 6f when "0010001111" => lookup <= "101101111"; when "1001110000" => lookup <= "101101111"; -- Data 70 when "1100101111" => lookup <= "101110000"; when "0111010000" => lookup <= "101110000"; -- Data 71 when "0100101111" => lookup <= "101110001"; when "1111010000" => lookup <= "101110001"; -- Data 72 when "1001111011" => lookup <= "101110010"; when "0010000100" => lookup <= "101110010"; -- Data 73 when "0001111011" => lookup <= "101110011"; when "1010000100" => lookup <= "101110011"; -- Data 74 when "1001111001" => lookup <= "101110100"; when "0010000110" => lookup <= "101110100"; -- Data 75 when "0001111001" => lookup <= "101110101"; when "1010000110" => lookup <= "101110101"; -- Data 76 when "1010000111" => lookup <= "101110110"; -- Data 77 when "1001111000" => lookup <= "101110111"; -- Data 78 when "1001111101" => lookup <= "101111000"; when "0010000010" => lookup <= "101111000"; -- Data 79 when "0001111101" => lookup <= "101111001"; when "1010000010" => lookup <= "101111001"; -- Data 7a when "0001111100" => lookup <= "101111010"; when "1010000011" => lookup <= "101111010"; -- Data 7b when "1001111100" => lookup <= "101111011"; when "0010000011" => lookup <= "101111011"; -- Data 7c when "0001111110" => lookup <= "101111100"; when "1010000001" => lookup <= "101111100"; -- Data 7d when "1001111110" => lookup <= "101111101"; when "0010000001" => lookup <= "101111101"; -- Data 7e when "1001111111" => lookup <= "101111110"; when "0010000000" => lookup <= "101111110"; -- Data 7f when "0001111111" => lookup <= "101111111"; when "1010000000" => lookup <= "101111111"; -- Data 80 when "1101111111" => lookup <= "110000000"; when "0110000000" => lookup <= "110000000"; -- Data 81 when "0101111111" => lookup <= "110000001"; when "1110000000" => lookup <= "110000001"; -- Data 82 when "0101111110" => lookup <= "110000010"; when "1110000001" => lookup <= "110000010"; -- Data 83 when "1101111110" => lookup <= "110000011"; when "0110000001" => lookup <= "110000011"; -- Data 84 when "0101111100" => lookup <= "110000100"; when "1110000011" => lookup <= "110000100"; -- Data 85 when "1101111100" => lookup <= "110000101"; when "0110000011" => lookup <= "110000101"; -- Data 86 when "1101111101" => lookup <= "110000110"; when "0110000010" => lookup <= "110000110"; -- Data 87 when "0101111101" => lookup <= "110000111"; when "1110000010" => lookup <= "110000111"; -- Data 88 when "0101111000" => lookup <= "110001000"; -- Data 89 when "0110000111" => lookup <= "110001001"; -- Data 8a when "1101111001" => lookup <= "110001010"; when "0110000110" => lookup <= "110001010"; -- Data 8b when "0101111001" => lookup <= "110001011"; when "1110000110" => lookup <= "110001011"; -- Data 8c when "1101111011" => lookup <= "110001100"; when "0110000100" => lookup <= "110001100"; -- Data 8d when "0101111011" => lookup <= "110001101"; when "1110000100" => lookup <= "110001101"; -- Data 8e when "1000101111" => lookup <= "110001110"; when "0011010000" => lookup <= "110001110"; -- Data 8f when "0000101111" => lookup <= "110001111"; when "1011010000" => lookup <= "110001111"; -- Data 90 when "1110001111" => lookup <= "110010000"; when "0101110000" => lookup <= "110010000"; -- Data 91 when "0110001111" => lookup <= "110010001"; when "1101110000" => lookup <= "110010001"; -- Data 92 when "0110001110" => lookup <= "110010010"; -- TERC4 0110 -- Data 93 when "0101110001" => lookup <= "110010011"; -- TERC4 0100 -- Data 94 when "1101110011" => lookup <= "110010100"; when "0110001100" => lookup <= "110010100"; -- Data 95 when "0101110011" => lookup <= "110010101"; when "1110001100" => lookup <= "110010101"; -- Data 96 when "1000100111" => lookup <= "110010110"; -- Data 97 when "1011011000" => lookup <= "110010111"; -- Data 98 when "1101110111" => lookup <= "110011000"; when "0110001000" => lookup <= "110011000"; -- Data 99 when "0101110111" => lookup <= "110011001"; when "1110001000" => lookup <= "110011001"; -- Data 9a when "0011011100" => lookup <= "110011010"; when "1000100011" => lookup <= "110011010"; -- Data 9b when "1011011100" => lookup <= "110011011"; when "0000100011" => lookup <= "110011011"; -- Data 9c when "0011011110" => lookup <= "110011100"; when "1000100001" => lookup <= "110011100"; -- Data 9d when "1011011110" => lookup <= "110011101"; when "0000100001" => lookup <= "110011101"; -- Data 9e when "1011011111" => lookup <= "110011110"; when "0000100000" => lookup <= "110011110"; -- Data 9f when "0011011111" => lookup <= "110011111"; when "1000100000" => lookup <= "110011111"; -- Data a0 when "1110011111" => lookup <= "110100000"; when "0101100000" => lookup <= "110100000"; -- Data a1 when "0110011111" => lookup <= "110100001"; when "1101100000" => lookup <= "110100001"; -- Data a2 when "0110011110" => lookup <= "110100010"; when "1101100001" => lookup <= "110100010"; -- Data a3 when "1110011110" => lookup <= "110100011"; when "0101100001" => lookup <= "110100011"; -- Data a4 when "0110011100" => lookup <= "110100100"; -- TERC4 1010 -- Data a5 when "0101100011" => lookup <= "110100101"; -- TERC4 1110 -- Data a6 when "1000110111" => lookup <= "110100110"; when "0011001000" => lookup <= "110100110"; -- Data a7 when "0000110111" => lookup <= "110100111"; when "1011001000" => lookup <= "110100111"; -- Data a8 when "1101100111" => lookup <= "110101000"; when "0110011000" => lookup <= "110101000"; -- Data a9 when "0101100111" => lookup <= "110101001"; when "1110011000" => lookup <= "110101001"; -- Data aa when "1000110011" => lookup <= "110101010"; -- Data ab when "1011001100" => lookup <= "110101011"; -- TERC4 1000 & HDMI Guard band (video C0 and Video C2) -- Data ac when "0011001110" => lookup <= "110101100"; when "1000110001" => lookup <= "110101100"; -- Data ad when "1011001110" => lookup <= "110101101"; when "0000110001" => lookup <= "110101101"; -- Data ae when "1011001111" => lookup <= "110101110"; when "0000110000" => lookup <= "110101110"; -- Data af when "0011001111" => lookup <= "110101111"; when "1000110000" => lookup <= "110101111"; -- Data b0 when "1101101111" => lookup <= "110110000"; when "0110010000" => lookup <= "110110000"; -- Data b1 when "0101101111" => lookup <= "110110001"; when "1110010000" => lookup <= "110110001"; -- Data b2 when "1000111011" => lookup <= "110110010"; when "0011000100" => lookup <= "110110010"; -- Data b3 when "0000111011" => lookup <= "110110011"; when "1011000100" => lookup <= "110110011"; -- Data b4 when "1000111001" => lookup <= "110110100"; -- Data b5 when "1011000110" => lookup <= "110110101"; -- TERC4 1011 -- Data b6 when "1011000111" => lookup <= "110110110"; when "0000111000" => lookup <= "110110110"; -- Data b7 when "0011000111" => lookup <= "110110111"; when "1000111000" => lookup <= "110110111"; -- Data b8 when "1000111101" => lookup <= "110111000"; when "0011000010" => lookup <= "110111000"; -- Data b9 when "0000111101" => lookup <= "110111001"; when "1011000010" => lookup <= "110111001"; -- Data ba when "1011000011" => lookup <= "110111010"; -- TERC4 1111 -- Data bb when "1000111100" => lookup <= "110111011"; -- Data bc when "0000111110" => lookup <= "110111100"; when "1011000001" => lookup <= "110111100"; -- Data bd when "1000111110" => lookup <= "110111101"; when "0011000001" => lookup <= "110111101"; -- Data be when "1000111111" => lookup <= "110111110"; when "0011000000" => lookup <= "110111110"; -- Data bf when "0000111111" => lookup <= "110111111"; when "1011000000" => lookup <= "110111111"; -- Data c0 when "1110111111" => lookup <= "111000000"; when "0101000000" => lookup <= "111000000"; -- Data c1 when "0110111111" => lookup <= "111000001"; when "1101000000" => lookup <= "111000001"; -- Data c2 when "0110111110" => lookup <= "111000010"; when "1101000001" => lookup <= "111000010"; -- Data c3 when "1110111110" => lookup <= "111000011"; when "0101000001" => lookup <= "111000011"; -- Data c4 when "0110111100" => lookup <= "111000100"; when "1101000011" => lookup <= "111000100"; -- Data c5 when "1110111100" => lookup <= "111000101"; when "0101000011" => lookup <= "111000101"; -- Data c6 when "1000010111" => lookup <= "111000110"; -- Data c7 when "1011101000" => lookup <= "111000111"; -- Data c8 when "0110111000" => lookup <= "111001000"; -- Data c9 when "0101000111" => lookup <= "111001001"; -- Data ca when "0011101100" => lookup <= "111001010"; when "1000010011" => lookup <= "111001010"; -- Data cb when "1011101100" => lookup <= "111001011"; when "0000010011" => lookup <= "111001011"; -- Data cc when "0011101110" => lookup <= "111001100"; when "1000010001" => lookup <= "111001100"; -- Data cd when "1011101110" => lookup <= "111001101"; when "0000010001" => lookup <= "111001101"; -- Data ce when "1011101111" => lookup <= "111001110"; when "0000010000" => lookup <= "111001110"; -- Data cf when "0011101111" => lookup <= "111001111"; when "1000010000" => lookup <= "111001111"; -- Data d0 when "1101001111" => lookup <= "111010000"; when "0110110000" => lookup <= "111010000"; -- Data d1 when "0101001111" => lookup <= "111010001"; when "1110110000" => lookup <= "111010001"; -- Data d2 when "1000011011" => lookup <= "111010010"; -- Data d3 when "1011100100" => lookup <= "111010011"; -- TERC4 0010 -- Data d4 when "0011100110" => lookup <= "111010100"; when "1000011001" => lookup <= "111010100"; -- Data d5 when "1011100110" => lookup <= "111010101"; when "0000011001" => lookup <= "111010101"; -- Data d6 when "1011100111" => lookup <= "111010110"; when "0000011000" => lookup <= "111010110"; -- Data d7 when "0011100111" => lookup <= "111010111"; when "1000011000" => lookup <= "111010111"; -- Data d8 when "1000011101" => lookup <= "111011000"; -- Data d9 when "1011100010" => lookup <= "111011001"; -- TERC4 0011 -- Data da when "1011100011" => lookup <= "111011010"; when "0000011100" => lookup <= "111011010"; -- Data db when "0011100011" => lookup <= "111011011"; when "1000011100" => lookup <= "111011011"; -- Data dc when "1011100001" => lookup <= "111011100"; -- Data dd when "1000011110" => lookup <= "111011101"; -- Data de when "1000011111" => lookup <= "111011110"; when "0011100000" => lookup <= "111011110"; -- Data df when "0000011111" => lookup <= "111011111"; when "1011100000" => lookup <= "111011111"; -- Data e0 when "1101011111" => lookup <= "111100000"; when "0110100000" => lookup <= "111100000"; -- Data e1 when "0101011111" => lookup <= "111100001"; when "1110100000" => lookup <= "111100001"; -- Data e2 when "0011110100" => lookup <= "111100010"; when "1000001011" => lookup <= "111100010"; -- Data e3 when "1011110100" => lookup <= "111100011"; when "0000001011" => lookup <= "111100011"; -- Data e4 when "0011110110" => lookup <= "111100100"; when "1000001001" => lookup <= "111100100"; -- Data e5 when "1011110110" => lookup <= "111100101"; when "0000001001" => lookup <= "111100101"; -- Data e6 when "1011110111" => lookup <= "111100110"; when "0000001000" => lookup <= "111100110"; -- Data e7 when "0011110111" => lookup <= "111100111"; when "1000001000" => lookup <= "111100111"; -- Data e8 when "0011110010" => lookup <= "111101000"; when "1000001101" => lookup <= "111101000"; -- Data e9 when "1011110010" => lookup <= "111101001"; when "0000001101" => lookup <= "111101001"; -- Data ea when "1011110011" => lookup <= "111101010"; when "0000001100" => lookup <= "111101010"; -- Data eb when "0011110011" => lookup <= "111101011"; when "1000001100" => lookup <= "111101011"; -- Data ec when "1011110001" => lookup <= "111101100"; when "0000001110" => lookup <= "111101100"; -- Data ed when "0011110001" => lookup <= "111101101"; when "1000001110" => lookup <= "111101101"; -- Data ee when "1000001111" => lookup <= "111101110"; -- Data ef when "1011110000" => lookup <= "111101111"; -- Data f0 when "0011111010" => lookup <= "111110000"; when "1000000101" => lookup <= "111110000"; -- Data f1 when "1011111010" => lookup <= "111110001"; when "0000000101" => lookup <= "111110001"; -- Data f2 when "1011111011" => lookup <= "111110010"; when "0000000100" => lookup <= "111110010"; -- Data f3 when "0011111011" => lookup <= "111110011"; when "1000000100" => lookup <= "111110011"; -- Data f4 when "1011111001" => lookup <= "111110100"; when "0000000110" => lookup <= "111110100"; -- Data f5 when "0011111001" => lookup <= "111110101"; when "1000000110" => lookup <= "111110101"; -- Data f6 when "0011111000" => lookup <= "111110110"; when "1000000111" => lookup <= "111110110"; -- Data f7 when "1011111000" => lookup <= "111110111"; when "0000000111" => lookup <= "111110111"; -- Data f8 when "1011111101" => lookup <= "111111000"; when "0000000010" => lookup <= "111111000"; -- Data f9 when "0011111101" => lookup <= "111111001"; when "1000000010" => lookup <= "111111001"; -- Data fa when "0011111100" => lookup <= "111111010"; when "1000000011" => lookup <= "111111010"; -- Data fb when "1011111100" => lookup <= "111111011"; when "0000000011" => lookup <= "111111011"; -- Data fc when "0011111110" => lookup <= "111111100"; when "1000000001" => lookup <= "111111100"; -- Data fd when "1011111110" => lookup <= "111111101"; when "0000000001" => lookup <= "111111101"; -- Data fe when "1011111111" => lookup <= "111111110"; when "0000000000" => lookup <= "111111110"; -- Data ff when "0011111111" => lookup <= "111111111"; when "1000000000" => lookup <= "111111111"; -- DVI-D CTL symbols when "0010101011" => lookup <= "01" & "00000" & "01"; -- CTL1 when "0101010100" => lookup <= "01" & "00000" & "10"; -- CTL2 when "1010101011" => lookup <= "01" & "00000" & "11"; -- CTL3 when "1101010100" => lookup <= "01" & "00000" & "00"; -- CTL0 -- Invalid symbols when others => lookup <= "0000" & "00000"; end case; end if; end process; end Behavioral; -- For Guard band and TERC4 decoding (to be done later!) -- when x"55" => -- "0100110011" HDMI Guard band (video C1, data C1 & C2) -- when x"5B" => -- "1010011100" TERC4 0000 -- when x"5A" => -- "1001100011" TERC4 0001 -- when x"D3" => -- "1011100100" TERC4 0010 -- when x"D9" => -- "1011100010" TERC4 0011 -- when x"93" => -- "0101110001" TERC4 0100 -- when x"22" => -- "0100011110" TERC4 0101 -- when x"92" => -- "0110001110" TERC4 0110 -- when x"44" => -- "0100111100" TERC4 0111 -- when x"AB" => -- "1011001100" TERC4 1000 & HDMI Guard band (video C0 and Video C2) -- when x"4B" => -- "0100111001" TERC4 1001 -- when x"A4" => -- "0110011100" TERC4 1010 -- when x"B5" => -- "1011000110" TERC4 1011 -- when x"6D" => -- "1010001110" TERC4 1100 -- when x"6C" => -- "1001110001" TERC4 1101 -- when x"A5" => -- "0101100011" TERC4 1110 -- when x"BA" => -- "1011000011" TERC4 1111 ================================================ FILE: src/tmds_encoder.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: tmds_encoder - Behavioral -- -- Description: 8b/10b TMDS encoder -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity tmds_encoder is Port ( clk : in std_logic; data : in std_logic_vector (7 downto 0); c : in std_logic_vector (1 downto 0); blank : in std_logic; encoded : out std_logic_vector (9 downto 0)); end entity; architecture Behavioral of tmds_encoder is signal xored : STD_LOGIC_VECTOR (8 downto 0); signal xnored : STD_LOGIC_VECTOR (8 downto 0); signal ones : STD_LOGIC_VECTOR (3 downto 0); signal data_word : STD_LOGIC_VECTOR (8 downto 0); signal data_word_inv : STD_LOGIC_VECTOR (8 downto 0); signal data_word_disparity : STD_LOGIC_VECTOR (3 downto 0); signal dc_bias : STD_LOGIC_VECTOR (3 downto 0) := (others => '0'); begin -- Work our the two different encodings for the byte xored(0) <= data(0); xored(1) <= data(1) xor xored(0); xored(2) <= data(2) xor xored(1); xored(3) <= data(3) xor xored(2); xored(4) <= data(4) xor xored(3); xored(5) <= data(5) xor xored(4); xored(6) <= data(6) xor xored(5); xored(7) <= data(7) xor xored(6); xored(8) <= '1'; xnored(0) <= data(0); xnored(1) <= data(1) xnor xnored(0); xnored(2) <= data(2) xnor xnored(1); xnored(3) <= data(3) xnor xnored(2); xnored(4) <= data(4) xnor xnored(3); xnored(5) <= data(5) xnor xnored(4); xnored(6) <= data(6) xnor xnored(5); xnored(7) <= data(7) xnor xnored(6); xnored(8) <= '0'; -- Count how many ones are set in data ones <= "0000" + data(0) + data(1) + data(2) + data(3) + data(4) + data(5) + data(6) + data(7); -- Decide which encoding to use process(ones, data(0), xnored, xored) begin if ones > 4 or (ones = 4 and data(0) = '0') then data_word <= xnored; data_word_inv <= NOT(xnored); else data_word <= xored; data_word_inv <= NOT(xored); end if; end process; -- Work out the DC bias of the dataword; data_word_disparity <= "1100" + data_word(0) + data_word(1) + data_word(2) + data_word(3) + data_word(4) + data_word(5) + data_word(6) + data_word(7); -- Now work out what the output should be process(clk) begin if rising_edge(clk) then if blank = '1' then -- In the control periods, all values have and have balanced bit count case c is when "00" => encoded <= "1101010100"; when "01" => encoded <= "0010101011"; when "10" => encoded <= "0101010100"; when others => encoded <= "1010101011"; end case; dc_bias <= (others => '0'); else if dc_bias = "00000" or data_word_disparity = 0 then -- dataword has no disparity if data_word(8) = '1' then encoded <= "01" & data_word(7 downto 0); dc_bias <= dc_bias + data_word_disparity; else encoded <= "10" & data_word_inv(7 downto 0); dc_bias <= dc_bias - data_word_disparity; end if; elsif (dc_bias(3) = '0' and data_word_disparity(3) = '0') or (dc_bias(3) = '1' and data_word_disparity(3) = '1') then encoded <= '1' & data_word(8) & data_word_inv(7 downto 0); dc_bias <= dc_bias + data_word(8) - data_word_disparity; else encoded <= '0' & data_word; dc_bias <= dc_bias - data_word_inv(8) + data_word_disparity; end if; end if; end if; end process; end Behavioral; ================================================ FILE: test_bench/hdmi_test_generator/hdmi_ouput_test.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Top level design for my minimal HDMI output project -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity hdmi_output_test is Port ( clk50 : in STD_LOGIC; hdmi_out_p : out STD_LOGIC_VECTOR(3 downto 0); hdmi_out_n : out STD_LOGIC_VECTOR(3 downto 0); leds : out std_logic_vector(7 downto 0)); end hdmi_output_test; architecture Behavioral of hdmi_output_test is COMPONENT vga_gen PORT( clk50 : IN std_logic; pixel_clock : OUT std_logic; red_p : OUT std_logic_vector(7 downto 0); green_p : OUT std_logic_vector(7 downto 0); blue_p : OUT std_logic_vector(7 downto 0); blank : OUT std_logic; hsync : OUT std_logic; vsync : OUT std_logic ); END COMPONENT; COMPONENT Minimal_hdmi_symbols PORT( clk : IN std_logic; blank : IN std_logic; hsync : IN std_logic; vsync : IN std_logic; red : IN std_logic; green : IN std_logic; blue : IN std_logic; c0 : OUT std_logic_vector(9 downto 0); c1 : OUT std_logic_vector(9 downto 0); c2 : OUT std_logic_vector(9 downto 0) ); END COMPONENT; COMPONENT serializers PORT( clk : IN std_logic; c0 : IN std_logic_vector(9 downto 0); c1 : IN std_logic_vector(9 downto 0); c2 : IN std_logic_vector(9 downto 0); hdmi_p : OUT std_logic_vector(3 downto 0); hdmi_n : OUT std_logic_vector(3 downto 0) ); END COMPONENT; signal pixel_clock : std_logic; signal red_p : std_logic_vector(7 downto 0); signal green_p : std_logic_vector(7 downto 0); signal blue_p : std_logic_vector(7 downto 0); signal blank : std_logic; signal hsync : std_logic; signal vsync : std_logic; signal c0, c1, c2 : std_logic_vector(9 downto 0); begin leds <= x"AA"; --------------------------------------- -- Generate a 1280x720 VGA test pattern --------------------------------------- Inst_vga_gen: vga_gen PORT MAP( clk50 => clk50, pixel_clock => pixel_clock, red_p => red_p, green_p => green_p, blue_p => blue_p, blank => blank, hsync => hsync, vsync => vsync ); --------------------------------------------------- -- Convert 9 bits of the VGA signals to the DVI-D/TMDS output --------------------------------------------------- i_Minimal_hdmi_symbols: Minimal_hdmi_symbols PORT MAP( clk => pixel_clock, blank => blank, hsync => hsync, vsync => vsync, red => red_p(7), green => green_p(7), blue => blue_p(7), c0 => c0, c1 => c1, c2 => c2 ); i_serializers : serializers PORT MAP ( clk => pixel_clock, c0 => c0, c1 => c1, c2 => c2, hdmi_p => hdmi_out_p, hdmi_n => hdmi_out_n); end Behavioral; ================================================ FILE: test_bench/hdmi_test_generator/minimal_hdmi_symbols.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field (others => '0')); signal symbols : STD_LOGIC_VECTOR (29 downto 0) := (others => '0'); signal last_blank : std_logic := '0'; signal last_vsync : std_logic := '0'; signal last_hsync : std_logic := '0'; signal data_island_armed : std_logic := '0'; signal data_island_index : unsigned(5 downto 0) := (others => '1'); begin c0 <= symbols(29 downto 20); c1 <= symbols(19 downto 10); c2 <= symbols( 9 downto 0); process(clk) begin if rising_edge(clk) then case symbol_queue(0) is --------------------------------------------------------------- -- Eight TMDS encoded colours for testing --------------------------------------------------------------- when "00000" => symbols <= "0111110000" & "0111110000" & "0111110000"; -- RGB 0x101010 - Black when "00001" => symbols <= "0111110000" & "0111110000" & "1011110000"; -- RGB 0xEF1010 - Red when "00010" => symbols <= "0111110000" & "1011110000" & "0111110000"; -- RGB 0x10EF10 - Green when "00011" => symbols <= "0111110000" & "1011110000" & "1011110000"; -- RGB 0xEFEF10 - Cyan when "00100" => symbols <= "1011110000" & "0111110000" & "0111110000"; -- RGB 0x1010EF - Blue when "00101" => symbols <= "1011110000" & "0111110000" & "1011110000"; -- RGB 0xEF10EF - Magenta when "00110" => symbols <= "1011110000" & "1011110000" & "0111110000"; -- RGB 0x10EFEF - Yellow when "00111" => symbols <= "1011110000" & "1011110000" & "1011110000"; -- RGB 0xEFEFEF - White --------------------------------------------------------------- -- control symbols from 5.4.2 - part of the DVI-D standard --------------------------------------------------------------- when "01000" => symbols <= "1101010100" & "1101010100" & "1101010100"; -- CTL periods when "01001" => symbols <= "0010101011" & "1101010100" & "1101010100"; -- Hsync when "01010" => symbols <= "0101010100" & "1101010100" & "1101010100"; -- vSync when "01011" => symbols <= "1010101011" & "1101010100" & "1101010100"; -- vSync+hSync --------------------------------------------------------------- -- Symbols to signal the start of a HDMI feature --------------------------------------------------------------- when "01100" => symbols <= "0101010100" & "0010101011" & "0010101011"; -- DataIslandPeamble, with VSYNC - 5.2.1.1 when "01101" => symbols <= "0101100011" & "0100110011" & "0100110011"; -- DataIslandGuardBand, with VSYNC - 5.2.3.3 when "01110" => symbols <= "1101010100" & "0010101011" & "1101010100"; -- VideoPramble 5.2.1.1 when "01111" => symbols <= "1011001100" & "0100110011" & "1011001100"; -- VideoGuardBand 5.2.2.1 --------------------------------------------------------------- -- From TERC4 codes in 5.4.3, and data data layout from 5.2.3.1 -- -- First nibble is used for the nFirstWordOfPacket (MSB) Header Bit, VSYNC, HSYNC (LSB). -- The packet is sent where VSYNC = '1' and HSYNC = '0', so we are left with 4 options -- Second nibble is used for the odd bits the four data sub-packets -- Third nibble is used for the even bits the four data sub-packets -- -- These can be used to contruct a data island with any header -- and any data in subpacket 0, but all other subpackets -- must be 0s. --------------------------------------------------------------- when "10000" => symbols <= "1011100100" & "1010011100" & "1010011100"; -- 0010 0000 0000, TERC4 coded when "10001" => symbols <= "1011100100" & "1010011100" & "1001100011"; -- 0010 0000 0001, TERC4 coded when "10010" => symbols <= "1011100100" & "1001100011" & "1010011100"; -- 0010 0000 0000, TERC4 coded when "10011" => symbols <= "1011100100" & "1001100011" & "1001100011"; -- 0010 0001 0001, TERC4 coded when "10100" => symbols <= "0110001110" & "1010011100" & "1010011100"; -- 0110 0000 0000, TERC4 coded when "10101" => symbols <= "0110001110" & "1010011100" & "1001100011"; -- 0110 0000 0001, TERC4 coded when "10110" => symbols <= "0110001110" & "1001100011" & "1010011100"; -- 0110 0001 0000, TERC4 coded when "10111" => symbols <= "0110001110" & "1001100011" & "1001100011"; -- 0110 0001 0001, TERC4 coded when "11000" => symbols <= "0110011100" & "1010011100" & "1010011100"; -- 1010 0000 0000, TERC4 coded when "11001" => symbols <= "0110011100" & "1010011100" & "1001100011"; -- 1010 0000 0001, TERC4 coded when "11010" => symbols <= "0110011100" & "1001100011" & "1010011100"; -- 1010 0001 0000, TERC4 coded when "11011" => symbols <= "0110011100" & "1001100011" & "1001100011"; -- 1010 0001 0001, TERC4 coded when "11100" => symbols <= "0101100011" & "1010011100" & "1010011100"; -- 1110 0000 0000, TERC4 coded when "11101" => symbols <= "0101100011" & "1010011100" & "1001100011"; -- 1110 0000 0001, TERC4 coded when "11110" => symbols <= "0101100011" & "1001100011" & "1010011100"; -- 1110 0001 0000, TERC4 coded when "11111" => symbols <= "0101100011" & "1001100011" & "1001100011"; -- 1110 0001 0001, TERC4 coded when others => symbols <= (others => '0'); end case; if blank = '0' then -- Are we being asked to send video data? If so we need to send a peramble if last_blank = '1' then symbol_queue(10) <= "00" & blue & green & red; symbol_queue(9) <= "01111"; -- Video Guard Band symbol_queue(8) <= "01111"; symbol_queue(7) <= "01110"; -- Video Preamble symbol_queue(6) <= "01110"; symbol_queue(5) <= "01110"; symbol_queue(4) <= "01110"; symbol_queue(3) <= "01110"; symbol_queue(2) <= "01110"; symbol_queue(1) <= "01110"; symbol_queue(0) <= "01110"; else symbol_queue(0 to 9) <= symbol_queue(1 to 10); symbol_queue(10) <= "00" & blue & green & red; end if; else -- Just merge in the syncs into the control period case data_island_index is when "000000" => symbol_queue(10) <= "01100"; -- Data island preamble when "000001" => symbol_queue(10) <= "01100"; -- Data island preamble when "000010" => symbol_queue(10) <= "01100"; -- Data island preamble when "000011" => symbol_queue(10) <= "01100"; -- Data island preamble when "000100" => symbol_queue(10) <= "01100"; -- Data island preamble when "000101" => symbol_queue(10) <= "01100"; -- Data island preamble when "000110" => symbol_queue(10) <= "01100"; -- Data island preamble when "000111" => symbol_queue(10) <= "01100"; -- Data island preamble when "001000" => symbol_queue(10) <= "01101"; -- Data island Guard Band when "001001" => symbol_queue(10) <= "01101"; -- Data island Guard Band ------------------------- -- For a YCC mode AVI Infoframe Data Island ------------------------- -- Data Island (0-7) when "001010" => symbol_queue(10) <= "10011"; -- First word when "001011" => symbol_queue(10) <= "11111"; when "001100" => symbol_queue(10) <= "11001"; when "001101" => symbol_queue(10) <= "11000"; when "001110" => symbol_queue(10) <= "11000"; when "001111" => symbol_queue(10) <= "11000"; when "010000" => symbol_queue(10) <= "11000"; when "010001" => symbol_queue(10) <= "11110"; -- Data Island (8-15) when "010010" => symbol_queue(10) <= "11000"; when "010011" => symbol_queue(10) <= "11100"; when "010100" => symbol_queue(10) <= "11000"; when "010101" => symbol_queue(10) <= "11000"; when "010110" => symbol_queue(10) <= "11000"; when "010111" => symbol_queue(10) <= "11000"; when "011000" => symbol_queue(10) <= "11000"; when "011001" => symbol_queue(10) <= "11000"; -- Data Island (16-23) when "011010" => symbol_queue(10) <= "11100"; when "011011" => symbol_queue(10) <= "11000"; when "011100" => symbol_queue(10) <= "11100"; when "011101" => symbol_queue(10) <= "11100"; when "011110" => symbol_queue(10) <= "11000"; when "011111" => symbol_queue(10) <= "11000"; when "100000" => symbol_queue(10) <= "11000"; when "100001" => symbol_queue(10) <= "11000"; -- Data Island (24-31) when "100010" => symbol_queue(10) <= "11000"; when "100011" => symbol_queue(10) <= "11000"; when "100100" => symbol_queue(10) <= "11100"; when "100101" => symbol_queue(10) <= "11000"; when "100110" => symbol_queue(10) <= "11010"; when "100111" => symbol_queue(10) <= "11100"; when "101000" => symbol_queue(10) <= "11111"; when "101001" => symbol_queue(10) <= "11110"; ------------------------- -- For a NULL Data Island ------------------------- -- Data Island (0-7) -- when "001010" => symbol_queue(10) <= "10000"; -- First word -- when "001011" => symbol_queue(10) <= "11000"; -- when "001100" => symbol_queue(10) <= "11000"; -- when "001101" => symbol_queue(10) <= "11000"; -- when "001110" => symbol_queue(10) <= "11000"; -- when "001111" => symbol_queue(10) <= "11000"; -- when "010000" => symbol_queue(10) <= "11000"; -- when "010001" => symbol_queue(10) <= "11000"; -- Data Island (8-15) -- when "010010" => symbol_queue(10) <= "11000"; -- when "010011" => symbol_queue(10) <= "11000"; -- when "010100" => symbol_queue(10) <= "11000"; -- when "010101" => symbol_queue(10) <= "11000"; -- when "010110" => symbol_queue(10) <= "11000"; -- when "010111" => symbol_queue(10) <= "11000"; -- when "011000" => symbol_queue(10) <= "11000"; -- when "011001" => symbol_queue(10) <= "11000"; -- Data Island (16-23) -- when "011010" => symbol_queue(10) <= "11000"; -- when "011011" => symbol_queue(10) <= "11000"; -- when "011100" => symbol_queue(10) <= "11000"; -- when "011101" => symbol_queue(10) <= "11000"; -- when "011110" => symbol_queue(10) <= "11000"; -- when "011111" => symbol_queue(10) <= "11000"; -- when "100000" => symbol_queue(10) <= "11000"; -- when "100001" => symbol_queue(10) <= "11000"; -- Data Island (24-31) -- when "100010" => symbol_queue(10) <= "11000"; -- when "100011" => symbol_queue(10) <= "11000"; -- when "100100" => symbol_queue(10) <= "11000"; -- when "100101" => symbol_queue(10) <= "11000"; -- when "100110" => symbol_queue(10) <= "11000"; -- when "100111" => symbol_queue(10) <= "11000"; -- when "101000" => symbol_queue(10) <= "11000"; -- when "101001" => symbol_queue(10) <= "11000"; -- Trailing guard band when "101010" => symbol_queue(10) <= "01101"; -- Data island Guard Band when "101011" => symbol_queue(10) <= "01101"; -- Data island Guard Band -- There has to be four CTL symbols before the next block of video our data, -- But that won't be a problem for us, we will have the rest of the vertical -- Blanking interval when others => symbol_queue(10) <= "010" & Vsync & Hsync; end case; symbol_queue(0 to 9) <= symbol_queue(1 to 10); end if; if data_island_index /= "111111" then data_island_index <= data_island_index + 1; end if; -- If we see the rising edge of vsync we need to send -- a data island the next time we see the hsync signal -- drop. if last_vsync = '0' and vsync = '1' then data_island_armed <= '1'; end if; if data_island_armed = '1' and last_hsync = '1' and hsync = '0' then data_island_index <= (others => '0'); data_island_armed <= '0'; end if; last_blank <= blank; last_hsync <= hsync; last_vsync <= vsync; end if; end process; end Behavioral; ================================================ FILE: test_bench/hdmi_test_generator/serializers.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Convert 3x 10-bit symbols to three serial channels and the clock channel. -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; library UNISIM; use UNISIM.VComponents.all; entity serializers is Port ( clk : in STD_LOGIC; c0 : in STD_LOGIC_VECTOR (9 downto 0); c1 : in STD_LOGIC_VECTOR (9 downto 0); c2 : in STD_LOGIC_VECTOR (9 downto 0); hdmi_p : out STD_LOGIC_VECTOR (3 downto 0); hdmi_n : out STD_LOGIC_VECTOR (3 downto 0)); end serializers; architecture Behavioral of serializers is -- For holding the outward bound TMDS symbols in the slow and fast domain signal c0_high_speed : std_logic_vector(9 downto 0) := (others => '0'); signal c1_high_speed : std_logic_vector(9 downto 0) := (others => '0'); signal c2_high_speed : std_logic_vector(9 downto 0) := (others => '0'); signal clk_high_speed : std_logic_vector(9 downto 0) := (others => '0'); signal c2_output_bits : std_logic_vector(1 downto 0) := "00"; signal c1_output_bits : std_logic_vector(1 downto 0) := "00"; signal c0_output_bits : std_logic_vector(1 downto 0) := "00"; signal clk_output_bits : std_logic_vector(1 downto 0) := "00"; -- Controlling the transfers into the high speed domain signal latch_high_speed : std_logic_vector(4 downto 0) := "00001"; -- From the DDR outputs to the output buffers signal c0_serial, c1_serial, c2_serial, clk_serial : std_logic; -- For generating the x5 clocks signal clk_x5, clk_x5_n, clk_x5_unbuffered : std_logic; signal clk_feedback : std_logic; -- To glue the HSYNC and VSYNC into the control character. signal syncs : std_logic_vector(1 downto 0); begin process(clk_x5) begin --------------------------------------------------------------- -- Now take the 10-bit words and take it into the high-speed -- clock domain once every five cycles. -- -- Then send out two bits every clock cycle using DDR output -- registers. --------------------------------------------------------------- if rising_edge(clk_x5) then c0_output_bits <= c0_high_speed(1 downto 0); c1_output_bits <= c1_high_speed(1 downto 0); c2_output_bits <= c2_high_speed(1 downto 0); clk_output_bits <= clk_high_speed(1 downto 0); if latch_high_speed(0) = '1' then c0_high_speed <= c0; c1_high_speed <= c1; c2_high_speed <= c2; clk_high_speed <= "0000011111"; else c0_high_speed <= "00" & c0_high_speed(9 downto 2); c1_high_speed <= "00" & c1_high_speed(9 downto 2); c2_high_speed <= "00" & c2_high_speed(9 downto 2); clk_high_speed <= "00" & clk_high_speed(9 downto 2); end if; latch_high_speed <= latch_high_speed(0) & latch_high_speed(4 downto 1); end if; end process; ------------------------------------------------------------------ -- Convert the TMDS codes into a serial stream, two bits at a time ------------------------------------------------------------------ clk_x5_n <= not clk_x5; c0_to_serial: ODDR2 generic map(DDR_ALIGNMENT => "C0", INIT => '0', SRTYPE => "ASYNC") port map (C0 => clk_x5, C1 => clk_x5_n, CE => '1', R => '0', S => '0', D0 => C0_output_bits(0), D1 => C0_output_bits(1), Q => c0_serial); OBUFDS_c0 : OBUFDS port map ( O => hdmi_p(0), OB => hdmi_n(0), I => c0_serial); c1_to_serial: ODDR2 generic map(DDR_ALIGNMENT => "C0", INIT => '0', SRTYPE => "ASYNC") port map (C0 => clk_x5, C1 => clk_x5_n, CE => '1', R => '0', S => '0', D0 => C1_output_bits(0), D1 => C1_output_bits(1), Q => c1_serial); OBUFDS_c1 : OBUFDS port map ( O => hdmi_p(1), OB => hdmi_n(1), I => c1_serial); c2_to_serial: ODDR2 generic map(DDR_ALIGNMENT => "C0", INIT => '0', SRTYPE => "ASYNC") port map (C0 => clk_x5, C1 => clk_x5_n, CE => '1', R => '0', S => '0', D0 => C2_output_bits(0), D1 => C2_output_bits(1), Q => c2_serial); OBUFDS_c2 : OBUFDS port map ( O => hdmi_p(2), OB => hdmi_n(2), I => c2_serial); clk_to_serial: ODDR2 generic map(DDR_ALIGNMENT => "C0", INIT => '0', SRTYPE => "ASYNC") port map (C0 => clk_x5, C1 => clk_x5_n, CE => '1', R => '0', S => '0', D0 => Clk_output_bits(0), D1 => Clk_output_bits(1), Q => clk_serial); OBUFDS_clk : OBUFDS port map ( O => hdmi_p(3), OB => hdmi_n(3), I => clk_serial); ------------------------------------------------------------------ -- Use a PLL to generate a x5 clock, which is used to drive -- the DDR registers.This allows 10 bits to be sent for every -- pixel clock ------------------------------------------------------------------ PLL_BASE_inst : PLL_BASE generic map ( CLKFBOUT_MULT => 10, CLKOUT0_DIVIDE => 2, CLKOUT0_PHASE => 0.0, -- Output 5x original frequency CLK_FEEDBACK => "CLKFBOUT", CLKIN_PERIOD => 13.33, DIVCLK_DIVIDE => 1 ) port map ( CLKFBOUT => clk_feedback, CLKOUT0 => clk_x5_unbuffered, CLKFBIN => clk_feedback, CLKIN => clk, RST => '0' ); BUFG_pclkx5 : BUFG port map ( I => clk_x5_unbuffered, O => clk_x5); end Behavioral; ================================================ FILE: test_bench/hdmi_test_generator/vga_clocking.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field 16, CLKOUT0_DIVIDE => 20, CLKOUT0_PHASE => 0.0, -- Output pixel clock, 1.5x original frequency CLK_FEEDBACK => "CLKFBOUT", -- Clock source to drive CLKFBIN ("CLKFBOUT" or "CLKOUT0") CLKIN_PERIOD => 20.0, -- IMPORTANT! 20.00 => 50MHz DIVCLK_DIVIDE => 1 -- Division value for all output clocks (1-52) ) port map ( CLKFBOUT => clk_feedback, CLKOUT0 => clock_x1_unbuffered, CLKOUT1 => open, CLKOUT2 => open, CLKOUT3 => open, CLKOUT4 => open, CLKOUT5 => open, LOCKED => pll_locked, CLKFBIN => clk_feedback, CLKIN => clk50_buffered, RST => '0' -- 1-bit input: Reset input ); BUFG_clk : BUFG port map ( I => clk50, O => clk50_buffered); BUFG_pclock : BUFG port map ( I => clock_x1_unbuffered, O => clock_x1); end Behavioral; ================================================ FILE: test_bench/hdmi_test_generator/vga_gen.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Description: Generates a test 1280x720 signal -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity vga_gen is Port ( clk50 : in STD_LOGIC; pixel_clock : out std_logic; red_p : out STD_LOGIC_VECTOR (7 downto 0) := (others => '0'); green_p : out STD_LOGIC_VECTOR (7 downto 0) := (others => '0'); blue_p : out STD_LOGIC_VECTOR (7 downto 0) := (others => '0'); blank : out STD_LOGIC := '0'; hsync : out STD_LOGIC := '0'; vsync : out STD_LOGIC := '0'); end vga_gen; architecture Behavioral of vga_gen is COMPONENT vga_clocking PORT( clk50 : IN std_logic; pixel_clock : OUT std_logic); END COMPONENT; constant h_rez : natural := 800; constant h_sync_start : natural := 800+40; constant h_sync_end : natural := 800+40+128; constant h_max : natural := 1056; signal h_count : unsigned(11 downto 0) := (others => '0'); signal h_offset : unsigned(7 downto 0) := (others => '0'); constant v_rez : natural := 600; constant v_sync_start : natural := 600+1; constant v_sync_end : natural := 600+1+4; constant v_max : natural := 628; signal v_count : unsigned(11 downto 0) := x"250"; signal v_offset : unsigned(7 downto 0) := (others => '0'); signal clk40 : std_logic; begin Inst_clocking: vga_clocking PORT MAP( clk50 => clk50, pixel_clock => clk40 ); pixel_clock <= clk40; process(clk40) begin if rising_edge(clk40) then if h_count < h_rez and v_count < v_rez then red_p <= std_logic_vector(h_count(7 downto 0)+h_offset); green_p <= std_logic_vector(v_count(7 downto 0)+v_offset); blue_p <= std_logic_vector(h_count(7 downto 0)+v_count(7 downto 0)); blank <= '0'; if h_count = 0 or h_count = h_rez-1 then red_p <= (others => '1'); green_p <= (others => '1'); blue_p <= (others => '1'); end if; if v_count = 0 or v_count = v_rez-1 then red_p <= (others => '1'); green_p <= (others => '0'); blue_p <= (others => '0'); end if; else red_p <= (others => '0'); green_p <= (others => '0'); blue_p <= (others => '0'); blank <= '1'; end if; if h_count >= h_sync_start and h_count < h_sync_end then hsync <= '1'; else hsync <= '0'; end if; if v_count >= v_sync_start and v_count < v_sync_end then vsync <= '1'; else vsync <= '0'; end if; if h_count = h_max then h_count <= (others => '0'); if v_count = v_max then h_offset <= h_offset + 1; v_offset <= v_offset + 1; v_count <= (others => '0'); else v_count <= v_count+1; end if; else h_count <= h_count+1; end if; end if; end process; end Behavioral; ================================================ FILE: test_bench/tb_audio_to_db.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: tb_audio_to_db - Behavioral -- -- Description: A testbench for the audio sample to db level calculation -- ---------------------------------------------------------------------------------- -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ---------------------------------------------------------------------------------- ----- Want to say thanks? -------------------------------------------------------- ---------------------------------------------------------------------------------- -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) ------------------------------------------------------------------------------------ library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; entity tb_audio_to_db is end tb_audio_to_db; architecture Behavioral of tb_audio_to_db is component audio_to_db is Port ( clk : in STD_LOGIC; in_channel : in STD_LOGIC_VECTOR (2 downto 0); in_de : in STD_LOGIC; in_sample : in STD_LOGIC_VECTOR (23 downto 0); out_channel : out STD_LOGIC_VECTOR (2 downto 0); out_de : out STD_LOGIC; out_level : out STD_LOGIC_VECTOR (5 downto 0)); end component; signal clk : STD_LOGIC := '0'; signal in_channel : STD_LOGIC_VECTOR (2 downto 0) := (others => '0'); signal in_de : STD_LOGIC := '1'; signal in_sample : STD_LOGIC_VECTOR (23 downto 0) := (others => '0'); signal out_channel : STD_LOGIC_VECTOR (2 downto 0); signal out_de : STD_LOGIC; signal out_level : STD_LOGIC_VECTOR (5 downto 0); begin process begin wait for 5 ns; clk <= '1'; wait for 5 ns; clk <= '0'; end process; process begin wait until rising_edge(clk); in_de <= '1'; in_sample <= in_sample(in_sample'high-1 downto 0) & not in_sample(in_sample'high); wait until rising_edge(clk); in_de <= '0'; wait until rising_edge(clk); wait until rising_edge(clk); wait until rising_edge(clk); wait until rising_edge(clk); end process; uut: audio_to_db port map ( clk => clk, in_channel => in_channel, in_de => in_de, in_sample => in_sample, out_channel => out_channel, out_de => out_de, out_level => out_level); end Behavioral; ================================================ FILE: test_bench/tb_convert_yCbCr_to_RGB.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Description: A testbench for YCbCr to RGB decoding -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ------------------------------------------------------------------------------------ ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values --use IEEE.NUMERIC_STD.ALL; -- Uncomment the following library declaration if instantiating -- any Xilinx leaf cells in this code. --library UNISIM; --use UNISIM.VComponents.all; entity tb_convert_yCbCr_to_RGB is end tb_convert_yCbCr_to_RGB; architecture Behavioral of tb_convert_yCbCr_to_RGB is component conversion_YCbCr_to_RGB is port ( clk : in std_Logic; input_is_YCbCr : in std_Logic; ------------------------ in_blank : in std_logic; in_hsync : in std_logic; in_vsync : in std_logic; in_U : in std_logic_vector(11 downto 0); -- B or Cb in_V : in std_logic_vector(11 downto 0); -- G or Y in_W : in std_logic_vector(11 downto 0); -- R or Cr ------------------------ out_blank : out std_logic; out_hsync : out std_logic; out_vsync : out std_logic; out_R : out std_logic_vector(11 downto 0); out_G : out std_logic_vector(11 downto 0); out_B : out std_logic_vector(11 downto 0)); end component; signal clk : std_Logic := '0'; signal input_is_YCbCr : std_Logic := '0'; signal in_blank : std_logic := '0'; signal in_hsync : std_logic := '0'; signal in_vsync : std_logic := '0'; signal in_U : std_logic_vector(11 downto 0) := x"800"; -- B or Cb signal in_V : std_logic_vector(11 downto 0) := x"800"; -- G or Y signal in_W : std_logic_vector(11 downto 0) := x"800"; -- R or Cr signal out_blank : std_logic := '0'; signal out_hsync : std_logic := '0'; signal out_vsync : std_logic := '0'; signal out_R : std_logic_vector(11 downto 0); signal out_G : std_logic_vector(11 downto 0); signal out_B : std_logic_vector(11 downto 0); begin process begin wait for 5 ns; clk <= not clk; end process; stim: process begin wait for 100 ns; in_U <= x"100"; wait for 100 ns; in_U <= x"EFF"; wait for 100 ns; in_U <= x"800"; wait for 100 ns; in_V <= x"100"; wait for 100 ns; in_V <= x"EFF"; wait for 100 ns; in_V <= x"800"; wait for 100 ns; in_W <= x"100"; wait for 100 ns; in_W <= x"EFF"; wait for 100 ns; in_W <= x"800"; end process; uut: conversion_YCbCr_to_RGB port map ( clk => clk, input_is_YCbCr => '1', ------------------------ in_blank => in_blank, in_hsync => in_hsync, in_vsync => in_vsync, in_U => in_U, in_V => in_V, in_W => in_W, ------------------------ out_blank => out_blank, out_hsync => out_hsync, out_vsync => out_vsync, out_R => out_R, out_G => out_G, out_B => out_B); end Behavioral; ================================================ FILE: test_bench/tb_hdmi_decode.vhd ================================================ ---------------------------------------------------------------------------------- -- Engineer: Mike Field -- -- Module Name: tb_hdmi_decode - Behavioral -- -- Description: A testbench for testing HDMI decoding -- ------------------------------------------------------------------------------------ -- The MIT License (MIT) -- -- Copyright (c) 2015 Michael Alan Field -- -- Permission is hereby granted, free of charge, to any person obtaining a copy -- of this software and associated documentation files (the "Software"), to deal -- in the Software without restriction, including without limitation the rights -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -- copies of the Software, and to permit persons to whom the Software is -- furnished to do so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in -- all copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -- THE SOFTWARE. ---------------------------------------------------------------------------------- ----- Want to say thanks? ---------------------------------------------------------- ------------------------------------------------------------------------------------ -- -- This design has taken many hours - with the industry metric of 30 lines -- per day, it is equivalent to about 6 months of work. I'm more than happy -- to share it if you can make use of it. It is released under the MIT license, -- so you are not under any onus to say thanks, but.... -- -- If you what to say thanks for this design how about trying PayPal? -- Educational use - Enough for a beer -- Hobbyist use - Enough for a pizza -- Research use - Enough to take the family out to dinner -- Commercial use - A weeks pay for an engineer (I wish!) ------------------------------------------------------------------------------------ library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity tb_hdmi_decode is end tb_hdmi_decode; architecture Behavioral of tb_hdmi_decode is component hdmi_design is Port ( clk100 : in STD_LOGIC; -- Control signals led : out std_logic_vector(7 downto 0); sw : in std_logic_vector(7 downto 0) :=(others => '0'); debug_pmod : out std_logic_vector(7 downto 0) :=(others => '0'); --HDMI input signals hdmi_rx_cec : inout std_logic; hdmi_rx_hpa : out std_logic; hdmi_rx_scl : in std_logic; hdmi_rx_sda : inout std_logic; hdmi_rx_txen : out std_logic; hdmi_rx_clk_n : in std_logic; hdmi_rx_clk_p : in std_logic; hdmi_rx_n : in std_logic_vector(2 downto 0); hdmi_rx_p : in std_logic_vector(2 downto 0); --- HDMI out hdmi_tx_cec : inout std_logic; hdmi_tx_clk_n : out std_logic; hdmi_tx_clk_p : out std_logic; hdmi_tx_hpd : in std_logic; hdmi_tx_rscl : inout std_logic; hdmi_tx_rsda : inout std_logic; hdmi_tx_p : out std_logic_vector(2 downto 0); hdmi_tx_n : out std_logic_vector(2 downto 0); -- For dumping symbols rs232_tx : out std_logic ); end component; component hdmi_output_test is Port ( clk50 : in STD_LOGIC; hdmi_out_p : out STD_LOGIC_VECTOR(3 downto 0); hdmi_out_n : out STD_LOGIC_VECTOR(3 downto 0); leds : out std_logic_vector(7 downto 0)); end component; signal clk : std_logic := '0'; signal clk50 : std_logic := '1'; signal led : std_logic_vector(7 downto 0); signal hdmi_rx_cec : std_logic; signal hdmi_rx_hpa : std_logic; signal hdmi_rx_scl : std_logic; signal hdmi_rx_sda : std_logic; signal hdmi_rx_txen : std_logic; signal hdmi_rx_clk_n : std_logic; signal hdmi_rx_clk_p : std_logic; signal hdmi2_rx_clk_n : std_logic := '1'; signal hdmi2_rx_clk_p : std_logic := '0'; signal hdmi_out_n : std_logic_vector(3 downto 0); signal hdmi_out_p : std_logic_vector(3 downto 0); signal hdmi_rx_n : std_logic_vector(2 downto 0); signal hdmi_rx_p : std_logic_vector(2 downto 0); signal hdmi_tx_cec : std_logic; signal hdmi_tx_clk_n : std_logic; signal hdmi_tx_clk_p : std_logic; signal hdmi_tx_hpd : std_logic; signal hdmi_tx_rscl : std_logic; signal hdmi_tx_rsda : std_logic; signal hdmi_tx_p : std_logic_vector(2 downto 0); signal hdmi_tx_n : std_logic_vector(2 downto 0); signal sdat_drive : std_logic := '1'; signal rs232_tx : std_logic := '1'; begin hdmi_rx_sda <= '0' when sdat_drive = '0' else 'H'; hdmi_rx_p <= transport hdmi_out_p(2 downto 0) after 5.00 ns; hdmi_rx_n <= transport hdmi_out_n(2 downto 0) after 5.00 ns; hdmi_rx_clk_p <= transport hdmi_out_p(3) after 1.25 ns; hdmi_rx_clk_n <= transport hdmi_out_n(3) after 1.25 ns; clk_proc: process begin wait for 7.0 ns; while 1 = 1 loop wait for 5.0 ns; clk <= not clk; end loop; end process; clk50_proc: process begin wait for 7.0 ns; while 1 = 1 loop wait for 5.0 ns; clk50 <= not clk50; end loop; end process; i_gen_signal: hdmi_output_test port map ( clk50 => clk50, hdmi_out_p => hdmi_out_p, hdmi_out_n => hdmi_out_n, leds => open); uut: hdmi_design Port map ( clk100 => clk, led => open, sw => (others => '0'), debug_pmod => open, --HDMI in hdmi_rx_cec => hdmi_rx_cec, hdmi_rx_hpa => hdmi_rx_hpa, hdmi_rx_scl => hdmi_rx_scl, hdmi_rx_sda => hdmi_rx_sda, hdmi_rx_txen => hdmi_rx_txen, hdmi_rx_clk_n => hdmi_rx_clk_n, hdmi_rx_clk_p => hdmi_rx_clk_p, hdmi_rx_n => hdmi_rx_n, hdmi_rx_p => hdmi_rx_p, --- HDMI out hdmi_tx_cec => hdmi_tx_cec, hdmi_tx_clk_n => hdmi_tx_clk_n, hdmi_tx_clk_p => hdmi_tx_clk_p, hdmi_tx_hpd => hdmi_tx_hpd, hdmi_tx_rscl => hdmi_tx_rscl, hdmi_tx_rsda => hdmi_tx_rsda, hdmi_tx_p => hdmi_tx_p, hdmi_tx_n => hdmi_tx_n, rs232_tx => rs232_tx ); edid_test_proc: process begin hdmi_rx_scl <= '1'; wait for 1 us; -- START condition sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- DEVICE ADDRESS FOR WRITE -- dev bit 7 sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 6 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 6 sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 4 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 3 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 2 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 1 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 0 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- Slave ACK -- Device to ack sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- SEND WRITE ADDRESS -- addr bit 7 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 6 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 6 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 4 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 3 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 2 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 1 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- addr bit 0 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- Slave ACK sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- repeated START condition sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- DEVICE ADDRESS / READ - -- dev bit 7 sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 6 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 6 sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 4 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 3 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 2 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 1 sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- dev bit 0 - READ! sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- ACK???? -- Device to ack sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; for i in 1 to 127 loop -- READ First byte -- read bit 7 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 6 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 6 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 4 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 3 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 2 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 1 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 0 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; sdat_drive <= '1'; -- Host to ack sdat_drive <= '0'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; sdat_drive <= '1'; end loop; -- READ Second -- read bit 7 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 6 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 6 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 4 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 3 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 2 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 1 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; -- read bit 0 wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; sdat_drive <= '1'; -- Master NACK sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 400 ns; hdmi_rx_scl <= '0'; wait for 200 ns; sdat_drive <= '1'; -- STOP sdat_drive <= '1'; wait for 200 ns; hdmi_rx_scl <= '1'; wait for 200 ns; wait; end process; end Behavioral;