-- Company: BUSE
-- ENgineer: PAVEL SUNKA
-- 
-- Create Date:   26.3.2017
-- Module Name:   RGB_driver 
-- Project Name:  RGB PANEL
-- Target Devices: 10M08
-----------------------------         ----------------------------
-- Description: RGB driver -------- chybna adresace------
-----------------------------         ----------------------------
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_signed.all;
--	use IEEE.std_logic_signed.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

--use IEEE.math_real.all;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity RGB_driver is
	Port(
		ARST          : in  STD_LOGIC;
		CLK           : in  std_logic;
		RGB1A_i       : in  std_logic_vector(15 downto 0);
		RGB2A_i       : in  std_logic_vector(15 downto 0);
		BRIGHT        : in  std_logic_vector(7 downto 0);
		TEST_SIZE     : in  std_logic;
		TEST_PIN_ROW  : in  std_logic;
		TEST_PIN_COL  : in  std_logic;
		SIZE_COL      : out std_logic_vector(7 downto 0);
		SIZE_ROW      : out std_logic_vector(4 downto 0);
		TEST_SIZE_END : out std_logic;
		SNAP_END      : out std_logic;
		ADR1_R        : out std_logic_vector(12 downto 0);
		ADR2_R        : out std_logic_vector(12 downto 0);
		G1A_OUT       : out std_logic;
		G2A_OUT       : out std_logic;
		R1A_OUT       : out std_logic;
		R2A_OUT       : out std_logic;
		B1A_OUT       : out std_logic;
		B2A_OUT       : out std_logic;
		LATCH         : out std_logic;
		ABC           : out std_logic_vector(3 downto 0);
		EN_OUT        : out std_logic;
		CLK_OUT       : out std_logic
	);
end RGB_driver;

architecture Behavioral of RGB_driver is

	constant f_on  : std_logic := '1';
	constant f_off : std_logic := '0';
	--constant col_size : std_logic_vector(8 downto 0) := "100000000"; --256

	-- multiplexer vystupnich dat  
	component rgb_mux
		port(
			ARST      : in  STD_LOGIC;
			CLK       : in  std_logic;
			RGB1_I    : in  std_logic_vector(17 downto 0);
			RGB2_I    : in  std_logic_vector(17 downto 0);
			SEL       : in  std_logic_vector(5 downto 0);
			RGB1_O    : out std_logic_vector(2 downto 0);
			RGB2_O    : out std_logic_vector(2 downto 0);
			RGB1_OLAT : out std_logic_vector(2 downto 0);
			RGB2_OLAT : out std_logic_vector(2 downto 0)
		);
	end component rgb_mux;

	--gama korekce--
	component gama
		port(
			Rgb1_I : in  std_logic_vector(15 downto 0);
			Rgb2_I : in  std_logic_vector(15 downto 0);
			Rgb1   : out std_logic_vector(17 downto 0);
			Rgb2   : out std_logic_vector(17 downto 0)
		);
	end component gama;

	--posuvny registr
	component shift_reg_ren
		generic(size : integer);
		port(
			CLK   : in  std_logic;
			ARST  : in  std_logic;
			CEN   : in  std_logic;
			DAT_I : in  std_logic;
			DAT_O : out std_logic_vector(size - 1 downto 0)
		);
	end component shift_reg_ren;

	-- -- citac s enablem-------------------
	component cnt_ren_stopval1
		generic(stop_b : natural);
		port(
			CLK      : in  std_logic;
			STOP_VAL : in  std_logic_vector(stop_b downto 0);
			EN       : in  std_logic;
			DATA_OUT : out std_logic_vector(stop_b downto 0)
		);
	end component cnt_ren_stopval1;

	-- odcitacka se synchronnim resetem
	component sub_ren_srst
		generic(STOP_BIT : natural);
		port(
			SRST  : in  std_logic;
			CLK   : in  std_logic;
			START : in  std_logic_vector(stop_bit downto 0);
			EN    : in  std_logic;
			DATA  : out std_logic_vector(stop_bit downto 0)
		);
	end component sub_ren_srst;

	-- D pamet 
	component D_ren
		generic(STOP_BITS : natural);
		port(
			ARST : in  STD_LOGIC;
			CLK  : in  stD_loGic;
			EN   : in  stD_loGic;
			D    : in  STD_LOGIC_VECTOR(STOP_BITS Downto 0);
			Q    : out STD_LOGIC_VECTOR(STOP_BITS Downto 0)
		);
	end component D_ren;

	-- posuvny registr vytvarejici pulz 2
	component sh_reg_2
		port(
			CLK  : in  std_logic;
			SRST : in  std_logic;
			DI   : in  std_logic;
			DO   : out std_logic_vector(1 downto 0)
		);
	end component sh_reg_2;

	-- comparator counteru a enable out
	component AlesB_14b
		port(
			DATAA : IN  STD_LOGIC_VECTOR(13 DOWNTO 0);
			DATAB : IN  STD_LOGIC_VECTOR(13 DOWNTO 0);
			ALB   : OUT STD_LOGIC
		);
	end component AlesB_14b;

	--nasobicka pro jas
	component mult9bx6b
		port(
			DATAA  : IN  STD_LOGIC_VECTOR(8 DOWNTO 0);
			DATAB  : IN  STD_LOGIC_VECTOR(5 DOWNTO 0);
			RESULT : OUT STD_LOGIC_VECTOR(14 DOWNTO 0)
		);
	end component mult9bx6b;
	--nasobicka pro adresu
	component mult9bX4b
		port(
			DATAA  : IN  STD_LOGIC_VECTOR(8 DOWNTO 0);
			DATAB  : IN  STD_LOGIC_VECTOR(3 DOWNTO 0);
			RESULT : OUT STD_LOGIC_VECTOR(12 DOWNTO 0)
		);
	end component mult9bX4b;

	component BCM_dynam
		port(
			ARST        : in  STD_LOGIC;
			CLK         : in  std_logic;
			WEREN       : in  std_logic;
			NEW_TEST    : in  std_logic;
			FIRST       : in  std_logic;
			RGB1        : in  std_logic_vector(17 downto 0);
			RGB2        : in  std_logic_vector(17 downto 0);
			WRITE_BIT1  : IN  std_logic_vector(2 downto 0);
			WRITE_BIT2  : IN  std_logic_vector(2 downto 0);
			END_ROW     : out std_logic;
			ACTUAL_BCMO : out std_logic_vector(5 downto 0);
			NEXT_BCMO   : out std_logic_vector(5 downto 0)
		);
	end component BCM_dynam;

	-- ucol

	signal rst_col     : std_logic;     --reset odcitacky sloupcu
	--signal en_subt_col : std_logic;     -- enable citace sloupcu
	signal col_start   : std_logic_vector(13 downto 0) := (others => '1'); -- zacatek odcitacky po reset
	signal col_start_h : std_logic_vector(13 downto 0); -- zacatek odcitacky po reset pomocna

	signal col      : std_logic_vector(13 downto 0) := (others => '0'); --vystup z odcitacky sloupcu
	signal col_zero : std_logic;        -- jsou-li sloupce v 0 vyhodi jednicku

	signal colh : std_logic_vector(13 downto 0); --pomocna col zvetsena o 0 v predu

	-- uCnt_ROW
	signal cnt_row_start : std_logic;   -- nastupna hrana pro  citac radku
	signal rst_row       : std_logic;
	signal en_cnt_row    : std_logic;   -- povoleni citace radku
	signal row           : std_logic_vector(3 downto 0) := (others => '0'); -- vystup citace radku
	signal en_buf_row    : std_logic;   -- enable nabuferovani dalsiho radku  
	signal abc_h         : std_logic_vector(3 downto 0); --pomocny signal pro vystup abc

	signal row_mult : std_logic_vector(12 downto 0); -- vysledek nasobeni radku fyzickym poctem sloupcu

	-- latence 
	signal rst_pulse : std_logic;       -- resetovani pulzu (nastu)
	signal pulse     : std_logic_vector(1 downto 0); -- pulz

	signal lat : std_logic_vector(1 downto 0); -- pomocny signal pro latch

	-- povleni odesilani dat ven	
	signal en_load_dat : std_logic;

	-- nasobicka
	-- nasobicka BCM

	signal actual_BCM : std_logic_vector(5 downto 0); -- vstupni data b do nasobicky  BCM

	signal brgt         : std_logic_vector(8 downto 0); -- pomocny signal
	signal mult_eno_1   : std_logic_vector(13 downto 0); -- pomocny unsigned signal zvetceny o 1 
	signal mult_eno     : std_logic_vector(14 downto 0); -- vystupni data z nasobicky enable
	signal mult_eno_lat : std_logic_vector(13 downto 0); -- vystupni data z nasobicky enable projity prez latch

	signal arst_sw : std_logic;         -- reset switche
	signal switch  : std_logic := '0';  -- resi, jestli jde prvni enable do 0 nebo do 1 

	--komparatory
	signal cmpr_col  : std_logic;       -- vystup z comparatoru sloupcu
	signal cmpr_load : std_logic;       -- vystup z comparatoru hlidjiciho nahravani dat
	signal cmpr_ENo  : std_logic;       -- vystup z comparatoru hlidjiciho vystupni enable

	-- RGB
	signal RGB1A_Ih, RGB2A_Ih : std_logic_vector(15 downto 0);

	signal rgb1, rgb2                           : std_logic_vector(17 downto 0); -- pomocna rozsirena gama
	signal rgb1_olat, rgb2_olat, rgb1_o, rgb2_o : std_logic_vector(2 downto 0); -- pomocna pro vystupni z multiplexeru

	signal nex_BCM : std_logic_vector(5 downto 0); -- nasledujici BCM oddil dat
	signal end_row : std_logic;         -- flag o poslednim bloku v BCM

	-- velikost panelu
	signal en_size_col : std_logic;
	signal col_size    : std_logic_vector(7 downto 0) := (others => '1');
	signal col_size_h  : std_logic_vector(8 downto 0);

	signal en_size_row       : std_logic;
	signal row_size          : std_logic_vector(3 downto 0) := (others => '1');
	signal test_size_pusle : std_logic:='0';
	signal test_size_pusle_h : std_logic:='0';
	signal test_chain_col    : std_logic;
	signal test_chain_row    : std_logic_vector(3 downto 0);
	signal test_reg          : std_logic_vector(3 downto 0);
	signal test_pin          : std_logic;
	signal col_size_i        : std_logic_vector(7 downto 0):=(others => '0');
	signal col_size_ih        : std_logic_vector(7 downto 0):=(others => '0');
	signal row_size_i        : std_logic_vector(3 downto 0):=(others => '0');
		
	-- adresa vycitanych dat
	signal adr_read  : std_logic_vector(11 downto 0);
	signal adr2_read : std_logic_vector(13 downto 0);

begin

------------------------------------------------------------------------------------------------------------
	-- testovani velikosti--

	-- pameti 
	uSize_col : D_ren
		generic map(
			STOP_BITS => 7
		)
		port map(
			ARST => '0',
			CLK  => CLK,
			EN   => en_size_col,
			D    => col_size_i,
			Q    => col_size
		);
	col_size_h <= "100000000" when col_size= x"00" else std_logic_vector('0' & unsigned(col_size) + 1);

	uSize_row : D_ren
		generic map(
			STOP_BITS => 3
		)
		port map(
			ARST => '0',
			CLK  => CLK,
			EN   => en_size_row,
			D    => row_size_i,
			Q    => row_size
		);

	-- prvotni testovaci pulz		
	process(CLK, ARST) is
	begin
		if ARST = '1' then
			test_size_pusle_h <= '0';
		elsif rising_edge(clk) then
				test_size_pusle_h <= TEST_SIZE;
		end if;
	end process;

	test_size_pusle <= (not test_size_pusle_h) and TEST_SIZE;
	test_chain_col  <= '1' when unsigned(col(9 downto 0)) = "1000000000" or unsigned(col(9 downto 0)) = "0111111111" or unsigned(col(9 downto 0)) = "0111111101" else '0';
	test_chain_row  <= "1111" when (unsigned(col(9 downto 3)) = "00011110") else "0001"; --when 247

	SIZE_COL      <= col_size;
	SIZE_ROW      <=  row_size & '1';
	TEST_SIZE_END <= '1' when TEST_SIZE = '1' and (unsigned(col(9 downto 1)) = "0001111000") else '0';

	test_pin <= TEST_PIN_COL or TEST_PIN_ROW;
	
	-- posuvny registr_prijem
	uSh_reg : component shift_reg_ren
		generic map(
			size => 4
		)
		port map(
			CLK   => CLK,
			ARST  => ARST,
			CEN   => TEST_SIZE,
			DAT_I => test_pin,
			DAT_O => test_reg
		);

	en_size_col <= '1' when (test_reg = "1101" and col(12 downto 9) = x"0" and TEST_SIZE = '1') else '0';
	en_size_row <= '1' when ((unsigned(col(7 downto 1)) = "1111001") and TEST_SIZE = '1') else '0';

	
	col_size_ih <= std_logic_vector(unsigned(col(7 downto 0))+"11"); -- kompenzace 3 bez reseni preteceni
	col_size_i <= std_logic_vector(x"FF" - unsigned(col_size_ih)); -- dvojkovy doplnek
	
	row_size_i <= x"F" when (test_reg(1) = '1') else x"7"; -- rozhodovani mezi 16 a 8 radky
--------------------------------------------------------------------------------------------------------------------
	-- odcitacka radku
	uSubt_col : sub_ren_srst
		generic map(
			STOP_BIT => 13
		)
		port map(
			SRST  => rst_pulse,
			CLK   => CLK,
			START => col_start,
			EN    => '1',
			DATA  => col
		);

	rst_row <= '1' when row = "0000" and en_cnt_row = '1' else '0';
	uCnt_ROW : component sub_ren_srst
		generic map(
			STOP_BIT => 3
		)
		port map(
			SRST  => rst_row,
			CLK   => CLK,
			START => row_size,
			EN    => en_cnt_row,
			DATA  => row
		);

	uDrenb_ROW : D_ren
		generic map(
			STOP_BITS => 3
		)
		port map(
			ARST => ARST,
			CLK  => CLK,
			EN   => en_buf_row,
			D    => row,
			Q    => abc_h
		);

	ABC <= "1111" - abc_h when TEST_SIZE = '0' else test_chain_row;

	uLATCH : component sh_reg_2
		port map(
			CLK  => CLK,
			SRST => ARST,
			DI   => rst_pulse,
			DO   => lat
		);
	uGama : gama
		port map(
			RGB1_I => RGB1A_I,
			RGB2_I => RGB2A_I,
			RGB1   => Rgb1,
			RGB2   => Rgb2
		);

	uMux_dat_o : rgb_mux
		port map(
			ARST      => ARST,
			CLK       => CLK,
			RGB1_I    => rgb1,
			RGB2_I    => rgb2,
			SEL       => nex_BCM,
			RGB1_O    => rgb1_o,
			RGB2_O    => rgb2_o,
			RGB1_OLAT => rgb1_olat,
			RGB2_OLAT => rgb2_olat
		);

	--dynamicka bcm	
	uDynam : BCM_dynam
		port map(
			ARST        => ARST,
			CLK         => CLK,
			WEREN       => en_load_dat,
			NEW_TEST    => rst_pulse,
			FIRST       => switch,
			RGB1        => RGB1,
			RGB2        => RGB2,
			WRITE_BIT1  => rgb1_o,
			WRITE_BIT2  => rgb2_o,
			END_ROW     => end_row,
			ACTUAL_BCMO => actual_BCM,
			NEXT_BCMO   => nex_BCM
		);

--------------------------------------------------------------------------------------------------------------------
	-- JAS/ EN_OUT

	mult_eno <= std_logic_vector('1' & unsigned(nex_BCM) * (x"FF" - unsigned(BRIGHT))) when switch = '0' else --
	std_logic_vector(unsigned(nex_BCM) * (unsigned(BRIGHT) + "000000001") + "10");

	uMem_mult_brg : component D_ren
		generic map(
			STOP_BITS => 13
		)
		port map(
			ARST => ARST,
			CLK  => CLK,
			EN   => rst_pulse,
			D    => mult_eno(13 downto 0),
			Q    => mult_eno_lat
		);

	-- comparator veliksti nahravacich oken
	uAlesB_cnt : AlesB_14b
		port map(
			DATAA => col,
			DATAB => mult_eno_lat,
			ALB   => cmpr_ENo
		);

	-- prepinac enable --
	switch_brgh : process(CLK) is
	begin
		if rising_edge(clk) then
			if rst_pulse = '1' then
				if nex_BCM(0) = '1' or arst = '1' then
					switch <= '0';
				else
					switch <= not switch;
				end if;
			end if;
		end if;
	end process switch_brgh;
--------------------------------------------------------------------------------------------------------------------
	en_buf_row <= actual_BCM(0);
	en_cnt_row <= end_row;              --lat and

	col_zero <= '1' when col = "00000000000000" else '0';

	col_start_h <= '0' & nex_BCM(5) & (nex_BCM(4) or nex_BCM(5)) & (nex_BCM(3) or nex_BCM(5) or nex_BCM(4)) & (nex_BCM(2) or nex_BCM(5) or nex_BCM(4) or nex_BCM(3)) & (nex_BCM(1) or nex_BCM(5) or nex_BCM(4) or nex_BCM(3) or nex_BCM(2)) & x"FF";
	col_start   <= "00" & x"302" when TEST_SIZE = '1' else std_logic_vector(unsigned(col_start_h) + "10");

	en_load_dat <= '1' when col(13 downto 8) = "000000" else '0';
	--

	rst_pulse <= col_zero or test_size_pusle;

	-- prirazovani vystupu
	R2A_OUT <= rgb1_olat(2) and en_load_dat when TEST_SIZE = '0' else test_chain_col;
	G2A_OUT <= rgb1_olat(1) and en_load_dat;
	B2A_OUT <= rgb1_olat(0) and en_load_dat;
	R1A_OUT <= rgb2_olat(2) and en_load_dat;
	G1A_OUT <= rgb2_olat(1) and en_load_dat;
	B1A_OUT <= rgb2_olat(0) and en_load_dat;

	CLK_OUT <= en_load_dat and not CLK;
	EN_OUT  <= cmpr_ENo xnor switch;
	LATCH   <= lat(0);

	SNAP_END <= rst_row;               

	uROW_mult : mult9bX4b
		port map(
			DATAA  => col_size_h,
			DATAB  => row,
			RESULT => row_mult
		);
	adr_read <= std_logic_vector(unsigned(row_mult(11 downto 0)) + unsigned(col(7 downto 0) + "10"));
	ADR1_R <= '0' & adr_read;
	adr2_read <= std_logic_vector((('0' & unsigned(row_size) + "01") * ('0' & unsigned(col_size) + "01")) + unsigned(adr_read)); --(12 downto 0); -- polovina ramky
	ADR2_R <= adr2_read(12 downto 0);
end Behavioral;

