Hola agaran!
Estas son las rutinas que yo personalmente utilizo. En su día las busqué, me funcionaron bien y... nunca me ha dado por optimizarlas (no he tenido tiempo).
Codigo:
suma_16_bits
movf Dato_A_L,W ;Carga menos peso del dato A
addwf Dato_B_L,W ;Suma menos peso del dato B
movwf Resultado_L ;Almacena el resultado
movf Dato_A_H,W ;Carga más peso del dato A
btfsc STATUS,C ;Hubo acarreo anterior ??
addlw 1 ;Si, suma 1 al acumulador
addwf Dato_B_H,W ;Suma más peso del dato B
movwf Resultado_H ;Guarda el resultado
return
Codigo:
resta_16_bits
movf Dato_B_L,W ;Carga menos peso del dato B (sustraendo)
subwf Dato_A_L,W ;Resta menos peso del dato A (minuendo)
movwf Resultado_L ;Almacena el resultado
movf Dato_B_H,W ;Carga más peso del dato B (sustraendo)
btfss STATUS,C ;Hubo acarreo (CARRY = 0) anterior ??
addlw 1 ;Si, añade 1 al acumulador (sustraendo)
subwf Dato_A_H,W ;Resta más peso del dato A (minuendo)
movwf Resultado_H ;Guarda el resultado
return
Codigo:
; MULTIPLY multiplier, multiplicand
; Multiply two 16-bit numbers into a 16-bit product, permitting overflow.
Multiply
CLRF prodH ; Clear product to make
CLRF prodL ; way for new calculation.
MOVLW d"16" ; Number of bits to calc.
MOVWF index
Multiply_loop
BCF STATUS,C
RLF prodL ; Shift product left.
RLF prodH
BCF STATUS,C
RLF mulcL ; Shift multiplicand left.
RLF mulcH
BTFSS STATUS,C ; If carry, add multiplier
GOTO Multiply_skip
MOVF mulpL,w ; to the product. Else skip.
ADDWF prodL
BTFSC STATUS,C ; 16-bit addition: prod+mulp
INCF prodH
MOVF mulpH,w
ADDWF prodH
Multiply_skip
DECFSZ index
GOTO Multiply_loop
RETLW 0h
Codigo:
; ; DIVIDE
; Divide one 16-bit number into another, returning the 16-bit result and
; the remainder. Upon entry, the top of the division fraction (the dividend)
; must be in topH and topL, and the bottom (divisor) in btmH and btmL.
; If division by zero is attempted, the routine will return immediately with
; the error code of 0FFh in w. Otherwise, it will perform the division, leaving
; the remainder in topH and topL and the result (quotient) in qH and qL.
; Upon return from a successful division, w contains 0.
Divide MOVF btmH,w ; Check for division by 0.
IORWF btmL,w
BTFSC STATUS,Z
RETLW d"255" ; Error code= 255: return.
MOVLW d"1" ; Otherwise, initialize variables
MOVWF count
CLRF index ; for the division.
CLRF qH
CLRF qL
Divide_sh_loop BTFSC btmH,d"7" ; Shift divisor left
GOTO Divide_d1
BCF STATUS,C ; until msb is in
RLF btmL ; btmH.7.
RLF btmH ; count = no. of shifts+1.
INCF count
GOTO Divide_sh_loop
Divide_d1 BCF STATUS,C
RLF qL ; Shift quotient left.
RLF qH
MOVF btmL,w ; top = top - btm.
SUBWF topL
BTFSC STATUS,C ; If top - btm < 0 then
GOTO Divide_d2
MOVLW d"1" ; top = top + btm
SUBWF topH
BTFSC STATUS,C ; The idea is to do the
GOTO Divide_d2
INCF topH ; the subtraction and comparison
MOVF btmL,w ; (top > btm?) in one step.
ADDWF topL
goto Divide_reentr ; Then, if btm > top, undo <Microchip instruction>
Divide_d2 MOVF btmH,w ; the subtraction by adding
SUBWF topH
BTFSS STATUS,C ; top and btm back together
goto Divide_less ; <Microchip instruction>
BSF qL,d"0"
Divide_reentr
BCF STATUS,C
RRF btmH
RRF btmL
DECFSZ count
GOTO Divide_d1
RETLW 0h ; Return w/ remainder in top
; and result in q.&nsp;
Divide_less MOVF btmL,w ; btm > top, so
ADDWF topL
BTFSC STATUS,C ; undo the subtraction by
INCF topH ; adding them back together.
MOVF btmH,w
ADDWF topH
goto Divide_reentr ; <Microchip instruction>
Vamos a sumar 1111+3333 (el resultado será 4444).
1111 (decimal) = 00000100 01010111
3333 (decimal) = 00001101 00000101
movlw b"00000100"
movwf Dato_A_H
movlw b"01010111"
movwf Dato_A_L
movlw b"00001101"
movwf Dato_B_H
movlw b"00000101"
movwf Dato_B_L
call suma_16_bits
El resultado lo tienes en las variables Resultado_H y Resultado_L
Resultado_H = 00010001
Resultado_L = 01011100
La resta no tienes más que pegarle un vistazo (es prácticamente igual).
Para explicar la multiplicación haremos la siguiente operación.
133 * 99 = 13167
133 = 00000000 10000101
99 = 00000000 01100011
movlw b"00000000"
movwf mulcH
movlw b"10000101"
movwf mulcL
movlw b"00000000"
movwf mulpH
movlw b"01100011"
movwf mulpL
call Multiply
El resultado lo tienes en las variables prodH y prodL
prodH = 00110011
prodL = 01101111
Para la división puedes leer el comentario de la función (explican como utilizarla).
Ya me comentas como te va la cosa.
Un saludo desde Alicante.