-- file Laser.vhd
-- Laser easy model controller implementation
-- copyright: (C) 2016-2020 MPSI Technologies GmbH
-- author: Alexander Wirthmueller (auto-generation)
-- date created: 10 May 2025
-- IP header --- ABOVE

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

use work.Dbecore.all;
use work.Zuvsp.all;

entity Laser is
	generic (
		fMclk: natural := 50000
	);
	port (
		reset: in std_logic;
		mclk: in std_logic;

		reqInvSet: in std_logic;
		ackInvSet: out std_logic;

		setL: in std_logic_vector(15 downto 0);
		setR: in std_logic_vector(15 downto 0);

		nss: out std_logic;
		sclk: out std_logic;
		mosi: out std_logic
	);
end Laser;

architecture Rtl of Laser is

	------------------------------------------------------------------------
	-- component declarations
	------------------------------------------------------------------------

	component Spimaster_v1_0 is
		generic (
			fMclk: natural := 50000;

			cpol: std_logic := '0';
			cpha: std_logic := '1';

			nssByteNotXfer: std_logic := '0';

			fSclk: natural range 100 to 50000000 := 2000000;
			Nstop: natural range 1 to 8 := 1
		);
		port (
			reset: in std_logic;
			mclk: in std_logic;

			req: in std_logic;
			ack: out std_logic;
			dne: out std_logic;

			len: in std_logic_vector(16 downto 0);

			send: in std_logic_vector(7 downto 0);
			strbSend: out std_logic;

			recv: out std_logic_vector(7 downto 0);
			strbRecv: out std_logic;

			nss: out std_logic;
			sclk: out std_logic;
			mosi: out std_logic;
			miso: in std_logic
		);
	end component;

	------------------------------------------------------------------------
	-- signal declarations
	------------------------------------------------------------------------

	---- main operation (op)
	type stateOp_t is (
		stateOpInit,
		stateOpIdle,
		stateOpInv,
		stateOpSendA, stateOpSendB, stateOpSendC,
		stateOpPrepwait,
		stateOpUpdwait
	);
	signal stateOp: stateOp_t;

	signal spilen: std_logic_vector(16 downto 0);
	signal spisend: std_logic_vector(7 downto 0);

	-- IP sigs.op.cust --- INSERT

	---- mySpi
	signal strbSpisend: std_logic;

	---- handshake
	-- op to mySpi
	signal reqSpi: std_logic;
	signal ackSpi: std_logic;
	signal dneSpi: std_logic;

	---- other
	-- IP sigs.oth.cust --- INSERT

begin

	------------------------------------------------------------------------
	-- sub-module instantiation
	------------------------------------------------------------------------

	mySpi : Spimaster_v1_0
		generic map (
			fMclk => fMclk,

			cpol => '0',
			cpha => '1',

			nssByteNotXfer => '0',

			fSclk => 2000000,
			Nstop => 1
		)
		port map (
			reset => reset,
			mclk => mclk,

			req => reqSpi,
			ack => ackSpi,
			dne => dneSpi,

			len => spilen,

			send => spisend,
			strbSend => strbSpisend,

			recv => open,
			strbRecv => open,

			nss => nss,
			sclk => sclk,
			mosi => mosi,
			miso => '0'
		);

	------------------------------------------------------------------------
	-- implementation: main operation (op)
	------------------------------------------------------------------------

	-- IP impl.op.wiring --- BEGIN
	ackInvSet <= '1' when stateOp=stateOpInv else '0';

	reqSpi <= '1' when (stateOp=stateOpSendA or stateOp=stateOpSendB) else '0';
	-- IP impl.op.wiring --- END

	-- IP impl.op.wiring.cust --- LINE

	-- IP impl.op.rising --- BEGIN
	process (reset, mclk)
		-- IP impl.op.vars --- BEGIN
		constant sizeTxbuf: natural := 2;
		type txbuf_t is array(0 to sizeTxbuf-1) of std_logic_vector(7 downto 0);
		variable txbuf: txbuf_t;

		variable bytecnt: natural range 0 to sizeTxbuf;
		variable updNotPrep: boolean;

		variable rNotL: boolean;
		variable r_lcl: std_logic_vector(9 downto 0);

		constant imax: natural := fMclk*8/1000; -- 8us
		variable i: natural range 0 to imax;

		constant jmax: natural := fMclk/1000; -- 1us
		variable j: natural range 0 to jmax;
		-- IP impl.op.vars --- END

	begin
		if reset='1' then
			-- IP impl.op.asyncrst --- BEGIN
			stateOp <= stateOpInit;
			spilen <= (others => '0');
			spisend <= (others => '0');

			txbuf := (x"00",x"00");
			bytecnt := 0;
			updNotPrep := false;
			rNotL := false;
			r_lcl := (others => '0');
			i := 0;
			j := 0;
			-- IP impl.op.asyncrst --- END
			-- IP impl.op.asyncrst.cust --- INSERT

		elsif rising_edge(mclk) then
			if stateOp=stateOpInit then
				-- IP impl.op.syncrst --- RBEGIN
				spilen <= std_logic_vector(to_unsigned(sizeTxbuf, 17));

				txbuf := (x"F0",x"10"); -- DAC O/P, wake-up
				bytecnt := 0;
				updNotPrep := false;

				spisend <= txbuf(bytecnt);
				-- IP impl.op.syncrst --- REND
				-- IP impl.op.syncrst.cust --- INSERT

				stateOp <= stateOpSendA;

			elsif stateOp=stateOpIdle then
				if reqInvSet='1' then
					-- IP impl.op.idle.invSet --- IBEGIN
					txbuf(0) := "0000" & setL(9 downto 6);
					txbuf(1) := setL(5 downto 0) & "00";
					bytecnt := 0;
					updNotPrep := true;
					rNotL := false;
					r_lcl := setR(9 downto 0);

					spisend <= txbuf(bytecnt);
					-- IP impl.op.idle.invSet --- IEND

					stateOp <= stateOpInv;
				end if;

			elsif stateOp=stateOpInv then
				if reqInvSet='0' then
					stateOp <= stateOpSendA;
				end if;

			elsif stateOp=stateOpSendA then
				if dneSpi='1' then
					stateOp <= stateOpSendC;

				elsif strbSpisend='0' then
					-- IP impl.op.sendA --- IBEGIN
					bytecnt := bytecnt + 1;

					spisend <= txbuf(bytecnt);
					-- IP impl.op.sendA --- IEND

					stateOp <= stateOpSendB;
				end if;

			elsif stateOp=stateOpSendB then
				if strbSpisend='1' then
					stateOp <= stateOpSendA;
				end if;

			elsif stateOp=stateOpSendC then
				if ackSpi='0' then
					if not updNotPrep then
						i := 0; -- IP impl.op.sendC.prepdone --- ILINE

						stateOp <= stateOpPrepwait;

					else
						if not rNotL then
							-- IP impl.op.sendC.ldone --- IBEGIN
							rNotL := true;
		
							txbuf(0) := "0001" & r_lcl(9 downto 6);
							txbuf(1) := r_lcl(5 downto 0) & "00";
		
							bytecnt := 0;
		
							spisend <= txbuf(bytecnt);

							j := 0;
							-- IP impl.op.sendC.ldone --- IEND

							stateOp <= stateOpUpdwait;

						else
							stateOp <= stateOpIdle;
						end if;
					end if;
				end if;

			elsif stateOp=stateOpPrepwait then
				if i=imax then
					stateOp <= stateOpIdle;

				else
					i := i + 1; -- IP impl.op.prepwait.inc --- ILINE

					stateOp <= stateOpPrepwait;
				end if;

			elsif stateOp=stateOpUpdwait then
				if j=jmax then
					stateOp <= stateOpSendA;

				else
					j := j + 1; -- IP impl.op.updwait.inc --- ILINE

					stateOp <= stateOpUpdwait;
				end if;
			end if;
		end if;
	end process;
	-- IP impl.op.rising --- END

	------------------------------------------------------------------------
	-- implementation: other 
	------------------------------------------------------------------------

	
	-- IP impl.oth.cust --- INSERT

end Rtl;
