hdmi/encoder.vhd

201 lines
7.2 KiB
VHDL

-- -----------------------------------------------------------------------------
-- Copyright (c) 2013 Benjamin Krill <benjamin@krll.de>
--
-- 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.
-- -----------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.dvi_package.all;
library UNISIM;
use UNISIM.Vcomponents.all;
entity encoder is
port (
clk : in std_logic;
rst_n : in std_logic;
data_i : in std_logic_vector(7 downto 0);
c0 : in std_logic;
c1 : in std_logic;
de : in std_logic;
data_o : out std_logic_vector(9 downto 0)
);
end encoder;
architecture encoder of encoder is
signal n1d : unsigned(3 downto 0);
signal data_iq : std_logic_vector(7 downto 0);
signal decision1 : std_logic;
signal q_m : std_logic_vector(8 downto 0);
signal n0q_m : unsigned(3 downto 0); -- number of 1s and 0s for q_m
signal n1q_m : unsigned(3 downto 0); -- number of 1s and 0s for q_m
signal n1q_i : unsigned(3 downto 0); -- number of 1s and 0s for q_m
signal cnt : unsigned(4 downto 0); -- disparity counter, MSB is the sign bit
signal decision2 : std_logic;
signal decision3 : std_logic;
type usigned_t is array(natural range <>) of unsigned(3 downto 0);
signal data_iu : usigned_t(7 downto 0);
signal q_mu : usigned_t(8 downto 0);
signal de_q, de_reg : std_logic;
signal c0_q, c1_q : std_logic;
signal c0_reg, c1_reg : std_logic;
signal c1c0 : std_logic_vector(1 downto 0);
signal q_m_reg : std_logic_vector(8 downto 0);
signal data_oq : std_logic_vector(9 downto 0);
begin
-- ----------------------------------------------------------
-- Counting number of 1s and 0s for each incoming pixel
-- component. Pipe line the result.
-- Register Data Input so it matches the pipe lined adder
-- output
-- ----------------------------------------------------------
tounsigned0: for I in 0 to 7 generate
data_iu(I)(3 downto 1) <= "000";
data_iu(I)(0 downto 0) <= unsigned(data_i(I downto I));
end generate;
process (clk, rst_n)
begin
if rst_n = '0' then
n1d <= (others => '0');
data_iq <= (others => '0');
elsif rising_edge(clk) then
n1d <= data_iu(0) + data_iu(1) + data_iu(2) + data_iu(3)
+ data_iu(4) + data_iu(5) + data_iu(6) + data_iu(7);
data_iq <= data_i;
end if;
end process;
-- ----------------------------------------------------------
-- Stage 1: 8 bit -> 9 bit
-- Refer to DVI 1.0 Specification, page 29, Figure 3-5
-- ----------------------------------------------------------
decision1 <= '1' when n1d > x"4" or (n1d = x"4" and data_iq(0) = '0') else '0';
q_m(0) <= data_iq(0);
q_m(1) <= (q_m(0) xnor data_iq(1)) when decision1 = '1' else q_m(0) xor data_iq(1);
q_m(2) <= (q_m(1) xnor data_iq(2)) when decision1 = '1' else q_m(1) xor data_iq(2);
q_m(3) <= (q_m(2) xnor data_iq(3)) when decision1 = '1' else q_m(2) xor data_iq(3);
q_m(4) <= (q_m(3) xnor data_iq(4)) when decision1 = '1' else q_m(3) xor data_iq(4);
q_m(5) <= (q_m(4) xnor data_iq(5)) when decision1 = '1' else q_m(4) xor data_iq(5);
q_m(6) <= (q_m(5) xnor data_iq(6)) when decision1 = '1' else q_m(5) xor data_iq(6);
q_m(7) <= (q_m(6) xnor data_iq(7)) when decision1 = '1' else q_m(6) xor data_iq(7);
q_m(8) <= '0' when decision1 = '1' else '1';
-- ----------------------------------------------------------
-- Stage 2: 9 bit -> 10 bit
-- Refer to DVI 1.0 Specification, page 29, Figure 3-5
-- ----------------------------------------------------------
tounsigned1: for I in 0 to 8 generate
q_mu(I)(3 downto 1) <= "000";
q_mu(I)(0 downto 0) <= unsigned(q_m(I downto I));
end generate;
n1q_i <= q_mu(0) + q_mu(1) + q_mu(2) + q_mu(3) + q_mu(4) + q_mu(5) + q_mu(6) + q_mu(7);
process (clk, rst_n)
begin
if rst_n = '0' then
n1q_m <= (others => '0');
n0q_m <= (others => '0');
elsif rising_edge(clk) then
n1q_m <= n1q_i;
n0q_m <= x"8" - n1q_i;
end if;
end process;
decision2 <= '1' when cnt = "00000" or n1q_m = n0q_m else '0';
-- ----------------------------------------------------------
-- [(cnt > 0) and (N1q_m > N0q_m)] or [(cnt < 0) and (N0q_m > N1q_m)]
-- ----------------------------------------------------------
decision3 <= '1' when (cnt(4) = '0' and n1q_m > n0q_m) or (cnt(4) = '1' and n0q_m > n1q_m) else '0';
-- --------------------------
-- pipe line alignment
-- --------------------------
process (clk, rst_n)
begin
if rst_n = '0' then
de_q <= '0';
de_reg <= '0';
c0_q <= '0';
c0_reg <= '0';
c1_q <= '0';
c1_reg <= '0';
q_m_reg <= (others => '0');
elsif rising_edge(clk) then
de_q <= de;
de_reg <= de_q;
c0_q <= c0;
c0_reg <= c0_q;
c1_q <= c1;
c1_reg <= c1_q;
q_m_reg <= q_m;
end if;
end process;
-- --------------------------
-- 10-bit out
-- disparity counter
-- --------------------------
process (clk, rst_n)
begin
if rst_n = '0' then
data_oq <= (others => '0');
cnt <= (others => '0');
elsif rising_edge(clk) then
if de_reg = '1' then
if decision2 = '1' then
data_oq(9) <= not q_m_reg(8);
data_oq(8) <= q_m_reg(8);
if q_m_reg(8) = '1' then
data_oq(7 downto 0) <= q_m_reg(7 downto 0);
cnt <= cnt + n1q_m - n0q_m;
else
data_oq(7 downto 0) <= not q_m_reg(7 downto 0);
cnt <= cnt + n0q_m - n1q_m;
end if;
elsif decision3 = '1' then
data_oq(9) <= '1';
data_oq(8) <= q_m_reg(8);
data_oq(7 downto 0) <= not q_m_reg(7 downto 0);
cnt <= cnt + (q_m_reg(8) & '0') + (n0q_m - n1q_m);
else
data_oq(9) <= '0';
data_oq(8) <= q_m_reg(8);
data_oq(7 downto 0) <= q_m_reg(7 downto 0);
cnt <= cnt - (not q_m_reg(8) & '0') + (n1q_m - n0q_m);
end if;
else
case c1c0 is
when "00" => data_oq <= CTRLTOKEN0;
when "01" => data_oq <= CTRLTOKEN1;
when "10" => data_oq <= CTRLTOKEN2;
when others => data_oq <= CTRLTOKEN3;
end case;
cnt <= (others => '0');
end if;
end if;
end process;
c1c0 <= c1_reg & c0_reg;
data_o <= data_oq;
end encoder;