#define Z IP
#define I FP
#define J LR

#define INPUT_VALUE 30

; in C
; int factorial(int n) {
; 	if (n <= 1) {
;		return 1;
;	} else {
;		return n * factorial(n-1);
;	}
;}

; in DCPU
:factorial
	@ Store link register on stack
	SUB SP, 2
	SET [SP], LR
	
	@ Store frame pointer on stack
	SUB SP, 2
	SET [SP], FP

	@ Set frame pointer to start of frame
	SET FP, SP

	@ Allocate n on the stack
	SUB SP, 2
	SET [SP], A

	@ Load n	
	SET C, FP
	SUB C, 2
	SET C, [C]

	@ compare n and 1
	IFG C, 1

	@ Handle the else branch
	SET PC, factorial_recurse

	@ Handle the if branch
	@ Return 1
	SET A, 1
	SET PC, factorial_end
	
:factorial_recurse
	@ Call factorial with n-1
	SET A, FP
	SUB A, 2
	SET A, [A]
	SUB A, 1
	MOV PC, factorial
	@ Multiply returned value by n and return
	SET C, FP
	SUB C, 2
	SET C, [C]
	MUL A, C
	SET PC, factorial_end
	
:factorial_end
	@ Unwind stack and return
	SET SP, FP
	SET FP, [SP]
	ADD SP, 2
	SET LR, [SP]
	SET PC, LR
	
:main
	@ Push LR to stack
	SUB SP, 2
	SET [SP], LR

	@ Call factorial with parameter INPUT_VALUE
	SET A, INPUT_VALUE
	SET PC, factorial

	@ Return the value returned by factorial
	ADD SP, 2
	SET PC, LR