Пример #1
0
/*
 * We can return positive or negative values. You must verify that the
 * number is not unknown (number_is_unknown) and is small enough
 * (number_is_immediate).
 */
long get_number_immediate(ivl_expr_t expr)
{
      long imm = 0;
      unsigned idx;

      switch (ivl_expr_type(expr)) {
      case IVL_EX_ULONG:
        imm = ivl_expr_uvalue(expr);
        break;

      case IVL_EX_NUMBER: {
        const char*bits = ivl_expr_bits(expr);
        unsigned nbits = ivl_expr_width(expr);
          /* We can not copy more bits than fit into a long. */
        if (nbits > 8*sizeof(long)) nbits = 8*sizeof(long);
        for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]){
            case '0':
              break;
            case '1':
              imm |= 1L << idx;
              break;
            default:
              assert(0);
        }
        if (ivl_expr_signed(expr) && bits[nbits-1]=='1' &&
            nbits < 8*sizeof(long)) imm |= -1L << nbits;
        break;
      }

      default:
        assert(0);
      }

      return imm;
}
Пример #2
0
static void draw_string_vec4(ivl_expr_t expr)
{
      unsigned wid = ivl_expr_width(expr);
      char*fp = process_octal_codes(ivl_expr_string(expr), wid);
      char*p = fp;

      unsigned long tmp = 0;
      unsigned tmp_wid = 0;
      int push_flag = 0;

      for (unsigned idx = 0 ; idx < wid ; idx += 8) {
	    tmp <<= 8;
	    tmp |= (unsigned long)*p;
	    p += 1;
	    tmp_wid += 8;
	    if (tmp_wid == 32) {
		  fprintf(vvp_out, "    %%pushi/vec4 %lu, 0, 32; draw_string_vec4\n", tmp);
		  tmp = 0;
		  tmp_wid = 0;
		  if (push_flag == 0)
			push_flag += 1;
		  else
			fprintf(vvp_out, "    %%concat/vec4; draw_string_vec4\n");
	    }
      }

      if (tmp_wid > 0) {
	    fprintf(vvp_out, "    %%pushi/vec4 %lu, 0, %u; draw_string_vec4\n", tmp, tmp_wid);
	    if (push_flag != 0)
		  fprintf(vvp_out, "    %%concat/vec4; draw_string_vec4\n");
      }

      free(fp);
}
Пример #3
0
static void show_memory_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);

      fprintf(out, "%*s<memory width=%u>\n", ind, "",
	      width);
}
Пример #4
0
void show_unary_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt = vt_type_string(net);

      char name[8];
      switch (ivl_expr_opcode(net)) {
	  default:
	    snprintf(name, sizeof name, "%c", ivl_expr_opcode(net));
	    break;

	  case 'm':
	    snprintf(name, sizeof name, "abs()");
	    break;
      }

      if (ivl_expr_opcode(net) == '!' && ivl_expr_value(net) == IVL_VT_REAL) {
	    fprintf(out, "%*sERROR: Real argument to unary ! !?\n", ind,"");
	    stub_errors += 1;
      }

      fprintf(out, "%*s<unary \"%s\" width=%u, %s, type=%s>\n", ind, "",
	      name, width, sign, vt);
      show_expression(ivl_expr_oper1(net), ind+4);
}
Пример #5
0
static void draw_sfunc_vec4(ivl_expr_t expr)
{
      unsigned parm_count = ivl_expr_parms(expr);

	/* Special case: If there are no arguments to print, then the
	   %vpi_call statement is easy to draw. */
      if (parm_count == 0) {
	    assert(ivl_expr_value(expr)==IVL_VT_LOGIC
		   || ivl_expr_value(expr)==IVL_VT_BOOL);

	    fprintf(vvp_out, "    %%vpi_func %u %u \"%s\" %u {0 0 0};\n",
		    ivl_file_table_index(ivl_expr_file(expr)),
		    ivl_expr_lineno(expr), ivl_expr_name(expr),
		    ivl_expr_width(expr));
	    return;
      }

      if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) {
	    draw_darray_pop(expr);
	    return;
      }
      if (strcmp(ivl_expr_name(expr),"$ivl_darray_method$pop_front")==0) {
	    draw_darray_pop(expr);
	    return;
      }

      draw_vpi_func_call(expr);
}
Пример #6
0
/*
 * This function returns TRUE if the number can be represented as a
 * lim_wid immediate value. This amounts to verifying that any upper
 * bits are the same. For a negative value we do not support the most
 * negative twos-complement value since it can not be negated. This
 * code generator always emits positive values, hence the negation
 * requirement.
 */
int number_is_immediate(ivl_expr_t expr, unsigned lim_wid, int negative_ok_flag)
{
      const char *bits;
      unsigned nbits = ivl_expr_width(expr);
      char pad_bit = '0';
      unsigned idx;

    /* We can only convert numbers to an immediate value. */
      if (ivl_expr_type(expr) != IVL_EX_NUMBER
      && ivl_expr_type(expr) != IVL_EX_ULONG
      && ivl_expr_type(expr) != IVL_EX_DELAY)
        return 0;

    /* If a negative value is OK, then we really have one less
     * significant bit because of the sign bit. */
      if (negative_ok_flag) lim_wid -= 1;

    /* This is an unsigned value so it can not have the -2**N problem. */
      if (ivl_expr_type(expr) == IVL_EX_ULONG) {
        unsigned long imm;
        if (lim_wid >= 8*sizeof(unsigned long)) return 1;
          /* At this point we know that lim_wid is smaller than an
           * unsigned long variable. */
        imm = ivl_expr_uvalue(expr);
        if (imm < (1UL << lim_wid)) return 1;
        else return 0;
      }

    /* This is an unsigned value so it can not have the -2**N problem. */
      if (ivl_expr_type(expr) == IVL_EX_DELAY) {
        uint64_t imm;
        if (lim_wid >= 8*sizeof(uint64_t)) return 1;
          /* At this point we know that lim_wid is smaller than a
           * uint64_t variable. */
        imm = ivl_expr_delay_val(expr);
        if (imm < ((uint64_t)1 << lim_wid)) return 1;
        else return 0;
      }

      bits = ivl_expr_bits(expr);

      if (ivl_expr_signed(expr) && bits[nbits-1]=='1') pad_bit = '1';

      if (pad_bit == '1' && !negative_ok_flag) return 0;

      for (idx = lim_wid ;  idx < nbits ;  idx += 1)
        if (bits[idx] != pad_bit) return 0;

    /* If we have a negative number make sure it is not too big. */
      if (pad_bit == '1') {
        for (idx = 0; idx < lim_wid; idx += 1)
          if (bits[idx] == '1') return 1;
        return 0;
      }

      return 1;
}
Пример #7
0
static void draw_unary_inc_dec(ivl_expr_t sub, bool incr, bool pre)
{
      ivl_signal_t sig = 0;
      unsigned wid = 0;

      switch (ivl_expr_type(sub)) {
	  case IVL_EX_SELECT: {
		ivl_expr_t e1 = ivl_expr_oper1(sub);
		sig = ivl_expr_signal(e1);
		wid = ivl_expr_width(e1);
		break;
	  }

	  case IVL_EX_SIGNAL:
	    sig = ivl_expr_signal(sub);
	    wid = ivl_expr_width(sub);
	    break;

	  default:
	    assert(0);
	    break;
      }

      draw_eval_vec4(sub);

      const char*cmd = incr? "%add" : "%sub";

      if (pre) {
	      /* prefix means we add the result first, and store the
		 result, as well as leaving a copy on the stack. */
	    fprintf(vvp_out, "    %%pushi/vec4 1, 0, %u;\n", wid);
	    fprintf(vvp_out, "    %s;\n", cmd);
	    fprintf(vvp_out, "    %%dup/vec4;\n");
	    fprintf(vvp_out, "    %%store/vec4 v%p_0, 0, %u;\n", sig, wid);

      } else {
	      /* The post-fix decrement returns the non-decremented
		 version, so there is a slight re-arrange. */
	    fprintf(vvp_out, "    %%dup/vec4;\n");
	    fprintf(vvp_out, "    %%pushi/vec4 1, 0, %u;\n", wid);
	    fprintf(vvp_out, "    %s;\n", cmd);
	    fprintf(vvp_out, "    %%store/vec4 v%p_0, 0, %u;\n", sig, wid);
      }
}
Пример #8
0
void resize_vec4_wid(ivl_expr_t expr, unsigned wid)
{
      if (ivl_expr_width(expr) == wid)
	    return;

      if (ivl_expr_signed(expr))
	    fprintf(vvp_out, "    %%pad/s %u;\n", wid);
      else
	    fprintf(vvp_out, "    %%pad/u %u;\n", wid);
}
Пример #9
0
static void draw_select_pad_vec4(ivl_expr_t expr)
{
	// This is the sub-expression to pad/truncate
      ivl_expr_t subexpr = ivl_expr_oper1(expr);
	// This is the target width of the expression
      unsigned wid = ivl_expr_width(expr);

	// Push the sub-expression onto the stack.
      draw_eval_vec4(subexpr);

	// Special case: The expression is already the correct width,
	// so there is nothing to be done.
      if (wid == ivl_expr_width(subexpr))
	    return;

      if (ivl_expr_signed(expr))
	    fprintf(vvp_out, "    %%pad/s %u;\n", wid);
      else
	    fprintf(vvp_out, "    %%pad/u %u;\n", wid);
}
Пример #10
0
/*
 * Test if the draw_immediate_vec4 instruction can be used.
 */
int test_immediate_vec4_ok(ivl_expr_t re)
{
      const char*bits;
      unsigned idx;

      if (ivl_expr_type(re) != IVL_EX_NUMBER)
	    return 0;

      if (ivl_expr_width(re) <= 32)
	    return 1;

      bits = ivl_expr_bits(re);

      for (idx = 32 ; idx < ivl_expr_width(re) ; idx += 1) {
	    if (bits[idx] != '0')
		  return 0;
      }

      return 1;
}
Пример #11
0
static void draw_select_vec4(ivl_expr_t expr)
{
	// This is the sub-expression to part-select.
      ivl_expr_t subexpr = ivl_expr_oper1(expr);
	// This is the base of the part select
      ivl_expr_t base = ivl_expr_oper2(expr);
	// This is the part select width
      unsigned wid = ivl_expr_width(expr);
	// Is the select base expression signed or unsigned?
      char sign_suff = ivl_expr_signed(base)? 's' : 'u';

	// Special Case: If the sub-expression is a STRING, then this
	// is a select from that string.
      if (ivl_expr_value(subexpr)==IVL_VT_STRING) {
	    assert(base);
	    assert(wid==8);
	    draw_eval_string(subexpr);
	    int base_idx = allocate_word();
	    draw_eval_expr_into_integer(base, base_idx);
	    fprintf(vvp_out, "    %%substr/vec4 %d, %u;\n", base_idx, wid);
	    fprintf(vvp_out, "    %%pop/str 1;\n");
	    clr_word(base_idx);
	    return;
      }

      if (ivl_expr_value(subexpr)==IVL_VT_DARRAY) {
	    ivl_signal_t sig = ivl_expr_signal(subexpr);
	    assert(sig);
	    assert( (ivl_signal_data_type(sig)==IVL_VT_DARRAY)
		    || (ivl_signal_data_type(sig)==IVL_VT_QUEUE) );

	    assert(base);
	    draw_eval_expr_into_integer(base, 3);
	    fprintf(vvp_out, "    %%load/dar/vec4 v%p_0;\n", sig);

	    return;
      }

      if (test_immediate_vec4_ok(base)) {
	    unsigned long val0, valx;
	    unsigned base_wid;
	    make_immediate_vec4_words(base, &val0, &valx, &base_wid);
	    assert(valx == 0);

	    draw_eval_vec4(subexpr);
	    fprintf(vvp_out, "    %%parti/%c %u, %lu, %u;\n",
		    sign_suff, wid, val0, base_wid);

      } else {
	    draw_eval_vec4(subexpr);
	    draw_eval_vec4(base);
	    fprintf(vvp_out, "    %%part/%c %u;\n", sign_suff, wid);
      }
}
Пример #12
0
static void show_binary_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt   = vt_type_string(net);

      ivl_expr_t oper1 = ivl_expr_oper1(net);
      ivl_expr_t oper2 = ivl_expr_oper2(net);

      fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "",
	      ivl_expr_opcode(net), width, sign, vt);
      if (oper1) {
	    show_expression(oper1, ind+3);
      } else {
	    fprintf(out, "%*sERROR: Missing operand 1\n", ind+3, "");
	    stub_errors += 1;
      }
      if (oper2) {
	    show_expression(oper2, ind+3);
      } else {
	    fprintf(out, "%*sERROR: Missing operand 2\n", ind+3, "");
	    stub_errors += 1;
      }

      switch (ivl_expr_opcode(net)) {

	  case '*':
	    if (ivl_expr_value(net) == IVL_VT_REAL) {
		  if (ivl_expr_width(net) != 1) {
			fprintf(out, "%*sERROR: Result width incorrect. Expecting 1, got %u\n",
				ind+3, "", ivl_expr_width(net));
			stub_errors += 1;
		  }
	    } else {
		    /* The width of a multiply may be any width. The
		       implicit assumption is that the multiply
		       returns a width that is the sum of the widths
		       of the arguments, that is then truncated to the
		       desired width, never padded. The compiler will
		       automatically take care of sign extensions of
		       arguments, so that the code generator need only
		       generate an UNSIGNED multiply, and the result
		       will come out right. */
		  unsigned max_width = ivl_expr_width(oper1) + ivl_expr_width(oper2);
		  if (ivl_expr_width(net) > max_width) {
			fprintf(out, "%*sERROR: Result width to width. Expecting <= %u, got %u\n",
				ind+3, "", max_width, ivl_expr_width(net));
			stub_errors += 1;
		  }
	    }
	    break;

	  default:
	    break;
      }
}
Пример #13
0
static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid)
{
      ivl_expr_t sel_expr = ivl_expr_oper2(expr);
      ivl_expr_t sig_expr = ivl_expr_oper1(expr);
      ivl_select_type_t sel_type = ivl_expr_sel_type(expr);
      if (sel_expr) {
	    unsigned width = ivl_expr_width(expr);
	    ivl_expr_type_t type = ivl_expr_type(sig_expr);
	    assert(width > 0);
	      /* The compiler uses selects for some shifts. */
	    if (type != IVL_EX_NUMBER && type != IVL_EX_SIGNAL) {
		  fprintf(vlog_out, "(" );
		  emit_select_name(scope, sig_expr, wid);
		  fprintf(vlog_out, " >> " );
		  emit_scaled_expr(scope, sel_expr, 1, 0);
		  fprintf(vlog_out, ")" );
	    } else {
		    /* A constant/parameter must be zero based in 1364-1995
		     * so keep the compiler generated normalization. This
		     * does not always work for selects before the parameter
		     * since 1364-1995 does not support signed math. */
		  int msb = 1;
		  int lsb = 0;
		  if (type == IVL_EX_SIGNAL) {
			ivl_signal_t sig = ivl_expr_signal(sig_expr);
			msb = ivl_signal_msb(sig);
			lsb = ivl_signal_lsb(sig);
		  }
		    /* A bit select. */
		  if (width == 1) {
			emit_select_name(scope, sig_expr, wid);
			fprintf(vlog_out, "[");
			emit_scaled_expr(scope, sel_expr, msb, lsb);
			fprintf(vlog_out, "]");
		  } else {
			if (ivl_expr_type(sel_expr) == IVL_EX_NUMBER) {
				/* A constant part select. */
			      emit_select_name(scope, sig_expr, wid);
			      emit_scaled_range(scope, sel_expr, width,
			                        msb, lsb);
			} else {
				/* An indexed part select. */
			      assert(sel_type != IVL_SEL_OTHER);
			      emit_expr_ips(scope, sig_expr, sel_expr,
			                    sel_type, width, msb, lsb);
			}
		  }
	    }
      } else {
// HERE: Should this sign extend if the expression is signed?
	    emit_expr(scope, sig_expr, wid);
      }
}
Пример #14
0
static void draw_binary_vec4_lor(ivl_expr_t expr)
{
      ivl_expr_t le = ivl_expr_oper1(expr);
      ivl_expr_t re = ivl_expr_oper2(expr);

	/* Push the left expression. Reduce it to a single bit if
	   necessary. */
      draw_eval_vec4(le);
      if (ivl_expr_width(le) > 1)
	    fprintf(vvp_out, "    %%or/r;\n");

	/* Now push the right expression. Again, reduce to a single
	   bit if necessary. */
      draw_eval_vec4(re);
      if (ivl_expr_width(re) > 1)
	    fprintf(vvp_out, "    %%or/r;\n");

      fprintf(vvp_out, "    %%or;\n");

      if (ivl_expr_width(expr) > 1)
	    fprintf(vvp_out, "    %%pad/u %u;\n", ivl_expr_width(expr));
}
Пример #15
0
/*
 * We can convert any 2^n ** <unsigned variable> expression to
 * 1 << (n * <unsigned variable>). If the variable is signed then we need
 * to add a check for less than zero and for that case return 0.
 */
static unsigned emit_power_as_shift(ivl_scope_t scope, ivl_expr_t expr,
                                    unsigned wid)
{
      int rtype;
      int64_t value, scale;
      unsigned is_signed_rval = 0;
      unsigned expr_wid;
      ivl_expr_t lval = ivl_expr_oper1(expr);
      ivl_expr_t rval = ivl_expr_oper2(expr);
	/* The L-value must be a number. */
      if (ivl_expr_type(lval) != IVL_EX_NUMBER) return 0;
	/* The L-value must of the form 2^n. */
      value = get_int64_from_number(lval, &rtype);
      if (rtype) return 0;
      expr_wid = ivl_expr_width(lval);
      if (value < 2) return 0;
      if (value % 2) return 0;
	/* Generate the appropriate conversion. */
      if (ivl_expr_signed(rval)) {
	    emit_expr(scope, rval, 0);
	    fprintf(vlog_out, " < 0 ? %u'h0 : (", expr_wid);
	    is_signed_rval = 1;
      }
      scale = value / 2;
      fprintf(vlog_out, "%u'h1 << ", expr_wid);
      if (scale != 1) {
	    if (is_signed_rval) {
		  fprintf(vlog_out, "(%"PRId64, scale);
	    } else {
		  fprintf(vlog_out, "(%u'h%"PRIx64,
		                    ivl_expr_width(rval), scale);
	    }
	    fprintf(vlog_out, " * ");
      }
      emit_expr(scope, rval, 0);
      if (scale != 1) fprintf(vlog_out, ")");
      if (is_signed_rval) fprintf(vlog_out, ")");
      return 1;
}
Пример #16
0
static unsigned emit_param_name_in_scope(ivl_scope_t scope, ivl_expr_t expr)
{
      unsigned idx, count, lineno;
      const char *file;
      count = ivl_scope_params(scope);
      file = ivl_expr_file(expr);
      lineno = ivl_expr_lineno(expr);
      for (idx = 0; idx < count; idx += 1) {
	    ivl_parameter_t par = ivl_scope_param(scope, idx);
	    if (lineno != ivl_parameter_lineno(par)) continue;
	    if (strcmp(file, ivl_parameter_file(par)) == 0) {
		    /* Check that the appropriate expression bits match the
		     * original parameter bits. */
		  ivl_expr_t pex = ivl_parameter_expr(par);
		  unsigned wid = ivl_expr_width(expr);
		  unsigned param_wid = ivl_expr_width(pex);
		  const char *my_bits = ivl_expr_bits(expr);
		  const char *param_bits = ivl_expr_bits(pex);
		  unsigned bit;
		  if (param_wid < wid) wid = param_wid;
		  for (bit = 0; bit < wid; bit += 1) {
			if (my_bits[bit] != param_bits[bit]) {
			      fprintf(stderr, "%s:%u: vlog95 error: Constant "
			                      "expression bits do not match "
			                      "parameter bits.\n",
			                      ivl_expr_file(expr),
			                      ivl_expr_lineno(expr));
			      break;
			}
		  }
// HERE: Does this work with an out of scope parameter reference?
//       What about real parameters?
		  emit_id(ivl_parameter_basename(par));
		  return 1;
	    }
      }
      return 0;
}
Пример #17
0
static void show_function_call(ivl_expr_t net, unsigned ind)
{
      ivl_scope_t def = ivl_expr_def(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt = vt_type_string(net);
      unsigned idx;

      fprintf(out, "%*s<%s %s function %s with %u arguments (width=%u)>\n",
	      ind, "", vt, sign, ivl_scope_name(def), ivl_expr_parms(net),
	      ivl_expr_width(net));

      for (idx = 0 ;  idx < ivl_expr_parms(net) ;  idx += 1)
	    show_expression(ivl_expr_parm(net,idx), ind+4);
}
Пример #18
0
static void string_ex_string(ivl_expr_t expr)
{
      const char*val = ivl_expr_string(expr);

	/* Special case: The elaborator converts the string "" to an
	   8-bit zero, which is in turn escaped to the 4-character
	   string \000. Detect this special case and convert it back
	   to an empty string. [Perhaps elaboration should be fixed?] */
      if (ivl_expr_width(expr)==8 && (strcmp(val,"\\000") == 0)) {
	    fprintf(vvp_out, "    %%pushi/str \"\";\n");
	    return;
      }

      fprintf(vvp_out, "    %%pushi/str \"%s\";\n", val);
}
Пример #19
0
static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
{
    unsigned ewidth, pwidth;

    /* ports cannot be arrays. */
    assert(ivl_signal_dimensions(port) == 0);

    ewidth = ivl_expr_width(expr);
    pwidth = ivl_signal_width(port);

    draw_eval_vec4(expr);
    if (ewidth < pwidth)
        fprintf(vvp_out, "    %%pad/u %u;\n", pwidth);

}
Пример #20
0
static int draw_condition_fallback(ivl_expr_t expr)
{
      int use_flag = allocate_flag();

	/* Evaluate the condition expression, including optionally
	   reducing it to a single bit. Put the result into a flag bit
	   for use by all the tests. */
      draw_eval_vec4(expr);
      if (ivl_expr_width(expr) > 1)
	    fprintf(vvp_out, "    %%or/r;\n");

      fprintf(vvp_out, "    %%flag_set/vec4 %d;\n", use_flag);

      return use_flag;
}
Пример #21
0
static void show_ternary_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt = vt_type_string(net);

      fprintf(out, "%*s<ternary  width=%u, %s type=%s>\n", ind, "",
	      width, sign, vt);
      show_expression(ivl_expr_oper1(net), ind+4);
      show_expression(ivl_expr_oper2(net), ind+4);
      show_expression(ivl_expr_oper3(net), ind+4);

      if (ivl_expr_width(ivl_expr_oper2(net)) != width) {
	    fprintf(out, "ERROR: Width of TRUE expressions is %u, not %u\n",
		    ivl_expr_width(ivl_expr_oper2(net)), width);
	    stub_errors += 1;
      }

      if (ivl_expr_width(ivl_expr_oper3(net)) != width) {
	    fprintf(out, "ERROR: Width of FALSE expressions is %u, not %u\n",
		    ivl_expr_width(ivl_expr_oper3(net)), width);
	    stub_errors += 1;
      }
}
static int draw_number_real(ivl_expr_t exp)
{
      unsigned int idx;
      int res = allocate_word();
      const char*bits = ivl_expr_bits(exp);
      unsigned wid = ivl_expr_width(exp);
      unsigned long mant = 0;

      for (idx = 0 ;  idx < wid ;  idx += 1) {
	    if (bits[idx] == '1')
		  mant |= 1 << idx;
      }

      fprintf(vvp_out, "    %%loadi/wr %d, %lu, 4096;\n", res, mant);
      return res;
}
Пример #23
0
static void show_signal_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt = vt_type_string(net);
      ivl_expr_t word = ivl_expr_oper1(net);

      ivl_signal_t sig = ivl_expr_signal(net);
      const char*vt_sig = data_type_string(ivl_signal_data_type(sig));
      unsigned dimensions = ivl_signal_dimensions(sig);
      unsigned word_count = ivl_signal_array_count(sig);

      if (dimensions == 0 && word_count != 1) {
	    fprintf(out, "%*sERROR: Word count = %u for non-array object\n",
		    ind, "", word_count);
	    stub_errors += 1;
      }

      fprintf(out, "%*s<signal=%s, words=%u, width=%u, %s type=%s (%s)>\n", ind, "",
	      ivl_expr_name(net), word_count, width, sign, vt, vt_sig);

      /* If the expression refers to a signal array, then there must
         also be a word select expression, and if the signal is not an
         array, there must NOT be a word expression. */
      if (dimensions == 0 && word != 0) {
	    fprintf(out, "%*sERROR: Unexpected word expression\n", ind+2, "");
	    stub_errors += 1;
      }
      if (dimensions >= 1 && word == 0) {
	    fprintf(out, "%*sERROR: Missing word expression\n", ind+2, "");
	    stub_errors += 1;
      }
	/* If this is not an array, then the expression with must
	   match the signal width. We have IVL_EX_SELECT expressions
	   for casting signal widths. */
      if (dimensions == 0 && ivl_signal_width(sig) != width) {
	    fprintf(out, "%*sERROR: Expression width (%u) doesn't match ivl_signal_width(sig)=%u\n",
		    ind+2, "", width, ivl_signal_width(sig));
	    stub_errors += 1;
      }

      if (word != 0) {
	    fprintf(out, "%*sAddress-0 word address:\n", ind+2, "");
	    show_expression(word, ind+2);
      }
}
Пример #24
0
int number_is_unknown(ivl_expr_t expr)
{
      const char*bits;
      unsigned idx;

      if (ivl_expr_type(expr) == IVL_EX_ULONG)
        return 0;

      assert(ivl_expr_type(expr) == IVL_EX_NUMBER);

      bits = ivl_expr_bits(expr);
      for (idx = 0 ;  idx < ivl_expr_width(expr) ;  idx += 1)
        if ((bits[idx] != '0') && (bits[idx] != '1'))
          return 1;

      return 0;
}
Пример #25
0
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid)
{
      unsigned swid = ivl_expr_width(expr);
      ivl_scope_t def = ivl_expr_def(expr);
      ivl_signal_t retval = ivl_scope_port(def, 0);
      struct vector_info res;
      unsigned load_wid;

	/* Take in arguments to function and call function code. */
      draw_ufunc_preamble(expr);

	/* Fresh basic block starts after the join. */
      clear_expression_lookaside();

	/* The return value is in a signal that has the name of the
	   expression. Load that into the thread and return the
	   vector result. */

      res.base = allocate_vector(wid);
      res.wid  = wid;
      if (res.base == 0) {
	    fprintf(stderr, "%s:%u: vvp.tgt error: "
		    "Unable to allocate %u thread bits for function result.\n",
		    ivl_expr_file(expr), ivl_expr_lineno(expr), wid);
	    vvp_errors += 1;
	    return res;
      }

      assert(res.base != 0);

      load_wid = swid;
      if (load_wid > ivl_signal_width(retval))
	    load_wid = ivl_signal_width(retval);

      assert(ivl_signal_dimensions(retval) == 0);
      fprintf(vvp_out, "    %%load/v  %u, v%p_0, %u;\n",
	      res.base, retval, load_wid);

	/* Pad the signal value with zeros. */
      if (load_wid < wid)
	    pad_expr_in_place(expr, res, swid);

      draw_ufunc_epilogue(expr);
      return res;
}
Пример #26
0
static void show_select_expression(ivl_expr_t net, unsigned ind)
{
      unsigned width = ivl_expr_width(net);
      const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
      const char*vt = vt_type_string(net);
      ivl_expr_t oper1 = ivl_expr_oper1(net);
      ivl_expr_t oper2 = ivl_expr_oper2(net);

      if (ivl_expr_value(oper1) == IVL_VT_STRING) {
	      /* If the sub-expression is a STRING, then this is a
		 substring and the code generator will handle it
		 differently. */
	    fprintf(out, "%*s<substring: width=%u bits, %u bytes>\n", ind, "", width, width/8);
	    if (width%8 != 0) {
		  fprintf(out, "%*sERROR: Width should be a multiple of 8 bits.\n", ind, "");
		  stub_errors += 1;
	    }
	    assert(oper1);
	    show_expression(oper1, ind+3);

	    if (oper2) {
		  show_expression(oper2, ind+3);
	    } else {
		  fprintf(out, "%*sERROR: oper2 missing! Pad makes no sense for IVL_VT_STRING expressions.\n", ind+3, "");
		  stub_errors += 1;
	    }

      } else if (oper2) {
	      /* If oper2 is present, then it is the base of a part
		 select. The width of the expression defines the range
		 of the part select. */
	    fprintf(out, "%*s<select: width=%u, %s, type=%s>\n", ind, "",
		    width, sign, vt);
	    show_expression(oper1, ind+3);
	    show_expression(oper2, ind+3);

      } else {
	      /* There is no base expression so this is a pad
		 operation. The sub-expression is padded (signed or
		 unsigned as appropriate) to the expression width. */
	    fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "",
		    width, sign);
	    show_expression(oper1, ind+3);
      }
}
Пример #27
0
static int draw_number_bool64(ivl_expr_t expr)
{
      int res;
      const char*bits = ivl_expr_bits(expr);
      uint64_t val = 0;
      unsigned long idx, low, hig;

      for (idx = 0 ;  idx < ivl_expr_width(expr) ;  idx += 1) {
	    if (bits[idx] == '1')
		  val |= 1UL << idx;
      }

      res = allocate_word();
      low = val % UINT64_C(0x100000000);
      hig = val / UINT64_C(0x100000000);
      fprintf(vvp_out, "    %%ix/load %d, %lu, %lu;\n", res, low, hig);
      return res;
}
Пример #28
0
static int show_stmt_assign_sig_string(ivl_statement_t net)
{
      ivl_lval_t lval = ivl_stmt_lval(net, 0);
      ivl_expr_t rval = ivl_stmt_rval(net);
      ivl_expr_t part = ivl_lval_part_off(lval);
      ivl_expr_t aidx = ivl_lval_idx(lval);
      ivl_signal_t var= ivl_lval_sig(lval);

      assert(ivl_stmt_lvals(net) == 1);
      assert(ivl_stmt_opcode(net) == 0);

	/* Simplest case: no mux. Evaluate the r-value as a string and
	   store the result into the variable. Note that the
	   %store/str opcode pops the string result. */
      if (part == 0 && aidx == 0) {
	    draw_eval_string(rval);
	    fprintf(vvp_out, "    %%store/str v%p_0;\n", var);
	    return 0;
      }

	/* Assign to array. The l-value has an index expression
	   expression so we are assigning to an array word. */
      if (aidx != 0) {
	    unsigned ix;
	    assert(part == 0);
	    draw_eval_string(rval);
	    draw_eval_expr_into_integer(aidx, (ix = allocate_word()));
	    fprintf(vvp_out, "    %%store/stra v%p, %u;\n", var, ix);
	    clr_word(ix);
	    return 0;
      }

      assert(ivl_expr_width(rval)==8);
      draw_eval_vec4(rval);

	/* Calculate the character select for the word. */
      int mux_word = allocate_word();
      draw_eval_expr_into_integer(part, mux_word);

      fprintf(vvp_out, "    %%putc/str/vec4 v%p_0, %d;\n", var, mux_word);

      clr_word(mux_word);
      return 0;
}
Пример #29
0
/*
 * Icarus translated wait(<expr) <stmt> into
 *   begin
 *    while (<expr> !== 1'b1) @(<expr sensitivities>);
 *    <stmt>
 *   end
 * This routine looks for this pattern and turns it back into a
 * wait statement.
 */
static unsigned is_wait(ivl_scope_t scope, ivl_statement_t stmt)
{
      ivl_statement_t while_wait, wait, wait_stmt;
      ivl_expr_t while_expr, expr;
      const char *bits;
	/* We must have two block elements. */
      if (ivl_stmt_block_count(stmt) != 2) return 0;
	/* The first must be a while. */
      while_wait = ivl_stmt_block_stmt(stmt, 0);
      if (ivl_statement_type(while_wait) != IVL_ST_WHILE) return 0;
	/* That has a wait with a NOOP statement. */
      wait = ivl_stmt_sub_stmt(while_wait);
      if (ivl_statement_type(wait) != IVL_ST_WAIT) return 0;
      wait_stmt = ivl_stmt_sub_stmt(wait);
      if (ivl_statement_type(wait_stmt) != IVL_ST_NOOP) return 0;
	/* Check that the while condition has the correct form. */
      while_expr = ivl_stmt_cond_expr(while_wait);
      if (ivl_expr_type(while_expr) != IVL_EX_BINARY) return 0;
      if (ivl_expr_opcode(while_expr) != 'N') return 0;
	/* Has a second operator that is a constant 1'b1. */
      expr = ivl_expr_oper2(while_expr);
      if (ivl_expr_type(expr) != IVL_EX_NUMBER) return 0;
      if (ivl_expr_width(expr) != 1) return 0;
      bits = ivl_expr_bits(expr);
      if (*bits != '1') return 0;
// HERE: There is no easy way to verify that the @ sensitivity list
//       matches the first expression so we don't check for that yet.
	/* And finally the two statements that represent the wait must
	 * have the same line number as the block. */
      if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_wait)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(wait))) {
	    return 0;
      }

	/* The pattern matched so generate the appropriate code. */
      fprintf(vlog_out, "%*cwait(", get_indent(), ' ');
      emit_expr(scope, ivl_expr_oper1(while_expr), 0);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_block_stmt(stmt, 1));
      return 1;
}
Пример #30
0
static void function_argument_logic(ivl_signal_t port, ivl_expr_t expr)
{
      struct vector_info res;
      unsigned ewidth, pwidth;

	/* ports cannot be arrays. */
      assert(ivl_signal_dimensions(port) == 0);

      ewidth = ivl_expr_width(expr);
      pwidth = ivl_signal_width(port);
	/* Just like a normal assignment the function arguments need to
	 * be evaluated at either their width or the argument width if
	 * it is larger. */
      if (ewidth < pwidth) ewidth = pwidth;
      res = draw_eval_expr_wid(expr, ewidth, 0);

	/* We could have extra bits so only select the ones we need. */
      fprintf(vvp_out, "    %%set/v v%p_0, %u, %u;\n", port, res.base, pwidth);

      clr_vector(res);
}