FUNCTION_BLOCK STACK_INT
  VAR_INPUT PUSH, POP: BOOL R_EDGE; (* Basic stack operations *)
            R1 : BOOL ;          (* Over-riding reset *)
            IN : INT ;           (* Input to be pushed *)
            N  : INT ;           (* Maximum depth after reset *)
  END_VAR
  VAR_OUTPUT EMPTY : BOOL := 1 ;     (* Stack empty *)
             OFLO  : BOOL := 0 ;     (* Stack overflow *)
             OUT   : INT  := 0 ;     (* Top of stack data *)
  END_VAR
  VAR STK : ARRAY[0..127] OF INT; (* Internal stack *)
      NI : INT :=128  ;           (* Storage for N upon reset *)
      PTR : INT := -1 ;           (* Stack pointer *)
  END_VAR
    (* Function Block body *)
	LD	R1	(* Dispatch on operations *)
	JMPC	RESET	
	LD	POP	
	ANDN	EMPTY	(* Don't pop empty stack *)
	JMPC	POP_STK	
	LD	PUSH	
	ANDN	OFLO	(* Don't push overflowed stack *)
	JMPC	PUSH_STK	
	RET		(* Return if no operations active *)
RESET:	LD	0	(* Stack reset operations *)
	ST	OFLO	
	LD	1	
	ST   	EMPTY	
	LD	-1	
	ST 	PTR	
	CAL	LIMIT(MN:=1,IN:=N,MX:=128)
	ST	NI	
	JMP	ZRO_OUT	
POP_STK:	LD	0	
	ST	OFLO	(* Popped stack is not overflowing *)
	LD	PTR	
	SUB	1	
	ST	PTR	
	LT	0	(* Empty when PTR < 0 *)
	ST	EMPTY	
	JMPC	ZRO_OUT	
	LD	STK[PTR]	
	JMP	SET_OUT	
PUSH_STK:	LD	0	
	ST	EMPTY	(* Pushed stack is not empty *)
	LD	PTR	
	ADD	1	
	ST	PTR	
	EQ	NI	(* Overflow when PTR = NI *)
	ST	OFLO	
	JMPC	ZRO_OUT	
	LD	IN	
	ST	STK[PTR]	(* Push IN onto STK *)
	JMP	SET_OUT	
ZRO_OUT:	LD	0	(* OUT=0 for EMPTY or OFLO *)
SET_OUT:	ST 	OUT	

  END_FUNCTION_BLOCK
