/* Math.Asm Copyright ©1998, 1999 Larry Barello Author: Larry Barello lbarello@accessone.com You are allowed to use this file for personal use only. You may use, embed, modify or distribute the contents of this file in any way you see fit as long as you include this copyright notice in the resulting file. Any commercial or industrial use including publishing or distributing in any form requires the written authorization of the copyright holder(s). No guarantees are made about fitness, functionality, correctness or performance of this file. The file is supplied on a "AS IS" basis, with no responsibility assumed by the author(s) for bug fixes, support, or damages of any sort arising from the use of this file. Contact the author with problem reports or fixes, feature requests or additions and questions. They are welcomed and will be incorporated as time and energy permits. */ #include "Registers.inc" ; ; Signed 8 and 16 bit math routines. ; MODULE MULT8X8S PUBLIC mult8x8s RSEG CODE:CODE ; ;----------------------------------------- ; 8x8 signed multiply ; ; PASSED: Xl = Multiplier, Wl = Multiplicand ; RETURNED: X = Results ; USED: Wh and flags ; STACK: None ; mult8x8s: sub Xh, Xh ;clear result High byte and carry ldi Wh, 8 m8s1: brcc m8s2 ;if carry (previous bit) set add Xh, Wl ; add multiplicand to result High byte m8s2: sbrc Xl, 0 ;if current bit set sub Xh, Wl ; subtract multiplicand from result High asr Xh ;shift right result High byte ror Xl ;shift right result L byte and multiplier dec Wh ;decrement loop counter brne m8s1 ;if not done, loop more ret ENDMOD MODULE MULT16x16S PUBLIC mult16x16s RSEG CODE:CODE ; ;----------------------------------------- ; Multiply16s ; ; Multiply two signed 16 bit numbers and return a ; 32 bit result ; ; PASSED: X = Multiplier, W = Multiplicand ; RETURN: Y:X = Results ; USED: R0 ; STACK: None ; CYCLES: ~220 including return ; mult16x16s: ldi Yl, 16 ; set up loop counter mov R0, Yl clr Yh sub Yl, Yl ; clear upper word of result and carry m16s1: brcc m16s2 ; if carry (previous bit) set add Yl, Wl ; add multiplicand Low to result byte 2 adc Yh ,Wh ; add multiplicand High to result byte 3 m16s2: sbrs Xl,0 rjmp m16s3 ; if current bit set sub Yl, Wl ; sub multiplicand Low from result byte 2 sbc Yh, Wh ; sub multiplicand High from result byte 3 m16s3: asr Yh ; shift right result and multiplier ror Yl ror Xh ror Xl dec R0 ; decrement counter brne m16s1 ; if not done, loop more ret ENDMOD MODULE DIV16x8s PUBLIC div16x8s RSEG CODE:CODE ; ;----------------------------------------- ; 16/8 signed Divide ; ; PASSED: X = Dividend, Wl = Divisor ; RETURNED: X = Results, R22 = Remainder ; USED: R0 and T ; STACK: 1 ; div16x8s: mov R0, Xh eor R0, Wl ; store XOR'd dividend and divisor bst R0, 7 ; sign bits in T ldi R22, 17 ; Set up loop counter mov R0, R22 push Wl sbrs Xh,7 ; X = ABS(X) rjmp d16s1 com Xl com Xh adiw Xl, 1 d16s1: sbrc Wl,7 ; Wl = ABS(Wl) neg Wl sub R22, R22 ;clear remainder word and carry ; ; Now, start to do the actual divide! ; d16s_3: rol Xl rol Xh dec R0 breq d16sxx rol R22 ; shift dividend into remainder sub R22,Wl ; remainder = remainder - divisor brcc d16s_6 ; if result negative add R22, Wl ; restore remainder clc ; clear carry to be shifted into result rjmp d16s_3 ; else d16s_6: sec ; set carry to be shifted into result rjmp d16s_3 d16sxx: brtc d16s_4 ; If sign bit (T) set com Xl com Xh adiw Xl, 1 d16s_4: pop Wl ; Restore original Xl ret ; return ENDMOD MODULE div32x16s PUBLIC div32x16s RSEG CODE:CODE ; ;----------------------------------------- ; 32/16 signed Divide ; ; PASSED: Y:X = Dividend, W = Divisor ; RETURNED: Y:X = Results, R23:22 = Remainder ; USED: R0 and T (Absolute value of X returned..) ; STACK: None ; div32x16s: mov R0, Yh eor R0, Wh ; store XOR'd dividend and divisor bst R0, 7 ; sign bits in T ldi R22, 33 ; Set up loop counter mov R0, R22 push Wl push Wh sbrs Yh, 7 ; Y:X = ABS(Y:X) rjmp d32s1 com Xl com Xh com Yl com Yh subi Xl, low(-1) sbci Xh, high(-1) sbci Yl, high(-1) sbci Yh, high(-1) d32s1: sbrs Wh, 7 ; W = ABS(W) rjmp d32s2 com Wh com Wl adiw Wl, 1 d32s2: clr R22 sub R23, R23 ;clear remainder word and carry ; ; Now, start to do the actual divide! ; d32s_3: rol Xl ;shift left dividend rol Xh rol Yl rol Yh dec R0 breq d32sxx rol R22 ; shift dividend into remainder rol R23 sub R22, Wl ; remainder = remainder - divisor sbc R23, Wh ; brcc d32s_6 ; if result negative add R22, Wl ; restore remainder adc R23, Wh clc ; clear carry to be shifted into result rjmp d32s_3 ; else d32s_6: sec ; set carry to be shifted into result rjmp d32s_3 d32sxx: brtc d32s_4 ; If sign bit (T) set com Xl com Xh com Yl com Yh subi Xl, low(-1) sbci Xh, high(-1) sbci Yl, high(-1) sbci Yh, high(-1) d32s_4: pop Wh pop Wl ; Restore original divisor ret ENDMOD MODULE LIMITWORD PUBLIC LimitWord RSEG CODE:CODE ;---------------------------------------------- ; LimitWord ; ; PASSED: X = 16 bit value to limit, W = ABS(Limit) ; RETURN: X = limited value, T=1 if limited ; USES: Wl, Wh, Flags ; LimitWord: clt cp Xl, Wl ; Try upper bound first cpc Xh, Wh brge LimitResults com Wl ; Negate limit and try lower bound com Wh adiw Wl, 1 cp Wl, Xl cpc Wh, Xh brlt NoLimiting LimitResults: set mov Xl, Wl mov Xh, Wh NoLimiting: ret ENDMOD MODULE LIMIT16X16 PUBLIC Limit16x16s RSEG CODE:CODE ;------------------------------------------ ; Limit16x16s ; ; Signed Upper/Lower limit of a 16 bit number by an ; posative signed 16 bit number (e.g. 15 bit integer) ; ; PASSED: X = Number to be limited ; R25:R24 = Limit Value (Posative Integer only) ; RETURNS: X = 16 bit value, T=1 if limited ; USES: R0, flags ; STACK: ; Limit16x16s: clt tst Xh brlt TryLower cp R24, Xl cpc R25, Xh brge Exit rjmp LimitValue TryLower: com R24 com R25 adiw R24,1 cp Xl, R24 cpc Xh, R25 brge Exit LimitValue: mov Xl, R24 mov Xh, R25 set ; Flag we did it & return Exit: ret ENDMOD MODULE LIMIT32X16 PUBLIC Limit32x16s RSEG CODE:CODE ;------------------------------------------ ; Limit32x16s ; ; Signed Upper/Lower limit of a 32 bit number by an ; posative signed 16 bit number (e.g. 15 bit integer) ; ; PASSED: Y:X = Number to be limited ; R25:R24 = Limit Value (Posative Integer only) ; RETURNS: X = 16 bit value, T=1 if limited ; USES: R0, flags ; STACK: ; Limit32x16s: clt clr R0 tst Yh brlt TryLower cp R24, Xl cpc R25, Xh cpc R0, Yl cpc R0, Yh brge Exit rjmp LimitValue TryLower: com R24 com R25 adiw R24,1 com R0 ; Sign extend into R0 cp Xl, R24 cpc Xh, R25 cpc Yl, R0 cpc Yh, R0 brge Exit LimitValue: mov Xl, R24 mov Xh, R25 set ; Flag we did it & return Exit: ret END