Multiplication, division, and square root can be computed by using add, subtract, and shift instructions. For other math-related examples, see the Log Table, Anti-Log Table, and Sine Table.
Here is an unsigned multiplier routine that multiplies two 16-bit values to yield a 32-bit product:
DAT '' Multiply x[15..0] by y[15..0] (y[31..16] must be 0) ' on exit, product in y[31..0] ' multiply shl x,#16 'get multiplicand into x[31..16] mov t,#16 'ready for 16 multiplier bits shr y,#1 wc 'get initial multiplier bit into c :loop if_c add y,x wc 'if c set, add multiplicand to product rcr y,#1 wc 'put next multiplier in c, shift prod. djnz t,#:loop 'loop until done multiply_ret ret 'return with product in y[31..0]
The above routine's execution time could be cut by ~1/3 if the loop was unrolled, repeating the ADD / RCR sequence and getting rid of the DJNZ instruction.
Division is like multiplication, but backwards. It is potentially more complex, though, because a comparison test must be performed before a subtraction can take place. To remedy this, there don’t is a special CMPSUB D, S instructions which tests to see if a subtraction can be performed without causing an underflow. If no underflow would occur, the subtraction takes place and the C output is 1. If an underflow would occur, D is left alone and the C output is 0.
Here is an unsigned divider routine that divides a 32-bit value by a 16-bit value to yield a 16-bit quotient and a 16-bit remainder:
DAT ' Divide x[31..0] by y[15..0] (y[16] must be 0) ' on exit, quotient is in x[15..0] and remainder is in x[31..16] ' divide shl y,#15 'get divisor into y[30..15] mov t,#16 'ready for 16 quotient bits :loop cmpsub x,y wc 'y =< x? Subtract it, quotient bit in c rcl x,#1 'rotate c into quotient, shift dividend djnz t,#:loop 'loop until done divide_ret ret 'quotient in x[15..0], 'remainder in x[31..16]
Like the multiplier routine, this divider routine could be recoded with a sequence of 16 CMPSUB + RCL instruction pairs to get rid of the DJNZ and cut execution time by ~1/3. By making such changes, speed can often be gained at the expense of code size.
Here is a square-root routine that uses the CMPSUB instruction:
DAT ' ' Compute square-root of y[31..0] into x[15..0] ' root mov a,#0 'reset accumulator mov x,#0 'reset root mov t,#16 'ready for 16 root bits :loop shl y,#1 wc 'rotate top two bits of y to accumulator rcl a,#1 shl y,#1 wc rcl a,#1 shl x,#2 'determine next bit of root or x,#1 cmpsub a,x wc shr x,#2 rcl x,#1 djnz t,#:loop 'loop until done root_ret ret 'square root in x[15..0]
Many complex math functions can be realized by additions, subtractions, and shifts. Though specific examples were given here, these types of algorithms may be coded in many different ways to best suit the application.
Propeller Help Version 1.1
Copyright © Parallax Inc.
5/13/2009