Also, there is a stack based version that implements add, subtract, multiply, and divide in a FORTH like stack based system
Maths routines for computers, microprocessors and microcontrollers are nothing new. They have been around almost since the invention of the computer, but finding a comprehensive set of routines can be difficult. If you do not have the ability to write your own routines then you must rely on someone else's work. It may be poorly written or incomprehensible due to lack of documentation ,which is often the author's experience. The purpose of this article is to explain how various maths functions are performed and to present a complete 32-bit maths package which can handle huge numbers, and yet not take too much precious memory space. The routines presented here are: Add, Subtract, Multiply, Divide, Round (for divide), Square Root, Binary to Decimal, and Decimal to Binary conversion.
An 8-bit register or memory is able to store numbers in the range 0 to 255. If two 8-bit numbers are added together it is quite possible that the sum will exceed 255, so how do we cope with larger numbers? The answer is to use more bits. Imagine a 16-bit register (or memory), this is able to hold numbers up to 65535. You can add numbers to this register many times so long as the total does not exceed 65535. Now split the 16-bit register down the middle into two 8-bit sections. This does not change the nature of the number it contains, but each section can now be stored in adjacent 8-bit (byte) memory locations. The two bytes are usually referred to as High byte and Low Byte. Of course the PIC cannot add 16-bit numbers directly, you must program it to add each byte separately and deal with any overflow from one byte to the next. If you need numbers larger than 65535 this concept can be extended to 24 bits using three bytes for the number, or 32 bits using four bytes. The name given to this is Multiple Precision Numbers.
General purpose maths routines should be able to cope with negative numbers as well as positive ones. Two's compliment is one of several method for representing both positive and negative numbers. It is a logical extension of unipolar (positive) numbers, which makes it the most widely used method. Other methods such as signed magnitude and offset (also known as biased) are to be found in floating point format numbers and are beyond the scope of this article. A disadvantage of two's compliment is that it works only for addition and subtraction, for other functions the result sign must first be calculated and the numbers made positive before calculating the result.
First we shall look at how two's complement numbers are derived. If an 8-bit register contains a value of 0, when 1 is subtracted from it the result will be FF. Logically this is -1. If 2 is subtracted from 0 the result is FE which is -2, FD is -3 and so on. With an 8-bit register it is possible to represent a numeric range of -128 to +127. For a 16-bit register, -1 = FFFF, -2 = FFFE, -3 = FFFD etc with a range of -32768 to +32767. This concept can be extended to any number of bits you wish although 32 bits is usually considered to be enough. This equates to a numerical range of -2,147,483,648 to +2,147,483,647. The term "Two's compliment" is derived from the method used to negate a number, i.e. change its sign from positive to negative or vice versa. To do this first invert all the bits of the number, this is known as one's compliment, and then add 1 to the number to obtain the two's compliment.
Where a number is more than 8 bits (one byte) long several consecutive bytes are used to store the number, this is called Multiple Precision. It is normally easy enough to add two multiple precision numbers, but the RISC instruction set of the PIC does not allow for carrying any overflow from addition into the next byte. In the authors experience there often appears to be some confusion of how to do this. Listing 1 shows the correct method of adding two multiple precision numbers, NUM1 and NUM2. The L, M and H at the end of the variable names refer to Low, Middle and High bytes respectively. The Carry will be correctly set on exit, indicating any overflow from the addition. Subtraction is performed in a similar manner. Another way of subtracting a number is to first negate it (twos complement) then perform an addition. This eliminates the need for a separate subtraction routine. The arithmetic unit of microprocessors, including PICs, use twos complement to perform subtractions.
movf NUM2L,W ;Add low bytes addwf NUM1L,F movf NUM2M,W ;Add mid bytes skpnc ;No carry_in, so just add incfsz NUM2M,W ;Add carry_in to NUM2 addwf NUM1M,F ;Add and propagate carry_out movf NUM2H,W ;Add high bytes skpnc ;No carry_in, so just add incfsz NUM2H,W ;Add carry_in to NUM2 addwf NUM1H,F ;Add and propagate carry_out
You can perform binary multiplication in the same way that you do decimal long multiplication by hand. Before going into detail we will look at a worked example of multiplying 13 by 10, in binary that is 1101 and 1010.
1101 (multiplicand) x1010 (multiplier) 0000 (partial products) 1101 0000 1101 10000010 (product)
Starting with the least significant digit of the multiplier, multiply the multiplicand by each multiplier digit in turn and write the results (partial products) below. Ensure the rightmost digit of each partial product lines up with its generating digit in the multiplier. Keep going until you run out of digits in the multiplier. Now add all the partial products together and you have the final result. A quick check of the result confirms it is correct. 128 + 2 = 130.
Now we shall look at how to write a multiply routine in assembler. Since the numbers are binary no multiplication is actually needed because multiplying by zero gives zero as a result, and multiplying by one produces the same number you started with. This just leaves the problem of whether to multiply by 0 or 1. To do this each bit of the multiplicand is shifted into the Carry for testing. If the bit is a 1 then the multiplier (or more correctly, the multiplier times one) is added to the partial product , if the bit is a 0 then nothing is done since there is no point in adding zero to the partial product. The final task is to ensure the bits are correctly aligned at each addition, this is simply achieved by shifting the partial product in line with the multiplicand.
Listing 2 shows a simplified 8-bit x 8-bit multiply. The variables MPCAND and MPLIER are multiplied to give a 16-bit result in PRODH and PRODL. There are numerous variations of this routine. It is also possible to work from left to right, starting with the most significant digit and shifting left. The best method to choose depends on the processor for which it is written, the number of bits and the programmers personal preference.
mult clrf PRODL,F ;Clear result clrf PRODH,F movlw 0x08 ;Bit counter movwf COUNT movf MPCAND,W ;Multiplicand in W reg loop rrf MPLIER,F ;Lsb into Carry skpnc ;Test Carry addwf PRODH,F ;Add multiplicand to result rrf PRODH,F ;Align result rrf PRODL,F decfsz COUNT,F ;Next bit goto loop
You will probably not be surprised to learn that division is pretty much the reverse of multiplication . Binary division can also be performed in the same way that you do decimal long division by hand, and again because the numbers are binary no division is actually needed. Where multiplication uses successive shifts and addition, division is done by successive shifts and subtraction.
An example of long division in binary is shown below. Those who are familiar with decimal long division should have no problem with the format, although it has been expanded somewhat for clarity. It shows 15 divided by 3.
0101 (quotient 5 ) 0011 ) 1111 (divisor 3 )dividend 15 ) 1 (partial remainders) 11 -11 (subtract divisor) 0 01 011 -011 (subtract divisor) 0 (remainder)
The most significant digit of the dividend is put into the partial remainder and compared with the divisor. If the partial remainder is less than the divisor then the quotient digit is a 0. If the partial remainder is equal to or greater than the divisor, the quotient digit is a 1, the divisor is subtracted and the remainder written below. The next dividend digit is now appended to the new partial remainder and the comparison is repeated until all the dividend digits have been processed. The partial remainder must always remain less than 2 times the divisor, for this reason division is not needed for binary numbers. Unless, of course, you insist that dividing by 1 is a valid argument.
In this example the division is exact i.e. the result is an exact integer. If, for example, 14 were divided by 3 the result would be 4 with a remainder of 2 on the bottom line. Integer division always rounds down to the nearest whole number unless extra code is written to provide rounding up the result if the remainder is 0.5 or more.
Converting the division procedure into an assembler routine is very easy. Listing 3 shows a simple 8-bit by 8-bit divide. Appending to the remainder is done by shifting the msb of the dividend into the Carry and then into the lsb of the remainder. Because of their RISC instruction set PICs do not have a compare instruction so subtract is used to compare the values of the remainder and divisor, the result of the subtraction being held in the W register. Setting the quotient bit is done by shifting in the Carry which was cleared or set by the subtraction.
divide clrf QUOT ;Clear quotient clrf REM ;Clear remainder movlw 0x08 ;Bit count movwf COUNT loop rlf DIVID,F ;Shift dividend bit rlf REM,F ;into remainder movf DIVIS,W ;Trial subtraction subwf REM,W skpnc movwf REM ;Subtraction was ok rlf QUOT,F ;Carry is result bit decfsz COUNT,F ;Next bit goto loop
As previously mentioned result of division is rounded down, or more correctly truncated, if the result is not an exact integer. We can obtain a more accurate result by rounding up or down to the nearest integer when there is a fractional part to the result. This routine adds 1 to the result if the remainder of the division is 0.1 binary or greater, which is equivalent to 0.5 decimal. This helps to minimise errors caused by multiple uses of division.
You can square a number simply by multiplying it by itself, square rooting a number is a little more difficult. There are many ways to find the square root of a number, probably the best method for large numbers was described by the same author in the August 2002 issue of EPE. It is very similar to division since the square root of a number is equal to the number divided by its square root. The original 24-bit routine has now been expanded to 32-bit.
You would like to see the results of all your calculations and would like it to be in decimal, similarly you want to input numbers in decimal. This makes Binary to Decimal and Decimal to Binary routines an essential part of any maths package. Many assembler programmers will at some time have attempted these conversions, usually in a crude fashion. (As were the authors attempts many years ago) . These methods such as subtracting the binary equivalent of powers of ten are perfectly valid and can be useful, but when it comes to very large numbers there are much better methods available. The Binary to Decimal and Decimal to Binary routines presented here complement each other, they both use the same method but each is the reverse of the other. The method chosen for this package is simplicity itself and very flexible. The routine is compact and easily modified for various bit lengths. A simplified version is shown in Listing 4. The most significant bit of BINARY is shifted into the least significant digit, ONES. If the digit has a value of 10 or more then 10 is subtracted from it and 1 is added to the next higher digit. The Carry is used to add 1 to the next digit as it will be set by the subtraction if the digit is greater than 9. The rest of the digits are shifted and checked in a similar manner and the whole process repeated until all the bits of the binary number have been shifted out of BINARY and into the digits. The hundreds digit is not tested in this instance since it cannot overflow as the maximum decimal value for 8-bit binary is 255.
Decimal to Binary consists of the same procedure but doing it all in reverse. Shifting bits through the digits and into the Carry, adding 10 to the digits when necessary and shifting the Carry into the binary.
clrf ONES clrf TENS clrf HUND movlw 8 ;Bit count movwf BCOUNT loop rlf BINARY,F ;Shift msb into rlf ONES,F ;first digit movlw 10 ;Digit > 9 ? subwf ONES,W skpnc movwf ONES ;Digit = digit -10 rlf TENS,F ;Shift carry in movlw 10 ;Digit > 9 ? subwf TENS,W skpnc movwf TENS ;Digit = digit -10 rlf HUND,F ;Shift carry in decfsz BCOUNT,F ;Next bit goto loop
Signed 32-bit numbers have a range of -2147483648 to +2147483647. However -2147483648 does not have a positive equivalent which would needed in many cases and so the range is limited to ± 2147483647, with -2147483648 being trapped as an error. Three 32-bit pseudo-registers are defined, REGA contains the first operand, REGB contains the second operand and REGC is used as temporary storage by the routines. The result is always returned in REGA. Each pseudo-register consists of 4 consecutive bytes denoted by 0, 1, 2 and 3. 0 is the least significant byte and 3 is the most significant byte. High level languages have built-in run-time error checking but assembler has no such luxuries and the programmer must write his/her own. Comprehensive error checking is included in the routines and the Carry will be set on return from the routines if an error is found. The code required for error checking after calling a routine is shown below.
Because the PICs stack cannot be manipulated errors would usually need to be passed back to the top-most level of the program. Most errors will be caused by an overflow, i.e. the result is greater than 32 bits. When an error is encountered the result returned in REGA will be meaningless. Checking the Carry after calling a routine is optional so long as you are sure no error will occur.
The header of each routine gives a brief description of its function and usage. The five basic arithmetic functions are given below for reference.
Add: REGA = REGA + REGB
Subtract: REGA = REGA - REGB
Multiply: REGA = REGA x REGB
Divide: REGA = REGA / REGB
Sq Root: REGA = SQRT (REGA)
Note that multiplying two 32-bit numbers can produce a result of up to 64 bits. A limit on the number of bits has to be drawn somewhere and it is 32, so an error will be returned if the result exceeds the 32 bits of REGA.
The Round routine is intended to be called only after division, it will not round the result of Square Root. Only the simplest of rounding is used since it was considered unnecessary to use a more complex method. Check for division error (if needed) before calling this routine.
The Decimal to Binary routine was designed for flexibility and keypad input in mind. It accepts a variable length BCD string of digits. Your input routine should put the first ( most significant) digit entered in the variable DIGIT1, the next digit into DIGIT2 and so on up to a maximum of 10 digits. A count of the number of digits entered must be kept and loaded into the W register before the routine is called. The reason for this is that people are unlikely to include leading zeros when entering a number to make up the full 10 digits that would otherwise be required, it seems leading zero suppression is in human nature. If your digits are in ASCII text format they should first be converted to BCD format by subtracting 48. It is also worthwhile checking that the digits are in the range of 0 to 9 to avoid the possibility of obtaining a meaningless result. The routine also requires a sign bit to indicate whether the number is positive or negative. This is held in the variable DSIGN which should be set to 0 for a positive number or 1 for negative.
Binary to Decimal requires little in the way of explanation. DSIGN is again used to indicate a positive or negative number. You may use this to precede the number with a + or - in your output routine. No output formatting is included as this will be dependant upon the application.
The routines are contained in the file Maths32.txt and are intended to be opened with a text editor such as Notepad and then copied and pasted into your assembly program. You copy all the routines or just the ones you require. But do not forget to also copy the utility routines, most of which will be required. The variable declarations will also need to be copied and you will need supply a start address for them.
The variables require 26 contiguous bytes of data memory but if you do not have this amount available they may be split. Only the variables DIGIT1 to DIGIT10 are required to be contiguous.
;*** SIGNED 32-BIT INTEGER MATHS ROUTINES FOR PIC16 SERIES BY PETER HEMSLEY *** ; ;Functions: ; add ; subtract ; multiply ; divide ; round ; sqrt ; bin2dec ; dec2bin ;Variable declarations mathram equ ;(insert required ram address here) cblock mathram REGA0 ;lsb REGA1 REGA2 REGA3 ;msb REGB0 ;lsb REGB1 REGB2 REGB3 ;msb REGC0 ;lsb REGC1 REGC2 REGC3 ;msb DSIGN ;Digit Sign. 0=positive,1=negative DIGIT1 ;MSD DIGIT2 DIGIT3 DIGIT4 DIGIT5 ;Decimal (BCD) digits DIGIT6 DIGIT7 DIGIT8 DIGIT9 DIGIT10 ;LSD MTEMP MCOUNT DCOUNT endc ;*** 32 BIT SIGNED SUTRACT *** ;REGA - REGB -> REGA ;Return carry set if overflow subtract call negateb ;Negate REGB skpnc return ;Overflow ;*** 32 BIT SIGNED ADD *** ;REGA + REGB -> REGA ;Return carry set if overflow add movf REGA3,w ;Compare signs xorwf REGB3,w movwf MTEMP call addba ;Add REGB to REGA clrc ;Check signs movf REGB3,w ;If signs are same xorwf REGA3,w ;so must result sign btfss MTEMP,7 ;else overflow addlw 0x80 return ;*** 32 BIT SIGNED MULTIPLY *** ;REGA * REGB -> REGA ;Return carry set if overflow multiply clrf MTEMP ;Reset sign flag call absa ;Make REGA positive skpc call absb ;Make REGB positive skpnc return ;Overflow call movac ;Move REGA to REGC call clra ;Clear product movlw D'31' ;Loop counter movwf MCOUNT muloop call slac ;Shift left product and multiplicand rlf REGC3,w ;Test MSB of multiplicand skpnc ;If multiplicand bit is a 1 then call addba ;add multiplier to product skpc ;Check for overflow rlf REGA3,w skpnc return decfsz MCOUNT,f ;Next goto muloop btfsc MTEMP,0 ;Check result sign call negatea ;Negative return ;*** 32 BIT SIGNED DIVIDE *** ;REGA / REGB -> REGA ;Remainder in REGC ;Return carry set if overflow or division by zero divide clrf MTEMP ;Reset sign flag movf REGB0,w ;Trap division by zero iorwf REGB1,w iorwf REGB2,w iorwf REGB3,w sublw 0 skpc call absa ;Make dividend (REGA) positive skpc call absb ;Make divisor (REGB) positive skpnc return ;Overflow clrf REGC0 ;Clear remainder clrf REGC1 clrf REGC2 clrf REGC3 call slac ;Purge sign bit movlw D'31' ;Loop counter movwf MCOUNT dvloop call slac ;Shift dividend (REGA) msb into remainder (REGC) movf REGB3,w ;Test if remainder (REGC) >= divisor (REGB) subwf REGC3,w skpz goto dtstgt movf REGB2,w subwf REGC2,w skpz goto dtstgt movf REGB1,w subwf REGC1,w skpz goto dtstgt movf REGB0,w subwf REGC0,w dtstgt skpc ;Carry set if remainder >= divisor goto dremlt movf REGB0,w ;Subtract divisor (REGB) from remainder (REGC) subwf REGC0,f movf REGB1,w skpc incfsz REGB1,w subwf REGC1,f movf REGB2,w skpc incfsz REGB2,w subwf REGC2,f movf REGB3,w skpc incfsz REGB3,w subwf REGC3,f clrc bsf REGA0,0 ;Set quotient bit dremlt decfsz MCOUNT,f ;Next goto dvloop btfsc MTEMP,0 ;Check result sign call negatea ;Negative return ;*** ROUND RESULT OF DIVISION TO NEAREST INTEGER *** round clrf MTEMP ;Reset sign flag call absa ;Make positive clrc call slc ;Multiply remainder by 2 movf REGB3,w ;Test if remainder (REGC) >= divisor (REGB) subwf REGC3,w skpz goto rtstgt movf REGB2,w subwf REGC2,w skpz goto dtstgt movf REGB1,w subwf REGC1,w skpz goto rtstgt movf REGB0,w subwf REGC0,w rtstgt skpc ;Carry set if remainder >= divisor goto rremlt incfsz REGA0,f ;Add 1 to quotient goto rremlt incfsz REGA1,f goto rremlt incfsz REGA2,f goto rremlt incf REGA3,f skpnz return ;Overflow,return carry set rremlt btfsc MTEMP,0 ;Restore sign call negatea return ;*** 32 BIT SQUARE ROOT *** ;sqrt(REGA) -> REGA ;Return carry set if negative sqrt rlf REGA3,w ;Trap negative values skpnc return call movac ;Move REGA to REGC call clrba ;Clear remainder (REGB) and root (REGA) movlw D'16' ;Loop counter movwf MCOUNT sqloop rlf REGC0,f ;Shift two msb's rlf REGC1,f ;into remainder rlf REGC2,f rlf REGC3,f rlf REGB0,f rlf REGB1,f rlf REGB2,f rlf REGC0,f rlf REGC1,f rlf REGC2,f rlf REGC3,f rlf REGB0,f rlf REGB1,f rlf REGB2,f setc ;Add 1 to root rlf REGA0,f ;Align root rlf REGA1,f rlf REGA2,f movf REGA2,w ;Test if remdr (REGB) >= root (REGA) subwf REGB2,w skpz goto ststgt movf REGA1,w subwf REGB1,w skpz goto ststgt movf REGA0,w subwf REGB0,w ststgt skpc ;Carry set if remdr >= root goto sremlt movf REGA0,w ;Subtract root (REGA) from remdr (REGB) subwf REGB0,f movf REGA1,w skpc incfsz REGA1,w subwf REGB1,f movf REGA2,w skpc incfsz REGA2,w subwf REGB2,f bsf REGA0,1 ;Set current root bit sremlt bcf REGA0,0 ;Clear test bit decfsz MCOUNT,f ;Next goto sqloop clrc rrf REGA2,f ;Adjust root alignment rrf REGA1,f rrf REGA0,f return ;*** 32 BIT SIGNED BINARY TO DECIMAL *** ;REGA -> DIGITS 1 (MSD) TO 10 (LSD) & DSIGN ;DSIGN = 0 if REGA is positive, 1 if negative ;Return carry set if overflow ;Uses FSR register bin2dec clrf MTEMP ;Reset sign flag call absa ;Make REGA positive skpnc return ;Overflow call clrdig ;Clear all digits movlw D'32' ;Loop counter movwf MCOUNT b2dloop rlf REGA0,f ;Shift msb into carry rlf REGA1,f rlf REGA2,f rlf REGA3,f movlw DIGIT10 movwf FSR ;Pointer to digits movlw D'10' ;10 digits to do movwf DCOUNT adjlp rlf INDF,f ;Shift digit and carry 1 bit left movlw D'10' subwf INDF,w ;Check and adjust for decimal overflow skpnc movwf INDF decf FSR,f ;Next digit decfsz DCOUNT,f goto adjlp decfsz MCOUNT,f ;Next bit goto b2dloop btfsc MTEMP,0 ;Check sign bsf DSIGN,0 ;Negative clrc return ;*** 32 BIT SIGNED DECIMAL TO BINARY *** ;Decimal DIGIT1 thro DIGIT(X) & DSIGN -> REGA ;Set DSIGN = 0 for positive, DSIGN = 1 for negative values ;Most significant digit in DIGIT1 ;Enter this routine with digit count in w register ;Return carry set if overflow ;Uses FSR register dec2bin movwf MTEMP ;Save digit count movlw D'32' ;Outer bit loop counter movwf MCOUNT d2blp1 movlw DIGIT1-1 ;Set up pointer to MSD movwf FSR movf MTEMP,w ;Inner digit loop counter movwf DCOUNT movlw D'10' clrc ;Bring in '0' bit into MSD d2blp2 incf FSR,f skpnc addwf INDF,f ;Add 10 if '1' bit from prev digit rrf INDF,f ;Shift out LSB of digit decfsz DCOUNT,f ;Next L.S. Digit goto d2blp2 rrf REGA3,f ;Shift in carry from digits rrf REGA2,f rrf REGA1,f rrf REGA0,f decfsz MCOUNT,f ;Next bit goto d2blp1 movf INDF,w ;Check for overflow addlw 0xFF skpc rlf REGA3,w skpnc return btfsc DSIGN,0 ;Check result sign call negatea ;Negative return ;UTILITY ROUTINES ;Add REGB to REGA (Unsigned) ;Used by add, multiply, addba movf REGB0,w ;Add lo byte addwf REGA0,f movf REGB1,w ;Add mid-lo byte skpnc ;No carry_in, so just add incfsz REGB1,w ;Add carry_in to REGB addwf REGA1,f ;Add and propagate carry_out movf REGB2,w ;Add mid-hi byte skpnc incfsz REGB2,w addwf REGA2,f movf REGB3,w ;Add hi byte skpnc incfsz REGB3,w addwf REGA3,f return ;Move REGA to REGC ;Used by multiply, sqrt movac movf REGA0,w movwf REGC0 movf REGA1,w movwf REGC1 movf REGA2,w movwf REGC2 movf REGA3,w movwf REGC3 return ;Clear REGB and REGA ;Used by sqrt clrba clrf REGB0 clrf REGB1 clrf REGB2 clrf REGB3 ;Clear REGA ;Used by multiply, sqrt clra clrf REGA0 clrf REGA1 clrf REGA2 clrf REGA3 return ;Check sign of REGA and convert negative to positive ;Used by multiply, divide, bin2dec, round absa rlf REGA3,w skpc return ;Positive ;Negate REGA ;Used by absa, multiply, divide, bin2dec, dec2bin, round negatea movf REGA3,w ;Save sign in w andlw 0x80 comf REGA0,f ;2's complement comf REGA1,f comf REGA2,f comf REGA3,f incfsz REGA0,f goto nega1 incfsz REGA1,f goto nega1 incfsz REGA2,f goto nega1 incf REGA3,f nega1 incf MTEMP,f ;flip sign flag addwf REGA3,w ;Return carry set if -2147483648 return ;Check sign of REGB and convert negative to positive ;Used by multiply, divide absb rlf REGB3,w skpc return ;Positive ;Negate REGB ;Used by absb, subtract, multiply, divide negateb movf REGB3,w ;Save sign in w andlw 0x80 comf REGB0,f ;2's complement comf REGB1,f comf REGB2,f comf REGB3,f incfsz REGB0,f goto negb1 incfsz REGB1,f goto negb1 incfsz REGB2,f goto negb1 incf REGB3,f negb1 incf MTEMP,f ;flip sign flag addwf REGB3,w ;Return carry set if -2147483648 return ;Shift left REGA and REGC ;Used by multiply, divide, round slac rlf REGA0,f rlf REGA1,f rlf REGA2,f rlf REGA3,f slc rlf REGC0,f rlf REGC1,f rlf REGC2,f rlf REGC3,f return ;Set all digits to 0 ;Used by bin2dec clrdig clrf DSIGN clrf DIGIT1 clrf DIGIT2 clrf DIGIT3 clrf DIGIT4 clrf DIGIT5 clrf DIGIT6 clrf DIGIT7 clrf DIGIT8 clrf DIGIT9 clrf DIGIT10 return+
bin2dec clrf MTEMP ;Reset sign flag
call absa ;Make REGA positive
call clrdig ;Clear all digits
movlw D'32' ;Loop counter
for movlw D'32' you have result=result*2
should be movlw D'31'
I'd like to use this 32bit math routines, but dec2bin does not perform well. After my trial, I have found the problem in this coding. Perhaps I have to change the coding as follow.dec2bin movlw D'32' movwf MCOUNT d2blp1 movlw DIGIT-1 movwf FSR movlw D'10' ;here MTEMP => D'10' movwf DCOUNT so..on
|file: /Techref/microchip/math/32bmath-ph.htm, 39KB, , updated: 2017/2/17 17:04, local time: 2023/1/29 08:08,
|©2023 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?|
<A HREF="http://techref.massmind.org/techref/microchip/math/32bmath-ph.htm"> 32-bit signed integer math routines. add, subtract, multiply, divide, round, sqrt, bin2dec, dec2bin. By Peter Hemsley.</A>
|Did you find what you needed?|
Welcome to massmind.org!
Welcome to techref.massmind.org!