/*****************************************************************************

  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 <ctype.h>
#include "sysc/datatypes/int/sc_int_ids.h"
#include "sysc/datatypes/int/sc_nbutils.h"
#include "sysc/kernel/sc_macros.h"


namespace sc_dt
{

// ----------------------------------------------------------------------------
//  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.
    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
  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;
    }
  }

#ifdef DEBUG_SYSTEMC
  // 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".
  assert(nskip <= 3);
#endif

  v += nskip;

  // Handles empty strings or strings without any digits after the
  // base or base and sign specifier.
  if (*v == '\0') { 
      char msg[BUFSIZ];
      std::sprintf( msg,
	       "get_base_and_sign( const char* v, small_type&, small_type& ) : "
	       "v = \"\" is not valid" );
      SC_REPORT_ERROR( sc_core::SC_ID_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( sc_core::SC_ID_CONVERSION_FAILED_,
                         "character string is zero" );
    }
    if( *src_p == 0 ) {
        SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_,
                         "character string is empty" );
    }


    // 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;
            src_i = 0;
            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:
                    {
                        char msg[BUFSIZ];
                        std::sprintf( msg, "character string '%s' is not valid", 
                        src_p );
                        SC_REPORT_ERROR(sc_core::SC_ID_CONVERSION_FAILED_, msg);
                    }
                    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:
                {
                    char msg[BUFSIZ];
                    std::sprintf( msg, "character string '%s' is not valid", 
                    src_p );
                    SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
                }
                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( sc_core::SC_ID_CONVERSION_FAILED_,
                         "character string is zero" );
    }
    if( *src_p == 0 ) {
        SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_,
                         "character string is empty" );
    }


    // 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;
            src_i = 0;
            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:
                    {
                        char msg[BUFSIZ];
                        std::sprintf( msg, "character string '%s' is not valid", 
                        src_p );
                        SC_REPORT_ERROR(sc_core::SC_ID_CONVERSION_FAILED_, msg);
                    }
                    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:
                {
                    char msg[BUFSIZ];
                    std::sprintf( msg, "character string '%s' is not valid", 
                    src_p );
                    SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
                }
                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
  assert((unb > 0) && (und > 0) && (u != NULL));
  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 {
	char msg[BUFSIZ];
	std::sprintf( msg,
		 "vec_from_str( int, int, sc_digit*, const char*, sc_numrep base ) : "
		 "base = %s does not match the default base",
		 to_string( base ).c_str() );
	SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
    }
  }

  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) {
	  char msg[BUFSIZ];
	  std::sprintf( msg,
		   "vec_from_str( int, int, sc_digit*, const char*, sc_numrep base ) : "
		   "'%c' is not a valid digit in base %d",
		   *v, b );
	  SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
      }
      
      // digit = digit * b + val;
      vec_mul_small_on(und, u, b);
      
      if (val)
        vec_add_small_on(und, u, val);

    }
    else {
	char msg[BUFSIZ];
	std::sprintf( msg,
		 "vec_from_str( int, int, sc_digit*, const char*, sc_numrep base ) : "
		 "'%c' is not a valid digit in base %d",
		 *v, b );
	SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
    }
  }

  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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(w != NULL);
  assert(ulen >= vlen);
#endif

  const sc_digit *uend = (u + ulen);
  const sc_digit *vend = (v + vlen);

  register 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
  assert((ulen > 0) && (ubegin != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(ulen >= vlen);
#endif

  register sc_digit *u = ubegin;
  const sc_digit *uend = (u + ulen);
  const sc_digit *vend = (v + vlen);

  register 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
  assert((ulen > 0) && (ubegin != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(ulen < vlen);
#endif

  register sc_digit *u = ubegin;
  const sc_digit *uend = (u + ulen);

  register 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
  assert((ulen > 0) && (u != NULL));
  assert(w != NULL);
#endif

  const sc_digit *uend = (u + ulen);

  // Add along the shorter v.
  register 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
  assert((ulen > 0) && (u != NULL));
#endif

  register 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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(w != NULL);
  assert(ulen >= vlen);
#endif

  const sc_digit *uend = (u + ulen);
  const sc_digit *vend = (v + vlen);

  register 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
  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
  assert((ulen > 0) && (ubegin != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(ulen >= vlen);
#endif

  register sc_digit *u = ubegin;
  const sc_digit *uend = (u + ulen);
  const sc_digit *vend = (v + vlen);

  register 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
  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
  assert((ulen > 0) && (ubegin != NULL));
  assert((vlen > 0) && (v != NULL));
#endif

  register sc_digit *u = ubegin;
  const sc_digit *uend = (u + sc_min(ulen, vlen));

  register 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
  assert(ulen > 0);
  assert(u != NULL);
#endif

  const sc_digit *uend = (u + ulen);

  // Add along the shorter v.
  register 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
  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
  assert((ulen > 0) && (u != NULL));
#endif

  for (register 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
  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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (vbegin != NULL));
  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.
    assert(u_h == (u_h & HALF_DIGIT_MASK));
#endif

    register sc_digit carry = 0;

    register sc_digit *w = (wbegin++);

    register 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.
      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
  assert((ulen > 0) && (u != NULL));
  assert(w != NULL);
  assert((0 < v) && (v < HALF_DIGIT_RADIX));
#endif

#define prod_h carry

  const sc_digit *uend = (u + ulen);

  register sc_digit carry = 0;

  while (u < uend) {

    sc_digit u_AB = (*u++);

#ifdef DEBUG_SYSTEMC
    // The overflow bits must be zero.
    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
  assert((ulen > 0) && (u != NULL));
  assert((0 < v) && (v < HALF_DIGIT_RADIX));
#endif

#define prod_h carry

  register sc_digit carry = 0;

  for (register int i = 0; i < ulen; ++i) {

#ifdef DEBUG_SYSTEMC
    // The overflow bits must be zero.
    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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(w != NULL);
  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
  assert(xlen > 1);
  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.
  register 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 (register int k = (xlen - ylen); k >= 0; --k) {

    // qk is a guess for q[k] such that q[k] = qk or qk - 1.
    register 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) {

      register uchar *xk = (x + k);  // A shortcut for x[k].

      // x = x - y * qk :
      register sc_digit carry = 0;

      for (register 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:
          // That is, x = x - y * (qk - 1) = x - y * qk + y = x_above + y.
          carry = 0;

          for (register 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
  assert((ulen > 0) && (u != NULL));
  assert(q != NULL);
  assert((0 < v) && (v < HALF_DIGIT_RADIX));
#endif

#define q_h r

  register 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.
    assert(high_half(u_AB) == high_half_masked(u_AB));
#endif

    register 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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
  assert(w != NULL);
  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
  assert(xlen > 1);
  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.
  register 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 (register int k = xlen - ylen; k >= 0; --k) {

    // qk is a guess for q[k] such that q[k] = qk or qk - 1.
    register 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) {

      register uchar *xk = (x + k);  // A shortcut for x[k].

      // x = x - y * qk;
      register sc_digit carry = 0;

      for (register 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 (register 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
  assert((ulen > 0) && (u != NULL));
  assert((0 < v) && (v < HALF_DIGIT_RADIX));
#endif

  // This function is adapted from vec_div_small().

  register sc_digit r = 0;
  const sc_digit *ubegin = u;

  u += ulen;

  while (ubegin < u) {
    register sc_digit u_AB = (*--u);  // A|B

#ifdef DEBUG_SYSTEMC
    // The overflow bits must be zero.
    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
  assert((ulen > 0) && (u != NULL));
  assert(v > 0);
#endif

#define q_h r

  register 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.
    assert(high_half(u_AB) == high_half_masked(u_AB));
#endif

    register 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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
#endif

  register int nbits = ulen * BITS_PER_DIGIT;

  register int right = 0;
  register 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;

    register 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
  assert((ulen > 0) && (u != NULL));
  assert((vlen > 0) && (v != NULL));
  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 (register int i = ulen - 2; i >= 0; --i) {

    // Manual inlining of vec_shift_left().

    register sc_digit *viter = v;

    register sc_digit carry = 0;

    while (viter < vend) {
      register 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
  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 (register 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.
  register sc_digit *uiter = u;
  sc_digit *uend = uiter + ulen;

  int nsr = BITS_PER_DIGIT - nsl;
  sc_digit mask = one_and_ones(nsr);

  register sc_digit carry = 0;

  while (uiter < uend) {
    register 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
  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 (register int j = 0; j < (ulen - nd); ++j)
        u[j] = u[j + nd];

      if (fill) {
        for (register 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;
  register sc_digit *uiter = (ubegin + ulen);

  int nsl = BITS_PER_DIGIT - nsr;
  sc_digit mask = one_and_ones(nsr);

  register sc_digit carry = (fill & mask) << nsl;

  while (ubegin < uiter) {
    register 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
  assert((unb > 0) && (und > 0) && (ud != NULL));
  assert((0 <= r) && (r <= l) && (l < unb));
#endif

  if (l < r) {
      char msg[BUFSIZ];
      std::sprintf( msg, "vec_reverse( int, int, sc_digit*, int l, int r ) : "
	       "l = %d < r = %d is not valid",
	       l, r );
      SC_REPORT_ERROR( sc_core::SC_ID_CONVERSION_FAILED_, msg );
  }

  // 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 (register 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
    
}

} // namespace sc_dt


// End of file.
