sc_nbutils.cc revision 12854
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_nbutils.cpp -- External and friend functions for both sc_signed and
2312854Sgabeblack@google.com                    sc_unsigned classes.
2412854Sgabeblack@google.com
2512854Sgabeblack@google.com  Original Author: Ali Dasdan, Synopsys, Inc.
2612854Sgabeblack@google.com
2712854Sgabeblack@google.com *****************************************************************************/
2812854Sgabeblack@google.com
2912854Sgabeblack@google.com/*****************************************************************************
3012854Sgabeblack@google.com
3112854Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3212854Sgabeblack@google.com  changes you are making here.
3312854Sgabeblack@google.com
3412854Sgabeblack@google.com      Name, Affiliation, Date:
3512854Sgabeblack@google.com  Description of Modification:
3612854Sgabeblack@google.com
3712854Sgabeblack@google.com *****************************************************************************/
3812854Sgabeblack@google.com
3912854Sgabeblack@google.com
4012854Sgabeblack@google.com// $Log: sc_nbutils.cpp,v $
4112854Sgabeblack@google.com// Revision 1.4  2011/08/24 22:05:46  acg
4212854Sgabeblack@google.com//  Torsten Maehne: initialization changes to remove warnings.
4312854Sgabeblack@google.com//
4412854Sgabeblack@google.com// Revision 1.3  2011/02/18 20:19:15  acg
4512854Sgabeblack@google.com//  Andy Goodrich: updating Copyright notice.
4612854Sgabeblack@google.com//
4712854Sgabeblack@google.com// Revision 1.2  2007/11/04 21:26:40  acg
4812854Sgabeblack@google.com//  Andy Goodrich: added a buffer to the allocation of the q array to address
4912854Sgabeblack@google.com//  an issue with references outside the array by 1 byte detected by valgrind.
5012854Sgabeblack@google.com//
5112854Sgabeblack@google.com// Revision 1.1.1.1  2006/12/15 20:20:05  acg
5212854Sgabeblack@google.com// SystemC 2.3
5312854Sgabeblack@google.com//
5412854Sgabeblack@google.com// Revision 1.3  2006/01/13 18:49:32  acg
5512854Sgabeblack@google.com// Added $Log command so that CVS check in comments are reproduced in the
5612854Sgabeblack@google.com// source.
5712854Sgabeblack@google.com//
5812854Sgabeblack@google.com
5912854Sgabeblack@google.com#include <cctype>
6012854Sgabeblack@google.com#include <cstdio>
6112854Sgabeblack@google.com#include <cstring>
6212854Sgabeblack@google.com#include <sstream>
6312854Sgabeblack@google.com
6412854Sgabeblack@google.com#include "systemc/ext/dt/int/sc_nbutils.hh"
6512854Sgabeblack@google.com#include "systemc/ext/utils/functions.hh"
6612854Sgabeblack@google.com
6712854Sgabeblack@google.comnamespace sc_dt
6812854Sgabeblack@google.com{
6912854Sgabeblack@google.com
7012854Sgabeblack@google.com// only used within vec_from_str (non-standard, deprecated)
7112854Sgabeblack@google.comstatic inline void
7212854Sgabeblack@google.comis_valid_base(sc_numrep base)
7312854Sgabeblack@google.com{
7412854Sgabeblack@google.com    switch (base) {
7512854Sgabeblack@google.com      case SC_NOBASE: case SC_BIN:
7612854Sgabeblack@google.com      case SC_OCT: case SC_DEC:
7712854Sgabeblack@google.com      case SC_HEX:
7812854Sgabeblack@google.com        break;
7912854Sgabeblack@google.com      case SC_BIN_US: case SC_BIN_SM:
8012854Sgabeblack@google.com      case SC_OCT_US: case SC_OCT_SM:
8112854Sgabeblack@google.com      case SC_HEX_US: case SC_HEX_SM:
8212854Sgabeblack@google.com      case SC_CSD:
8312854Sgabeblack@google.com        SC_REPORT_ERROR("not implemented",
8412854Sgabeblack@google.com                        "is_valid_base( sc_numrep base ) : "
8512854Sgabeblack@google.com                        "bases SC_CSD, or ending in _US and _SM are "
8612854Sgabeblack@google.com                        "not supported");
8712854Sgabeblack@google.com        break;
8812854Sgabeblack@google.com      default:
8912854Sgabeblack@google.com        std::stringstream msg;
9012854Sgabeblack@google.com        msg << "is_valid_base( sc_numrep base ) : base = " << base <<
9112854Sgabeblack@google.com               " is not valid";
9212854Sgabeblack@google.com        SC_REPORT_ERROR("value is not valid", msg.str().c_str() );
9312854Sgabeblack@google.com    }
9412854Sgabeblack@google.com}
9512854Sgabeblack@google.com
9612854Sgabeblack@google.com// ----------------------------------------------------------------------------
9712854Sgabeblack@google.com//  ENUM : sc_numrep
9812854Sgabeblack@google.com//
9912854Sgabeblack@google.com//  Enumeration of number representations for character string conversion.
10012854Sgabeblack@google.com// ----------------------------------------------------------------------------
10112854Sgabeblack@google.com
10212854Sgabeblack@google.comconst std::string
10312854Sgabeblack@google.comto_string(sc_numrep numrep)
10412854Sgabeblack@google.com{
10512854Sgabeblack@google.com    switch (numrep) {
10612854Sgabeblack@google.com#define CASE_ENUM2STR(Value) case Value: return #Value
10712854Sgabeblack@google.com
10812854Sgabeblack@google.com      CASE_ENUM2STR(SC_DEC);
10912854Sgabeblack@google.com
11012854Sgabeblack@google.com      CASE_ENUM2STR(SC_BIN);
11112854Sgabeblack@google.com      CASE_ENUM2STR(SC_BIN_US);
11212854Sgabeblack@google.com      CASE_ENUM2STR(SC_BIN_SM);
11312854Sgabeblack@google.com
11412854Sgabeblack@google.com      CASE_ENUM2STR(SC_OCT);
11512854Sgabeblack@google.com      CASE_ENUM2STR(SC_OCT_US);
11612854Sgabeblack@google.com      CASE_ENUM2STR(SC_OCT_SM);
11712854Sgabeblack@google.com
11812854Sgabeblack@google.com      CASE_ENUM2STR(SC_HEX);
11912854Sgabeblack@google.com      CASE_ENUM2STR(SC_HEX_US);
12012854Sgabeblack@google.com      CASE_ENUM2STR(SC_HEX_SM);
12112854Sgabeblack@google.com
12212854Sgabeblack@google.com      CASE_ENUM2STR(SC_CSD);
12312854Sgabeblack@google.com
12412854Sgabeblack@google.com#undef CASE_ENUM2STR
12512854Sgabeblack@google.com
12612854Sgabeblack@google.com      default:
12712854Sgabeblack@google.com        return "unknown";
12812854Sgabeblack@google.com    }
12912854Sgabeblack@google.com}
13012854Sgabeblack@google.com
13112854Sgabeblack@google.com// ----------------------------------------------------------------------------
13212854Sgabeblack@google.com//  SECTION: General utility functions.
13312854Sgabeblack@google.com// ----------------------------------------------------------------------------
13412854Sgabeblack@google.com
13512854Sgabeblack@google.com// Return the number of characters to advance the source of c.  This
13612854Sgabeblack@google.com// function implements one move of the FSM to parse the following
13712854Sgabeblack@google.com// regular expressions. Error checking is done in the caller.
13812854Sgabeblack@google.com
13912854Sgabeblack@google.comsmall_type
14012854Sgabeblack@google.comfsm_move(char c, small_type &b, small_type &s, small_type &state)
14112854Sgabeblack@google.com{
14212854Sgabeblack@google.com    // Possible regular expressions (REs):
14312854Sgabeblack@google.com    // Let N = any digit depending on the base.
14412854Sgabeblack@google.com    //    1. [0|1|..|9]N*
14512854Sgabeblack@google.com    //    2. [+|-][0|1|..|9]N*
14612854Sgabeblack@google.com    //    3. 0[b|B|d|D|o|O|x|X][0|1|..|F]N*
14712854Sgabeblack@google.com    //    4. [+|-]?0[b|B|d|D|o|O|x|X][0|1|..|F]N*
14812854Sgabeblack@google.com    //
14912854Sgabeblack@google.com    // The finite state machine (FMS) to parse these regular expressions
15012854Sgabeblack@google.com    // has 4 states, 0 to 3. 0 is the initial state and 3 is the final
15112854Sgabeblack@google.com    // state.
15212854Sgabeblack@google.com    //
15312854Sgabeblack@google.com    // Default sign = SC_POS, default base = NB_DEFAULT_BASE.
15412854Sgabeblack@google.com
15512854Sgabeblack@google.com    switch (state) {
15612854Sgabeblack@google.com      case 0: // The initial state.
15712854Sgabeblack@google.com        switch (c) {
15812854Sgabeblack@google.com          case '0': s = SC_POS; state = 1; return 0; // RE 1 or 3
15912854Sgabeblack@google.com          case '+': s = SC_POS; state = 2; return 1; // RE 2
16012854Sgabeblack@google.com          case '-': s = SC_NEG; state = 2; return 1; // RE 2
16112854Sgabeblack@google.com          default:
16212854Sgabeblack@google.com            s = SC_POS; b = NB_DEFAULT_BASE; state = 3; return 0; // RE 1
16312854Sgabeblack@google.com        }
16412854Sgabeblack@google.com        // break; //unreachable code
16512854Sgabeblack@google.com      case 1: // 0...
16612854Sgabeblack@google.com        switch (c) {
16712854Sgabeblack@google.com          case 'x': case 'X': b = SC_HEX; state = 3; return 2; // RE 3 or 4
16812854Sgabeblack@google.com          case 'd': case 'D': b = SC_DEC; state = 3; return 2; // RE 3 or 4
16912854Sgabeblack@google.com          case 'o': case 'O': b = SC_OCT; state = 3; return 2; // RE 3 or 4
17012854Sgabeblack@google.com          case 'b': case 'B': b = SC_BIN; state = 3; return 2; // RE 3 or 4
17112854Sgabeblack@google.com          default: b = NB_DEFAULT_BASE; state = 3; return 0; // RE 1
17212854Sgabeblack@google.com        }
17312854Sgabeblack@google.com        // break; //unreachable code
17412854Sgabeblack@google.com      case 2: // +... or -...
17512854Sgabeblack@google.com        switch (c) {
17612854Sgabeblack@google.com          case '0': state = 1; return 0; // RE 2 or 4
17712854Sgabeblack@google.com          default: b = NB_DEFAULT_BASE; state = 3; return 0; // RE 2
17812854Sgabeblack@google.com        }
17912854Sgabeblack@google.com        // break; //unreachable code
18012854Sgabeblack@google.com      case 3: // The final state.
18112854Sgabeblack@google.com        break;
18212854Sgabeblack@google.com      default:
18312854Sgabeblack@google.com        // Any other state is not possible.
18412854Sgabeblack@google.com        sc_assert((0 <= state) && (state <= 3));
18512854Sgabeblack@google.com    } // switch
18612854Sgabeblack@google.com    return 0;
18712854Sgabeblack@google.com}
18812854Sgabeblack@google.com
18912854Sgabeblack@google.com
19012854Sgabeblack@google.com// Get base b and sign s of the number in the char string v. Return a
19112854Sgabeblack@google.com// pointer to the first char after the point where b and s are
19212854Sgabeblack@google.com// determined or where the end of v is reached. The input string v has
19312854Sgabeblack@google.com// to be null terminated.
19412854Sgabeblack@google.comconst char *
19512854Sgabeblack@google.comget_base_and_sign(const char *v, small_type &b, small_type &s)
19612854Sgabeblack@google.com{
19712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
19812854Sgabeblack@google.com    sc_assert(v != NULL);
19912854Sgabeblack@google.com#endif
20012854Sgabeblack@google.com    const small_type STATE_START = 0;
20112854Sgabeblack@google.com    const small_type STATE_FINISH = 3;
20212854Sgabeblack@google.com
20312854Sgabeblack@google.com    // Default sign = SC_POS, default base = 10.
20412854Sgabeblack@google.com    s = SC_POS;
20512854Sgabeblack@google.com    b = NB_DEFAULT_BASE;
20612854Sgabeblack@google.com
20712854Sgabeblack@google.com    small_type state = STATE_START;
20812854Sgabeblack@google.com    small_type nskip = 0; // Skip that many chars.
20912854Sgabeblack@google.com    const char *u = v;
21012854Sgabeblack@google.com
21112854Sgabeblack@google.com    while (*u) {
21212854Sgabeblack@google.com        if (isspace(*u)) { // Skip white space.
21312854Sgabeblack@google.com            ++u;
21412854Sgabeblack@google.com        } else {
21512854Sgabeblack@google.com            nskip += fsm_move(*u, b, s, state);
21612854Sgabeblack@google.com            if (state == STATE_FINISH)
21712854Sgabeblack@google.com              break;
21812854Sgabeblack@google.com            else
21912854Sgabeblack@google.com              ++u;
22012854Sgabeblack@google.com        }
22112854Sgabeblack@google.com    }
22212854Sgabeblack@google.com
22312854Sgabeblack@google.com    // Test to see if the above loop executed more than it should
22412854Sgabeblack@google.com    // have. The max number of skipped chars is equal to the length of
22512854Sgabeblack@google.com    // the longest format specifier, e.g., "-0x".
22612854Sgabeblack@google.com    sc_assert(nskip <= 3);
22712854Sgabeblack@google.com
22812854Sgabeblack@google.com    v += nskip;
22912854Sgabeblack@google.com
23012854Sgabeblack@google.com    // Handles empty strings or strings without any digits after the
23112854Sgabeblack@google.com    // base or base and sign specifier.
23212854Sgabeblack@google.com    if (*v == '\0') {
23312854Sgabeblack@google.com        static const char msg[] =
23412854Sgabeblack@google.com            "get_base_and_sign( const char* v, small_type&, small_type& ) : "
23512854Sgabeblack@google.com            "v = \"\" is not valid";
23612854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed", msg);
23712854Sgabeblack@google.com    }
23812854Sgabeblack@google.com    return v;
23912854Sgabeblack@google.com}
24012854Sgabeblack@google.com
24112854Sgabeblack@google.com//-----------------------------------------------------------------------------
24212854Sgabeblack@google.com//"parse_binary_bits"
24312854Sgabeblack@google.com//
24412854Sgabeblack@google.com// This function parses the supplied string into the supplied vector as a
24512854Sgabeblack@google.com// right justified bit value.
24612854Sgabeblack@google.com//    src_p  -> character string representing the bits to be parsed.
24712854Sgabeblack@google.com//    dst_n  =  number of words in data_p and ctrl_p.
24812854Sgabeblack@google.com//    data_p -> words w/BITS_PER_DIGIT bits to receive the value's data bits.
24912854Sgabeblack@google.com//    ctrl_p -> words w/BITS_PER_DIGIT bits to receive the value's control
25012854Sgabeblack@google.com//              bits, or zero.
25112854Sgabeblack@google.com// Result is true if value was non-zero.
25212854Sgabeblack@google.com//-----------------------------------------------------------------------------
25312854Sgabeblack@google.comvoid
25412854Sgabeblack@google.comparse_binary_bits(const char *src_p, int dst_n,
25512854Sgabeblack@google.com                  sc_digit *data_p, sc_digit *ctrl_p)
25612854Sgabeblack@google.com{
25712854Sgabeblack@google.com    int bit_i; // Number of bit now processing.
25812854Sgabeblack@google.com    sc_digit ctrl; // Control word now assembling.
25912854Sgabeblack@google.com    sc_digit data; // Data word now assembling.
26012854Sgabeblack@google.com    int delta_n; // src_n - dst_n*BITS_PER_DIGIT.
26112854Sgabeblack@google.com    int src_i; // Index in src_p now accessing (left to right).
26212854Sgabeblack@google.com    int src_n; // Length of source that is left in bits.
26312854Sgabeblack@google.com    int word_i; // Bit within word now accessing (left to right).
26412854Sgabeblack@google.com
26512854Sgabeblack@google.com    // MAKE SURE WE HAVE A STRING TO PARSE:
26612854Sgabeblack@google.com    if (src_p == 0) {
26712854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed",
26812854Sgabeblack@google.com                        "character string is zero");
26912854Sgabeblack@google.com        return;
27012854Sgabeblack@google.com    }
27112854Sgabeblack@google.com    if (*src_p == 0) {
27212854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed",
27312854Sgabeblack@google.com                        "character string is empty");
27412854Sgabeblack@google.com        return;
27512854Sgabeblack@google.com    }
27612854Sgabeblack@google.com
27712854Sgabeblack@google.com
27812854Sgabeblack@google.com    // INDEX INTO THE SOURCE TO A DEPTH THAT WILL ACCOMODATE OUR SIZE:
27912854Sgabeblack@google.com    //
28012854Sgabeblack@google.com    // If the source is smaller than our value initialize our value to zero.
28112854Sgabeblack@google.com
28212854Sgabeblack@google.com    src_n = strlen(src_p);
28312854Sgabeblack@google.com    delta_n = src_n - (dst_n*BITS_PER_DIGIT);
28412854Sgabeblack@google.com    if (delta_n > 0) {
28512854Sgabeblack@google.com        src_p = &src_p[delta_n];
28612854Sgabeblack@google.com        src_n -= delta_n;
28712854Sgabeblack@google.com    } else {
28812854Sgabeblack@google.com        for (word_i = 0; word_i < dst_n; word_i++)
28912854Sgabeblack@google.com            data_p[word_i] = 0;
29012854Sgabeblack@google.com        if (ctrl_p)
29112854Sgabeblack@google.com            for (word_i = 0; word_i < dst_n; word_i++)
29212854Sgabeblack@google.com                ctrl_p[word_i] = 0;
29312854Sgabeblack@google.com    }
29412854Sgabeblack@google.com
29512854Sgabeblack@google.com    // LOOP OVER THE SOURCE ASSEMBLING WORDS AND PLACING THEM IN OUR VALUE:
29612854Sgabeblack@google.com    //
29712854Sgabeblack@google.com    // We stride right to left through the source in BITS_PER_DIGIT chunks.
29812854Sgabeblack@google.com    // Each of those chunks is processed from left to right a bit at a time.
29912854Sgabeblack@google.com    // We process the high order word specially, since there are less bits.
30012854Sgabeblack@google.com    src_n = src_n - BITS_PER_DIGIT;
30112854Sgabeblack@google.com    for (word_i=0; word_i < dst_n; word_i++) {
30212854Sgabeblack@google.com        src_i = src_n;
30312854Sgabeblack@google.com
30412854Sgabeblack@google.com        // PARTIAL LAST WORD TO ASSEMBLE:
30512854Sgabeblack@google.com        if (src_i < 0) {
30612854Sgabeblack@google.com            src_n += BITS_PER_DIGIT;
30712854Sgabeblack@google.com            data = 0;
30812854Sgabeblack@google.com            ctrl = 0;
30912854Sgabeblack@google.com            for (src_i = 0; src_i < src_n; src_i++) {
31012854Sgabeblack@google.com                ctrl = ctrl << 1;
31112854Sgabeblack@google.com                data = data << 1;
31212854Sgabeblack@google.com                switch (src_p[src_i]) {
31312854Sgabeblack@google.com                  case 'X':
31412854Sgabeblack@google.com                  case 'x': ctrl = ctrl | 1; data = data | 1; break;
31512854Sgabeblack@google.com                  case '1': data = data | 1; break;
31612854Sgabeblack@google.com                  case 'Z':
31712854Sgabeblack@google.com                  case 'z': ctrl = ctrl | 1; break;
31812854Sgabeblack@google.com                  case '0': break;
31912854Sgabeblack@google.com                  default:
32012854Sgabeblack@google.com                    {
32112854Sgabeblack@google.com                        std::stringstream msg;
32212854Sgabeblack@google.com                        msg << "character string '" << src_p <<
32312854Sgabeblack@google.com                               "' is not valid";
32412854Sgabeblack@google.com                        SC_REPORT_ERROR("conversion failed",
32512854Sgabeblack@google.com                                        msg.str().c_str());
32612854Sgabeblack@google.com                        return;
32712854Sgabeblack@google.com                    }
32812854Sgabeblack@google.com                    break;
32912854Sgabeblack@google.com                }
33012854Sgabeblack@google.com            }
33112854Sgabeblack@google.com            if (ctrl_p)
33212854Sgabeblack@google.com                ctrl_p[word_i] = ctrl;
33312854Sgabeblack@google.com            data_p[word_i] = data;
33412854Sgabeblack@google.com            break;
33512854Sgabeblack@google.com        }
33612854Sgabeblack@google.com
33712854Sgabeblack@google.com        // FULL WORD TO BE ASSEMBLED:
33812854Sgabeblack@google.com        ctrl = 0;
33912854Sgabeblack@google.com        data = 0;
34012854Sgabeblack@google.com        for (bit_i = 0; bit_i < BITS_PER_DIGIT; bit_i++) {
34112854Sgabeblack@google.com            ctrl = ctrl << 1;
34212854Sgabeblack@google.com            data = data << 1;
34312854Sgabeblack@google.com            switch (src_p[src_i++]) {
34412854Sgabeblack@google.com              case 'X':
34512854Sgabeblack@google.com              case 'x': ctrl = ctrl | 1; data = data | 1; break;
34612854Sgabeblack@google.com              case '1': data = data | 1; break;
34712854Sgabeblack@google.com              case 'Z':
34812854Sgabeblack@google.com              case 'z': ctrl = ctrl | 1; break;
34912854Sgabeblack@google.com              case '0': break;
35012854Sgabeblack@google.com              default:
35112854Sgabeblack@google.com                {
35212854Sgabeblack@google.com                    std::stringstream msg;
35312854Sgabeblack@google.com                    msg << "character string '" << src_p <<
35412854Sgabeblack@google.com                           "' is not valid";
35512854Sgabeblack@google.com                    SC_REPORT_ERROR("conversion failed",
35612854Sgabeblack@google.com                                    msg.str().c_str());
35712854Sgabeblack@google.com                    return;
35812854Sgabeblack@google.com                }
35912854Sgabeblack@google.com                break;
36012854Sgabeblack@google.com            }
36112854Sgabeblack@google.com        }
36212854Sgabeblack@google.com        if (ctrl_p)
36312854Sgabeblack@google.com            ctrl_p[word_i] = ctrl;
36412854Sgabeblack@google.com        data_p[word_i] = data;
36512854Sgabeblack@google.com        src_n = src_n - BITS_PER_DIGIT;
36612854Sgabeblack@google.com    }
36712854Sgabeblack@google.com}
36812854Sgabeblack@google.com
36912854Sgabeblack@google.com
37012854Sgabeblack@google.com//-----------------------------------------------------------------------------
37112854Sgabeblack@google.com//"parse_hex_bits"
37212854Sgabeblack@google.com//
37312854Sgabeblack@google.com// This function parses the supplied string into the supplied vector as a
37412854Sgabeblack@google.com// right justified bit value.
37512854Sgabeblack@google.com//    src_p  -> character string representing the bits to be parsed.
37612854Sgabeblack@google.com//    dst_n  =  number of words in data_p and ctrl_p.
37712854Sgabeblack@google.com//    data_p -> words w/32 bits to receive the value's data bits.
37812854Sgabeblack@google.com//    ctrl_p -> words w/32 bits to receive the value's control bits,
37912854Sgabeblack@google.com//              or zero.
38012854Sgabeblack@google.com// Result is true if value was non-zero.
38112854Sgabeblack@google.com//-----------------------------------------------------------------------------
38212854Sgabeblack@google.comvoid
38312854Sgabeblack@google.comparse_hex_bits(const char *src_p, int dst_n,
38412854Sgabeblack@google.com               sc_digit *data_p, sc_digit *ctrl_p)
38512854Sgabeblack@google.com{
38612854Sgabeblack@google.com    sc_digit ctrl; // Control word now assembling.
38712854Sgabeblack@google.com    sc_digit data; // Data word now assembling.
38812854Sgabeblack@google.com    int delta_n; // src_n - dst_n*BITS_PER_DIGIT.
38912854Sgabeblack@google.com    int digit_i; // Number of digit now processing.
39012854Sgabeblack@google.com    int src_i; // Index in src_p now accessing (left to right).
39112854Sgabeblack@google.com    int src_n; // Length of source that is left in bits.
39212854Sgabeblack@google.com    int word_i; // Bit within word now accessing (left to right).
39312854Sgabeblack@google.com
39412854Sgabeblack@google.com    // MAKE SURE WE HAVE A STRING TO PARSE:
39512854Sgabeblack@google.com    if (src_p == 0) {
39612854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed",
39712854Sgabeblack@google.com                        "character string is zero");
39812854Sgabeblack@google.com        return;
39912854Sgabeblack@google.com    }
40012854Sgabeblack@google.com    if (*src_p == 0) {
40112854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed",
40212854Sgabeblack@google.com                        "character string is empty");
40312854Sgabeblack@google.com        return;
40412854Sgabeblack@google.com    }
40512854Sgabeblack@google.com
40612854Sgabeblack@google.com    // INDEX INTO THE SOURCE TO A DEPTH THAT WILL ACCOMODATE OUR SIZE:
40712854Sgabeblack@google.com    //
40812854Sgabeblack@google.com    // If the source is smaller than our value initialize our value to zero.
40912854Sgabeblack@google.com    src_n = strlen(src_p);
41012854Sgabeblack@google.com    delta_n = src_n - (dst_n*8);
41112854Sgabeblack@google.com    if (delta_n > 0) {
41212854Sgabeblack@google.com        src_p = &src_p[delta_n];
41312854Sgabeblack@google.com        src_n -= delta_n;
41412854Sgabeblack@google.com    } else {
41512854Sgabeblack@google.com        for (word_i = 0; word_i < dst_n; word_i++)
41612854Sgabeblack@google.com            data_p[word_i] = 0;
41712854Sgabeblack@google.com        if (ctrl_p)
41812854Sgabeblack@google.com            for (word_i = 0; word_i < dst_n; word_i++)
41912854Sgabeblack@google.com                ctrl_p[word_i] = 0;
42012854Sgabeblack@google.com    }
42112854Sgabeblack@google.com
42212854Sgabeblack@google.com    // LOOP OVER THE SOURCE ASSEMBLING WORDS AND PLACING THEM IN OUR VALUE:
42312854Sgabeblack@google.com    //
42412854Sgabeblack@google.com    // We stride right to left through the source in BITS_PER_DIGIT chunks.
42512854Sgabeblack@google.com    // Each of those chunks is processed from left to right a bit at a time.
42612854Sgabeblack@google.com    // We process the high order word specially, since there are less bits.
42712854Sgabeblack@google.com    src_n = src_n - 8;
42812854Sgabeblack@google.com    for (word_i = 0; word_i < dst_n; word_i++) {
42912854Sgabeblack@google.com        src_i = src_n;
43012854Sgabeblack@google.com
43112854Sgabeblack@google.com        // PARTIAL LAST WORD TO ASSEMBLE:
43212854Sgabeblack@google.com        if (src_i < 0) {
43312854Sgabeblack@google.com            src_n += 8;
43412854Sgabeblack@google.com            data = 0;
43512854Sgabeblack@google.com            ctrl = 0;
43612854Sgabeblack@google.com            for (src_i = 0; src_i < src_n; src_i++) {
43712854Sgabeblack@google.com                ctrl = ctrl << 4;
43812854Sgabeblack@google.com                data = data << 4;
43912854Sgabeblack@google.com                switch (src_p[src_i]) {
44012854Sgabeblack@google.com                  case 'X':
44112854Sgabeblack@google.com                  case 'x': ctrl = ctrl | 15; data = data | 15; break;
44212854Sgabeblack@google.com                  case 'F':
44312854Sgabeblack@google.com                  case 'f': data = data | 15; break;
44412854Sgabeblack@google.com                  case 'E':
44512854Sgabeblack@google.com                  case 'e': data = data | 14; break;
44612854Sgabeblack@google.com                  case 'D':
44712854Sgabeblack@google.com                  case 'd': data = data | 13; break;
44812854Sgabeblack@google.com                  case 'C':
44912854Sgabeblack@google.com                  case 'c': data = data | 12; break;
45012854Sgabeblack@google.com                  case 'B':
45112854Sgabeblack@google.com                  case 'b': data = data | 11; break;
45212854Sgabeblack@google.com                  case 'A':
45312854Sgabeblack@google.com                  case 'a': data = data | 10; break;
45412854Sgabeblack@google.com                  case '9': data = data |  9; break;
45512854Sgabeblack@google.com                  case '8': data = data |  8; break;
45612854Sgabeblack@google.com                  case '7': data = data |  7; break;
45712854Sgabeblack@google.com                  case '6': data = data |  6; break;
45812854Sgabeblack@google.com                  case '5': data = data |  5; break;
45912854Sgabeblack@google.com                  case '4': data = data |  4; break;
46012854Sgabeblack@google.com                  case '3': data = data |  3; break;
46112854Sgabeblack@google.com                  case '2': data = data |  2; break;
46212854Sgabeblack@google.com                  case '1': data = data |  1; break;
46312854Sgabeblack@google.com                  case '0': break;
46412854Sgabeblack@google.com                  case 'Z':
46512854Sgabeblack@google.com                  case 'z': ctrl = ctrl | 15; break;
46612854Sgabeblack@google.com                  default:
46712854Sgabeblack@google.com                    {
46812854Sgabeblack@google.com                        std::stringstream msg;
46912854Sgabeblack@google.com                        msg << "character string '" << src_p <<
47012854Sgabeblack@google.com                               "' is not valid";
47112854Sgabeblack@google.com                        SC_REPORT_ERROR("conversion failed",
47212854Sgabeblack@google.com                                        msg.str().c_str());
47312854Sgabeblack@google.com                        return;
47412854Sgabeblack@google.com                    }
47512854Sgabeblack@google.com                    break;
47612854Sgabeblack@google.com                }
47712854Sgabeblack@google.com            }
47812854Sgabeblack@google.com            if (ctrl_p)
47912854Sgabeblack@google.com                ctrl_p[word_i] = ctrl;
48012854Sgabeblack@google.com            data_p[word_i] = data;
48112854Sgabeblack@google.com            break;
48212854Sgabeblack@google.com        }
48312854Sgabeblack@google.com
48412854Sgabeblack@google.com        // FULL WORD TO BE ASSEMBLED:
48512854Sgabeblack@google.com        ctrl = 0;
48612854Sgabeblack@google.com        data = 0;
48712854Sgabeblack@google.com        for (digit_i = 0; digit_i < 8; digit_i++) {
48812854Sgabeblack@google.com            ctrl = ctrl << 4;
48912854Sgabeblack@google.com            data = data << 4;
49012854Sgabeblack@google.com            switch (src_p[src_i++]) {
49112854Sgabeblack@google.com              case 'X':
49212854Sgabeblack@google.com              case 'x': ctrl = ctrl | 15; data = data | 15; break;
49312854Sgabeblack@google.com              case 'F':
49412854Sgabeblack@google.com              case 'f': data = data | 15; break;
49512854Sgabeblack@google.com              case 'E':
49612854Sgabeblack@google.com              case 'e': data = data | 14; break;
49712854Sgabeblack@google.com              case 'D':
49812854Sgabeblack@google.com              case 'd': data = data | 13; break;
49912854Sgabeblack@google.com              case 'C':
50012854Sgabeblack@google.com              case 'c': data = data | 12; break;
50112854Sgabeblack@google.com              case 'B':
50212854Sgabeblack@google.com              case 'b': data = data | 11; break;
50312854Sgabeblack@google.com              case 'A':
50412854Sgabeblack@google.com              case 'a': data = data | 10; break;
50512854Sgabeblack@google.com              case '9': data = data |  9; break;
50612854Sgabeblack@google.com              case '8': data = data |  8; break;
50712854Sgabeblack@google.com              case '7': data = data |  7; break;
50812854Sgabeblack@google.com              case '6': data = data |  6; break;
50912854Sgabeblack@google.com              case '5': data = data |  5; break;
51012854Sgabeblack@google.com              case '4': data = data |  4; break;
51112854Sgabeblack@google.com              case '3': data = data |  3; break;
51212854Sgabeblack@google.com              case '2': data = data |  2; break;
51312854Sgabeblack@google.com              case '1': data = data |  1; break;
51412854Sgabeblack@google.com              case '0': break;
51512854Sgabeblack@google.com              case 'Z':
51612854Sgabeblack@google.com              case 'z': ctrl = ctrl | 15; break;
51712854Sgabeblack@google.com              default:
51812854Sgabeblack@google.com                {
51912854Sgabeblack@google.com                    std::stringstream msg;
52012854Sgabeblack@google.com                    msg << "character string '" << src_p << "' is not valid";
52112854Sgabeblack@google.com                    SC_REPORT_ERROR("conversion failed",
52212854Sgabeblack@google.com                                    msg.str().c_str() );
52312854Sgabeblack@google.com                    return;
52412854Sgabeblack@google.com                }
52512854Sgabeblack@google.com                break;
52612854Sgabeblack@google.com            }
52712854Sgabeblack@google.com        }
52812854Sgabeblack@google.com        if (ctrl_p)
52912854Sgabeblack@google.com            ctrl_p[word_i] = ctrl;
53012854Sgabeblack@google.com        data_p[word_i] = data;
53112854Sgabeblack@google.com        src_n = src_n - BITS_PER_DIGIT;
53212854Sgabeblack@google.com    }
53312854Sgabeblack@google.com}
53412854Sgabeblack@google.com
53512854Sgabeblack@google.com
53612854Sgabeblack@google.com// ----------------------------------------------------------------------------
53712854Sgabeblack@google.com//  SECTION: Utility functions involving unsigned vectors.
53812854Sgabeblack@google.com// ----------------------------------------------------------------------------
53912854Sgabeblack@google.com
54012854Sgabeblack@google.com// Read u from a null terminated char string v. Note that operator>>
54112854Sgabeblack@google.com// in sc_nbcommon.cpp is similar to this function.
54212854Sgabeblack@google.comsmall_type
54312854Sgabeblack@google.comvec_from_str(int unb, int und, sc_digit *u, const char *v, sc_numrep base)
54412854Sgabeblack@google.com{
54512854Sgabeblack@google.com
54612854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
54712854Sgabeblack@google.com    sc_assert((unb > 0) && (und > 0) && (u != NULL));
54812854Sgabeblack@google.com    sc_assert(v != NULL);
54912854Sgabeblack@google.com#endif
55012854Sgabeblack@google.com    is_valid_base(base);
55112854Sgabeblack@google.com
55212854Sgabeblack@google.com    small_type b, s; // base and sign.
55312854Sgabeblack@google.com
55412854Sgabeblack@google.com    v = get_base_and_sign(v, b, s);
55512854Sgabeblack@google.com
55612854Sgabeblack@google.com    if (base != SC_NOBASE) {
55712854Sgabeblack@google.com        if (b == NB_DEFAULT_BASE) {
55812854Sgabeblack@google.com            b = base;
55912854Sgabeblack@google.com        } else {
56012854Sgabeblack@google.com            std::stringstream msg;
56112854Sgabeblack@google.com            msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
56212854Sgabeblack@google.com                   "sc_numrep base ) : base = " << base <<
56312854Sgabeblack@google.com                   " does not match the default base";
56412854Sgabeblack@google.com            SC_REPORT_ERROR("conversion failed",
56512854Sgabeblack@google.com                            msg.str().c_str());
56612854Sgabeblack@google.com            return 0;
56712854Sgabeblack@google.com        }
56812854Sgabeblack@google.com    }
56912854Sgabeblack@google.com
57012854Sgabeblack@google.com    vec_zero(und, u);
57112854Sgabeblack@google.com
57212854Sgabeblack@google.com    char c;
57312854Sgabeblack@google.com    for (; (c = *v); ++v) {
57412854Sgabeblack@google.com        if (isalnum(c)) {
57512854Sgabeblack@google.com            small_type val;  // Numeric value of a char.
57612854Sgabeblack@google.com
57712854Sgabeblack@google.com            if (isalpha(c)) // Hex digit.
57812854Sgabeblack@google.com                val = toupper(c) - 'A' + 10;
57912854Sgabeblack@google.com            else
58012854Sgabeblack@google.com                val = c - '0';
58112854Sgabeblack@google.com
58212854Sgabeblack@google.com            if (val >= b) {
58312854Sgabeblack@google.com                std::stringstream msg;
58412854Sgabeblack@google.com                msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
58512854Sgabeblack@google.com                       "sc_numrep base ) : '" << *v << "' is not a valid " <<
58612854Sgabeblack@google.com                       "digit in base " << b;
58712854Sgabeblack@google.com                SC_REPORT_ERROR("conversion failed",
58812854Sgabeblack@google.com                                msg.str().c_str());
58912854Sgabeblack@google.com                return 0;
59012854Sgabeblack@google.com            }
59112854Sgabeblack@google.com
59212854Sgabeblack@google.com            // digit = digit * b + val;
59312854Sgabeblack@google.com            vec_mul_small_on(und, u, b);
59412854Sgabeblack@google.com
59512854Sgabeblack@google.com            if (val)
59612854Sgabeblack@google.com                vec_add_small_on(und, u, val);
59712854Sgabeblack@google.com        } else {
59812854Sgabeblack@google.com            std::stringstream msg;
59912854Sgabeblack@google.com            msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
60012854Sgabeblack@google.com                   "sc_numrep base ) : '" << *v << "' is not a valid " <<
60112854Sgabeblack@google.com                   "digit in base " << b;
60212854Sgabeblack@google.com            SC_REPORT_ERROR("conversion failed",
60312854Sgabeblack@google.com                            msg.str().c_str());
60412854Sgabeblack@google.com            return 0;
60512854Sgabeblack@google.com        }
60612854Sgabeblack@google.com    }
60712854Sgabeblack@google.com
60812854Sgabeblack@google.com    return convert_signed_SM_to_2C_to_SM(s, unb, und, u);
60912854Sgabeblack@google.com}
61012854Sgabeblack@google.com
61112854Sgabeblack@google.com
61212854Sgabeblack@google.com// All vec_ functions assume that the vector to hold the result,
61312854Sgabeblack@google.com// called w, has sufficient length to hold the result. For efficiency
61412854Sgabeblack@google.com// reasons, we do not test whether or not we are out of bounds.
61512854Sgabeblack@google.com
61612854Sgabeblack@google.com// Compute w = u + v, where w, u, and v are vectors.
61712854Sgabeblack@google.com// - ulen >= vlen
61812854Sgabeblack@google.com// - wlen >= sc_max(ulen, vlen) + 1
61912854Sgabeblack@google.comvoid
62012854Sgabeblack@google.comvec_add(int ulen, const sc_digit *u, int vlen, const sc_digit *v, sc_digit *w)
62112854Sgabeblack@google.com{
62212854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
62312854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
62412854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
62512854Sgabeblack@google.com    sc_assert(w != NULL);
62612854Sgabeblack@google.com    sc_assert(ulen >= vlen);
62712854Sgabeblack@google.com#endif
62812854Sgabeblack@google.com
62912854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
63012854Sgabeblack@google.com    const sc_digit *vend = (v + vlen);
63112854Sgabeblack@google.com
63212854Sgabeblack@google.com    sc_digit carry = 0; // Also used as sum to save space.
63312854Sgabeblack@google.com
63412854Sgabeblack@google.com    // Add along the shorter v.
63512854Sgabeblack@google.com    while (v < vend) {
63612854Sgabeblack@google.com        carry += (*u++) + (*v++);
63712854Sgabeblack@google.com        (*w++) = carry & DIGIT_MASK;
63812854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
63912854Sgabeblack@google.com    }
64012854Sgabeblack@google.com
64112854Sgabeblack@google.com    // Propagate the carry.
64212854Sgabeblack@google.com    while (carry && (u < uend)) {
64312854Sgabeblack@google.com        carry = (*u++) + 1;
64412854Sgabeblack@google.com        (*w++) = carry & DIGIT_MASK;
64512854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
64612854Sgabeblack@google.com    }
64712854Sgabeblack@google.com
64812854Sgabeblack@google.com    // Copy the rest of u to the result.
64912854Sgabeblack@google.com    while (u < uend)
65012854Sgabeblack@google.com        (*w++) = (*u++);
65112854Sgabeblack@google.com
65212854Sgabeblack@google.com    // Propagate the carry if it is still 1.
65312854Sgabeblack@google.com    if (carry)
65412854Sgabeblack@google.com        (*w) = 1;
65512854Sgabeblack@google.com}
65612854Sgabeblack@google.com
65712854Sgabeblack@google.com
65812854Sgabeblack@google.com// Compute u += v, where u and v are vectors.
65912854Sgabeblack@google.com// - ulen >= vlen
66012854Sgabeblack@google.comvoid
66112854Sgabeblack@google.comvec_add_on(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
66212854Sgabeblack@google.com{
66312854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
66412854Sgabeblack@google.com    sc_assert((ulen > 0) && (ubegin != NULL));
66512854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
66612854Sgabeblack@google.com    sc_assert(ulen >= vlen);
66712854Sgabeblack@google.com#endif
66812854Sgabeblack@google.com
66912854Sgabeblack@google.com    sc_digit *u = ubegin;
67012854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
67112854Sgabeblack@google.com    const sc_digit *vend = (v + vlen);
67212854Sgabeblack@google.com
67312854Sgabeblack@google.com    sc_digit carry = 0; // Also used as sum to save space.
67412854Sgabeblack@google.com
67512854Sgabeblack@google.com    // Add along the shorter v.
67612854Sgabeblack@google.com    while (v < vend) {
67712854Sgabeblack@google.com        carry += (*u) + (*v++);
67812854Sgabeblack@google.com        (*u++) = carry & DIGIT_MASK;
67912854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
68012854Sgabeblack@google.com    }
68112854Sgabeblack@google.com
68212854Sgabeblack@google.com    // Propagate the carry.
68312854Sgabeblack@google.com    while (carry && (u < uend)) {
68412854Sgabeblack@google.com        carry = (*u) + 1;
68512854Sgabeblack@google.com        (*u++) = carry & DIGIT_MASK;
68612854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
68712854Sgabeblack@google.com    }
68812854Sgabeblack@google.com
68912854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
69012854Sgabeblack@google.com    if (carry != 0) {
69112854Sgabeblack@google.com        SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
69212854Sgabeblack@google.com                          "vec_add_on( int, sc_digit*, int, const "
69312854Sgabeblack@google.com                          "sc_digit* ) : "
69412854Sgabeblack@google.com                          "result of addition is wrapped around");
69512854Sgabeblack@google.com    }
69612854Sgabeblack@google.com#endif
69712854Sgabeblack@google.com}
69812854Sgabeblack@google.com
69912854Sgabeblack@google.com
70012854Sgabeblack@google.com// Compute u += v, where u and v are vectors.
70112854Sgabeblack@google.com// - ulen < vlen
70212854Sgabeblack@google.comvoid
70312854Sgabeblack@google.comvec_add_on2(int ulen, sc_digit *ubegin, int,
70412854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
70512854Sgabeblack@google.com            vlen,
70612854Sgabeblack@google.com#endif
70712854Sgabeblack@google.com            const sc_digit *v)
70812854Sgabeblack@google.com{
70912854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
71012854Sgabeblack@google.com    sc_assert((ulen > 0) && (ubegin != NULL));
71112854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
71212854Sgabeblack@google.com    sc_assert(ulen < vlen);
71312854Sgabeblack@google.com#endif
71412854Sgabeblack@google.com
71512854Sgabeblack@google.com    sc_digit *u = ubegin;
71612854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
71712854Sgabeblack@google.com
71812854Sgabeblack@google.com    sc_digit carry = 0; // Also used as sum to save space.
71912854Sgabeblack@google.com
72012854Sgabeblack@google.com    // Add along the shorter u.
72112854Sgabeblack@google.com    while (u < uend) {
72212854Sgabeblack@google.com        carry += (*u) + (*v++);
72312854Sgabeblack@google.com        (*u++) = carry & DIGIT_MASK;
72412854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
72512854Sgabeblack@google.com    }
72612854Sgabeblack@google.com
72712854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
72812854Sgabeblack@google.com    if (carry != 0) {
72912854Sgabeblack@google.com        SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
73012854Sgabeblack@google.com                          "vec_add_on2( int, sc_digit*, int, const "
73112854Sgabeblack@google.com                          "sc_digit* ) : "
73212854Sgabeblack@google.com                          "result of addition is wrapped around");
73312854Sgabeblack@google.com    }
73412854Sgabeblack@google.com#endif
73512854Sgabeblack@google.com}
73612854Sgabeblack@google.com
73712854Sgabeblack@google.com
73812854Sgabeblack@google.com// Compute w = u + v, where w and u are vectors, and v is a scalar.
73912854Sgabeblack@google.comvoid
74012854Sgabeblack@google.comvec_add_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
74112854Sgabeblack@google.com{
74212854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
74312854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
74412854Sgabeblack@google.com    sc_assert(w != NULL);
74512854Sgabeblack@google.com#endif
74612854Sgabeblack@google.com
74712854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
74812854Sgabeblack@google.com
74912854Sgabeblack@google.com    // Add along the shorter v.
75012854Sgabeblack@google.com    sc_digit carry = (*u++) + v;
75112854Sgabeblack@google.com    (*w++) = carry & DIGIT_MASK;
75212854Sgabeblack@google.com    carry >>= BITS_PER_DIGIT;
75312854Sgabeblack@google.com
75412854Sgabeblack@google.com    // Propagate the carry.
75512854Sgabeblack@google.com    while (carry && (u < uend)) {
75612854Sgabeblack@google.com        carry = (*u++) + 1;
75712854Sgabeblack@google.com        (*w++) = carry & DIGIT_MASK;
75812854Sgabeblack@google.com        carry >>= BITS_PER_DIGIT;
75912854Sgabeblack@google.com    }
76012854Sgabeblack@google.com
76112854Sgabeblack@google.com    // Copy the rest of u to the result.
76212854Sgabeblack@google.com    while (u < uend)
76312854Sgabeblack@google.com        (*w++) = (*u++);
76412854Sgabeblack@google.com
76512854Sgabeblack@google.com    // Propagate the carry if it is still 1.
76612854Sgabeblack@google.com    if (carry)
76712854Sgabeblack@google.com        (*w) = 1;
76812854Sgabeblack@google.com}
76912854Sgabeblack@google.com
77012854Sgabeblack@google.com// Compute u += v, where u is vectors, and v is a scalar.
77112854Sgabeblack@google.comvoid
77212854Sgabeblack@google.comvec_add_small_on(int ulen, sc_digit *u, sc_digit v)
77312854Sgabeblack@google.com{
77412854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
77512854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
77612854Sgabeblack@google.com#endif
77712854Sgabeblack@google.com
77812854Sgabeblack@google.com    int i = 0;
77912854Sgabeblack@google.com
78012854Sgabeblack@google.com    while (v && (i < ulen)) {
78112854Sgabeblack@google.com        v += u[i];
78212854Sgabeblack@google.com        u[i++] = v & DIGIT_MASK;
78312854Sgabeblack@google.com        v >>= BITS_PER_DIGIT;
78412854Sgabeblack@google.com    }
78512854Sgabeblack@google.com
78612854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
78712854Sgabeblack@google.com    if (v != 0) {
78812854Sgabeblack@google.com        SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
78912854Sgabeblack@google.com                          "vec_add_small_on( int, sc_digit*, unsigned "
79012854Sgabeblack@google.com                          "long ) : "
79112854Sgabeblack@google.com                          "result of addition is wrapped around");
79212854Sgabeblack@google.com    }
79312854Sgabeblack@google.com#endif
79412854Sgabeblack@google.com}
79512854Sgabeblack@google.com
79612854Sgabeblack@google.com// Compute w = u - v, where w, u, and v are vectors.
79712854Sgabeblack@google.com// - ulen >= vlen
79812854Sgabeblack@google.com// - wlen >= sc_max(ulen, vlen)
79912854Sgabeblack@google.comvoid
80012854Sgabeblack@google.comvec_sub(int ulen, const sc_digit *u, int vlen, const sc_digit *v, sc_digit *w)
80112854Sgabeblack@google.com{
80212854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
80312854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
80412854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
80512854Sgabeblack@google.com    sc_assert(w != NULL);
80612854Sgabeblack@google.com    sc_assert(ulen >= vlen);
80712854Sgabeblack@google.com#endif
80812854Sgabeblack@google.com
80912854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
81012854Sgabeblack@google.com    const sc_digit *vend = (v + vlen);
81112854Sgabeblack@google.com
81212854Sgabeblack@google.com    sc_digit borrow = 0; // Also used as diff to save space.
81312854Sgabeblack@google.com
81412854Sgabeblack@google.com    // Subtract along the shorter v.
81512854Sgabeblack@google.com    while (v < vend) {
81612854Sgabeblack@google.com        borrow = ((*u++) + DIGIT_RADIX) - (*v++) - borrow;
81712854Sgabeblack@google.com        (*w++) = borrow & DIGIT_MASK;
81812854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
81912854Sgabeblack@google.com    }
82012854Sgabeblack@google.com
82112854Sgabeblack@google.com    // Propagate the borrow.
82212854Sgabeblack@google.com    while (borrow && (u < uend)) {
82312854Sgabeblack@google.com        borrow = ((*u++) + DIGIT_RADIX) - 1;
82412854Sgabeblack@google.com        (*w++) = borrow & DIGIT_MASK;
82512854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
82612854Sgabeblack@google.com    }
82712854Sgabeblack@google.com
82812854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
82912854Sgabeblack@google.com    sc_assert(borrow == 0);
83012854Sgabeblack@google.com#endif
83112854Sgabeblack@google.com
83212854Sgabeblack@google.com    // Copy the rest of u to the result.
83312854Sgabeblack@google.com    while (u < uend)
83412854Sgabeblack@google.com        (*w++) = (*u++);
83512854Sgabeblack@google.com}
83612854Sgabeblack@google.com
83712854Sgabeblack@google.com// Compute u = u - v, where u and v are vectors.
83812854Sgabeblack@google.com// - u > v
83912854Sgabeblack@google.com// - ulen >= vlen
84012854Sgabeblack@google.comvoid
84112854Sgabeblack@google.comvec_sub_on(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
84212854Sgabeblack@google.com{
84312854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
84412854Sgabeblack@google.com    sc_assert((ulen > 0) && (ubegin != NULL));
84512854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
84612854Sgabeblack@google.com    sc_assert(ulen >= vlen);
84712854Sgabeblack@google.com#endif
84812854Sgabeblack@google.com
84912854Sgabeblack@google.com    sc_digit *u = ubegin;
85012854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
85112854Sgabeblack@google.com    const sc_digit *vend = (v + vlen);
85212854Sgabeblack@google.com
85312854Sgabeblack@google.com    sc_digit borrow = 0;   // Also used as diff to save space.
85412854Sgabeblack@google.com
85512854Sgabeblack@google.com    // Subtract along the shorter v.
85612854Sgabeblack@google.com    while (v < vend) {
85712854Sgabeblack@google.com        borrow = ((*u) + DIGIT_RADIX) - (*v++) - borrow;
85812854Sgabeblack@google.com        (*u++) = borrow & DIGIT_MASK;
85912854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
86012854Sgabeblack@google.com    }
86112854Sgabeblack@google.com
86212854Sgabeblack@google.com    // Propagate the borrow.
86312854Sgabeblack@google.com    while (borrow && (u < uend)) {
86412854Sgabeblack@google.com        borrow = ((*u) + DIGIT_RADIX) - 1;
86512854Sgabeblack@google.com        (*u++) = borrow & DIGIT_MASK;
86612854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
86712854Sgabeblack@google.com    }
86812854Sgabeblack@google.com
86912854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
87012854Sgabeblack@google.com    sc_assert(borrow == 0);
87112854Sgabeblack@google.com#endif
87212854Sgabeblack@google.com}
87312854Sgabeblack@google.com
87412854Sgabeblack@google.com// Compute u = v - u, where u and v are vectors.
87512854Sgabeblack@google.com// - v > u
87612854Sgabeblack@google.com// - ulen <= vlen or ulen > ulen
87712854Sgabeblack@google.comvoid
87812854Sgabeblack@google.comvec_sub_on2(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
87912854Sgabeblack@google.com{
88012854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
88112854Sgabeblack@google.com    sc_assert((ulen > 0) && (ubegin != NULL));
88212854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
88312854Sgabeblack@google.com#endif
88412854Sgabeblack@google.com
88512854Sgabeblack@google.com    sc_digit *u = ubegin;
88612854Sgabeblack@google.com    const sc_digit *uend = (u + sc_min(ulen, vlen));
88712854Sgabeblack@google.com
88812854Sgabeblack@google.com    sc_digit borrow = 0;   // Also used as diff to save space.
88912854Sgabeblack@google.com
89012854Sgabeblack@google.com    // Subtract along the shorter u.
89112854Sgabeblack@google.com    while (u < uend) {
89212854Sgabeblack@google.com        borrow = ((*v++) + DIGIT_RADIX) - (*u) - borrow;
89312854Sgabeblack@google.com        (*u++) = borrow & DIGIT_MASK;
89412854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
89512854Sgabeblack@google.com    }
89612854Sgabeblack@google.com
89712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
89812854Sgabeblack@google.com    if (borrow != 0) {
89912854Sgabeblack@google.com        SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
90012854Sgabeblack@google.com                          "vec_sub_on2( int, sc_digit*, int, const "
90112854Sgabeblack@google.com                          "sc_digit* ) : "
90212854Sgabeblack@google.com                          "result of subtraction is wrapped around");
90312854Sgabeblack@google.com    }
90412854Sgabeblack@google.com#endif
90512854Sgabeblack@google.com}
90612854Sgabeblack@google.com
90712854Sgabeblack@google.com// Compute w = u - v, where w and u are vectors, and v is a scalar.
90812854Sgabeblack@google.comvoid
90912854Sgabeblack@google.comvec_sub_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
91012854Sgabeblack@google.com{
91112854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
91212854Sgabeblack@google.com    sc_assert(ulen > 0);
91312854Sgabeblack@google.com    sc_assert(u != NULL);
91412854Sgabeblack@google.com#endif
91512854Sgabeblack@google.com
91612854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
91712854Sgabeblack@google.com
91812854Sgabeblack@google.com    // Add along the shorter v.
91912854Sgabeblack@google.com    sc_digit borrow = ((*u++) + DIGIT_RADIX) - v;
92012854Sgabeblack@google.com    (*w++) = borrow & DIGIT_MASK;
92112854Sgabeblack@google.com    borrow = 1 - (borrow >> BITS_PER_DIGIT);
92212854Sgabeblack@google.com
92312854Sgabeblack@google.com    // Propagate the borrow.
92412854Sgabeblack@google.com    while (borrow && (u < uend)) {
92512854Sgabeblack@google.com        borrow = ((*u++) + DIGIT_RADIX) - 1;
92612854Sgabeblack@google.com        (*w++) = borrow & DIGIT_MASK;
92712854Sgabeblack@google.com        borrow = 1 - (borrow >> BITS_PER_DIGIT);
92812854Sgabeblack@google.com    }
92912854Sgabeblack@google.com
93012854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
93112854Sgabeblack@google.com    sc_assert(borrow == 0);
93212854Sgabeblack@google.com#endif
93312854Sgabeblack@google.com
93412854Sgabeblack@google.com    // Copy the rest of u to the result.
93512854Sgabeblack@google.com    while (u < uend)
93612854Sgabeblack@google.com        (*w++) = (*u++);
93712854Sgabeblack@google.com}
93812854Sgabeblack@google.com
93912854Sgabeblack@google.com
94012854Sgabeblack@google.com// Compute u -= v, where u is vectors, and v is a scalar.
94112854Sgabeblack@google.comvoid
94212854Sgabeblack@google.comvec_sub_small_on(int ulen, sc_digit *u, sc_digit v)
94312854Sgabeblack@google.com{
94412854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
94512854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
94612854Sgabeblack@google.com#endif
94712854Sgabeblack@google.com
94812854Sgabeblack@google.com    for (int i = 0; i < ulen; ++i) {
94912854Sgabeblack@google.com      v = (u[i] + DIGIT_RADIX) - v;
95012854Sgabeblack@google.com      u[i] = v & DIGIT_MASK;
95112854Sgabeblack@google.com      v = 1 - (v >> BITS_PER_DIGIT);
95212854Sgabeblack@google.com    }
95312854Sgabeblack@google.com
95412854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
95512854Sgabeblack@google.com    sc_assert(v == 0);
95612854Sgabeblack@google.com#endif
95712854Sgabeblack@google.com}
95812854Sgabeblack@google.com
95912854Sgabeblack@google.com// Compute w = u * v, where w, u, and v are vectors.
96012854Sgabeblack@google.comvoid
96112854Sgabeblack@google.comvec_mul(int ulen, const sc_digit *u, int vlen, const sc_digit *vbegin,
96212854Sgabeblack@google.com        sc_digit *wbegin)
96312854Sgabeblack@google.com{
96412854Sgabeblack@google.com
96512854Sgabeblack@google.com  /* Consider u = Ax + B and v = Cx + D where x is equal to
96612854Sgabeblack@google.com     HALF_DIGIT_RADIX. In other words, A is the higher half of u and
96712854Sgabeblack@google.com     B is the lower half of u. The interpretation for v is
96812854Sgabeblack@google.com     similar. Then, we have the following picture:
96912854Sgabeblack@google.com
97012854Sgabeblack@google.com              u_h     u_l
97112854Sgabeblack@google.com     u: -------- --------
97212854Sgabeblack@google.com               A        B
97312854Sgabeblack@google.com
97412854Sgabeblack@google.com              v_h     v_l
97512854Sgabeblack@google.com     v: -------- --------
97612854Sgabeblack@google.com               C        D
97712854Sgabeblack@google.com
97812854Sgabeblack@google.com     result (d):
97912854Sgabeblack@google.com     carry_before:                           -------- --------
98012854Sgabeblack@google.com                                              carry_h  carry_l
98112854Sgabeblack@google.com     result_before:        -------- -------- -------- --------
98212854Sgabeblack@google.com                               R1_h     R1_l     R0_h     R0_l
98312854Sgabeblack@google.com                                             -------- --------
98412854Sgabeblack@google.com                                                 BD_h     BD_l
98512854Sgabeblack@google.com                                    -------- --------
98612854Sgabeblack@google.com                                        AD_h     AD_l
98712854Sgabeblack@google.com                                    -------- --------
98812854Sgabeblack@google.com                                        BC_h     BC_l
98912854Sgabeblack@google.com                           -------- --------
99012854Sgabeblack@google.com                               AC_h     AC_l
99112854Sgabeblack@google.com     result_after:         -------- -------- -------- --------
99212854Sgabeblack@google.com                              R1_h'    R1_l'    R0_h'    R0_l'
99312854Sgabeblack@google.com
99412854Sgabeblack@google.com     prod_l = R0_h|R0_l + B * D  + 0|carry_l
99512854Sgabeblack@google.com            = R0_h|R0_l + BD_h|BD_l + 0|carry_l
99612854Sgabeblack@google.com
99712854Sgabeblack@google.com     prod_h = A * D + B * C + high_half(prod_l) + carry_h
99812854Sgabeblack@google.com            = AD_h|AD_l + BC_h|BC_l + high_half(prod_l) + 0|carry_h
99912854Sgabeblack@google.com
100012854Sgabeblack@google.com     carry = A * C + high_half(prod_h)
100112854Sgabeblack@google.com           = AC_h|AC_l + high_half(prod_h)
100212854Sgabeblack@google.com
100312854Sgabeblack@google.com     R0_l' = low_half(prod_l)
100412854Sgabeblack@google.com
100512854Sgabeblack@google.com     R0_h' = low_half(prod_h)
100612854Sgabeblack@google.com
100712854Sgabeblack@google.com     R0 = high_half(prod_h)|low_half(prod_l)
100812854Sgabeblack@google.com
100912854Sgabeblack@google.com     where '|' is the concatenation operation and the suffixes 0 and 1
101012854Sgabeblack@google.com     show the iteration number, i.e., 0 is the current iteration and 1
101112854Sgabeblack@google.com     is the next iteration.
101212854Sgabeblack@google.com
101312854Sgabeblack@google.com     NOTE: sc_max(prod_l, prod_h, carry) <= 2 * x^2 - 1, so any
101412854Sgabeblack@google.com     of these numbers can be stored in a digit.
101512854Sgabeblack@google.com
101612854Sgabeblack@google.com     NOTE: low_half(u) returns the lower BITS_PER_HALF_DIGIT of u,
101712854Sgabeblack@google.com     whereas high_half(u) returns the rest of the bits, which may
101812854Sgabeblack@google.com     contain more bits than BITS_PER_HALF_DIGIT.
101912854Sgabeblack@google.com  */
102012854Sgabeblack@google.com
102112854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
102212854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
102312854Sgabeblack@google.com    sc_assert((vlen > 0) && (vbegin != NULL));
102412854Sgabeblack@google.com    sc_assert(wbegin != NULL);
102512854Sgabeblack@google.com#endif
102612854Sgabeblack@google.com
102712854Sgabeblack@google.com#define prod_h carry
102812854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
102912854Sgabeblack@google.com    const sc_digit *vend = (vbegin + vlen);
103012854Sgabeblack@google.com
103112854Sgabeblack@google.com    while (u < uend) {
103212854Sgabeblack@google.com        sc_digit u_h = (*u++); // A|B
103312854Sgabeblack@google.com        sc_digit u_l = low_half(u_h); // B
103412854Sgabeblack@google.com        u_h = high_half(u_h); // A
103512854Sgabeblack@google.com
103612854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
103712854Sgabeblack@google.com        // The overflow bits must be zero.
103812854Sgabeblack@google.com        sc_assert(u_h == (u_h & HALF_DIGIT_MASK));
103912854Sgabeblack@google.com#endif
104012854Sgabeblack@google.com        sc_digit carry = 0;
104112854Sgabeblack@google.com        sc_digit *w = (wbegin++);
104212854Sgabeblack@google.com        const sc_digit *v = vbegin;
104312854Sgabeblack@google.com
104412854Sgabeblack@google.com        while (v < vend) {
104512854Sgabeblack@google.com            sc_digit v_h = (*v++); // C|D
104612854Sgabeblack@google.com            sc_digit v_l = low_half(v_h); // D
104712854Sgabeblack@google.com
104812854Sgabeblack@google.com            v_h = high_half(v_h); // C
104912854Sgabeblack@google.com
105012854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
105112854Sgabeblack@google.com            // The overflow bits must be zero.
105212854Sgabeblack@google.com            sc_assert(v_h == (v_h & HALF_DIGIT_MASK));
105312854Sgabeblack@google.com#endif
105412854Sgabeblack@google.com
105512854Sgabeblack@google.com            sc_digit prod_l = (*w) + u_l * v_l + low_half(carry);
105612854Sgabeblack@google.com            prod_h = u_h * v_l + u_l * v_h +
105712854Sgabeblack@google.com                high_half(prod_l) + high_half(carry);
105812854Sgabeblack@google.com            (*w++) = concat(low_half(prod_h), low_half(prod_l));
105912854Sgabeblack@google.com            carry = u_h * v_h + high_half(prod_h);
106012854Sgabeblack@google.com        }
106112854Sgabeblack@google.com        (*w) = carry;
106212854Sgabeblack@google.com    }
106312854Sgabeblack@google.com#undef prod_h
106412854Sgabeblack@google.com}
106512854Sgabeblack@google.com
106612854Sgabeblack@google.com// Compute w = u * v, where w and u are vectors, and v is a scalar.
106712854Sgabeblack@google.com// - 0 < v < HALF_DIGIT_RADIX.
106812854Sgabeblack@google.comvoid
106912854Sgabeblack@google.comvec_mul_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
107012854Sgabeblack@google.com{
107112854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
107212854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
107312854Sgabeblack@google.com    sc_assert(w != NULL);
107412854Sgabeblack@google.com    sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
107512854Sgabeblack@google.com#endif
107612854Sgabeblack@google.com
107712854Sgabeblack@google.com#define prod_h carry
107812854Sgabeblack@google.com
107912854Sgabeblack@google.com    const sc_digit *uend = (u + ulen);
108012854Sgabeblack@google.com    sc_digit carry = 0;
108112854Sgabeblack@google.com    while (u < uend) {
108212854Sgabeblack@google.com        sc_digit u_AB = (*u++);
108312854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
108412854Sgabeblack@google.com        // The overflow bits must be zero.
108512854Sgabeblack@google.com        sc_assert(high_half(u_AB) == high_half_masked(u_AB));
108612854Sgabeblack@google.com#endif
108712854Sgabeblack@google.com        sc_digit prod_l = v * low_half(u_AB) + low_half(carry);
108812854Sgabeblack@google.com        prod_h = v * high_half(u_AB) + high_half(prod_l) + high_half(carry);
108912854Sgabeblack@google.com        (*w++) = concat(low_half(prod_h), low_half(prod_l));
109012854Sgabeblack@google.com        carry = high_half(prod_h);
109112854Sgabeblack@google.com    }
109212854Sgabeblack@google.com    (*w) = carry;
109312854Sgabeblack@google.com#undef prod_h
109412854Sgabeblack@google.com}
109512854Sgabeblack@google.com
109612854Sgabeblack@google.com// Compute u = u * v, where u is a vector, and v is a scalar.
109712854Sgabeblack@google.com// - 0 < v < HALF_DIGIT_RADIX.
109812854Sgabeblack@google.comvoid
109912854Sgabeblack@google.comvec_mul_small_on(int ulen, sc_digit *u, sc_digit v)
110012854Sgabeblack@google.com{
110112854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
110212854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
110312854Sgabeblack@google.com    sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
110412854Sgabeblack@google.com#endif
110512854Sgabeblack@google.com
110612854Sgabeblack@google.com#define   prod_h carry
110712854Sgabeblack@google.com    sc_digit carry = 0;
110812854Sgabeblack@google.com    for (int i = 0; i < ulen; ++i) {
110912854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
111012854Sgabeblack@google.com        // The overflow bits must be zero.
111112854Sgabeblack@google.com        sc_assert(high_half(u[i]) == high_half_masked(u[i]));
111212854Sgabeblack@google.com#endif
111312854Sgabeblack@google.com        sc_digit prod_l = v * low_half(u[i]) + low_half(carry);
111412854Sgabeblack@google.com        prod_h = v * high_half(u[i]) + high_half(prod_l) + high_half(carry);
111512854Sgabeblack@google.com        u[i] = concat(low_half(prod_h), low_half(prod_l));
111612854Sgabeblack@google.com        carry = high_half(prod_h);
111712854Sgabeblack@google.com    }
111812854Sgabeblack@google.com#undef   prod_h
111912854Sgabeblack@google.com
112012854Sgabeblack@google.com#ifdef   DEBUG_SYSTEMC
112112854Sgabeblack@google.com    if (carry != 0) {
112212854Sgabeblack@google.com        SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
112312854Sgabeblack@google.com                          "vec_mul_small_on( int, sc_digit*, unsigned "
112412854Sgabeblack@google.com                          "long ) : "
112512854Sgabeblack@google.com                          "result of multiplication is wrapped around");
112612854Sgabeblack@google.com    }
112712854Sgabeblack@google.com#endif
112812854Sgabeblack@google.com}
112912854Sgabeblack@google.com
113012854Sgabeblack@google.com// Compute w = u / v, where w, u, and v are vectors.
113112854Sgabeblack@google.com// - u and v are assumed to have at least two digits as uchars.
113212854Sgabeblack@google.comvoid
113312854Sgabeblack@google.comvec_div_large(int ulen, const sc_digit *u, int vlen, const sc_digit *v,
113412854Sgabeblack@google.com              sc_digit *w)
113512854Sgabeblack@google.com{
113612854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
113712854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
113812854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
113912854Sgabeblack@google.com    sc_assert(w != NULL);
114012854Sgabeblack@google.com    sc_assert(BITS_PER_DIGIT >= 3 * BITS_PER_BYTE);
114112854Sgabeblack@google.com#endif
114212854Sgabeblack@google.com
114312854Sgabeblack@google.com    // We will compute q = x / y where x = u and y = v. The reason for
114412854Sgabeblack@google.com    // using x and y is that x and y are BYTE_RADIX copies of u and v,
114512854Sgabeblack@google.com    // respectively. The use of BYTE_RADIX radix greatly simplifies the
114612854Sgabeblack@google.com    // complexity of the division operation. These copies are also
114712854Sgabeblack@google.com    // needed even when we use DIGIT_RADIX representation.
114812854Sgabeblack@google.com
114912854Sgabeblack@google.com    int xlen = BYTES_PER_DIGIT * ulen + 1;
115012854Sgabeblack@google.com    int ylen = BYTES_PER_DIGIT * vlen;
115112854Sgabeblack@google.com
115212854Sgabeblack@google.com#ifdef SC_MAX_NBITS
115312854Sgabeblack@google.com    uchar x[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
115412854Sgabeblack@google.com    uchar y[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
115512854Sgabeblack@google.com    uchar q[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
115612854Sgabeblack@google.com#else
115712854Sgabeblack@google.com    uchar *x = new uchar[xlen];
115812854Sgabeblack@google.com    uchar *y = new uchar[ylen];
115912854Sgabeblack@google.com    // valgrind complains about us accessing too far to so leave a buffer.
116012854Sgabeblack@google.com    uchar *q = new uchar[(xlen - ylen) + 10];
116112854Sgabeblack@google.com#endif
116212854Sgabeblack@google.com
116312854Sgabeblack@google.com    // q corresponds to w.
116412854Sgabeblack@google.com
116512854Sgabeblack@google.com    // Set (uchar) x = (sc_digit) u.
116612854Sgabeblack@google.com    xlen = vec_to_char(ulen, u, xlen, x);
116712854Sgabeblack@google.com
116812854Sgabeblack@google.com    // Skip all the leading zeros in x.
116912854Sgabeblack@google.com    while ((--xlen >= 0) && (! x[xlen]))
117012854Sgabeblack@google.com        continue;
117112854Sgabeblack@google.com    xlen++;
117212854Sgabeblack@google.com
117312854Sgabeblack@google.com    // Set (uchar) y = (sc_digit) v.
117412854Sgabeblack@google.com    ylen = vec_to_char(vlen, v, ylen, y);
117512854Sgabeblack@google.com
117612854Sgabeblack@google.com    // Skip all the leading zeros in y.
117712854Sgabeblack@google.com    while ((--ylen >= 0) && (! y[ylen]))
117812854Sgabeblack@google.com        continue;
117912854Sgabeblack@google.com    ylen++;
118012854Sgabeblack@google.com
118112854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
118212854Sgabeblack@google.com    sc_assert(xlen > 1);
118312854Sgabeblack@google.com    sc_assert(ylen > 1);
118412854Sgabeblack@google.com#endif
118512854Sgabeblack@google.com
118612854Sgabeblack@google.com    // At this point, all the leading zeros are eliminated from x and y.
118712854Sgabeblack@google.com
118812854Sgabeblack@google.com    // Zero the last digit of x.
118912854Sgabeblack@google.com    x[xlen] = 0;
119012854Sgabeblack@google.com
119112854Sgabeblack@google.com    // The first two digits of y.
119212854Sgabeblack@google.com    sc_digit y2 = (y[ylen - 1] << BITS_PER_BYTE) + y[ylen - 2];
119312854Sgabeblack@google.com
119412854Sgabeblack@google.com    const sc_digit DOUBLE_BITS_PER_BYTE = 2 * BITS_PER_BYTE;
119512854Sgabeblack@google.com
119612854Sgabeblack@google.com    // Find each q[k].
119712854Sgabeblack@google.com    for (int k = (xlen - ylen); k >= 0; --k) {
119812854Sgabeblack@google.com        // qk is a guess for q[k] such that q[k] = qk or qk - 1.
119912854Sgabeblack@google.com        sc_digit qk;
120012854Sgabeblack@google.com
120112854Sgabeblack@google.com        // Find qk by just using 2 digits of y and 3 digits of x. The
120212854Sgabeblack@google.com        // following code assumes that sizeof(sc_digit) >= 3 BYTEs.
120312854Sgabeblack@google.com        int k2 = k + ylen;
120412854Sgabeblack@google.com
120512854Sgabeblack@google.com        qk = ((x[k2] << DOUBLE_BITS_PER_BYTE) +
120612854Sgabeblack@google.com              (x[k2 - 1] << BITS_PER_BYTE) + x[k2 - 2]) / y2;
120712854Sgabeblack@google.com
120812854Sgabeblack@google.com        if (qk >= BYTE_RADIX) // qk cannot be larger than the largest
120912854Sgabeblack@google.com            qk = BYTE_RADIX - 1; // digit in BYTE_RADIX.
121012854Sgabeblack@google.com
121112854Sgabeblack@google.com        // q[k] = qk or qk - 1. The following if-statement determines which:
121212854Sgabeblack@google.com        if (qk) {
121312854Sgabeblack@google.com            uchar *xk = (x + k);  // A shortcut for x[k].
121412854Sgabeblack@google.com
121512854Sgabeblack@google.com            // x = x - y * qk :
121612854Sgabeblack@google.com            sc_digit carry = 0;
121712854Sgabeblack@google.com
121812854Sgabeblack@google.com            for (int i = 0; i < ylen; ++i) {
121912854Sgabeblack@google.com                carry += y[i] * qk;
122012854Sgabeblack@google.com                sc_digit diff = (xk[i] + BYTE_RADIX) - (carry & BYTE_MASK);
122112854Sgabeblack@google.com                xk[i] = (uchar)(diff & BYTE_MASK);
122212854Sgabeblack@google.com                carry = (carry >> BITS_PER_BYTE) +
122312854Sgabeblack@google.com                    (1 - (diff >> BITS_PER_BYTE));
122412854Sgabeblack@google.com            }
122512854Sgabeblack@google.com
122612854Sgabeblack@google.com            // If carry, qk may be one too large.
122712854Sgabeblack@google.com            if (carry) {
122812854Sgabeblack@google.com                // 2's complement the last digit.
122912854Sgabeblack@google.com                carry = (xk[ylen] + BYTE_RADIX) - carry;
123012854Sgabeblack@google.com                xk[ylen] = (uchar)(carry & BYTE_MASK);
123112854Sgabeblack@google.com                carry = 1 - (carry >> BITS_PER_BYTE);
123212854Sgabeblack@google.com
123312854Sgabeblack@google.com                if (carry) {
123412854Sgabeblack@google.com
123512854Sgabeblack@google.com                  // qk was one too large, so decrement it.
123612854Sgabeblack@google.com                  --qk;
123712854Sgabeblack@google.com
123812854Sgabeblack@google.com                  // Since qk was decreased by one, y must be added to x:
123912854Sgabeblack@google.com                  // x = x - y * (qk - 1) = x - y * qk + y = x_above + y.
124012854Sgabeblack@google.com                  carry = 0;
124112854Sgabeblack@google.com
124212854Sgabeblack@google.com                  for (int i = 0; i < ylen; ++i) {
124312854Sgabeblack@google.com                      carry += xk[i] + y[i];
124412854Sgabeblack@google.com                      xk[i] = (uchar)(carry & BYTE_MASK);
124512854Sgabeblack@google.com                      carry >>= BITS_PER_BYTE;
124612854Sgabeblack@google.com                  }
124712854Sgabeblack@google.com
124812854Sgabeblack@google.com                  if (carry)
124912854Sgabeblack@google.com                      xk[ylen] = (uchar)((xk[ylen] + 1) & BYTE_MASK);
125012854Sgabeblack@google.com
125112854Sgabeblack@google.com                }  // second if carry
125212854Sgabeblack@google.com            }  // first if carry
125312854Sgabeblack@google.com        }  // if qk
125412854Sgabeblack@google.com        q[k] = (uchar)qk;
125512854Sgabeblack@google.com    }  // for k
125612854Sgabeblack@google.com
125712854Sgabeblack@google.com    // Set (sc_digit) w = (uchar) q.
125812854Sgabeblack@google.com    vec_from_char(xlen - ylen + 1, q, ulen, w);
125912854Sgabeblack@google.com
126012854Sgabeblack@google.com#ifndef SC_MAX_NBITS
126112854Sgabeblack@google.com    delete [] x;
126212854Sgabeblack@google.com    delete [] y;
126312854Sgabeblack@google.com    delete [] q;
126412854Sgabeblack@google.com#endif
126512854Sgabeblack@google.com
126612854Sgabeblack@google.com}
126712854Sgabeblack@google.com
126812854Sgabeblack@google.com// Compute w = u / v, where u and w are vectors, and v is a scalar.
126912854Sgabeblack@google.com// - 0 < v < HALF_DIGIT_RADIX. Below, we rename w to q.
127012854Sgabeblack@google.comvoid
127112854Sgabeblack@google.comvec_div_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *q)
127212854Sgabeblack@google.com{
127312854Sgabeblack@google.com    // Given (u = u_1u_2...u_n)_b = (q = q_1q_2...q_n) * v + r, where b
127412854Sgabeblack@google.com    // is the base, and 0 <= r < v. Then, the algorithm is as follows:
127512854Sgabeblack@google.com    //
127612854Sgabeblack@google.com    // r = 0;
127712854Sgabeblack@google.com    // for (j = 1; j <= n; j++) {
127812854Sgabeblack@google.com    //   q_j = (r * b + u_j) / v;
127912854Sgabeblack@google.com    //   r = (r * b + u_j) % v;
128012854Sgabeblack@google.com    // }
128112854Sgabeblack@google.com    //
128212854Sgabeblack@google.com    // In our case, b = DIGIT_RADIX, and u = Ax + B and q = Cx + D where
128312854Sgabeblack@google.com    // x = HALF_DIGIT_RADIX. Note that r < v < x and b = x^2. Then, a
128412854Sgabeblack@google.com    // typical situation is as follows:
128512854Sgabeblack@google.com    //
128612854Sgabeblack@google.com    // ---- ----
128712854Sgabeblack@google.com    // 0    r
128812854Sgabeblack@google.com    //           ---- ----
128912854Sgabeblack@google.com    //           A    B
129012854Sgabeblack@google.com    //      ---- ---- ----
129112854Sgabeblack@google.com    //      r    A    B     = r * b + u
129212854Sgabeblack@google.com    //
129312854Sgabeblack@google.com    // Hence, C = (r|A) / v.
129412854Sgabeblack@google.com    //        D = (((r|A) % v)|B) / v
129512854Sgabeblack@google.com    //        r = (((r|A) % v)|B) % v
129612854Sgabeblack@google.com
129712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
129812854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
129912854Sgabeblack@google.com    sc_assert(q != NULL);
130012854Sgabeblack@google.com    sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
130112854Sgabeblack@google.com#endif
130212854Sgabeblack@google.com
130312854Sgabeblack@google.com#define q_h r
130412854Sgabeblack@google.com    sc_digit r = 0;
130512854Sgabeblack@google.com    const sc_digit *ubegin = u;
130612854Sgabeblack@google.com
130712854Sgabeblack@google.com    u += ulen;
130812854Sgabeblack@google.com    q += ulen;
130912854Sgabeblack@google.com
131012854Sgabeblack@google.com    while (ubegin < u) {
131112854Sgabeblack@google.com        sc_digit u_AB = (*--u); // A|B
131212854Sgabeblack@google.com
131312854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
131412854Sgabeblack@google.com        // The overflow bits must be zero.
131512854Sgabeblack@google.com        sc_assert(high_half(u_AB) == high_half_masked(u_AB));
131612854Sgabeblack@google.com#endif
131712854Sgabeblack@google.com
131812854Sgabeblack@google.com        sc_digit num = concat(r, high_half(u_AB)); // num = r|A
131912854Sgabeblack@google.com        q_h = num / v; // C
132012854Sgabeblack@google.com        num = concat((num % v), low_half(u_AB)); // num = (((r|A) % v)|B)
132112854Sgabeblack@google.com        (*--q) = concat(q_h, num / v); // q = C|D
132212854Sgabeblack@google.com        r = num % v;
132312854Sgabeblack@google.com    }
132412854Sgabeblack@google.com#undef q_h
132512854Sgabeblack@google.com}
132612854Sgabeblack@google.com
132712854Sgabeblack@google.com// Compute w = u % v, where w, u, and v are vectors.
132812854Sgabeblack@google.com// - u and v are assumed to have at least two digits as uchars.
132912854Sgabeblack@google.comvoid
133012854Sgabeblack@google.comvec_rem_large(int ulen, const sc_digit *u, int vlen, const sc_digit *v,
133112854Sgabeblack@google.com              sc_digit *w)
133212854Sgabeblack@google.com{
133312854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
133412854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
133512854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
133612854Sgabeblack@google.com    sc_assert(w != NULL);
133712854Sgabeblack@google.com    sc_assert(BITS_PER_DIGIT >= 3 * BITS_PER_BYTE);
133812854Sgabeblack@google.com#endif
133912854Sgabeblack@google.com
134012854Sgabeblack@google.com    // This function is adapted from vec_div_large.
134112854Sgabeblack@google.com    int xlen = BYTES_PER_DIGIT * ulen + 1;
134212854Sgabeblack@google.com    int ylen = BYTES_PER_DIGIT * vlen;
134312854Sgabeblack@google.com
134412854Sgabeblack@google.com#ifdef SC_MAX_NBITS
134512854Sgabeblack@google.com    uchar x[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
134612854Sgabeblack@google.com    uchar y[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
134712854Sgabeblack@google.com#else
134812854Sgabeblack@google.com    uchar *x = new uchar[xlen];
134912854Sgabeblack@google.com    uchar *y = new uchar[ylen];
135012854Sgabeblack@google.com#endif
135112854Sgabeblack@google.com
135212854Sgabeblack@google.com    // r corresponds to w.
135312854Sgabeblack@google.com
135412854Sgabeblack@google.com    // Set (uchar) x = (sc_digit) u.
135512854Sgabeblack@google.com    xlen = vec_to_char(ulen, u, xlen, x);
135612854Sgabeblack@google.com
135712854Sgabeblack@google.com    // Skip all the leading zeros in x.
135812854Sgabeblack@google.com    while ((--xlen >= 0) && (!x[xlen]))
135912854Sgabeblack@google.com        continue;
136012854Sgabeblack@google.com    xlen++;
136112854Sgabeblack@google.com
136212854Sgabeblack@google.com    // Set (uchar) y = (sc_digit) v.
136312854Sgabeblack@google.com    ylen = vec_to_char(vlen, v, ylen, y);
136412854Sgabeblack@google.com
136512854Sgabeblack@google.com    // Skip all the leading zeros in y.
136612854Sgabeblack@google.com    while ((--ylen >= 0) && (!y[ylen]))
136712854Sgabeblack@google.com        continue;
136812854Sgabeblack@google.com    ylen++;
136912854Sgabeblack@google.com
137012854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
137112854Sgabeblack@google.com    sc_assert(xlen > 1);
137212854Sgabeblack@google.com    sc_assert(ylen > 1);
137312854Sgabeblack@google.com#endif
137412854Sgabeblack@google.com
137512854Sgabeblack@google.com    // At this point, all the leading zeros are eliminated from x and y.
137612854Sgabeblack@google.com
137712854Sgabeblack@google.com    // Zero the last digit of x.
137812854Sgabeblack@google.com    x[xlen] = 0;
137912854Sgabeblack@google.com
138012854Sgabeblack@google.com    // The first two digits of y.
138112854Sgabeblack@google.com    sc_digit y2 = (y[ylen - 1] << BITS_PER_BYTE) + y[ylen - 2];
138212854Sgabeblack@google.com
138312854Sgabeblack@google.com    const sc_digit DOUBLE_BITS_PER_BYTE = 2 * BITS_PER_BYTE;
138412854Sgabeblack@google.com
138512854Sgabeblack@google.com    // Find each q[k].
138612854Sgabeblack@google.com    for (int k = xlen - ylen; k >= 0; --k) {
138712854Sgabeblack@google.com        // qk is a guess for q[k] such that q[k] = qk or qk - 1.
138812854Sgabeblack@google.com        sc_digit qk;
138912854Sgabeblack@google.com
139012854Sgabeblack@google.com        // Find qk by just using 2 digits of y and 3 digits of x. The
139112854Sgabeblack@google.com        // following code assumes that sizeof(sc_digit) >= 3 BYTEs.
139212854Sgabeblack@google.com        int k2 = k + ylen;
139312854Sgabeblack@google.com
139412854Sgabeblack@google.com        qk = ((x[k2] << DOUBLE_BITS_PER_BYTE) +
139512854Sgabeblack@google.com            (x[k2 - 1] << BITS_PER_BYTE) + x[k2 - 2]) / y2;
139612854Sgabeblack@google.com
139712854Sgabeblack@google.com        if (qk >= BYTE_RADIX) // qk cannot be larger than the largest
139812854Sgabeblack@google.com            qk = BYTE_RADIX - 1; // digit in BYTE_RADIX.
139912854Sgabeblack@google.com
140012854Sgabeblack@google.com        // q[k] = qk or qk - 1. The following if-statement determines which.
140112854Sgabeblack@google.com        if (qk) {
140212854Sgabeblack@google.com            uchar *xk = (x + k);  // A shortcut for x[k].
140312854Sgabeblack@google.com
140412854Sgabeblack@google.com            // x = x - y * qk;
140512854Sgabeblack@google.com            sc_digit carry = 0;
140612854Sgabeblack@google.com
140712854Sgabeblack@google.com            for (int i = 0; i < ylen; ++i) {
140812854Sgabeblack@google.com                carry += y[i] * qk;
140912854Sgabeblack@google.com                sc_digit diff = (xk[i] + BYTE_RADIX) - (carry & BYTE_MASK);
141012854Sgabeblack@google.com                xk[i] = (uchar)(diff & BYTE_MASK);
141112854Sgabeblack@google.com                carry = (carry >> BITS_PER_BYTE) +
141212854Sgabeblack@google.com                    (1 - (diff >> BITS_PER_BYTE));
141312854Sgabeblack@google.com            }
141412854Sgabeblack@google.com
141512854Sgabeblack@google.com            if (carry) {
141612854Sgabeblack@google.com                // 2's complement the last digit.
141712854Sgabeblack@google.com                carry = (xk[ylen] + BYTE_RADIX) - carry;
141812854Sgabeblack@google.com                xk[ylen] = (uchar)(carry & BYTE_MASK);
141912854Sgabeblack@google.com                carry = 1 - (carry >> BITS_PER_BYTE);
142012854Sgabeblack@google.com
142112854Sgabeblack@google.com                if (carry) {
142212854Sgabeblack@google.com                  // qk was one too large, so decrement it.
142312854Sgabeblack@google.com                  // --qk;
142412854Sgabeblack@google.com
142512854Sgabeblack@google.com                  // x = x - y * (qk - 1) = x - y * qk + y = x_above + y.
142612854Sgabeblack@google.com                  carry = 0;
142712854Sgabeblack@google.com
142812854Sgabeblack@google.com                  for (int i = 0; i < ylen; ++i) {
142912854Sgabeblack@google.com                      carry += xk[i] + y[i];
143012854Sgabeblack@google.com                      xk[i] = (uchar)(carry & BYTE_MASK);
143112854Sgabeblack@google.com                      carry >>= BITS_PER_BYTE;
143212854Sgabeblack@google.com                  }
143312854Sgabeblack@google.com
143412854Sgabeblack@google.com                  if (carry)
143512854Sgabeblack@google.com                      xk[ylen] = (uchar)((xk[ylen] + 1) & BYTE_MASK);
143612854Sgabeblack@google.com                }  // second if carry
143712854Sgabeblack@google.com            } // first if carry
143812854Sgabeblack@google.com        }  // if qk
143912854Sgabeblack@google.com    }  // for k
144012854Sgabeblack@google.com
144112854Sgabeblack@google.com    // Set (sc_digit) w = (uchar) x for the remainder.
144212854Sgabeblack@google.com    vec_from_char(ylen, x, ulen, w);
144312854Sgabeblack@google.com
144412854Sgabeblack@google.com#ifndef SC_MAX_NBITS
144512854Sgabeblack@google.com    delete [] x;
144612854Sgabeblack@google.com    delete [] y;
144712854Sgabeblack@google.com#endif
144812854Sgabeblack@google.com
144912854Sgabeblack@google.com}
145012854Sgabeblack@google.com
145112854Sgabeblack@google.com// Compute r = u % v, where u is a vector, and r and v are scalars.
145212854Sgabeblack@google.com// - 0 < v < HALF_DIGIT_RADIX.
145312854Sgabeblack@google.com// - The remainder r is returned.
145412854Sgabeblack@google.comsc_digit
145512854Sgabeblack@google.comvec_rem_small(int ulen, const sc_digit *u, sc_digit v)
145612854Sgabeblack@google.com{
145712854Sgabeblack@google.com
145812854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
145912854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
146012854Sgabeblack@google.com    sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
146112854Sgabeblack@google.com#endif
146212854Sgabeblack@google.com
146312854Sgabeblack@google.com    // This function is adapted from vec_div_small().
146412854Sgabeblack@google.com
146512854Sgabeblack@google.com    sc_digit r = 0;
146612854Sgabeblack@google.com    const sc_digit *ubegin = u;
146712854Sgabeblack@google.com
146812854Sgabeblack@google.com    u += ulen;
146912854Sgabeblack@google.com
147012854Sgabeblack@google.com    while (ubegin < u) {
147112854Sgabeblack@google.com        sc_digit u_AB = (*--u); // A|B
147212854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
147312854Sgabeblack@google.com        // The overflow bits must be zero.
147412854Sgabeblack@google.com        sc_assert(high_half(u_AB) == high_half_masked(u_AB));
147512854Sgabeblack@google.com#endif
147612854Sgabeblack@google.com        // r = (((r|A) % v)|B) % v
147712854Sgabeblack@google.com        r = (concat(((concat(r, high_half(u_AB))) % v), low_half(u_AB))) % v;
147812854Sgabeblack@google.com    }
147912854Sgabeblack@google.com
148012854Sgabeblack@google.com    return r;
148112854Sgabeblack@google.com}
148212854Sgabeblack@google.com
148312854Sgabeblack@google.com// u = u / v, r = u % v.
148412854Sgabeblack@google.comsc_digit
148512854Sgabeblack@google.comvec_rem_on_small(int ulen, sc_digit *u, sc_digit v)
148612854Sgabeblack@google.com{
148712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
148812854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
148912854Sgabeblack@google.com    sc_assert(v > 0);
149012854Sgabeblack@google.com#endif
149112854Sgabeblack@google.com
149212854Sgabeblack@google.com#define q_h r
149312854Sgabeblack@google.com    sc_digit r = 0;
149412854Sgabeblack@google.com    const sc_digit *ubegin = u;
149512854Sgabeblack@google.com
149612854Sgabeblack@google.com    u += ulen;
149712854Sgabeblack@google.com    while (ubegin < u) {
149812854Sgabeblack@google.com        sc_digit u_AB = (*--u); // A|B
149912854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
150012854Sgabeblack@google.com        // The overflow bits must be zero.
150112854Sgabeblack@google.com        sc_assert(high_half(u_AB) == high_half_masked(u_AB));
150212854Sgabeblack@google.com#endif
150312854Sgabeblack@google.com        sc_digit num = concat(r, high_half(u_AB)); // num = r|A
150412854Sgabeblack@google.com        q_h = num / v; // C
150512854Sgabeblack@google.com        num = concat((num % v), low_half(u_AB)); // num = (((r|A) % v)|B)
150612854Sgabeblack@google.com        (*u) = concat(q_h, num / v); // q = C|D
150712854Sgabeblack@google.com        r = num % v;
150812854Sgabeblack@google.com    }
150912854Sgabeblack@google.com#undef q_h
151012854Sgabeblack@google.com    return r;
151112854Sgabeblack@google.com}
151212854Sgabeblack@google.com
151312854Sgabeblack@google.com// Set (uchar) v = (sc_digit) u. Return the new vlen.
151412854Sgabeblack@google.comint
151512854Sgabeblack@google.comvec_to_char(int ulen, const sc_digit *u, int vlen, uchar *v)
151612854Sgabeblack@google.com{
151712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
151812854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
151912854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
152012854Sgabeblack@google.com#endif
152112854Sgabeblack@google.com
152212854Sgabeblack@google.com    int nbits = ulen * BITS_PER_DIGIT;
152312854Sgabeblack@google.com    int right = 0;
152412854Sgabeblack@google.com    int left = right + BITS_PER_BYTE - 1;
152512854Sgabeblack@google.com
152612854Sgabeblack@google.com    vlen = 0;
152712854Sgabeblack@google.com    while (nbits > 0) {
152812854Sgabeblack@google.com        int left_digit = left / BITS_PER_DIGIT;
152912854Sgabeblack@google.com        int right_digit = right / BITS_PER_DIGIT;
153012854Sgabeblack@google.com        int nsr = ((vlen << LOG2_BITS_PER_BYTE) % BITS_PER_DIGIT);
153112854Sgabeblack@google.com        int d = u[right_digit] >> nsr;
153212854Sgabeblack@google.com
153312854Sgabeblack@google.com        if (left_digit != right_digit) {
153412854Sgabeblack@google.com            if (left_digit < ulen)
153512854Sgabeblack@google.com                d |= u[left_digit] << (BITS_PER_DIGIT - nsr);
153612854Sgabeblack@google.com        }
153712854Sgabeblack@google.com
153812854Sgabeblack@google.com        v[vlen++] = (uchar)(d & BYTE_MASK);
153912854Sgabeblack@google.com
154012854Sgabeblack@google.com        left += BITS_PER_BYTE;
154112854Sgabeblack@google.com        right += BITS_PER_BYTE;
154212854Sgabeblack@google.com        nbits -= BITS_PER_BYTE;
154312854Sgabeblack@google.com    }
154412854Sgabeblack@google.com    return vlen;
154512854Sgabeblack@google.com}
154612854Sgabeblack@google.com
154712854Sgabeblack@google.com// Set (sc_digit) v = (uchar) u.
154812854Sgabeblack@google.com// - sizeof(uchar) <= sizeof(sc_digit),
154912854Sgabeblack@google.comvoid
155012854Sgabeblack@google.comvec_from_char(int ulen, const uchar *u, int vlen, sc_digit *v)
155112854Sgabeblack@google.com{
155212854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
155312854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
155412854Sgabeblack@google.com    sc_assert((vlen > 0) && (v != NULL));
155512854Sgabeblack@google.com    sc_assert(sizeof(uchar) <= sizeof(sc_digit));
155612854Sgabeblack@google.com#endif
155712854Sgabeblack@google.com
155812854Sgabeblack@google.com    sc_digit *vend = (v + vlen);
155912854Sgabeblack@google.com
156012854Sgabeblack@google.com    const int nsr = BITS_PER_DIGIT - BITS_PER_BYTE;
156112854Sgabeblack@google.com    const sc_digit mask = one_and_ones(nsr);
156212854Sgabeblack@google.com
156312854Sgabeblack@google.com    (*v) = (sc_digit) u[ulen - 1];
156412854Sgabeblack@google.com
156512854Sgabeblack@google.com    for (int i = ulen - 2; i >= 0; --i) {
156612854Sgabeblack@google.com        // Manual inlining of vec_shift_left().
156712854Sgabeblack@google.com        sc_digit *viter = v;
156812854Sgabeblack@google.com        sc_digit carry = 0;
156912854Sgabeblack@google.com        while (viter < vend) {
157012854Sgabeblack@google.com            sc_digit vval = (*viter);
157112854Sgabeblack@google.com            (*viter++) = (((vval & mask) << BITS_PER_BYTE) | carry);
157212854Sgabeblack@google.com            carry = vval >> nsr;
157312854Sgabeblack@google.com        }
157412854Sgabeblack@google.com
157512854Sgabeblack@google.com        if (viter < vend)
157612854Sgabeblack@google.com            (*viter) = carry;
157712854Sgabeblack@google.com
157812854Sgabeblack@google.com        (*v) |= (sc_digit)u[i];
157912854Sgabeblack@google.com    }
158012854Sgabeblack@google.com}
158112854Sgabeblack@google.com
158212854Sgabeblack@google.com// Set u <<= nsl.
158312854Sgabeblack@google.com// If nsl is negative, it is ignored.
158412854Sgabeblack@google.comvoid
158512854Sgabeblack@google.comvec_shift_left(int ulen, sc_digit *u, int nsl)
158612854Sgabeblack@google.com{
158712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
158812854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
158912854Sgabeblack@google.com#endif
159012854Sgabeblack@google.com
159112854Sgabeblack@google.com    if (nsl <= 0)
159212854Sgabeblack@google.com        return;
159312854Sgabeblack@google.com
159412854Sgabeblack@google.com    // Shift left whole digits if nsl is large enough.
159512854Sgabeblack@google.com    if (nsl >= (int) BITS_PER_DIGIT) {
159612854Sgabeblack@google.com        int nd;
159712854Sgabeblack@google.com        if (nsl % BITS_PER_DIGIT == 0) {
159812854Sgabeblack@google.com            nd = nsl / BITS_PER_DIGIT; // No need to use DIV_CEIL(nsl).
159912854Sgabeblack@google.com            nsl = 0;
160012854Sgabeblack@google.com        } else {
160112854Sgabeblack@google.com            nd = DIV_CEIL(nsl) - 1;
160212854Sgabeblack@google.com            nsl -= nd * BITS_PER_DIGIT;
160312854Sgabeblack@google.com        }
160412854Sgabeblack@google.com
160512854Sgabeblack@google.com        if (nd) {
160612854Sgabeblack@google.com            // Shift left for nd digits.
160712854Sgabeblack@google.com            for (int j = ulen - 1; j >= nd; --j)
160812854Sgabeblack@google.com                u[j] = u[j - nd];
160912854Sgabeblack@google.com
161012854Sgabeblack@google.com            vec_zero(sc_min(nd, ulen), u);
161112854Sgabeblack@google.com        }
161212854Sgabeblack@google.com        if (nsl == 0)
161312854Sgabeblack@google.com            return;
161412854Sgabeblack@google.com    }
161512854Sgabeblack@google.com
161612854Sgabeblack@google.com    // Shift left if nsl < BITS_PER_DIGIT.
161712854Sgabeblack@google.com    sc_digit *uiter = u;
161812854Sgabeblack@google.com    sc_digit *uend = uiter + ulen;
161912854Sgabeblack@google.com
162012854Sgabeblack@google.com    int nsr = BITS_PER_DIGIT - nsl;
162112854Sgabeblack@google.com    sc_digit mask = one_and_ones(nsr);
162212854Sgabeblack@google.com
162312854Sgabeblack@google.com    sc_digit carry = 0;
162412854Sgabeblack@google.com
162512854Sgabeblack@google.com    while (uiter < uend) {
162612854Sgabeblack@google.com        sc_digit uval = (*uiter);
162712854Sgabeblack@google.com        (*uiter++) = (((uval & mask) << nsl) | carry);
162812854Sgabeblack@google.com        carry = uval >> nsr;
162912854Sgabeblack@google.com    }
163012854Sgabeblack@google.com
163112854Sgabeblack@google.com    if (uiter < uend)
163212854Sgabeblack@google.com        (*uiter) = carry;
163312854Sgabeblack@google.com}
163412854Sgabeblack@google.com
163512854Sgabeblack@google.com// Set u >>= nsr.
163612854Sgabeblack@google.com// If nsr is negative, it is ignored.
163712854Sgabeblack@google.comvoid
163812854Sgabeblack@google.comvec_shift_right(int ulen, sc_digit *u, int nsr, sc_digit fill)
163912854Sgabeblack@google.com{
164012854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
164112854Sgabeblack@google.com    sc_assert((ulen > 0) && (u != NULL));
164212854Sgabeblack@google.com#endif
164312854Sgabeblack@google.com
164412854Sgabeblack@google.com    // fill is usually either 0 or DIGIT_MASK; it can be any value.
164512854Sgabeblack@google.com    if (nsr <= 0)
164612854Sgabeblack@google.com        return;
164712854Sgabeblack@google.com
164812854Sgabeblack@google.com    // Shift right whole digits if nsr is large enough.
164912854Sgabeblack@google.com    if (nsr >= (int) BITS_PER_DIGIT) {
165012854Sgabeblack@google.com        int nd;
165112854Sgabeblack@google.com        if (nsr % BITS_PER_DIGIT == 0) {
165212854Sgabeblack@google.com            nd = nsr / BITS_PER_DIGIT;
165312854Sgabeblack@google.com            nsr = 0;
165412854Sgabeblack@google.com        } else {
165512854Sgabeblack@google.com            nd = DIV_CEIL(nsr) - 1;
165612854Sgabeblack@google.com            nsr -= nd * BITS_PER_DIGIT;
165712854Sgabeblack@google.com        }
165812854Sgabeblack@google.com
165912854Sgabeblack@google.com        if (nd) {
166012854Sgabeblack@google.com            // Shift right for nd digits.
166112854Sgabeblack@google.com            for (int j = 0; j < (ulen - nd); ++j)
166212854Sgabeblack@google.com                u[j] = u[j + nd];
166312854Sgabeblack@google.com
166412854Sgabeblack@google.com            if (fill) {
166512854Sgabeblack@google.com                for (int j = ulen - sc_min( nd, ulen ); j < ulen; ++j)
166612854Sgabeblack@google.com                    u[j] = fill;
166712854Sgabeblack@google.com            } else {
166812854Sgabeblack@google.com                vec_zero(ulen - sc_min( nd, ulen ), ulen, u);
166912854Sgabeblack@google.com            }
167012854Sgabeblack@google.com        }
167112854Sgabeblack@google.com        if (nsr == 0)
167212854Sgabeblack@google.com          return;
167312854Sgabeblack@google.com    }
167412854Sgabeblack@google.com
167512854Sgabeblack@google.com    // Shift right if nsr < BITS_PER_DIGIT.
167612854Sgabeblack@google.com    sc_digit *ubegin = u;
167712854Sgabeblack@google.com    sc_digit *uiter = (ubegin + ulen);
167812854Sgabeblack@google.com
167912854Sgabeblack@google.com    int nsl = BITS_PER_DIGIT - nsr;
168012854Sgabeblack@google.com    sc_digit mask = one_and_ones(nsr);
168112854Sgabeblack@google.com
168212854Sgabeblack@google.com    sc_digit carry = (fill & mask) << nsl;
168312854Sgabeblack@google.com
168412854Sgabeblack@google.com    while (ubegin < uiter) {
168512854Sgabeblack@google.com        sc_digit uval = (*--uiter);
168612854Sgabeblack@google.com        (*uiter) = (uval >> nsr) | carry;
168712854Sgabeblack@google.com        carry = (uval & mask) << nsl;
168812854Sgabeblack@google.com    }
168912854Sgabeblack@google.com}
169012854Sgabeblack@google.com
169112854Sgabeblack@google.com
169212854Sgabeblack@google.com// Let u[l..r], where l and r are left and right bit positions
169312854Sgabeblack@google.com// respectively, be equal to its mirror image.
169412854Sgabeblack@google.comvoid
169512854Sgabeblack@google.comvec_reverse(int unb, int und, sc_digit *ud, int l, int r)
169612854Sgabeblack@google.com{
169712854Sgabeblack@google.com#ifdef DEBUG_SYSTEMC
169812854Sgabeblack@google.com    sc_assert((unb > 0) && (und > 0) && (ud != NULL));
169912854Sgabeblack@google.com    sc_assert((0 <= r) && (r <= l) && (l < unb));
170012854Sgabeblack@google.com#endif
170112854Sgabeblack@google.com
170212854Sgabeblack@google.com    if (l < r) {
170312854Sgabeblack@google.com        std::stringstream msg;
170412854Sgabeblack@google.com        msg << "vec_reverse( int, int, sc_digit*, int l, int r ) : " <<
170512854Sgabeblack@google.com               "l = " << l << " < r = " << r << " is not valid",
170612854Sgabeblack@google.com        SC_REPORT_ERROR("conversion failed", msg.str().c_str());
170712854Sgabeblack@google.com        return;
170812854Sgabeblack@google.com    }
170912854Sgabeblack@google.com
171012854Sgabeblack@google.com    // Make sure that l and r are within bounds.
171112854Sgabeblack@google.com    r = sc_max(r, 0);
171212854Sgabeblack@google.com    l = sc_min(l, unb - 1);
171312854Sgabeblack@google.com
171412854Sgabeblack@google.com    // Allocate memory for processing.
171512854Sgabeblack@google.com#ifdef SC_MAX_NBITS
171612854Sgabeblack@google.com    sc_digit d[MAX_NDIGITS];
171712854Sgabeblack@google.com#else
171812854Sgabeblack@google.com    sc_digit *d = new sc_digit[und];
171912854Sgabeblack@google.com#endif
172012854Sgabeblack@google.com
172112854Sgabeblack@google.com    // d is a copy of ud.
172212854Sgabeblack@google.com    vec_copy(und, d, ud);
172312854Sgabeblack@google.com
172412854Sgabeblack@google.com    // Based on the value of the ith in d, find the value of the jth bit
172512854Sgabeblack@google.com    // in ud.
172612854Sgabeblack@google.com    for (int i = l, j = r; i >= r; --i, ++j) {
172712854Sgabeblack@google.com        if ((d[digit_ord(i)] & one_and_zeros(bit_ord(i))) != 0) // Test.
172812854Sgabeblack@google.com            ud[digit_ord(j)] |= one_and_zeros(bit_ord(j)); // Set.
172912854Sgabeblack@google.com        else
173012854Sgabeblack@google.com            ud[digit_ord(j)] &= ~(one_and_zeros(bit_ord(j))); // Clear.
173112854Sgabeblack@google.com    }
173212854Sgabeblack@google.com
173312854Sgabeblack@google.com#ifndef SC_MAX_NBITS
173412854Sgabeblack@google.com    delete [] d;
173512854Sgabeblack@google.com#endif
173612854Sgabeblack@google.com}
173712854Sgabeblack@google.com
173812854Sgabeblack@google.com#ifdef SC_MAX_NBITS
173912854Sgabeblack@google.comvoid test_bound_failed(int nb)
174012854Sgabeblack@google.com{
174112854Sgabeblack@google.com    std::stringstream msg;
174212854Sgabeblack@google.com    msg << "test_bound( int nb ) : "
174312854Sgabeblack@google.com           "nb = " << nb << " > SC_MAX_NBITS = " << SC_MAX_NBITS <<
174412854Sgabeblack@google.com           "  is not valid";
174512854Sgabeblack@google.com    SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str());
174612854Sgabeblack@google.com}
174712854Sgabeblack@google.com#endif // SC_MAX_NBITS
174812854Sgabeblack@google.com
174912854Sgabeblack@google.com} // namespace sc_dt
1750