/* FILE NAME: arithm.c TITLE: Package for arbitrary precision integer arithmetic DESCRIPTION: This abstract data implements arbitrary precision integer and unsigned integer numbers by machine independent way. The implementation of the package functions are not sufficiently efficient in order to use for run-time. The package functions are oriented to implement constant-folding in compilers. This package is necessary because host machine may not support such arithmetic for target machine. For example, VAX does not support does not support more 32-bits integer numbers arithmetic. The numbers are represented by bytes in big endian mode, negative integer numbers are represented in complementary code. All sizes are given in bytes and must be positive. Results of executions of all functions can coincide with a operand(s). All functions of addition, subtraction, multiplication, division, evaluation of remainder, shift, changing size and transformation of string into number fix overflow. The overflow is fixed when result can not be represented by number of given size. */ #include "arithm.h" #include "ammunition_string.h" /* This variable can have only two values 0 or 1. The value `1' corresponds to overflow. The variable value are modified by all functions of addition, subtract, multiplication, division, evaluation of remainder, shift, changing size and transformation of string into number fix overflow. */ int ammunition_overflow_bit; /* The following function adds unsigned integers. The function returns 1 if unsigned integer overflow is fixed, 0 otherwise. Result can be placed in any operand. */ int ammunition_add_unsigned_integer_without_overflow_reaction ( int size, const void *op1, const void *op2, void *result ) { int digit_num; int carry; unsigned int sum; _Pragma( "loopbound min 4 max 4" ) for ( digit_num = size - 1, carry = 0; digit_num >= 0; digit_num-- ) { sum = ( ( ( unsigned char * ) op1 ) [digit_num] + ( ( unsigned char * ) op2 ) [digit_num] + carry ); if ( sum > UCHAR_MAX ) { sum -= UCHAR_MAX + 1; carry = 1; } else carry = 0; ( ( unsigned char * ) result ) [digit_num] = sum; } return carry != 0; } /* The following function adds unsigned integers. The function returns 1 if unsigned integer overflow (the first operand is less than the second) is fixed, 0 otherwise. Result can be placed in any operand. */ int ammunition_subtract_unsigned_integer_without_overflow_reaction ( int size, const void *op1, const void *op2, void *result ) { int digit_num; int carry; int subtraction; _Pragma( "loopbound min 4 max 4" ) for ( digit_num = size - 1, carry = 0; digit_num >= 0; digit_num-- ) { subtraction = ( ( ( unsigned char * ) op1 ) [digit_num] - ( ( unsigned char * ) op2 ) [digit_num] - carry ); if ( subtraction < 0 ) { subtraction += UCHAR_MAX + 1; carry = 1; } else carry = 0; ( ( unsigned char * ) result ) [digit_num] = subtraction; } return carry != 0; } /* The following function makes complementary code of number. Result can be placed in operand. */ void ammunition_make_complementary_code ( int size, const void *operand, void *result ) { int digit_num; int carry; int subtraction; _Pragma( "loopbound min 2 max 6" ) for ( digit_num = size - 1, carry = 0; digit_num >= 0; digit_num-- ) { subtraction = ( 0 - ( ( unsigned char * ) operand ) [digit_num] - carry ); if ( subtraction != 0 ) { subtraction += UCHAR_MAX + 1; carry = 1; } else carry = 0; ( ( unsigned char * ) result ) [digit_num] = subtraction; } } /* The following function multiplys unsigned integer by digit (byte size). The function returns 1 if unsigned integer overflow is fixed, 0 otherwise. */ int ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction ( int size, void *operand, unsigned int digit ) { int digit_num; unsigned int carry; unsigned int sum; _Pragma( "loopbound min 4 max 4" ) for ( digit_num = size - 1, carry = 0; digit_num >= 0; digit_num-- ) { sum = ( ( ( unsigned char * ) operand ) [digit_num] * digit + carry ); if ( sum > UCHAR_MAX ) { carry = sum / ( UCHAR_MAX + 1 ); sum %= UCHAR_MAX + 1; } else carry = 0; ( ( unsigned char * ) operand ) [digit_num] = sum; } return carry != 0; } /* Originally reaction on all integer and unsigned integer overflow is equal to the following function. The function does nothing. */ void ammunition_arithmetic_overflow_reaction ( void ) {} /* Originally reaction on all integer and unsigned integer overflow is equal to the following function. The function does nothing. */ void ammunition_arithmetic_unsigned_overflow_reaction ( void ) {} /* This page contains functions for arbitrary precision addition. */ /* The function adds unsigned integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `add_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_add_unsigned_integer ( int size, const void *op1, const void *op2, void *result ) { ammunition_overflow_bit = ammunition_add_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); if ( ammunition_overflow_bit != 0 ) ammunition_arithmetic_unsigned_overflow_reaction(); } /* The function adds integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `add_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_add_integer ( int size, const void *op1, const void *op2, void *result ) { int op1_sign; int sign_equality; op1_sign = INTEGER_SIGN ( op1 ); sign_equality = INTEGER_SIGN ( op1 ) == INTEGER_SIGN ( op2 ); ammunition_add_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); ammunition_overflow_bit = sign_equality && ( op1_sign != INTEGER_SIGN ( result ) ); if ( ammunition_overflow_bit != 0 ) ammunition_arithmetic_overflow_reaction(); } /* This page contains functions for arbitrary precision subtraction. */ /* The function subtracts unsigned integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `subtract_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_subtract_unsigned_integer ( int size, const void *op1, const void *op2, void *result ) { ammunition_overflow_bit = ammunition_subtract_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); if ( ammunition_overflow_bit != 0 ) ammunition_arithmetic_unsigned_overflow_reaction(); } /* The function subtracts integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `subtract_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_subtract_integer ( int size, const void *op1, const void *op2, void *result ) { int op1_sign; int sign_unequality; op1_sign = INTEGER_SIGN ( op1 ); sign_unequality = INTEGER_SIGN ( op1 ) != INTEGER_SIGN ( op2 ); ammunition_subtract_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); ammunition_overflow_bit = sign_unequality && ( op1_sign != INTEGER_SIGN ( result ) ); if ( ammunition_overflow_bit != 0 ) ammunition_arithmetic_overflow_reaction(); } /* This page contains functions for arbitrary precision multiplication. */ /* The following function multiplys unsigned integers. The function returns 1 if unsigned integer overflow is fixed, 0 otherwise. Result can be placed in any operand. */ int ammunition_multiply_unsigned_integer_without_overflow_reaction ( int size, const void *op1, const void *op2, void *result ) { int op1_digit_num; int op2_digit_num; int carry; unsigned long int partial_sum; int result_digit_number; int overflow_flag; unsigned char long_result [2 * MAX_INTEGER_OPERAND_SIZE]; ammunition_memset ( long_result + size, 0, ( size_x ) size ); _Pragma( "loopbound min 4 max 4" ) for ( op2_digit_num = size - 1; op2_digit_num >= 0; op2_digit_num-- ) { if ( ( ( unsigned char * ) op2 ) [op2_digit_num] != 0 ) { _Pragma( "loopbound min 4 max 4" ) for ( op1_digit_num = size - 1, carry = 0; op1_digit_num >= 0; op1_digit_num-- ) { partial_sum = ( ( ( unsigned char * ) op1 ) [op1_digit_num] * ( ( unsigned char * ) op2 ) [op2_digit_num] + long_result [op1_digit_num + op2_digit_num + 1] + carry ); long_result [op1_digit_num + op2_digit_num + 1] = ( unsigned char ) ( partial_sum % ( UCHAR_MAX + 1 ) ); carry = partial_sum / ( UCHAR_MAX + 1 ); } long_result [op2_digit_num] = carry; } else long_result [op2_digit_num] = 0; } overflow_flag = 0; _Pragma( "loopbound min 1 max 4" ) for ( result_digit_number = size - 1; result_digit_number >= 0; result_digit_number-- ) { if ( long_result [result_digit_number] != 0 ) { overflow_flag = 1; break; } } ammunition_memcpy ( result, long_result + size, ( size_x ) size ); return overflow_flag; } /* The following function multiplys unsigned integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `multiply_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_multiply_unsigned_integer ( int size, const void *op1, const void *op2, void *result ) { ammunition_overflow_bit = ammunition_multiply_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); if ( ammunition_overflow_bit ) ammunition_arithmetic_unsigned_overflow_reaction(); } /* The function multiplys integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `multiply_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_multiply_integer ( int size, const void *op1, const void *op2, void *result ) { int negative_result_flag; unsigned char op1_complementary [MAX_INTEGER_OPERAND_SIZE]; unsigned char op2_complementary [MAX_INTEGER_OPERAND_SIZE]; unsigned const char *abs_op1; unsigned const char *abs_op2; int unsigned_result_sign; negative_result_flag = INTEGER_SIGN ( op1 ) != INTEGER_SIGN ( op2 ); if ( INTEGER_SIGN ( op1 ) ) { /* May be integer overflow. But result is correct because it is unsigned. */ ammunition_make_complementary_code ( size, op1, op1_complementary ); abs_op1 = ( unsigned const char * )op1_complementary; } else abs_op1 = ( unsigned const char * )op1; if ( INTEGER_SIGN ( op2 ) ) { /* May be integer overflow. But result is correct because it is unsigned. */ ammunition_make_complementary_code ( size, op2, op2_complementary ); abs_op2 = ( unsigned const char * )op2_complementary; } else abs_op2 = ( unsigned const char * )op2; ammunition_overflow_bit = ammunition_multiply_unsigned_integer_without_overflow_reaction ( size, abs_op1, abs_op2, result ); unsigned_result_sign = INTEGER_SIGN ( result ); if ( negative_result_flag ) ammunition_make_complementary_code ( size, result, result ); if ( unsigned_result_sign && ( !negative_result_flag || INTEGER_SIGN ( result ) != unsigned_result_sign ) ) /* Unsigned result can not be represented as integer. */ ammunition_overflow_bit = 1; if ( ammunition_overflow_bit ) ammunition_arithmetic_overflow_reaction(); } /* This page contains functions for arbitrary precision division. */ /* The following function divides unsigned integers. The function returns 1 if unsigned integer overflow (division by zero) is fixed, 0 otherwise. Result can be placed in any operand. See algorithm in Knuth's book. */ int ammunition_divide_unsigned_integer_without_overflow_reaction ( int size, const void *op1, const void *op2, void *result ) { int scaled_op1_digit_num; unsigned int q_approximation; int first_nonzero_digit_number; int op2_digit_number; unsigned int scale; unsigned char scaled_op1 [MAX_INTEGER_OPERAND_SIZE + 1]; unsigned char normalized_op2 [MAX_INTEGER_OPERAND_SIZE]; unsigned char extended_normalized_op2 [MAX_INTEGER_OPERAND_SIZE + 1]; _Pragma( "loopbound min 4 max 4" ) for ( op2_digit_number = 0; op2_digit_number < size; op2_digit_number++ ) { if ( ( ( unsigned char * ) op2 ) [op2_digit_number] != 0 ) break; } first_nonzero_digit_number = op2_digit_number; if ( first_nonzero_digit_number == size ) { /* Zero divisor */ ammunition_memset ( result, 0, ( size_x ) size ); return 1 /* TRUE */; } else if ( first_nonzero_digit_number == size - 1 ) { /* Division by digit. */ int digit_num; int digit; unsigned long divisable; unsigned long remainder; digit = ( ( unsigned char * ) op2 ) [first_nonzero_digit_number]; ammunition_memcpy ( result, op1, ( size_x ) size ); remainder = 0; _Pragma( "loopbound min 4 max 4" ) for ( digit_num = 0; digit_num < size; digit_num++ ) { divisable = ( remainder * ( UCHAR_MAX + 1 ) + ( ( unsigned char * ) result ) [digit_num] ); remainder = divisable % digit; ( ( unsigned char * ) result ) [digit_num] = ( unsigned char ) ( divisable / digit ); } return 0 /* FALSE */; } /* Normalization of divisor. */ scale = ( UCHAR_MAX + 1 ) / ( ( ( unsigned char * ) op2 ) [op2_digit_number] + 1 ); ammunition_memcpy ( scaled_op1 + 1, op1, ( size_x ) size ); *scaled_op1 = 0; ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction ( size + 1, scaled_op1, scale ); ammunition_memcpy ( normalized_op2, op2, ( size_x ) size ); ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction ( size, normalized_op2, scale ); _Pragma( "loopbound min 0 max 0" ) for ( scaled_op1_digit_num = 0; scaled_op1_digit_num <= first_nonzero_digit_number; scaled_op1_digit_num++ ) { /* Division of `scaled_op1[scaled_op1_digit_number]..scaled_op1[size]' by `normalized_op2[first_nonzero_digit_number]..normalized_op2[size-1]' for evaluation of one digit of quotient `result[size-1-first_nonzero_digit_number-scaled_op1_digit_number]'. */ if ( scaled_op1 [scaled_op1_digit_num] == normalized_op2 [first_nonzero_digit_number] ) q_approximation = UCHAR_MAX; else q_approximation = ( scaled_op1 [scaled_op1_digit_num] * ( UCHAR_MAX + 1 ) + scaled_op1 [scaled_op1_digit_num + 1] ) / normalized_op2 [first_nonzero_digit_number]; _Pragma( "loopbound min 0 max 0" ) while ( normalized_op2 [first_nonzero_digit_number + 1] * q_approximation > ( ( ( unsigned long int ) scaled_op1 [scaled_op1_digit_num] * ( UCHAR_MAX + 1 ) + scaled_op1 [scaled_op1_digit_num + 1] - q_approximation * normalized_op2 [first_nonzero_digit_number] ) * ( UCHAR_MAX + 1 ) + scaled_op1 [scaled_op1_digit_num + 2] ) ) q_approximation --; /* Multiply and subtract */ ammunition_memcpy ( extended_normalized_op2 + 1, normalized_op2 + first_nonzero_digit_number, ( size_x ) ( size - first_nonzero_digit_number ) ); *extended_normalized_op2 = 0; ammunition_multiply_unsigned_integer_by_digit_without_overflow_reaction ( size - first_nonzero_digit_number + 1, extended_normalized_op2, q_approximation ); if ( ammunition_subtract_unsigned_integer_without_overflow_reaction ( size - first_nonzero_digit_number + 1, scaled_op1 + scaled_op1_digit_num, extended_normalized_op2, scaled_op1 + scaled_op1_digit_num ) ) { /* Negative result. Compensation by addition. */ q_approximation--; ammunition_memcpy ( extended_normalized_op2 + 1, normalized_op2 + first_nonzero_digit_number, ( size_x ) ( size - first_nonzero_digit_number ) ); *extended_normalized_op2 = 0; ammunition_add_unsigned_integer_without_overflow_reaction ( size - first_nonzero_digit_number + 1, scaled_op1 + scaled_op1_digit_num, extended_normalized_op2, scaled_op1 + scaled_op1_digit_num ); } ( ( unsigned char * ) result ) [size - 1 - first_nonzero_digit_number + scaled_op1_digit_num] = q_approximation; } ammunition_memset ( result, 0, ( size_x ) ( size - 1 - first_nonzero_digit_number ) ); return 0 /* TRUE */; } /* The function divides unsigned integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `divide_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_divide_unsigned_integer ( int size, const void *op1, const void *op2, void *result ) { ammunition_overflow_bit = ammunition_divide_unsigned_integer_without_overflow_reaction ( size, op1, op2, result ); if ( ammunition_overflow_bit ) ammunition_arithmetic_unsigned_overflow_reaction(); } /* The function divides integers and fixes overflow reaction if it is needed. The function makes this with the aid of function `divide_unsigned_integer_without_overflow_reaction'. Result can be placed in any operand. */ void ammunition_divide_integer ( int size, const void *op1, const void *op2, void *result ) { int negative_result_flag; unsigned char op1_complementary [MAX_INTEGER_OPERAND_SIZE]; unsigned char op2_complementary [MAX_INTEGER_OPERAND_SIZE]; unsigned const char *abs_op1; unsigned const char *abs_op2; int unsigned_result_sign; negative_result_flag = INTEGER_SIGN ( op1 ) != INTEGER_SIGN ( op2 ); if ( INTEGER_SIGN ( op1 ) ) { /* May be integer overflow for minimal int. But result is correct because it is unsigned. */ ammunition_make_complementary_code ( size, op1, op1_complementary ); abs_op1 = ( unsigned const char * )op1_complementary; } else abs_op1 = ( unsigned const char * )op1; if ( INTEGER_SIGN ( op2 ) ) { /* May be integer overflow for minimal int. But result is correct because it is unsigned. */ ammunition_make_complementary_code ( size, op2, op2_complementary ); abs_op2 = ( unsigned const char * )op2_complementary; } else abs_op2 = ( unsigned const char * )op2; ammunition_overflow_bit = ammunition_divide_unsigned_integer_without_overflow_reaction ( size, abs_op1, abs_op2, result ); unsigned_result_sign = INTEGER_SIGN ( result ); if ( negative_result_flag ) ammunition_make_complementary_code ( size, result, result ); if ( unsigned_result_sign && ( !negative_result_flag || INTEGER_SIGN ( result ) != unsigned_result_sign ) ) /* Unsigned result can not be represented as integer. */ ammunition_overflow_bit = 1; if ( ammunition_overflow_bit ) ammunition_arithmetic_overflow_reaction(); } /* This page contains functions for arbitrary precision evaluation of remainder. */ /* The function evaluates remainder of division of unsigned integers as `op1 - (op1/op2)*op2' and fixes overflow reaction if it is needed. Result can be placed in any operand. */ void ammunition_unsigned_integer_remainder ( int size, const void *op1, const void *op2, void *result ) { unsigned char temporary [MAX_INTEGER_OPERAND_SIZE]; ammunition_divide_unsigned_integer ( size, op1, op2, temporary ); if ( ammunition_overflow_bit ) /* Reaction on zero is called from `divide_unsigned_integer'. */ ammunition_memset ( result, 0, ( size_x ) size ); else { ammunition_multiply_unsigned_integer ( size, temporary, op2, temporary ); ammunition_subtract_unsigned_integer ( size, op1, temporary, result ); } } /* This page contains functions for arbitrary precision number shifts. */ /* This function makes right shift of unsigned integer of given size on given number of bits. If number of bits is negative the function makes shift to left actually with the aid of function `unsigned_integer_shift_left'. The function fixes overflow when result can not be represented by number of given size, i.e. in other words the opposite unsigned shift (to left) results in number not equal to source operand. Result can be placed in operand. */ void ammunition_unsigned_integer_shift_right ( int size, const void *operand, int bits, void *result ) { int byte_number; unsigned byte; unsigned carry; int bit_shift; int byte_shift; if ( bits < 0 ) ammunition_unsigned_integer_shift_left ( size, operand, -bits, result ); else { ammunition_overflow_bit = 0; byte_shift = bits / CHAR_BIT; bit_shift = bits % CHAR_BIT; _Pragma( "loopbound min 0 max 3" ) for ( byte_number = ( byte_shift >= size ? 0 : size - byte_shift ); byte_number < size; byte_number++ ) if ( ( ( unsigned char * ) operand ) [byte_number] != 0 ) { ammunition_overflow_bit = 1; break; } if ( byte_shift >= size ) ammunition_memset ( result, 0, ( size_x ) size ); else { ammunition_memmove ( ( char * ) result + byte_shift, operand, ( size_x ) ( size - byte_shift ) ); ammunition_memset ( result, 0, ( size_x ) byte_shift ); if ( bit_shift == 0 ) return; _Pragma( "loopbound min 3 max 3" ) for ( byte_number = byte_shift, carry = 0; byte_number < size; byte_number++ ) { byte = ( ( unsigned char * ) result ) [byte_number]; ( ( unsigned char * ) result ) [byte_number] = carry | ( byte >> bit_shift ); carry = ( byte << ( CHAR_BIT - bit_shift ) ) & UCHAR_MAX; } if ( carry != 0 ) ammunition_overflow_bit = 1; } if ( ammunition_overflow_bit ) ammunition_arithmetic_unsigned_overflow_reaction(); } } /* This function makes right arithmetic shift of integer of given size on given number of bits. If number of bits is negative the function makes shift to left actually with the aid of function `integer_shift_left'. The function fixes overflow when result can not be represented by number of given size, i.e. in other words the opposite shift (to left) results in number not equal to source operand. Result can be placed in operand. */ void ammunition_integer_shift_right ( int size, const void *operand, int bits, void *result ) { int byte_number; unsigned byte; unsigned carry; int bit_shift; int byte_shift; int operand_sign; if ( bits < 0 ) ammunition_integer_shift_left ( size, operand, -bits, result ); else { operand_sign = INTEGER_SIGN ( operand ); ammunition_overflow_bit = 0; byte_shift = bits / CHAR_BIT; bit_shift = bits % CHAR_BIT; _Pragma( "loopbound min 0 max 3" ) for ( byte_number = ( byte_shift >= size ? 0 : size - byte_shift ); byte_number < size; byte_number++ ) if ( ( ( unsigned char * ) operand ) [byte_number] != 0 ) { ammunition_overflow_bit = 1; break; } if ( byte_shift >= size ) ammunition_memset ( result, ( operand_sign ? UCHAR_MAX : 0 ), ( size_x ) size ); else { ammunition_memmove ( ( char * ) result + byte_shift, operand, ( size_x ) ( size - byte_shift ) ); ammunition_memset ( result, ( operand_sign ? UCHAR_MAX : 0 ), ( size_x ) byte_shift ); if ( bit_shift == 0 ) return; carry = ( ( ( operand_sign ? UCHAR_MAX : 0 ) << ( CHAR_BIT - bit_shift ) ) & UCHAR_MAX ); _Pragma( "loopbound min 3 max 3" ) for ( byte_number = byte_shift; byte_number < size; byte_number++ ) { byte = ( ( unsigned char * ) result ) [byte_number]; ( ( unsigned char * ) result ) [byte_number] = carry | ( byte >> bit_shift ); carry = ( byte << ( CHAR_BIT - bit_shift ) ) & UCHAR_MAX; } if ( carry != 0 ) ammunition_overflow_bit = 1; } if ( ammunition_overflow_bit ) ammunition_arithmetic_overflow_reaction(); } } /* This function makes left shift of unsigned integer of given size on given number of bits. If number of bits is negative the function makes shift to left actually with the aid of function `unsigned_integer_shift_right'. The function fixes overflow when result can not be represented by number of given size, i.e. i.e. in other words the opposite shift (to right) results in number not equal to source operand. Result can be placed in operand. */ void ammunition_unsigned_integer_shift_left ( int size, const void *operand, int bits, void *result ) { int byte_number; unsigned byte; unsigned carry; int bit_shift; int byte_shift; if ( bits < 0 ) ammunition_unsigned_integer_shift_right ( size, operand, -bits, result ); else { ammunition_overflow_bit = 0; byte_shift = bits / CHAR_BIT; bit_shift = bits % CHAR_BIT; _Pragma( "loopbound min 0 max 2" ) for ( byte_number = 0; byte_number < byte_shift && byte_number < size; byte_number++ ) if ( ( ( unsigned char * ) operand ) [byte_number] != 0 ) { ammunition_overflow_bit = 1; break; } if ( byte_shift >= size ) ammunition_memset ( result, 0, ( size_x ) size ); else { ammunition_memmove ( result, ( char * ) operand + byte_shift, ( size_x ) ( size - byte_shift ) ); ammunition_memset ( ( char * ) result + ( size - byte_shift ), 0, ( size_x ) byte_shift ); if ( bit_shift == 0 ) return; _Pragma( "loopbound min 2 max 3" ) for ( byte_number = size - byte_shift - 1, carry = 0; byte_number >= 0; byte_number-- ) { byte = ( ( unsigned char * ) result ) [byte_number]; ( ( unsigned char * ) result ) [byte_number] = carry | ( byte << bit_shift ); carry = byte >> ( CHAR_BIT - bit_shift ); } if ( carry != 0 ) ammunition_overflow_bit = 1; } if ( ammunition_overflow_bit ) ammunition_arithmetic_unsigned_overflow_reaction(); } } /* This function makes left arithmetic shift of integer of given size on given number of bits. If number of bits is negative the function makes shift to left actually with the aid of function `integer_shift_right'. The function fixes overflow when result can not be represented by number of given size, i.e. in other words the opposite shift (to right) results in number not equal to source operand. Result can be placed in operand. */ void ammunition_integer_shift_left ( int size, const void *operand, int bits, void *result ) { int byte_number; unsigned byte; unsigned carry; int bit_shift; int byte_shift; int operand_sign; if ( bits < 0 ) ammunition_integer_shift_right ( size, operand, -bits, result ); else { operand_sign = INTEGER_SIGN ( operand ); ammunition_overflow_bit = 0; byte_shift = bits / CHAR_BIT; bit_shift = bits % CHAR_BIT; _Pragma( "loopbound min 0 max 2" ) for ( byte_number = 0; byte_number < byte_shift && byte_number < size; byte_number++ ) if ( ( ( unsigned char * ) operand ) [byte_number] != ( operand_sign ? UCHAR_MAX : 0 ) ) { ammunition_overflow_bit = 1; break; } if ( byte_shift >= size ) ammunition_memset ( result, 0, ( size_x ) size ); else { ammunition_memmove ( result, ( char * ) operand + byte_shift, ( size_x ) ( size - byte_shift ) ); ammunition_memset ( ( char * ) result + ( size - byte_shift ), 0, ( size_x ) byte_shift ); if ( bit_shift == 0 ) return; _Pragma( "loopbound min 2 max 3" ) for ( byte_number = size - byte_shift - 1, carry = 0; byte_number >= 0; byte_number-- ) { byte = ( ( unsigned char * ) result ) [byte_number]; ( ( unsigned char * ) result ) [byte_number] = carry | ( byte << bit_shift ); carry = byte >> ( CHAR_BIT - bit_shift ); } if ( carry != ( ( unsigned ) ( operand_sign ? UCHAR_MAX : 0 ) >> ( CHAR_BIT - bit_shift ) ) ) ammunition_overflow_bit = 1; } if ( operand_sign != INTEGER_SIGN ( result ) ) ammunition_overflow_bit = 1; if ( ammunition_overflow_bit ) ammunition_arithmetic_overflow_reaction(); } } /* This page contains functions for bitwise operations of arbitrary precision numbers. */ /* This function makes bitwise `or' of two integers of given size. */ void ammunition_integer_or ( int size, const void *op1, const void *op2, void *result ) { int byte_number; _Pragma( "loopbound min 4 max 4" ) for ( byte_number = 0; byte_number < size; byte_number++ ) { ( ( unsigned char * ) result ) [byte_number] = ( ( unsigned char * ) op1 ) [byte_number] | ( ( unsigned char * ) op2 ) [byte_number]; } } /* This function makes bitwise `or' of two unsigned integers of given size. */ void ammunition_unsigned_integer_or ( int size, const void *op1, const void *op2, void *result ) { ammunition_integer_or ( size, op1, op2, result ); } /* This function makes bitwise `and' of two integers of given size. */ void ammunition_integer_and ( int size, const void *op1, const void *op2, void *result ) { int byte_number; _Pragma( "loopbound min 4 max 4" ) for ( byte_number = 0; byte_number < size; byte_number++ ) { ( ( unsigned char * ) result ) [byte_number] = ( ( unsigned char * ) op1 ) [byte_number] & ( ( unsigned char * ) op2 ) [byte_number]; } } /* This function makes bitwise `and' of two unsigned integers of given size. */ void ammunition_unsigned_integer_and ( int size, const void *op1, const void *op2, void *result ) { ammunition_integer_and ( size, op1, op2, result ); } /* This function makes bitwise `not' of integer of given size. */ void ammunition_integer_not ( int size, const void *operand, void *result ) { int byte_number; _Pragma( "loopbound min 4 max 4" ) for ( byte_number = 0; byte_number < size; byte_number++ ) { ( ( unsigned char * ) result ) [byte_number] = ( ( unsigned char * ) operand ) [byte_number] ^ UCHAR_MAX; } } /* This function makes bitwise `not' of unsigned integer of given size. */ void ammunition_unsigned_integer_not ( int size, const void *operand, void *result ) { ammunition_integer_not ( size, operand, result ); } /* This page contains functions for comparison of arbitrary precision numbers. */ /* This function compares two unsigned integers of given size on equality. The function returns 1 if unsigned integers are equal, 0 otherwise. */ int ammunition_eq_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_memcmp ( op1, op2, ( size_x ) size ) == 0; } /* This function compares two integers of given size on equality. The function returns 1 if integers are equal, 0 otherwise. */ int ammunition_eq_integer ( int size, const void *op1, const void *op2 ) { return ammunition_memcmp ( op1, op2, ( size_x ) size ) == 0; } /* This function compares two unsigned integers of given size on inequality. The function returns 1 if unsigned integers are not equal, 0 otherwise. */ int ammunition_ne_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_memcmp ( op1, op2, ( size_x ) size ) != 0; } /* This function compares two integers of given size on inequality. The function returns 1 if integers are not equal, 0 otherwise. */ int ammunition_ne_integer ( int size, const void *op1, const void *op2 ) { return ammunition_memcmp ( op1, op2, ( size_x ) size ) != 0; } /* This function compares two memory parts of given size on that the first operand is greater than the second. The bytes are described as unsigned. The function returns 1 if the first operand is greater than the second, - 1 if the first operand is less than the second, 0 otherwise. */ int ammunition_bytes_comparison ( const void *op1, const void *op2, int size ) { const unsigned char *str1 = ( unsigned const char * )op1; const unsigned char *str2 = ( unsigned const char * )op2; _Pragma( "loopbound min 1 max 4" ) while ( size > 0 && *str1 == *str2 ) { str1++; str2++; size--; } if ( size <= 0 ) return 0; else if ( *str1 > *str2 ) return 1; else return -1; } /* This function compares two unsigned integers of given size on that the first operand is greater than the second. The function returns 1 if the first unsigned integer is greater than the second, 0 otherwise. */ int ammunition_gt_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_bytes_comparison ( op1, op2, size ) > 0; } /* This function compares two integers of given size on that the first operand is greater than the second. The function returns 1 if the first integer is greater than the second, 0 otherwise. */ int ammunition_gt_integer ( int size, const void *op1, const void *op2 ) { if ( INTEGER_SIGN ( op1 ) == 0 ) { if ( INTEGER_SIGN ( op2 ) == 0 ) return ammunition_bytes_comparison ( op1, op2, size ) > 0; else return 1; /* TRUE */ } else if ( INTEGER_SIGN ( op2 ) == 0 ) return 0; /*FALSE*/ else return ammunition_bytes_comparison ( op1, op2, size ) > 0; } /* This function compares two unsigned integers of given size on that the first operand is less than the second. The function returns 1 if the first unsigned integer is less than the second, 0 otherwise. */ int ammunition_lt_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_bytes_comparison ( op1, op2, size ) < 0; } /* This function compares two integers of given size on that the first operand is less than the second. The function returns 1 if the first integer is less than the second, 0 otherwise. */ int ammunition_lt_integer ( int size, const void *op1, const void *op2 ) { if ( INTEGER_SIGN ( op1 ) == 0 ) { if ( INTEGER_SIGN ( op2 ) == 0 ) return ammunition_bytes_comparison ( op1, op2, size ) < 0; else return 0; /*FALSE*/ } else if ( INTEGER_SIGN ( op2 ) == 0 ) return 1; /* TRUE */ else return ammunition_bytes_comparison ( op1, op2, size ) < 0; } /* This function compares two unsigned integers of given size on that the first operand is greater than or equal to the second. The function returns 1 if the first unsigned integer is greater than or equal to the second, 0 otherwise. */ int ammunition_ge_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_bytes_comparison ( op1, op2, size ) >= 0; } /* This function compares two integers of given size on that the first operand is greater than or equal to the second. The function returns 1 if the first integer is greater than or equal to the second, 0 otherwise. */ int ammunition_ge_integer ( int size, const void *op1, const void *op2 ) { if ( INTEGER_SIGN ( op1 ) == 0 ) { if ( INTEGER_SIGN ( op2 ) == 0 ) return ammunition_bytes_comparison ( op1, op2, size ) >= 0; else return 1; /* TRUE */ } else if ( INTEGER_SIGN ( op2 ) == 0 ) return 0; /*FALSE*/ else return ammunition_bytes_comparison ( op1, op2, size ) >= 0; } /* This function compares two unsigned integers of given size on that the first operand is less than or equal to the second. The function returns 1 if the first unsigned integer is less than or equal to the second, 0 otherwise. */ int ammunition_le_unsigned_integer ( int size, const void *op1, const void *op2 ) { return ammunition_bytes_comparison ( op1, op2, size ) <= 0; } /* This function compares two integers of given * field <y> of register <x>. This value is suitable for direct * comparison with unshifted values appropriate for use in field <y> * of register <x>. */ #ifndef _hw_ltc_gv11b_h_ #define _hw_ltc_gv11b_h_ static inline u32 ltc_pltcg_base_v(void) { return 0x00140000U; } static inline u32 ltc_pltcg_extent_v(void) { return 0x0017ffffU; } static inline u32 ltc_ltc0_ltss_v(void) { return 0x00140200U; } static inline u32 ltc_ltc0_lts0_v(void) { return 0x00140400U; } static inline u32 ltc_ltcs_ltss_v(void) { return 0x0017e200U; } static inline u32 ltc_ltcs_lts0_cbc_ctrl1_r(void) { return 0x0014046cU; } static inline u32 ltc_ltc0_lts0_dstg_cfg0_r(void) { return 0x00140518U; } static inline u32 ltc_ltcs_ltss_dstg_cfg0_r(void) { return 0x0017e318U; } static inline u32 ltc_ltcs_ltss_dstg_cfg0_vdc_4to2_disable_m(void) { return 0x1U << 15U; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_r(void) { return 0x00140494U; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_active_ways_v(u32 r) { return (r >> 0U) & 0xffffU; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_active_sets_v(u32 r) { return (r >> 16U) & 0x3U; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_active_sets_all_v(void) { return 0x00000000U; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_active_sets_half_v(void) { return 0x00000001U; } static inline u32 ltc_ltc0_lts0_tstg_cfg1_active_sets_quarter_v(void) { return 0x00000002U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_r(void) { return 0x0017e26cU; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_clean_active_f(void) { return 0x1U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_invalidate_active_f(void) { return 0x2U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_clear_v(u32 r) { return (r >> 2U) & 0x1U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_clear_active_v(void) { return 0x00000001U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl1_clear_active_f(void) { return 0x4U; } static inline u32 ltc_ltc0_lts0_cbc_ctrl1_r(void) { return 0x0014046cU; } static inline u32 ltc_ltcs_ltss_cbc_ctrl2_r(void) { return 0x0017e270U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl2_clear_lower_bound_f(u32 v) { return (v & 0x3ffffU) << 0U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl3_r(void) { return 0x0017e274U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl3_clear_upper_bound_f(u32 v) { return (v & 0x3ffffU) << 0U; } static inline u32 ltc_ltcs_ltss_cbc_ctrl3_clear_upper_bound_init_v(void) { return 0x0003ffffU