diff src/math.asm @ 0:11d4fc797f74

init
author heinrichsweikamp
date Wed, 24 Apr 2013 19:22:45 +0200
parents
children 653a3ab08062
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/math.asm	Wed Apr 24 19:22:45 2013 +0200
@@ -0,0 +1,325 @@
+;=============================================================================
+;
+;   File math.asm
+;
+;   Math subroutines
+;
+;   Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
+;=============================================================================
+; HISTORY
+;  2011-08-03 : [mH] moving from OSTC code
+
+
+#include    "ostc3.inc"                  ; Mandatory header
+
+basic   CODE
+;=============================================================================
+	global	convert_time
+convert_time:							; converts hi:lo in minutes to hours (hi) and minutes (lo)
+	movff	lo,xA+0						; divide by 60...
+	movff	hi,xA+1						; 
+	movlw	d'60'						; 
+	movwf	xB+0						; 
+	clrf	xB+1						; 
+	rcall	div16x16					; xA/xB=xC with xA as remainder
+	movff	xC+0,hi						; Hours
+	movff	xA+0,lo						; =remaining minutes (0.....59)
+	return
+
+	global	div16
+div16:
+; divA=divA/2^divB (divB: 8Bit only!)
+	bcf		STATUS,C
+	rrcf	divA+1
+	rrcf	divA+0
+	decfsz	divB
+	bra		div16
+	return
+
+	global	sub16
+sub16:
+;  sub_c = sub_a - sub_b (with signed values)
+	bcf		neg_flag
+	movf   	sub_b+0, W             	; Get Value to be subtracted
+	subwf  	sub_a+0, W             	; Do the High Byte
+	movwf  	sub_c+0
+	movf   	sub_b+1, W              ; Get the Value to be Subbed
+	subwfb 	sub_a+1, W
+	movwf  	sub_c+1
+
+	btfss	STATUS,N                ; Negativ result ?
+	return							; NO: result positive done.
+
+	bsf		neg_flag				; MARK result negative
+
+    comf    sub_c+1                 ; 16bit sign change.
+    negf    sub_c+0
+    btfsc   STATUS,C                ; Carry to propagate ?
+    incf    sub_c+1,F               ; YES: do it.
+
+    return        
+
+	global	subU16
+subU16:
+;  sub_c = sub_a - sub_b (with UNSIGNED values)
+	bcf		neg_flag
+	movf   	sub_b+0, W             	; Get Value to be subtracted
+	subwf  	sub_a+0, W             	; Do the High Byte
+	movwf  	sub_c+0
+	movf   	sub_b+1, W              ; Get the Value to be Subbed
+	subwfb 	sub_a+1, W
+	movwf  	sub_c+1
+	btfsc	STATUS,C                ; Borrow to propagate ? (B == /CARRY)
+	return							; NO: result positive done.
+	bsf		neg_flag				; MARK result negative
+    comf    sub_c+1                 ; 16bit sign change.
+    negf    sub_c+0
+    btfsc   STATUS,C                ; Carry to propagate ?
+    incf    sub_c+1,F               ; YES: do it.
+    return        
+
+	global	mult16x16
+mult16x16:		;xA*xB=xC
+	clrf    xC+2        	  ;  Clear the High-Order Bits
+	clrf    xC+3
+	movf    xA, w               ;  Do the "L" Multiplication first
+	mulwf   xB
+	movf    PRODL, w            ;  Save result
+	movwf   xC
+	movf    PRODH, w
+	movwf   xC+1
+	movf    xA, w               ;  Do the "I" Multiplication
+	mulwf   xB+1
+	movf    PRODL, w            ;  Save the Most Significant Byte First
+	addwf   xC+1, f
+	movf    PRODH, w
+	addwfc  xC+2, f    	 		 ;  Add to the Last Result
+	movf    xA+1, w               ;  Do the "O" Multiplication
+	mulwf   xB
+	movf    PRODL, w            ;  Add the Lower Byte Next
+	addwf   xC+1, f
+	movf    PRODH, w            ;  Add the High Byte First
+	addwfc  xC+2, f
+	btfsc   STATUS, C           ;  Add the Carry
+	incf    xC+3, f
+	movf    xA+1, w               ;  Do the "F" Multiplication
+	mulwf   xB+1
+	movf    PRODL, w
+	addwf   xC+2, f
+	movf    PRODH, w
+	addwfc  xC+3, f
+	return
+
+	global	div16x16
+div16x16:						;xA/xB=xC with xA+0 as remainder 	
+								;uses divB as temp variable
+		clrf	xC+0
+		clrf	xC+1
+        MOVF    xB+0,W       	; Check for zero
+        IORWF   xB+1,W     		; 
+        BTFSC   STATUS,Z        ; Check for zero
+        RETLW   H'FF'           ; return 0xFF if illegal
+        MOVLW   1               ; Start count at 1
+        MOVWF   divB	       ; Clear Count
+div16x16_1:
+    	BTFSC   xB+1,7     		; High bit set ?
+        bra	    div16x16_2      ; Yes then continue
+        INCF    divB,F     		; Increment count
+
+		bcf		STATUS,C
+		rlcf	xB+0,F
+		rlcf	xB+1,F
+        bra	    div16x16_1
+div16x16_2:
+								; Shift result left
+		bcf		STATUS,C
+		rlcf	xC+0,F
+		rlcf	xC+1,F
+
+ 			; Reduce Divisor		
+
+        MOVF    xB,W         ; Get low byte of subtrahend
+        SUBWF   xA,F         ; Subtract DST(low) - SRC(low)
+        MOVF    xB+1,W       ; Now get high byte of subtrahend
+        BTFSS   STATUS,C     ; If there was a borrow, rather than
+        INCF    xB+1,W       ; decrement high byte of dst we inc src
+        SUBWF   xA+1,F       ; Subtract the high byte and we're done
+
+
+        BTFSC   STATUS, C       ; Did it reduce?        
+        bra	    div16x16_3      ; No, so it was less than
+
+		movf	xB+0,W			; Reverse subtraction
+		addwf	xA+0,F
+		movf	xB+1,W
+		addwfc	xA+1,F
+
+        bra	    div16x16_4      ; Continue the process
+div16x16_3:
+	     BSF     xC+0,0        	; Yes it did, this gets a 1 bit
+div16x16_4:
+	     DECF    divB,F 		    ; Decrement N_COUNT
+        BTFSC   STATUS,Z        ; If its not zero then continue
+        return
+
+		bcf		STATUS,C
+		rrcf	xB+1,F
+		rrcf	xB+0,F
+
+        bra    div16x16_2              ; Next bit.
+
+	global	div32x16
+div32x16:  ; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder
+	; Setup
+	movlw		.32		; setup shift counter
+	movwf		divB
+	movff		xC+3,xA+1		; move ACCb to ACCf
+	movff		xC+2,xA+0
+	movff		xC+1,sub_a+1	; move ACCc to ACCe
+	movff		xC+0,sub_a+0
+	clrf		xC+3
+	clrf		xC+2
+	clrf		xC+1
+	clrf		xC+0
+	clrf		sub_b+1
+	clrf		sub_b+0
+div32x16_2:
+	bcf			STATUS,C
+	rlcf		sub_a+0,F
+	rlcf		sub_a+1,F
+	rlcf		xA+0,F
+	rlcf		xA+1,F
+	rlcf		sub_b+0,F
+	rlcf		sub_b+1,F
+	movf		xB+1,W
+	subwf		sub_b+1,W	; check if a>d
+	btfss		STATUS,Z
+	bra			div32x16_3
+	movf		xB+0,W
+	subwf		sub_b+0,W	; if msb equal then check lsb
+div32x16_3:
+	btfss		STATUS,C	; carry set if d>a
+	bra			div32x16_4
+	movf		xB+0,W		; d-a into d
+	subwf		sub_b+0,F
+	btfss		STATUS,C
+	decf		sub_b+1,F
+	movf		xB+1,W
+	subwf		sub_b+1,F
+	bsf			STATUS,C	; shift a 1 into b (result)
+div32x16_4:
+	rlcf		xC+0,F
+	rlcf		xC+1,F
+	rlcf		xC+2,F
+	rlcf		xC+3,F
+	decfsz		divB,F	; loop until all bits checked
+	bra			div32x16_2
+	return
+
+;;=============================================================================
+;; u16 * u16 --> 32bit multiply (xA * xB --> xC)
+;; Used in interupt service routines, to compute temperature and pressure.
+;;
+;	global	isr_mult16x16
+;isr_mult16x16:
+;	clrf    isr_xC+2        	  ;  Clear the High-Order Bits
+;	clrf    isr_xC+3
+;	movf    isr_xA, w               ;  Do the "L" Multiplication first
+;	mulwf   isr_xB
+;	movf    PRODL, w            ;  Save result
+;	movwf   isr_xC+0
+;	movf    PRODH, w
+;	movwf   isr_xC+1
+;	movf    isr_xA+0, w               ;  Do the "I" Multiplication
+;	mulwf   isr_xB+1
+;	movf    PRODL, w            ;  Save the Most Significant Byte First
+;	addwf   isr_xC+1, f
+;	movf    PRODH, w
+;	addwfc  isr_xC+2, f    	 		 ;  Add to the Last Result
+;	movf    isr_xA+1, w               ;  Do the "O" Multiplication
+;	mulwf   isr_xB
+;	movf    PRODL, w            ;  Add the Lower Byte Next
+;	addwf   isr_xC+1, f
+;	movf    PRODH, w            ;  Add the High Byte First
+;	addwfc  isr_xC+2, f
+;	btfsc   STATUS, C           ;  Add the Carry
+;	incf    isr_xC+3, f
+;	movf    isr_xA+1, w               ;  Do the "F" Multiplication
+;	mulwf   isr_xB+1
+;	movf    PRODL, w
+;	addwf   isr_xC+2, f
+;	movf    PRODH, w
+;	addwfc  isr_xC+3, f
+;	return
+
+;=============================================================================
+; 24bit shift, repeted WREG times.
+; Because we shift less than 8bits, and keep only C[2:1], we don't care what
+; bit is inserted...
+;
+	global	isr_shift_C31
+isr_shift_C31:
+	rrcf    isr_xC+3,F                  ; Shift the three bytes...
+	rrcf    isr_xC+2,F
+	rrcf    isr_xC+1,F
+	decfsz  WREG
+	bra     isr_shift_C31
+	return
+
+;=============================================================================
+; s16 * s16 --> 32bit multiply (xA * xB --> xC)
+; Signed multiplication.
+; Code from... the Pic18F documentation ;-)
+	global	isr_unsigned_mult16x16
+isr_unsigned_mult16x16:
+        MOVF    isr_xA+0, W             ; Lowest is simply a[0] * b[0]
+        MULWF   isr_xB+0
+        MOVFF   PRODL, isr_xC+0
+        MOVFF   PRODH, isr_xC+1
+        ;
+        MOVF    isr_xA+1, W             ; And highest a[1] * b[1]
+        MULWF   isr_xB+1
+        MOVFF   PRODL, isr_xC+2
+        MOVFF   PRODH, isr_xC+3
+        ;
+        MOVF    isr_xA+0, W             ; Intermediates do propagate:
+        MULWF   isr_xB+1
+        MOVF    PRODL, W
+        ADDWF   isr_xC+1, F             ; Add cross products
+        MOVF    PRODH, W
+        ADDWFC  isr_xC+2, F             ; with propagated carry
+        CLRF    WREG
+        ADDWFC  isr_xC+3, F             ; on the three bytes.
+        ;
+        MOVF    isr_xA+1, W             ; And the second one, similarly.
+        MULWF   isr_xB+0
+        MOVF    PRODL, W
+        ADDWF   isr_xC+1, F             ; Add cross products
+        MOVF    PRODH, W
+        ADDWFC  isr_xC+2, F
+        CLRF    WREG
+        ADDWFC  isr_xC+3, F
+        return
+
+	global	isr_signed_mult16x16
+isr_signed_mult16x16:
+        rcall   isr_unsigned_mult16x16
+
+        ; Manage sign extension of operand B
+        BTFSS   isr_xB+1,7              ; Is B negatif ?
+        BRA     isr_signed_mult_checkA  ; No: check ARG1
+        MOVF    isr_xA+0, W             ; Yes: add -65536 * A
+        SUBWF   isr_xC+2, F
+        MOVF    isr_xA+1, W
+        SUBWFB  isr_xC+3, F
+        ; And of operand A
+isr_signed_mult_checkA
+        BTFSS   isr_xA+1, 7             ; Is A negatif ?
+        RETURN                          ; No: done
+        MOVF    isr_xB+0, W
+        SUBWF   isr_xC+2, F
+        MOVF    isr_xB+1, W
+        SUBWFB  isr_xC+3, F
+        RETURN
+
+ END
\ No newline at end of file