OpenCores
URL https://opencores.org/ocsvn/neo430/neo430/trunk

Subversion Repositories neo430

[/] [neo430/] [trunk/] [neo430/] [sw/] [lib/] [neo430/] [source/] [neo430_muldiv.c] - Blame information for rev 198

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 198 zero_gravi
// #################################################################################################
2
// #  < neo430_muldiv.c - Multiplier/Divider function >                                            #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6
// # Copyright (c) 2020, Stephan Nolting. All rights reserved.                                     #
7
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32
// # The NEO430 Processor - https://github.com/stnolting/neo430                                    #
33
// #################################################################################################
34
 
35
#include "neo430.h"
36
#include "neo430_muldiv.h"
37
 
38
// Macros
39
#define muldiv_processing_delay {asm volatile("nop"); asm volatile("nop"); asm volatile("nop");}
40
 
41
 
42
/* ------------------------------------------------------------
43
 * INFO Unsigned 16x16-bit multiplication
44
 * PARAM 16-bit factor a
45
 * PARAM 16-bit factor b
46
 * RETURN 32-bit product
47
 * ------------------------------------------------------------ */
48
uint32_t neo430_umul32(uint16_t a, uint16_t b) {
49
 
50
  MULDIV_OPA_RESX = a;
51
  MULDIV_OPB_UMUL_RESY = b;
52
 
53
#if NEO430_HWMUL_DSP
54
  // no processind delay required for DSP (MUL) blocks
55
#else
56
  muldiv_processing_delay // HW processing delay
57
#endif
58
 
59
  return MULDIV_R32bit;
60
}
61
 
62
 
63
/* ------------------------------------------------------------
64
 * INFO Unsigned 32x32-bit multiplication (large!)
65
 * PARAM 32-bit factor a
66
 * PARAM 32-bit factor b
67
 * RETURN 32-bit product
68
 * ------------------------------------------------------------ */
69
uint32_t neo430_umul32_32(uint32_t a, uint32_t b) {
70
 
71
  union uint32_u tmp32;
72
 
73
  // get input words (16-bit)
74
  tmp32.uint32 = a;
75
  register uint16_t a_lo = tmp32.uint16[0];
76
  register uint16_t a_hi = tmp32.uint16[1];
77
 
78
  tmp32.uint32 = b;
79
  register uint16_t b_lo = tmp32.uint16[0];
80
  register uint16_t b_hi = tmp32.uint16[1];
81
 
82
  // compute partial results and arrange in 64-bit word
83
  MULDIV_OPA_RESX      = a_lo;
84
  MULDIV_OPB_UMUL_RESY = b_lo;
85
#if NEO430_HWMUL_DSP
86
  // no processind delay required for DSP (MUL) blocks
87
#else
88
  muldiv_processing_delay // HW processing delay
89
#endif
90
  tmp32.uint16[0] = MULDIV_OPA_RESX;
91
  tmp32.uint16[1] = MULDIV_OPB_UMUL_RESY;
92
  uint32_t res32 = tmp32.uint32;
93
 
94
//MULDIV_OPA_RESX      = a_lo;
95
  MULDIV_OPB_UMUL_RESY = b_hi;
96
#if NEO430_HWMUL_DSP
97
  // no processind delay required for DSP (MUL) blocks
98
#else
99
  muldiv_processing_delay // HW processing delay
100
#endif
101
  tmp32.uint16[0] = 0;
102
  tmp32.uint16[1] = MULDIV_OPA_RESX;
103
  res32 += tmp32.uint32;
104
 
105
  MULDIV_OPA_RESX      = a_hi;
106
  MULDIV_OPB_UMUL_RESY = b_lo;
107
#if NEO430_HWMUL_DSP
108
  // no processind delay required for DSP (MUL) blocks
109
#else
110
  muldiv_processing_delay // HW processing delay
111
#endif
112
  tmp32.uint16[0] = 0;
113
  tmp32.uint16[1] = MULDIV_OPA_RESX;
114
  res32 += tmp32.uint32;
115
 
116
  return res32;
117
}
118
 
119
 
120
/* ------------------------------------------------------------
121
 * INFO Unsigned 32x32-bit multiplication (large!)
122
 * PARAM 32-bit factor a
123
 * PARAM 32-bit factor b
124
 * RETURN 64-bit product
125
 * ------------------------------------------------------------ */
126
uint64_t neo430_umul64(uint32_t a, uint32_t b) {
127
 
128
  union uint32_u tmp32;
129
  union uint64_u tmp64;
130
 
131
  // get input words (16-bit)
132
  tmp32.uint32 = a;
133
  register uint16_t a_lo = tmp32.uint16[0];
134
  register uint16_t a_hi = tmp32.uint16[1];
135
 
136
  tmp32.uint32 = b;
137
  register uint16_t b_lo = tmp32.uint16[0];
138
  register uint16_t b_hi = tmp32.uint16[1];
139
 
140
  // compute partial results and arrange in 64-bit word
141
  MULDIV_OPA_RESX      = a_lo;
142
  MULDIV_OPB_UMUL_RESY = b_lo;
143
#if NEO430_HWMUL_DSP
144
  // no processind delay required for DSP (MUL) blocks
145
#else
146
  muldiv_processing_delay // HW processing delay
147
#endif
148
  tmp64.uint16[0] = MULDIV_OPA_RESX;
149
  tmp64.uint16[1] = MULDIV_OPB_UMUL_RESY;
150
  tmp64.uint16[2] = 0;
151
  tmp64.uint16[3] = 0;
152
  uint64_t res64 = tmp64.uint64;
153
 
154
//MULDIV_OPA_RESX      = a_lo;
155
  MULDIV_OPB_UMUL_RESY = b_hi;
156
#if NEO430_HWMUL_DSP
157
  // no processind delay required for DSP (MUL) blocks
158
#else
159
  muldiv_processing_delay // HW processing delay
160
#endif
161
  tmp64.uint16[0] = 0;
162
  tmp64.uint16[1] = MULDIV_OPA_RESX;
163
  tmp64.uint16[2] = MULDIV_OPB_UMUL_RESY;
164
  tmp64.uint16[3] = 0;
165
  res64 += tmp64.uint64;
166
 
167
  MULDIV_OPA_RESX      = a_hi;
168
  MULDIV_OPB_UMUL_RESY = b_lo;
169
#if NEO430_HWMUL_DSP
170
  // no processind delay required for DSP (MUL) blocks
171
#else
172
  muldiv_processing_delay // HW processing delay
173
#endif
174
  tmp64.uint16[0] = 0;
175
  tmp64.uint16[1] = MULDIV_OPA_RESX;
176
  tmp64.uint16[2] = MULDIV_OPB_UMUL_RESY;
177
  tmp64.uint16[3] = 0;
178
  res64 += tmp64.uint64;
179
 
180
//MULDIV_OPA_RESX      = a_hi;
181
  MULDIV_OPB_UMUL_RESY = b_hi;
182
#if NEO430_HWMUL_DSP
183
  // no processind delay required for DSP (MUL) blocks
184
#else
185
  muldiv_processing_delay // HW processing delay
186
#endif
187
  tmp64.uint16[0] = 0;
188
  tmp64.uint16[1] = 0;
189
  tmp64.uint16[2] = MULDIV_OPA_RESX;
190
  tmp64.uint16[3] = MULDIV_OPB_UMUL_RESY;
191
  res64 += tmp64.uint64;
192
 
193
  return res64;
194
}
195
 
196
 
197
/* ------------------------------------------------------------
198
 * INFO Signed 16x16-bit multiplication
199
 * PARAM 16-bit factor a
200
 * PARAM 16-bit factor b
201
 * RETURN 32-bit product
202
 * ------------------------------------------------------------ */
203
int32_t neo430_mul32(int16_t a, int16_t b) {
204
 
205
  MULDIV_OPA_RESX = (uint16_t)a;
206
  MULDIV_OPB_SMUL = (uint16_t)b;
207
 
208
#if NEO430_HWMUL_DSP
209
  // no processind delay required for DSP (MUL) blocks
210
#else
211
  muldiv_processing_delay // HW processing delay
212
#endif
213
 
214
  int32_t r = (int32_t)MULDIV_R32bit;
215
 
216
  return r;
217
}
218
 
219
 
220
/* ------------------------------------------------------------
221
 * INFO Signed 32x32-bit multiplication (large!)
222
 * PARAM 32-bit factor a
223
 * PARAM 32-bit factor b
224
 * RETURN 64-bit product
225
 * ------------------------------------------------------------ */
226
int64_t neo430_mul64(int32_t a, int32_t b) {
227
 
228
  union int32_u tmp32;
229
  union int64_u tmp64;
230
 
231
  // get input words (16-bit)
232
  tmp32.int32 = a;
233
  register int16_t a_lo = tmp32.int16[0];
234
  register int16_t a_hi = tmp32.int16[1];
235
 
236
  tmp32.int32 = b;
237
  register int16_t b_lo = tmp32.int16[0];
238
  register int16_t b_hi = tmp32.int16[1];
239
 
240
  // compute partial results and arrange in 64-bit word
241
  MULDIV_OPA_RESX = (uint16_t)a_lo;
242
  MULDIV_OPB_SMUL = (uint16_t)b_lo;
243
#if NEO430_HWMUL_DSP
244
  // no processind delay required for DSP (MUL) blocks
245
#else
246
  muldiv_processing_delay // HW processing delay
247
#endif
248
  tmp64.int16[0] = MULDIV_OPA_RESX;
249
  tmp64.int16[1] = MULDIV_OPB_UMUL_RESY;
250
  tmp64.int16[2] = 0;
251
  tmp64.int16[3] = 0;
252
  int64_t res64 = tmp64.int64;
253
 
254
//MULDIV_OPA_RESX = (uint16_t)a_lo;
255
  MULDIV_OPB_SMUL = (uint16_t)b_hi;
256
#if NEO430_HWMUL_DSP
257
  // no processind delay required for DSP (MUL) blocks
258
#else
259
  muldiv_processing_delay // HW processing delay
260
#endif
261
  tmp64.int16[0] = 0;
262
  tmp64.int16[1] = MULDIV_OPA_RESX;
263
  tmp64.int16[2] = MULDIV_OPB_UMUL_RESY;
264
  if (tmp64.int16[2] < 0) // sign extension
265
    tmp64.int16[3] = 0xffff;
266
  else
267
    tmp64.int16[3] = 0;
268
  res64 += tmp64.int64;
269
 
270
  MULDIV_OPA_RESX = (uint16_t)a_hi;
271
  MULDIV_OPB_SMUL = (uint16_t)b_lo;
272
#if NEO430_HWMUL_DSP
273
  // no processind delay required for DSP (MUL) blocks
274
#else
275
  muldiv_processing_delay // HW processing delay
276
#endif
277
  tmp64.int16[0] = 0;
278
  tmp64.int16[1] = MULDIV_OPA_RESX;
279
  tmp64.int16[2] = MULDIV_OPB_UMUL_RESY;
280
  if (tmp64.int16[2] < 0) // sign extension
281
    tmp64.int16[3] = 0xffff;
282
  else
283
    tmp64.int16[3] = 0;
284
  res64 += tmp64.int64;
285
 
286
//MULDIV_OPA_RESX = (uint16_t)a_hi;
287
  MULDIV_OPB_SMUL = (uint16_t)b_lo;
288
#if NEO430_HWMUL_DSP
289
  // no processind delay required for DSP (MUL) blocks
290
#else
291
  muldiv_processing_delay // HW processing delay
292
#endif
293
  tmp64.int16[0] = 0;
294
  tmp64.int16[1] = 0;
295
  tmp64.int16[2] = MULDIV_OPA_RESX;
296
  tmp64.int16[3] = MULDIV_OPB_UMUL_RESY;
297
  res64 += tmp64.int64;
298
 
299
  return res64;
300
}
301
 
302
 
303
/* ------------------------------------------------------------
304
 * INFO Unsigned 16 by 16-bit division
305
 * PARAM 16-bit dividend
306
 * PARAM 16-bit divisor
307
 * RETURN 16-bit quotient
308
 * ------------------------------------------------------------ */
309
uint16_t neo430_udiv16(uint16_t dividend, uint16_t divisor) {
310
 
311
  MULDIV_OPA_RESX = dividend;
312
  MULDIV_OPB_UDIV = divisor;
313
 
314
  muldiv_processing_delay // HW processing delay
315
 
316
  return MULDIV_OPA_RESX;
317
}
318
 
319
 
320
/* ------------------------------------------------------------
321
 * INFO Signed 16 by 16-bit division
322
 * PARAM 16-bit dividend
323
 * PARAM 16-bit divisor
324
 * RETURN 16-bit quotient
325
 * ------------------------------------------------------------ */
326
int16_t neo430_div16(int16_t dividend, int16_t divisor) {
327
 
328
  // make positive / unsigned
329
  if (dividend < 0)
330
    dividend = 0 - dividend;
331
  if (divisor < 0)
332
    divisor = 0 - divisor;
333
 
334
  MULDIV_OPA_RESX = (uint16_t)dividend;
335
  MULDIV_OPB_UDIV = (uint16_t)divisor;
336
 
337
  muldiv_processing_delay // HW processing delay
338
 
339
  int16_t r = (int16_t)MULDIV_OPA_RESX;
340
 
341
  if (dividend < 0)
342
    return 0 - r;
343
  else
344
    return r;
345
}
346
 
347
 
348
/* ------------------------------------------------------------
349
 * INFO Unsigned 16 by 16-bit division
350
 * PARAM 16-bit dividend
351
 * PARAM 16-bit divisor
352
 * RETURN 16-bit remainder
353
 * ------------------------------------------------------------ */
354
uint16_t neo430_umod16(uint16_t dividend, uint16_t divisor) {
355
 
356
  MULDIV_OPA_RESX = dividend;
357
  MULDIV_OPB_UDIV = divisor;
358
 
359
  muldiv_processing_delay // HW processing delay
360
 
361
  return MULDIV_OPB_UMUL_RESY;
362
}
363
 
364
 
365
/* ------------------------------------------------------------
366
 * INFO Signed 16 by 16-bit division
367
 * PARAM 16-bit dividend
368
 * PARAM 16-bit divisor
369
 * RETURN 16-bit remainder
370
 * ------------------------------------------------------------ */
371
int16_t neo430_mod16(int16_t dividend, int16_t divisor) {
372
 
373
  int16_t dividend_int = dividend;
374
 
375
  // make positive / unsigned
376
  if (dividend_int < 0)
377
    dividend_int = 0 - dividend_int;
378
  if (divisor < 0)
379
    divisor = 0 - divisor;
380
 
381
  MULDIV_OPA_RESX = (uint16_t)dividend_int;
382
  MULDIV_OPB_UDIV = (uint16_t)divisor;
383
 
384
  muldiv_processing_delay // HW processing delay
385
 
386
  int16_t r = (int16_t)MULDIV_OPB_UMUL_RESY;
387
 
388
  if (dividend < 0)
389
    return 0 - r;
390
  else
391
    return r;
392
}
393
 
394
 
395
/* ------------------------------------------------------------
396
 * INFO Unsigned 16 by 16-bit division
397
 * PARAM 16-bit dividend
398
 * PARAM 16-bit divisor
399
 * PARAM Pointer to store 16-bit remainder
400
 * RETURN 16-bit quotient
401
 * ------------------------------------------------------------ */
402
uint16_t neo430_umoddiv16(uint16_t *remainder, uint16_t dividend, uint16_t divisor) {
403
 
404
  MULDIV_OPA_RESX = dividend;
405
  MULDIV_OPB_UDIV = divisor;
406
 
407
  muldiv_processing_delay // HW processing delay
408
 
409
  *remainder = MULDIV_OPB_UMUL_RESY;
410
  return MULDIV_OPA_RESX;
411
}
412
 
413
 
414
/* ------------------------------------------------------------
415
 * INFO Signed 16 by 16-bit division
416
 * PARAM 16-bit dividend
417
 * PARAM 16-bit divisor
418
 * PARAM Pointer to store 16-bit remainder
419
 * RETURN 16-bit quotient
420
 * ------------------------------------------------------------ */
421
int16_t neo430_moddiv16(int16_t *remainder, int16_t dividend, int16_t divisor) {
422
 
423
  int16_t sign = dividend ^ divisor;
424
  int16_t dividend_int = dividend;
425
 
426
  // make positive / unsigned
427
  if (dividend_int < 0)
428
    dividend_int = 0 - dividend_int;
429
  if (divisor < 0)
430
    divisor = 0 - divisor;
431
 
432
  MULDIV_OPA_RESX = (uint16_t)dividend_int;
433
  MULDIV_OPB_UDIV = (uint16_t)divisor;
434
 
435
  muldiv_processing_delay // HW processing delay
436
 
437
  int16_t q = (int16_t)MULDIV_OPA_RESX;
438
  int16_t r = (int16_t)MULDIV_OPB_UMUL_RESY;
439
 
440
  if (dividend < 0)
441
    *remainder = 0 - r;
442
  else
443
    *remainder = r;
444
 
445
  if (sign < 0)
446
    return 0 - q;
447
  else
448
    return q;
449
}
450
 
451
 
452
// *****************************************************************************
453
// * DANGER ZONE!!!                                                            *
454
// * Override primitives for multiplication to use the MULDIV hardware unit    *
455
// *****************************************************************************
456
#if NEO430_HWMUL_ABI_OVERRIDE
457
 
458
int16_t __mulhi2(int16_t x, int16_t y) {
459
  return (int16_t)neo430_umul32((uint16_t)x,(uint16_t)y);
460
}
461
 
462
int32_t __mulhisi2(int16_t x, int16_t y) {
463
  return neo430_mul32(x,y);
464
}
465
 
466
uint32_t __umulhisi2(uint16_t x, uint16_t y) {
467
  return neo430_umul32(x,y);
468
}
469
 
470
int32_t __mulsi2(int32_t x, int32_t y) {
471
  return (int32_t)neo430_umul32_32((uint32_t)x,(uint32_t)y);
472
}
473
 
474
int32_t __mulsidi2(int32_t x, int32_t y) {
475
  return neo430_mul64(x,y);
476
}
477
 
478
uint64_t __umulsidi2(uint32_t x, uint32_t y) {
479
  return neo430_umul64(x,y);
480
}
481
 
482
#endif
483
// *****************************************************************************

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.