blob: a78013d772db182bb87f5315f79b4a181f3ab911 [file] [log] [blame]
/*****************************************************************************
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/bit/messages.hh"
#include "systemc/ext/dt/int/messages.hh"
#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(sc_core::SC_ID_VALUE_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(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");
return;
}
if (*src_p == 0) {
SC_REPORT_ERROR(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_CONVERSION_FAILED_,
"character string is zero");
return;
}
if (*src_p == 0) {
SC_REPORT_ERROR(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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(sc_core::SC_ID_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