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