LIBRARY ieee;
USE ieee.std_logic_1164. all;
USE ieee.numeric_std.all;
 
ENTITY action_qualifier IS

	PORT (
    TBCLK 		: 	IN std_logic;							--! Time-base clock.
	 
	 CTR_PRD		:	IN	std_logic;						--! Time-base counter equal to the specified period (TBCTR = TBPRD)
	 CTR_ZERO	:	IN std_logic;							--! Time-base counter equal to zero (TBCTR = 0x0000)
	 CTR_CMPA	:	IN std_logic;							--! Time-base counter equal to the counter-compare A register (TBCTR = CMPA)
	 CTR_CMPB	:	IN std_logic;							--! Time-base counter equal to the counter-compare B register (TBCTR = CMPB)
	 CTR_DIR		:	IN std_logic;						--! Time-base counter direction.
	 
	 CTR_MODE	:	IN std_logic_vector(1 DOWNTO 0); 		--! Time-base counter mode.
	 
	 A_CBD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPB register and the counter is decrementing.
	 A_CBU		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPB register and the counter is incrementing.
	 A_CAD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPA register and the counter is decrementing.
	 A_CAU		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPA register and the counter is incrementing.
	 A_PRD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the period.
	 A_ZRO		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when counter equals zero.
	 
	 B_CBD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPB register and the counter is decrementing.
	 B_CBU		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPB register and the counter is incrementing.
	 B_CAD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPA register and the counter is decrementing.
	 B_CAU		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the active CMPA register and the counter is incrementing.
	 B_PRD		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when the counter equals the period.
	 B_ZRO		:	IN std_logic_vector(1 DOWNTO 0); 		--! Action when counter equals zero.
	 
	 EPWMXA		:	OUT std_logic; 							--! PWM output A
	 EPWMXB		:	OUT std_logic);  						--! PWM output B
	 	
END action_qualifier;
 

ARCHITECTURE Behavioral OF action_qualifier IS

	SIGNAL pwmA : std_logic := '0';							--! Internal PWM A
	SIGNAL pwmB : std_logic := '0';							--! Internal PWM B
	
	
	--! Function to set signal on desired level
	
	FUNCTION signalEvent(signal_in 		: std_logic;
						 signal_event 	: std_logic_vector(1 DOWNTO 0)) 
						RETURN std_logic IS VARIABLE signal_out : std_logic := '0';
	BEGIN
		CASE signal_event IS
			WHEN "00" => signal_out := signal_in;			--! Keep outputs EPWMxA and EPWMxB at same level as currently set.
			WHEN "01" => signal_out := '0';					--! Set output EPWMxA or EPWMxB to a high level.
			WHEN "10" => signal_out := '1';					--! Set output EPWMxA or EPWMxB to a low level.
			WHEN OTHERS => signal_out := NOT signal_in;		--! If EPWMxA or EPWMxB is currently pulled high, then pull the output low. If EPWMxA or EPWMxB is currently pulled low, then pull the output high.
		END CASE;
		RETURN signal_out;	
	END FUNCTION;	

BEGIN

	PROCESS(TBCLK, CTR_CMPA, CTR_CMPB, CTR_DIR, CTR_PRD, CTR_ZERO, pwmA, pwmB) 
	BEGIN
		IF rising_edge(TBCLK) THEN
		
			--! Priority sequence when CTR_MODE = UP
			
			IF CTR_MODE = "00" THEN	
				IF(CTR_PRD = '1') THEN
					pwmA <= signalEvent(pwmA, A_PRD);
					pwmB <= signalEvent(pwmB, B_PRD);
				ELSIF(CTR_CMPB = '1' AND CTR_DIR = '1') THEN
					pwmA <= signalEvent(pwmA, A_CBU);
					pwmB <= signalEvent(pwmB, B_CBU);
				ELSIF(CTR_CMPA = '1' AND CTR_DIR = '1') THEN
					pwmA <= signalEvent(pwmA, A_CAU);
					pwmB <= signalEvent(pwmB, B_CAU);
				ELSIF(CTR_ZERO = '1') THEN
					pwmA <= signalEvent(pwmA, A_ZRO);
					pwmB <= signalEvent(pwmB, B_ZRO);		
				END IF;
				
			--! Priority sequence when CTR_MODE = DOWN
			
			ELSIF CTR_MODE = "01" THEN
				IF(CTR_ZERO = '1') THEN
					pwmA <= signalEvent(pwmA, A_ZRO);
					pwmB <= signalEvent(pwmB, B_ZRO);
				ELSIF(CTR_CMPB = '1' AND CTR_DIR = '0') THEN
					pwmA <= signalEvent(pwmA, A_CBD);
					pwmB <= signalEvent(pwmB, B_CBD);
				ELSIF(CTR_CMPA = '1' AND CTR_DIR = '0') THEN
					pwmA <= signalEvent(pwmA, A_CAD);
					pwmB <= signalEvent(pwmB, B_CAD);
				ELSIF(CTR_PRD = '1') THEN
					pwmA <= signalEvent(pwmA, A_PRD);
					pwmB <= signalEvent(pwmB, B_PRD);	
				END IF;	
			
			--! Priority sequence when CTR_MODE = UP/DOWN
			
			ELSIF CTR_MODE = "10" THEN
				IF CTR_DIR = '1' THEN
					IF(CTR_CMPB = '1' AND CTR_DIR = '1') THEN
						pwmA <= signalEvent(pwmA, A_CBU);
						pwmB <= signalEvent(pwmB, B_CBU);
					ELSIF(CTR_CMPA = '1' AND CTR_DIR = '1') THEN
						pwmA <= signalEvent(pwmA, A_CAU);
						pwmB <= signalEvent(pwmB, B_CAU);	
					ELSIF(CTR_ZERO = '1') THEN
						pwmA <= signalEvent(pwmA, A_ZRO);
						pwmB <= signalEvent(pwmB, B_ZRO);					
					ELSIF(CTR_CMPB = '1' AND CTR_DIR = '0') THEN
						pwmA <= signalEvent(pwmA, A_CBD);
						pwmB <= signalEvent(pwmB, B_CBD);
					ELSIF(CTR_CMPA = '1' AND CTR_DIR = '0') THEN
						pwmA <= signalEvent(pwmA, A_CAD);
						pwmB <= signalEvent(pwmB, B_CAD);				
					END IF;
				ELSE
					IF(CTR_CMPB = '1' AND CTR_DIR = '0') THEN
						pwmA <= signalEvent(pwmA, A_CBD);
						pwmB <= signalEvent(pwmB, B_CBD);
					ELSIF(CTR_CMPA = '1' AND CTR_DIR = '0') THEN
						pwmA <= signalEvent(pwmA, A_CAD);
						pwmB <= signalEvent(pwmB, B_CAD);
					ELSIF(CTR_PRD = '1') THEN
						pwmA <= signalEvent(pwmA, A_PRD);
						pwmB <= signalEvent(pwmB, B_PRD);	
					ELSIF(CTR_CMPB = '1' AND CTR_DIR = '1') THEN
						pwmA <= signalEvent(pwmA, A_CBU);
						pwmB <= signalEvent(pwmB, B_CBU);
					ELSIF(CTR_CMPA = '1' AND CTR_DIR = '1') THEN
						pwmA <= signalEvent(pwmA, A_CAU);
						pwmB <= signalEvent(pwmB, B_CAU);				
					END IF;					
				END IF;
			END IF;
		END IF;
	END PROCESS;

	EPWMXA <= pwmA;	--! assign internal PWM A to PWM output A
	EPWMXB <= pwmB;	--! assign internal PWM B to PWM output B		
END Behavioral;