414 lines
19 KiB
VHDL
414 lines
19 KiB
VHDL
----------------------------------------------------------------------------------
|
|
-- Engineer: Mike Field <hasmter@snap.net.nz>
|
|
--
|
|
-- 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;
|