/******************************************************************************
Cfft2_2191.ASM       ADSP-2191 Radix-2 DIT Complex FFT

Performs a radix-2 DIT FFT of length 64 or greater on input data x(n).

        N		Real part of normal-ordered complex input stored in DM
        N		Imaginary part of normal-ordered complex input stored in PM
		N		Real part of fft stored in DM 
        N/2		Sin table stored in DM
		N/2		Cos table stored in PM
										
Calling Information:
    pm(twid_real[N/2])	- sin(2pi*n/N) table in bitreversed order
	dm(twid_imag[N/2])	- cos(2pi*n/N) table in bitreversed order
						 
    dm(Inputreal[N])    - Real part of complex input array stored in dm
	pm(Inputimag[N])    - Imaginary part of complex input array stored in pm

Results:
    dm(Refft[N])     - Real FFT results ordered sequentially
    dm(Inputreal[N]) - Imaginary FFT results ordered sequentially

Benchmarks:                               	  
	FFT Length          cycles	 	 time (us) 160MHz     
    ----------      -------------    ---------------        
	1024				24160			151

Memory Usage:
    PM code(24-bit) = 92 words 
	PM data(24-bit) = N + 2 + N/2 words 
	DM data(16-bit) = 2N + 4 + N + 1 words

******************************************************************************/

/**********The constants below must be changed for different length FFTs*******

N         			= number of points in the FFT, must be a power of 2
log2N     			= log2(N)
Mod_Value 			= 2^(16-LOG2N)
Refft_Bitrev 		= bitrev addr of output real in dm
Inputreal_Bitrev 	= bitrev addr of output imag in dm

******************************************************************************/

/* Set Constants for N-point FFT */
#define     N           		1024         
#define     Ndiv2	     		(N/2)       
#define     log2N       		10          
#define		Mod_Value			64		
#define		Refft_Bitrev		0x0001  
#define		Inputreal_Bitrev	0x0009 


/* DM data */
.section/data data1;
.VAR     twid_imag [Ndiv2] = "twid_sin.dat";
.VAR     groups = 1;
.VAR     node_space = Ndiv2;

/* DM data */
.section/data seg_buf1;                 
.VAR     Inputreal [N+2] = "inreal.dat";

/* DM data */
.section/data seg_buf2;                 
.VAR     Refft[N+2];              

/* PM data */
.section/pm data2;
.VAR/init24   twid_real [Ndiv2] = "twid_cos.dat";
.VAR   Inputimag [N+2] = "inimag.dat";

/* PM interrupt vector code */
.section/pm IVreset;
        JUMP start; NOP; NOP;     
        

/* Program Code */
.section/pm program;
start: 
    dmpg2 = page(twid_real);			/* Initialize page for PM data */
	M0 = 0;	
	L0 = length(twid_imag);				/* Initialize twid_imag circular buffer */
    AX1 = twid_imag;
    REG(b0) = AX1;						/* Initialize pointer to twid_imag */						
	M1 = 1;							
    L1 = 0;                             /* Initialize for modulo addressing */
	M4 = 0;
    L4 = length(twid_real);				/* Initialize twid_real circular buffer */
    AX1 = twid_real;
    REG(b4) = AX1;						/* Initialize pointer to twid_real */
	M5 = 1;
    L5 = 0; 							/* Initialize for modulo addressing */
    M6 = -1;
    L6 = 0;								/* Initialize for modulo addressing */ 
    L2 = 0; 
    L3 = 0; 
    L7 = 0; 

    CNTR = log2N -1;                    /* Initialize Stage Counter */
    DO stage_loop UNTIL CE;             /* Compute all stages in FFT */
        I0 = twid_imag;              	/* I0 --> (-S) of W0 */
        I1 = Inputreal;                	/* I1 --> x1 in 1st group of stage */
        I2 = Inputreal;                	/* I2 --> x0 in 1st group of stage */
        I4 = twid_real;                 /* I4 --> C of W0 */   
        I5 = Inputimag;                	/* I5 --> y1 in 1st group of stage */
        I6 = Inputimag;                	/* I6 --> y0 in 1st group of stage */
        SI = DM(groups);
        CNTR = SI;                      /* CNTR = # of groups in stage */
        SR = LSHIFT SI BY 1(LO);
        DM(groups) = SR0;                 
        SI = DM(node_space);            /* SI = node_space modifier */
        M2 =SI;							
        M7 =SI; 
        MODIFY(I1,M2);                  /* I1 --> x1 in 1st group of stage */
        MODIFY(I5,M7);                  /* I5 --> y1 in 1st group of stage */
        DO group_loop UNTIL CE;
            MY0 = PM(I4,M5), MX0 = DM(I1,M0); 	/* MY0=C, MX0=x1 */
            MR = MX0*MY0(SS), MX1 = PM(I5,M4); 	/* MR=C*x1,MX1=y1  */
            MY1 = DM(I0,M1);              		/* MY1 = (-S)  */ 
            CNTR = SI;                    		/* CNTR = butterfly counter */
            DO bfly_loop UNTIL CE;
                MR = MR-MX1*MY1(RND), AY0 = DM(I2,M0); 	/* MR=x1*C-y1*-S, AY0=x0 */
                AR = MR1+AY0, AX1 = PM(I5,M5); 		/* AR=x0'=x0+(x1*C-y1*-S) */
                DM(I2,M1) = AR, AR = AY0-MR1; 		/* DM=x0', AR=x1'=x0-(x1*C-y1*(-S)) */
                MR = MX0*MY1(SS), DM(I1,M1) = AR; 	/* MR=x1*(-S), DM=x1' */
                MR = MR+MX1*MY0(RND), AY1 = PM(I6,M4), MX0 = DM(I1,M0); /*MR=x1*(-S)+y1*C, AY1=y0, MX0=next x1*/
                AR = MR1+AY1, MX1 = PM(I5,M6); 		/* AR=y0'=y0+(y1*C+x1*(-S)), MX1= next y1 */
                PM(I6,M5) = AR, AR = AY1-MR1; 		/* PM=y0', AR=y1'=y0-(y1*C+x1*(-S)) */
bfly_loop:      
				MR = MX0*MY0(SS), PM(I5,M5) = AR; 	/* PM=y1' */
            MY0 = PM(I5,M7), MX0 = DM(I1,M2); 		
group_loop:	
			MY0=PM(I6,M7), MX0=DM(I2,M2); 			
        SR=ASHIFT SI BY -1 (LO);					
stage_loop:
        DM(node_space)=SR0;            	

    I0 = twid_imag;                    	/* I0 --> (-S) */
    I1 = Inputreal;                    	/* I1 --> x1 */
    I2 = Inputreal;                    	/* I2 --> x0 */
    M2 = 2; 
    I3 = Refft_Bitrev;            		/* Refft bitreversed */
    M3 = Mod_Value;						/* Bitreversed modifier */
    I4 = twid_real;                     /* I4 --> C  */   
    I5 = Inputimag;                    	/* I5 --> y1 */
    I6 = Inputimag;                    	/* I6 --> y0 */
    M6 = 2;                             
    MODIFY(I1,M1);                      /* I1 -->x1 */
    MODIFY(I5,M5);                      /* I5 -->y1 */
    MY0 = PM(I4,M5), MX0 = DM(I1,M2);   /* MY0=C, MX0=x1 */
    MR = MX0*MY0(SS), MX1 = PM(I5,M6);  /* MR = C*x1, MX1 = y1 */
    MY1 = DM(I0,M1);                    /* MY1 = (-S) */
    CNTR = Ndiv2;                     
    DO last_loop UNTIL CE;
        MR = MR-MX1*MY1(RND), AY0 = DM(I2,M2); /* MR=x1*C-y1*(-S), AY0=x0 */
        AR = MR1+AY0, AY1 = PM(I6,M4);    	/* AR=x0'=x0+(x1*C-y1*(-S)), AY1=y0 */
        ENA BIT_REV; 						
        DM(I3,M3) = AR, AR = AY0-MR1;       /* Read real data */
        MR = MX0*MY1(SS), DM(I3,M3) = AR;   /* Place in sequential order(using bit-reversal) */
        DIS BIT_REV; 						
	    MR = MR+MX1*MY0(RND), MY0 = PM(I4,M5), MX0 = DM(I1,M2); 
        AR = MR1+AY1, MX1 = PM(I5,M6);   	/* AR=y0'=y0+(y1*C+x1*(-S)), MX1= next y1 */
        PM(I6,M5) = AR, AR = AY1-MR1;       /* PM=y0', AR=y1'=y0-(y1*C+x1*(-S)) */
		MY1 = DM(I0,M1);                  	/* MY1 = (-S) */
last_loop:	
        MR = MX0*MY0(SS), PM(I6,M5) = AR;   /*PM=y1' */

    I3 = Inputreal_Bitrev;          
    M3 = Mod_Value;					/* Bitreversed modifier */
    I5 = Inputimag;
    ENA BIT_REV;
    CNTR = N;   
	DO bit_rev_imag UNTIL CE;
		AX0 = PM(I5,M5);            /* Read imaginary data */
bit_rev_imag:	DM(I3,M3) = AX0;    /* Place in sequential order */
	DIS BIT_REV; 					

looping:       JUMP looping;


