-- Company: BUSE
-- Engineer: PAVEL SUNKA
-- 
-- Create Date:   8.6.2017
-- Module Name:   Top modul 
-- Project Name:  Micomp
-- Target Devices: 10M08
-----------------------------         ----------------------------
-- precte velikost retezce, pohlida konec a odesle potvrzujici byt, pocita crc !!!!!! neni dodelane response z nadrazeneho mista
-----------------------------         ----------------------------
----------------------------------------------------------------------------------
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;

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

entity Micomp is
	Generic(
		UART_DIV     : natural := (35000000 / 9600); -- vstup. frekvence, pozadovana frekvence
		UART_CNT_B   : natural := 12;   -- pocet potrebnych bitu na citac zmenseny o 1: 13b= (12 downto 0)
		MESSAGE_SIZE : natural := 3;
		MESSAGE_B    : natural := 1
	);
	Port(
		ARST     : in  STD_LOGIC;
		CLK      : in  std_logic;
		RX       : in  std_logic;
		SEND_MSG : in  std_logic;
		MSG      : in  std_logic_vector(MESSAGE_SIZE * 8 - 1 downto 0);
		MSG_SIZE : in  std_logic_vector(MESSAGE_B downto 0);
		DAT_O    : out std_logic_vector(7 downto 0);
		DAT_O_EN : out std_logic;
		RIGHT_RE : out std_logic_vector(1 downto 0);
		TX       : out std_logic
	);
end Micomp;

architecture Behavioral of Micomp is
	constant MSGBUFF_B : natural := MESSAGE_SIZE * 8 - 1;

	component Uart
		generic(
			UART_DIV   : natural := (40000000 / 9600);
			UART_CNT_B : natural := 12
		);
		port(
			CLK      : in  std_logic;
			ARST     : in  std_logic;
			RX       : in  std_logic;
			EN_WR    : in  std_logic;
			DAT_WR   : in  std_logic_vector(7 downto 0);
			BYT_END  : out std_logic;
			END_WR   : out std_logic;
			TX       : out std_logic;
			DAT_READ : out std_logic_vector(7 downto 0)
		);
	end component Uart;

	component sub_ren_rst
		generic(STOP_BIT : natural);
		port(
			ARST   : in  std_logic;
			CLK    : in  std_logic;
			START  : in  std_logic_vector(stop_bit downto 0);
			EN     : in  std_logic;
			SUBD_O: out std_logic_vector(stop_bit downto 0)
		);
	end component sub_ren_rst;

	component crc
		port(
			CLK      : in  std_logic;
			SRST     : in  std_logic;
			EN       : in  std_logic;
			DAT_I    : in  std_logic_vector(7 downto 0);
			RIGHT_WR : out std_logic
		);
	end component crc;

	-- uart-
	signal DAT_Ien    : std_logic;      -- enable prichozich dat
	signal DAT_I      : std_logic_vector(7 downto 0); -- prichozi data
	signal right      : std_logic_vector(7 downto 0); -- spravny prijem dat
	signal end_wr_byt : std_logic;      -- flag odeslaneho byjtu

	signal sub_set : std_logic;         -- nastaveni odcitacky/citacky
	signal sub_en  : std_logic;         -- povoleni odecteni
	signal sub_byt : std_logic_vector(7 downto 0); -- vas--LEDek odcitacky

	signal crc_en    : std_logic;       -- povoleni pricteni crc
	signal crc_right : std_logic;       -- bit urcujici spravne soucet
	signal crc_rst   : std_logic;       -- resetovani kontrolniho souctu

	--odpoved
	signal msg_buff    : std_logic_vector(MSGBUFF_B downto 0);
	signal msg_size_o  : std_logic_vector(MESSAGE_B downto 0);
	signal zero_remain : std_logic_vector(8 - MESSAGE_B - 2 downto 0) := (others => '0'); -- dolpneni nul podle velikosti zpravy
	signal crco_in     : std_logic_vector(7 downto 0);
	signal crco_res    : std_logic_vector(7 downto 0) := (others => '0');
	signal crco_srst    : std_logic;
	signal response_en : std_logic;     -- odeslani odpovedi
	signal response    : std_logic_vector(7 downto 0); -- odpoved

	type stat_i is (sSize, sData, sCrc,sResult);
	signal state_i : stat_i := sSize;

	type stat_o is (sWait_o, sSize_o, sData_o, sCRC_o);
	signal state_o : stat_o := sWait_o;

begin
	uUart : Uart
		generic map(
			UART_DIV   => UART_DIV,
			UART_CNT_B => UART_CNT_B
		)
		port map(
			CLK      => CLK,
			ARST     => ARST,
			RX       => RX,
			EN_WR    => response_en,
			DAT_WR   => response,
			BYT_END  => DAT_Ien,
			END_WR   => end_wr_byt,
			TX       => TX,
			DAT_READ => DAT_I
		);

	-- prijem dat
	uSuB_size : sub_ren_rst
		generic map(
			STOP_BIT => 7
		)
		port map(
			ARST   => sub_set,
			CLK    => CLK,
			START  => DAT_I,
			EN     => sub_en,
			SUBD_O=> sub_byt
		);
	uCrc_in : crc
		port map(
			CLK      => CLK,
			SRST     => crc_rst,
			EN       => crc_en,
			DAT_I    => DAT_I,
			RIGHT_WR => crc_right
		);

	process(CLK, ARST) is
	begin
		if ARST = '1' then
			state_i <= sSize;
		elsif rising_edge(CLK) then
			case state_i is

				when sSize =>
					if DAT_Ien = '1' then
						state_i <= sData;
					end if;

				when sData =>
					if sub_byt = x"00" then
						state_i <= sCrc;
					end if;

				when sCrc =>
					if DAT_Ien = '1' then
						state_i <= sResult;
					end if;
				when sResult =>
					state_i <= sSize;
				when others =>
					state_i <= sSize;
			end case;
		end if;
	end process;

	process(state_i, DAT_Ien, crc_right) is
	begin
		sub_set  <= '0';
		crc_rst  <= '0';
		sub_en   <= '0';
		crc_en   <= '0';
		DAT_O_EN <= '0';
		right    <= x"FF";

		DAT_O_EN <= '0';
		-- LED <= "11111";

		case state_i is
			when sSize =>
				crc_en  <= DAT_Ien;
				sub_set <= DAT_Ien;
			when sData =>
				DAT_O_EN <= DAT_Ien;
				sub_en   <= DAT_Ien;
				crc_en   <= DAT_Ien;

			when sCrc =>
				crc_en <= DAT_Ien;

			when sResult =>

				if crc_right = '1' then
					right <= X"4f";
				else
					right <= x"52";
				end if;
				crc_rst <= '1';
			when others =>
				null;
		end case;
	end process;

	DAT_O    <= DAT_I;
	RIGHT_RE <= right(5 downto 4);      -- pozvrzeni

	-- odpoved ------------------------------------------------------------

	-- odcitacka bufferu
	uSuB_outbyte : component sub_ren_rst
		generic map(
			STOP_BIT => MESSAGE_B
		)
		port map(
			ARST   => SEND_MSG,
			CLK    => CLK,
			START  => MSG_SIZE,
			EN     => end_wr_byt,
			SUBD_O=> msg_size_o
		);

	-- buffer posuvny 8 bit	
	process(CLK, ARST) is
	begin
		if ARST = '1' then
			msg_buff <= (others => '0');
		elsif rising_edge(CLK) then
			if SEND_MSG = '1' then
				msg_buff <= MSG;
			elsif end_wr_byt = '1' then
				msg_buff <= msg_buff(MSGBUFF_B - 8 downto 0) & x"00";
			end if;
		end if;
	end process;

	-- vypocet CRC
	crco_in <= std_logic_vector(x"FF" - unsigned(msg_buff(MSGBUFF_B downto MSGBUFF_B - 7)) + unsigned(crco_res));
	-- crc_out
	process(CLK, ARST) is
	begin
		if rising_edge(CLK) then
			if crco_srst = '1' then
				crco_res <= (others => '0');
			elsif end_wr_byt = '1' then
				crco_res <= crco_in;
			end if;
		end if;
	end process;

	-- stav. automat
	process(CLK, ARST) is
	begin
		if ARST = '1' then
			state_o <= sWait_o;
		elsif rising_edge(CLK) then
			case state_o is
				when sWait_o =>
					if SEND_MSG = '1' then
						state_o <= sSize_o;
					end if;
				when sSize_o =>
					state_o <= sData_o;
				when sData_o =>
					if end_wr_byt = '1' and msg_size_o = "01" then
						state_o <= sCRC_o;
					end if;
				when sCRC_o =>
					if end_wr_byt = '1' then
						state_o <= sWait_o;
					end if;
			end case;
		end if;
	end process;

	process(state_o, zero_remain, MSG_SIZE, msg_buff, end_wr_byt, crco_res) is
	begin
		response    <= x"ff";
		response_en <= '0';
		crco_srst <= '0';
		case state_o is
			when sWait_o =>
				null;
			when sSize_o =>
				response    <= zero_remain &  msg_size_o;
				response_en <= '1';
			when sData_o =>
				response    <= msg_buff(MSGBUFF_B downto MSGBUFF_B - 7);
				response_en <= end_wr_byt;
			when sCRC_o =>
				response    <= crco_res;
				response_en <= end_wr_byt;
				crco_srst <= end_wr_byt;
		end case;
	end process;

end Behavioral;

