library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Encoder_v1_0 is
	generic (
		-- Users to add parameters here
        PULSES : integer := 1250;
        PAIRS : integer := 4;
        CLK_FREQ : integer := 50;
        ORDER : integer := 0;
		-- User parameters ends
		-- Do not modify the parameters beyond this line
        

		-- Parameters of Axi Slave Bus Interface S00_AXI
		C_S00_AXI_DATA_WIDTH	: integer	:= 32;
		C_S00_AXI_ADDR_WIDTH	: integer	:= 4
	);
	port (
		-- Users to add ports here
        sync_in : in std_logic;
        clk : in std_logic;
        zero_calib : in std_logic;        
        SENS_A : in std_logic;
        SENS_B : in std_logic;
        SENS_INDEX : in std_logic;        
        angle : out std_logic_vector (15 downto 0);
        speed : out std_logic_vector (15 downto 0);
        zero_calib_done : out std_logic;
        sync_out : out std_logic;
		-- User ports ends
		-- Do not modify the ports beyond this line


		-- Ports of Axi Slave Bus Interface S00_AXI
		s00_axi_aclk	: in std_logic;
		s00_axi_aresetn	: in std_logic;
		s00_axi_awaddr	: in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
		s00_axi_awprot	: in std_logic_vector(2 downto 0);
		s00_axi_awvalid	: in std_logic;
		s00_axi_awready	: out std_logic;
		s00_axi_wdata	: in std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
		s00_axi_wstrb	: in std_logic_vector((C_S00_AXI_DATA_WIDTH/8)-1 downto 0);
		s00_axi_wvalid	: in std_logic;
		s00_axi_wready	: out std_logic;
		s00_axi_bresp	: out std_logic_vector(1 downto 0);
		s00_axi_bvalid	: out std_logic;
		s00_axi_bready	: in std_logic;
		s00_axi_araddr	: in std_logic_vector(C_S00_AXI_ADDR_WIDTH-1 downto 0);
		s00_axi_arprot	: in std_logic_vector(2 downto 0);
		s00_axi_arvalid	: in std_logic;
		s00_axi_arready	: out std_logic;
		s00_axi_rdata	: out std_logic_vector(C_S00_AXI_DATA_WIDTH-1 downto 0);
		s00_axi_rresp	: out std_logic_vector(1 downto 0);
		s00_axi_rvalid	: out std_logic;
		s00_axi_rready	: in std_logic
	);
end Encoder_v1_0;

architecture arch_imp of Encoder_v1_0 is

    signal angle_signal : unsigned (15 downto 0);
    signal speed_signal : signed (15 downto 0);
    
    constant order_bit : std_logic := to_unsigned(ORDER,1)(0);
    
    signal AXI_DATA0 : std_logic_vector (C_S00_AXI_DATA_WIDTH-1 downto 0);
    signal AXI_DATA1 : std_logic_vector (C_S00_AXI_DATA_WIDTH-1 downto 0);
	-- component declaration
	component Encoder_v1_0_S00_AXI is
		generic (
		C_S_AXI_DATA_WIDTH	: integer	:= 32;
		C_S_AXI_ADDR_WIDTH	: integer	:= 4
		);
		port (
		AXI_DATA0 : in std_logic_vector (C_S_AXI_DATA_WIDTH-1 downto 0);
        AXI_DATA1 : in std_logic_vector (C_S_AXI_DATA_WIDTH-1 downto 0);
		S_AXI_ACLK	: in std_logic;
		S_AXI_ARESETN	: in std_logic;
		S_AXI_AWADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		S_AXI_AWPROT	: in std_logic_vector(2 downto 0);
		S_AXI_AWVALID	: in std_logic;
		S_AXI_AWREADY	: out std_logic;
		S_AXI_WDATA	: in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		S_AXI_WSTRB	: in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
		S_AXI_WVALID	: in std_logic;
		S_AXI_WREADY	: out std_logic;
		S_AXI_BRESP	: out std_logic_vector(1 downto 0);
		S_AXI_BVALID	: out std_logic;
		S_AXI_BREADY	: in std_logic;
		S_AXI_ARADDR	: in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
		S_AXI_ARPROT	: in std_logic_vector(2 downto 0);
		S_AXI_ARVALID	: in std_logic;
		S_AXI_ARREADY	: out std_logic;
		S_AXI_RDATA	: out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
		S_AXI_RRESP	: out std_logic_vector(1 downto 0);
		S_AXI_RVALID	: out std_logic;
		S_AXI_RREADY	: in std_logic
		);
	end component Encoder_v1_0_S00_AXI;
	
	component Encoder_core is
      generic(
        pulses : integer;
        pairs : integer;
        clk_freq : integer;
        inv_dir : std_logic
      );
        port (
        sens_a : in std_logic;
        sens_b : in std_logic;
        sens_index : in std_logic;
        zero_calib : in std_logic;
        clk : in std_logic;
        angle : out unsigned (15 downto 0);
        speed : out signed (15 downto 0);
        zero_calib_done : out std_logic    
        );
    end component;

begin

-- Instantiation of Axi Bus Interface S00_AXI
Encoder_v1_0_S00_AXI_inst : Encoder_v1_0_S00_AXI
	generic map (
		C_S_AXI_DATA_WIDTH	=> C_S00_AXI_DATA_WIDTH,
		C_S_AXI_ADDR_WIDTH	=> C_S00_AXI_ADDR_WIDTH
	)
	port map (
	    AXI_DATA0 => AXI_DATA0,
        AXI_DATA1 => AXI_DATA1,
		S_AXI_ACLK	=> s00_axi_aclk,
		S_AXI_ARESETN	=> s00_axi_aresetn,
		S_AXI_AWADDR	=> s00_axi_awaddr,
		S_AXI_AWPROT	=> s00_axi_awprot,
		S_AXI_AWVALID	=> s00_axi_awvalid,
		S_AXI_AWREADY	=> s00_axi_awready,
		S_AXI_WDATA	=> s00_axi_wdata,
		S_AXI_WSTRB	=> s00_axi_wstrb,
		S_AXI_WVALID	=> s00_axi_wvalid,
		S_AXI_WREADY	=> s00_axi_wready,
		S_AXI_BRESP	=> s00_axi_bresp,
		S_AXI_BVALID	=> s00_axi_bvalid,
		S_AXI_BREADY	=> s00_axi_bready,
		S_AXI_ARADDR	=> s00_axi_araddr,
		S_AXI_ARPROT	=> s00_axi_arprot,
		S_AXI_ARVALID	=> s00_axi_arvalid,
		S_AXI_ARREADY	=> s00_axi_arready,
		S_AXI_RDATA	=> s00_axi_rdata,
		S_AXI_RRESP	=> s00_axi_rresp,
		S_AXI_RVALID	=> s00_axi_rvalid,
		S_AXI_RREADY	=> s00_axi_rready
	);

	-- Add user logic here
    Encoder_core_inst : Encoder_core
        generic map(
            pulses => PULSES,
            pairs => PAIRS,
            clk_freq => CLK_FREQ,
            inv_dir => order_bit
        )
        port map(
            sens_a => SENS_A,
            sens_b => SENS_B,
            sens_index => SENS_INDEX,
            zero_calib  => zero_calib,
            clk => clk,
            angle => angle_signal,
            speed => speed_signal,
            zero_calib_done => zero_calib_done    
        );
        
    process (clk) begin 
        if (clk'event and clk='1') then
            if (sync_in='1') then
                angle <= std_logic_vector(angle_signal);
                speed <= std_logic_vector(speed_signal);
                AXI_DATA0 <= std_logic_vector(resize(angle_signal,C_S00_AXI_DATA_WIDTH));
                AXI_DATA1 <= std_logic_vector(resize(speed_signal,C_S00_AXI_DATA_WIDTH));
                sync_out <= '1';
            else
                sync_out <= '0';    
            end if;    
        end if;  
    end process;    
	-- User logic ends

end arch_imp;
