1 /**
2 * \file
3 *
4 * \brief SAM Divide and Square Root Accelerator (DIVAS) Driver
5 *
6 * Copyright (c) 2015 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46
47 #include "divas.h"
48
49 /**
50 * \internal
51 * \brief Initializes and enables the Divide and Square Root Accelerator (DIVAS) Driver.
52 *
53 * Enable the clocks used by Divide and Square Root Accelerator (DIVAS) Driver.
54 * Enable leading zero optimization.
55 *
56 * \note When SYSTEM module is used, this function will be invoked by
57 * \ref system_init() automatically if the module is included.
58 */
59 void _system_divas_init(void);
_system_divas_init(void)60 void _system_divas_init(void)
61 {
62 /* Turn on the digital interface clock. */
63 system_ahb_clock_set_mask(MCLK_AHBMASK_DIVAS);
64
65 DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_DLZ;
66 }
67
68 /**
69 * \brief Signed division operation
70 *
71 * Run the signed division operation and return the quotient.
72 *
73 * \param[in] numerator The dividend of the signed division operation
74 * \param[in] denominator The divisor of the signed division operation
75 *
76 * \return The quotient of the DIVAS signed division operation.
77 */
divas_idiv(int32_t numerator,int32_t denominator)78 int32_t divas_idiv(int32_t numerator, int32_t denominator)
79 {
80 /* Disable interrupt. */
81 cpu_irq_enter_critical();
82
83 /* Signed division. */
84 DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
85
86 /* Write the dividend to DIVIDEND register. */
87 DIVAS->DIVIDEND.reg = numerator;
88 /* Write the divisor to DIVISOR register. */
89 DIVAS->DIVISOR.reg = denominator;
90
91 while(DIVAS->STATUS.bit.BUSY){
92 /* Wait the division is complete. */
93 }
94
95 int32_t quotient = DIVAS->RESULT.reg;
96
97 /* Enable interrupt. */
98 cpu_irq_leave_critical();
99
100 return quotient;
101 }
102
103 /**
104 * \brief Unsigned division operation
105 *
106 * Run the unsigned division operation and return the results.
107 *
108 * \param[in] numerator The dividend of the unsigned division operation
109 * \param[in] denominator The divisor of the unsigned division operation
110 *
111 * \return The quotient of the DIVAS unsigned division operation.
112 */
divas_uidiv(uint32_t numerator,uint32_t denominator)113 uint32_t divas_uidiv(uint32_t numerator, uint32_t denominator)
114 {
115 /* Disable interrupt. */
116 cpu_irq_enter_critical();
117
118 /* Unsigned division. */
119 DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
120
121 /* Write the dividend to DIVIDEND register. */
122 DIVAS->DIVIDEND.reg = numerator;
123 /* Write the divisor to DIVISOR register. */
124 DIVAS->DIVISOR.reg = denominator;
125
126 while(DIVAS->STATUS.bit.BUSY){
127 /* Wait the division is complete. */
128 }
129
130 uint32_t quotient = DIVAS->RESULT.reg;
131
132 /* Enable interrupt. */
133 cpu_irq_leave_critical();
134
135 return quotient;
136 }
137
138 /**
139 * \brief Signed division remainder operation
140 *
141 * Run the signed division operation and return the remainder.
142 *
143 * \param[in] numerator The dividend of the signed division operation
144 * \param[in] denominator The divisor of the signed division operation
145 *
146 * \return The remainder of the DIVAS signed division operation.
147 */
divas_idivmod(int32_t numerator,int32_t denominator)148 int32_t divas_idivmod(int32_t numerator, int32_t denominator)
149 {
150 /* Disable interrupt. */
151 cpu_irq_enter_critical();
152
153 /* Signed division. */
154 DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
155
156 /* Write the dividend to DIVIDEND register. */
157 DIVAS->DIVIDEND.reg = numerator;
158 /* Write the divisor to DIVISOR register. */
159 DIVAS->DIVISOR.reg = denominator;
160
161 while(DIVAS->STATUS.bit.BUSY){
162 /* Wait the division is complete. */
163 }
164
165 int32_t remainder = DIVAS->REM.reg;
166
167 /* Enable interrupt. */
168 cpu_irq_leave_critical();
169
170 return remainder;
171 }
172
173 /**
174 * \brief Unsigned division remainder operation
175 *
176 * Run the unsigned division operation and return the remainder.
177 *
178 * \param[in] numerator The dividend of the unsigned division operation
179 * \param[in] denominator The divisor of the unsigned division operation
180 *
181 * \return The remainder of the DIVAS unsigned division operation.
182 */
divas_uidivmod(uint32_t numerator,uint32_t denominator)183 uint32_t divas_uidivmod(uint32_t numerator, uint32_t denominator)
184 {
185 /* Disable interrupt. */
186 cpu_irq_enter_critical();
187
188 /* Unsigned division. */
189 DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
190
191 /* Write the dividend to DIVIDEND register. */
192 DIVAS->DIVIDEND.reg = numerator;
193 /* Write the divisor to DIVISOR register. */
194 DIVAS->DIVISOR.reg = denominator;
195
196 while(DIVAS->STATUS.bit.BUSY){
197 /* Wait the division is complete. */
198 }
199
200 uint32_t remainder = DIVAS->REM.reg;
201
202 /* Enable interrupt. */
203 cpu_irq_leave_critical();
204
205 return remainder;
206 }
207
208 /**
209 * \brief Square root operation
210 *
211 * Run the square root operation and return the results.
212 *
213 * \param[in] radicand The radicand of the square root operation
214 *
215 * \return The result of the DIVAS square root operation.
216 */
divas_sqrt(uint32_t radicand)217 uint32_t divas_sqrt(uint32_t radicand)
218 {
219 /* Disable interrupt. */
220 cpu_irq_enter_critical();
221
222 /* Write the radicand to DIVIDEND register. */
223 DIVAS->SQRNUM.reg = radicand;
224
225 while(DIVAS->STATUS.bit.BUSY){
226 /* Wait the square root is complete. */
227 }
228
229 uint32_t result_sqrt = DIVAS->RESULT.reg;
230
231 /* Enable interrupt. */
232 cpu_irq_leave_critical();
233
234 return result_sqrt;
235 }
236
237 /**
238 * \name DIVAS Operation Overloading
239 * @{
240 */
241
242 #if DIVAS_OVERLOAD_MODE == true
243 # if defined ( __GNUC__ )
244
245 /**
246 * \brief Signed division operation overload
247 *
248 * Run the signed division operation and return the results.
249 *
250 * \param[in] numerator The dividend of the signed division operation
251 * \param[in] denominator The divisor of the signed division operation
252 *
253 * \return The quotient of the DIVAS signed division operation.
254 */
__aeabi_idiv(int32_t numerator,int32_t denominator)255 int32_t __aeabi_idiv(int32_t numerator, int32_t denominator)
256 {
257 return divas_idiv(numerator, denominator);
258 }
259
260 /**
261 * \brief Unsigned division operation overload
262 *
263 * Run the unsigned division operation and return the results.
264 *
265 * \param[in] numerator The dividend of the unsigned division operation
266 * \param[in] denominator The divisor of the unsigned division operation
267 *
268 * \return The quotient of the DIVAS unsigned division operation.
269 */
__aeabi_uidiv(uint32_t numerator,uint32_t denominator)270 uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator)
271 {
272 return divas_uidiv(numerator, denominator);
273 }
274
275 /**
276 * \brief Signed division remainder operation overload
277 *
278 * Run the signed division operation and return the remainder.
279 *
280 * \param[in] numerator The dividend of the signed division operation
281 * \param[in] denominator The divisor of the signed division operation
282 *
283 * \return The remainder of the DIVAS signed division operation.
284 */
__aeabi_idivmod(int32_t numerator,int32_t denominator)285 uint64_t __aeabi_idivmod(int32_t numerator, int32_t denominator)
286 {
287 uint64_t uret;
288 int32_t quotient, remainder;
289
290 /* Disable interrupt. */
291 cpu_irq_enter_critical();
292
293 /* Signed division. */
294 DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
295
296 /* Write the dividend to DIVIDEND register. */
297 DIVAS->DIVIDEND.reg = numerator;
298 /* Write the divisor to DIVISOR register. */
299 DIVAS->DIVISOR.reg = denominator;
300
301 while(DIVAS->STATUS.bit.BUSY){
302 /* Wait the division is complete. */
303 }
304
305 /* Read out the result. */
306 quotient = DIVAS->RESULT.reg;
307 remainder = DIVAS->REM.reg;
308
309 /* quotient in r0, remainder in r1 */
310 uret = ((uint64_t)quotient & 0x00000000FFFFFFFF ) |
311 (((uint64_t)remainder ) << 32);
312
313 /* Enable interrupt. */
314 cpu_irq_leave_critical();
315
316 return uret;
317 }
318
319 /**
320 * \brief Unsigned division remainder operation overload
321 *
322 * Run the unsigned division operation and return the remainder.
323 *
324 * \param[in] numerator The dividend of the unsigned division operation
325 * \param[in] denominator The divisor of the unsigned division operation
326 *
327 * \return The remainder of the DIVAS unsigned division operation.
328 */
__aeabi_uidivmod(uint32_t numerator,uint32_t denominator)329 uint64_t __aeabi_uidivmod(uint32_t numerator, uint32_t denominator)
330 {
331 uint64_t uret;
332 uint32_t quotient, remainder;
333
334 /* Disable interrupt. */
335 cpu_irq_enter_critical();
336
337 /* Unsigned division. */
338 DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
339
340 /* Write the dividend to DIVIDEND register. */
341 DIVAS->DIVIDEND.reg = numerator;
342 /* Write the divisor to DIVISOR register. */
343 DIVAS->DIVISOR.reg = denominator;
344
345 while(DIVAS->STATUS.bit.BUSY){
346 /* Wait the division is complete. */
347 }
348
349 /* Read out the result. */
350 quotient = DIVAS->RESULT.reg;
351 remainder = DIVAS->REM.reg;
352
353 /* quotient in r0, remainder in r1 */
354 uret = quotient | (((uint64_t)remainder) << 32);
355
356 /* Enable interrupt. */
357 cpu_irq_leave_critical();
358
359 return uret;
360 }
361
362 # elif defined ( __ICCARM__ )
363 /**
364 * \brief Signed division operation overload
365 *
366 * Run the signed division operation and return the results.
367 *
368 * \param[in] numerator The dividend of the signed division operation
369 * \param[in] denominator The divisor of the signed division operation
370 *
371 * \return The quotient of the DIVAS signed division operation.
372 */
__aeabi_idiv(int32_t numerator,int32_t denominator)373 int32_t __aeabi_idiv(int32_t numerator, int32_t denominator)
374 {
375 return divas_idiv(numerator, denominator);
376 }
377
378 /**
379 * \brief Unsigned division operation overload
380 *
381 * Run the unsigned division operation and return the results.
382 *
383 * \param[in] numerator The dividend of the unsigned division operation
384 * \param[in] denominator The divisor of the unsigned division operation
385 *
386 * \return The quotient of the DIVAS unsigned division operation.
387 */
__aeabi_uidiv(uint32_t numerator,uint32_t denominator)388 uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator)
389 {
390 return divas_uidiv(numerator, denominator);
391 }
392
393 /**
394 * \brief Signed division remainder operation overload
395 *
396 * Run the signed division operation and return the remainder.
397 * \param[in] numerator The dividend of the signed division operation
398 * \param[in] denominator The divisor of the signed division operation
399 *
400 * \return The remainder of the DIVAS signed division operation.
401 */
__aeabi_idivmod(int numerator,int denominator)402 __value_in_regs idiv_return __aeabi_idivmod(int numerator, int denominator)
403 {
404 idiv_return result;
405
406 /* Disable interrupt. */
407 cpu_irq_enter_critical();
408
409 /* Signed division. */
410 DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
411
412 /* Write the dividend to DIVIDEND register. */
413 DIVAS->DIVIDEND.reg = numerator;
414 /* Write the divisor to DIVISOR register. */
415 DIVAS->DIVISOR.reg = denominator;
416
417 while(DIVAS->STATUS.bit.BUSY){
418 /* Wait the division is complete. */
419 }
420
421 /* Read out the result. */
422 result.quotient = DIVAS->RESULT.reg;
423 result.remainder = DIVAS->REM.reg;
424
425 /* Enable interrupt. */
426 cpu_irq_leave_critical();
427
428 return result;
429 }
430
431 /**
432 * \brief Unsigned division remainder operation overload
433 *
434 * Run the unsigned division operation and return the remainder.
435 * \param[in] numerator The dividend of the unsigned division operation
436 * \param[in] denominator The divisor of the unsigned division operation
437 *
438 * \return The remainder of the DIVAS unsigned division operation.
439 */
__aeabi_uidivmod(unsigned numerator,unsigned denominator)440 __value_in_regs uidiv_return __aeabi_uidivmod(unsigned numerator, unsigned denominator)
441 {
442 uidiv_return result;
443
444 /* Disable interrupt. */
445 cpu_irq_enter_critical();
446
447 /* Unsigned division. */
448 DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
449
450 /* Write the dividend to DIVIDEND register. */
451 DIVAS->DIVIDEND.reg = numerator;
452 /* Write the divisor to DIVISOR register. */
453 DIVAS->DIVISOR.reg = denominator;
454
455 while(DIVAS->STATUS.bit.BUSY){
456 /* Wait the division is complete. */
457 }
458
459 /* Read out the result. */
460 result.quotient = DIVAS->RESULT.reg;
461 result.remainder = DIVAS->REM.reg;
462
463 /* Enable interrupt. */
464 cpu_irq_leave_critical();
465
466 return result;
467 }
468
469 # endif
470 #endif
471
472 /** @} */
473
474