/**************************************************************
File Name:	Viterbi.asm
		
Date Modified:	6/23/01		BJM

Description:
			ADSP-2192 single core subroutine that implements the 
			1/2 rate GSM soft decision Viterbi decoder.
			
Assumptions:
			The class 1 bits are encoded with the 1/2 rate convolutional code defined by 
			the polynomials:
				G0 = 1 + D3+ D4
				G1 = 1 + D + D3+ D4

			Encoded outputs are transmitted as signed antipodal analog signals.  They are recieved at 
			the decoder and quantized.  The quantized number is represented in a 2's
			compliment giving the range of -8 to 7.  The process of quantizing a binary analog signal
			with a multi-bit qunatizer is called soft decision.  This soft decision is represented by
			the array 'SOFT_DEC_INPUT'


Registers Affected:
			I0,I1,I2,I3,I4
			M0,M1,M2,M3,M4,M5,M6,M7
			L0,L1,L2,L3,L4
			B1,B3,B4
			AX0,AX1,AY0,AY1
			AR,AF,SR,SI,SE
			MX0

Cycle Count:
			30751 Cycles
Memory Usage:
			Instructions Words (24-bits):
					107 instruction words
			
			Data Words (16 or 24-bits):
				2*N_out = Number of soft decisions (16-bit)
				  N_out = Number of state transitions (16-bit)
				     16 = Number of New and Old metrics (16-bit)
				N_Words = Decoded output of GSM frame (16-bit)
					  8 = Metric Table (16-bit)

Notes: 

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

#define			N_out      189             
#define			N_words		12              
#define			N_mod_16 	13              

/* DM data */
.section/data data1;
.VAR	soft_dec_input[2*N_out] = 	"gsm_rec.dat";
.VAR	state_trans[N_out]; 
.VAR	old_acc_metric[16];
.VAR	new_acc_metric[16];
.VAR	decoded_output[N_words+4];
.VAR	met_table[8]; 			



/* PM interrupt vector code */
.section/pm IVreset;
        JUMP start; NOP; NOP; NOP;      /* Interupt vector table */
       
/* Program memory code */
.section/pm program;
start:  
	I0 = soft_dec_input;				/* Initialize soft_dec_input pointer */
	L0 = 0;                          	/* Initialize for modulo addressing */   
	I1 = old_acc_metric;                /* Initialize old_acc_metric pointer */
	L1 = length(old_acc_metric);   		/* Initialize old_acc_metric circular buffer */
	AX0 = I1;  
	reg(B1) = AX0; 						/* Initialize pointer to old_acc_metric */
	I2 = state_trans; 					/* Initialize state_trans pointer */
	L2 = 0;								/* Initialize for modulo addressing */
    I3 = met_table;                    	/* Initialize met_table pointer */
    L3 = length(met_table);  			/* Initialize met_table circular buffer */
	AX0 = I3;  
	reg(B3) = AX0; 						/* Initialize pointer to met_table */
	I4 = new_acc_metric;               	/* Initialize new_acc_metric pointer */    
    L4 = length(new_acc_metric);   		/* Initialize new_acc_metric circular buffer */
	AX0 = I4;  
	reg(B4) = AX0; 						/* Initialize pointer to new_acc_metric */
    M0 = -8;                            
    M1 = 1;  
    M2 = -16;
    M3 = 0;
	M4 = 8;
	M5 = -7; 
	M6 = -8;
	M7 = -1; 
	SE = 1;                            /* Setup bit shift */
	SI = 0X8000;
	SR0 = 0;
    SR1 = 0;

CNTR = 16;
	DO zero_metric UNTIL CE;
zero_metric:	dm(I1,M1) = M3;                 /* Initialize accumulated metric array */

   	CNTR = N_out;    						/* FOR (k=0; k<N_out; k++) */                   
	DO add_compare UNTIL CE;
        AX0 = dm(I0,M1);               
        AY0 = dm(I0,M1);               
        AR = AX0 + AY0;	
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR, AR = AX0 - AY0; 
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR, AR = -AR;       
        dm(I3,M1) = AR;	           		
        CNTR = 8;								/* FOR (i=0; i<8; i++) */
        DO calc_metric UNTIL CE; 	
            AY0 = dm(I3,M1);            		
            AX1 = dm(I1,M1);            		
            AF = AX1 + AY0, AX0 = dm(I1,M1);	/* AF = old_acc_metric[2*i] + Met_table */
            AR = AX0 - AY0;             		/* AR = old_acc_metric[2*i+1] - Met_table */ 
            SR = LSHIFT SR1 (HI);       		/* State_trans[k] = state_trans[k] << by 1 */
            NONE = AR - AF;             	
            IF GT   SR = SR OR LSHIFT SI (LO); 	/* Then state_trans[k] = state_trans[k]<<1 | 1 */
            IF LT   AR = PASS AF;      			 
	       	dm(I4,M4) = AR, AF = AX1 - AY0; 	/* AF = old_acc_metric[2*i] - Met_table */
            AR = AX0 + AY0;             		/* AR = old_acc_metric[2*i+1] + (-Met_table)  */
            SR = LSHIFT SR1 (HI);       		/* State_trans[k] = state_trans[k] << by 1 */
            NONE = AR - AF;             	
            IF GT    SR = SR OR LSHIFT SI (LO); /* Then state_trans[k] = state_trans[k]<<1 | 1 */
            IF LT    AR = PASS AF;     			
 
 calc_metric: dm(I4,M5) = AR;           /* New_acc_metric[i+2] = AR */

    modify(I4,M6);                      /* Reset I4 to new_acc_metirc */
 	AX1 = I1;                           /* AX1 = old_acc_metric */
	I1 = I4;                            /* Old_acc_metric = new_acc_metric */                          
	AX0 = I1;  
	reg(B1) = AX0;           			/* Initialize pointer to old_acc_metric */
	I4 = AX1;                           /* New_acc_metric = AX1 */    
    reg(B4) = AX1;                      /* Initialize pointer to new_acc_metric */
add_compare:	dm(I2,M1) = SR1;                /* Store state_trans[k] */


	M1 = -1;                           
	I3 = decoded_output + N_words;          	/* Initialize decoded_output + N_words pointer */
    L3 = 0;								/* Initialize for modulo addressing */   
	AY0 = -15;
	AY1 = 15;
	MR0 = N_out - 1;                          
	MR1 = 0;                            
    SI = dm(I2,M1);                     /* Save previous state_trans  */
	AX0 = 0; 
	MX0 = N_mod_16; 						/* First word only has 13 valid bits */
 	CNTR = N_words;
	DO trace_back UNTIL CE;
        CNTR = MX0;
        DO state_bits UNTIL CE; 
	        SR = LSHIFT MR1 by 1(LO);   	/* SR0 = State << 1 */
            AR = CLRBIT 4 OF SR0;
            AX1 = AR; 
            AF = TSTBIT 4 OF SR0; 
            IF NE AR = SETBIT 0 OF AR;
            AR = AR	+ AY0, SI = dm(I2,M1); 	/* Bit_Pos = 15 - rotate(State) */
            SE = AR;                    	
            SR = LSHIFT SI (LO);        	
            AR = TSTBIT 0 OF SR0;			
            AR = AR OR AX1;             	/* AR = state_trans[k] >> Bit_Pos */
            MR2 = AR, AR = MR0 AND AY1;  	
            SR = LSHIFT MR1 by - 3(LO); 	
            SE = AR;                    	
            AR = TSTBIT 0 OF SR0;		
            SI = AR;
            SR = LSHIFT SI (LO);			
            AR = AX0 OR SR0;
            AX0 = AR;
            AR = MR0 -1;                	/* Decoded_output |= ((State & 8) >> 3) << (k & 15) */
            MR0 = AR;
state_bits:
            MR1 = MR2;                  	/* State = new_acc_metric */
        MX0 = 16;                       	
        dm(I3,M1) = AX0;                	
trace_back:
        AX0 = 0;
	
looping:   JUMP looping;     /* Loop upon itself */


