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