-------------------------------------------------------------
--	Filename:  CRC16_8b.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 1
--	Date last modified: 9/14/05
-- Inheritance: 	none
--
-- description:  CRC16 verification for incoming data packets. 
-- CRC16 generation for outgoing data packets.  
-- Data is entered byte by byte.
-- The CRC is computed iteratively. The Initial CRC16 value for the first message
-- byte is all 1's. 
--
-- Rev 2 10/21/16 AZ
-- Switched to numeric_std library
-- Moved to synchronous reset
---------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity CRC16_8b is
    port ( 
	 	--// Clocks Resets
		CLK: in std_logic;	-- reference clock
		SYNC_RESET: in std_logic;	-- clock synchronous reset

		--// Inputs
		CRC16_IN: in std_logic_vector(15 downto 0);
			-- Initialize to all 1's for the first byte in the data packet.
			-- For subsequent bytes use the previous CRC16_OUT value, as the 
			-- CRC16 computation is iterative, byte by byte.
		DATA_IN: in std_logic_vector(7 downto 0);
			-- message from which the CRC16 is computed and/or checked. 
			-- Entered byte by byte. Does not include PID as PID is excluded from the
			-- CRC computation.
		DATA_VALID_IN: in std_logic;
			-- 1 CLK wide pulse to indicate that DATA_IN and CRC16_IN are ready to be
 		   -- processed.

		--// Outputs
		CRC16_OUT: out std_logic_vector(15 downto 0);
			-- Computed CRC16. 
			-- Latency: 1 CLK after DATA_VALID_IN.
			-- If all token bits are received without error, the sixteen-bit residual at
			-- the receiver will be 1000000000001101B.
	  	CRC16_VALID: out std_logic
			-- '1' when computed CRC16 = 1000000000001101B. 
		   -- valid only once the entire data packet is read.
			-- Latency: 1 CLK after DATA_VALID_IN.
			-- Stays until start (first byte) of next message.
			);
end entity;

architecture behavioral of CRC16_8b is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
signal DATA_IN_MSBFIRST: std_logic_vector(7 downto 0);
signal CRC16_OUT_LOCAL: std_logic_vector(15 downto 0);

-------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

-- Flip DATA_IN so that the CRC computation belows (designed for D7 transmitted first)
-- works when D0 is transmitted first as per USB.
--DATA_IN_MSBFIRST(7) <= DATA_IN(0);
--DATA_IN_MSBFIRST(6) <= DATA_IN(1);
--DATA_IN_MSBFIRST(5) <= DATA_IN(2);
--DATA_IN_MSBFIRST(4) <= DATA_IN(3);
--DATA_IN_MSBFIRST(3) <= DATA_IN(4);
--DATA_IN_MSBFIRST(2) <= DATA_IN(5);
--DATA_IN_MSBFIRST(1) <= DATA_IN(6);
--DATA_IN_MSBFIRST(0) <= DATA_IN(7);
DATA_IN_MSBFIRST <= DATA_IN;

CRC_COMPUTE_001: process(CLK, DATA_IN_MSBFIRST, DATA_VALID_IN) 
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			CRC16_OUT_LOCAL <= (others => '1');
		elsif(DATA_VALID_IN = '1') then
			-- new incoming byte
			CRC16_OUT_LOCAL(0) <= DATA_IN_MSBFIRST(7) xor DATA_IN_MSBFIRST(6) xor DATA_IN_MSBFIRST(5) xor DATA_IN_MSBFIRST(4) 
									xor DATA_IN_MSBFIRST(3) xor DATA_IN_MSBFIRST(2) xor DATA_IN_MSBFIRST(1) xor DATA_IN_MSBFIRST(0) 
									xor CRC16_IN(15) xor CRC16_IN(14) xor CRC16_IN(13) xor CRC16_IN(12) xor CRC16_IN(11)
									xor CRC16_IN(10) xor CRC16_IN(9) xor CRC16_IN(8);
			CRC16_OUT_LOCAL(1) <= DATA_IN_MSBFIRST(7) xor DATA_IN_MSBFIRST(6) xor DATA_IN_MSBFIRST(5) xor DATA_IN_MSBFIRST(4) 
									xor DATA_IN_MSBFIRST(3) xor DATA_IN_MSBFIRST(2) xor DATA_IN_MSBFIRST(1) 
									xor CRC16_IN(15) xor CRC16_IN(14) xor CRC16_IN(13) xor CRC16_IN(12) xor CRC16_IN(11)
									xor CRC16_IN(10) xor CRC16_IN(9);
			CRC16_OUT_LOCAL(2) <= DATA_IN_MSBFIRST(1) xor DATA_IN_MSBFIRST(0) 
									xor CRC16_IN(9) xor CRC16_IN(8);
			CRC16_OUT_LOCAL(3) <= DATA_IN_MSBFIRST(2) xor DATA_IN_MSBFIRST(1) 
									xor CRC16_IN(10) xor CRC16_IN(9);
			CRC16_OUT_LOCAL(4) <= DATA_IN_MSBFIRST(3) xor DATA_IN_MSBFIRST(2) 
									xor CRC16_IN(11) xor CRC16_IN(10);
			CRC16_OUT_LOCAL(5) <= DATA_IN_MSBFIRST(4) xor DATA_IN_MSBFIRST(3) 
									xor CRC16_IN(12) xor CRC16_IN(11);
			CRC16_OUT_LOCAL(6) <= DATA_IN_MSBFIRST(5) xor DATA_IN_MSBFIRST(4) 
									xor CRC16_IN(13) xor CRC16_IN(12);
			CRC16_OUT_LOCAL(7) <= DATA_IN_MSBFIRST(6) xor DATA_IN_MSBFIRST(5) 
									xor CRC16_IN(14) xor CRC16_IN(13);
			CRC16_OUT_LOCAL(8) <= DATA_IN_MSBFIRST(7) xor DATA_IN_MSBFIRST(6) 
									xor CRC16_IN(15) xor CRC16_IN(14) xor CRC16_IN(0);
			CRC16_OUT_LOCAL(9) <= DATA_IN_MSBFIRST(7) 
									xor CRC16_IN(15) xor CRC16_IN(1);
			CRC16_OUT_LOCAL(10) <= CRC16_IN(2);
			CRC16_OUT_LOCAL(11) <= CRC16_IN(3);
			CRC16_OUT_LOCAL(12) <= CRC16_IN(4);
			CRC16_OUT_LOCAL(13) <= CRC16_IN(5);
			CRC16_OUT_LOCAL(14) <= CRC16_IN(6);
			CRC16_OUT_LOCAL(15) <= DATA_IN_MSBFIRST(7) xor DATA_IN_MSBFIRST(6) xor DATA_IN_MSBFIRST(5) xor DATA_IN_MSBFIRST(4) 
									xor DATA_IN_MSBFIRST(3) xor DATA_IN_MSBFIRST(2) xor DATA_IN_MSBFIRST(1) xor DATA_IN_MSBFIRST(0) 
									xor CRC16_IN(15) xor CRC16_IN(14) xor CRC16_IN(13) xor CRC16_IN(12) xor CRC16_IN(11)
									xor CRC16_IN(10) xor CRC16_IN(9) xor CRC16_IN(8) xor CRC16_IN(7);
		end if;
	end if;
end process;

CRC16_OUT <= CRC16_OUT_LOCAL;

CRC16_VALID <= '1' when (CRC16_OUT_LOCAL = "1000000000001101") else '0';

end behavioral;