AVR200: Multiply and Divide Routines: 8-Bit MCU With Downloadable Flash Application Note
AVR200: Multiply and Divide Routines: 8-Bit MCU With Downloadable Flash Application Note
1
Algorithm Description
The algorithm for the Code Size optimized version is as fol- 5. Shift right result High byte into result Low byte/multi-
lows: plier.
1. Clear result High byte. 6. Shift right result Low byte/multiplier.
2. Load loop counter with 8. 7. Decrement Loop counter.
3. Shift right multiplier 8. If loop counter not zero, goto Step 4.
4. If carry (previous bit 0 of multiplier) set, add multipli-
cand to result High byte.
MPY8U
CLEAR RESULT
HIGH BYTE
LOOP COUNTER ‹ 8
SHIFT MULTIPLIER
RIGHT
ADD MULTIPLICAND Y
CARRY SET?
TO RESULT HIGH BYTE
DECREMENT LOOP
COUNTER
N
LOOP COUNTER = 0?
RETURN
2 AVR200
AVR200
Usage
The usage of “mpy8u” is the same for both versions: 3. The 16 -bit result is found in the two register variables
1. Load register variables “mp8u” and “mc8u” with the “m8uH” (High byte) and “m8uL” (Low byte)
multiplier and multiplicand, respectively. Observe that to minimize register usage, code and execu-
2. Call “mpy8u” tion time, the multiplier and result Low byte share the same
register.
Performance
Table 2. “mpy8u” Register Usage (Code Size Optimized Implementation)
Register Input Internal Output
R16 “mc8u” - multiplicand
R17 “mp8u” - multiplier “m8uL” - result Low byte
R18 “m8uH” - result High byte
R19 “mcnt8u” - loop counter
3
8 x 8 = 16 Signed Multiplication - 1. Clear result High byte and carry.
“mpy8s” 2. Load loop counter with 8.
This subroutine, which is found in “avr200.asm” imple- 3. If carry (previous bit 0 of multiplier) set, add multipli-
ments signed 8 x 8 multiplication. Negative numbers are cand to result High byte.
represented as 2's complement numbers. The application 4. If current bit 0 of multiplier set, subtract multiplicand
is an implementation of Booth's algorithm. The algorithm from result High byte.
provides both small and fast code. However, it has one lim- 5. Shift right result High byte into result Low byte/multi-
itation that the user should bear in mind; If all 16-bits of the plier.
result is needed, the algorithm fails when used with the
6. Shift right result Low byte/multiplier.
most negative number (-128) as the multiplicand.
7. Decrement loop counter
Algorithm Description 8. If loop counter not zero, goto Step 3.
The algorithm for signed 8 x 8 multiplication is as follows:
MPY8S
CLEAR RESULT
HIGH BYTE AND CARRY
LOOP COUNTER ‹ 8
ADD MULTIPLICAND Y
CARRY = 1?
TO RESULT HIGH BYTE
BIT 0 OF
SUBTRACT MULTIPLICAND Y
MULTIPLIER
FROM RESULT HIGH BYTE
SET?
DECREMENT LOOP
COUNTER
N
LOOP COUNTER = 0?
RETURN
4 AVR200
AVR200
5
MPY16U
CLEAR RESULT
HIGH WORD
LOOP COUNTER ‹ 16
SHIFT MULTIPLIER
RIGHT
ADD MULTIPLICAND Y
CARRY SET?
TO RESULT HIGH WORD
DECREMENT LOOP
COUNTER
N
LOOP COUNTER = 0?
RETURN
6 AVR200
AVR200
Performance
Table 8. “mpy16u” Register Usage (Code Size Optimized Implementation)
Register Input Internal Output
R16 “mc16uL” - multiplicand low byte
R17 “mc16uH” - multiplicand high byte
R18 “mp16uL” - multiplier low byte “m16u0” - result byte 0
R19 “mp16uH” - multiplier high byte “m16u1” - result byte 1
R20 “m16u2” - result byte 2
R21 “m16u3” - result byte 3
R22 “mcnt16u” - loop counter
7
16 x 16 = 32 Signed Multiplication -
“mpy16s” MPY16S
This subroutine, which is found in “avr200.asm” imple-
ments signed 16 x 16 multiplication. Negative numbers are
represented as 2's complement numbers. The application CLEAR RESULT
is an implementation of Booth's algorithm. The algorithm HIGH WORD AND CARRY
provides both small and fast code. However, it has one lim-
itation that the user should bear in mind; If all 32-bits of the
result is needed, the algorithm fails when used with the LOOP COUNTER ‹ 8
most negative number (-32768) as the multiplicand.
Algorithm Description
The algorithm for signed 16 x 16 multiplication is as follows:
ADD MULTIPLICAND Y
CARRY = 1?
1. Clear result High word (Bytes 2&3) and carry. TO RESULT HIGH WORD
2. Load loop counter with 16.
N
3. If carry (previous bit 0 of multiplier Low byte) set, add
multiplicand to result High word.
BIT 0 OF
4. If current bit 0 of multiplier Low byte set, subtract multi- SUBTRACT MULTIPLICAND Y
MULTIPLIER LOW
FROM RESULT HIGH WORD
plicand from result High word. BYTE SET?
DECREMENT LOOP
COUNTER
N
LOOP COUNTER = 0?
RETURN
8 AVR200
AVR200
Usage
The usage of “mpy16s” is as follows: 3. Call “mpy16s”
1. Load register variables “mp16sL”/”mp16sH” with multi- 4. The 32-bit result is found in the four-byte register vari-
plier Low and High byte, respectively. able “m16s3:m16s2:m16s1:m16s0”.
2. Load register variables “mc16sH”/”mc16sH” with multi- Observe that to minimize register usage, code and execu-
plicand Low and High byte, respectively. tion time, the multiplier and result Low byte share the same
register.
Performance
Table 12. “mpy16s” Register Usage
Register Input Internal Output
R16 “mc16uL” - multiplicand low byte
R17 “mc16uH” - multiplicand high byte
R18 “mp16uL” - multiplier low byte “m16u0” - result byte 0
R19 “mp16uH” - multiplier high byte “m16u1” - result byte 1
R20 “m16u2” - result byte 2
R21 “m16u3” - result byte 3
R22 “mcnt16u” - loop counter
9
DIV8U
CLEAR REMAINDER
AND CARRY
LOOP COUNTER ‹ 9
DECREMENT LOOP
COUNTER
N
SHIFT LEFT REMAINDER LOOP COUNTER = 0?
Y
REMAINDER ‹
REMAINDER DIVISOR
RETURN
Y REMAINDER ‹
RESULT NEGATIVE?
REMAINDER + DIVISOR
N
CLEAR CARRY
SET CARRY
10 AVR200
AVR200
Performance
Table 14. “div8u” Register Usage (Code Size Optimized Version)
Register Input Internal Output
R15 “drem8u” - remainder
R16 “dd8u” - dividend “dres8u” - result
R17 “dv8u” - divisor”
R18 “dcnt8u” - loop counter
11
Algorithm Description
The algorithm for signed 8 / 8 division is as follows:
1. XOR dividend and divisor and store in a Sign register.
2. If MSB of dividend set, negate dividend.
3. If MSB if divisor set, negate dividend.
4. Clear remainder and carry.
5. Load loop counter with 9.
6. Shift left dividend into carry.
7. Decrement loop counter.
8. If loop counter ≠ 0, goto step 11.
9. If MSB of Sign register set, negate result.
10. Return
11. Shift left carry (from dividend/result) into remainder
12. Subtract divisor from remainder.
13. If result negative, add back divisor, clear carry and goto
Step 6.
14. Set carry and goto Step 6.
12 AVR200
AVR200
DIV8S
SIGN REGISTER ‹
DIVIDEND XOR DIVISOR
MSB OF Y
NEGATE DIVISOR
DIVISOR SET?
MSB OF Y
NEGATE DIVIDEND
DIVIDEND SET?
LOOP COUNTER ‹ 9
DECREMENT LOOP
COUNTER
N Y MSB OF SIGN Y
SHIFT LEFT REMAINDER LOOP COUNTER = 0? NEGATE RESULT
REGISTER SET?
N
REMAINDER ‹
REMAINDER DIVISOR
RETURN
Y REMAINDER ‹
RESULT NEGATIVE?
REMAINDER + DIVISOR
CLEAR CARRY
SET CARRY
13
Usage
The usage of “div8s” follows the procedure below: 3. Call “div8s”.
1. Load register variable “dd8s” with the dividend (the 4. The result is found in “dres8s” and the remainder in
number to be divided). “drem8s”.
2. Load register variable “dv8s” with the divisor (the divid-
ing number).
Performance
Table 18. “div8s” Register Usage
Register Input Internal Output
R14 “d8s” - sign register
R15 “drem8s” - remainder
R16 “dd8s” - dividend “dres8s” - result
R17 “dv8s” - divisor”
R18 “dcnt8s” - loop counter
14 AVR200
AVR200
DIV16U
CLEAR REMAINDER
AND CARRY
LOOP COUNTER ‹ 17
DECREMENT LOOP
COUNTER
N
SHIFT LEFT REMAINDER LOOP COUNTER = 0?
Y
REMAINDER ‹
REMAINDER DIVISOR
RETURN
Y REMAINDER ‹
RESULT NEGATIVE?
REMAINDER + DIVISOR
CLEAR CARRY
SET CARRY
15
Performance
Table 20. “div16u” Register Usage (Code Size Optimized Version)
Register Input Internal Output
R14 “drem16uL” - remainder low byte
R15 “drem16uH - remainder high byte
R16 “dd16uL” - dividend low byte “dres16uL” - result low byte
R17 “dd16uH” - dividend high byte “dres16uH” - result high byte
R18 “dv16uL” - divisor low byte
R19 “dv16uH” - divisor high byte
R20 “dcnt16u” - loop counter
16 AVR200
AVR200
16 / 16 = 16 + 16 Signed Division -
“div16s”
The subroutine “mpy16s” implements signed 16-bit divi-
sion. The implementation is Code Size optimized. If nega-
tive, the input values shall be represented on 2's comple-
ment's form.
Algorithm Description
The algorithm for signed 16 / 16 division is as follows:
1. XOR dividend and divisor High bytes and store in a
Sign register.
2. If MSB of dividend High byte set, negate dividend.
3. If MSB if divisor set High byte, negate dividend.
4. Clear remainder and carry.
5. Load loop counter with 17.
6. Shift left dividend into carry
7. Decrement loop counter.
8. If loop counter ≠ 0, goto step 11.
9. If MSB of Sign register set, negate result.
10. Return
11. Shift left carry (from dividend/result) into remainder
12. Subtract divisor from remainder.
13. If result negative, add back divisor, clear carry and goto
Step 6.
14. Set carry and goto Step 6.
17
DIV16S
SIGN REGISTER ‹
DIVIDENDH XOR DIVISORH
MSB OF Y
NEGATE DIVISOR
DIVISOR SET?
MSB OF Y
NEGATE DIVIDEND
DIVIDEND SET?
LOOP COUNTER ‹ 17
DECREMENT LOOP
COUNTER
N Y MSB OF SIGN Y
SHIFT LEFT REMAINDER LOOP COUNTER = 0? NEGATE RESULT
REGISTER SET?
N
REMAINDER ‹
REMAINDER DIVISOR
RETURN
Y REMAINDER ‹
RESULT NEGATIVE?
REMAINDER + DIVISOR
CLEAR CARRY
SET CARRY
18 AVR200
AVR200
Usage
The usage of “div16s” is described in the following proce- 3. Call “div16s”.
dure: 4. The result is found in “dres16s” and the remainder in
1. Load the 16-bit register variable “dd16sH:dd16sL” with “drem16s”.
the dividend (the number to be divided).
2. Load the 16-bit register variable “dv16sH:dv16sL” with
the divisor (the dividing number).
Performance
Table 24. “div16s” Register Usage
Register Input Internal Output
R14 “drem16sL” - remainder low byte
R15 “drem16sH - remainder high byte
R16 “dd16sL” - dividend low byte “dres16sL” - result low byte
R17 “dd16sH” - dividend high byte “dres16sH” - result high byte
R18 “dv16sL” - divisor low byte
R19 “dv16sH” - divisor high byte
R20 “dcnt16s” - loop counter
19