+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;
+
+ low = 0;
+ for (counter = 0; counter < calc_buffer_size; counter++) {
+ switch (val[counter]) {
+ case SC_1:
+ case SC_3:
+ case SC_5:
+ case SC_7:
+ case SC_9:
+ case SC_B:
+ case SC_D:
+ case SC_F:
+ return low;
+ case SC_2:
+ case SC_6:
+ case SC_A:
+ case SC_E:
+ return low + 1;
+ case SC_4:
+ case SC_C:
+ return low + 2;
+ case SC_8:
+ return low + 3;
+ default:
+ low += 4;
+ }
+ }
+ 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 do_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;
+ int nibble_ofs = 2 * byte_ofs;
+ unsigned char res;
+
+ /* the current scheme uses one byte to store a nibble */
+ if (4 * nibble_ofs >= len)
+ return 0;
+
+ res = _val(val[nibble_ofs]);
+ if (len > 4 * (nibble_ofs + 1))
+ res |= _val(val[nibble_ofs + 1]) << 4;
+
+ /* kick bits outsize */
+ if (len - 8 * byte_ofs < 8) {
+ res &= (1 << (len - 8 * byte_ofs)) - 1;
+ }
+ return res;
+}
+
+/*
+ * convert to a string
+ * FIXME: Doesn't check buffer bounds
+ */
+const char *sc_print(const void *value, unsigned bits, enum base_t base, int signed_mode) {
+ 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;
+ const char *digits = small_digits;
+
+ 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 = output_buffer + bit_pattern_size;
+ *(--pos) = '\0';
+
+ /* special case */
+ if (bits == 0) {
+ bits = bit_pattern_size;
+#ifdef STRCALC_DEBUG_FULLPRINT
+ bits <<= 1;
+#endif
+ }
+ nibbles = bits >> 2;
+ switch (base) {
+
+ case SC_HEX:
+ 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) = digits[_val(x)];
+ }
+
+ /* now kill zeros */
+ for (; counter > 1; --counter, ++pos) {
+#ifdef STRCALC_DEBUG_GROUPPRINT
+ if (pos[0] == ' ') ++pos;
+#endif
+ if (pos[0] != '0')
+ break;
+ }
+ break;
+
+ case SC_BIN:
+ for (counter = 0; counter < nibbles; ++counter) {
+ pos -= 4;
+ p = binary_table[_val(val[counter])];
+ pos[0] = p[0];
+ pos[1] = p[1];
+ pos[2] = p[2];
+ pos[3] = p[3];
+ }
+
+ /* last nibble must be masked */
+ if (bits & 3) {
+ x = and_table[_val(val[++counter])][bits & 3];
+
+ pos -= 4;
+ p = binary_table[_val(x)];
+ pos[0] = p[0];
+ pos[1] = p[1];
+ pos[2] = p[2];
+ pos[3] = p[3];
+ }
+
+ /* now kill zeros */
+ for (counter <<= 2; counter > 1; --counter, ++pos)
+ if (pos[0] != '0')
+ break;
+ break;
+
+ case SC_DEC:
+ case SC_OCT:
+ memset(base_val, SC_0, calc_buffer_size);
+ base_val[0] = base == SC_DEC ? SC_A : SC_8;
+
+ p = val;
+ sign = 0;
+ if (signed_mode && base == SC_DEC) {
+ /* check for negative values */
+ if (do_bit(val, bits - 1)) {
+ do_negate(val, div2_res);
+ sign = 1;
+ p = div2_res;
+ }
+ }
+
+ /* transfer data into oscillating buffers */
+ memset(div1_res, SC_0, calc_buffer_size);
+ for (counter = 0; counter < nibbles; ++counter)
+ div1_res[counter] = p[counter];
+
+ /* last nibble must be masked */
+ if (bits & 3) {
+ ++counter;
+
+ div1_res[counter] = and_table[_val(p[counter])][bits & 3];
+ }
+
+ m = div1_res;
+ n = div2_res;
+ for (;;) {
+ do_divmod(m, base_val, n, rem_res);
+ t = m;
+ m = n;
+ n = t;
+ *(--pos) = digits[_val(rem_res[0])];
+
+ x = 0;
+ for (i = 0; i < calc_buffer_size; ++i)
+ x |= _val(m[i]);
+
+ if (x == 0)
+ break;
+ }
+ if (sign)
+ *(--pos) = '-';
+ break;
+
+ default:
+ panic("Unsupported base %d", base);
+ }
+ return pos;
+}
+
+void init_strcalc(int precision) {
+ if (calc_buffer == NULL) {
+ if (precision <= 0) precision = SC_DEFAULT_PRECISION;
+
+ /* round up to multiple of 4 */
+ precision = (precision + 3) & ~3;
+
+ bit_pattern_size = (precision);
+ calc_buffer_size = (precision / 2);
+ max_value_size = (precision / 4);
+
+ calc_buffer = xmalloc(calc_buffer_size+1 * sizeof(char));
+ output_buffer = xmalloc(bit_pattern_size+1 * sizeof(char));
+
+ 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(void) {
+ free(calc_buffer); calc_buffer = NULL;
+ free(output_buffer); output_buffer = NULL;
+}
+
+int sc_get_precision(void) {
+ return bit_pattern_size;
+}
+
+
+void sc_add(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s + ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_add(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_sub(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s - ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_sub(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_neg(const void *value1, void *buffer) {
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("- %s ->", sc_print_hex(value1)));
+
+ do_negate(value1, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_and(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s & ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_bitand(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_or(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s | ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_bitor(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_xor(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s ^ ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_bitxor(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_not(const void *value1, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("~ %s ->", sc_print_hex(value1)));
+
+ do_bitnot(value1, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_mul(const void *value1, const void *value2, void *buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s * ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_mul(value1, value2, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_div(const void *value1, const void *value2, void *buffer) {
+ /* temp buffer holding unused result of divmod */
+ char *unused_res = alloca(calc_buffer_size);
+
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s / ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_divmod(value1, value2, calc_buffer, unused_res);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_mod(const void *value1, const void *value2, void *buffer) {
+ /* temp buffer holding unused result of divmod */
+ char *unused_res = alloca(calc_buffer_size);
+
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s %% ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_divmod(value1, value2, unused_res, calc_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memcpy(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_divmod(const void *value1, const void *value2, void *div_buffer, void *mod_buffer) {
+ CLEAR_BUFFER(calc_buffer);
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s %% ", sc_print_hex(value1)));
+ DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+
+ do_divmod(value1, value2, div_buffer, mod_buffer);
+
+ DEBUGPRINTF_COMPUTATION(("%s:%s\n", sc_print_hex(div_buffer), sc_print_hex(mod_buffer)));
+}
+
+
+void sc_shlI(const void *val1, long shift_cnt, int bitsize, int sign, void *buffer) {
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s << %ld ", sc_print_hex(value1), shift_cnt));
+ do_shl(val1, calc_buffer, shift_cnt, bitsize, sign);
+
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memmove(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_shl(const void *val1, const void *val2, int bitsize, int sign, void *buffer) {
+ long offset = sc_val_to_long(val2);
+
+ sc_shlI(val1, offset, bitsize, sign, buffer);
+}
+
+void sc_shrI(const void *val1, long shift_cnt, int bitsize, int sign, void *buffer) {
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s >>u %ld ", sc_print_hex(value1), shift_cnt));
+ do_shr(val1, calc_buffer, shift_cnt, bitsize, sign, 0);
+
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memmove(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_shr(const void *val1, const void *val2, int bitsize, int sign, void *buffer) {
+ long shift_cnt = sc_val_to_long(val2);
+
+ sc_shrI(val1, shift_cnt, bitsize, sign, buffer);
+}
+
+void sc_shrs(const void *val1, const void *val2, int bitsize, int sign, void *buffer) {
+ long offset = sc_val_to_long(val2);
+
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s >>s %ld ", sc_print_hex(value1), offset));
+ do_shr(val1, calc_buffer, offset, bitsize, sign, 1);
+
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memmove(buffer, calc_buffer, calc_buffer_size);
+ }
+}
+
+void sc_rotl(const void *val1, const void *val2, int bitsize, int sign, void *buffer) {
+ long offset = sc_val_to_long(val2);
+
+ carry_flag = 0;
+
+ DEBUGPRINTF_COMPUTATION(("%s <<>> %ld ", sc_print_hex(value1), offset));
+ do_rotl(val1, calc_buffer, offset, bitsize, sign);
+
+ DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
+
+ if ((buffer != NULL) && (buffer != calc_buffer)) {
+ memmove(buffer, calc_buffer, calc_buffer_size);
+ }