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

entity PI_controller_v1_0 is
	generic (
		-- Users to add parameters here
        Fvz : integer := 20;
        Kp : integer := 1000;
        Ki : integer := 1000;
        Ext_par : 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
        run : in std_logic;
        clk : in std_logic;
        sync_in : in std_logic;
        Kp_ext : in std_logic_vector (31 downto 0);
        Ki_ext : in std_logic_vector (31 downto 0);
        w : in std_logic_vector(15 downto 0);
        y : in std_logic_vector(15 downto 0);
        x : out std_logic_vector(15 downto 0);
        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 PI_controller_v1_0;

architecture arch_imp of PI_controller_v1_0 is

    signal sync : std_logic;
    
    signal w_signal : signed (15 downto 0);
    signal y_signal : signed (15 downto 0);
    signal x_signal : signed (15 downto 0);
    signal Kp_signal : signed (31 downto 0);
    signal Ki_signal : signed (31 downto 0);
    
    signal AXI_DATA0 : std_logic_vector (C_S00_AXI_DATA_WIDTH-1 downto 0);
    
	-- component declaration
	component PI_controller_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);
		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 PI_controller_v1_0_S00_AXI;
	
	component PI_core is
      generic(
        Fvz : integer := 20
      );
        port (
        run : in std_logic;
        clk : in std_logic;
        sync_in : in std_logic;
        lim : in signed (15 downto 0);
        Kp : signed (31 downto 0);
        Ki : signed (31 downto 0);
        w : in signed(15 downto 0);
        y : in signed(15 downto 0);
        x : out signed(15 downto 0);
        sync_out : out std_logic  
        );
    end component;

begin

-- Instantiation of Axi Bus Interface S00_AXI
PI_controller_v1_0_S00_AXI_inst : PI_controller_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,
		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
	);
	
	PI_inst : PI_core
          generic map(
            Fvz => Fvz
          )
            port map(
            run => run,
            clk => clk,
            sync_in => sync_in,
            lim => x"7FFF",
            Kp => Kp_signal,
            Ki => Ki_signal,
            w => w_signal,
            y => y_signal,
            x => x_signal,
            sync_out => sync  
            );

	-- Add user logic here
	Kp_signal <= signed(Kp_ext) when Ext_par=1 else to_signed(Kp,32);
    Ki_signal <= signed(Ki_ext) when Ext_par=1 else to_signed(Ki,32);
	
    w_signal <= signed(w);
    y_signal <= signed(y);
    
    process (clk) begin
      if (clk'event and clk='1') then
        if sync='1' then
            AXI_DATA0 <= std_logic_vector(resize(x_signal,32));
            x <= std_logic_vector(x_signal);
            sync_out <= '1';
        else
            sync_out <= '0';
        end if; 
      end if;
    end process;
	-- User logic ends

end arch_imp;
