comparison src/math.asm @ 634:4050675965ea

3.10 stable release
author heinrichsweikamp
date Tue, 28 Apr 2020 17:34:31 +0200
parents cd58f7fc86db
children 7d8a4c60ec1a
comparison
equal deleted inserted replaced
633:690c48db7b5b 634:4050675965ea
1 ;============================================================================= 1 ;=============================================================================
2 ; 2 ;
3 ; File math.asm combined next generation V3.04.3 3 ; File math.asm * combined next generation V3.09.4k
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 ;=============================================================================
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 math CODE 15
16 16 ;=============================================================================
17 ;============================================================================= 17 math1 CODE
18 18 ;=============================================================================
19 global convert_time ; converts hi:lo in minutes to hours (up:hi) and minutes (lo) 19
20 ; also usable for conversion of seconds to minutes and seconds 20 ;-----------------------------------------------------------------------------
21 ; trashes xA, xB, xC 21 ; Divide a 16 Bit Integer by a Power of 2: divA:2 = divA:2 / 2^WREG
22 convert_time: 22 ;
23 movff lo,xA+0 ; copy hi:lo to xA 23 ; trashes WREG
24 movff hi,xA+1 ; 24 ;
25 movlw d'60' ; set divisor to 60 25 global div16
26 movwf xB+0 ; write 60 to xB
27 clrf xB+1 ;
28 rcall div16x16 ; xC = xA / xB with xA as remainder
29 movff xC+1,up ; result is hours / minutes, copy to up (high byte)
30 movff xC+0,hi ; result is hours / minutes, copy to hi (low byte)
31 movff xA+0,lo ; remainder is minutes / seconds, copy to lo
32 return
33
34
35 global div16 ; divA:2 = divA:2 / 2^WREG
36 ; trashes WREG
37 div16: 26 div16:
38 bcf STATUS,C ; clear carry 27 bcf STATUS,C ; clear carry
39 rrcf divA+1 ; rotate right high byte, carry into MSB, LSB into carry 28 rrcf divA+1 ; rotate right high byte, carry into MSB, LSB into carry
40 rrcf divA+0 ; rotate right low byte, carry into MSB, LSB into carry 29 rrcf divA+0 ; rotate right low byte, carry into MSB, LSB into carry
41 decfsz WREG ; decrement counter, done? 30 decfsz WREG ; decrement counter, done?
42 bra div16 ; NO - loop 31 bra div16 ; NO - loop
43 return ; YES - done 32 return ; YES - done
44 33
45 34
46 global mult16 ; xA:2 = xA:2 * 2^WREG 35 ;=============================================================================
47 ; trashes WREG 36 math2 CODE
37 ;=============================================================================
38
39 ;-----------------------------------------------------------------------------
40 ; Multiply a 16 bit Integer by a Power of 2: xA:2 = xA:2 * 2^WREG
41 ;
42 ; trashes WREG
43 ;
44 global mult16
48 mult16: 45 mult16:
49 bcf STATUS,C ; clear carry 46 bcf STATUS,C ; clear carry
50 rlcf divA+0,F ; rotate left low byte, carry into LSB, MSB into carry 47 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 48 rlcf divA+1,F ; rotate left high byte, carry into LSB, MSB into carry
52 decfsz WREG ; decrement counter, done? 49 decfsz WREG ; decrement counter, done?
53 bra mult16 ; NO - loop 50 bra mult16 ; NO - loop
54 return ; YES - done 51 return ; YES - done
55 52
56 53
57 global addU16 ; ; sub_c:2 = sub_a:2 + sub_b:2 with USIGNED values 54 ;=============================================================================
58 ; trashes WREG 55 math3 CODE
56 ;=============================================================================
57
58 ;-----------------------------------------------------------------------------
59 ; Add two UNSIGNED 16 bit Integers: sub_c:2 = sub_a:2 + sub_b:2
60 ;
61 ; trashes WREG
62 ;
63 global addU16
59 addU16: 64 addU16:
60 movf sub_a+0,W ; get 1st summand (low byte) to WREG 65 movf sub_a+0,W ; get 1st summand (low byte) to WREG
61 addwf sub_b+0,W ; add 2nd summand (low byte) and store result in WREG 66 addwf sub_b+0,W ; add 2nd summand (low byte) and store result in WREG
62 movwf sub_c+0 ; copy result (low byte) to sub_c 67 movwf sub_c+0 ; copy result (low byte) to sub_c
63 movf sub_a+1,W ; get 1st summand (high byte) to WREG 68 movf sub_a+1,W ; get 1st summand (high byte) to WREG
64 addwfc sub_b+1,W ; add 2nd summand (high byte) and store result in WREG 69 addwfc sub_b+1,W ; add 2nd summand (high byte) and store result in WREG
65 movwf sub_c+1 ; copy result (high byte) to sub_c 70 movwf sub_c+1 ; copy result (high byte) to sub_c
66 return ; done 71 return ; done
67 72
68 73
69 global sub16 ; sub_c:2 = sub_a:2 - sub_b:2 with SIGNED values 74 ;=============================================================================
70 ; sets neg_flag if result is < 0 75 math4 CODE
71 ; trashes WREG 76 ;=============================================================================
77
78 ;-----------------------------------------------------------------------------
79 ; Subtract two SIGNED 16 Bit Integers: sub_c:2 = sub_a:2 - sub_b:2
80 ;
81 ; sets neg_flag if result is < 0, trashes WREG
82 ;
83 global sub16
72 sub16: 84 sub16:
73 bcf neg_flag ; clear flag which will indicate if result is negative 85 bcf neg_flag ; clear flag which will indicate if result is negative
74 movf sub_b+0,W ; get value to be subtracted, low byte 86 movf sub_b+0,W ; get value to be subtracted, low byte
75 subwf sub_a+0,W ; execute subtraction on low byte 87 subwf sub_a+0,W ; execute subtraction on low byte
76 movwf sub_c+0 ; copy result to output variable, low byte 88 movwf sub_c+0 ; copy result to output variable, low byte
85 btfsc STATUS,C ; - carry to be propagated ? 97 btfsc STATUS,C ; - carry to be propagated ?
86 incf sub_c+1,F ; YES - do it 98 incf sub_c+1,F ; YES - do it
87 return ; - done 99 return ; - done
88 100
89 101
90 global subU16 ; sub_c:2 = sub_a:2 - sub_b:2 with UNSIGNED values 102 ;=============================================================================
91 ; sets neg_flag if result is < 0 103 math5 CODE
92 ; trashes WREG 104 ;=============================================================================
105
106 ;-----------------------------------------------------------------------------
107 ; Subtract two UNSIGNED 16 Bit Integers: sub_c:2 = sub_a:2 - sub_b:2
108 ;
109 ; sets neg_flag if result is < 0, trashes WREG
110 ;
111 global subU16
93 subU16: 112 subU16:
94 bcf neg_flag ; clear flag which will indicate if result is negative 113 bcf neg_flag ; clear flag which will indicate if result is negative
95 movf sub_b+0,W ; get value to be subtracted, low byte 114 movf sub_b+0,W ; get value to be subtracted, low byte
96 subwf sub_a+0,W ; execute subtraction on low byte 115 subwf sub_a+0,W ; execute subtraction on low byte
97 movwf sub_c+0 ; copy result to output variable, low byte 116 movwf sub_c+0 ; copy result to output variable, low byte
106 btfsc STATUS,C ; - carry to be propagated ? 125 btfsc STATUS,C ; - carry to be propagated ?
107 incf sub_c+1,F ; YES - do it 126 incf sub_c+1,F ; YES - do it
108 return ; - done 127 return ; - done
109 128
110 129
111 global cmpU16 ; sub_a:2 - sub_b:2 with UNSIGNED values 130 ;=============================================================================
112 ; sets neg_flag if result is < 0, but does not store result itself 131 math6 CODE
113 ; trashes WREG 132 ;=============================================================================
133
134 ;-----------------------------------------------------------------------------
135 ; Compare two UNSIGNED 16 Bit Integers: sub_a:2 - sub_b:2
136 ;
137 ; sets neg_flag if result is < 0, trashes WREG
138 ; the subtraction result is not stored
139 ;
140 global cmpU16
114 cmpU16: 141 cmpU16:
115 bcf neg_flag ; clear flag which will indicate if result is negative 142 bcf neg_flag ; clear flag which will indicate if result is negative
116 movf sub_b+0,W ; get value to be subtracted, low byte 143 movf sub_b+0,W ; get value to be subtracted, low byte
117 subwf sub_a+0,W ; execute subtraction on low byte 144 subwf sub_a+0,W ; execute subtraction on low byte
118 movf sub_b+1,W ; get value to be subtracted, high byte 145 movf sub_b+1,W ; get value to be subtracted, high byte
120 btfss STATUS,C ; borrow to propagate (B == /CARRY) ? 147 btfss STATUS,C ; borrow to propagate (B == /CARRY) ?
121 bsf neg_flag ; YES - result is negative, set flag 148 bsf neg_flag ; YES - result is negative, set flag
122 return ; done 149 return ; done
123 150
124 151
125 global mult16x16 ; xC:4 = xA:2 * xB:2 with UNSIGNED values 152 ;=============================================================================
126 ; trashes PRODL, PRODH, WREG 153 math7 CODE
154 ;=============================================================================
155
156 ;-----------------------------------------------------------------------------
157 ; Multiply two UNSIGNED 16 bit Integers: xC:4 = xA:2 * xB:2
158 ;
159 ; trashes PRODL, PRODH, WREG
160 ;
161 global mult16x16
127 mult16x16: 162 mult16x16:
128 clrf xC+2 ; clear the high-order bits 163 clrf xC+2 ; clear the high-order bits
129 clrf xC+3 164 clrf xC+3 ; ...
130 ; 165
131 movf xA+0,W ; do the "L" multiplication 166 movf xA+0,W ; do the "L" multiplication
132 mulwf xB+0 167 mulwf xB+0
133 movff PRODL,xC+0 ; copy result to xC 168 movff PRODL,xC+0 ; copy result to xC
134 movff PRODH,xC+1 169 movff PRODH,xC+1
135 ; 170
136 movf xA+0,W ; do the "I" multiplication 171 movf xA+0,W ; do the "I" multiplication
137 mulwf xB+1 172 mulwf xB+1
138 movf PRODL,W ; get the product's low byte... 173 movf PRODL,W ; get the product's low byte...
139 addwf xC+1,F ; ... and add it to xC+1 174 addwf xC+1,F ; ... and add it to xC+1
140 movf PRODH,W ; get the product's high byte... 175 movf PRODH,W ; get the product's high byte...
141 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1 176 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1
142 ; 177
143 movf xA+1,W ; do the "O" multiplication 178 movf xA+1,W ; do the "O" multiplication
144 mulwf xB+0 179 mulwf xB+0
145 movf PRODL,W ; get the product's low byte... 180 movf PRODL,W ; get the product's low byte...
146 addwf xC+1,F ; ... and add it to xC+1 181 addwf xC+1,F ; ... and add it to xC+1
147 movf PRODH,W ; get the product's high byte... 182 movf PRODH,W ; get the product's high byte...
148 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1 183 addwfc xC+2,F ; ... and add it to xC+2 obeying carry bit from xC+1
149 clrf WREG ; clear WREG... 184 clrf WREG ; clear WREG...
150 addwfc xC+3,F ; ... add add it to xC+3 obeying carry bit from xC+2 (can only happen in "O" multiplication) 185 addwfc xC+3,F ; ... add add it to xC+3 obeying carry bit from xC+2 (can only happen in "O" multiplication)
151 ; 186
152 movf xA+1,W ; do the "F" multiplication 187 movf xA+1,W ; do the "F" multiplication
153 mulwf xB+1 188 mulwf xB+1
154 movf PRODL,W ; get the product's low byte... 189 movf PRODL,W ; get the product's low byte...
155 addwf xC+2,F ; ... and add it to xC+2 190 addwf xC+2,F ; ... and add it to xC+2
156 movf PRODH,W ; get the product's high byte... 191 movf PRODH,W ; get the product's high byte...
157 addwfc xC+3,F ; ... and add it to xC+3 obeying carry bit from xC+2 192 addwfc xC+3,F ; ... and add it to xC+3 obeying carry bit from xC+2
158 return 193
159 194 return ; done
160 195
161 global div16x16 ; xC:2 = xA:2 / xB:2 with xA as remainder 196
162 ; trashes WREG 197 ;=============================================================================
198 math8 CODE
199 ;=============================================================================
200
201 ;-----------------------------------------------------------------------------
202 ; Divide two UNSIGNED 16 Bit Integers: xC:2 = xA:2 / xB:2 with xA as remainder
203 ;
204 ; trashes WREG
205 ;
206 global div16x16
163 div16x16: 207 div16x16:
164 movlw .16 ; process 16 bits ... 208 movlw .16 ; process 16 bits ...
165 movwf math_loop ; ... initialize loop counter 209 movwf math_loop ; ... initialize loop counter
166 movff xA+0,xC+0 ; copy xA to xC 210 movff xA+0,xC+0 ; copy xA to xC
167 movff xA+1,xC+1 ; ... 211 movff xA+1,xC+1 ; ...
191 decfsz math_loop,F ; decrement loop counter, all bits done? 235 decfsz math_loop,F ; decrement loop counter, all bits done?
192 bra div16x16_1 ; NO - loop 236 bra div16x16_1 ; NO - loop
193 return ; YES - done 237 return ; YES - done
194 238
195 239
196 global div32x16 ; xC:4 = xC:4 / xB:2 with xA as remainder 240 ;=============================================================================
197 ; trashes WREG 241 math9 CODE
242 ;=============================================================================
243
244 ;-----------------------------------------------------------------------------
245 ; Divide a 32 Bit Integer by a 16 Bit Integer: xC:4 = xC:4 / xB:2 with xA as remainder
246 ;
247 ; trashes WREG
248 ;
249 global div32x16
198 div32x16: 250 div32x16:
199 movlw .32 ; process 32 bits ... 251 movlw .32 ; process 32 bits ...
200 movwf math_loop ; ... initialize loop counter 252 movwf math_loop ; ... initialize loop counter
201 clrf xA+0 ; clear xA, will be used to hold the remainder 253 clrf xA+0 ; clear xA, will be used to hold the remainder
202 clrf xA+1 ; ... 254 clrf xA+1 ; ...
226 decfsz math_loop,F ; decrement loop counter, all bits done? 278 decfsz math_loop,F ; decrement loop counter, all bits done?
227 bra div32x16_1 ; NO - loop 279 bra div32x16_1 ; NO - loop
228 return ; YES - done 280 return ; YES - done
229 281
230 282
231 ;============================================================================= 283 ;-----------------------------------------------------------------------------
232 284 ;
233 ; ISR math functions 285 ; ISR math functions
234 286 ;
235 global isr_shift_C31 ; 24 bit shift, repeated WREG times, dedicated to a specific usage: 287 ;-----------------------------------------------------------------------------
236 ; Because less than 8 bits are shifted and only C[2:1] is needed, 288
237 ; we don't care what bit is inserted. 289 ;=============================================================================
290 math10 CODE
291 ;=============================================================================
292
293 ;-----------------------------------------------------------------------------
294 ; 24 Bit Shift, repeated WREG Times, dedicated to a specific Usage
295 ;
296 ; Because less than 8 bits are shifted and only C[2:1] is needed,
297 ; we don't care what bit is inserted.
298 ;
299 global isr_shift_C31
238 isr_shift_C31: 300 isr_shift_C31:
239 rrcf isr_xC+3,F ; shift three bytes 301 rrcf isr_xC+3,F ; shift three bytes
240 rrcf isr_xC+2,F 302 rrcf isr_xC+2,F ; ...
241 rrcf isr_xC+1,F 303 rrcf isr_xC+1,F ; ...
242 decfsz WREG ; decrement loop counter, done? 304 decfsz WREG ; decrement loop counter, done?
243 bra isr_shift_C31 ; NO - loop 305 bra isr_shift_C31 ; NO - loop
244 return ; YES - done 306 return ; YES - done
245 307
246 308
247 global isr_unsigned_mult16x16 ; isr_xC = isr_xA * _isr_xB with UNSIGNED values 309 ;=============================================================================
248 ; trashes PRODL, PRODH, WREG 310 math11 CODE
311 ;=============================================================================
312
313 ;-----------------------------------------------------------------------------
314 ; Multiply two UNSIGNED 16 Bit Integers: isr_xC = isr_xA * isr_xB
315 ;
316 ; trashes PRODL, PRODH, WREG
317 ;
318 global isr_unsigned_mult16x16
249 isr_unsigned_mult16x16: 319 isr_unsigned_mult16x16:
250 movf isr_xA+0,W ; multiply a[0] * b[0] 320 movf isr_xA+0,W ; multiply a[0] * b[0]
251 mulwf isr_xB+0 321 mulwf isr_xB+0 ; ...
252 movff PRODL,isr_xC+0 ; store product to c[1]:c[0] 322 movff PRODL,isr_xC+0 ; store product to c[1]:c[0]
253 movff PRODH,isr_xC+1 323 movff PRODH,isr_xC+1 ; ...
254 ; 324
255 movf isr_xA+1,W ; multiply a[1] * b[1] 325 movf isr_xA+1,W ; multiply a[1] * b[1]
256 mulwf isr_xB+1 326 mulwf isr_xB+1 ; ...
257 movff PRODL, isr_xC+2 ; store product to c[3]:c[2] 327 movff PRODL, isr_xC+2 ; store product to c[3]:c[2]
258 movff PRODH, isr_xC+3 328 movff PRODH, isr_xC+3 ; ...
259 ; 329
260 movf isr_xA+0,W ; multiply a[0] * b[1] 330 movf isr_xA+0,W ; multiply a[0] * b[1]
261 mulwf isr_xB+1 331 mulwf isr_xB+1 ; ...
262 movf PRODL,W ; add cross product to c[3]:c[2]:c[1] 332 movf PRODL,W ; add cross product to c[3]:c[2]:c[1]
263 addwf isr_xC+1,F 333 addwf isr_xC+1,F ; ...
264 movf PRODH,W 334 movf PRODH,W ; ...
265 addwfc isr_xC+2,F ; propagate carry 335 addwfc isr_xC+2,F ; propagate carry
266 clrf WREG 336 clrf WREG ; ...
267 addwfc isr_xC+3,F ; propagate carry 337 addwfc isr_xC+3,F ; ...
268 ; 338
269 movf isr_xA+1,W ; multiply a[1] * b[0] 339 movf isr_xA+1,W ; multiply a[1] * b[0]
270 mulwf isr_xB+0 340 mulwf isr_xB+0 ; ...
271 movf PRODL,W ; add cross product 341 movf PRODL,W ; add cross product
272 addwf isr_xC+1,F 342 addwf isr_xC+1,F ; ...
273 movf PRODH,W 343 movf PRODH,W ; ...
274 addwfc isr_xC+2,F ; propagate carry 344 addwfc isr_xC+2,F ; propagate carry
275 clrf WREG 345 clrf WREG ; ...
276 addwfc isr_xC+3,F ; propagate carry 346 addwfc isr_xC+3,F ; ...
277 return 347 return ; done
278 348
279 349
280 global isr_signed_mult16x16 ; isr_xC = isr_xA * isr_xB with SIGNED values 350 ;-----------------------------------------------------------------------------
281 ; trashes PRODL, PRODH, WREG 351 ; Multiply two SIGNED 16 Bit Integers: isr_xC = isr_xA * isr_xB
352 ;
353 ; trashes PRODL, PRODH, WREG
354 ;
355 global isr_signed_mult16x16
282 isr_signed_mult16x16: 356 isr_signed_mult16x16:
283 rcall isr_unsigned_mult16x16 ; do an unsigned multiplication first 357 ; do an unsigned multiplication first
284 ; ; manage sign extension of operand B 358 rcall isr_unsigned_mult16x16
359
360 ; manage sign extension of operand B
285 btfss isr_xB+1,7 ; is B negative ? 361 btfss isr_xB+1,7 ; is B negative ?
286 bra isr_signed_mult_checkA ; NO - continue checking operand A 362 bra isr_signed_mult_checkA ; NO - continue checking operand A
287 movf isr_xA+0,W ; Yes - add -65536 * A 363 movf isr_xA+0,W ; YES - add -65536 * A
288 subwf isr_xC+2,F 364 subwf isr_xC+2,F ; - ...
289 movf isr_xA+1,W 365 movf isr_xA+1,W ; - ...
290 subwfb isr_xC+3,F 366 subwfb isr_xC+3,F ; - ...
291 isr_signed_mult_checkA ; manage sign extension of operand B 367 isr_signed_mult_checkA ; manage sign extension of operand B
292 btfss isr_xA+1,7 ; is A negative ? 368 btfss isr_xA+1,7 ; is A negative ?
293 return ; NO - done 369 return ; NO - done
294 movf isr_xB+0,W ; Yes - add -65536 * B 370 movf isr_xB+0,W ; YES - add -65536 * B
295 subwf isr_xC+2,F 371 subwf isr_xC+2,F ; - ...
296 movf isr_xB+1,W 372 movf isr_xB+1,W ; - ...
297 subwfb isr_xC+3,F 373 subwfb isr_xC+3,F ; - ...
298 return 374 return ; - done
375
376 ;-----------------------------------------------------------------------------
299 377
300 END 378 END