; ; This program originally available on the Motorola DSP bulletin board. ; It is provided under a DISCLAMER OF WARRANTY available from ; Motorola DSP Operation, 6501 Wm. Cannon Drive W., Austin, Tx., 78735. ; ;************************************************************************** ; ; ADPCM.ASM Full-Duplex 32-kbit/s CCITT ADPCM Algorithm ; ; Version 1.0 - 1/27/89 ; Version 1.1 - 9/30/98 MNW, TY (Corrected line 6 of INIT routine) ; ; This program implements the algorithm defined in CCITT Recommendation ; G.721: "32 kbit/s Adaptive Differential Pulse Code Modulation" dated ; August 1986. This version passes all of the mu-law and A-law test ; sequences as defined in Appendix II of Recommendation G.721. ; ; Please refer to the file ADPCM.HLP for further information about ; this program. ; ;************************************************************************** OPT CC,CEX START EQU $0040 ORG X:$0000 ;******************** Encoder variables *********************************** ; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format) I_T DS 1 ;ADPCM codeword ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) DQ_T DS 1 ;Quantized difference signal ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) Y_T DS 1 ;Quantizer scale factor ; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) AP_T DS 1 ;Unlimited speed control parameter ; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM) AL_T DS 1 ;Limited speed control parameter ;******************** Decoder variables *********************************** I_R DS 1 ;ADPCM codeword DQ_R DS 1 ;Quantized difference signal Y_R DS 1 ;Quantizer scale factor AP_R DS 1 ;Unlimited speed control parameter AL_R DS 1 ;Limited speed control parameter ; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format) SP_R DS 1 ;PCM reconstructed signal ;******************** Temporary variables ********************************* ; IMAG = 0iii. 0000 | 0000 0000 | 0000 0000 IMAG DS 1 ;|I| ; PKS1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) PKS1 DS 1 ;XOR of PK0 & PK1 ; PKS2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) PKS2 DS 1 ;XOR of PK0 & PK2 DATAPTR_T DS 1 ;Transmit data buffer pointer DATAPTR_R DS 1 ;Receive data buffer pointer ;******************** Table for quantizing DLN **************************** ; Used in QUAN routine QUANTAB DS 8 ;******************** Table for unquantizing I **************************** ; Used in RECONST IQUANTAB DS 8 ;******************** W(I) lookup table *********************************** ; Used in FUNCTW routine WIBASE DS 8 ;******************** Table used in COMPRESS ****************************** TAB DS 8 ;******************** Constants used by FMULT ***************************** CONST DS 6 ;******************** Encoder data buffer ********************************* ; DQn (11FL) stored separately as exponent, mantissa, and sign ; DQnEXP = 0000 0000 | 0000 0000 | 0000 eeee ; DQnMANT = 01mm mmm0 | 0000 0000 | 0000 0000 ; DQnS = sXXX XXXX | XXXX XXXX | 0000 0000 ; SRn in same format DATA_T DSM 24 ;24 word modulo buffer for data, ; R2 is used as pointer, DATAPTR_T ; points to start of buffer (DQ1EXP) ; at beginning of cycle ;DQ1EXP,DQ1MANT,DQ1S ;DQ2EXP,DQ2MANT,DQ2S ;DQ3EXP,DQ3MANT,DQ3S ;DQ4EXP,DQ4MANT,DQ4S ;DQ5EXP,DQ5MANT,DQ5S ;DQ6EXP,DQ6MANT,DQ6S ;SR1EXP,SR1MANT,SR1S ;SR2EXP,SR2MANT,SR2S ;******************** Encoder partial product buffer ********************** ; WBn = siii iiii | iiii iii.f | 0000 0000 (16TC) ; WAn in same format PP_T DSM 8 ;8 word modulo buffer for partial ; products, R1 is used as pointer ;WB1 ;WB2 ;WB3 ;WB4 ;WB5 ;WB6 ;WA1 ;WA2 ;******************** Decoder data buffer ********************************* DATA_R DSM 24 ;24 word modulo buffer for data ; (same format as DATA_T) ;******************** Decoder partial product buffer ********************** PP_R DSM 8 ;8 word modulo buffer for partial products ; (same format as PP_T) ORG Y:$0000 ;******************** Encoder variables *********************************** ; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC) SE_T DS 1 ;Signal estimate ; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC) SEZ_T DS 1 ;Partial signal estimate ; SR = siii iiii | iiii iiii. | 0000 0000 (16TC) SR_T DS 1 ;Reconstructed signal ; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) PK0_T DS 1 ;Sign of DQ + SEZ ; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) PK1_T DS 1 ;Delayed sign of DQ + SEZ ; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) PK2_T DS 1 ;Delayed sign of DQ + SEZ ; DMS = 0iii. ffff | ffff f000 | 0000 0000 (12SM) DMS_T DS 1 ;Short term average of F(I) ; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) DML_T DS 1 ;Long term average of F(I) ; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC) TDP_T DS 1 ;Tone detect ; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC) TD_T DS 1 ;Delayed tone detect ; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) YU_T DS 1 ;Fast quantizer scale factor ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) YL_T DS 1 ;Slow quantizer scale factor ; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC) SIGPK_T DS 1 ;Sgn[p(k)] flag ; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC) A2P_T DS 1 ;Second order predictor coef ; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC) TR_T DS 1 ;Transition detect ;******************** Decoder variables *********************************** SE_R DS 1 ;Signal estimate SEZ_R DS 1 ;Partial signal estimate SR_R DS 1 ;Reconstructed signal PK0_R DS 1 ;Sign of DQ + SEZ PK1_R DS 1 ;Delayed sign of DQ + SEZ PK2_R DS 1 ;Delayed sign of DQ + SEZ DMS_R DS 1 ;Short term average of F(I) DML_R DS 1 ;Long term average of F(I) TDP_R DS 1 ;Tone detect TD_R DS 1 ;Delayed tone detect YU_R DS 1 ;Fast quantizer scale factor YL_R DS 1 ;Slow quantizer scale factor SIGPK_R DS 1 ;Sgn[p(k)] flag A2P_R DS 1 ;Second order predictor coef TR_R DS 1 ;Transition detect ;******************** Temporary variables ********************************* LAW DS 1 ;Select A-law or mu-law DQMAG DS 1 ;|DQ| ;******************** Shift constant lookup table ************************* ; Shift constants used for doing left or right shifts by multiplying by a ; power of 2. For right shift, some routines use R5 as a base and N5 as ; and offset for lookup of shift constant. RSHFT DS 24 LSHFT ;******************** Misc. constants ************************************* CONST1 DS 3 CONST4 DS 4 CONST8 DS 9 CONST17 DS 16 ;******************** Encoder coef. buffer ******************************** ; Bn = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; An in same format COEF_T DSM 8 ;8 word modulo buffer for coefs., ; R6 is used as pointer ;B1 ;B2 ;B3 ;B4 ;B5 ;B6 ;A1 ;A2 ;******************** Decoder coef. buffer ******************************** COEF_R DSM 8 ;8 locations for coef. queue ; (same format as COEF_T) PAGE ORG P:$0000 JMP START ORG P:START CLR A MOVEC #$06,OMR ;Enable internal ROM tables MOVEP A,X:$FFFE ;Set BCR for 0 wait states JSR INIT ;************************************************************************** ; ; Encoder ; ;************************************************************************** ENCODE MOVE #PP_T,R1 ;Set partial product ptr to WB1 MOVE X:DATAPTR_T,R2 ;Set data pointer to DQ1EXP MOVE #COEF_T,R6 ;Set coef pointer to B1 MOVE #CONST1,R7 ;Set pointer to misc constants ;************************************************************************** ; FMULT ; ; Multiply predictor coefficients with corresponding ; quantized difference signal or reconstructed signal ; ; Data (DQn or SRn) is stored in 11FL format (separate), ; & coefficient (Bn or An) is stored in 16TC format. ; ; Computes [An(k-1) * SR(k-n)] or [Bn(k-1) * DQ(k-n)] ; ; Flow Description: ; 1. Convert 16TC An to 13SM AnMAG ; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT) ; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits) ; 4. Multiply SRnMANT with AnMANT, add '48', and truncate ; to 8-bits to get WAnMANT ; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG ; 6. XOR AnS with SRnS to find WAnS ; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn ; ; Input: ; SRn = (11FL) ; SRnEXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee ; SRnMANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000 ; SRnS = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000 ; (DQ in same format as SR) ; ; An = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; (Bn in same format as An) ; ; Output: ; WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC) ; (WBn in same format as WAn) ; ;************************************************************************** MOVE #CONST,R0 ;Set pointer to FMULT constants MOVE #0,Y1 DO #8,ACCUM_T ;Execute mult 8 times ; 1. Convert 16TC An to 13SM AnMAG MOVE X:(R0)+,X1 Y:(R6),A ;Get An and mask KF1 AND X1,A X:(R0)+,X1 ;Truncate An to 13 bits (An>>2), ; get mask KF2 ABS A #$000D,R4 ;Find AnMAG, load ; exponent bias (13) into R4 AND X1,A #<$7E,X1 ;Truncate any ovrflw, get mask ; A1 = 0i.ff ffff | ffff ff00 | 0000 0000 (A2=A0=0) ; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT) JNE 26, do left shift REP B1 ;Offset>26, shift WAnMANT LSL A ; left up to 4 times JMP $0F,Y0 ;Find |offset|, get '15' CMP Y0,B B1,N5 ;Compare |offset| to '15', ; load offset for shift TGE Y1,A ;If |offset|>=15 WAnMAG=0 MOVE A1,X1 ;Move WAnMANT for shift MOVE Y:(R5+N5),Y0 ;Lookup shift constant MPY Y0,X1,A ;Shift WAnMANT right up to 14 times ; A1 = ?mmm mmmm | mmmm mmmm | ???? ???? (A2=A0=0) TRUNC_T AND X0,A X:(R2)+,X1 Y:(R6)+,B ;Truncate WAnMAG to 15 bits, ; get SRnS & AnS ; A1 = 0iii iiii | iiii iii.f | 0000 0000 (A2=A0=0) NEG A A1,X0 ;Find -WAnMAG, save WAnMAG ; 6. XOR AnS with SRnS to find WAnS ; B1 = sXXX XXXX | XXXX XXXX | 0000 0000 (B2=sign ext, B0=0) ; X1 = sXXX XXXX | XXXX XXXX | 0000 0000 EOR X1,B #CONST,R0 ;Find WAnS (in MSB of B), ; update pointer to constants ; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn TPL X0,A ;If WAnS=0 use WAnMAG, else use -WAnMAG ; A1 = siii iiii | iiii iii.f | 0000 0000 (A2=sign ext, A0=0) MOVE A1,X:(R1)+ ;Save WAn ;************************************************************************** ; ACCUM ; ; Add predictor outputs to form the partial signal estimate ; and the signal estimate ; ; SEZ(k) = [B1(k-1) * DQ(k-1)] + ... + [B6(k-1) * DQ(k-6)] ; = WB1 + WB2 + ... + WB6 ; ; SE(k) = SEZ(k) + [A1(k-1) * SR(k-1)] + [A2(k-1) * SR(k-2)] ; = SEZ + WA1 + WA2 ; ; Inputs: ; WBn & WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC) ; ; Outputs: ; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; ;************************************************************************** ACCUM_T MOVE X:(R1)+,A ;Get WB1 MOVE X:(R1)+,X0 ;Get WB2 ADD X0,A X:(R1)+,X0 ;Accumulate WB1&WB2, get WB3 ADD X0,A X:(R1)+,X0 ;Accumulate WB3, get WB4 ADD X0,A X:(R1)+,X0 ;Accumulate WB4, get WB5 ADD X0,A X:(R1)+,X0 ;Accumulate WB5, get WB6 ADD X0,A X:(R1)+,X0 ;Accumulate WB6 to get SEZI, get WA1 TFR A,B Y:(R7)+,X1 ;Copy SEZI, get mask K1 AND X1,B X:AP_T,Y0 ;Truncate SEZI, get AP ADD X0,A X:(R1)+,X0 ;Accumulate WA1, get WA2 ADD X0,A B1,Y:SEZ_T ;Accumulate WA2 to get SEI, save SEZ AND X1,A #<$20,X0 ;Truncate SEI, get '1' TFR Y0,A A1,Y:SE_T ;Move AP, save SE ;************************************************************************** ; LIMA ; ; Limit speed control parameter ; ; AL(k) = 1 if AP(k-1) > 1 ; = AP(k-1) if AP(k-1) <= 1 ; ; Inputs: ; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM) ; ;************************************************************************** CMP X0,A Y:YL_T,B ;Test AP, get YL TGT X0,A ;If AP>'1' set AL='1' LSL A #<$7F,X0 ;Shift to align radix pt., get mask AND X0,A Y:(R7)+,X0 ;Truncate AL (AP>>2), get mask K2 ;************************************************************************** ; MIX ; ; Form linear combination of fast and slow quantizer ; scale factors ; ; Y(k) = AL(k) * YU(k-1) + [1 - AL(k)] * YL(k-1) ; ; Inputs: ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM) ; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** AND X0,B A,X0 Y:YU_T,A ;Truncate YL (YL>>6), get YU SUB B,A B,Y1 X0,X:AL_T ;Find DIF=YU-YL, save YL, get AL ABS A A,B ;Find DIFM=|DIF|, save DIFS MOVE A1,Y0 MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFM*AL, get mask K3 AND X0,A ;Truncate to find PRODM=(DIFM*AL)>>6 NEG A A1,X0 ;Find -PRODM, save PRODM TST B ;Check DIFS TPL X0,A ;If DIFS=0 PROD=PRODM, ; else PROD=-PRODM ASL A Y1,B ;Line up radix point ADD Y1,A ;Find Y=PROD+(YL>>6) MOVE A,X:Y_T ;Save Y ;************************************************************************** ; ; Input PCM data (S) here. For simulation purposes the Input ; Word from File subroutine on the 56001 ADS board is used. ; ;************************************************************************** MOVE #1,X0 ;Input PCM word (S) JSR $E002 ;************************************************************************** ; EXPAND ; ; Convert A-law or mu-law PCM to uniform PCM (according to ; Recommendation G.711). For further details see Motorola ; application bulletin "Logarithmic/Linear Conversion ; Routines for DSP56000/1". ; ; Input: ; S = psss qqqq | 0000 0000 | 0000 0000 (PCM log format) ; ; Output: ; SL = siii iiii | iiii ii.00 | 0000 0000 (14TC) ; ;************************************************************************** MOVE A,X0 Y:(R7)+,Y1 ;Get shift constant K4 MPY X0,Y1,A Y:(R7)+,X1 ;Shift S to 8 lsb's of A1, get K5 AND X1,A Y:SE_T,B ;Mask off sign of S, get SE ASR B A1,N3 ;sign extend SE, load |S| as offset CMPM Y1,A ;Check sign of S MOVE X:(R3+N3),A ;Lookup |SL| from ROM table JGE >3 & combine with EXP, ; get mask K8 ; A1 = 0eee e.mmm | mmmm 0000 | 0000 0000 (A2=A0=0) ; = 0iii i.fff | ffff 0000 | 0000 0000 (A2=A0=0) ;************************************************************************** ; SUBTB ; ; Scale log version of difference signal by subtracting ; scale factor ; ; DLN = DL - Y ; ; Inputs: ; DL = 0iii i.fff | ffff 0000 | 0000 0000 (11SM) ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Output: ; DLN = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; ;************************************************************************** SUBTB_T AND X0,B #QUANTAB,R0 ;Truncate Y to 11 bits (Y>>2), ; get quantization table base SUB B,A #>QUANTAB+2,X1 ;Find DLN=DL-Y, ; get offset for quan. conversion ;************************************************************************** ; QUAN ; ; Quantize difference signal in log domain ; ; log2|D(k)| - Y(k) | |I(k)| ; ------------------+-------- ; [3.12, + inf) | 7 ; [2.72, 3.12) | 6 ; [2.34, 2.72) | 5 ; [1.91, 2.34) | 4 ; [1.38, 1.91) | 3 ; [0.62, 1.38) | 2 ; [-0.98, 0.62) | 1 ; (- inf, -0.98) | 0 ; ; Inputs: ; DLN = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; DS = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; ; Output: ; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format) ; ;************************************************************************** MOVE X:(R0)+,X0 ;Get quan table value TSTDLN_T CMP X0,A X:(R0)+,X0 ;Compare to DLN JGE =0 (DS=0) convert DQL, ; else DQL<0 (DS=1), set |DQ|=0 TFR Y1,A #<$80,X0 ;Get DQS (MSB of I), get mask AND X0,A #0,B ;Mask off DQS, set |DQ|=0 ; A1 = s000 0000 | 0000 0000 | 0000 0000 (A2=sign ext, A0=0) MOVE B1,Y:DQMAG ;Save DQMAG=|DQ| MOVE (R7)+ ;Adjust constant pointer MOVE (R7)+ JMP >19, get '10' (K10) ; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0) ; B1 = 0000 0000 | 0000 0000 | 0000 iiii. (B2=B0=0) SUB X0,B Y:(R7)+,X0 ;Find DQT shift=DEX-'10', ; get mask K11 JEQ 24 x 2**(YL(k)) ; 0 otherwise ; ; Inputs: ; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) ; ; Output: ; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; ;************************************************************************** MOVE Y:TD_T,A ;Get TD TST A #0,A ;Check TD, set TR=0 JEQ >10), get '1' OR X0,A B,X1 Y:(R7)+,Y1 ;Add implied '1' to YLFRAC, ; get mask K13 MPY Y1,X1,B Y:(R7)+,X0 ;Find YLINT=YL>>15, get '8' (K14) MOVE B1,B ;Adjust sign extension CMP X0,B Y:(R7)+,X0 ;Compare YLINT to '8', get '5' (K15) JGT 8 set maximum THR2 SUB X0,B ;Find YLINT-5 JEQ >1 AND X0,B ;Truncate THR2>>1 ADD B,A #0,X1 ;Find THR2+(THR2>>1) LSR A ;Find (THR2+(THR2>>1)>>1 AND X0,A Y:DQMAG,X0 ;Truncate to find DQTHR, get DQMAG CMP X0,A #<$80,A ;Compare DQMAG to DQTHR, set TR=1 TGT X1,A ;If DQMAG>DQTHR leave TR=1, ; else DQMAG<=DQTHR, set TR=0 SAVETR_T MOVE A1,Y:TR_T ;Save TR ;************************************************************************** ; ADDB ; ; Add quantized difference signal and signal estimate ; to form reconstructed signal ; ; SR(k-n) = SE(k-n) + DQ(k-n) ; ; Inputs: ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) ; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; ; Output: ; SR = siii iiii | iiii iiii. | 0000 0000 (16TC) ; ;************************************************************************** MOVE Y:SE_T,B ;Get SE ASR B X:DQ_T,A ;Sign extend SE to get SEI, get DQS TST A Y:DQMAG,A ;Check DQS, get DQMAG JPL >8 AND X0,A ;Truncate (Bn>>8) NEG A ;Find UBn=ULBn=-(Bn>>8) ADD Y1,A ;Find BnP=Bn+UBn MOVE A1,Y:(R6)+ ;Store BnP to Bn ENDLOOP_T JMP >8, get mask K19 AND X1,B ;Truncate (Bn>>8) NEG B ;Find ULBn=-(Bn>>8) ADD B,A ;Find UBn=UGBn+ULBn ADD Y1,A ;Find BnP=Bn+UBn MOVE A1,Y:(R6)+ ;Store BnP to Bn UPTR_T MOVE (R7)+ ;Adjust constant pointer MOVE (R7)+ ;************************************************************************** ; UPA2 ; ; Update the A2 coefficient of the second order predictor. ; ; A2(k) = [1-(2**-7)] * A2(k-1) ; + (2**-7) * { sgn[P(k)] * sgn[P(k-2)] ; - F[A1(k-1)] * sgn[P(k)] * sgn[P(k-1)] } ; ; F[A1(k)] = 4 * A1 if |A1|<=(2**-1) ; = 2 * sgn(A1) if |A1|>(2**-1) ; ; Inputs: ; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; A2 = Y:(R6+1) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; (Note: PKS1 & PKS2 have been previously calculated) ; ; Outputs: ; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** UPA2_T MOVE X:PKS2,A ;Get PKS2=PK0**PK2 TST A #<$10,Y0 ;Check PKS2, get '+1' MOVE #<$F0,Y1 ;Get '-1' TPL Y0,A ;If PKS2=0, set UGA2A='+1' TMI Y1,A ;If PKS2=1, set UGA2A='-1' MOVE A,X1 Y:(R6)+,A ;Save UGA2A, get A1 MOVE Y:(R7)+,Y0 ;Get '+1.99' (K20) CMP Y0,A Y:(R7)+,Y1 ;Check A1, get '-1.99' (K21) TGT Y0,A ;If A1>=1/2, set FA1='1.99' CMP Y1,A X:PKS1,B ;Check A1 again, get PKS1=PK0**PK1 TLT Y1,A ;If A1<=-1/2, set FA1='-1.99' TST B #0,X0 ;Check PKS1 JMI >7, get mask K22 AND X1,A Y:SIGPK_T,B ;Truncate UGA2, get SIGPK TST B Y:(R6),Y0 ;Check SIGPK, get A2 TMI X0,A ;If SIGPK=1, set UGA2=0 MOVE Y:RSHFT+7,X0 ;Get shift constant MPY Y0,X0,B ;Find A2>>7 AND X1,B ;Truncate to find A2>>7 NEG B #<$D0,X0 ;Find ULA2=-(A2>>7), get A2LL ADD B,A #<$30,X1 ;Find UA2=UGA2+ULA2, get A2UL ADD Y0,A Y:(R7)+,Y1 ;Find A2T=A2+UA2, get -gain (K23) ;************************************************************************** ; LIMC ; ; Limit the A2 coefficient of the second order predictor. ; ; |A2(k)| <= '0.75' ; ; Inputs: ; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ; Outputs: ; A2P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** CMP X0,A Y:(R7)+,Y0 ;Check A2P, get +gain (K24) TLT X0,A ;If A2P<-0.75, set A2P=-0.75 CMP X1,A X:PKS1,B ;Check A2P again, get PKS1=PK0**PK1 TGT X1,A ;If A2P>0.75, set A2P=0.75 MOVE A,Y:A2P_T ;Save A2P MOVE A,Y:(R6)- ;Save A2P to A2 ;************************************************************************** ; UPA1 ; ; Update the A1 coefficient of the second order predictor. ; ; A1(k) = [1-(2**-8)] * A1(k-1) ; + 3 * (2**-8) * sgn[P(k)] * sgn[P(k-1)] ; ; Inputs: ; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; SIGPK = Y:(R0) = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; (Note: PKS1 has been previously calculated) ; ; Outputs: ; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** TST B Y:SIGPK_T,B ;Check PKS1, get SIGPK TPL Y0,A ;If PKS=0, set UGA1=+gain TMI Y1,A ;If PKS=1, set UGA1=-gain TST B #0,X0 ;Check SIGPK TMI X0,A ;If SIGPK=1, set UGA1=0 MOVE Y:(R6),X1 ;Get A1 MOVE Y:RSHFT+8,Y0 ;Get shift constant MPY Y0,X1,B Y:(R7)+,X0 ;Find A1>>8, get mask K25 AND X0,B ;Truncate (A1>>8) NEG B ;Find ULA1=-(A1>>8) ADD B,A #<$3C,B ;Find UA1=UGA1+ULA1, ; get OME='1-(2**-4)' ADD X1,A Y:A2P_T,X0 ;Find A1T=A1+UA1, get A2P ;************************************************************************** ; LIMD ; ; Limit the A1 coefficient of the second order predictor. ; ; |A1(k)| <= [1-(2**-4)] - A2(k) ; ; Inputs: ; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ; Outputs: ; A1P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** SUB X0,B ;Find A1UL=OME-A2P CMP B,A B,X0 ;Check A1T TGT X0,A ;If A1T>A1UL, set A1P=A1UL NEG B (R2)+ ;Find A1LL=-A1UL=A2P-OME CMP B,A B,X0 ;Check A1T again TLT X0,A ;If A1T>5, get mask K27 AND X0,A Y:DML_T,Y1 ;Truncate DIFSX, get DML ADD Y0,A Y:RSHFT+7,X1 ;Find DMSP=DIFSX+DMS ;************************************************************************** ; FILTB ; ; Update long term average of F(I) ; ; DML(k) = (1 - 2**(-7)) * DML(k-1) + 2**(-7) * F[I(k)] ; ; Inputs: ; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM) ; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; ; Output: ; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; ;************************************************************************** SUB Y1,B A1,Y:DMS_T ;Find DIF=FI-DML MOVE B1,X0 MPY X0,X1,B Y:(R7)+,X0 ;Find DFISX=DIF>>7, get mask K28 AND X0,B ;Truncate DIFSX ADD Y1,B Y:RSHFT+3,X1 ;Find DMLP=DIFSX+DML ;************************************************************************** ; SUBTC ; ; Compute magnitude of the difference of short and long ; term functions of quantizer output sequence and then ; perform threshold comparison for quantizing speed control ; parameter. ; ; AX = 1 if Y(k)>=3, TD(k)=1, & |DMS(k)-DML(k)|>(2**-3)*DML(k) ; = 0 otherwise ; ; Input: ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM) ; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; ; Output: ; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM) ; ;************************************************************************** SUB B,A B1,Y:DML_T ;Find DIF=DMSP-DMLP, save DML ABS A B1,Y0 ;Find DIFM=|DIF| MPY X1,Y0,B #<$18,Y0 ;Find DTHR=DMLP>>3, get '3' AND X0,B #<$40,X0 ;Truncate DTHR, get '1' CMP B,A #0,B ;Compare DIFM & DTHR, set AX=0 TGE X0,B ;If DIFM>=DTHR set AX=1 MOVE Y:TDP_T,A ;Get TDP TST A X:Y_T,A ;Check TDP, get Y TNE X0,B ;If TDP!=0 set AX=1 CMP Y0,A X:AP_T,X1 ;Check for Y<"3", get AP TLT X0,B ;If Y<"3" set AX=1 ;************************************************************************** ; FILTC ; ; Low pass filter of speed control parameter ; ; AP(k) = (1-2**(-4)) * AP(k-1) + AX ; ; Inputs: ; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM) ; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ;************************************************************************** SUB X1,B Y:RSHFT+4,Y0 ;Find DIF=AX-AP MOVE B1,X0 MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFSX=DIF>>4, get K29 AND X0,A Y:TR_T,B ;Truncate DIFSX, get TR ADD X1,A #<$20,X0 ;Find APP=DIFSX+AP, get '1' ;************************************************************************** ; TRIGA ; ; Speed control trigger block ; ; AP(k) = AP(k) if TR(k)=0 ; = 1 if TR(k)=1 ; ; Inputs: ; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; APR = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ;************************************************************************** TST B X:IMAG,X1 ;Check TR, get IMAG TMI X0,A ;If TR=1 set APR=1, else APR=APP MOVE A1,X:AP_T ;Save APR to AP ;************************************************************************** ; FUNCTW ; ; Map quantizer output into logarithmic version of scale ; factor multiplier ; ; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ; ---------+-----+-----+-----+-----+-----+-----+-----+-----+ ; W(I) |70.13|22.19|12.38| 7.00| 4.00| 2.56| 1.13|-0.75| ; ; Inputs: ; I = siii. 0000 | 0000 0000 | 0000 0000 (ADPCM format) ; ; Outputs: ; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC) ; ;************************************************************************** MOVE Y:RSHFT+20,X0 ;Get shift constant MPY X0,X1,A #WIBASE,R0 ;Shift IM=IMAG for lookup, ; load lookup table base MOVE A1,N0 ;Load IM as offset MOVE Y:RSHFT+3,X1 ;Get shift constant MOVE X:Y_T,Y0 ;Get Y MPY Y0,X1,B X:(R0+N0),A ;Shift Y>>3, ; get WI from lookup table ;************************************************************************** ; FILTD ; ; Update of fast quantizer scale factor ; ; YU(k) = (1 - 2**(-5)) * Y(k) + 2**(-5) * W[I(k)] ; ; Inputs: ; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC) ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** SUB B,A ;Find DIF=WI-Y ASR A ;Find DIFSX=DIF>>5 (actually DIF>>2) ASR A Y:(R7)+,X0 ;Get mask K30 AND X0,A ;Truncate DIFSX ADD Y0,A #<$50,X0 ;Find YUT=DIFSX+Y, ; get upper limit '10' ;************************************************************************** ; LIMB ; ; Limit quantizer scale factor ; ; 1.06 <= YU(k) <= 10.00 ; ; Inputs: ; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** CMP X0,A Y:(R7)+,X1 ;Check for YU>10, ; get lower limit '1.06' (K31) TGT X0,A ;If YU>10 set YU=10 CMP X1,A Y:YL_T,Y1 ;Check for YU<1.06, get YL TLT X1,A ;If YU<1.06 set YU=1.06 ;************************************************************************** ; FILTE ; ; Update of slow quantizer scale factor ; ; YL(k) = (1 - 2**(-6)) * YL(k-1) + 2**(-6) * YU(k) ; ; Inputs: ; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; ; Outputs: ; YLP = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; ;************************************************************************** TFR Y1,B A1,Y:YU_T ;Move YL, save YUP NEG B Y:(R7)+,Y0 ;Find -YL, save YL, get mask K32 AND Y0,B ;Truncate -YL (-YL>>6) ADD B,A Y:RSHFT+6,Y0 ;Find DIF=YUP+(-YL>>6) MOVE A1,X1 MPY Y0,X1,A ;Find DIFSX>>6 ADD Y1,A R2,X:DATAPTR_T ;Find YLP=DIFSX+YL, ; save transmit data pointer MOVE A1,Y:YL_T ;Save YL ;************************************************************************** ; ; Decoder ; ;************************************************************************** DECODE MOVE #PP_R,R1 ;Set partial product ptr to WB1 MOVE X:DATAPTR_R,R2 ;Set data pointer to DQ1EXP MOVE #COEF_R,R6 ;Set coef pointer to B1 MOVE #CONST1,R7 ;Set pointer to misc constants ;************************************************************************** ; FMULT ; ; Multiply predictor coefficients with corresponding ; quantized difference signal or reconstructed signal ; ; Data (DQn or SRn) is stored in 11FL format (separate), ; & coefficient (Bn or An) is stored in 16TC format. ; ; Computes [An(k-1) * SR(k-n)] or [Bn(k-1) * DQ(k-n)] ; ; Flow Description: ; 1. Convert 16TC An to 13SM AnMAG ; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT) ; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits) ; 4. Multiply SRnMANT with AnMANT, add '48', and truncate ; to 8-bits to get WAnMANT ; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG ; 6. XOR AnS with SRnS to find WAnS ; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn ; ; Input: ; SRn = (11FL) ; SRnEXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee ; SRnMANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000 ; SRnS = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000 ; (DQ in same format as SR) ; ; An = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; (Bn in same format as An) ; ; Output: ; WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC) ; (WBn in same format as WAn) ; ;************************************************************************** MOVE #CONST,R0 ;Set pointer to FMULT constants MOVE #0,Y1 DO #8,ACCUM_R ;Execute mult 8 times ; 1. Convert 16TC An to 13SM AnMAG MOVE X:(R0)+,X1 Y:(R6),A ;Get An and mask KF1 AND X1,A X:(R0)+,X1 ;Truncate An to 13 bits (An>>2), ; get mask KF2 ABS A #$000D,R4 ;Find AnMAG, load ; exponent bias (13) into R4 AND X1,A #<$7E,X1 ;Truncate any ovrflw, get mask ; A1 = 0i.ff ffff | ffff ff00 | 0000 0000 (A2=A0=0) ; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT) JNE 26, do left shift REP B1 ;Offset>26, shift WAnMANT LSL A ; left up to 4 times JMP $0F,Y0 ;Find |offset|, get '15' CMP Y0,B B1,N5 ;Compare |offset| to '15', ; load offset for shift TGE Y1,A ;If |offset|>=15 WAnMAG=0 MOVE A1,X1 ;Move WAnMANT for shift MOVE Y:(R5+N5),Y0 ;Lookup shift constant MPY Y0,X1,A ;Shift WAnMANT right up to 14 times ; A1 = ?mmm mmmm | mmmm mmmm | ???? ???? (A2=A0=0) TRUNC_R AND X0,A X:(R2)+,X1 Y:(R6)+,B ;Truncate WAnMAG to 15 bits, ; get SRnS & AnS ; A1 = 0iii iiii | iiii iii.f | 0000 0000 (A2=A0=0) NEG A A1,X0 ;Find -WAnMAG, save WAnMAG ; 6. XOR AnS with SRnS to find WAnS ; B1 = sXXX XXXX | XXXX XXXX | 0000 0000 (B2=sign ext, B0=0) ; X1 = sXXX XXXX | XXXX XXXX | 0000 0000 EOR X1,B #CONST,R0 ;Find WAnS (in MSB of B), ; update pointer to constants ; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn TPL X0,A ;If WAnS=0 use WAnMAG, else use -WAnMAG ; A1 = siii iiii | iiii iii.f | 0000 0000 (A2=sign ext, A0=0) MOVE A1,X:(R1)+ ;Save WAn ;************************************************************************** ; ACCUM ; ; Add predictor outputs to form the partial signal estimate ; and the signal estimate ; ; SEZ(k) = [B1(k-1) * DQ(k-1)] + ... + [B6(k-1) * DQ(k-6)] ; = WB1 + WB2 + ... + WB6 ; ; SE(k) = SEZ(k) + [A1(k-1) * SR(k-1)] + [A2(k-1) * SR(k-2)] ; = SEZ + WA1 + WA2 ; ; Inputs: ; WBn & WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC) ; ; Outputs: ; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; ;************************************************************************** ACCUM_R MOVE X:(R1)+,A ;Get WB1 MOVE X:(R1)+,X0 ;Get WB2 ADD X0,A X:(R1)+,X0 ;Accumulate WB1&WB2, get WB3 ADD X0,A X:(R1)+,X0 ;Accumulate WB3, get WB4 ADD X0,A X:(R1)+,X0 ;Accumulate WB4, get WB5 ADD X0,A X:(R1)+,X0 ;Accumulate WB5, get WB6 ADD X0,A X:(R1)+,X0 ;Accumulate WB6 to get SEZI, get WA1 TFR A,B Y:(R7)+,X1 ;Copy SEZI, get mask K1 AND X1,B X:AP_R,Y0 ;Truncate SEZI, get AP ADD X0,A X:(R1)+,X0 ;Accumulate WA1, get WA2 ADD X0,A B1,Y:SEZ_R ;Accumulate WA2 to get SEI, save SEZ AND X1,A #<$20,X0 ;Truncate SEI, get '1' TFR Y0,A A1,Y:SE_R ;Move AP, save SE ;************************************************************************** ; LIMA ; ; Limit speed control parameter ; ; AL(k) = 1 if AP(k-1) > 1 ; = AP(k-1) if AP(k-1) <= 1 ; ; Inputs: ; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM) ; ;************************************************************************** CMP X0,A Y:YL_R,B ;Test AP, get YL TGT X0,A ;If AP>'1' set AL='1' LSL A #<$7F,X0 ;Shift to align radix pt., get mask AND X0,A Y:(R7)+,X0 ;Truncate AL (AP>>2), get mask K2 ;************************************************************************** ; MIX ; ; Form linear combination of fast and slow quantizer ; scale factors ; ; Y(k) = AL(k) * YU(k-1) + [1 - AL(k)] * YL(k-1) ; ; Inputs: ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM) ; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** AND X0,B A,X0 Y:YU_R,A ;Truncate YL (YL>>6), get YU SUB B,A B,Y1 X0,X:AL_R ;Find DIF=YU-YL, save YL, get AL ABS A A,B ;Find DIFM=|DIF|, save DIFS MOVE A1,Y0 MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFM*AL, get mask K3 AND X0,A ;Truncate to find PRODM=(DIFM*AL)>>6 NEG A A1,X0 ;Find -PRODM, save PRODM TST B ;Check DIFS TPL X0,A ;If DIFS=0 PROD=PRODM, ; else PROD=-PRODM ASL A Y1,B ;Line up radix point ADD Y1,A ;Find Y=PROD+(YL>>6) MOVE A,X:Y_R ;Save Y ;************************************************************************** ; ; Input ADPCM data (I) here. For simulation purposes the Input ; Word from File subroutine on the 56001 ADS board is used. ; ;************************************************************************** MOVE #2,X0 ;Input ADPCM word (I) JSR $E002 ;************************************************************************** ; RECONST ; ; Reconstruct quantized difference signal in the log domain ; ; |I(k)| | log2|DQ(k)| - Y(k) ; --------+------------------- ; 7 | 3.32 ; 6 | 2.91 ; 5 | 2.52 ; 4 | 2.13 ; 3 | 1.66 ; 2 | 1.05 ; 1 | 0.031 ; 0 | - inf ; ; Inputs: ; I = iiii 0000 | 0000 0000 | 0000 0000 (ADPCM format) ; ; Output: ; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC) ; ;************************************************************************** MOVE #<$F0,X1 MOVE A,Y1 A,X:I_R ;Save DQS (sign of I) to Y1 EOR X1,A Y:RSHFT+20,Y0 ;Invert bits of I TMI Y1,A ;If ^IS=1, use I, else use ^I ; A1 = 0iii 0000 | 0000 0000 | 0000 0000 (A2=?, A0=0) MOVE A1,X0 MOVE A1,X:IMAG ;Save |I| MPY X0,Y0,A #IQUANTAB,R4 ;Shift IMAG>>20 ; A1 = 0000 0000 | 0000 0000 | 0000 0iii (A2=A0=0) MOVE A1,N4 ;Load IMAG as offset MOVE X:Y_R,B ; into IQUAN table, get Y MOVE #CONST8,R7 ;Adjust constant pointer MOVE X:(R4+N4),A ;Lookup DQLN ;************************************************************************** ; ADDA ; ; Add scale factor to log version of quantized difference ; signal ; ; DQL = DQLN + Y ; ; Inputs: ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; ; Output: ; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; ;************************************************************************** MOVE Y:(R7)+,Y0 ;Get mask K8 for ADDA AND Y0,B Y:(R7)+,X0 ;Truncate Y to 11 bits (Y<<2), ; get mask K9 ADD B,A #<$08,X1 ;Find DQL=DQLN+(Y<<2), get '1' ;************************************************************************** ; ANTILOG ; ; Convert quantized difference signal from log to linear ; domain ; ; Input: ; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC) ; ; Outputs: ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) ; ;************************************************************************** JPL =0 (DS=0) convert DQL, ; else DQL<0 (DS=1), set |DQ|=0 TFR Y1,A #<$80,X0 ;Get DQS (MSB of I), get mask AND X0,A #0,B ;Mask off DQS, set |DQ|=0 ; A1 = s000 0000 | 0000 0000 | 0000 0000 (A2=sign ext, A0=0) MOVE B1,Y:DQMAG ;Save DQMAG=|DQ| MOVE (R7)+ ;Adjust constant pointer MOVE (R7)+ JMP >19, get '10' (K10) ; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0) ; B1 = 0000 0000 | 0000 0000 | 0000 iiii. (B2=B0=0) SUB X0,B Y:(R7)+,X0 ;Find DQT shift=DEX-'10', ; get mask K11 JEQ 24 x 2**(YL(k)) ; 0 otherwise ; ; Inputs: ; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) ; ; Output: ; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; ;************************************************************************** MOVE Y:TD_R,A ;Get TD TST A #0,A ;Check TD, set TR=0 JEQ >10), get '1' OR X0,A B,X1 Y:(R7)+,Y1 ;Add implied '1' to YLFRAC, ; get mask K13 MPY Y1,X1,B Y:(R7)+,X0 ;Find YLINT=YL>>15, get '8' (K14) MOVE B1,B ;Adjust sign extension CMP X0,B Y:(R7)+,X0 ;Compare YLINT to '8', get '5' (K15) JGT 8 set maximum THR2 SUB X0,B ;Find YLINT-5 JEQ >1 AND X0,B ;Truncate THR2>>1 ADD B,A #0,X1 ;Find THR2+(THR2>>1) LSR A ;Find (THR2+(THR2>>1)>>1 AND X0,A Y:DQMAG,X0 ;Truncate to find DQTHR, get DQMAG CMP X0,A #<$80,A ;Compare DQMAG to DQTHR, set TR=1 TGT X1,A ;If DQMAG>DQTHR leave TR=1, ; else DQMAG<=DQTHR, set TR=0 SAVETR_R MOVE A1,Y:TR_R ;Save TR ;************************************************************************** ; ADDB ; ; Add quantized difference signal and signal estimate ; to form reconstructed signal ; ; SR(k-n) = SE(k-n) + DQ(k-n) ; ; Inputs: ; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM) ; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC) ; ; Output: ; SR = siii iiii | iiii iiii. | 0000 0000 (16TC) ; ;************************************************************************** MOVE Y:SE_R,B ;Get SE ASR B X:DQ_R,A ;Sign extend SE to get SEI, get DQS TST A Y:DQMAG,A ;Check DQS, get DQMAG JPL >8 AND X0,A ;Truncate (Bn>>8) NEG A ;Find UBn=ULBn=-(Bn>>8) ADD Y1,A ;Find BnP=Bn+UBn MOVE A1,Y:(R6)+ ;Store BnP to Bn ENDLOOP_R JMP >8, get mask K19 AND X1,B ;Truncate (Bn>>8) NEG B ;Find ULBn=-(Bn>>8) ADD B,A ;Find UBn=UGBn+ULBn ADD Y1,A ;Find BnP=Bn+UBn MOVE A1,Y:(R6)+ ;Store BnP to Bn UPTR_R MOVE (R7)+ ;Adjust constant pointer MOVE (R7)+ ;************************************************************************** ; UPA2 ; ; Update the A2 coefficient of the second order predictor. ; ; A2(k) = [1-(2**-7)] * A2(k-1) ; + (2**-7) * { sgn[P(k)] * sgn[P(k-2)] ; - F[A1(k-1)] * sgn[P(k)] * sgn[P(k-1)] } ; ; F[A1(k)] = 4 * A1 if |A1|<=(2**-1) ; = 2 * sgn(A1) if |A1|>(2**-1) ; ; Inputs: ; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; A2 = Y:(R6+1) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; (Note: PKS1 & PKS2 have been previously calculated) ; ; Outputs: ; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** UPA2_R MOVE X:PKS2,A ;Get PKS2=PK0**PK2 TST A #<$10,Y0 ;Check PKS2, get '+1' MOVE #<$F0,Y1 ;Get '-1' TPL Y0,A ;If PKS2=0, set UGA2A='+1' TMI Y1,A ;If PKS2=1, set UGA2A='-1' MOVE A,X1 Y:(R6)+,A ;Save UGA2A, get A1 MOVE Y:(R7)+,Y0 ;Get '+1.99' (K20) CMP Y0,A Y:(R7)+,Y1 ;Check A1, get '-1.99' (K21) TGT Y0,A ;If A1>=1/2, set FA1='1.99' CMP Y1,A X:PKS1,B ;Check A1 again, get PKS1=PK0**PK1 TLT Y1,A ;If A1<=-1/2, set FA1='-1.99' TST B #0,X0 ;Check PKS1 JMI >7, get mask K22 AND X1,A Y:SIGPK_R,B ;Truncate UGA2, get SIGPK TST B Y:(R6),Y0 ;Check SIGPK, get A2 TMI X0,A ;If SIGPK=1, set UGA2=0 MOVE Y:RSHFT+7,X0 ;Get shift constant MPY Y0,X0,B ;Find A2>>7 AND X1,B ;Truncate to find A2>>7 NEG B #<$D0,X0 ;Find ULA2=-(A2>>7), get A2LL ADD B,A #<$30,X1 ;Find UA2=UGA2+ULA2, get A2UL ADD Y0,A Y:(R7)+,Y1 ;Find A2T=A2+UA2, get -gain (K23) ;************************************************************************** ; LIMC ; ; Limit the A2 coefficient of the second order predictor. ; ; |A2(k)| <= '0.75' ; ; Inputs: ; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ; Outputs: ; A2P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** CMP X0,A Y:(R7)+,Y0 ;Check A2P, get +gain (K24) TLT X0,A ;If A2P<-0.75, set A2P=-0.75 CMP X1,A X:PKS1,B ;Check A2P again, get PKS1=PK0**PK1 TGT X1,A ;If A2P>0.75, set A2P=0.75 MOVE A,Y:A2P_R ;Save A2P MOVE A,Y:(R6)- ;Save A2P to A2 ;************************************************************************** ; UPA1 ; ; Update the A1 coefficient of the second order predictor. ; ; A1(k) = [1-(2**-8)] * A1(k-1) ; + 3 * (2**-8) * sgn[P(k)] * sgn[P(k-1)] ; ; Inputs: ; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; SIGPK = Y:(R0) = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; (Note: PKS1 has been previously calculated) ; ; Outputs: ; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** TST B Y:SIGPK_R,B ;Check PKS1, get SIGPK TPL Y0,A ;If PKS=0, set UGA1=+gain TMI Y1,A ;If PKS=1, set UGA1=-gain TST B #0,X0 ;Check SIGPK TMI X0,A ;If SIGPK=1, set UGA1=0 MOVE Y:(R6),X1 ;Get A1 MOVE Y:RSHFT+8,Y0 ;Get shift constant MPY Y0,X1,B Y:(R7)+,X0 ;Find A1>>8, get mask K25 AND X0,B ;Truncate (A1>>8) NEG B ;Find ULA1=-(A1>>8) ADD B,A #<$3C,B ;Find UA1=UGA1+ULA1, ; get OME='1-(2**-4)' ADD X1,A Y:A2P_R,X0 ;Find A1T=A1+UA1, get A2P ;************************************************************************** ; LIMD ; ; Limit the A1 coefficient of the second order predictor. ; ; |A1(k)| <= [1-(2**-4)] - A2(k) ; ; Inputs: ; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ; Outputs: ; A1P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC) ; ;************************************************************************** SUB X0,B ;Find A1UL=OME-A2P CMP B,A B,X0 ;Check A1T TGT X0,A ;If A1T>A1UL, set A1P=A1UL NEG B (R2)+ ;Find A1LL=-A1UL=A2P-OME CMP B,A B,X0 ;Check A1T again TLT X0,A ;If A1T>5, get mask K27 AND X0,A Y:DML_R,Y1 ;Truncate DIFSX, get DML ADD Y0,A Y:RSHFT+7,X1 ;Find DMSP=DIFSX+DMS ;************************************************************************** ; FILTB ; ; Update long term average of F(I) ; ; DML(k) = (1 - 2**(-7)) * DML(k-1) + 2**(-7) * F[I(k)] ; ; Inputs: ; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM) ; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; ; Output: ; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; ;************************************************************************** SUB Y1,B A1,Y:DMS_R ;Find DIF=FI-DML MOVE B1,X0 MPY X0,X1,B Y:(R7)+,X0 ;Find DFISX=DIF>>7, get mask K28 AND X0,B ;Truncate DIFSX ADD Y1,B Y:RSHFT+3,X1 ;Find DMLP=DIFSX+DML ;************************************************************************** ; SUBTC ; ; Compute magnitude of the difference of short and long ; term functions of quantizer output sequence and then ; perform threshold comparison for quantizing speed control ; parameter. ; ; AX = 1 if Y>=3, TDP=1, & |DMSP-DMLP|>(2**-3)*DMLP ; = 0 otherwise ; ; Input: ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM) ; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM) ; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; ; Output: ; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM) ; ;************************************************************************** SUB B,A B1,Y:DML_R ;Find DIF=DMSP-DMLP, save DML ABS A B1,Y0 ;Find DIFM=|DIF| MPY X1,Y0,B #<$18,Y0 ;Find DTHR=DMLP>>3, get '3' AND X0,B #<$40,X0 ;Truncate DTHR, get '1' CMP B,A #0,B ;Compare DIFM & DTHR, set AX=0 TGE X0,B ;If DIFM>=DTHR set AX=1 MOVE Y:TDP_R,A ;Get TDP TST A X:Y_R,A ;Check TDP, get Y TNE X0,B ;If TDP!=0 set AX=1 CMP Y0,A X:AP_R,X1 ;Check for Y<"3", get AP TLT X0,B ;If Y<"3" set AX=1 ;************************************************************************** ; FILTC ; ; Low pass filter of speed control parameter ; ; AP(k) = (1-2**(-4)) * AP(k-1) + AX ; ; Inputs: ; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM) ; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ;************************************************************************** SUB X1,B Y:RSHFT+4,Y0 ;Find DIF=AX-AP MOVE B1,X0 MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFSX=DIF>>4, get K29 AND X0,A Y:TR_R,B ;Truncate DIFSX, get TR ADD X1,A #<$20,X0 ;Find APP=DIFSX+AP, get '1' ;************************************************************************** ; TRIGA ; ; Speed control trigger block ; ; AP(k) = AP(k) if TR(k)=0 ; = 1 if TR(k)=1 ; ; Inputs: ; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC) ; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ; Outputs: ; APR = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM) ; ;************************************************************************** TST B X:IMAG,X1 ;Check TR, get IMAG TMI X0,A ;If TR=1 set APR=1, else APR=APP MOVE A1,X:AP_R ;Save APR to AP ;************************************************************************** ; FUNCTW ; ; Map quantizer output into logarithmic version of scale ; factor multiplier ; ; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ; ---------+-----+-----+-----+-----+-----+-----+-----+-----+ ; W(I) |70.13|22.19|12.38| 7.00| 4.00| 2.56| 1.13|-0.75| ; ; Inputs: ; I = siii. 0000 | 0000 0000 | 0000 0000 (ADPCM format) ; ; Outputs: ; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC) ; ;************************************************************************** MOVE Y:RSHFT+20,X0 ;Get shift constant MPY X0,X1,A #WIBASE,R0 ;Shift IM=IMAG for lookup, ; load lookup table base MOVE A1,N0 ;Load IM as offset MOVE Y:RSHFT+3,X1 ;Get shift constant MOVE X:Y_R,Y0 ;Get Y MPY Y0,X1,B X:(R0+N0),A ;Shift Y>>3, ; get WI from lookup table ;************************************************************************** ; FILTD ; ; Update of fast quantizer scale factor ; ; YU(k) = (1 - 2**(-5)) * Y(k) + 2**(-5) * W[I(k)] ; ; Inputs: ; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC) ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** SUB B,A ;Find DIF=WI-Y ASR A ;Find DIFSX=DIF>>5 (actually DIF>>2) ASR A Y:(R7)+,X0 ;Get mask K30 AND X0,A ;Truncate DIFSX ADD Y0,A #<$50,X0 ;Find YUT=DIFSX+Y, ; get upper limit '10' ;************************************************************************** ; LIMB ; ; Limit quantizer scale factor ; ; 1.06 <= YU(k) <= 10.00 ; ; Inputs: ; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Outputs: ; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ;************************************************************************** CMP X0,A Y:(R7)+,X1 ;Check for YU>10, ; get lower limit '1.06' (K31) TGT X0,A ;If YU>10 set YU=10 CMP X1,A Y:YL_R,Y1 ;Check for YU<1.06, get YL TLT X1,A ;If YU<1.06 set YU=1.06 ;************************************************************************** ; FILTE ; ; Update of slow quantizer scale factor ; ; YL(k) = (1 - 2**(-6)) * YL(k-1) + 2**(-6) * YU(k) ; ; Inputs: ; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; ; Outputs: ; YLP = 0iii i.fff | ffff ffff | ffff 0000 (19SM) ; ;************************************************************************** TFR Y1,B A1,Y:YU_R ;Move YL, save YUP NEG B Y:(R7)+,Y0 ;Find -YL, save YL, get mask K32 AND Y0,B #CONST4,R7 ;Truncate -YL (-YL>>6), ; adjust constant pointer ADD B,A Y:RSHFT+6,Y0 ;Find DIF=YUP+(-YL>>6) MOVE A1,X1 MPY Y0,X1,A #$002100,Y0 ;Find DIFSX>>6, get bias ADD Y1,A Y:LAW,B ;Find YLP=DIFSX+YL MOVE A1,Y:YL_R ;Save YL ;************************************************************************** ; COMPRESS ; ; Convert from uniform PCM to A-law or mu-law PCM (according to ; Recommendation G.711). For further details see Motorola ; application bulletin "Logarithmic/Linear Conversion ; Routines for DSP56000/1". ; ; Input: ; SR = siii iiii | iiii iiii. | 0000 0000 (16TC) ; ; Output: ; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format) ; ;************************************************************************** TST B Y:SR_R,A ;Adjust constant pointer JNE >3 & combine with EXP, ; get mask K8 ; A1 = 0eee e.mmm | mmmm 0000 | 0000 0000 (A2=A0=0) ; = 0iii i.fff | ffff 0000 | 0000 0000 (A2=A0=0) ;************************************************************************** ; SUBTB ; ; Scale log version of difference signal by subtracting ; scale factor ; ; DLNX = DLX - Y ; ; Inputs: ; DLX = 0iii i.fff | ffff 0000 | 0000 0000 (11SM) ; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM) ; ; Output: ; DLNX = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; ;************************************************************************** SUBTB_R AND X0,B #QUANTAB,R0 ;Truncate Y to 11 bits (Y>>2), ; get quantization table base SUB B,A #>QUANTAB+2,X1 ;Find DLNX=DLX-Y ;************************************************************************** ; SYNC ; ; Re-encode output PCM sample in decoder for synchronous ; tandem coding ; ; Inputs: ; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format) ; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format) ; DLNX = siii i.fff | ffff 0000 | 0000 0000 (12TC) ; DSX = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC) ; ; Output: ; SD = psss qqqq | 0000 0000 | 0000 0000 (PCM log format) ; ;************************************************************************** MOVE X:(R0)+,X0 ;Get quan table value TSTDLN_R CMP X0,A X:(R0)+,X0 ;Compare to DLNX JGE IM, SD=SP- TST A #<$80,X0 JEQ IM, SD=SP- TST A #<$80,X0 JEQ >1 <<23 DC $200000 ;>>2 <<22 DC $100000 ;>>3 <<21 DC $080000 ;>>4 <<20 DC $040000 ;>>5 <<19 DC $020000 ;>>6 <<18 DC $010000 ;>>7 <<17 DC $008000 ;>>8 <<16 DC $004000 ;>>9 <<15 DC $002000 ;>>10 <<14 DC $001000 ;>>11 <<13 DC $000800 ;>>12 <<12 DC $000400 ;>>13 <<11 DC $000200 ;>>14 <<10 DC $000100 ;>>15 <<9 DC $000080 ;>>16 <<8 DC $000040 ;>>17 <<7 DC $000020 ;>>18 <<6 DC $000010 ;>>19 <<5 DC $000008 ;>>20 <<4 DC $000004 ;>>21 <<3 DC $000002 ;>>22 <<2 DC $000001 ;>>23 <<1 ;CONST1 DC $FFFE00 ;K1 = trunc mask (ACCUM) DC $7FFC00 ;K2 = trunc mask (MIX) DC $7FFE00 ;K3 = trunc mask (MIX) DC $000080 ;K4 = shift const (EXPAND) DC $00007F ;K5 = sign mask (EXPAND) DC $3F8000 ;K6 = trunc mask (LOG) DC $100000 ;K7 = shift const (LOG) DC $7FF000 ;K8 = trunc mask (SUBTB & ADDA) DC $07F000 ;K9 = sign mask (ANTILOG) DC $00000A ;K10 = '10' (ANTILOG) DC $7FFE00 ;K11 = trunc mask (ANTILOG) DC $07C000 ;K12 = trunc mask (TRANS) DC $000010 ;K13 = shift const (TRANS) DC $000008 ;K14 = '8' (TRANS) DC $000005 ;K15 = '5' (TRANS) DC $7FFE00 ;K16 = trunc mask (TRANS) DC $008000 ;K17 = +gain (UPB) DC $FF8000 ;K18 = -gain (UPB) DC $FFFF00 ;K19 = trunc mask (UPB) DC $1FFF00 ;K20 = '+1.99' (UPA2) DC $E00100 ;K21 = '-1.99' (UPA2) DC $FFFF00 ;K22 = trunc mask (UPA2) DC $FF4000 ;K23 = -gain (UPA1) DC $00C000 ;K24 = +gain (UPA1) DC $FFFF00 ;K25 = trunc mask (UPA1) DC $040000 ;K26 = shift const (FILTA) DC $FFF800 ;K27 = trunc mask (FILTA) DC $FFFE00 ;K28 = trunc mask (FILTB) DC $FFE000 ;K29 = trunc mask (FILTC) DC $FFFC00 ;K30 = trunc mask (FILTD) DC $088000 ;K31 = '1.06' (LIMB) DC $FFFC00 ;K32 = trunc mask (FILTE)