-/****i* strcalc/implementation
- *
- * AUTHORS
- * Matthias Heil
- *
- * NOTES
- ******/
+/*
+ * Project: libFIRM
+ * File name: ir/tv/strcalc.c
+ * Purpose:
+ * Author: Mathias Heil
+ * Modified by:
+ * Created:
+ * CVS-ID: $Id$
+ * Copyright: (c) 2003 Universität Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
-#include <assert.h> /* assertions */
-#include <string.h> /* memset/memcmp */
#include "strcalc.h"
-#include <stdio.h> /* output for error messages */
#include <stdlib.h>
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+#include <assert.h> /* assertions */
+#include <string.h> /* memset/memcmp */
+#include <stdio.h> /* output for error messages */
+#include <limits.h> /* definition of LONG_MIN, used in sc_get_val_from_long */
/*
* local definitions and macros
*/
-#define BIT_PATTERN_SIZE (8 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-#define CALC_BUFFER_SIZE (4 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-#define MAX_VALUE_SIZE (2 * BIGGEST_INTEGER_SIZE_IN_BYTES)
-
-#define CLEAR_CALC_BUFFER() assert(calc_buffer); memset(calc_buffer, SC_0, CALC_BUFFER_SIZE)
+#define CLEAR_BUFFER(b) assert(b); memset(b, SC_0, CALC_BUFFER_SIZE)
#define _val(a) ((a)-SC_0)
#define _digit(a) ((a)+SC_0)
#define _bitisset(digit, pos) (and_table[_val(digit)][_val(shift_table[pos])] != SC_0)
#define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__, __LINE__)
-/* shortcut output for debugging only, gices always full precisition */
-#define sc_print_hex(a) sc_print((a), 0, SC_HEX)
-#define sc_print_dec(a) sc_print((a), 0, SC_DEC)
-#define sc_print_oct(a) sc_print((a), 0, SC_OCT)
-#define sc_print_bin(a) sc_print((a), 0, SC_BIN)
+/* shortcut output for debugging */
+# define sc_print_hex(a) sc_print((a), 0, SC_HEX)
+# define sc_print_dec(a) sc_print((a), 0, SC_DEC)
+# define sc_print_oct(a) sc_print((a), 0, SC_OCT)
+# define sc_print_bin(a) sc_print((a), 0, SC_BIN)
-
-#if 0
+#ifdef STRCALC_DEBUG_PRINTCOMP
+# define DEBUGPRINTF_COMPUTATION(x) printf x
+#else
+# define DEBUGPRINTF_COMPUTATION(x) ((void)0)
+#endif
+#ifdef STRCALC_DEBUG
# define DEBUGPRINTF(x) printf x
#else
# define DEBUGPRINTF(x) ((void)0)
#endif
+
/*
* private variables
*/
-static char calc_buffer[CALC_BUFFER_SIZE]; /* buffer holding all results */
+static char *calc_buffer = NULL; /* buffer holding all results */
+static char *output_buffer = NULL; /* buffer for output */
+static int BIT_PATTERN_SIZE; /* maximum number of bits */
+static int CALC_BUFFER_SIZE; /* size of internally stored values */
+static int MAX_VALUE_SIZE; /* maximum size of values */
+
+static int carry_flag; /* some computation set carry_flag: */
+ /* rightshift if bits were lost due to shifting */
+ /* division if there was a remainder */
static const char max_digit[4] = { SC_0, SC_1, SC_3, SC_7 };
static const char min_digit[4] = { SC_F, SC_E, SC_C, SC_8 };
SC_8, SC_8, SC_8, SC_8, SC_C, SC_C, SC_C, SC_C },
{ SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5,
- SC_8, SC_9, SC_8, SC_9, SC_D, SC_E, SC_D, SC_E },
+ SC_8, SC_9, SC_8, SC_9, SC_C, SC_D, SC_C, SC_D },
{ SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6,
SC_8, SC_8, SC_A, SC_A, SC_C, SC_C, SC_E, SC_E },
static int _sign(const char *val)
{
- return (val[CALC_BUFFER_SIZE-1] < SC_7) ? (1) : (-1);
+ return (val[CALC_BUFFER_SIZE-1] <= SC_7) ? (1) : (-1);
+}
+
+/*
+ * returns non-zero if bit at position pos is set
+ */
+static int _bit(const char *val, int pos)
+{
+ int bit = pos & 3;
+ int nibble = pos >> 2;
+
+ return _bitisset(val[nibble], bit);
}
static void _inc(char *val, char *buffer)
return;
}
}
- /* here a carry could be lost, this is intended because this will only
- * happen when a value changes sign. */
+ /* here a carry could be lost, this is intended because this should
+ * happen only when a value changes sign. */
}
static void _negate(const char *val, char *buffer)
buffer[counter] = add2[0];
carry = add_table[_val(add1[1])][_val(add2[1])][0];
}
- /* loose last carry, which will occur only when changing sign */
}
static void _mul(const char *val1, const char *val2, char *buffer)
{
- char temp_buffer[CALC_BUFFER_SIZE]; /* result buffer */
- char neg_val1[CALC_BUFFER_SIZE]; /* abs of val1 */
- char neg_val2[CALC_BUFFER_SIZE]; /* abs of val2 */
+ char* temp_buffer; /* result buffer */
+ char* neg_val1; /* abs of val1 */
+ char* neg_val2; /* abs of val2 */
const char *mul, *add1, *add2; /* intermediate result containers */
char carry = SC_0; /* container for carries */
char sign = 0; /* marks result sign */
int c_inner, c_outer; /* loop counters */
+ temp_buffer = alloca(CALC_BUFFER_SIZE);
+ neg_val1 = alloca(CALC_BUFFER_SIZE);
+ neg_val2 = alloca(CALC_BUFFER_SIZE);
+
/* init result buffer to zeroes */
memset(temp_buffer, SC_0, CALC_BUFFER_SIZE);
/* A carry may hang over */
/* c_outer is always smaller than MAX_VALUE_SIZE! */
temp_buffer[MAX_VALUE_SIZE + c_outer] = carry;
+ carry = SC_0;
}
}
static void _sub(const char *val1, const char *val2, char *buffer)
{
- char temp_buffer[CALC_BUFFER_SIZE]; /* intermediate buffer to hold -val2 */
+ char *temp_buffer; /* intermediate buffer to hold -val2 */
+ temp_buffer = alloca(CALC_BUFFER_SIZE);
_negate(val2, temp_buffer);
_add(val1, temp_buffer, buffer);
static void _divmod(const char *dividend, const char *divisor, char *quot, char *rem)
{
const char *minus_divisor;
- char neg_val1[CALC_BUFFER_SIZE];
- char neg_val2[CALC_BUFFER_SIZE];
+ char *neg_val1;
+ char *neg_val2;
char sign = 0; /* remember result sign */
int c_dividend; /* loop counters */
+ neg_val1 = alloca(CALC_BUFFER_SIZE);
+ neg_val2 = alloca(CALC_BUFFER_SIZE);
+
/* clear result buffer */
memset(quot, SC_0, CALC_BUFFER_SIZE);
memset(rem, SC_0, CALC_BUFFER_SIZE);
+ /* if the divisor is zero this won't work (quot is zero) */
+ if (sc_comp(divisor, quot) == 0) assert(0 && "division by zero!");
+
/* if the dividend is zero result is zero (quot is zero)*/
if (sc_comp(dividend, quot) == 0)
return;
- /* if the divisor is zero this won't work (quot is zero) */
- if (sc_comp(divisor, quot) == 0) assert(0 && "quotision by zero!");
if (_sign(dividend) == -1)
{
minus_divisor = neg_val2;
}
- /* if divisor >= dividend quotision is easy
+ /* if divisor >= dividend division is easy
* (remember these are absolute values) */
switch (sc_comp(dividend, divisor))
{
memcpy(rem, dividend, CALC_BUFFER_SIZE);
return;
- default: /* unluckily quotision is necessary :( */
+ default: /* unluckily division is necessary :( */
break;
}
- for (c_dividend = MAX_VALUE_SIZE - 1; c_dividend >= 0; c_dividend--)
+ for (c_dividend = CALC_BUFFER_SIZE - 1; c_dividend >= 0; c_dividend--)
{
_push(dividend[c_dividend], rem);
_push(SC_0, quot);
}
}
+ carry_flag = !sc_is_zero(rem);
+
if (sign)
{
_negate(quot, quot);
}
}
-static void _shl(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed)
+static void _shl(const char *val1, char *buffer, long offset, int radius, unsigned is_signed)
{
const char *shl;
char shift;
char carry = SC_0;
int counter;
- int offset = 0;
int bitoffset = 0;
- assert((_sign(val2) != -1) || (0 && "negative leftshift"));
+ assert((offset >= 0) || (0 && "negative leftshift"));
assert(((_sign(val1) != -1) || is_signed) || (0 && "unsigned mode and negative value"));
assert(((!_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == -1)) || (0 && "value is positive, should be negative"));
assert(((_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == 1)) || (0 && "value is negative, should be positive"));
- /* the whole value must be moved left the number of bytes represented
- * by the value in quot, with bytes to the right set to zero */
- /*XXX This might result in trouble */
- for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
- {
- offset = (offset << 4) | (_val(val2[counter]));
- }
-
- shift = shift_table[_val(offset%4)]; /* this is 2 ** (val2 % 4) */
-
/* if shifting far enough the result is zero */
if (offset >= radius)
{
memset(buffer, SC_0, CALC_BUFFER_SIZE);
return;
}
+
+ shift = shift_table[_val(offset%4)]; /* this is 2 ** (offset % 4) */
offset = offset / 4;
/* shift the single digits some bytes (offset) and some bits (table)
* to the left */
- for (counter = 0; counter < CALC_BUFFER_SIZE - offset; counter++)
+ for (counter = 0; counter < radius/4 - offset; counter++)
{
shl = mul_table[_val(val1[counter])][_val(shift)];
buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
carry = shl[1];
}
+ if (radius%4 > 0)
+ {
+ shl = mul_table[_val(val1[counter])][_val(shift)];
+ buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
+ bitoffset = counter;
+ } else {
+ bitoffset = counter - 1;
+ }
/* fill with zeroes */
- for (counter = 0; counter < offset; counter++) buffer[counter] = 0;
+ for (counter = 0; counter < offset; counter++) buffer[counter] = SC_0;
+
/* if the mode was signed, change sign when the mode's msb is now 1 */
- offset = (radius - 1) / 4;
- bitoffset = (radius - 1) % 4;
- if (is_signed && _bitisset(buffer[offset], bitoffset) && (_sign(buffer) == 1))
+ offset = bitoffset + offset;
+ bitoffset = (radius-1) % 4;
+ if (is_signed && _bitisset(buffer[offset], bitoffset))
{
/* this sets the upper bits of the leftmost digit */
buffer[offset] = or_table[_val(buffer[offset])][_val(min_digit[bitoffset])];
buffer[counter] = SC_F;
}
}
- else if (is_signed && !_bitisset(buffer[offset], bitoffset) && (_sign(buffer) == -1))
+ else if (is_signed && !_bitisset(buffer[offset], bitoffset))
{
/* this unsets the upper bits of the leftmost digit */
buffer[offset] = and_table[_val(buffer[offset])][_val(max_digit[bitoffset])];
- /* zero the upper part of the value */
for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++)
{
buffer[counter] = SC_0;
}
}
-static void _shr(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed, int signed_shift)
+static void _shr(const char *val1, char *buffer, long offset, int radius, unsigned is_signed, int signed_shift)
{
const char *shrs;
char sign;
int shift;
int counter;
- int offset = 0;
int bitoffset = 0;
- assert((_sign(val2) != -1) || (0 && "negative rightshift"));
+ assert((offset >= 0) || (0 && "negative rightshift"));
assert(((_sign(val1) != -1) || is_signed) || (0 && "unsigned mode and negative value"));
assert(((!_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == -1)) || (0 && "value is positive, should be negative"));
assert(((_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == 1)) || (0 && "value is negative, should be positive"));
- /*XXX get the value of val2, this might result in trouble *
- * (but who wants shifts THAT far anyway) */
- for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
- {
- offset = (offset << 4) | (_val(val2[counter]));
- }
-
- shift = offset % 4; /* this is val2 % 4 */
-
sign = ((signed_shift) && (_sign(val1) == -1))?(SC_F):(SC_0);
+
/* if shifting far enough the result is either 0 or -1 */
if (offset >= radius)
{
+ if (!sc_is_zero(val1)) {
+ carry_flag = 1;
+ }
memset(buffer, sign, CALC_BUFFER_SIZE);
return;
}
+
+ shift = offset % 4;
offset = offset / 4;
- buffer[0] = shrs_table[_val(val1[offset])][shift][0];
+ /* check if any bits are lost, and set carry_flag if so */
+ for (counter = 0; counter < offset; counter++)
+ {
+ if (val1[counter] != 0)
+ {
+ carry_flag = 1;
+ break;
+ }
+ }
+ if ((_val(val1[counter]) & ((1<<shift)-1)) != 0)
+ {
+ carry_flag = 1;
+ }
/* shift digits to the right with offset, carry and all */
- for (counter = 1; counter < radius/4; counter++)
+ counter = 0;
+ if (radius/4 - offset > 0) {
+ buffer[counter] = shrs_table[_val(val1[offset])][shift][0];
+ counter = 1;
+ }
+ for (; counter < radius/4 - offset; counter++)
{
shrs = shrs_table[_val(val1[counter + offset])][shift];
buffer[counter] = shrs[0];
}
/* the last digit is special in regard of signed/unsigned shift */
- /* counter = radius/4 (after for loop) */
bitoffset = radius%4;
- msd = val1[counter]; /* most significant digit */
+ msd = (radius/4<CALC_BUFFER_SIZE)?(val1[radius/4]):(sign); /* most significant digit */
/* remove sign bits if mode was signed and this is an unsigned shift */
if (!signed_shift && is_signed) {
} else {
buffer[counter] = shrs[0];
}
- buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
+
+ if (counter > 0) buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
/* fill with SC_F or SC_0 depending on sign */
for (counter++; counter < CALC_BUFFER_SIZE; counter++)
}
/* positive: low-order -> high order, negative other direction */
-static void _rot(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed)
+static void _rot(const char *val1, char *buffer, long offset, int radius, unsigned is_signed)
{
- char temp_buffer[CALC_BUFFER_SIZE];
+ char *temp1, *temp2;
+ temp1 = alloca(CALC_BUFFER_SIZE);
+ temp2 = alloca(CALC_BUFFER_SIZE);
- const char *shl;
- char carry = SC_0;
-
- int counter, old_counter;
- int shift;
- int offset = 0;
- int bitoffset;
+ offset = offset % radius;
- /*XXX get the value of val2, this might result in trouble *
- * (but who wants shifts THAT far anyway) */
- for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--)
- {
- offset = (offset << 4) | (_val(val2[counter]));
- }
/* rotation by multiples of the typelength is identity */
- offset = offset % radius;
if (offset == 0) {
memmove(buffer, val1, CALC_BUFFER_SIZE);
return;
}
- /* rotation to the right is the same as rotation to the left
- * when done by the right amount */
- if (offset < 0) offset = radius + offset;
-
- shift = _val(shift_table[offset % 4]);
- offset = offset / 4;
-
- DEBUGPRINTF(("offset: %d, shift: %d\n", offset, shift));
- for (counter = 0; counter < radius/4 - offset; counter++)
- {
- shl = mul_table[_val(val1[counter])][_val(shift)];
- temp_buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)];
- carry = shl[1];
- DEBUGPRINTF(("%d(%x): %s\n", counter, shl[0], sc_print_hex(temp_buffer)));
- }
- old_counter = counter;
- for (; counter < radius/4; counter++)
- {
- shl = mul_table[_val(val1[counter])][_val(shift)];
- temp_buffer[counter - old_counter] = or_table[_val(shl[0])][_val(carry)];
- carry = shl[1];
- DEBUGPRINTF(("%d(%x)> %s\n", counter, shl[0], sc_print_hex(temp_buffer)));
- }
- temp_buffer[counter - old_counter] = or_table[_val(temp_buffer[counter-old_counter])][_val(carry)];
-
- offset = (radius-1)/4;
- bitoffset - (radius-1)%4;
- /* fill the rest of the buffer depending on msb and mode signedness*/
- if (is_signed && _bitisset(temp_buffer[offset], bitoffset))
- {
-
- }
- else
- {
-
- }
- memcpy(buffer, temp_buffer, CALC_BUFFER_SIZE);
+ _shl(val1, temp1, offset, radius, is_signed);
+ _shr(val1, temp2, radius - offset, radius, is_signed, 0);
+ _bitor(temp1, temp2, buffer);
+ carry_flag = 0; /* set by shr, but due to rot this is false */
}
/*****************************************************************************
return CALC_BUFFER_SIZE;
}
-void sc_val_from_str(const char *str, unsigned int len)
+/* XXX doesn't check for overflows */
+void sc_val_from_str(const char *str, unsigned int len, void *buffer)
{
const char *orig_str = str;
unsigned int orig_len = len;
char sign = 0;
- char base[CALC_BUFFER_SIZE];
- char val[CALC_BUFFER_SIZE];
+ char *base, *val;
+
+ base = alloca(CALC_BUFFER_SIZE);
+ val = alloca(CALC_BUFFER_SIZE);
/* verify valid pointers (not null) */
assert(str);
/* a string no characters long is an error */
assert(len);
- CLEAR_CALC_BUFFER();
+ if (buffer == NULL) buffer = calc_buffer;
+
+ CLEAR_BUFFER(buffer);
memset(base, SC_0, CALC_BUFFER_SIZE);
memset(val, SC_0, CALC_BUFFER_SIZE);
base[1] = SC_0; base[0] = SC_A;
}
- /* begin string evaluation, from left to right */
+ /* BEGIN string evaluation, from left to right */
while (len > 0)
{
switch (*str)
}
}
-void sc_val_from_long(long value)
+void sc_val_from_long(long value, void *buffer)
{
char *pos;
- int sign;
+ char sign, is_minlong;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ pos = buffer;
- pos = calc_buffer;
sign = (value < 0);
+ is_minlong = value == LONG_MIN;
- /* FIXME MININT won't work */
- if (sign) value = -value;
+ /* use absolute value, special treatment of MIN_LONG */
+ if (sign) {
+ if (is_minlong)
+ value = -(value+1);
+ else
+ value = -value;
+ }
- CLEAR_CALC_BUFFER();
+ CLEAR_BUFFER(buffer);
- while ((value != 0) && (pos < calc_buffer + CALC_BUFFER_SIZE))
+ while ((value != 0) && (pos < (char*)buffer + CALC_BUFFER_SIZE))
{
- *pos++ = _digit(value % 16);
- value /= 16;
+ *pos++ = _digit(value & 0xf);
+ value >>= 4;
}
- if (sign) _negate(calc_buffer, calc_buffer);
+
+ if (sign) {
+ if (is_minlong)
+ _inc(buffer, buffer);
+
+ _negate(buffer, buffer);
+ }
+}
+
+void sc_val_from_ulong(unsigned long value, void *buffer)
+{
+ char *pos;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ pos = buffer;
+
+ while (pos < (char*)buffer + CALC_BUFFER_SIZE)
+ {
+ *pos++ = _digit(value & 0xf);
+ value >>= 4;
+ }
}
long sc_val_to_long(const void *val)
return l;
}
-void sc_min_from_bits(unsigned int num_bits, unsigned int sign)
+void sc_min_from_bits(unsigned int num_bits, unsigned int sign, void *buffer)
{
char* pos;
int i, bits;
- CLEAR_CALC_BUFFER();
+ if (buffer == NULL) buffer = calc_buffer;
+ CLEAR_BUFFER(buffer);
+
if (!sign) return; /* unsigned means minimum is 0(zero) */
- pos = calc_buffer;
+ pos = buffer;
bits = num_bits - 1;
for (i = 0; i < bits/4; i++)
*pos++ = SC_F;
}
-void sc_max_from_bits(unsigned int num_bits, unsigned int sign)
+void sc_max_from_bits(unsigned int num_bits, unsigned int sign, void *buffer)
{
char* pos;
int i, bits;
- CLEAR_CALC_BUFFER();
- pos = calc_buffer;
+ if (buffer == NULL) buffer = calc_buffer;
+ CLEAR_BUFFER(buffer);
+ pos = buffer;
bits = num_bits - sign;
for (i = 0; i < bits/4; i++)
*pos++ = SC_0;
}
-void sc_calc(const void* value1, const void* value2, unsigned op)
+void sc_calc(const void* value1, const void* value2, unsigned op, void *buffer)
{
- char unused_res[CALC_BUFFER_SIZE]; /* temp buffer holding unused result of divmod */
+ char *unused_res; /* temp buffer holding unused result of divmod */
const char *val1 = (const char *)value1;
const char *val2 = (const char *)value2;
- CLEAR_CALC_BUFFER();
- DEBUGPRINTF(("%s ", sc_print(value1, SC_HEX)));
+ unused_res = alloca(CALC_BUFFER_SIZE);
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
switch (op)
{
case SC_NEG:
_negate(val1, calc_buffer);
- DEBUGPRINTF(("negated: %s\n", sc_print_hex(calc_buffer)));
- return;
+ DEBUGPRINTF_COMPUTATION(("negated: %s\n", sc_print_hex(calc_buffer)));
+ break;
case SC_OR:
- DEBUGPRINTF(("| "));
+ DEBUGPRINTF_COMPUTATION(("| "));
_bitor(val1, val2, calc_buffer);
break;
case SC_AND:
- DEBUGPRINTF(("& "));
+ DEBUGPRINTF_COMPUTATION(("& "));
_bitand(val1, val2, calc_buffer);
break;
case SC_XOR:
- DEBUGPRINTF(("^ "));
+ DEBUGPRINTF_COMPUTATION(("^ "));
_bitxor(val1, val2, calc_buffer);
break;
case SC_NOT:
_bitnot(val1, calc_buffer);
- DEBUGPRINTF(("bit-negated: %s\n", sc_print_hex(calc_buffer)));
- return;
+ DEBUGPRINTF_COMPUTATION(("bit-negated: %s\n", sc_print_hex(calc_buffer)));
+ break;
case SC_ADD:
- DEBUGPRINTF(("+ "));
+ DEBUGPRINTF_COMPUTATION(("+ "));
_add(val1, val2, calc_buffer);
break;
case SC_SUB:
- DEBUGPRINTF(("- "));
+ DEBUGPRINTF_COMPUTATION(("- "));
_sub(val1, val2, calc_buffer);
break;
case SC_MUL:
- DEBUGPRINTF(("* "));
+ DEBUGPRINTF_COMPUTATION(("* "));
_mul(val1, val2, calc_buffer);
break;
case SC_DIV:
- DEBUGPRINTF(("/ "));
+ DEBUGPRINTF_COMPUTATION(("/ "));
_divmod(val1, val2, calc_buffer, unused_res);
break;
case SC_MOD:
- DEBUGPRINTF(("%% "));
+ DEBUGPRINTF_COMPUTATION(("%% "));
_divmod(val1, val2, unused_res, calc_buffer);
break;
default:
assert(0);
}
- DEBUGPRINTF(("%s -> ", sc_print_hex(value2)));
- DEBUGPRINTF(("%s\n", sc_print_hex(calc_buffer)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer))
+ {
+ memcpy(buffer, calc_buffer, CALC_BUFFER_SIZE);
+ }
}
-void sc_bitcalc(const void* value1, const void* value2, unsigned radius, unsigned sign, unsigned op)
+void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, unsigned op, void* buffer)
{
const char *val1 = (const char *)value1;
const char *val2 = (const char *)value2;
- CLEAR_CALC_BUFFER();
+ long offset;
+
+ carry_flag = 0;
+ offset = sc_val_to_long(val2);
- DEBUGPRINTF(("%s ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
switch (op)
{
case SC_SHL:
- DEBUGPRINTF(("<< "));
- _shl(val1, val2, calc_buffer, radius, sign);
+ DEBUGPRINTF_COMPUTATION(("<< %ld ", offset));
+ _shl(val1, calc_buffer, offset, radius, sign);
break;
case SC_SHR:
- DEBUGPRINTF((">> "));
- _shr(val1, val2, calc_buffer, radius, sign, 0);
+ DEBUGPRINTF_COMPUTATION((">> %ld ", offset));
+ _shr(val1, calc_buffer, offset, radius, sign, 0);
break;
case SC_SHRS:
- DEBUGPRINTF((">>> "));
- _shr(val1, val2, calc_buffer, radius, sign, 1);
+ DEBUGPRINTF_COMPUTATION((">>> %ld ", offset));
+ _shr(val1, calc_buffer, offset, radius, sign, 1);
break;
case SC_ROT:
- DEBUGPRINTF(("<<>> "));
- _rot(val1, val2, calc_buffer, radius, sign);
+ DEBUGPRINTF_COMPUTATION(("<<>> %ld ", offset));
+ _rot(val1, calc_buffer, offset, radius, sign);
break;
default:
assert(0);
}
- DEBUGPRINTF(("%s -> ", sc_print_hex(value2)));
- DEBUGPRINTF(("%s\n", sc_print_hex(calc_buffer)));
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer))
+ {
+ memmove(buffer, calc_buffer, CALC_BUFFER_SIZE);
+ }
}
int sc_comp(const void* value1, const void* value2)
return (val1[counter] > val2[counter]) ? (1) : (-1);
}
+int sc_get_highest_set_bit(const void *value)
+{
+ const char *val = (const char*)value;
+ int high, counter;
+
+ high = CALC_BUFFER_SIZE * 4 - 1;
+
+ for (counter = CALC_BUFFER_SIZE-1; counter >= 0; counter--) {
+ if (val[counter] == SC_0) high -= 4;
+ else {
+ if (val[counter] > SC_7) return high;
+ else if (val[counter] > SC_3) return high - 1;
+ else if (val[counter] > SC_1) return high - 2;
+ else return high - 3;
+ }
+ }
+ return high;
+}
+
+int sc_get_lowest_set_bit(const void *value)
+{
+ const char *val = (const char*)value;
+ int low, counter;
+ char sign;
+
+ sign = (_sign(val)==1)?(SC_0):(SC_F);
+ low = 0;
+
+ for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) {
+ if (val[counter] == SC_0) low += 4;
+ else {
+ if (val[counter] < SC_2) return low;
+ else if (val[counter] < SC_4) return low + 1;
+ else if (val[counter] < SC_8) return low + 2;
+ else return low + 3;
+ }
+ }
+ return -1;
+}
+
+int sc_is_zero(const void *value)
+{
+ const char* val = (const char *)value;
+ int counter;
+
+ for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) {
+ if (val[counter] != SC_0) return 0;
+ }
+ return 1;
+}
+
+int sc_is_negative(const void *value)
+{
+ return _sign(value) == -1;
+}
+
+int sc_had_carry(void)
+{
+ return carry_flag;
+}
+
unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs)
{
const char *val = (const char *)value;
/*
* convert to a string
+ * XXX Doesn't check buffer bounds
*/
const char *sc_print(const void *value, unsigned bits, enum base_t base)
{
- char base_val[CALC_BUFFER_SIZE];
- char div1_res[CALC_BUFFER_SIZE];
- char div2_res[CALC_BUFFER_SIZE];
- char rem_res[CALC_BUFFER_SIZE];
- int counter, nibbles, i;
+ static const char big_digits[] = "0123456789ABCDEF";
+ static const char small_digits[] = "0123456789abcdef";
+
+ char *base_val, *div1_res, *div2_res, *rem_res;
+ int counter, nibbles, i, sign;
char x;
const char *val = (const char *)value;
const char *p;
char *m, *n, *t;
char *pos;
- static char *buf = NULL;
+ const char *digits = small_digits;
- if (! buf) {
- /* TODO: this buffer could be allocated in the initialising phase too */
- buf = malloc(BIT_PATTERN_SIZE + 1);
- if (! buf)
- return NULL;
- }
+ base_val = alloca(CALC_BUFFER_SIZE);
+ div1_res = alloca(CALC_BUFFER_SIZE);
+ div2_res = alloca(CALC_BUFFER_SIZE);
+ rem_res = alloca(CALC_BUFFER_SIZE);
- pos = buf + BIT_PATTERN_SIZE;
- *pos = '\0';
+ pos = output_buffer + BIT_PATTERN_SIZE;
+ *(--pos) = '\0';
/* special case */
- if (bits == 0)
+ if (bits == 0) {
bits = BIT_PATTERN_SIZE;
-
+#ifdef STRCALC_DEBUG_FULLPRINT
+ bits <<= 1;
+#endif
+ }
nibbles = bits >> 2;
switch (base) {
case SC_HEX:
- for (counter = 0; counter < nibbles; ++counter)
- *(--pos) = "0123456789abcdef"[_val(val[counter])];
+ digits = big_digits;
+ case SC_hex:
+ for (counter = 0; counter < nibbles; ++counter) {
+ *(--pos) = digits[_val(val[counter])];
+#ifdef STRCALC_DEBUG_GROUPPRINT
+ if ((counter+1)%8 == 0)
+ *(--pos) = ' ';
+#endif
+ }
/* last nibble must be masked */
if (bits & 3) {
x = and_table[_val(val[++counter])][bits & 3];
- *(--pos) = "0123456789abcdef"[_val(x)];
+ *(--pos) = digits[_val(x)];
}
/* now kill zeros */
- for (; counter > 1; --counter, ++pos)
+ for (; counter > 1; --counter, ++pos) {
+#ifdef STRCALC_DEBUG_GROUPPRINT
+ if (pos[0] == ' ') ++pos;
+#endif
if (pos[0] != '0')
break;
+ }
break;
case SC_BIN:
memset(base_val, SC_0, CALC_BUFFER_SIZE);
base_val[0] = base == SC_DEC ? SC_A : SC_8;
+ p = val;
+ sign = 0;
+ if (base == SC_DEC) {
+ /* check for negative values */
+ if (_bit(val, bits - 1)) {
+ _negate(val, div2_res);
+ sign = 1;
+ p = div2_res;
+ }
+ }
+
/* transfer data into oscilating buffers */
memset(div1_res, SC_0, CALC_BUFFER_SIZE);
for (counter = 0; counter < nibbles; ++counter)
- div1_res[counter] = val[counter];
+ div1_res[counter] = p[counter];
- /* last nibble must be masked */
+ /* last nibble must be masked */
if (bits & 3) {
++counter;
- div1_res[counter] = and_table[_val(val[counter])][bits & 3];
+ div1_res[counter] = and_table[_val(p[counter])][bits & 3];
}
m = div1_res;
t = m;
m = n;
n = t;
- *(--pos) = "0123456789abcdef"[_val(rem_res[0])];
+ *(--pos) = digits[_val(rem_res[0])];
x = 0;
for (i = 0; i < sizeof(div1_res); ++i)
if (x == 0)
break;
}
+ if (sign)
+ *(--pos) = '-';
break;
default:
+ printf("%i\n", base);
assert(0);
return NULL;
}
return pos;
}
+
+void init_strcalc(int precision)
+{
+ if (calc_buffer == NULL) {
+ if (precision <= 0) precision = SC_DEFAULT_PRECISION;
+
+ /* round up to multiple of 4 */
+ if (precision & 0x3) precision += 4 - (precision&0x3);
+
+ BIT_PATTERN_SIZE = (precision);
+ CALC_BUFFER_SIZE = (precision / 2);
+ MAX_VALUE_SIZE = (precision / 4);
+
+ calc_buffer = malloc(CALC_BUFFER_SIZE+1 * sizeof(char));
+ output_buffer = malloc(BIT_PATTERN_SIZE+1 * sizeof(char));
+
+ if (calc_buffer == NULL || output_buffer == NULL)
+ {
+ assert(0 && "malloc failed");
+ exit(-1);
+ }
+
+ DEBUGPRINTF(("init strcalc: \n\tPRECISION: %d\n\tCALC_BUFFER_SIZE = %d\n\tMAX_VALUE_SIZE = %d\n\tbuffer pointer: %p\n", precision, CALC_BUFFER_SIZE, MAX_VALUE_SIZE, calc_buffer));
+ }
+}
+
+
+void finish_strcalc() {
+ free(calc_buffer); calc_buffer = NULL;
+ free(output_buffer); output_buffer = NULL;
+}
+int sc_get_precision(void)
+{
+ return BIT_PATTERN_SIZE;
+}