| /***************************************************************************** | |
| 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 |