/***************************************************************************** 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_nbexterns.cpp -- External functions for both sc_signed and sc_unsigned classes. These functions work on two parameters u and v, and copy the result to the first parameter u. This is also the reason that they are suffixed with _on_help. 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_nbexterns.cpp,v $ // Revision 1.2 2011/02/18 20:19:15 acg // Andy Goodrich: updating Copyright notice. // // 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 "systemc/ext/dt/int/sc_nbexterns.hh" #include "systemc/ext/utils/functions.hh" namespace sc_dt { // ---------------------------------------------------------------------------- // SECTION: External functions for PLUS operators. // ---------------------------------------------------------------------------- // Handles the cases 3 and 4 and returns the result in u. void add_on_help(small_type &us, int /* unb */, int und, sc_digit *ud, small_type vs, int /* vnb */, int vnd, const sc_digit *vd) { vnd = vec_skip_leading_zeros(vnd, vd); if (us == vs) { // case 3 if (und >= vnd) vec_add_on(und, ud, vnd, vd); else vec_add_on2(und, ud, vnd, vd); } else { // case 4 // vec_cmp expects that und is the number of non-zero digits in ud. int new_und = vec_skip_leading_zeros(und, ud); int cmp_res = vec_cmp(new_und, ud, vnd, vd); if (cmp_res == 0) { // u == v us = SC_ZERO; vec_zero(und, ud); return; } if (cmp_res > 0) { // u > v vec_sub_on(und, ud, vnd, vd); } else { // u < v us = -us; vec_sub_on2(und, ud, vnd, vd); } } } // ---------------------------------------------------------------------------- /* mul_on_help_signed and mul_on_help_unsigned have the same body except that CONVERT_SM_to_2C_to_SM and COPY_DIGITS are defined for signed and unsigned, respectively. This comment also applies to the signed/unsigned versions of div_on_help and mod_on_help. It is possible to take COPY_DIGITS out of these functions and create a single version of each of these helper functions; however, this will impose an onverhead on performance. In the versions below, any change in the signed version of a helper function must be carried to a corresponding change in the unsigned verion of the same function or vice versa. */ // ---------------------------------------------------------------------------- // SECTION: External functions of MULTIPLICATION operators. // ---------------------------------------------------------------------------- void mul_on_help_signed(small_type &us, int unb, int und, sc_digit *ud, int vnb, int vnd, const sc_digit *vd) { #define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM #define COPY_DIGITS copy_digits_signed { // Body of mul_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); sc_digit ud0 = (*ud); sc_digit vd0 = (*vd); if ((vnd == 1) && (vd0 == 1)) { us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud); return; } if ((und == 1) && (ud0 == 1)) { COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd); return; } if ((und == 1) && (vnd == 1) && (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) { sc_digit d = ud0 * vd0; COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d); return; } int nd = und + vnd; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); if ((und == 1) && (ud0 < HALF_DIGIT_RADIX)) vec_mul_small(vnd, vd, ud0, d); else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) vec_mul_small(und, ud, vd0, d); else if (vnd < und) vec_mul(und, ud, vnd, vd, d); else vec_mul(vnd, vd, und, ud, d); COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS #undef CONVERT_SM_to_2C_to_SM } void mul_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud, int vnb, int vnd, const sc_digit *vd) { #define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM #define COPY_DIGITS copy_digits_unsigned { // Body of mul_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); sc_digit ud0 = (*ud); sc_digit vd0 = (*vd); if ((vnd == 1) && (vd0 == 1)) { us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud); return; } if ((und == 1) && (ud0 == 1)) { COPY_DIGITS(us, unb, old_und, ud, vnb, vnd, vd); return; } if ((und == 1) && (vnd == 1) && (ud0 < HALF_DIGIT_RADIX) && (vd0 < HALF_DIGIT_RADIX)) { sc_digit d = ud0 * vd0; COPY_DIGITS(us, unb, old_und, ud, unb + vnb, 1, &d); return; } int nd = und + vnd; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); if ((und == 1) && (ud0 < HALF_DIGIT_RADIX)) vec_mul_small(vnd, vd, ud0, d); else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) vec_mul_small(und, ud, vd0, d); else if (vnd < und) vec_mul(und, ud, vnd, vd, d); else vec_mul(vnd, vd, und, ud, d); COPY_DIGITS(us, unb, old_und, ud, unb + vnb, nd, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS #undef CONVERT_SM_to_2C_to_SM } // ---------------------------------------------------------------------------- // SECTION: External functions for DIVISION operators. // ---------------------------------------------------------------------------- void div_on_help_signed(small_type &us, int unb, int und, sc_digit *ud, int vnb, int vnd, const sc_digit *vd) { #define CONVERT_SM_to_2C_to_SM convert_signed_SM_to_2C_to_SM #define COPY_DIGITS copy_digits_signed { // Body of div_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); int cmp_res = vec_cmp(und, ud, vnd, vd); if (cmp_res < 0) { // u < v => u / v = 0 - case 4 us = SC_ZERO; vec_zero(old_und, ud); return; } sc_digit vd0 = (*vd); if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1)) { us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud); return; } // One extra digit for d is allocated to simplify vec_div_*(). int nd = sc_max(und, vnd) + 1; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS + 1]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); // u = v => u / v = 1 - case 3 if (cmp_res == 0) d[0] = 1; else if ((vnd == 1) && (und == 1)) d[0] = (*ud) / vd0; else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) vec_div_small(und, ud, vd0, d); else vec_div_large(und, ud, vnd, vd, d); COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS #undef CONVERT_SM_to_2C_to_SM } void div_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud, int vnb, int vnd, const sc_digit *vd) { #define CONVERT_SM_to_2C_to_SM convert_unsigned_SM_to_2C_to_SM #define COPY_DIGITS copy_digits_unsigned { // Body of div_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); int cmp_res = vec_cmp(und, ud, vnd, vd); if (cmp_res < 0) { // u < v => u / v = 0 - case 4 us = SC_ZERO; vec_zero(old_und, ud); return; } sc_digit vd0 = (*vd); if ((cmp_res > 0) && (vnd == 1) && (vd0 == 1)) { us = CONVERT_SM_to_2C_to_SM(us, unb, old_und, ud); return; } // One extra digit for d is allocated to simplify vec_div_*(). int nd = sc_max(und, vnd) + 1; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS + 1]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); // u = v => u / v = 1 - case 3 if (cmp_res == 0) d[0] = 1; else if ((vnd == 1) && (und == 1)) d[0] = (*ud) / vd0; else if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) vec_div_small(und, ud, vd0, d); else vec_div_large(und, ud, vnd, vd, d); COPY_DIGITS(us, unb, old_und, ud, sc_max(unb, vnb), nd - 1, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS #undef CONVERT_SM_to_2C_to_SM } // ---------------------------------------------------------------------------- // SECTION: External functions for MOD operators. // ---------------------------------------------------------------------------- void mod_on_help_signed(small_type &us, int unb, int und, sc_digit *ud, int /* vnb */, int vnd, const sc_digit *vd) { #define COPY_DIGITS copy_digits_signed { // Body of mod_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); int cmp_res = vec_cmp(und, ud, vnd, vd); // u < v => u % v = u - case 4 if (cmp_res < 0) return; // u = v => u % v = 0 - case 3 if (cmp_res == 0) { us = SC_ZERO; vec_zero(old_und, ud); return; } // else if u > v - case 5 sc_digit vd0 = (*vd); if ((vnd == 1) && (vd0 == 1)) { us = SC_ZERO; vec_zero(old_und, ud); return; } // One extra digit for d is allocated to simplify vec_div_*(). int nd = sc_max(und, vnd) + 1; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS + 1]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); if ((vnd == 1) && (und == 1)) d[0] = (*ud) % vd0; if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) d[0] = vec_rem_small(und, ud, vd0); else vec_rem_large(und, ud, vnd, vd, d); us = check_for_zero(us, nd - 1, d); if (us == SC_ZERO) vec_zero(old_und, ud); else COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS } void mod_on_help_unsigned(small_type &us, int unb, int und, sc_digit *ud, int /* vnb */, int vnd, const sc_digit *vd) { #define COPY_DIGITS copy_digits_unsigned { // Body of mod_on_help int old_und = und; und = vec_skip_leading_zeros(und, ud); vnd = vec_skip_leading_zeros(vnd, vd); int cmp_res = vec_cmp(und, ud, vnd, vd); // u < v => u % v = u - case 4 if (cmp_res < 0) return; // u = v => u % v = 0 - case 3 if (cmp_res == 0) { us = SC_ZERO; vec_zero(old_und, ud); return; } // else if u > v - case 5 sc_digit vd0 = (*vd); if ((vnd == 1) && (vd0 == 1)) { us = SC_ZERO; vec_zero(old_und, ud); return; } // One extra digit for d is allocated to simplify vec_div_*(). int nd = sc_max(und, vnd) + 1; #ifdef SC_MAX_NBITS sc_digit d[MAX_NDIGITS + 1]; #else sc_digit *d = new sc_digit[nd]; #endif vec_zero(nd, d); if ((vnd == 1) && (und == 1)) d[0] = (*ud) % vd0; if ((vnd == 1) && (vd0 < HALF_DIGIT_RADIX)) d[0] = vec_rem_small(und, ud, vd0); else vec_rem_large(und, ud, vnd, vd, d); us = check_for_zero(us, nd - 1, d); if (us == SC_ZERO) vec_zero(old_und, ud); else COPY_DIGITS(us, unb, old_und, ud, sc_min(unb, vnd), nd - 1, d); #ifndef SC_MAX_NBITS delete [] d; #endif } #undef COPY_DIGITS } // ---------------------------------------------------------------------------- // SECTION: External functions for AND operators. // ---------------------------------------------------------------------------- // Handles the cases 2-5 and returns the result in u. void and_on_help(small_type us, int /* unb */, int und, sc_digit *ud, small_type vs, int /* vnb */, int vnd, const sc_digit *vd) { sc_digit *x = ud; const sc_digit *y = vd; int xnd = und; int ynd = vnd; // Truncate y. if (xnd < ynd) ynd = xnd; const sc_digit *xend = (x + xnd); const sc_digit *yend = (y + ynd); // x is longer than y. small_type s = mul_signs(us, vs); if (s > 0) { if (us > 0) { // case 2 while (y < yend) (*x++) &= (*y++); while (x < xend) (*x++) = 0; } else { // case 3 sc_digit xcarry = 1; sc_digit ycarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += (~(*y++) & DIGIT_MASK); (*x++) = (xcarry & ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += DIGIT_MASK; (*x++) = (xcarry & ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } } } else { if (us > 0) { // case 4 sc_digit ycarry = 1; while (y < yend) { ycarry += (~(*y++) & DIGIT_MASK); (*x++) &= ycarry & DIGIT_MASK; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { ycarry += DIGIT_MASK; (*x++) &= ycarry & DIGIT_MASK; ycarry >>= BITS_PER_DIGIT; } } else { // case 5 sc_digit xcarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); (*x++) = (xcarry & (*y++)) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; } while (x < xend) (*x++) = 0; } } } // ---------------------------------------------------------------------------- // SECTION: External functions for OR operators. // ---------------------------------------------------------------------------- // Handles the cases 3-5 and returns the result in u. void or_on_help(small_type us, int /* unb */, int und, sc_digit *ud, small_type vs, int /* vnb */, int vnd, const sc_digit *vd) { sc_digit *x = ud; const sc_digit *y = vd; int xnd = und; int ynd = vnd; if (xnd < ynd) ynd = xnd; const sc_digit *xend = (x + xnd); const sc_digit *yend = (y + ynd); // x is longer than y. small_type s = mul_signs(us, vs); if (s > 0) { if (us > 0) { // case 3 while (y < yend) (*x++) |= (*y++); // No change for the rest of x. } else { // case 4 sc_digit xcarry = 1; sc_digit ycarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += (~(*y++) & DIGIT_MASK); (*x++) = (xcarry | ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += DIGIT_MASK; (*x++) = (xcarry | ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } } } else { if (us > 0) { // case 5 sc_digit ycarry = 1; while (y < yend) { ycarry += (~(*y++) & DIGIT_MASK); (*x) = ((*x) | ycarry) & DIGIT_MASK; x++; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { ycarry += DIGIT_MASK; (*x) = ((*x) | ycarry) & DIGIT_MASK; x++; ycarry >>= BITS_PER_DIGIT; } } else { // case 6 sc_digit xcarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); (*x++) = (xcarry | (*y++)) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; } while (x < xend) { xcarry += (~(*x) & DIGIT_MASK); (*x++) = xcarry & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; } } } } // ---------------------------------------------------------------------------- // SECTION: External functions for XOR operators. // ---------------------------------------------------------------------------- // Handles the cases 3-5 and returns the result in u. void xor_on_help(small_type us, int /* unb */, int und, sc_digit *ud, small_type vs, int /* vnb */, int vnd, const sc_digit *vd) { sc_digit *x = ud; const sc_digit *y = vd; int xnd = und; int ynd = vnd; if (xnd < ynd) ynd = xnd; const sc_digit *xend = (x + xnd); const sc_digit *yend = (y + ynd); // x is longer than y. small_type s = mul_signs(us, vs); if (s > 0) { if (us > 0) { // case 3 while (y < yend) { (*x) = ((*x) ^ (*y)) & DIGIT_MASK; x++; y++; } // No change for the rest of x. } else { // case 4 sc_digit xcarry = 1; sc_digit ycarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += (~(*y++) & DIGIT_MASK); (*x++) = (xcarry ^ ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { xcarry += (~(*x) & DIGIT_MASK); ycarry += DIGIT_MASK; (*x++) = (xcarry ^ ycarry) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; ycarry >>= BITS_PER_DIGIT; } } } else { if (us > 0) { // case 5 sc_digit ycarry = 1; while (y < yend) { ycarry += (~(*y++) & DIGIT_MASK); (*x) = ((*x) ^ ycarry) & DIGIT_MASK; x++; ycarry >>= BITS_PER_DIGIT; } while (x < xend) { ycarry += DIGIT_MASK; (*x) = ((*x) ^ ycarry) & DIGIT_MASK; x++; ycarry >>= BITS_PER_DIGIT; } } else { // case 6 sc_digit xcarry = 1; while (y < yend) { xcarry += (~(*x) & DIGIT_MASK); (*x++) = (xcarry ^ (*y++)) & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; } while (x < xend) { xcarry += (~(*x) & DIGIT_MASK); (*x++) = xcarry & DIGIT_MASK; xcarry >>= BITS_PER_DIGIT; } } } } } // namespace sc_dt