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;