// Test fixed arithmetic macros #include #include #include //for square root only #include //I like these definitions #define begin { #define end } //===The fixed macros========================================= #define int2fix(a) (((int)(a))<<8) //Convert char to fix #define fix2intSlow(a) ((signed char)((a)>>8)) //Convert fix to char #define float2fix(a) ((int)((a)*256.0)) //Convert float to fix #define fix2float(a) ((float)(a)/256.0) //Convert fix to float #define multfixSlow(a,b) ((int)((((long)(a))*((long)(b)))>>8)) //multiply two fixed # //see below for the fast version #define divfixslow(a,b) ((int)((((long)(a))<<8)/((long)(b)))) //divide two fixed # //lsqrt is in math.h #define sqrtfixSlow(a) (lsqrt(((long)(a))<<8)) //square root //== fixed to char ================================= char fix2int(int a) begin #asm ldd r30, Y+1 ;moves the high byte of the input to low byte #endasm end //==Fast fixed multiply================================= int multfix(int a,int b) begin #asm ;****************************************************************************** ;* ;* FUNCTION ;* muls16x16_24 ;* DECRIPTION ;* Signed multiply of two 16bits numbers with 24bits result. ;* USAGE ;* r31:r30:rxx = r23:r22 * r21:r20 ;****************************************************************************** ;push r20 ;push r21 mov r24, r20 mov r25, r21 LDD R22,Y+2 ;load a LDD R23,Y+3 LD R20,Y ;load b LDD R21,Y+1 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ;r18, r0 mul r22, r20 ; al * bl mov r30, r1 ;movw r17:r16, r1:r0 ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ;r17, r0 adc r31, r1 ;r18, r1 mulsu r21, r22 ; (signed)bh * al add r30, r0 ;r17, r0 adc r31, r1 ;r18, r1 ;pop r21 ;pop r20 mov r20, r24 mov r21, r25 #endasm end //======================================================== int reciprocalfix(int dd) begin signed char count, neg ; //r16, r17 int x, d ; //r18:19, r20:21 d=dd ; #asm clr r16 ;count = 0; clr r17 ;neg = 0; ;only works with + numbers ;if (d & 0x8000) ;begin ; neg = 1; ; d = -d ; ;end tst r21 ;d negative? brpl notneg ldi r17, 1 ; neg = 1; negative flag clr r18 ; d = -d ; clr r19 sub r18, r20 sbc r19, r21 mov r20, r18 mov r21, r19 notneg: #endasm // range reduction // bigger than one while (d>0x0100) begin --count ; d >>= 1 ; end // less than 1/2 while (d<0x0080) begin ++count ; d <<= 1 ; end // Newton interation //x = 0x02ea - (d<<1) ; //x = multfix(x, 0x0201 + ~multfix(d,x)); //x = multfix(x, 0x0200-multfix(d,x)); #asm ; form initial x ldi r22, 0xea ;load the constant 2.914 ldi r23, 0x02 mov r24, r20 ; copy d mov r25, r21 lsl r24 ; and form 2*d rol r25 sub r22, r24 ; form 2.914-2*d sbc r23, r25 mov r18, r22 ; store x mov r19, r23 ;mov r22, r18 ; load x ;mov r23, r19 ;mov r20,r20 ; load d ;mov r21,r21 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ; mul r22, r20 ; al * bl mov r30, r1 ; ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ; adc r31, r1 ; mulsu r21, r22 ; (signed)bh * al add r30, r0 ; adc r31, r1 ; com r30 com r31 ldi r24, 0x01 ldi r25, 0x02 add r30, r24 adc r31, r25 mov r22, r18 ;load x mov r23, r19 mov r20,r30 ;load 2-d*x mov r21,r31 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ; mul r22, r20 ; al * bl mov r30, r1 ; ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ; adc r31, r1 ; mulsu r21, r22 ; (signed)bh * al add r30, r0 ; adc r31, r1 ; ; range expansion ; if (count>0) x = x<>(-count) ; tst r16 breq recipEnd brmi recipNeg lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 breq recipEnd lsl r30 rol r31 dec r16 rjmp recipEnd recipNeg: lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 breq recipEnd lsr r31 ror r30 inc r16 recipEnd: ; fix sign ; if (neg==1) x=-x; tst r17 ;neg flag set? breq recip1 ;if not, do nothing clr r24 clr r25 sub r24, r30 sbc r25, r31 mov r30, r24 mov r31, r25 recip1: ; return x in r30:31 #endasm end //======================================================== int divfix(int nn, int dd) begin signed char count, neg ; //r16, r17 int x, d ; //r18:19, r20:21 int n ; d=dd ; n=nn ; #asm clr r16 ;count = 0; clr r17 ;neg = 0; ;only works with + numbers ;if (d & 0x8000) ;begin ; neg = 1; ; d = -d ; ;end tst r21 ;d negative? brpl Dnotneg ldi r17, 1 ; neg = 1; negative flag clr r18 ; d = -d ; clr r19 sub r18, r20 sbc r19, r21 mov r20, r18 mov r21, r19 Dnotneg: #endasm // range reduction // bigger than one while (d>0x0100) begin --count ; d >>= 1 ; end // less than 1/2 while (d<0x0080) begin ++count ; d <<= 1 ; end // Newton interation //x = 0x02ea - (d<<1) ; //x = multfix(x, 0x0201 + ~multfix(d,x)); //x = multfix(x, 0x0200-multfix(d,x)); #asm ; form initial x ldi r22, 0xea ;load the constant 2.914 ldi r23, 0x02 mov r24, r20 ; copy d mov r25, r21 lsl r24 ; and form 2*d rol r25 sub r22, r24 ; form 2.914-2*d sbc r23, r25 mov r18, r22 ; store x mov r19, r23 ;mov r22, r18 ; load x ;mov r23, r19 ;mov r20,r20 ; load d ;mov r21,r21 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ; mul r22, r20 ; al * bl mov r30, r1 ; ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ; adc r31, r1 ; mulsu r21, r22 ; (signed)bh * al add r30, r0 ; adc r31, r1 ; com r30 com r31 ldi r24, 0x01 ldi r25, 0x02 add r30, r24 adc r31, r25 mov r22, r18 ;load x mov r23, r19 mov r20,r30 ;load 2-d*x mov r21,r31 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ; mul r22, r20 ; al * bl mov r30, r1 ; ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ; adc r31, r1 ; mulsu r21, r22 ; (signed)bh * al add r30, r0 ; adc r31, r1 ; ; range expansion ; if (count>0) x = x<>(-count) ; tst r16 breq DrecipEnd brmi DrecipNeg lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 breq DrecipEnd lsl r30 rol r31 dec r16 rjmp DrecipEnd DrecipNeg: lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 breq DrecipEnd lsr r31 ror r30 inc r16 DrecipEnd: ; fix sign ; if (neg==1) x=-x; tst r17 ;neg flag set? breq Drecip1 ;if not, do nothing clr r24 clr r25 sub r24, r30 sbc r25, r31 mov r30, r24 mov r31, r25 Drecip1: ; x = multfix(x,nn) ; mov r22, r30 mov r23, r31 ldd r20,Y+6 ; load n ldd r21,Y+7 muls r23, r21 ; (signed)ah * (signed)bh mov r31, r0 ; mul r22, r20 ; al * bl mov r30, r1 ; ;mov r16, r0 mulsu r23, r20 ; (signed)ah * bl add r30, r0 ; adc r31, r1 ; mulsu r21, r22 ; (signed)bh * al add r30, r0 ; adc r31, r1 ; #endasm end //======================================================== signed char cIn; //an input integer float fIn, fIn2 ; //an input float char fInString[16]; signed int fInFix2, fInFix, prod, ratio ; char i; //========================================================== void main(void) begin //serial setop for debugging using printf, etc. UCSRB = 0x18 ; UBRRL = 103 ; putsf("\r\nStarting...\r\n"); while(1) begin //test float2fix printf("\n\r enter a float:") ; scanf("%s",fInString); fIn = atof(fInString); printf("%f",fIn); fInFix = float2fix(fIn); printf(" fixed rep:%04x\r\n",fInFix); //test float2fix printf("\n\r enter a float:") ; scanf("%s",fInString); fIn2 = atof(fInString); printf("%f",fIn2); fInFix2 = float2fix(fIn2); printf(" fixed rep:%04x\r\n",fInFix2); //test reciprocal ratio = reciprocalfix(fInFix); printf("reciprocal(%f)=%f",fIn,fix2float(ratio)) ; printf(" fixed rep:%04x\r\n",ratio); //test divfix ratio = divfix(fInFix2,fInFix); printf("ratio(%f/%f)=%f", fIn2,fIn,fix2float(ratio)) ; printf(" fixed rep:%04x\r\n",ratio); //============================================ TCCR1B = 1 ; TCNT1 = 0; prod = reciprocalfix(fInFix) ; TCCR1B = 0; printf("reciprocal cycles=%d\n\r",TCNT1) ; TCCR1B = 1 ; TCNT1 = 0; prod = divfix(fInFix2,fInFix) ; TCCR1B = 0; printf("divfix cycles=%d\n\r",TCNT1) ; TCCR1B = 1 ; TCNT1 = 0; fIn = fIn2/(fIn) ; TCCR1B = 0; printf(" ratio float cycles=%d\n\r",TCNT1) ; //============================================ end end