112854Sgabeblack@google.com/*****************************************************************************
212854Sgabeblack@google.com
312854Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412854Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
512854Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
612854Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
712854Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
812854Sgabeblack@google.com  License.  You may obtain a copy of the License at
912854Sgabeblack@google.com
1012854Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1112854Sgabeblack@google.com
1212854Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1312854Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1412854Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512854Sgabeblack@google.com  implied.  See the License for the specific language governing
1612854Sgabeblack@google.com  permissions and limitations under the License.
1712854Sgabeblack@google.com
1812854Sgabeblack@google.com *****************************************************************************/
1912854Sgabeblack@google.com
2012854Sgabeblack@google.com/*****************************************************************************
2112854Sgabeblack@google.com
2212854Sgabeblack@google.com  sc_nbexterns.cpp -- External functions for both sc_signed and sc_unsigned
2312854Sgabeblack@google.com                      classes. These functions work on two parameters u and
2412854Sgabeblack@google.com                      v, and copy the result to the first parameter u. This
2512854Sgabeblack@google.com                      is also the reason that they are suffixed with _on_help.
2612854Sgabeblack@google.com
2712854Sgabeblack@google.com  Original Author: Ali Dasdan, Synopsys, Inc.
2812854Sgabeblack@google.com
2912854Sgabeblack@google.com *****************************************************************************/
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com/*****************************************************************************
3212854Sgabeblack@google.com
3312854Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3412854Sgabeblack@google.com  changes you are making here.
3512854Sgabeblack@google.com
3612854Sgabeblack@google.com      Name, Affiliation, Date:
3712854Sgabeblack@google.com  Description of Modification:
3812854Sgabeblack@google.com
3912854Sgabeblack@google.com *****************************************************************************/
4012854Sgabeblack@google.com
4112854Sgabeblack@google.com
4212854Sgabeblack@google.com// $Log: sc_nbexterns.cpp,v $
4312854Sgabeblack@google.com// Revision 1.2  2011/02/18 20:19:15  acg
4412854Sgabeblack@google.com//  Andy Goodrich: updating Copyright notice.
4512854Sgabeblack@google.com//
4612854Sgabeblack@google.com// Revision 1.1.1.1  2006/12/15 20:20:05  acg
4712854Sgabeblack@google.com// SystemC 2.3
4812854Sgabeblack@google.com//
4912854Sgabeblack@google.com// Revision 1.3  2006/01/13 18:49:32  acg
5012854Sgabeblack@google.com// Added $Log command so that CVS check in comments are reproduced in the
5112854Sgabeblack@google.com// source.
5212854Sgabeblack@google.com//
5312854Sgabeblack@google.com
5412854Sgabeblack@google.com#include "systemc/ext/dt/int/sc_nbexterns.hh"
5512854Sgabeblack@google.com#include "systemc/ext/utils/functions.hh"
5612854Sgabeblack@google.com
5712854Sgabeblack@google.comnamespace sc_dt
5812854Sgabeblack@google.com{
5912854Sgabeblack@google.com
6012854Sgabeblack@google.com// ----------------------------------------------------------------------------
6112854Sgabeblack@google.com//  SECTION: External functions for PLUS operators.
6212854Sgabeblack@google.com// ----------------------------------------------------------------------------
6312854Sgabeblack@google.com
6412854Sgabeblack@google.com// Handles the cases 3 and 4 and returns the result in u.
6512854Sgabeblack@google.comvoid
6612854Sgabeblack@google.comadd_on_help(small_type &us, int /* unb */, int und, sc_digit *ud,
6712854Sgabeblack@google.com            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
6812854Sgabeblack@google.com{
6912854Sgabeblack@google.com    vnd = vec_skip_leading_zeros(vnd, vd);
7012854Sgabeblack@google.com
7112854Sgabeblack@google.com    if (us == vs) {  // case 3
7212854Sgabeblack@google.com        if (und >= vnd)
7312854Sgabeblack@google.com            vec_add_on(und, ud, vnd, vd);
7412854Sgabeblack@google.com        else
7512854Sgabeblack@google.com            vec_add_on2(und, ud, vnd, vd);
7612854Sgabeblack@google.com
7712854Sgabeblack@google.com    } else {  // case 4
7812854Sgabeblack@google.com        // vec_cmp expects that und is the number of non-zero digits in ud.
7912854Sgabeblack@google.com        int new_und = vec_skip_leading_zeros(und, ud);
8012854Sgabeblack@google.com        int cmp_res = vec_cmp(new_und, ud, vnd, vd);
8112854Sgabeblack@google.com
8212854Sgabeblack@google.com        if (cmp_res == 0) { // u == v
8312854Sgabeblack@google.com            us = SC_ZERO;
8412854Sgabeblack@google.com            vec_zero(und, ud);
8512854Sgabeblack@google.com            return;
8612854Sgabeblack@google.com        }
8712854Sgabeblack@google.com
8812854Sgabeblack@google.com        if (cmp_res > 0) { // u > v
8912854Sgabeblack@google.com            vec_sub_on(und, ud, vnd, vd);
9012854Sgabeblack@google.com        } else { // u < v
9112854Sgabeblack@google.com            us = -us;
9212854Sgabeblack@google.com            vec_sub_on2(und, ud, vnd, vd);
9312854Sgabeblack@google.com        }
9412854Sgabeblack@google.com    }
9512854Sgabeblack@google.com}
9612854Sgabeblack@google.com
9712854Sgabeblack@google.com
9812854Sgabeblack@google.com// ----------------------------------------------------------------------------
9912854Sgabeblack@google.com
10012854Sgabeblack@google.com/*
10112854Sgabeblack@google.com
10212854Sgabeblack@google.commul_on_help_signed and mul_on_help_unsigned have the same body except
10312854Sgabeblack@google.comthat CONVERT_SM_to_2C_to_SM and COPY_DIGITS are defined for signed and
10412854Sgabeblack@google.comunsigned, respectively.  This comment also applies to the
10512854Sgabeblack@google.comsigned/unsigned versions of div_on_help and mod_on_help. It is
10612854Sgabeblack@google.compossible to take COPY_DIGITS out of these functions and create a
10712854Sgabeblack@google.comsingle version of each of these helper functions; however, this will
10812854Sgabeblack@google.comimpose an onverhead on performance. In the versions below, any change
10912854Sgabeblack@google.comin the signed version of a helper function must be carried to a
11012854Sgabeblack@google.comcorresponding change in the unsigned verion of the same function or
11112854Sgabeblack@google.comvice versa.
11212854Sgabeblack@google.com
11312854Sgabeblack@google.com*/
11412854Sgabeblack@google.com
11512854Sgabeblack@google.com
11612854Sgabeblack@google.com// ----------------------------------------------------------------------------
11712854Sgabeblack@google.com//  SECTION: External functions of MULTIPLICATION operators.
11812854Sgabeblack@google.com// ----------------------------------------------------------------------------
11912854Sgabeblack@google.com
12012854Sgabeblack@google.comvoid
12112854Sgabeblack@google.commul_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
12212854Sgabeblack@google.com                   int vnb, int vnd, const sc_digit *vd)
12312854Sgabeblack@google.com{
12412854Sgabeblack@google.com#define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM
12512854Sgabeblack@google.com#define COPY_DIGITS copy_digits_signed
12612854Sgabeblack@google.com    { // Body of mul_on_help
12712854Sgabeblack@google.com        int old_und = und;
12812854Sgabeblack@google.com
12912854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
13012854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
13112854Sgabeblack@google.com
13212854Sgabeblack@google.com        sc_digit ud0 = (*ud);
13312854Sgabeblack@google.com        sc_digit vd0 = (*vd);
13412854Sgabeblack@google.com
13512854Sgabeblack@google.com        if ((vnd == 1) && (vd0 == 1)) {
13612854Sgabeblack@google.com            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
13712854Sgabeblack@google.com            return;
13812854Sgabeblack@google.com        }
13912854Sgabeblack@google.com
14012854Sgabeblack@google.com        if ((und == 1) && (ud0 == 1)) {
14112854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd);
14212854Sgabeblack@google.com            return;
14312854Sgabeblack@google.com        }
14412854Sgabeblack@google.com
14512854Sgabeblack@google.com        if ((und == 1) && (vnd == 1) &&
14612854Sgabeblack@google.com            (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) {
14712854Sgabeblack@google.com
14812854Sgabeblack@google.com            sc_digit d = ud0 * vd0;
14912854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d);
15012854Sgabeblack@google.com            return;
15112854Sgabeblack@google.com        }
15212854Sgabeblack@google.com
15312854Sgabeblack@google.com        int nd = und + vnd;
15412854Sgabeblack@google.com
15512854Sgabeblack@google.com#ifdef SC_MAX_NBITS
15612854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS];
15712854Sgabeblack@google.com#else
15812854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
15912854Sgabeblack@google.com#endif
16012854Sgabeblack@google.com
16112854Sgabeblack@google.com        vec_zero(nd, d);
16212854Sgabeblack@google.com
16312854Sgabeblack@google.com        if ((und == 1) && (ud0 < HALF_DIGIT_RADIX))
16412854Sgabeblack@google.com            vec_mul_small(vnd, vd, ud0, d);
16512854Sgabeblack@google.com        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
16612854Sgabeblack@google.com            vec_mul_small(und, ud, vd0, d);
16712854Sgabeblack@google.com        else if (vnd < und)
16812854Sgabeblack@google.com            vec_mul(und, ud, vnd, vd, d);
16912854Sgabeblack@google.com        else
17012854Sgabeblack@google.com            vec_mul(vnd, vd, und, ud, d);
17112854Sgabeblack@google.com
17212854Sgabeblack@google.com        COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d);
17312854Sgabeblack@google.com
17412854Sgabeblack@google.com#ifndef SC_MAX_NBITS
17512854Sgabeblack@google.com        delete [] d;
17612854Sgabeblack@google.com#endif
17712854Sgabeblack@google.com    }
17812854Sgabeblack@google.com#undef COPY_DIGITS
17912854Sgabeblack@google.com#undef CONVERT_SM_to_2C_to_SM
18012854Sgabeblack@google.com}
18112854Sgabeblack@google.com
18212854Sgabeblack@google.com
18312854Sgabeblack@google.comvoid
18412854Sgabeblack@google.commul_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
18512854Sgabeblack@google.com                     int vnb, int vnd, const sc_digit *vd)
18612854Sgabeblack@google.com{
18712854Sgabeblack@google.com#define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM
18812854Sgabeblack@google.com#define COPY_DIGITS copy_digits_unsigned
18912854Sgabeblack@google.com    { // Body of mul_on_help
19012854Sgabeblack@google.com        int old_und = und;
19112854Sgabeblack@google.com
19212854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
19312854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
19412854Sgabeblack@google.com
19512854Sgabeblack@google.com        sc_digit ud0 = (*ud);
19612854Sgabeblack@google.com        sc_digit vd0 = (*vd);
19712854Sgabeblack@google.com
19812854Sgabeblack@google.com        if ((vnd == 1) && (vd0 == 1)) {
19912854Sgabeblack@google.com            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
20012854Sgabeblack@google.com            return;
20112854Sgabeblack@google.com        }
20212854Sgabeblack@google.com
20312854Sgabeblack@google.com        if ((und == 1) && (ud0 == 1)) {
20412854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd);
20512854Sgabeblack@google.com            return;
20612854Sgabeblack@google.com        }
20712854Sgabeblack@google.com
20812854Sgabeblack@google.com        if ((und == 1) && (vnd == 1) &&
20912854Sgabeblack@google.com            (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) {
21012854Sgabeblack@google.com
21112854Sgabeblack@google.com            sc_digit d = ud0 * vd0;
21212854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d);
21312854Sgabeblack@google.com            return;
21412854Sgabeblack@google.com        }
21512854Sgabeblack@google.com
21612854Sgabeblack@google.com        int nd = und + vnd;
21712854Sgabeblack@google.com
21812854Sgabeblack@google.com#ifdef SC_MAX_NBITS
21912854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS];
22012854Sgabeblack@google.com#else
22112854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
22212854Sgabeblack@google.com#endif
22312854Sgabeblack@google.com
22412854Sgabeblack@google.com        vec_zero(nd, d);
22512854Sgabeblack@google.com
22612854Sgabeblack@google.com        if ((und == 1) && (ud0 < HALF_DIGIT_RADIX))
22712854Sgabeblack@google.com            vec_mul_small(vnd, vd, ud0, d);
22812854Sgabeblack@google.com        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
22912854Sgabeblack@google.com            vec_mul_small(und, ud, vd0, d);
23012854Sgabeblack@google.com        else if (vnd < und)
23112854Sgabeblack@google.com            vec_mul(und, ud, vnd, vd, d);
23212854Sgabeblack@google.com        else
23312854Sgabeblack@google.com            vec_mul(vnd, vd, und, ud, d);
23412854Sgabeblack@google.com
23512854Sgabeblack@google.com        COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d);
23612854Sgabeblack@google.com
23712854Sgabeblack@google.com#ifndef SC_MAX_NBITS
23812854Sgabeblack@google.com        delete [] d;
23912854Sgabeblack@google.com#endif
24012854Sgabeblack@google.com      }
24112854Sgabeblack@google.com#undef COPY_DIGITS
24212854Sgabeblack@google.com#undef CONVERT_SM_to_2C_to_SM
24312854Sgabeblack@google.com}
24412854Sgabeblack@google.com
24512854Sgabeblack@google.com
24612854Sgabeblack@google.com// ----------------------------------------------------------------------------
24712854Sgabeblack@google.com//  SECTION: External functions for DIVISION operators.
24812854Sgabeblack@google.com// ----------------------------------------------------------------------------
24912854Sgabeblack@google.com
25012854Sgabeblack@google.comvoid
25112854Sgabeblack@google.comdiv_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
25212854Sgabeblack@google.com                   int vnb, int vnd, const sc_digit *vd)
25312854Sgabeblack@google.com{
25412854Sgabeblack@google.com#define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM
25512854Sgabeblack@google.com#define COPY_DIGITS copy_digits_signed
25612854Sgabeblack@google.com    {  // Body of div_on_help
25712854Sgabeblack@google.com        int old_und = und;
25812854Sgabeblack@google.com
25912854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
26012854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
26112854Sgabeblack@google.com
26212854Sgabeblack@google.com        int cmp_res = vec_cmp(und, ud, vnd, vd);
26312854Sgabeblack@google.com
26412854Sgabeblack@google.com        if (cmp_res < 0) { // u < v => u / v = 0 - case 4
26512854Sgabeblack@google.com            us = SC_ZERO;
26612854Sgabeblack@google.com            vec_zero(old_und, ud);
26712854Sgabeblack@google.com            return;
26812854Sgabeblack@google.com        }
26912854Sgabeblack@google.com
27012854Sgabeblack@google.com        sc_digit vd0 = (*vd);
27112854Sgabeblack@google.com
27212854Sgabeblack@google.com        if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1)) {
27312854Sgabeblack@google.com            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
27412854Sgabeblack@google.com            return;
27512854Sgabeblack@google.com        }
27612854Sgabeblack@google.com
27712854Sgabeblack@google.com        // One extra digit for d is allocated to simplify vec_div_*().
27812854Sgabeblack@google.com        int nd = sc_max(und, vnd) + 1;
27912854Sgabeblack@google.com
28012854Sgabeblack@google.com#ifdef SC_MAX_NBITS
28112854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS + 1];
28212854Sgabeblack@google.com#else
28312854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
28412854Sgabeblack@google.com#endif
28512854Sgabeblack@google.com
28612854Sgabeblack@google.com        vec_zero(nd, d);
28712854Sgabeblack@google.com
28812854Sgabeblack@google.com        // u = v => u / v = 1 - case 3
28912854Sgabeblack@google.com        if (cmp_res == 0)
29012854Sgabeblack@google.com            d[0] = 1;
29112854Sgabeblack@google.com        else if ((vnd == 1) && (und == 1))
29212854Sgabeblack@google.com            d[0] = (*ud) / vd0;
29312854Sgabeblack@google.com        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
29412854Sgabeblack@google.com            vec_div_small(und, ud, vd0, d);
29512854Sgabeblack@google.com        else
29612854Sgabeblack@google.com            vec_div_large(und, ud, vnd, vd, d);
29712854Sgabeblack@google.com
29812854Sgabeblack@google.com        COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d);
29912854Sgabeblack@google.com
30012854Sgabeblack@google.com#ifndef SC_MAX_NBITS
30112854Sgabeblack@google.com        delete [] d;
30212854Sgabeblack@google.com#endif
30312854Sgabeblack@google.com    }
30412854Sgabeblack@google.com#undef COPY_DIGITS
30512854Sgabeblack@google.com#undef CONVERT_SM_to_2C_to_SM
30612854Sgabeblack@google.com}
30712854Sgabeblack@google.com
30812854Sgabeblack@google.com
30912854Sgabeblack@google.comvoid
31012854Sgabeblack@google.comdiv_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
31112854Sgabeblack@google.com                     int vnb, int vnd, const sc_digit *vd)
31212854Sgabeblack@google.com{
31312854Sgabeblack@google.com#define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM
31412854Sgabeblack@google.com#define COPY_DIGITS copy_digits_unsigned
31512854Sgabeblack@google.com    { // Body of div_on_help
31612854Sgabeblack@google.com        int old_und = und;
31712854Sgabeblack@google.com
31812854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
31912854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
32012854Sgabeblack@google.com
32112854Sgabeblack@google.com        int cmp_res = vec_cmp(und, ud, vnd, vd);
32212854Sgabeblack@google.com
32312854Sgabeblack@google.com        if (cmp_res < 0) { // u < v => u / v = 0 - case 4
32412854Sgabeblack@google.com            us = SC_ZERO;
32512854Sgabeblack@google.com            vec_zero(old_und, ud);
32612854Sgabeblack@google.com            return;
32712854Sgabeblack@google.com        }
32812854Sgabeblack@google.com
32912854Sgabeblack@google.com        sc_digit vd0 = (*vd);
33012854Sgabeblack@google.com
33112854Sgabeblack@google.com        if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1))  {
33212854Sgabeblack@google.com            us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud);
33312854Sgabeblack@google.com            return;
33412854Sgabeblack@google.com        }
33512854Sgabeblack@google.com
33612854Sgabeblack@google.com        // One extra digit for d is allocated to simplify vec_div_*().
33712854Sgabeblack@google.com        int nd = sc_max(und, vnd) + 1;
33812854Sgabeblack@google.com
33912854Sgabeblack@google.com#ifdef SC_MAX_NBITS
34012854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS + 1];
34112854Sgabeblack@google.com#else
34212854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
34312854Sgabeblack@google.com#endif
34412854Sgabeblack@google.com
34512854Sgabeblack@google.com        vec_zero(nd, d);
34612854Sgabeblack@google.com
34712854Sgabeblack@google.com        // u = v => u / v = 1 - case 3
34812854Sgabeblack@google.com        if (cmp_res == 0)
34912854Sgabeblack@google.com            d[0] = 1;
35012854Sgabeblack@google.com        else if ((vnd == 1) && (und == 1))
35112854Sgabeblack@google.com            d[0] = (*ud) / vd0;
35212854Sgabeblack@google.com        else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
35312854Sgabeblack@google.com            vec_div_small(und, ud, vd0, d);
35412854Sgabeblack@google.com        else
35512854Sgabeblack@google.com            vec_div_large(und, ud, vnd, vd, d);
35612854Sgabeblack@google.com
35712854Sgabeblack@google.com        COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d);
35812854Sgabeblack@google.com
35912854Sgabeblack@google.com#ifndef SC_MAX_NBITS
36012854Sgabeblack@google.com        delete [] d;
36112854Sgabeblack@google.com#endif
36212854Sgabeblack@google.com      }
36312854Sgabeblack@google.com#undef COPY_DIGITS
36412854Sgabeblack@google.com#undef CONVERT_SM_to_2C_to_SM
36512854Sgabeblack@google.com}
36612854Sgabeblack@google.com
36712854Sgabeblack@google.com
36812854Sgabeblack@google.com// ----------------------------------------------------------------------------
36912854Sgabeblack@google.com//  SECTION: External functions for MOD operators.
37012854Sgabeblack@google.com// ----------------------------------------------------------------------------
37112854Sgabeblack@google.com
37212854Sgabeblack@google.comvoid
37312854Sgabeblack@google.commod_on_help_signed(small_type &us, int unb, int und, sc_digit *ud,
37412854Sgabeblack@google.com                   int /* vnb */, int vnd, const sc_digit *vd)
37512854Sgabeblack@google.com{
37612854Sgabeblack@google.com#define COPY_DIGITS copy_digits_signed
37712854Sgabeblack@google.com    { // Body of mod_on_help
37812854Sgabeblack@google.com        int old_und = und;
37912854Sgabeblack@google.com
38012854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
38112854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
38212854Sgabeblack@google.com
38312854Sgabeblack@google.com        int cmp_res = vec_cmp(und, ud, vnd, vd);
38412854Sgabeblack@google.com
38512854Sgabeblack@google.com        // u < v => u % v = u - case 4
38612854Sgabeblack@google.com        if (cmp_res < 0)
38712854Sgabeblack@google.com            return;
38812854Sgabeblack@google.com
38912854Sgabeblack@google.com        // u = v => u % v = 0 - case 3
39012854Sgabeblack@google.com        if (cmp_res == 0) {
39112854Sgabeblack@google.com            us = SC_ZERO;
39212854Sgabeblack@google.com            vec_zero(old_und, ud);
39312854Sgabeblack@google.com            return;
39412854Sgabeblack@google.com        }
39512854Sgabeblack@google.com        // else if u > v - case 5
39612854Sgabeblack@google.com
39712854Sgabeblack@google.com        sc_digit vd0 = (*vd);
39812854Sgabeblack@google.com
39912854Sgabeblack@google.com        if ((vnd == 1) && (vd0 == 1)) {
40012854Sgabeblack@google.com            us = SC_ZERO;
40112854Sgabeblack@google.com            vec_zero(old_und, ud);
40212854Sgabeblack@google.com            return;
40312854Sgabeblack@google.com        }
40412854Sgabeblack@google.com
40512854Sgabeblack@google.com        // One extra digit for d is allocated to simplify vec_div_*().
40612854Sgabeblack@google.com        int nd = sc_max(und, vnd) + 1;
40712854Sgabeblack@google.com
40812854Sgabeblack@google.com#ifdef SC_MAX_NBITS
40912854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS + 1];
41012854Sgabeblack@google.com#else
41112854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
41212854Sgabeblack@google.com#endif
41312854Sgabeblack@google.com
41412854Sgabeblack@google.com        vec_zero(nd, d);
41512854Sgabeblack@google.com
41612854Sgabeblack@google.com        if ((vnd == 1) && (und == 1))
41712854Sgabeblack@google.com            d[0] = (*ud) % vd0;
41812854Sgabeblack@google.com        if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
41912854Sgabeblack@google.com            d[0] = vec_rem_small(und, ud, vd0);
42012854Sgabeblack@google.com        else
42112854Sgabeblack@google.com            vec_rem_large(und, ud, vnd, vd, d);
42212854Sgabeblack@google.com
42312854Sgabeblack@google.com        us = check_for_zero(us, nd - 1, d);
42412854Sgabeblack@google.com
42512854Sgabeblack@google.com        if (us == SC_ZERO)
42612854Sgabeblack@google.com            vec_zero(old_und, ud);
42712854Sgabeblack@google.com        else
42812854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d);
42912854Sgabeblack@google.com
43012854Sgabeblack@google.com#ifndef SC_MAX_NBITS
43112854Sgabeblack@google.com        delete [] d;
43212854Sgabeblack@google.com#endif
43312854Sgabeblack@google.com    }
43412854Sgabeblack@google.com#undef COPY_DIGITS
43512854Sgabeblack@google.com}
43612854Sgabeblack@google.com
43712854Sgabeblack@google.com
43812854Sgabeblack@google.comvoid
43912854Sgabeblack@google.commod_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud,
44012854Sgabeblack@google.com                     int /* vnb */, int vnd, const sc_digit *vd)
44112854Sgabeblack@google.com{
44212854Sgabeblack@google.com#define COPY_DIGITS copy_digits_unsigned
44312854Sgabeblack@google.com    { // Body of mod_on_help
44412854Sgabeblack@google.com        int old_und = und;
44512854Sgabeblack@google.com
44612854Sgabeblack@google.com        und = vec_skip_leading_zeros(und, ud);
44712854Sgabeblack@google.com        vnd = vec_skip_leading_zeros(vnd, vd);
44812854Sgabeblack@google.com
44912854Sgabeblack@google.com        int cmp_res = vec_cmp(und, ud, vnd, vd);
45012854Sgabeblack@google.com
45112854Sgabeblack@google.com        // u < v => u % v = u - case 4
45212854Sgabeblack@google.com        if (cmp_res < 0)
45312854Sgabeblack@google.com            return;
45412854Sgabeblack@google.com
45512854Sgabeblack@google.com        // u = v => u % v = 0 - case 3
45612854Sgabeblack@google.com        if (cmp_res == 0) {
45712854Sgabeblack@google.com            us = SC_ZERO;
45812854Sgabeblack@google.com            vec_zero(old_und, ud);
45912854Sgabeblack@google.com            return;
46012854Sgabeblack@google.com        }
46112854Sgabeblack@google.com
46212854Sgabeblack@google.com        // else if u > v - case 5
46312854Sgabeblack@google.com
46412854Sgabeblack@google.com        sc_digit vd0 = (*vd);
46512854Sgabeblack@google.com
46612854Sgabeblack@google.com        if ((vnd == 1) && (vd0 == 1)) {
46712854Sgabeblack@google.com            us = SC_ZERO;
46812854Sgabeblack@google.com            vec_zero(old_und, ud);
46912854Sgabeblack@google.com            return;
47012854Sgabeblack@google.com        }
47112854Sgabeblack@google.com
47212854Sgabeblack@google.com        // One extra digit for d is allocated to simplify vec_div_*().
47312854Sgabeblack@google.com        int nd = sc_max(und, vnd) + 1;
47412854Sgabeblack@google.com
47512854Sgabeblack@google.com#ifdef SC_MAX_NBITS
47612854Sgabeblack@google.com        sc_digit d[MAX_NDIGITS + 1];
47712854Sgabeblack@google.com#else
47812854Sgabeblack@google.com        sc_digit *d = new sc_digit[nd];
47912854Sgabeblack@google.com#endif
48012854Sgabeblack@google.com
48112854Sgabeblack@google.com        vec_zero(nd, d);
48212854Sgabeblack@google.com
48312854Sgabeblack@google.com        if ((vnd == 1) && (und == 1))
48412854Sgabeblack@google.com            d[0] = (*ud) % vd0;
48512854Sgabeblack@google.com        if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX))
48612854Sgabeblack@google.com            d[0] = vec_rem_small(und, ud, vd0);
48712854Sgabeblack@google.com        else
48812854Sgabeblack@google.com            vec_rem_large(und, ud, vnd, vd, d);
48912854Sgabeblack@google.com
49012854Sgabeblack@google.com        us = check_for_zero(us, nd - 1, d);
49112854Sgabeblack@google.com
49212854Sgabeblack@google.com        if (us == SC_ZERO)
49312854Sgabeblack@google.com            vec_zero(old_und, ud);
49412854Sgabeblack@google.com        else
49512854Sgabeblack@google.com            COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d);
49612854Sgabeblack@google.com
49712854Sgabeblack@google.com#ifndef SC_MAX_NBITS
49812854Sgabeblack@google.com        delete [] d;
49912854Sgabeblack@google.com#endif
50012854Sgabeblack@google.com    }
50112854Sgabeblack@google.com#undef COPY_DIGITS
50212854Sgabeblack@google.com}
50312854Sgabeblack@google.com
50412854Sgabeblack@google.com
50512854Sgabeblack@google.com// ----------------------------------------------------------------------------
50612854Sgabeblack@google.com//  SECTION: External functions for AND operators.
50712854Sgabeblack@google.com// ----------------------------------------------------------------------------
50812854Sgabeblack@google.com
50912854Sgabeblack@google.com// Handles the cases 2-5 and returns the result in u.
51012854Sgabeblack@google.comvoid
51112854Sgabeblack@google.comand_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
51212854Sgabeblack@google.com            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
51312854Sgabeblack@google.com{
51412854Sgabeblack@google.com    sc_digit *x = ud;
51512854Sgabeblack@google.com    const sc_digit *y = vd;
51612854Sgabeblack@google.com    int xnd = und;
51712854Sgabeblack@google.com    int ynd = vnd;
51812854Sgabeblack@google.com
51912854Sgabeblack@google.com    // Truncate y.
52012854Sgabeblack@google.com    if (xnd < ynd)
52112854Sgabeblack@google.com        ynd = xnd;
52212854Sgabeblack@google.com
52312854Sgabeblack@google.com    const sc_digit *xend = (x + xnd);
52412854Sgabeblack@google.com    const sc_digit *yend = (y + ynd);
52512854Sgabeblack@google.com
52612854Sgabeblack@google.com    // x is longer than y.
52712854Sgabeblack@google.com    small_type s = mul_signs(us, vs);
52812854Sgabeblack@google.com
52912854Sgabeblack@google.com    if (s > 0) {
53012854Sgabeblack@google.com        if (us > 0) { // case 2
53112854Sgabeblack@google.com            while (y < yend)
53212854Sgabeblack@google.com                (*x++) &= (*y++);
53312854Sgabeblack@google.com            while (x < xend)
53412854Sgabeblack@google.com                (*x++) = 0;
53512854Sgabeblack@google.com        } else { // case 3
53612854Sgabeblack@google.com            sc_digit xcarry = 1;
53712854Sgabeblack@google.com            sc_digit ycarry = 1;
53812854Sgabeblack@google.com            while (y < yend) {
53912854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
54012854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
54112854Sgabeblack@google.com                (*x++) = (xcarry & ycarry) & DIGIT_MASK;
54212854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
54312854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
54412854Sgabeblack@google.com            }
54512854Sgabeblack@google.com            while (x < xend) {
54612854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
54712854Sgabeblack@google.com                ycarry += DIGIT_MASK;
54812854Sgabeblack@google.com                (*x++) = (xcarry & ycarry) & DIGIT_MASK;
54912854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
55012854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
55112854Sgabeblack@google.com            }
55212854Sgabeblack@google.com
55312854Sgabeblack@google.com        }
55412854Sgabeblack@google.com    } else {
55512854Sgabeblack@google.com        if (us > 0) { // case 4
55612854Sgabeblack@google.com            sc_digit ycarry = 1;
55712854Sgabeblack@google.com            while (y < yend) {
55812854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
55912854Sgabeblack@google.com                (*x++) &= ycarry & DIGIT_MASK;
56012854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
56112854Sgabeblack@google.com            }
56212854Sgabeblack@google.com            while (x < xend) {
56312854Sgabeblack@google.com                ycarry += DIGIT_MASK;
56412854Sgabeblack@google.com                (*x++) &= ycarry & DIGIT_MASK;
56512854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
56612854Sgabeblack@google.com            }
56712854Sgabeblack@google.com        } else { // case 5
56812854Sgabeblack@google.com            sc_digit xcarry = 1;
56912854Sgabeblack@google.com            while (y < yend) {
57012854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
57112854Sgabeblack@google.com                (*x++) = (xcarry & (*y++)) & DIGIT_MASK;
57212854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
57312854Sgabeblack@google.com            }
57412854Sgabeblack@google.com            while (x < xend)
57512854Sgabeblack@google.com                (*x++) = 0;
57612854Sgabeblack@google.com        }
57712854Sgabeblack@google.com    }
57812854Sgabeblack@google.com}
57912854Sgabeblack@google.com
58012854Sgabeblack@google.com
58112854Sgabeblack@google.com// ----------------------------------------------------------------------------
58212854Sgabeblack@google.com//  SECTION: External functions for OR operators.
58312854Sgabeblack@google.com// ----------------------------------------------------------------------------
58412854Sgabeblack@google.com
58512854Sgabeblack@google.com// Handles the cases 3-5 and returns the result in u.
58612854Sgabeblack@google.comvoid
58712854Sgabeblack@google.comor_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
58812854Sgabeblack@google.com           small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
58912854Sgabeblack@google.com{
59012854Sgabeblack@google.com    sc_digit *x = ud;
59112854Sgabeblack@google.com    const sc_digit *y = vd;
59212854Sgabeblack@google.com    int xnd = und;
59312854Sgabeblack@google.com    int ynd = vnd;
59412854Sgabeblack@google.com
59512854Sgabeblack@google.com    if (xnd < ynd)
59612854Sgabeblack@google.com        ynd = xnd;
59712854Sgabeblack@google.com
59812854Sgabeblack@google.com    const sc_digit *xend = (x + xnd);
59912854Sgabeblack@google.com    const sc_digit *yend = (y + ynd);
60012854Sgabeblack@google.com
60112854Sgabeblack@google.com    // x is longer than y.
60212854Sgabeblack@google.com    small_type s = mul_signs(us, vs);
60312854Sgabeblack@google.com
60412854Sgabeblack@google.com    if (s > 0) {
60512854Sgabeblack@google.com        if (us > 0) { // case 3
60612854Sgabeblack@google.com            while (y < yend)
60712854Sgabeblack@google.com                (*x++) |= (*y++);
60812854Sgabeblack@google.com            // No change for the rest of x.
60912854Sgabeblack@google.com        } else { // case 4
61012854Sgabeblack@google.com            sc_digit xcarry = 1;
61112854Sgabeblack@google.com            sc_digit ycarry = 1;
61212854Sgabeblack@google.com            while (y < yend) {
61312854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
61412854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
61512854Sgabeblack@google.com                (*x++) = (xcarry | ycarry) & DIGIT_MASK;
61612854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
61712854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
61812854Sgabeblack@google.com            }
61912854Sgabeblack@google.com            while (x < xend) {
62012854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
62112854Sgabeblack@google.com                ycarry += DIGIT_MASK;
62212854Sgabeblack@google.com                (*x++) = (xcarry | ycarry) & DIGIT_MASK;
62312854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
62412854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
62512854Sgabeblack@google.com            }
62612854Sgabeblack@google.com        }
62712854Sgabeblack@google.com    } else {
62812854Sgabeblack@google.com        if (us > 0) { // case 5
62912854Sgabeblack@google.com            sc_digit ycarry = 1;
63012854Sgabeblack@google.com            while (y < yend) {
63112854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
63212854Sgabeblack@google.com                (*x) = ((*x) | ycarry) & DIGIT_MASK;
63312854Sgabeblack@google.com                x++;
63412854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
63512854Sgabeblack@google.com            }
63612854Sgabeblack@google.com            while (x < xend) {
63712854Sgabeblack@google.com                ycarry += DIGIT_MASK;
63812854Sgabeblack@google.com                (*x) = ((*x) | ycarry) & DIGIT_MASK;
63912854Sgabeblack@google.com                x++;
64012854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
64112854Sgabeblack@google.com            }
64212854Sgabeblack@google.com        } else { // case 6
64312854Sgabeblack@google.com            sc_digit xcarry = 1;
64412854Sgabeblack@google.com            while (y < yend) {
64512854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
64612854Sgabeblack@google.com                (*x++) = (xcarry | (*y++)) & DIGIT_MASK;
64712854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
64812854Sgabeblack@google.com            }
64912854Sgabeblack@google.com            while (x < xend) {
65012854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
65112854Sgabeblack@google.com                (*x++) = xcarry & DIGIT_MASK;
65212854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
65312854Sgabeblack@google.com            }
65412854Sgabeblack@google.com        }
65512854Sgabeblack@google.com    }
65612854Sgabeblack@google.com}
65712854Sgabeblack@google.com
65812854Sgabeblack@google.com
65912854Sgabeblack@google.com// ----------------------------------------------------------------------------
66012854Sgabeblack@google.com//  SECTION: External functions for XOR operators.
66112854Sgabeblack@google.com// ----------------------------------------------------------------------------
66212854Sgabeblack@google.com
66312854Sgabeblack@google.com// Handles the cases 3-5 and returns the result in u.
66412854Sgabeblack@google.comvoid
66512854Sgabeblack@google.comxor_on_help(small_type us, int /* unb */, int und, sc_digit *ud,
66612854Sgabeblack@google.com            small_type vs, int /* vnb */, int vnd, const sc_digit *vd)
66712854Sgabeblack@google.com{
66812854Sgabeblack@google.com    sc_digit *x = ud;
66912854Sgabeblack@google.com    const sc_digit *y = vd;
67012854Sgabeblack@google.com    int xnd = und;
67112854Sgabeblack@google.com    int ynd = vnd;
67212854Sgabeblack@google.com
67312854Sgabeblack@google.com    if (xnd < ynd)
67412854Sgabeblack@google.com        ynd = xnd;
67512854Sgabeblack@google.com
67612854Sgabeblack@google.com    const sc_digit *xend = (x + xnd);
67712854Sgabeblack@google.com    const sc_digit *yend = (y + ynd);
67812854Sgabeblack@google.com
67912854Sgabeblack@google.com    // x is longer than y.
68012854Sgabeblack@google.com    small_type s = mul_signs(us, vs);
68112854Sgabeblack@google.com
68212854Sgabeblack@google.com    if (s > 0) {
68312854Sgabeblack@google.com        if (us > 0) { // case 3
68412854Sgabeblack@google.com            while (y < yend) {
68512854Sgabeblack@google.com                (*x) = ((*x) ^ (*y)) & DIGIT_MASK;
68612854Sgabeblack@google.com                x++;
68712854Sgabeblack@google.com                y++;
68812854Sgabeblack@google.com            }
68912854Sgabeblack@google.com            // No change for the rest of x.
69012854Sgabeblack@google.com        } else { // case 4
69112854Sgabeblack@google.com            sc_digit xcarry = 1;
69212854Sgabeblack@google.com            sc_digit ycarry = 1;
69312854Sgabeblack@google.com            while (y < yend) {
69412854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
69512854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
69612854Sgabeblack@google.com                (*x++) = (xcarry ^ ycarry) & DIGIT_MASK;
69712854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
69812854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
69912854Sgabeblack@google.com            }
70012854Sgabeblack@google.com            while (x < xend) {
70112854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
70212854Sgabeblack@google.com                ycarry += DIGIT_MASK;
70312854Sgabeblack@google.com                (*x++) = (xcarry ^ ycarry) & DIGIT_MASK;
70412854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
70512854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
70612854Sgabeblack@google.com            }
70712854Sgabeblack@google.com        }
70812854Sgabeblack@google.com    } else {
70912854Sgabeblack@google.com        if (us > 0) { // case 5
71012854Sgabeblack@google.com            sc_digit ycarry = 1;
71112854Sgabeblack@google.com            while (y < yend) {
71212854Sgabeblack@google.com                ycarry += (~(*y++) & DIGIT_MASK);
71312854Sgabeblack@google.com                (*x) = ((*x) ^ ycarry) & DIGIT_MASK;
71412854Sgabeblack@google.com                x++;
71512854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
71612854Sgabeblack@google.com            }
71712854Sgabeblack@google.com            while (x < xend) {
71812854Sgabeblack@google.com                ycarry += DIGIT_MASK;
71912854Sgabeblack@google.com                (*x) = ((*x) ^ ycarry) & DIGIT_MASK;
72012854Sgabeblack@google.com                x++;
72112854Sgabeblack@google.com                ycarry >>= BITS_PER_DIGIT;
72212854Sgabeblack@google.com            }
72312854Sgabeblack@google.com        } else { // case 6
72412854Sgabeblack@google.com            sc_digit xcarry = 1;
72512854Sgabeblack@google.com            while (y < yend) {
72612854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
72712854Sgabeblack@google.com                (*x++) = (xcarry ^ (*y++)) & DIGIT_MASK;
72812854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
72912854Sgabeblack@google.com            }
73012854Sgabeblack@google.com            while (x < xend) {
73112854Sgabeblack@google.com                xcarry += (~(*x) & DIGIT_MASK);
73212854Sgabeblack@google.com                (*x++) = xcarry & DIGIT_MASK;
73312854Sgabeblack@google.com                xcarry >>= BITS_PER_DIGIT;
73412854Sgabeblack@google.com            }
73512854Sgabeblack@google.com        }
73612854Sgabeblack@google.com    }
73712854Sgabeblack@google.com}
73812854Sgabeblack@google.com
73912854Sgabeblack@google.com} // namespace sc_dt
740