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