summaryrefslogtreecommitdiff
path: root/src/systemc/dt/int/sc_nbutils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/dt/int/sc_nbutils.cc')
-rw-r--r--src/systemc/dt/int/sc_nbutils.cc1749
1 files changed, 1749 insertions, 0 deletions
diff --git a/src/systemc/dt/int/sc_nbutils.cc b/src/systemc/dt/int/sc_nbutils.cc
new file mode 100644
index 000000000..df7cc554d
--- /dev/null
+++ b/src/systemc/dt/int/sc_nbutils.cc
@@ -0,0 +1,1749 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ sc_nbutils.cpp -- External and friend functions for both sc_signed and
+ sc_unsigned classes.
+
+ Original Author: Ali Dasdan, Synopsys, Inc.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ MODIFICATION LOG - modifiers, enter your name, affiliation, date and
+ changes you are making here.
+
+ Name, Affiliation, Date:
+ Description of Modification:
+
+ *****************************************************************************/
+
+
+// $Log: sc_nbutils.cpp,v $
+// Revision 1.4 2011/08/24 22:05:46 acg
+// Torsten Maehne: initialization changes to remove warnings.
+//
+// Revision 1.3 2011/02/18 20:19:15 acg
+// Andy Goodrich: updating Copyright notice.
+//
+// Revision 1.2 2007/11/04 21:26:40 acg
+// Andy Goodrich: added a buffer to the allocation of the q array to address
+// an issue with references outside the array by 1 byte detected by valgrind.
+//
+// Revision 1.1.1.1 2006/12/15 20:20:05 acg
+// SystemC 2.3
+//
+// Revision 1.3 2006/01/13 18:49:32 acg
+// Added $Log command so that CVS check in comments are reproduced in the
+// source.
+//
+
+#include <cctype>
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+
+#include "systemc/ext/dt/int/sc_nbutils.hh"
+#include "systemc/ext/utils/functions.hh"
+
+namespace sc_dt
+{
+
+// only used within vec_from_str (non-standard, deprecated)
+static inline void
+is_valid_base(sc_numrep base)
+{
+ switch (base) {
+ case SC_NOBASE: case SC_BIN:
+ case SC_OCT: case SC_DEC:
+ case SC_HEX:
+ break;
+ case SC_BIN_US: case SC_BIN_SM:
+ case SC_OCT_US: case SC_OCT_SM:
+ case SC_HEX_US: case SC_HEX_SM:
+ case SC_CSD:
+ SC_REPORT_ERROR("not implemented",
+ "is_valid_base( sc_numrep base ) : "
+ "bases SC_CSD, or ending in _US and _SM are "
+ "not supported");
+ break;
+ default:
+ std::stringstream msg;
+ msg << "is_valid_base( sc_numrep base ) : base = " << base <<
+ " is not valid";
+ SC_REPORT_ERROR("value is not valid", msg.str().c_str() );
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ENUM : sc_numrep
+//
+// Enumeration of number representations for character string conversion.
+// ----------------------------------------------------------------------------
+
+const std::string
+to_string(sc_numrep numrep)
+{
+ switch (numrep) {
+#define CASE_ENUM2STR(Value) case Value: return #Value
+
+ CASE_ENUM2STR(SC_DEC);
+
+ CASE_ENUM2STR(SC_BIN);
+ CASE_ENUM2STR(SC_BIN_US);
+ CASE_ENUM2STR(SC_BIN_SM);
+
+ CASE_ENUM2STR(SC_OCT);
+ CASE_ENUM2STR(SC_OCT_US);
+ CASE_ENUM2STR(SC_OCT_SM);
+
+ CASE_ENUM2STR(SC_HEX);
+ CASE_ENUM2STR(SC_HEX_US);
+ CASE_ENUM2STR(SC_HEX_SM);
+
+ CASE_ENUM2STR(SC_CSD);
+
+#undef CASE_ENUM2STR
+
+ default:
+ return "unknown";
+ }
+}
+
+// ----------------------------------------------------------------------------
+// SECTION: General utility functions.
+// ----------------------------------------------------------------------------
+
+// Return the number of characters to advance the source of c. This
+// function implements one move of the FSM to parse the following
+// regular expressions. Error checking is done in the caller.
+
+small_type
+fsm_move(char c, small_type &b, small_type &s, small_type &state)
+{
+ // Possible regular expressions (REs):
+ // Let N = any digit depending on the base.
+ // 1. [0|1|..|9]N*
+ // 2. [+|-][0|1|..|9]N*
+ // 3. 0[b|B|d|D|o|O|x|X][0|1|..|F]N*
+ // 4. [+|-]?0[b|B|d|D|o|O|x|X][0|1|..|F]N*
+ //
+ // The finite state machine (FMS) to parse these regular expressions
+ // has 4 states, 0 to 3. 0 is the initial state and 3 is the final
+ // state.
+ //
+ // Default sign = SC_POS, default base = NB_DEFAULT_BASE.
+
+ switch (state) {
+ case 0: // The initial state.
+ switch (c) {
+ case '0': s = SC_POS; state = 1; return 0; // RE 1 or 3
+ case '+': s = SC_POS; state = 2; return 1; // RE 2
+ case '-': s = SC_NEG; state = 2; return 1; // RE 2
+ default:
+ s = SC_POS; b = NB_DEFAULT_BASE; state = 3; return 0; // RE 1
+ }
+ // break; //unreachable code
+ case 1: // 0...
+ switch (c) {
+ case 'x': case 'X': b = SC_HEX; state = 3; return 2; // RE 3 or 4
+ case 'd': case 'D': b = SC_DEC; state = 3; return 2; // RE 3 or 4
+ case 'o': case 'O': b = SC_OCT; state = 3; return 2; // RE 3 or 4
+ case 'b': case 'B': b = SC_BIN; state = 3; return 2; // RE 3 or 4
+ default: b = NB_DEFAULT_BASE; state = 3; return 0; // RE 1
+ }
+ // break; //unreachable code
+ case 2: // +... or -...
+ switch (c) {
+ case '0': state = 1; return 0; // RE 2 or 4
+ default: b = NB_DEFAULT_BASE; state = 3; return 0; // RE 2
+ }
+ // break; //unreachable code
+ case 3: // The final state.
+ break;
+ default:
+ // Any other state is not possible.
+ sc_assert((0 <= state) && (state <= 3));
+ } // switch
+ return 0;
+}
+
+
+// Get base b and sign s of the number in the char string v. Return a
+// pointer to the first char after the point where b and s are
+// determined or where the end of v is reached. The input string v has
+// to be null terminated.
+const char *
+get_base_and_sign(const char *v, small_type &b, small_type &s)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert(v != NULL);
+#endif
+ const small_type STATE_START = 0;
+ const small_type STATE_FINISH = 3;
+
+ // Default sign = SC_POS, default base = 10.
+ s = SC_POS;
+ b = NB_DEFAULT_BASE;
+
+ small_type state = STATE_START;
+ small_type nskip = 0; // Skip that many chars.
+ const char *u = v;
+
+ while (*u) {
+ if (isspace(*u)) { // Skip white space.
+ ++u;
+ } else {
+ nskip += fsm_move(*u, b, s, state);
+ if (state == STATE_FINISH)
+ break;
+ else
+ ++u;
+ }
+ }
+
+ // Test to see if the above loop executed more than it should
+ // have. The max number of skipped chars is equal to the length of
+ // the longest format specifier, e.g., "-0x".
+ sc_assert(nskip <= 3);
+
+ v += nskip;
+
+ // Handles empty strings or strings without any digits after the
+ // base or base and sign specifier.
+ if (*v == '\0') {
+ static const char msg[] =
+ "get_base_and_sign( const char* v, small_type&, small_type& ) : "
+ "v = \"\" is not valid";
+ SC_REPORT_ERROR("conversion failed", msg);
+ }
+ return v;
+}
+
+//-----------------------------------------------------------------------------
+//"parse_binary_bits"
+//
+// This function parses the supplied string into the supplied vector as a
+// right justified bit value.
+// src_p -> character string representing the bits to be parsed.
+// dst_n = number of words in data_p and ctrl_p.
+// data_p -> words w/BITS_PER_DIGIT bits to receive the value's data bits.
+// ctrl_p -> words w/BITS_PER_DIGIT bits to receive the value's control
+// bits, or zero.
+// Result is true if value was non-zero.
+//-----------------------------------------------------------------------------
+void
+parse_binary_bits(const char *src_p, int dst_n,
+ sc_digit *data_p, sc_digit *ctrl_p)
+{
+ int bit_i; // Number of bit now processing.
+ sc_digit ctrl; // Control word now assembling.
+ sc_digit data; // Data word now assembling.
+ int delta_n; // src_n - dst_n*BITS_PER_DIGIT.
+ int src_i; // Index in src_p now accessing (left to right).
+ int src_n; // Length of source that is left in bits.
+ int word_i; // Bit within word now accessing (left to right).
+
+ // MAKE SURE WE HAVE A STRING TO PARSE:
+ if (src_p == 0) {
+ SC_REPORT_ERROR("conversion failed",
+ "character string is zero");
+ return;
+ }
+ if (*src_p == 0) {
+ SC_REPORT_ERROR("conversion failed",
+ "character string is empty");
+ return;
+ }
+
+
+ // INDEX INTO THE SOURCE TO A DEPTH THAT WILL ACCOMODATE OUR SIZE:
+ //
+ // If the source is smaller than our value initialize our value to zero.
+
+ src_n = strlen(src_p);
+ delta_n = src_n - (dst_n*BITS_PER_DIGIT);
+ if (delta_n > 0) {
+ src_p = &src_p[delta_n];
+ src_n -= delta_n;
+ } else {
+ for (word_i = 0; word_i < dst_n; word_i++)
+ data_p[word_i] = 0;
+ if (ctrl_p)
+ for (word_i = 0; word_i < dst_n; word_i++)
+ ctrl_p[word_i] = 0;
+ }
+
+ // LOOP OVER THE SOURCE ASSEMBLING WORDS AND PLACING THEM IN OUR VALUE:
+ //
+ // We stride right to left through the source in BITS_PER_DIGIT chunks.
+ // Each of those chunks is processed from left to right a bit at a time.
+ // We process the high order word specially, since there are less bits.
+ src_n = src_n - BITS_PER_DIGIT;
+ for (word_i=0; word_i < dst_n; word_i++) {
+ src_i = src_n;
+
+ // PARTIAL LAST WORD TO ASSEMBLE:
+ if (src_i < 0) {
+ src_n += BITS_PER_DIGIT;
+ data = 0;
+ ctrl = 0;
+ for (src_i = 0; src_i < src_n; src_i++) {
+ ctrl = ctrl << 1;
+ data = data << 1;
+ switch (src_p[src_i]) {
+ case 'X':
+ case 'x': ctrl = ctrl | 1; data = data | 1; break;
+ case '1': data = data | 1; break;
+ case 'Z':
+ case 'z': ctrl = ctrl | 1; break;
+ case '0': break;
+ default:
+ {
+ std::stringstream msg;
+ msg << "character string '" << src_p <<
+ "' is not valid";
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return;
+ }
+ break;
+ }
+ }
+ if (ctrl_p)
+ ctrl_p[word_i] = ctrl;
+ data_p[word_i] = data;
+ break;
+ }
+
+ // FULL WORD TO BE ASSEMBLED:
+ ctrl = 0;
+ data = 0;
+ for (bit_i = 0; bit_i < BITS_PER_DIGIT; bit_i++) {
+ ctrl = ctrl << 1;
+ data = data << 1;
+ switch (src_p[src_i++]) {
+ case 'X':
+ case 'x': ctrl = ctrl | 1; data = data | 1; break;
+ case '1': data = data | 1; break;
+ case 'Z':
+ case 'z': ctrl = ctrl | 1; break;
+ case '0': break;
+ default:
+ {
+ std::stringstream msg;
+ msg << "character string '" << src_p <<
+ "' is not valid";
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return;
+ }
+ break;
+ }
+ }
+ if (ctrl_p)
+ ctrl_p[word_i] = ctrl;
+ data_p[word_i] = data;
+ src_n = src_n - BITS_PER_DIGIT;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//"parse_hex_bits"
+//
+// This function parses the supplied string into the supplied vector as a
+// right justified bit value.
+// src_p -> character string representing the bits to be parsed.
+// dst_n = number of words in data_p and ctrl_p.
+// data_p -> words w/32 bits to receive the value's data bits.
+// ctrl_p -> words w/32 bits to receive the value's control bits,
+// or zero.
+// Result is true if value was non-zero.
+//-----------------------------------------------------------------------------
+void
+parse_hex_bits(const char *src_p, int dst_n,
+ sc_digit *data_p, sc_digit *ctrl_p)
+{
+ sc_digit ctrl; // Control word now assembling.
+ sc_digit data; // Data word now assembling.
+ int delta_n; // src_n - dst_n*BITS_PER_DIGIT.
+ int digit_i; // Number of digit now processing.
+ int src_i; // Index in src_p now accessing (left to right).
+ int src_n; // Length of source that is left in bits.
+ int word_i; // Bit within word now accessing (left to right).
+
+ // MAKE SURE WE HAVE A STRING TO PARSE:
+ if (src_p == 0) {
+ SC_REPORT_ERROR("conversion failed",
+ "character string is zero");
+ return;
+ }
+ if (*src_p == 0) {
+ SC_REPORT_ERROR("conversion failed",
+ "character string is empty");
+ return;
+ }
+
+ // INDEX INTO THE SOURCE TO A DEPTH THAT WILL ACCOMODATE OUR SIZE:
+ //
+ // If the source is smaller than our value initialize our value to zero.
+ src_n = strlen(src_p);
+ delta_n = src_n - (dst_n*8);
+ if (delta_n > 0) {
+ src_p = &src_p[delta_n];
+ src_n -= delta_n;
+ } else {
+ for (word_i = 0; word_i < dst_n; word_i++)
+ data_p[word_i] = 0;
+ if (ctrl_p)
+ for (word_i = 0; word_i < dst_n; word_i++)
+ ctrl_p[word_i] = 0;
+ }
+
+ // LOOP OVER THE SOURCE ASSEMBLING WORDS AND PLACING THEM IN OUR VALUE:
+ //
+ // We stride right to left through the source in BITS_PER_DIGIT chunks.
+ // Each of those chunks is processed from left to right a bit at a time.
+ // We process the high order word specially, since there are less bits.
+ src_n = src_n - 8;
+ for (word_i = 0; word_i < dst_n; word_i++) {
+ src_i = src_n;
+
+ // PARTIAL LAST WORD TO ASSEMBLE:
+ if (src_i < 0) {
+ src_n += 8;
+ data = 0;
+ ctrl = 0;
+ for (src_i = 0; src_i < src_n; src_i++) {
+ ctrl = ctrl << 4;
+ data = data << 4;
+ switch (src_p[src_i]) {
+ case 'X':
+ case 'x': ctrl = ctrl | 15; data = data | 15; break;
+ case 'F':
+ case 'f': data = data | 15; break;
+ case 'E':
+ case 'e': data = data | 14; break;
+ case 'D':
+ case 'd': data = data | 13; break;
+ case 'C':
+ case 'c': data = data | 12; break;
+ case 'B':
+ case 'b': data = data | 11; break;
+ case 'A':
+ case 'a': data = data | 10; break;
+ case '9': data = data | 9; break;
+ case '8': data = data | 8; break;
+ case '7': data = data | 7; break;
+ case '6': data = data | 6; break;
+ case '5': data = data | 5; break;
+ case '4': data = data | 4; break;
+ case '3': data = data | 3; break;
+ case '2': data = data | 2; break;
+ case '1': data = data | 1; break;
+ case '0': break;
+ case 'Z':
+ case 'z': ctrl = ctrl | 15; break;
+ default:
+ {
+ std::stringstream msg;
+ msg << "character string '" << src_p <<
+ "' is not valid";
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return;
+ }
+ break;
+ }
+ }
+ if (ctrl_p)
+ ctrl_p[word_i] = ctrl;
+ data_p[word_i] = data;
+ break;
+ }
+
+ // FULL WORD TO BE ASSEMBLED:
+ ctrl = 0;
+ data = 0;
+ for (digit_i = 0; digit_i < 8; digit_i++) {
+ ctrl = ctrl << 4;
+ data = data << 4;
+ switch (src_p[src_i++]) {
+ case 'X':
+ case 'x': ctrl = ctrl | 15; data = data | 15; break;
+ case 'F':
+ case 'f': data = data | 15; break;
+ case 'E':
+ case 'e': data = data | 14; break;
+ case 'D':
+ case 'd': data = data | 13; break;
+ case 'C':
+ case 'c': data = data | 12; break;
+ case 'B':
+ case 'b': data = data | 11; break;
+ case 'A':
+ case 'a': data = data | 10; break;
+ case '9': data = data | 9; break;
+ case '8': data = data | 8; break;
+ case '7': data = data | 7; break;
+ case '6': data = data | 6; break;
+ case '5': data = data | 5; break;
+ case '4': data = data | 4; break;
+ case '3': data = data | 3; break;
+ case '2': data = data | 2; break;
+ case '1': data = data | 1; break;
+ case '0': break;
+ case 'Z':
+ case 'z': ctrl = ctrl | 15; break;
+ default:
+ {
+ std::stringstream msg;
+ msg << "character string '" << src_p << "' is not valid";
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str() );
+ return;
+ }
+ break;
+ }
+ }
+ if (ctrl_p)
+ ctrl_p[word_i] = ctrl;
+ data_p[word_i] = data;
+ src_n = src_n - BITS_PER_DIGIT;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// SECTION: Utility functions involving unsigned vectors.
+// ----------------------------------------------------------------------------
+
+// Read u from a null terminated char string v. Note that operator>>
+// in sc_nbcommon.cpp is similar to this function.
+small_type
+vec_from_str(int unb, int und, sc_digit *u, const char *v, sc_numrep base)
+{
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert((unb > 0) && (und > 0) && (u != NULL));
+ sc_assert(v != NULL);
+#endif
+ is_valid_base(base);
+
+ small_type b, s; // base and sign.
+
+ v = get_base_and_sign(v, b, s);
+
+ if (base != SC_NOBASE) {
+ if (b == NB_DEFAULT_BASE) {
+ b = base;
+ } else {
+ std::stringstream msg;
+ msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
+ "sc_numrep base ) : base = " << base <<
+ " does not match the default base";
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return 0;
+ }
+ }
+
+ vec_zero(und, u);
+
+ char c;
+ for (; (c = *v); ++v) {
+ if (isalnum(c)) {
+ small_type val; // Numeric value of a char.
+
+ if (isalpha(c)) // Hex digit.
+ val = toupper(c) - 'A' + 10;
+ else
+ val = c - '0';
+
+ if (val >= b) {
+ std::stringstream msg;
+ msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
+ "sc_numrep base ) : '" << *v << "' is not a valid " <<
+ "digit in base " << b;
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return 0;
+ }
+
+ // digit = digit * b + val;
+ vec_mul_small_on(und, u, b);
+
+ if (val)
+ vec_add_small_on(und, u, val);
+ } else {
+ std::stringstream msg;
+ msg << "vec_from_str( int, int, sc_digit*, const char*, " <<
+ "sc_numrep base ) : '" << *v << "' is not a valid " <<
+ "digit in base " << b;
+ SC_REPORT_ERROR("conversion failed",
+ msg.str().c_str());
+ return 0;
+ }
+ }
+
+ return convert_signed_SM_to_2C_to_SM(s, unb, und, u);
+}
+
+
+// All vec_ functions assume that the vector to hold the result,
+// called w, has sufficient length to hold the result. For efficiency
+// reasons, we do not test whether or not we are out of bounds.
+
+// Compute w = u + v, where w, u, and v are vectors.
+// - ulen >= vlen
+// - wlen >= sc_max(ulen, vlen) + 1
+void
+vec_add(int ulen, const sc_digit *u, int vlen, const sc_digit *v, sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(w != NULL);
+ sc_assert(ulen >= vlen);
+#endif
+
+ const sc_digit *uend = (u + ulen);
+ const sc_digit *vend = (v + vlen);
+
+ sc_digit carry = 0; // Also used as sum to save space.
+
+ // Add along the shorter v.
+ while (v < vend) {
+ carry += (*u++) + (*v++);
+ (*w++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+ // Propagate the carry.
+ while (carry && (u < uend)) {
+ carry = (*u++) + 1;
+ (*w++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+ // Copy the rest of u to the result.
+ while (u < uend)
+ (*w++) = (*u++);
+
+ // Propagate the carry if it is still 1.
+ if (carry)
+ (*w) = 1;
+}
+
+
+// Compute u += v, where u and v are vectors.
+// - ulen >= vlen
+void
+vec_add_on(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (ubegin != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(ulen >= vlen);
+#endif
+
+ sc_digit *u = ubegin;
+ const sc_digit *uend = (u + ulen);
+ const sc_digit *vend = (v + vlen);
+
+ sc_digit carry = 0; // Also used as sum to save space.
+
+ // Add along the shorter v.
+ while (v < vend) {
+ carry += (*u) + (*v++);
+ (*u++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+ // Propagate the carry.
+ while (carry && (u < uend)) {
+ carry = (*u) + 1;
+ (*u++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+#ifdef DEBUG_SYSTEMC
+ if (carry != 0) {
+ SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
+ "vec_add_on( int, sc_digit*, int, const "
+ "sc_digit* ) : "
+ "result of addition is wrapped around");
+ }
+#endif
+}
+
+
+// Compute u += v, where u and v are vectors.
+// - ulen < vlen
+void
+vec_add_on2(int ulen, sc_digit *ubegin, int,
+#ifdef DEBUG_SYSTEMC
+ vlen,
+#endif
+ const sc_digit *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (ubegin != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(ulen < vlen);
+#endif
+
+ sc_digit *u = ubegin;
+ const sc_digit *uend = (u + ulen);
+
+ sc_digit carry = 0; // Also used as sum to save space.
+
+ // Add along the shorter u.
+ while (u < uend) {
+ carry += (*u) + (*v++);
+ (*u++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+#ifdef DEBUG_SYSTEMC
+ if (carry != 0) {
+ SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
+ "vec_add_on2( int, sc_digit*, int, const "
+ "sc_digit* ) : "
+ "result of addition is wrapped around");
+ }
+#endif
+}
+
+
+// Compute w = u + v, where w and u are vectors, and v is a scalar.
+void
+vec_add_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert(w != NULL);
+#endif
+
+ const sc_digit *uend = (u + ulen);
+
+ // Add along the shorter v.
+ sc_digit carry = (*u++) + v;
+ (*w++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+
+ // Propagate the carry.
+ while (carry && (u < uend)) {
+ carry = (*u++) + 1;
+ (*w++) = carry & DIGIT_MASK;
+ carry >>= BITS_PER_DIGIT;
+ }
+
+ // Copy the rest of u to the result.
+ while (u < uend)
+ (*w++) = (*u++);
+
+ // Propagate the carry if it is still 1.
+ if (carry)
+ (*w) = 1;
+}
+
+// Compute u += v, where u is vectors, and v is a scalar.
+void
+vec_add_small_on(int ulen, sc_digit *u, sc_digit v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+#endif
+
+ int i = 0;
+
+ while (v && (i < ulen)) {
+ v += u[i];
+ u[i++] = v & DIGIT_MASK;
+ v >>= BITS_PER_DIGIT;
+ }
+
+#ifdef DEBUG_SYSTEMC
+ if (v != 0) {
+ SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
+ "vec_add_small_on( int, sc_digit*, unsigned "
+ "long ) : "
+ "result of addition is wrapped around");
+ }
+#endif
+}
+
+// Compute w = u - v, where w, u, and v are vectors.
+// - ulen >= vlen
+// - wlen >= sc_max(ulen, vlen)
+void
+vec_sub(int ulen, const sc_digit *u, int vlen, const sc_digit *v, sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(w != NULL);
+ sc_assert(ulen >= vlen);
+#endif
+
+ const sc_digit *uend = (u + ulen);
+ const sc_digit *vend = (v + vlen);
+
+ sc_digit borrow = 0; // Also used as diff to save space.
+
+ // Subtract along the shorter v.
+ while (v < vend) {
+ borrow = ((*u++) + DIGIT_RADIX) - (*v++) - borrow;
+ (*w++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+ // Propagate the borrow.
+ while (borrow && (u < uend)) {
+ borrow = ((*u++) + DIGIT_RADIX) - 1;
+ (*w++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(borrow == 0);
+#endif
+
+ // Copy the rest of u to the result.
+ while (u < uend)
+ (*w++) = (*u++);
+}
+
+// Compute u = u - v, where u and v are vectors.
+// - u > v
+// - ulen >= vlen
+void
+vec_sub_on(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (ubegin != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(ulen >= vlen);
+#endif
+
+ sc_digit *u = ubegin;
+ const sc_digit *uend = (u + ulen);
+ const sc_digit *vend = (v + vlen);
+
+ sc_digit borrow = 0; // Also used as diff to save space.
+
+ // Subtract along the shorter v.
+ while (v < vend) {
+ borrow = ((*u) + DIGIT_RADIX) - (*v++) - borrow;
+ (*u++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+ // Propagate the borrow.
+ while (borrow && (u < uend)) {
+ borrow = ((*u) + DIGIT_RADIX) - 1;
+ (*u++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(borrow == 0);
+#endif
+}
+
+// Compute u = v - u, where u and v are vectors.
+// - v > u
+// - ulen <= vlen or ulen > ulen
+void
+vec_sub_on2(int ulen, sc_digit *ubegin, int vlen, const sc_digit *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (ubegin != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+#endif
+
+ sc_digit *u = ubegin;
+ const sc_digit *uend = (u + sc_min(ulen, vlen));
+
+ sc_digit borrow = 0; // Also used as diff to save space.
+
+ // Subtract along the shorter u.
+ while (u < uend) {
+ borrow = ((*v++) + DIGIT_RADIX) - (*u) - borrow;
+ (*u++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+#ifdef DEBUG_SYSTEMC
+ if (borrow != 0) {
+ SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
+ "vec_sub_on2( int, sc_digit*, int, const "
+ "sc_digit* ) : "
+ "result of subtraction is wrapped around");
+ }
+#endif
+}
+
+// Compute w = u - v, where w and u are vectors, and v is a scalar.
+void
+vec_sub_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert(ulen > 0);
+ sc_assert(u != NULL);
+#endif
+
+ const sc_digit *uend = (u + ulen);
+
+ // Add along the shorter v.
+ sc_digit borrow = ((*u++) + DIGIT_RADIX) - v;
+ (*w++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+
+ // Propagate the borrow.
+ while (borrow && (u < uend)) {
+ borrow = ((*u++) + DIGIT_RADIX) - 1;
+ (*w++) = borrow & DIGIT_MASK;
+ borrow = 1 - (borrow >> BITS_PER_DIGIT);
+ }
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(borrow == 0);
+#endif
+
+ // Copy the rest of u to the result.
+ while (u < uend)
+ (*w++) = (*u++);
+}
+
+
+// Compute u -= v, where u is vectors, and v is a scalar.
+void
+vec_sub_small_on(int ulen, sc_digit *u, sc_digit v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+#endif
+
+ for (int i = 0; i < ulen; ++i) {
+ v = (u[i] + DIGIT_RADIX) - v;
+ u[i] = v & DIGIT_MASK;
+ v = 1 - (v >> BITS_PER_DIGIT);
+ }
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(v == 0);
+#endif
+}
+
+// Compute w = u * v, where w, u, and v are vectors.
+void
+vec_mul(int ulen, const sc_digit *u, int vlen, const sc_digit *vbegin,
+ sc_digit *wbegin)
+{
+
+ /* Consider u = Ax + B and v = Cx + D where x is equal to
+ HALF_DIGIT_RADIX. In other words, A is the higher half of u and
+ B is the lower half of u. The interpretation for v is
+ similar. Then, we have the following picture:
+
+ u_h u_l
+ u: -------- --------
+ A B
+
+ v_h v_l
+ v: -------- --------
+ C D
+
+ result (d):
+ carry_before: -------- --------
+ carry_h carry_l
+ result_before: -------- -------- -------- --------
+ R1_h R1_l R0_h R0_l
+ -------- --------
+ BD_h BD_l
+ -------- --------
+ AD_h AD_l
+ -------- --------
+ BC_h BC_l
+ -------- --------
+ AC_h AC_l
+ result_after: -------- -------- -------- --------
+ R1_h' R1_l' R0_h' R0_l'
+
+ prod_l = R0_h|R0_l + B * D + 0|carry_l
+ = R0_h|R0_l + BD_h|BD_l + 0|carry_l
+
+ prod_h = A * D + B * C + high_half(prod_l) + carry_h
+ = AD_h|AD_l + BC_h|BC_l + high_half(prod_l) + 0|carry_h
+
+ carry = A * C + high_half(prod_h)
+ = AC_h|AC_l + high_half(prod_h)
+
+ R0_l' = low_half(prod_l)
+
+ R0_h' = low_half(prod_h)
+
+ R0 = high_half(prod_h)|low_half(prod_l)
+
+ where '|' is the concatenation operation and the suffixes 0 and 1
+ show the iteration number, i.e., 0 is the current iteration and 1
+ is the next iteration.
+
+ NOTE: sc_max(prod_l, prod_h, carry) <= 2 * x^2 - 1, so any
+ of these numbers can be stored in a digit.
+
+ NOTE: low_half(u) returns the lower BITS_PER_HALF_DIGIT of u,
+ whereas high_half(u) returns the rest of the bits, which may
+ contain more bits than BITS_PER_HALF_DIGIT.
+ */
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (vbegin != NULL));
+ sc_assert(wbegin != NULL);
+#endif
+
+#define prod_h carry
+ const sc_digit *uend = (u + ulen);
+ const sc_digit *vend = (vbegin + vlen);
+
+ while (u < uend) {
+ sc_digit u_h = (*u++); // A|B
+ sc_digit u_l = low_half(u_h); // B
+ u_h = high_half(u_h); // A
+
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(u_h == (u_h & HALF_DIGIT_MASK));
+#endif
+ sc_digit carry = 0;
+ sc_digit *w = (wbegin++);
+ const sc_digit *v = vbegin;
+
+ while (v < vend) {
+ sc_digit v_h = (*v++); // C|D
+ sc_digit v_l = low_half(v_h); // D
+
+ v_h = high_half(v_h); // C
+
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(v_h == (v_h & HALF_DIGIT_MASK));
+#endif
+
+ sc_digit prod_l = (*w) + u_l * v_l + low_half(carry);
+ prod_h = u_h * v_l + u_l * v_h +
+ high_half(prod_l) + high_half(carry);
+ (*w++) = concat(low_half(prod_h), low_half(prod_l));
+ carry = u_h * v_h + high_half(prod_h);
+ }
+ (*w) = carry;
+ }
+#undef prod_h
+}
+
+// Compute w = u * v, where w and u are vectors, and v is a scalar.
+// - 0 < v < HALF_DIGIT_RADIX.
+void
+vec_mul_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert(w != NULL);
+ sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
+#endif
+
+#define prod_h carry
+
+ const sc_digit *uend = (u + ulen);
+ sc_digit carry = 0;
+ while (u < uend) {
+ sc_digit u_AB = (*u++);
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(high_half(u_AB) == high_half_masked(u_AB));
+#endif
+ sc_digit prod_l = v * low_half(u_AB) + low_half(carry);
+ prod_h = v * high_half(u_AB) + high_half(prod_l) + high_half(carry);
+ (*w++) = concat(low_half(prod_h), low_half(prod_l));
+ carry = high_half(prod_h);
+ }
+ (*w) = carry;
+#undef prod_h
+}
+
+// Compute u = u * v, where u is a vector, and v is a scalar.
+// - 0 < v < HALF_DIGIT_RADIX.
+void
+vec_mul_small_on(int ulen, sc_digit *u, sc_digit v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
+#endif
+
+#define prod_h carry
+ sc_digit carry = 0;
+ for (int i = 0; i < ulen; ++i) {
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(high_half(u[i]) == high_half_masked(u[i]));
+#endif
+ sc_digit prod_l = v * low_half(u[i]) + low_half(carry);
+ prod_h = v * high_half(u[i]) + high_half(prod_l) + high_half(carry);
+ u[i] = concat(low_half(prod_h), low_half(prod_l));
+ carry = high_half(prod_h);
+ }
+#undef prod_h
+
+#ifdef DEBUG_SYSTEMC
+ if (carry != 0) {
+ SC_REPORT_WARNING(sc_core::SC_ID_WITHOUT_MESSAGE_,
+ "vec_mul_small_on( int, sc_digit*, unsigned "
+ "long ) : "
+ "result of multiplication is wrapped around");
+ }
+#endif
+}
+
+// Compute w = u / v, where w, u, and v are vectors.
+// - u and v are assumed to have at least two digits as uchars.
+void
+vec_div_large(int ulen, const sc_digit *u, int vlen, const sc_digit *v,
+ sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(w != NULL);
+ sc_assert(BITS_PER_DIGIT >= 3 * BITS_PER_BYTE);
+#endif
+
+ // We will compute q = x / y where x = u and y = v. The reason for
+ // using x and y is that x and y are BYTE_RADIX copies of u and v,
+ // respectively. The use of BYTE_RADIX radix greatly simplifies the
+ // complexity of the division operation. These copies are also
+ // needed even when we use DIGIT_RADIX representation.
+
+ int xlen = BYTES_PER_DIGIT * ulen + 1;
+ int ylen = BYTES_PER_DIGIT * vlen;
+
+#ifdef SC_MAX_NBITS
+ uchar x[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
+ uchar y[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
+ uchar q[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
+#else
+ uchar *x = new uchar[xlen];
+ uchar *y = new uchar[ylen];
+ // valgrind complains about us accessing too far to so leave a buffer.
+ uchar *q = new uchar[(xlen - ylen) + 10];
+#endif
+
+ // q corresponds to w.
+
+ // Set (uchar) x = (sc_digit) u.
+ xlen = vec_to_char(ulen, u, xlen, x);
+
+ // Skip all the leading zeros in x.
+ while ((--xlen >= 0) && (! x[xlen]))
+ continue;
+ xlen++;
+
+ // Set (uchar) y = (sc_digit) v.
+ ylen = vec_to_char(vlen, v, ylen, y);
+
+ // Skip all the leading zeros in y.
+ while ((--ylen >= 0) && (! y[ylen]))
+ continue;
+ ylen++;
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(xlen > 1);
+ sc_assert(ylen > 1);
+#endif
+
+ // At this point, all the leading zeros are eliminated from x and y.
+
+ // Zero the last digit of x.
+ x[xlen] = 0;
+
+ // The first two digits of y.
+ sc_digit y2 = (y[ylen - 1] << BITS_PER_BYTE) + y[ylen - 2];
+
+ const sc_digit DOUBLE_BITS_PER_BYTE = 2 * BITS_PER_BYTE;
+
+ // Find each q[k].
+ for (int k = (xlen - ylen); k >= 0; --k) {
+ // qk is a guess for q[k] such that q[k] = qk or qk - 1.
+ sc_digit qk;
+
+ // Find qk by just using 2 digits of y and 3 digits of x. The
+ // following code assumes that sizeof(sc_digit) >= 3 BYTEs.
+ int k2 = k + ylen;
+
+ qk = ((x[k2] << DOUBLE_BITS_PER_BYTE) +
+ (x[k2 - 1] << BITS_PER_BYTE) + x[k2 - 2]) / y2;
+
+ if (qk >= BYTE_RADIX) // qk cannot be larger than the largest
+ qk = BYTE_RADIX - 1; // digit in BYTE_RADIX.
+
+ // q[k] = qk or qk - 1. The following if-statement determines which:
+ if (qk) {
+ uchar *xk = (x + k); // A shortcut for x[k].
+
+ // x = x - y * qk :
+ sc_digit carry = 0;
+
+ for (int i = 0; i < ylen; ++i) {
+ carry += y[i] * qk;
+ sc_digit diff = (xk[i] + BYTE_RADIX) - (carry & BYTE_MASK);
+ xk[i] = (uchar)(diff & BYTE_MASK);
+ carry = (carry >> BITS_PER_BYTE) +
+ (1 - (diff >> BITS_PER_BYTE));
+ }
+
+ // If carry, qk may be one too large.
+ if (carry) {
+ // 2's complement the last digit.
+ carry = (xk[ylen] + BYTE_RADIX) - carry;
+ xk[ylen] = (uchar)(carry & BYTE_MASK);
+ carry = 1 - (carry >> BITS_PER_BYTE);
+
+ if (carry) {
+
+ // qk was one too large, so decrement it.
+ --qk;
+
+ // Since qk was decreased by one, y must be added to x:
+ // x = x - y * (qk - 1) = x - y * qk + y = x_above + y.
+ carry = 0;
+
+ for (int i = 0; i < ylen; ++i) {
+ carry += xk[i] + y[i];
+ xk[i] = (uchar)(carry & BYTE_MASK);
+ carry >>= BITS_PER_BYTE;
+ }
+
+ if (carry)
+ xk[ylen] = (uchar)((xk[ylen] + 1) & BYTE_MASK);
+
+ } // second if carry
+ } // first if carry
+ } // if qk
+ q[k] = (uchar)qk;
+ } // for k
+
+ // Set (sc_digit) w = (uchar) q.
+ vec_from_char(xlen - ylen + 1, q, ulen, w);
+
+#ifndef SC_MAX_NBITS
+ delete [] x;
+ delete [] y;
+ delete [] q;
+#endif
+
+}
+
+// Compute w = u / v, where u and w are vectors, and v is a scalar.
+// - 0 < v < HALF_DIGIT_RADIX. Below, we rename w to q.
+void
+vec_div_small(int ulen, const sc_digit *u, sc_digit v, sc_digit *q)
+{
+ // Given (u = u_1u_2...u_n)_b = (q = q_1q_2...q_n) * v + r, where b
+ // is the base, and 0 <= r < v. Then, the algorithm is as follows:
+ //
+ // r = 0;
+ // for (j = 1; j <= n; j++) {
+ // q_j = (r * b + u_j) / v;
+ // r = (r * b + u_j) % v;
+ // }
+ //
+ // In our case, b = DIGIT_RADIX, and u = Ax + B and q = Cx + D where
+ // x = HALF_DIGIT_RADIX. Note that r < v < x and b = x^2. Then, a
+ // typical situation is as follows:
+ //
+ // ---- ----
+ // 0 r
+ // ---- ----
+ // A B
+ // ---- ---- ----
+ // r A B = r * b + u
+ //
+ // Hence, C = (r|A) / v.
+ // D = (((r|A) % v)|B) / v
+ // r = (((r|A) % v)|B) % v
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert(q != NULL);
+ sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
+#endif
+
+#define q_h r
+ sc_digit r = 0;
+ const sc_digit *ubegin = u;
+
+ u += ulen;
+ q += ulen;
+
+ while (ubegin < u) {
+ sc_digit u_AB = (*--u); // A|B
+
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(high_half(u_AB) == high_half_masked(u_AB));
+#endif
+
+ sc_digit num = concat(r, high_half(u_AB)); // num = r|A
+ q_h = num / v; // C
+ num = concat((num % v), low_half(u_AB)); // num = (((r|A) % v)|B)
+ (*--q) = concat(q_h, num / v); // q = C|D
+ r = num % v;
+ }
+#undef q_h
+}
+
+// Compute w = u % v, where w, u, and v are vectors.
+// - u and v are assumed to have at least two digits as uchars.
+void
+vec_rem_large(int ulen, const sc_digit *u, int vlen, const sc_digit *v,
+ sc_digit *w)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(w != NULL);
+ sc_assert(BITS_PER_DIGIT >= 3 * BITS_PER_BYTE);
+#endif
+
+ // This function is adapted from vec_div_large.
+ int xlen = BYTES_PER_DIGIT * ulen + 1;
+ int ylen = BYTES_PER_DIGIT * vlen;
+
+#ifdef SC_MAX_NBITS
+ uchar x[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
+ uchar y[DIV_CEIL2(SC_MAX_NBITS, BITS_PER_BYTE)];
+#else
+ uchar *x = new uchar[xlen];
+ uchar *y = new uchar[ylen];
+#endif
+
+ // r corresponds to w.
+
+ // Set (uchar) x = (sc_digit) u.
+ xlen = vec_to_char(ulen, u, xlen, x);
+
+ // Skip all the leading zeros in x.
+ while ((--xlen >= 0) && (!x[xlen]))
+ continue;
+ xlen++;
+
+ // Set (uchar) y = (sc_digit) v.
+ ylen = vec_to_char(vlen, v, ylen, y);
+
+ // Skip all the leading zeros in y.
+ while ((--ylen >= 0) && (!y[ylen]))
+ continue;
+ ylen++;
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert(xlen > 1);
+ sc_assert(ylen > 1);
+#endif
+
+ // At this point, all the leading zeros are eliminated from x and y.
+
+ // Zero the last digit of x.
+ x[xlen] = 0;
+
+ // The first two digits of y.
+ sc_digit y2 = (y[ylen - 1] << BITS_PER_BYTE) + y[ylen - 2];
+
+ const sc_digit DOUBLE_BITS_PER_BYTE = 2 * BITS_PER_BYTE;
+
+ // Find each q[k].
+ for (int k = xlen - ylen; k >= 0; --k) {
+ // qk is a guess for q[k] such that q[k] = qk or qk - 1.
+ sc_digit qk;
+
+ // Find qk by just using 2 digits of y and 3 digits of x. The
+ // following code assumes that sizeof(sc_digit) >= 3 BYTEs.
+ int k2 = k + ylen;
+
+ qk = ((x[k2] << DOUBLE_BITS_PER_BYTE) +
+ (x[k2 - 1] << BITS_PER_BYTE) + x[k2 - 2]) / y2;
+
+ if (qk >= BYTE_RADIX) // qk cannot be larger than the largest
+ qk = BYTE_RADIX - 1; // digit in BYTE_RADIX.
+
+ // q[k] = qk or qk - 1. The following if-statement determines which.
+ if (qk) {
+ uchar *xk = (x + k); // A shortcut for x[k].
+
+ // x = x - y * qk;
+ sc_digit carry = 0;
+
+ for (int i = 0; i < ylen; ++i) {
+ carry += y[i] * qk;
+ sc_digit diff = (xk[i] + BYTE_RADIX) - (carry & BYTE_MASK);
+ xk[i] = (uchar)(diff & BYTE_MASK);
+ carry = (carry >> BITS_PER_BYTE) +
+ (1 - (diff >> BITS_PER_BYTE));
+ }
+
+ if (carry) {
+ // 2's complement the last digit.
+ carry = (xk[ylen] + BYTE_RADIX) - carry;
+ xk[ylen] = (uchar)(carry & BYTE_MASK);
+ carry = 1 - (carry >> BITS_PER_BYTE);
+
+ if (carry) {
+ // qk was one too large, so decrement it.
+ // --qk;
+
+ // x = x - y * (qk - 1) = x - y * qk + y = x_above + y.
+ carry = 0;
+
+ for (int i = 0; i < ylen; ++i) {
+ carry += xk[i] + y[i];
+ xk[i] = (uchar)(carry & BYTE_MASK);
+ carry >>= BITS_PER_BYTE;
+ }
+
+ if (carry)
+ xk[ylen] = (uchar)((xk[ylen] + 1) & BYTE_MASK);
+ } // second if carry
+ } // first if carry
+ } // if qk
+ } // for k
+
+ // Set (sc_digit) w = (uchar) x for the remainder.
+ vec_from_char(ylen, x, ulen, w);
+
+#ifndef SC_MAX_NBITS
+ delete [] x;
+ delete [] y;
+#endif
+
+}
+
+// Compute r = u % v, where u is a vector, and r and v are scalars.
+// - 0 < v < HALF_DIGIT_RADIX.
+// - The remainder r is returned.
+sc_digit
+vec_rem_small(int ulen, const sc_digit *u, sc_digit v)
+{
+
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((0 < v) && (v < HALF_DIGIT_RADIX));
+#endif
+
+ // This function is adapted from vec_div_small().
+
+ sc_digit r = 0;
+ const sc_digit *ubegin = u;
+
+ u += ulen;
+
+ while (ubegin < u) {
+ sc_digit u_AB = (*--u); // A|B
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(high_half(u_AB) == high_half_masked(u_AB));
+#endif
+ // r = (((r|A) % v)|B) % v
+ r = (concat(((concat(r, high_half(u_AB))) % v), low_half(u_AB))) % v;
+ }
+
+ return r;
+}
+
+// u = u / v, r = u % v.
+sc_digit
+vec_rem_on_small(int ulen, sc_digit *u, sc_digit v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert(v > 0);
+#endif
+
+#define q_h r
+ sc_digit r = 0;
+ const sc_digit *ubegin = u;
+
+ u += ulen;
+ while (ubegin < u) {
+ sc_digit u_AB = (*--u); // A|B
+#ifdef DEBUG_SYSTEMC
+ // The overflow bits must be zero.
+ sc_assert(high_half(u_AB) == high_half_masked(u_AB));
+#endif
+ sc_digit num = concat(r, high_half(u_AB)); // num = r|A
+ q_h = num / v; // C
+ num = concat((num % v), low_half(u_AB)); // num = (((r|A) % v)|B)
+ (*u) = concat(q_h, num / v); // q = C|D
+ r = num % v;
+ }
+#undef q_h
+ return r;
+}
+
+// Set (uchar) v = (sc_digit) u. Return the new vlen.
+int
+vec_to_char(int ulen, const sc_digit *u, int vlen, uchar *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+#endif
+
+ int nbits = ulen * BITS_PER_DIGIT;
+ int right = 0;
+ int left = right + BITS_PER_BYTE - 1;
+
+ vlen = 0;
+ while (nbits > 0) {
+ int left_digit = left / BITS_PER_DIGIT;
+ int right_digit = right / BITS_PER_DIGIT;
+ int nsr = ((vlen << LOG2_BITS_PER_BYTE) % BITS_PER_DIGIT);
+ int d = u[right_digit] >> nsr;
+
+ if (left_digit != right_digit) {
+ if (left_digit < ulen)
+ d |= u[left_digit] << (BITS_PER_DIGIT - nsr);
+ }
+
+ v[vlen++] = (uchar)(d & BYTE_MASK);
+
+ left += BITS_PER_BYTE;
+ right += BITS_PER_BYTE;
+ nbits -= BITS_PER_BYTE;
+ }
+ return vlen;
+}
+
+// Set (sc_digit) v = (uchar) u.
+// - sizeof(uchar) <= sizeof(sc_digit),
+void
+vec_from_char(int ulen, const uchar *u, int vlen, sc_digit *v)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+ sc_assert((vlen > 0) && (v != NULL));
+ sc_assert(sizeof(uchar) <= sizeof(sc_digit));
+#endif
+
+ sc_digit *vend = (v + vlen);
+
+ const int nsr = BITS_PER_DIGIT - BITS_PER_BYTE;
+ const sc_digit mask = one_and_ones(nsr);
+
+ (*v) = (sc_digit) u[ulen - 1];
+
+ for (int i = ulen - 2; i >= 0; --i) {
+ // Manual inlining of vec_shift_left().
+ sc_digit *viter = v;
+ sc_digit carry = 0;
+ while (viter < vend) {
+ sc_digit vval = (*viter);
+ (*viter++) = (((vval & mask) << BITS_PER_BYTE) | carry);
+ carry = vval >> nsr;
+ }
+
+ if (viter < vend)
+ (*viter) = carry;
+
+ (*v) |= (sc_digit)u[i];
+ }
+}
+
+// Set u <<= nsl.
+// If nsl is negative, it is ignored.
+void
+vec_shift_left(int ulen, sc_digit *u, int nsl)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+#endif
+
+ if (nsl <= 0)
+ return;
+
+ // Shift left whole digits if nsl is large enough.
+ if (nsl >= (int) BITS_PER_DIGIT) {
+ int nd;
+ if (nsl % BITS_PER_DIGIT == 0) {
+ nd = nsl / BITS_PER_DIGIT; // No need to use DIV_CEIL(nsl).
+ nsl = 0;
+ } else {
+ nd = DIV_CEIL(nsl) - 1;
+ nsl -= nd * BITS_PER_DIGIT;
+ }
+
+ if (nd) {
+ // Shift left for nd digits.
+ for (int j = ulen - 1; j >= nd; --j)
+ u[j] = u[j - nd];
+
+ vec_zero(sc_min(nd, ulen), u);
+ }
+ if (nsl == 0)
+ return;
+ }
+
+ // Shift left if nsl < BITS_PER_DIGIT.
+ sc_digit *uiter = u;
+ sc_digit *uend = uiter + ulen;
+
+ int nsr = BITS_PER_DIGIT - nsl;
+ sc_digit mask = one_and_ones(nsr);
+
+ sc_digit carry = 0;
+
+ while (uiter < uend) {
+ sc_digit uval = (*uiter);
+ (*uiter++) = (((uval & mask) << nsl) | carry);
+ carry = uval >> nsr;
+ }
+
+ if (uiter < uend)
+ (*uiter) = carry;
+}
+
+// Set u >>= nsr.
+// If nsr is negative, it is ignored.
+void
+vec_shift_right(int ulen, sc_digit *u, int nsr, sc_digit fill)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((ulen > 0) && (u != NULL));
+#endif
+
+ // fill is usually either 0 or DIGIT_MASK; it can be any value.
+ if (nsr <= 0)
+ return;
+
+ // Shift right whole digits if nsr is large enough.
+ if (nsr >= (int) BITS_PER_DIGIT) {
+ int nd;
+ if (nsr % BITS_PER_DIGIT == 0) {
+ nd = nsr / BITS_PER_DIGIT;
+ nsr = 0;
+ } else {
+ nd = DIV_CEIL(nsr) - 1;
+ nsr -= nd * BITS_PER_DIGIT;
+ }
+
+ if (nd) {
+ // Shift right for nd digits.
+ for (int j = 0; j < (ulen - nd); ++j)
+ u[j] = u[j + nd];
+
+ if (fill) {
+ for (int j = ulen - sc_min( nd, ulen ); j < ulen; ++j)
+ u[j] = fill;
+ } else {
+ vec_zero(ulen - sc_min( nd, ulen ), ulen, u);
+ }
+ }
+ if (nsr == 0)
+ return;
+ }
+
+ // Shift right if nsr < BITS_PER_DIGIT.
+ sc_digit *ubegin = u;
+ sc_digit *uiter = (ubegin + ulen);
+
+ int nsl = BITS_PER_DIGIT - nsr;
+ sc_digit mask = one_and_ones(nsr);
+
+ sc_digit carry = (fill & mask) << nsl;
+
+ while (ubegin < uiter) {
+ sc_digit uval = (*--uiter);
+ (*uiter) = (uval >> nsr) | carry;
+ carry = (uval & mask) << nsl;
+ }
+}
+
+
+// Let u[l..r], where l and r are left and right bit positions
+// respectively, be equal to its mirror image.
+void
+vec_reverse(int unb, int und, sc_digit *ud, int l, int r)
+{
+#ifdef DEBUG_SYSTEMC
+ sc_assert((unb > 0) && (und > 0) && (ud != NULL));
+ sc_assert((0 <= r) && (r <= l) && (l < unb));
+#endif
+
+ if (l < r) {
+ std::stringstream msg;
+ msg << "vec_reverse( int, int, sc_digit*, int l, int r ) : " <<
+ "l = " << l << " < r = " << r << " is not valid",
+ SC_REPORT_ERROR("conversion failed", msg.str().c_str());
+ return;
+ }
+
+ // Make sure that l and r are within bounds.
+ r = sc_max(r, 0);
+ l = sc_min(l, unb - 1);
+
+ // Allocate memory for processing.
+#ifdef SC_MAX_NBITS
+ sc_digit d[MAX_NDIGITS];
+#else
+ sc_digit *d = new sc_digit[und];
+#endif
+
+ // d is a copy of ud.
+ vec_copy(und, d, ud);
+
+ // Based on the value of the ith in d, find the value of the jth bit
+ // in ud.
+ for (int i = l, j = r; i >= r; --i, ++j) {
+ if ((d[digit_ord(i)] & one_and_zeros(bit_ord(i))) != 0) // Test.
+ ud[digit_ord(j)] |= one_and_zeros(bit_ord(j)); // Set.
+ else
+ ud[digit_ord(j)] &= ~(one_and_zeros(bit_ord(j))); // Clear.
+ }
+
+#ifndef SC_MAX_NBITS
+ delete [] d;
+#endif
+}
+
+#ifdef SC_MAX_NBITS
+void test_bound_failed(int nb)
+{
+ std::stringstream msg;
+ msg << "test_bound( int nb ) : "
+ "nb = " << nb << " > SC_MAX_NBITS = " << SC_MAX_NBITS <<
+ " is not valid";
+ SC_REPORT_ERROR(sc_core::SC_ID_OUT_OF_BOUNDS_, msg.str().c_str());
+}
+#endif // SC_MAX_NBITS
+
+} // namespace sc_dt