comparison src/math.asm @ 604:ca4556fb60b9

bump to 2.99beta, work on 3.00 stable
author heinrichsweikamp
date Thu, 22 Nov 2018 19:47:26 +0100
parents 653a3ab08062
children c40025d8e750
comparison
equal deleted inserted replaced
603:00b24fb4324d 604:ca4556fb60b9
1 ;============================================================================= 1 ;=============================================================================
2 ; 2 ;
3 ; File math.asm 3 ; File math.asm REFACTORED VERSION V2.99d
4 ; 4 ;
5 ; Math subroutines 5 ; Math subroutines
6 ; 6 ;
7 ; Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved. 7 ; Copyright (c) 2011, JD Gascuel, HeinrichsWeikamp, all right reserved.
8 ;============================================================================= 8 ;=============================================================================
9 ; HISTORY 9 ; HISTORY
10 ; 2011-08-03 : [mH] moving from OSTC code 10 ; 2011-08-03 : [mH] moving from OSTC code
11 11
12 12
13 #include "hwos.inc" ; Mandatory header 13 #include "hwos.inc" ; mandatory header
14 14
15 basic CODE 15 math CODE
16 ;============================================================================= 16
17 global convert_time 17 ;=============================================================================
18 convert_time: ; converts hi:lo in minutes to hours (hi) and minutes (lo) 18
19 movff lo,xA+0 ; divide by 60... 19 global convert_time ; converts hi:lo in minutes to hours (up:hi) and minutes (lo)
20 movff hi,xA+1 ; 20 ; also usable for conversion of seconds to minutes and seconds
21 movlw d'60' ; 21 ; trashes xA, xB, xC
22 movwf xB+0 ; 22 convert_time:
23 movff lo,xA+0 ; copy hi:lo to xA
24 movff hi,xA+1 ;
25 movlw d'60' ; set divisor to 60
26 movwf xB+0 ; write 60 to xB
23 clrf xB+1 ; 27 clrf xB+1 ;
24 rcall div16x16 ; xA/xB=xC with xA as remainder 28 rcall div16x16 ; xC = xA / xB with xA as remainder
25 movff xC+0,hi ; Hours 29 movff xC+1,up ; result is hours / minutes, copy to up (high byte)
26 movff xA+0,lo ; =remaining minutes (0.....59) 30 movff xC+0,hi ; result is hours / minutes, copy to hi (low byte)
27 return 31 movff xA+0,lo ; remainder is minutes / seconds, copy to lo
28 32 return
29 global div16 33
34
35 global div16 ; divA:2 = divA:2 / 2^WREG
36 ; trashes WREG
30 div16: 37 div16:
31 ; divA=divA/2^divB (divB: 8Bit only!) 38 bcf STATUS,C ; clear carry
32 bcf STATUS,C 39 rrcf divA+1 ; rotate right high byte, carry into MSB, LSB into carry
33 rrcf divA+1 40 rrcf divA+0 ; rotate right low byte, carry into MSB, LSB into carry
34 rrcf divA+0 41 decfsz WREG ; decrement counter, done?
35 decfsz divB 42 bra div16 ; NO - loop
36 bra div16 43 return ; YES - done
37 return 44
38 45
39 global sub16 46 global mult16 ; xA:2 = xA:2 * 2^WREG
47 ; trashes WREG
48 mult16:
49 bcf STATUS,C ; clear carry
50 rlcf divA+0,F ; rotate left low byte, carry into LSB, MSB into carry
51 rlcf divA+1,F ; rotate left high byte, carry into LSB, MSB into carry
52 decfsz WREG ; decrement counter, done?
53 bra mult16 ; NO - loop
54 return ; YES - done
55
56
57 global sub16 ; sub_c:2 = sub_a:2 - sub_b:2 with SIGNED values
58 ; sets neg_flag if result is < 0
59 ; trashes WREG
40 sub16: 60 sub16:
41 ; sub_c = sub_a - sub_b (with signed values) 61 bcf neg_flag ; clear flag which will indicate if result is negative
42 bcf neg_flag 62 movf sub_b+0,W ; get value to be subtracted, low byte
43 movf sub_b+0, W ; Get Value to be subtracted 63 subwf sub_a+0,W ; execute subtraction on low byte
44 subwf sub_a+0, W ; Do the High Byte 64 movwf sub_c+0 ; copy result to output variable, low byte
45 movwf sub_c+0 65 movf sub_b+1,W ; get value to be subtracted, high byte
46 movf sub_b+1, W ; Get the Value to be Subbed 66 subwfb sub_a+1,W ; execute subtraction on high byte, considering borrow flag
47 subwfb sub_a+1, W 67 movwf sub_c+1 ; copy result to output variable, high byte
48 movwf sub_c+1 68 btfss STATUS,N ; result negative ?
49 69 return ; NO - result positive, done
50 btfss STATUS,N ; Negativ result ? 70 bsf neg_flag ; YES - set flag
51 return ; NO: result positive done. 71 comf sub_c+1 ; - do a 16 bit sign change
52 72 negf sub_c+0 ;
53 bsf neg_flag ; MARK result negative 73 btfsc STATUS,C ; - carry to be propagated ?
54 74 incf sub_c+1,F ; YES - do it
55 comf sub_c+1 ; 16bit sign change. 75 return ; - done
56 negf sub_c+0 76
57 btfsc STATUS,C ; Carry to propagate ? 77
58 incf sub_c+1,F ; YES: do it. 78 global subU16 ; sub_c:2 = sub_a:2 - sub_b:2 with UNSIGNED values
59 79 ; sets neg_flag if result is < 0
60 return 80 ; trashes WREG
61
62 global subU16
63 subU16: 81 subU16:
64 ; sub_c = sub_a - sub_b (with UNSIGNED values) 82 bcf neg_flag ; clear flag which will indicate if result is negative
65 bcf neg_flag 83 movf sub_b+0,W ; get Value to be subtracted, low byte
66 movf sub_b+0, W ; Get Value to be subtracted 84 subwf sub_a+0,W ; execute subtraction on low byte
67 subwf sub_a+0, W ; Do the High Byte 85 movwf sub_c+0 ; copy result to output variable, low byte
68 movwf sub_c+0 86 movf sub_b+1,W ; get value to be subtracted, high byte
69 movf sub_b+1, W ; Get the Value to be Subbed 87 subwfb sub_a+1,W ; execute subtraction on high byte, considering borrow flag
70 subwfb sub_a+1, W 88 movwf sub_c+1 ; copy result to output variable, high byte
71 movwf sub_c+1 89 btfsc STATUS,C ; borrow to propagate (B == /CARRY) ?
72 btfsc STATUS,C ; Borrow to propagate ? (B == /CARRY) 90 return ; NO - result positive, done
73 return ; NO: result positive done. 91 bsf neg_flag ; YES - set flag
74 bsf neg_flag ; MARK result negative 92 comf sub_c+1 ; - do a 16 bit sign change
75 comf sub_c+1 ; 16bit sign change. 93 negf sub_c+0 ;
76 negf sub_c+0 94 btfsc STATUS,C ; - carry to be propagated ?
77 btfsc STATUS,C ; Carry to propagate ? 95 incf sub_c+1,F ; YES - do it
78 incf sub_c+1,F ; YES: do it. 96 return ; - done
79 return 97
80 98
81 global mult16x16 99 global mult16x16 ; xC:4 = xA:2 * xB:2 with UNSIGNED values
82 mult16x16: ;xA*xB=xC 100 ; trashes PRODL, PRODH, WREG
83 clrf xC+2 ; Clear the High-Order Bits 101 mult16x16:
84 clrf xC+3 102 clrf xC+2 ; clear the high-order bits
85 movf xA, w ; Do the "L" Multiplication first 103 clrf xC+3
86 mulwf xB 104 ;
87 movf PRODL, w ; Save result 105 movf xA+0,W ; do the "L" multiplication
88 movwf xC 106 mulwf xB+0
89 movf PRODH, w 107 movff PRODL,xC+0 ; copy result to xC
90 movwf xC+1 108 movff PRODH,xC+1
91 movf xA, w ; Do the "I" Multiplication 109 ;
92 mulwf xB+1 110 movf xA+0,W ; do the "I" multiplication
93 movf PRODL, w ; Save the Most Significant Byte First 111 mulwf xB+1
94 addwf xC+1, f 112 movf PRODL,W ; get the product's low byte...
95 movf PRODH, w 113 addwf xC+1,F ; ... and add it to xC+1
96 addwfc xC+2, f ; Add to the Last Result 114 movf PRODH,W ; get the product's high byte...
97 movf xA+1, w ; Do the "O" Multiplication 115 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1
98 mulwf xB 116 ;
99 movf PRODL, w ; Add the Lower Byte Next 117 movf xA+1,W ; do the "O" multiplication
100 addwf xC+1, f 118 mulwf xB+0
101 movf PRODH, w ; Add the High Byte First 119 movf PRODL,W ; get the product's low byte...
102 addwfc xC+2, f 120 addwf xC+1,F ; ... and add it to xC+1
103 btfsc STATUS, C ; Add the Carry 121 movf PRODH,W ; get the product's high byte...
104 incf xC+3, f 122 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1
105 movf xA+1, w ; Do the "F" Multiplication 123 clrf WREG ; clear WREG...
106 mulwf xB+1 124 addwfc xC+3,F ; ... add add it to xC+3 obeying carry bit from xC+2 (can only happen in "O" multiplication)
107 movf PRODL, w 125 ;
108 addwf xC+2, f 126 movf xA+1,W ; do the "F" multiplication
109 movf PRODH, w 127 mulwf xB+1
110 addwfc xC+3, f 128 movf PRODL,W ; get the product's low byte...
111 return 129 addwf xC+2,F ; ... and add it to xC+2
112 130 movf PRODH,W ; get the product's high byte...
113 global div16x16 131 addwfc xC+3,F ; ... and add it to xC+3 obeying carry bit from xC+2
114 div16x16: ;xA/xB=xC with xA+0 as remainder 132 return
115 ;uses divB as temp variable 133
116 clrf xC+0 134
117 clrf xC+1 135 global div16x16 ; xC:2 = xA:2 / xB:2 with xA as remainder
118 MOVF xB+0,W ; Check for zero 136 ; trashes WREG
119 IORWF xB+1,W ; 137 div16x16:
120 BTFSC STATUS,Z ; Check for zero 138 movlw .16 ; process 16 bits ...
121 RETLW H'FF' ; return 0xFF if illegal 139 movwf math_loop ; ... initialize loop counter
122 MOVLW 1 ; Start count at 1 140 movff xA+0,xC+0 ; copy xA to xC
123 MOVWF divB ; Clear Count 141 movff xA+1,xC+1 ; ...
142 clrf xA+0 ; clear xA, will now be used to hold the remainder
143 clrf xA+1 ; ...
124 div16x16_1: 144 div16x16_1:
125 BTFSC xB+1,7 ; High bit set ? 145 bcf STATUS,C ; clear carry flag to shift in a zero bit
126 bra div16x16_2 ; Yes then continue 146 rlcf xC+0,F ; shift left xC
127 INCF divB,F ; Increment count 147 rlcf xC+1,F ; ... shifting MSB out of xC...
128 148 rlcf xA+0,F ; ... and into LSB of xA
129 bcf STATUS,C 149 rlcf xA+1,F ; ...
130 rlcf xB+0,F 150 btfsc STATUS,C ; did the remainder overflow (carry set)?
131 rlcf xB+1,F 151 bra div16x16_2 ; YES - directly generate a result bit = 1
132 bra div16x16_1 152 movf xB+0,W ; NO - compute remainder - divisor = xA - xB, trash result to WREG
153 subwf xA+0,W ; - ...
154 movf xB+1,W ; - ...
155 subwfb xA+1,W ; - ...
156 btfss STATUS,C ; - remainder < divisor (-> borrow flag set, equals carry flag cleared) ?
157 bra div16x16_3 ; YES - result bit = 0, keep LSB of xC+0 being 0
133 div16x16_2: 158 div16x16_2:
134 ; Shift result left 159 bsf xC+0,0 ; NO - result bit = 1, set LSB of xC+0 to 1
135 bcf STATUS,C 160 movf xB+0,W ; - subtract divisor from remainder "for real": xA = xA - xB
136 rlcf xC+0,F 161 subwf xA+0,F ; - ...
137 rlcf xC+1,F 162 movf xB+1,W ; - ...
138 163 subwfb xA+1,F ; - ...
139 ; Reduce Divisor
140
141 MOVF xB,W ; Get low byte of subtrahend
142 SUBWF xA,F ; Subtract DST(low) - SRC(low)
143 MOVF xB+1,W ; Now get high byte of subtrahend
144 BTFSS STATUS,C ; If there was a borrow, rather than
145 INCF xB+1,W ; decrement high byte of dst we inc src
146 SUBWF xA+1,F ; Subtract the high byte and we're done
147
148
149 BTFSC STATUS, C ; Did it reduce?
150 bra div16x16_3 ; No, so it was less than
151
152 movf xB+0,W ; Reverse subtraction
153 addwf xA+0,F
154 movf xB+1,W
155 addwfc xA+1,F
156
157 bra div16x16_4 ; Continue the process
158 div16x16_3: 164 div16x16_3:
159 BSF xC+0,0 ; Yes it did, this gets a 1 bit 165 decfsz math_loop,F ; decrement loop counter, all bits done?
160 div16x16_4: 166 bra div16x16_1 ; NO - loop
161 DECF divB,F ; Decrement N_COUNT 167 return ; YES - done
162 BTFSC STATUS,Z ; If its not zero then continue 168
163 return 169
164 170 global div32x16 ; xC:4 = xC:4 / xB:2 with xA as remainder
165 bcf STATUS,C 171 ; trashes WREG
166 rrcf xB+1,F 172 div32x16:
167 rrcf xB+0,F 173 movlw .32 ; process 32 bits ...
168 174 movwf math_loop ; ... initialize loop counter
169 bra div16x16_2 ; Next bit. 175 clrf xA+0 ; clear xA, will be used to hold the remainder
170 176 clrf xA+1 ; ...
171 global div32x16 177 div32x16_1:
172 div32x16: ; xC:4 / xB:2 = xC+3:xC+2 with xC+1:xC+0 as remainder 178 bcf STATUS,C ; clear carry flag to shift in a zero bit
173 ; Setup 179 rlcf xC+0,F ; shift left xC
174 movlw .32 ; setup shift counter 180 rlcf xC+1,F ; ...
175 movwf divB 181 rlcf xC+2,F ; ...
176 movff xC+3,xA+1 ; move ACCb to ACCf 182 rlcf xC+3,F ; ... shifting MSB out of xC...
177 movff xC+2,xA+0 183 rlcf xA+0,F ; ... and into LSB of xA
178 movff xC+1,sub_a+1 ; move ACCc to ACCe 184 rlcf xA+1,F ; ...
179 movff xC+0,sub_a+0 185 btfsc STATUS,C ; did the remainder overflow (carry set)?
180 clrf xC+3 186 bra div32x16_2 ; YES - directly generate a result bit = 1
181 clrf xC+2 187 movf xB+0,W ; NO - compute remainder - divisor = xA - xB, trash result to WREG
182 clrf xC+1 188 subwf xA+0,W ; - ...
183 clrf xC+0 189 movf xB+1,W ; - ...
184 clrf sub_b+1 190 subwfb xA+1,W ; - ...
185 clrf sub_b+0 191 btfss STATUS,C ; - remainder < divisor (-> borrow flag set, equals carry flag cleared) ?
192 bra div32x16_3 ; YES - result bit = 0, keep LSB of xC+0 being 0
186 div32x16_2: 193 div32x16_2:
187 bcf STATUS,C 194 bsf xC+0,0 ; NO - result bit = 1, set LSB of xC+0 to 1
188 rlcf sub_a+0,F 195 movf xB+0,W ; - subtract divisor from remainder "for real": xA = xA - xB
189 rlcf sub_a+1,F 196 subwf xA+0,F ; - ...
190 rlcf xA+0,F 197 movf xB+1,W ; - ...
191 rlcf xA+1,F 198 subwfb xA+1,F ; - ...
192 rlcf sub_b+0,F
193 rlcf sub_b+1,F
194 movf xB+1,W
195 subwf sub_b+1,W ; check if a>d
196 btfss STATUS,Z
197 bra div32x16_3
198 movf xB+0,W
199 subwf sub_b+0,W ; if msb equal then check lsb
200 div32x16_3: 199 div32x16_3:
201 btfss STATUS,C ; carry set if d>a 200 decfsz math_loop,F ; decrement loop counter, all bits done?
202 bra div32x16_4 201 bra div32x16_1 ; NO - loop
203 movf xB+0,W ; d-a into d 202 return ; YES - done
204 subwf sub_b+0,F 203
205 btfss STATUS,C 204
206 decf sub_b+1,F 205 ;=============================================================================
207 movf xB+1,W 206
208 subwf sub_b+1,F 207 ; ISR math functions
209 bsf STATUS,C ; shift a 1 into b (result) 208
210 div32x16_4: 209 global isr_shift_C31 ; 24 bit shift, repeated WREG times, dedicated to a specific usage:
211 rlcf xC+0,F 210 ; Because less than 8 bits are shifted and only C[2:1] is needed,
212 rlcf xC+1,F 211 ; we don't care what bit is inserted.
213 rlcf xC+2,F
214 rlcf xC+3,F
215 decfsz divB,F ; loop until all bits checked
216 bra div32x16_2
217 return
218
219 ;;=============================================================================
220 ;; u16 * u16 --> 32bit multiply (xA * xB --> xC)
221 ;; Used in interupt service routines, to compute temperature and pressure.
222 ;;
223 ; global isr_mult16x16
224 ;isr_mult16x16:
225 ; clrf isr_xC+2 ; Clear the High-Order Bits
226 ; clrf isr_xC+3
227 ; movf isr_xA, w ; Do the "L" Multiplication first
228 ; mulwf isr_xB
229 ; movf PRODL, w ; Save result
230 ; movwf isr_xC+0
231 ; movf PRODH, w
232 ; movwf isr_xC+1
233 ; movf isr_xA+0, w ; Do the "I" Multiplication
234 ; mulwf isr_xB+1
235 ; movf PRODL, w ; Save the Most Significant Byte First
236 ; addwf isr_xC+1, f
237 ; movf PRODH, w
238 ; addwfc isr_xC+2, f ; Add to the Last Result
239 ; movf isr_xA+1, w ; Do the "O" Multiplication
240 ; mulwf isr_xB
241 ; movf PRODL, w ; Add the Lower Byte Next
242 ; addwf isr_xC+1, f
243 ; movf PRODH, w ; Add the High Byte First
244 ; addwfc isr_xC+2, f
245 ; btfsc STATUS, C ; Add the Carry
246 ; incf isr_xC+3, f
247 ; movf isr_xA+1, w ; Do the "F" Multiplication
248 ; mulwf isr_xB+1
249 ; movf PRODL, w
250 ; addwf isr_xC+2, f
251 ; movf PRODH, w
252 ; addwfc isr_xC+3, f
253 ; return
254
255 ;=============================================================================
256 ; 24bit shift, repeted WREG times.
257 ; Because we shift less than 8bits, and keep only C[2:1], we don't care what
258 ; bit is inserted...
259 ;
260 global isr_shift_C31
261 isr_shift_C31: 212 isr_shift_C31:
262 rrcf isr_xC+3,F ; Shift the three bytes... 213 rrcf isr_xC+3,F ; shift three bytes
263 rrcf isr_xC+2,F 214 rrcf isr_xC+2,F
264 rrcf isr_xC+1,F 215 rrcf isr_xC+1,F
265 decfsz WREG 216 decfsz WREG ; decrement loop counter, done?
266 bra isr_shift_C31 217 bra isr_shift_C31 ; NO - loop
267 return 218 return ; YES - done
268 219
269 ;============================================================================= 220
270 ; s16 * s16 --> 32bit multiply (xA * xB --> xC) 221 global isr_unsigned_mult16x16 ; isr_xC = isr_xA * _isr_xB with UNSIGNED values
271 ; Signed multiplication. 222 ; trashes PRODL, PRODH, WREG
272 ; Code from... the Pic18F documentation ;-)
273 global isr_unsigned_mult16x16
274 isr_unsigned_mult16x16: 223 isr_unsigned_mult16x16:
275 MOVF isr_xA+0, W ; Lowest is simply a[0] * b[0] 224 movf isr_xA+0,W ; multiply a[0] * b[0]
276 MULWF isr_xB+0 225 mulwf isr_xB+0
277 MOVFF PRODL, isr_xC+0 226 movff PRODL,isr_xC+0 ; store product to c[1]:c[0]
278 MOVFF PRODH, isr_xC+1 227 movff PRODH,isr_xC+1
279 ; 228 ;
280 MOVF isr_xA+1, W ; And highest a[1] * b[1] 229 movf isr_xA+1,W ; multiply a[1] * b[1]
281 MULWF isr_xB+1 230 mulwf isr_xB+1
282 MOVFF PRODL, isr_xC+2 231 movff PRODL, isr_xC+2 ; store product to c[3]:c[2]
283 MOVFF PRODH, isr_xC+3 232 movff PRODH, isr_xC+3
284 ; 233 ;
285 MOVF isr_xA+0, W ; Intermediates do propagate: 234 movf isr_xA+0,W ; multiply a[0] * b[1]
286 MULWF isr_xB+1 235 mulwf isr_xB+1
287 MOVF PRODL, W 236 movf PRODL,W ; add cross product to c[3]:c[2]:c[1]
288 ADDWF isr_xC+1, F ; Add cross products 237 addwf isr_xC+1,F
289 MOVF PRODH, W 238 movf PRODH,W
290 ADDWFC isr_xC+2, F ; with propagated carry 239 addwfc isr_xC+2,F ; propagate carry
291 CLRF WREG 240 clrf WREG
292 ADDWFC isr_xC+3, F ; on the three bytes. 241 addwfc isr_xC+3,F ; propagate carry
293 ; 242 ;
294 MOVF isr_xA+1, W ; And the second one, similarly. 243 movf isr_xA+1,W ; multiply a[1] * b[0]
295 MULWF isr_xB+0 244 mulwf isr_xB+0
296 MOVF PRODL, W 245 movf PRODL,W ; add cross product
297 ADDWF isr_xC+1, F ; Add cross products 246 addwf isr_xC+1,F
298 MOVF PRODH, W 247 movf PRODH,W
299 ADDWFC isr_xC+2, F 248 addwfc isr_xC+2,F ; propagate carry
300 CLRF WREG 249 clrf WREG
301 ADDWFC isr_xC+3, F 250 addwfc isr_xC+3,F ; propagate carry
302 return 251 return
303 252
304 global isr_signed_mult16x16 253
254 global isr_signed_mult16x16 ; isr_xC = isr_xA * _isr_xB with SIGNED values
255 ; trashes PRODL, PRODH, WREG
305 isr_signed_mult16x16: 256 isr_signed_mult16x16:
306 rcall isr_unsigned_mult16x16 257 rcall isr_unsigned_mult16x16 ; do an unsigned multiplication first
307 258 ; ; manage sign extension of operand B
308 ; Manage sign extension of operand B 259 btfss isr_xB+1,7 ; is B negative ?
309 BTFSS isr_xB+1,7 ; Is B negatif ? 260 bra isr_signed_mult_checkA ; NO - continue checking operand A
310 BRA isr_signed_mult_checkA ; No: check ARG1 261 movf isr_xA+0,W ; Yes - add -65536 * A
311 MOVF isr_xA+0, W ; Yes: add -65536 * A 262 subwf isr_xC+2,F
312 SUBWF isr_xC+2, F 263 movf isr_xA+1,W
313 MOVF isr_xA+1, W 264 subwfb isr_xC+3,F
314 SUBWFB isr_xC+3, F 265 isr_signed_mult_checkA ; manage sign extension of operand B
315 ; And of operand A 266 btfss isr_xA+1,7 ; is A negative ?
316 isr_signed_mult_checkA 267 return ; NO - done
317 BTFSS isr_xA+1, 7 ; Is A negatif ? 268 movf isr_xB+0,W ; Yes - add -65536 * B
318 RETURN ; No: done 269 subwf isr_xC+2,F
319 MOVF isr_xB+0, W 270 movf isr_xB+1,W
320 SUBWF isr_xC+2, F 271 subwfb isr_xC+3,F
321 MOVF isr_xB+1, W 272 return
322 SUBWFB isr_xC+3, F 273
323 RETURN 274 END
324
325 END