sc_nbexterns.cc revision 12854:c95c35407325
114039Sstacze01@arm.com/*****************************************************************************
214039Sstacze01@arm.com
314039Sstacze01@arm.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
414039Sstacze01@arm.com  more contributor license agreements.  See the NOTICE file distributed
514039Sstacze01@arm.com  with this work for additional information regarding copyright ownership.
614039Sstacze01@arm.com  Accellera licenses this file to you under the Apache License, Version 2.0
714039Sstacze01@arm.com  (the "License"); you may not use this file except in compliance with the
814039Sstacze01@arm.com  License.  You may obtain a copy of the License at
914039Sstacze01@arm.com
1014039Sstacze01@arm.com    http://www.apache.org/licenses/LICENSE-2.0
1114039Sstacze01@arm.com
1214039Sstacze01@arm.com  Unless required by applicable law or agreed to in writing, software
1314039Sstacze01@arm.com  distributed under the License is distributed on an "AS IS" BASIS,
1414039Sstacze01@arm.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1514039Sstacze01@arm.com  implied.  See the License for the specific language governing
1614039Sstacze01@arm.com  permissions and limitations under the License.
1714039Sstacze01@arm.com
1814039Sstacze01@arm.com *****************************************************************************/
1914039Sstacze01@arm.com
2014039Sstacze01@arm.com/*****************************************************************************
2114039Sstacze01@arm.com
2214039Sstacze01@arm.com  sc_nbexterns.cpp -- External functions for both sc_signed and sc_unsigned
2314039Sstacze01@arm.com                      classes. These functions work on two parameters u and
2414039Sstacze01@arm.com                      v, and copy the result to the first parameter u. This
2514039Sstacze01@arm.com                      is also the reason that they are suffixed with _on_help.
2614039Sstacze01@arm.com
2714039Sstacze01@arm.com  Original Author: Ali Dasdan, Synopsys, Inc.
2814039Sstacze01@arm.com
2914039Sstacze01@arm.com *****************************************************************************/
3014039Sstacze01@arm.com
3114039Sstacze01@arm.com/*****************************************************************************
3214039Sstacze01@arm.com
3314039Sstacze01@arm.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3414039Sstacze01@arm.com  changes you are making here.
3514039Sstacze01@arm.com
3614039Sstacze01@arm.com      Name, Affiliation, Date:
3714039Sstacze01@arm.com  Description of Modification:
3814039Sstacze01@arm.com
3914039Sstacze01@arm.com *****************************************************************************/
4014039Sstacze01@arm.com
4114039Sstacze01@arm.com
4214039Sstacze01@arm.com// $Log: sc_nbexterns.cpp,v $
4314039Sstacze01@arm.com// Revision 1.2  2011/02/18 20:19:15  acg
4414039Sstacze01@arm.com//  Andy Goodrich: updating Copyright notice.
4514039Sstacze01@arm.com//
4614039Sstacze01@arm.com// Revision 1.1.1.1  2006/12/15 20:20:05  acg
4714039Sstacze01@arm.com// SystemC 2.3
4814039Sstacze01@arm.com//
4914039Sstacze01@arm.com// Revision 1.3  2006/01/13 18:49:32  acg
5014039Sstacze01@arm.com// Added $Log command so that CVS check in comments are reproduced in the
5114039Sstacze01@arm.com// source.
5214039Sstacze01@arm.com//
5314039Sstacze01@arm.com
5414039Sstacze01@arm.com#include "systemc/ext/dt/int/sc_nbexterns.hh"
5514039Sstacze01@arm.com#include "systemc/ext/utils/functions.hh"
5614039Sstacze01@arm.com
5714039Sstacze01@arm.comnamespace sc_dt
5814039Sstacze01@arm.com{
5914104Sgiacomo.travaglini@arm.com
6014104Sgiacomo.travaglini@arm.com// ----------------------------------------------------------------------------
6114104Sgiacomo.travaglini@arm.com//  SECTION: External functions for PLUS operators.
6214104Sgiacomo.travaglini@arm.com// ----------------------------------------------------------------------------
6314104Sgiacomo.travaglini@arm.com
6414039Sstacze01@arm.com// Handles the cases 3 and 4 and returns the result in u.
6514104Sgiacomo.travaglini@arm.comvoid
6614104Sgiacomo.travaglini@arm.comadd_on_help(small_type &us, int /* unb */, int und, sc_digit *ud,
6714104Sgiacomo.travaglini@arm.com            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
6814104Sgiacomo.travaglini@arm.com{
6914104Sgiacomo.travaglini@arm.com    vnd = vec_skip_leading_zeros(vnd, vd);
7014104Sgiacomo.travaglini@arm.com
7114039Sstacze01@arm.com    if (us == vs) {  // case 3
7214039Sstacze01@arm.com        if (und >= vnd)
7314104Sgiacomo.travaglini@arm.com            vec_add_on(und, ud, vnd, vd);
7414039Sstacze01@arm.com        else
7514104Sgiacomo.travaglini@arm.com            vec_add_on2(und, ud, vnd, vd);
7614039Sstacze01@arm.com
7714039Sstacze01@arm.com    } else {  // case 4
7814104Sgiacomo.travaglini@arm.com        // vec_cmp expects that und is the number of non-zero digits in ud.
7914039Sstacze01@arm.com        int new_und = vec_skip_leading_zeros(und, ud);
8014104Sgiacomo.travaglini@arm.com        int cmp_res = vec_cmp(new_und, ud, vnd, vd);
8114039Sstacze01@arm.com
8214039Sstacze01@arm.com        if (cmp_res == 0) { // u == v
8314039Sstacze01@arm.com            us = SC_ZERO;
8414039Sstacze01@arm.com            vec_zero(und, ud);
8514064Sadrian.herrera@arm.com            return;
8614064Sadrian.herrera@arm.com        }
8714039Sstacze01@arm.com
8814039Sstacze01@arm.com        if (cmp_res > 0) { // u > v
8914039Sstacze01@arm.com            vec_sub_on(und, ud, vnd, vd);
9014039Sstacze01@arm.com        } else { // u < v
91            us = -us;
92            vec_sub_on2(und, ud, vnd, vd);
93        }
94    }
95}
96
97
98// ----------------------------------------------------------------------------
99
100/*
101
102mul_on_help_signed and mul_on_help_unsigned have the same body except
103that CONVERT_SM_to_2C_to_SM and COPY_DIGITS are defined for signed and
104unsigned, respectively.  This comment also applies to the
105signed/unsigned versions of div_on_help and mod_on_help. It is
106possible to take COPY_DIGITS out of these functions and create a
107single version of each of these helper functions; however, this will
108impose an onverhead on performance. In the versions below, any change
109in the signed version of a helper function must be carried to a
110corresponding change in the unsigned verion of the same function or
111vice versa.
112
113*/
114
115
116// ----------------------------------------------------------------------------
117//  SECTION: External functions of MULTIPLICATION operators.
118// ----------------------------------------------------------------------------
119
120void
121mul_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
122                   int vnb, int vnd, const sc_digit *vd)
123{
124#define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM
125#define COPY_DIGITS copy_digits_signed
126    { // Body of mul_on_help
127        int old_und = und;
128
129        und = vec_skip_leading_zeros(und, ud);
130        vnd = vec_skip_leading_zeros(vnd, vd);
131
132        sc_digit ud0 = (*ud);
133        sc_digit vd0 = (*vd);
134
135        if ((vnd == 1) && (vd0 == 1)) {
136            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
137            return;
138        }
139
140        if ((und == 1) && (ud0 == 1)) {
141            COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd);
142            return;
143        }
144
145        if ((und == 1) && (vnd == 1) &&
146            (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) {
147
148            sc_digit d = ud0 * vd0;
149            COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d);
150            return;
151        }
152
153        int nd = und + vnd;
154
155#ifdef SC_MAX_NBITS
156        sc_digit d[MAX_NDIGITS];
157#else
158        sc_digit *d = new sc_digit[nd];
159#endif
160
161        vec_zero(nd, d);
162
163        if ((und == 1) && (ud0 < HALF_DIGIT_RADIX))
164            vec_mul_small(vnd, vd, ud0, d);
165        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
166            vec_mul_small(und, ud, vd0, d);
167        else if (vnd < und)
168            vec_mul(und, ud, vnd, vd, d);
169        else
170            vec_mul(vnd, vd, und, ud, d);
171
172        COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d);
173
174#ifndef SC_MAX_NBITS
175        delete [] d;
176#endif
177    }
178#undef COPY_DIGITS
179#undef CONVERT_SM_to_2C_to_SM
180}
181
182
183void
184mul_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
185                     int vnb, int vnd, const sc_digit *vd)
186{
187#define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM
188#define COPY_DIGITS copy_digits_unsigned
189    { // Body of mul_on_help
190        int old_und = und;
191
192        und = vec_skip_leading_zeros(und, ud);
193        vnd = vec_skip_leading_zeros(vnd, vd);
194
195        sc_digit ud0 = (*ud);
196        sc_digit vd0 = (*vd);
197
198        if ((vnd == 1) && (vd0 == 1)) {
199            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
200            return;
201        }
202
203        if ((und == 1) && (ud0 == 1)) {
204            COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd);
205            return;
206        }
207
208        if ((und == 1) && (vnd == 1) &&
209            (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) {
210
211            sc_digit d = ud0 * vd0;
212            COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d);
213            return;
214        }
215
216        int nd = und + vnd;
217
218#ifdef SC_MAX_NBITS
219        sc_digit d[MAX_NDIGITS];
220#else
221        sc_digit *d = new sc_digit[nd];
222#endif
223
224        vec_zero(nd, d);
225
226        if ((und == 1) && (ud0 < HALF_DIGIT_RADIX))
227            vec_mul_small(vnd, vd, ud0, d);
228        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
229            vec_mul_small(und, ud, vd0, d);
230        else if (vnd < und)
231            vec_mul(und, ud, vnd, vd, d);
232        else
233            vec_mul(vnd, vd, und, ud, d);
234
235        COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d);
236
237#ifndef SC_MAX_NBITS
238        delete [] d;
239#endif
240      }
241#undef COPY_DIGITS
242#undef CONVERT_SM_to_2C_to_SM
243}
244
245
246// ----------------------------------------------------------------------------
247//  SECTION: External functions for DIVISION operators.
248// ----------------------------------------------------------------------------
249
250void
251div_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
252                   int vnb, int vnd, const sc_digit *vd)
253{
254#define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM
255#define COPY_DIGITS copy_digits_signed
256    {  // Body of div_on_help
257        int old_und = und;
258
259        und = vec_skip_leading_zeros(und, ud);
260        vnd = vec_skip_leading_zeros(vnd, vd);
261
262        int cmp_res = vec_cmp(und, ud, vnd, vd);
263
264        if (cmp_res < 0) { // u < v => u / v = 0 - case 4
265            us = SC_ZERO;
266            vec_zero(old_und, ud);
267            return;
268        }
269
270        sc_digit vd0 = (*vd);
271
272        if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1)) {
273            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
274            return;
275        }
276
277        // One extra digit for d is allocated to simplify vec_div_*().
278        int nd = sc_max(und, vnd) + 1;
279
280#ifdef SC_MAX_NBITS
281        sc_digit d[MAX_NDIGITS + 1];
282#else
283        sc_digit *d = new sc_digit[nd];
284#endif
285
286        vec_zero(nd, d);
287
288        // u = v => u / v = 1 - case 3
289        if (cmp_res == 0)
290            d[0] = 1;
291        else if ((vnd == 1) && (und == 1))
292            d[0] = (*ud) / vd0;
293        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
294            vec_div_small(und, ud, vd0, d);
295        else
296            vec_div_large(und, ud, vnd, vd, d);
297
298        COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d);
299
300#ifndef SC_MAX_NBITS
301        delete [] d;
302#endif
303    }
304#undef COPY_DIGITS
305#undef CONVERT_SM_to_2C_to_SM
306}
307
308
309void
310div_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
311                     int vnb, int vnd, const sc_digit *vd)
312{
313#define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM
314#define COPY_DIGITS copy_digits_unsigned
315    { // Body of div_on_help
316        int old_und = und;
317
318        und = vec_skip_leading_zeros(und, ud);
319        vnd = vec_skip_leading_zeros(vnd, vd);
320
321        int cmp_res = vec_cmp(und, ud, vnd, vd);
322
323        if (cmp_res < 0) { // u < v => u / v = 0 - case 4
324            us = SC_ZERO;
325            vec_zero(old_und, ud);
326            return;
327        }
328
329        sc_digit vd0 = (*vd);
330
331        if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1))  {
332            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
333            return;
334        }
335
336        // One extra digit for d is allocated to simplify vec_div_*().
337        int nd = sc_max(und, vnd) + 1;
338
339#ifdef SC_MAX_NBITS
340        sc_digit d[MAX_NDIGITS + 1];
341#else
342        sc_digit *d = new sc_digit[nd];
343#endif
344
345        vec_zero(nd, d);
346
347        // u = v => u / v = 1 - case 3
348        if (cmp_res == 0)
349            d[0] = 1;
350        else if ((vnd == 1) && (und == 1))
351            d[0] = (*ud) / vd0;
352        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
353            vec_div_small(und, ud, vd0, d);
354        else
355            vec_div_large(und, ud, vnd, vd, d);
356
357        COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d);
358
359#ifndef SC_MAX_NBITS
360        delete [] d;
361#endif
362      }
363#undef COPY_DIGITS
364#undef CONVERT_SM_to_2C_to_SM
365}
366
367
368// ----------------------------------------------------------------------------
369//  SECTION: External functions for MOD operators.
370// ----------------------------------------------------------------------------
371
372void
373mod_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
374                   int /* vnb */, int vnd, const sc_digit *vd)
375{
376#define COPY_DIGITS copy_digits_signed
377    { // Body of mod_on_help
378        int old_und = und;
379
380        und = vec_skip_leading_zeros(und, ud);
381        vnd = vec_skip_leading_zeros(vnd, vd);
382
383        int cmp_res = vec_cmp(und, ud, vnd, vd);
384
385        // u < v => u % v = u - case 4
386        if (cmp_res < 0)
387            return;
388
389        // u = v => u % v = 0 - case 3
390        if (cmp_res == 0) {
391            us = SC_ZERO;
392            vec_zero(old_und, ud);
393            return;
394        }
395        // else if u > v - case 5
396
397        sc_digit vd0 = (*vd);
398
399        if ((vnd == 1) && (vd0 == 1)) {
400            us = SC_ZERO;
401            vec_zero(old_und, ud);
402            return;
403        }
404
405        // One extra digit for d is allocated to simplify vec_div_*().
406        int nd = sc_max(und, vnd) + 1;
407
408#ifdef SC_MAX_NBITS
409        sc_digit d[MAX_NDIGITS + 1];
410#else
411        sc_digit *d = new sc_digit[nd];
412#endif
413
414        vec_zero(nd, d);
415
416        if ((vnd == 1) && (und == 1))
417            d[0] = (*ud) % vd0;
418        if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
419            d[0] = vec_rem_small(und, ud, vd0);
420        else
421            vec_rem_large(und, ud, vnd, vd, d);
422
423        us = check_for_zero(us, nd - 1, d);
424
425        if (us == SC_ZERO)
426            vec_zero(old_und, ud);
427        else
428            COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d);
429
430#ifndef SC_MAX_NBITS
431        delete [] d;
432#endif
433    }
434#undef COPY_DIGITS
435}
436
437
438void
439mod_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
440                     int /* vnb */, int vnd, const sc_digit *vd)
441{
442#define COPY_DIGITS copy_digits_unsigned
443    { // Body of mod_on_help
444        int old_und = und;
445
446        und = vec_skip_leading_zeros(und, ud);
447        vnd = vec_skip_leading_zeros(vnd, vd);
448
449        int cmp_res = vec_cmp(und, ud, vnd, vd);
450
451        // u < v => u % v = u - case 4
452        if (cmp_res < 0)
453            return;
454
455        // u = v => u % v = 0 - case 3
456        if (cmp_res == 0) {
457            us = SC_ZERO;
458            vec_zero(old_und, ud);
459            return;
460        }
461
462        // else if u > v - case 5
463
464        sc_digit vd0 = (*vd);
465
466        if ((vnd == 1) && (vd0 == 1)) {
467            us = SC_ZERO;
468            vec_zero(old_und, ud);
469            return;
470        }
471
472        // One extra digit for d is allocated to simplify vec_div_*().
473        int nd = sc_max(und, vnd) + 1;
474
475#ifdef SC_MAX_NBITS
476        sc_digit d[MAX_NDIGITS + 1];
477#else
478        sc_digit *d = new sc_digit[nd];
479#endif
480
481        vec_zero(nd, d);
482
483        if ((vnd == 1) && (und == 1))
484            d[0] = (*ud) % vd0;
485        if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
486            d[0] = vec_rem_small(und, ud, vd0);
487        else
488            vec_rem_large(und, ud, vnd, vd, d);
489
490        us = check_for_zero(us, nd - 1, d);
491
492        if (us == SC_ZERO)
493            vec_zero(old_und, ud);
494        else
495            COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d);
496
497#ifndef SC_MAX_NBITS
498        delete [] d;
499#endif
500    }
501#undef COPY_DIGITS
502}
503
504
505// ----------------------------------------------------------------------------
506//  SECTION: External functions for AND operators.
507// ----------------------------------------------------------------------------
508
509// Handles the cases 2-5 and returns the result in u.
510void
511and_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
512            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
513{
514    sc_digit *x = ud;
515    const sc_digit *y = vd;
516    int xnd = und;
517    int ynd = vnd;
518
519    // Truncate y.
520    if (xnd < ynd)
521        ynd = xnd;
522
523    const sc_digit *xend = (x + xnd);
524    const sc_digit *yend = (y + ynd);
525
526    // x is longer than y.
527    small_type s = mul_signs(us, vs);
528
529    if (s > 0) {
530        if (us > 0) { // case 2
531            while (y < yend)
532                (*x++) &= (*y++);
533            while (x < xend)
534                (*x++) = 0;
535        } else { // case 3
536            sc_digit xcarry = 1;
537            sc_digit ycarry = 1;
538            while (y < yend) {
539                xcarry += (~(*x) & DIGIT_MASK);
540                ycarry += (~(*y++) & DIGIT_MASK);
541                (*x++) = (xcarry & ycarry) & DIGIT_MASK;
542                xcarry >>= BITS_PER_DIGIT;
543                ycarry >>= BITS_PER_DIGIT;
544            }
545            while (x < xend) {
546                xcarry += (~(*x) & DIGIT_MASK);
547                ycarry += DIGIT_MASK;
548                (*x++) = (xcarry & ycarry) & DIGIT_MASK;
549                xcarry >>= BITS_PER_DIGIT;
550                ycarry >>= BITS_PER_DIGIT;
551            }
552
553        }
554    } else {
555        if (us > 0) { // case 4
556            sc_digit ycarry = 1;
557            while (y < yend) {
558                ycarry += (~(*y++) & DIGIT_MASK);
559                (*x++) &= ycarry & DIGIT_MASK;
560                ycarry >>= BITS_PER_DIGIT;
561            }
562            while (x < xend) {
563                ycarry += DIGIT_MASK;
564                (*x++) &= ycarry & DIGIT_MASK;
565                ycarry >>= BITS_PER_DIGIT;
566            }
567        } else { // case 5
568            sc_digit xcarry = 1;
569            while (y < yend) {
570                xcarry += (~(*x) & DIGIT_MASK);
571                (*x++) = (xcarry & (*y++)) & DIGIT_MASK;
572                xcarry >>= BITS_PER_DIGIT;
573            }
574            while (x < xend)
575                (*x++) = 0;
576        }
577    }
578}
579
580
581// ----------------------------------------------------------------------------
582//  SECTION: External functions for OR operators.
583// ----------------------------------------------------------------------------
584
585// Handles the cases 3-5 and returns the result in u.
586void
587or_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
588           small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
589{
590    sc_digit *x = ud;
591    const sc_digit *y = vd;
592    int xnd = und;
593    int ynd = vnd;
594
595    if (xnd < ynd)
596        ynd = xnd;
597
598    const sc_digit *xend = (x + xnd);
599    const sc_digit *yend = (y + ynd);
600
601    // x is longer than y.
602    small_type s = mul_signs(us, vs);
603
604    if (s > 0) {
605        if (us > 0) { // case 3
606            while (y < yend)
607                (*x++) |= (*y++);
608            // No change for the rest of x.
609        } else { // case 4
610            sc_digit xcarry = 1;
611            sc_digit ycarry = 1;
612            while (y < yend) {
613                xcarry += (~(*x) & DIGIT_MASK);
614                ycarry += (~(*y++) & DIGIT_MASK);
615                (*x++) = (xcarry | ycarry) & DIGIT_MASK;
616                xcarry >>= BITS_PER_DIGIT;
617                ycarry >>= BITS_PER_DIGIT;
618            }
619            while (x < xend) {
620                xcarry += (~(*x) & DIGIT_MASK);
621                ycarry += DIGIT_MASK;
622                (*x++) = (xcarry | ycarry) & DIGIT_MASK;
623                xcarry >>= BITS_PER_DIGIT;
624                ycarry >>= BITS_PER_DIGIT;
625            }
626        }
627    } else {
628        if (us > 0) { // case 5
629            sc_digit ycarry = 1;
630            while (y < yend) {
631                ycarry += (~(*y++) & DIGIT_MASK);
632                (*x) = ((*x) | ycarry) & DIGIT_MASK;
633                x++;
634                ycarry >>= BITS_PER_DIGIT;
635            }
636            while (x < xend) {
637                ycarry += DIGIT_MASK;
638                (*x) = ((*x) | ycarry) & DIGIT_MASK;
639                x++;
640                ycarry >>= BITS_PER_DIGIT;
641            }
642        } else { // case 6
643            sc_digit xcarry = 1;
644            while (y < yend) {
645                xcarry += (~(*x) & DIGIT_MASK);
646                (*x++) = (xcarry | (*y++)) & DIGIT_MASK;
647                xcarry >>= BITS_PER_DIGIT;
648            }
649            while (x < xend) {
650                xcarry += (~(*x) & DIGIT_MASK);
651                (*x++) = xcarry & DIGIT_MASK;
652                xcarry >>= BITS_PER_DIGIT;
653            }
654        }
655    }
656}
657
658
659// ----------------------------------------------------------------------------
660//  SECTION: External functions for XOR operators.
661// ----------------------------------------------------------------------------
662
663// Handles the cases 3-5 and returns the result in u.
664void
665xor_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
666            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
667{
668    sc_digit *x = ud;
669    const sc_digit *y = vd;
670    int xnd = und;
671    int ynd = vnd;
672
673    if (xnd < ynd)
674        ynd = xnd;
675
676    const sc_digit *xend = (x + xnd);
677    const sc_digit *yend = (y + ynd);
678
679    // x is longer than y.
680    small_type s = mul_signs(us, vs);
681
682    if (s > 0) {
683        if (us > 0) { // case 3
684            while (y < yend) {
685                (*x) = ((*x) ^ (*y)) & DIGIT_MASK;
686                x++;
687                y++;
688            }
689            // No change for the rest of x.
690        } else { // case 4
691            sc_digit xcarry = 1;
692            sc_digit ycarry = 1;
693            while (y < yend) {
694                xcarry += (~(*x) & DIGIT_MASK);
695                ycarry += (~(*y++) & DIGIT_MASK);
696                (*x++) = (xcarry ^ ycarry) & DIGIT_MASK;
697                xcarry >>= BITS_PER_DIGIT;
698                ycarry >>= BITS_PER_DIGIT;
699            }
700            while (x < xend) {
701                xcarry += (~(*x) & DIGIT_MASK);
702                ycarry += DIGIT_MASK;
703                (*x++) = (xcarry ^ ycarry) & DIGIT_MASK;
704                xcarry >>= BITS_PER_DIGIT;
705                ycarry >>= BITS_PER_DIGIT;
706            }
707        }
708    } else {
709        if (us > 0) { // case 5
710            sc_digit ycarry = 1;
711            while (y < yend) {
712                ycarry += (~(*y++) & DIGIT_MASK);
713                (*x) = ((*x) ^ ycarry) & DIGIT_MASK;
714                x++;
715                ycarry >>= BITS_PER_DIGIT;
716            }
717            while (x < xend) {
718                ycarry += DIGIT_MASK;
719                (*x) = ((*x) ^ ycarry) & DIGIT_MASK;
720                x++;
721                ycarry >>= BITS_PER_DIGIT;
722            }
723        } else { // case 6
724            sc_digit xcarry = 1;
725            while (y < yend) {
726                xcarry += (~(*x) & DIGIT_MASK);
727                (*x++) = (xcarry ^ (*y++)) & DIGIT_MASK;
728                xcarry >>= BITS_PER_DIGIT;
729            }
730            while (x < xend) {
731                xcarry += (~(*x) & DIGIT_MASK);
732                (*x++) = xcarry & DIGIT_MASK;
733                xcarry >>= BITS_PER_DIGIT;
734            }
735        }
736    }
737}
738
739} // namespace sc_dt
740