Example #1
0
/* Helper to fill in the range (src_min, src_max, dest_min, dest_max)
 * based on message parameters and known connection and signal
 * properties; return flags to indicate which parts of the range were
 * found. */
static int set_range(mapper_connection c,
                     mapper_message_t *msg)
{
    lo_arg **args = NULL;
    const char *types = NULL;
    int i, length = 0, updated = 0, result;

    if (!c)
        return 0;

    /* The logic here is to first try to use information from the
     * message, starting with @srcMax, @srcMin, @destMax, @destMin,
     * and then @min and @max.
     * Next priority is already-known properties of the connection.
     * Lastly, we fill in source range from the signal. */

    /* @srcMax */
    args = mapper_msg_get_param(msg, AT_SRC_MAX);
    types = mapper_msg_get_type(msg, AT_SRC_MAX);
    length = mapper_msg_get_length(msg, AT_SRC_MAX);
    if (args && types && is_number_type(types[0])) {
        if (length == c->props.src_length) {
            if (!c->props.src_max)
                c->props.src_max = calloc(1, length * c->props.src_type);
            c->props.range_known |= CONNECTION_RANGE_SRC_MAX;
            for (i=0; i<length; i++) {
                result = propval_set_from_lo_arg(c->props.src_max,
                                                 c->props.src_type,
                                                 args[i], types[i], i);
                if (result == -1) {
                    c->props.range_known &= ~CONNECTION_RANGE_SRC_MAX;
                    break;
                }
                else
                    updated += result;
            }
        }
        else
            c->props.range_known &= ~CONNECTION_RANGE_SRC_MAX;
    }

    /* @srcMin */
    args = mapper_msg_get_param(msg, AT_SRC_MIN);
    types = mapper_msg_get_type(msg, AT_SRC_MIN);
    length = mapper_msg_get_length(msg, AT_SRC_MIN);
    if (args && types && is_number_type(types[0])) {
        if (length == c->props.src_length) {
            if (!c->props.src_min)
                c->props.src_min = calloc(1, length * c->props.src_type);
            c->props.range_known |= CONNECTION_RANGE_SRC_MIN;
            for (i=0; i<length; i++) {
                result = propval_set_from_lo_arg(c->props.src_min,
                                                 c->props.src_type,
                                                 args[i], types[i], i);
                if (result == -1) {
                    c->props.range_known &= ~CONNECTION_RANGE_SRC_MIN;
                    break;
                }
                else
                    updated += result;
            }
        }
        else
            c->props.range_known &= ~CONNECTION_RANGE_SRC_MIN;
    }

    /* @destMax */
    args = mapper_msg_get_param(msg, AT_DEST_MAX);
    types = mapper_msg_get_type(msg, AT_DEST_MAX);
    length = mapper_msg_get_length(msg, AT_DEST_MAX);
    if (args && types && is_number_type(types[0])) {
        if (length == c->props.dest_length) {
            if (!c->props.dest_max)
                c->props.dest_max = calloc(1, length * c->props.dest_type);
            c->props.range_known |= CONNECTION_RANGE_DEST_MAX;
            for (i=0; i<length; i++) {
                result = propval_set_from_lo_arg(c->props.dest_max,
                                                 c->props.dest_type,
                                                 args[i], types[i], i);
                if (result == -1) {
                    c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX;
                    break;
                }
                else
                    updated += result;
            }
        }
        else
            c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX;
    }

    /* @destMin */
    args = mapper_msg_get_param(msg, AT_DEST_MIN);
    types = mapper_msg_get_type(msg, AT_DEST_MIN);
    length = mapper_msg_get_length(msg, AT_DEST_MIN);
    if (args && types && is_number_type(types[0])) {
        if (length == c->props.dest_length) {
            if (!c->props.dest_min)
                c->props.dest_min = calloc(1, length * c->props.dest_type);
            c->props.range_known |= CONNECTION_RANGE_DEST_MIN;
            for (i=0; i<length; i++) {
                result = propval_set_from_lo_arg(c->props.dest_min,
                                                 c->props.dest_type,
                                                 args[i], types[i], i);
                if (result == -1) {
                    c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN;
                    break;
                }
                else
                    updated += result;
            }
        }
        else
            c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN;
    }

    /* @min, @max */
    if (!(c->props.range_known & CONNECTION_RANGE_DEST_MIN)) {
        args = mapper_msg_get_param(msg, AT_MIN);
        types = mapper_msg_get_type(msg, AT_MIN);
        length = mapper_msg_get_length(msg, AT_MIN);
        if (args && types && is_number_type(types[0]))
        {
            if (length == c->props.dest_length) {
                if (!c->props.dest_min)
                    c->props.dest_min = calloc(1, length * c->props.dest_type);
                c->props.range_known |= CONNECTION_RANGE_DEST_MIN;
                for (i=0; i<length; i++) {
                    result = propval_set_from_lo_arg(c->props.dest_min,
                                                     c->props.dest_type,
                                                     args[i], types[i], i);
                    if (result == -1) {
                        c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN;
                        break;
                    }
                    else
                        updated += result;
                }
            }
            else
                c->props.range_known &= ~CONNECTION_RANGE_DEST_MIN;
        }
    }

    if (!(c->props.range_known & CONNECTION_RANGE_DEST_MAX)) {
        args = mapper_msg_get_param(msg, AT_MAX);
        types = mapper_msg_get_type(msg, AT_MAX);
        length = mapper_msg_get_length(msg, AT_MAX);
        if (args && types && is_number_type(types[0]))
        {
            if (length == c->props.dest_length) {
                if (!c->props.dest_max)
                    c->props.dest_max = calloc(1, length * c->props.dest_type);
                c->props.range_known |= CONNECTION_RANGE_DEST_MAX;
                for (i=0; i<length; i++) {
                    result = propval_set_from_lo_arg(c->props.dest_max,
                                                     c->props.dest_type,
                                                     args[i], types[i], i);
                    if (result == -1) {
                        c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX;
                        break;
                    }
                    else
                        updated += result;
                }
            }
            else
                c->props.range_known &= ~CONNECTION_RANGE_DEST_MAX;
        }
    }

    /* Signal */
    mapper_signal sig = c->parent->signal;

    /* If parent signal is an output it must be the "source" of this connection,
     * if it is an input it must be the "destination". According to the protocol
     * for negotiating new connections, we will only fill-in ranges for the
     * "source" signal.*/
    if (!sig || !sig->props.is_output)
        return updated;

    if (!c->props.src_min && sig->props.minimum)
    {
        c->props.src_min = malloc(msig_vector_bytes(sig));
        memcpy(c->props.src_min, sig->props.minimum,
               msig_vector_bytes(sig));
        c->props.range_known |= CONNECTION_RANGE_SRC_MIN;
        updated++;
    }

    if (!c->props.src_max && sig->props.maximum)
    {
        c->props.src_max = malloc(msig_vector_bytes(sig));
        memcpy(c->props.src_max, sig->props.maximum,
               msig_vector_bytes(sig));
        c->props.range_known |= CONNECTION_RANGE_SRC_MAX;
        updated++;
    }

    return updated;
}
Example #2
0
smt_astt 
smt_convt::convert_byte_update(const expr2tc &expr)
{
  const byte_update2t &data = to_byte_update2t(expr);

  assert(is_scalar_type(data.source_value) && "Byte update only works on "
         "scalar variables now");

  if (!is_constant_int2t(data.source_offset)) {
    expr2tc source = data.source_value;
    unsigned int src_width = source->type->get_width();
    if (!is_bv_type(source))
      source = typecast2tc(get_uint_type(src_width), source);

    expr2tc offs = data.source_offset;

    // Endian-ness: if we're in non-"native" endian-ness mode, then flip the
    // offset distance. The rest of these calculations will still apply.
    if (data.big_endian) {
      auto data_size = type_byte_size(*source->type);
      constant_int2tc data_size_expr(source->type, data_size - 1);
      sub2tc sub(source->type, data_size_expr, offs);
      offs = sub;
    }

    if (offs->type->get_width() != src_width)
      offs = typecast2tc(get_uint_type(src_width), offs);

    expr2tc update = data.update_value;
    if (update->type->get_width() != src_width)
      update = typecast2tc(get_uint_type(src_width), update);

    // The approach: mask, shift and or. XXX, byte order?
    // Massively inefficient.

    expr2tc eight = constant_int2tc(get_uint_type(src_width), BigInt(8));
    expr2tc effs = constant_int2tc(eight->type, BigInt(255));
    offs = mul2tc(eight->type, offs, eight);

    expr2tc shl = shl2tc(offs->type, effs, offs);
    expr2tc noteffs = bitnot2tc(effs->type, shl);
    source = bitand2tc(source->type, source, noteffs);

    expr2tc shl2 = shl2tc(offs->type, update, offs);
    return convert_ast(bitor2tc(offs->type, shl2, source));
  }

  // We are merging two values: an 8 bit update value, and a larger source
  // value that we will have to merge it into. Start off by collecting
  // information about the source values and their widths.
  assert(is_number_type(data.source_value->type) && "Byte update of unsupported data type");

  smt_astt value, src_value;
  unsigned int width_op0, width_op2, src_offset;

  value = convert_ast(data.update_value);
  src_value = convert_ast(data.source_value);

  width_op2 = data.update_value->type->get_width();
  width_op0 = data.source_value->type->get_width();
  src_offset = to_constant_int2t(data.source_offset).constant_value.to_ulong();

  // Flip location if we're in big-endian mode
  if (data.big_endian) {
    unsigned int data_size =
      type_byte_size(*data.source_value->type).to_ulong() - 1;
    src_offset = data_size - src_offset;
  }

  if (int_encoding) {
    std::cerr << "Can't byte update in integer mode; rerun in bitvector mode"
              << std::endl;
    abort();
  }

  // Assertion some of our assumptions, which broadly mean that we'll only work
  // on bytes that are going into non-byte words
  assert(width_op2 == 8 && "Can't byte update non-byte operations");
  assert(width_op2 != width_op0 && "Can't byte update bytes, sorry");

  smt_astt top, middle, bottom;

  // Build in three parts: the most significant bits, any in the middle, and
  // the bottom, of the reconstructed / merged output. There might not be a
  // middle if the update byte is at the top or the bottom.
  unsigned int top_of_update = (8 * src_offset) + 8;
  unsigned int bottom_of_update = (8 * src_offset);

  if (top_of_update == width_op0) {
    top = value;
  } else {
    smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - top_of_update, false);
    top = mk_extract(src_value, width_op0 - 1, top_of_update, s);
  }

  if (top == value) {
    middle = NULL;
  } else {
    middle = value;
  }

  if (src_offset == 0) {
    middle = NULL;
    bottom = value;
  } else {
    smt_sortt s = mk_sort(SMT_SORT_BV, bottom_of_update, false);
    bottom = mk_extract(src_value, bottom_of_update - 1, 0, s);
  }

  // Concatenate the top and bottom, and possible middle, together.
  smt_astt concat;

  if (middle != NULL) {
    smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - bottom_of_update, false);
    concat = mk_func_app(s, SMT_FUNC_CONCAT, top, middle);
  } else {
    concat = top;
  }

  return mk_func_app(src_value->sort, SMT_FUNC_CONCAT, concat, bottom);
}