Example #1
0
/*
 * This function assigns a value to a real .variable. This is destined
 * for /dev/null when typed ivl_signal_t takes over all the real
 * variable support.
 */
static int show_stmt_assign_sig_real(ivl_statement_t net)
{
      ivl_lval_t lval;
      ivl_signal_t var;

      assert(ivl_stmt_opcode(net) == 0);

      draw_eval_real(ivl_stmt_rval(net));

      assert(ivl_stmt_lvals(net) == 1);
      lval = ivl_stmt_lval(net, 0);
      var = ivl_lval_sig(lval);
      assert(var != 0);

      if (ivl_signal_dimensions(var) == 0) {
	    fprintf(vvp_out, "    %%store/real v%p_0;\n", var);
	    return 0;
      }

	// For now, only support 1-dimensional arrays.
      assert(ivl_signal_dimensions(var) == 1);

      ivl_expr_t word_ex = ivl_lval_idx(lval);
      int word_ix = allocate_word();

	/* If the word index is a constant, then we can write
	   directly to the word and save the index calculation.
	   Out-of-bounds and undefined indices are converted to
	   a canonical index of 'bx during elaboration, and we
	   don't try to optimise that case. */
      if (word_ex && number_is_immediate(word_ex, IMM_WID, 0) &&
	  !number_is_unknown(word_ex)) {
	    unsigned long use_word = get_number_immediate(word_ex);
	    assert(use_word < ivl_signal_array_count(var));
	    fprintf(vvp_out, "    %%ix/load %u, %lu, 0;\n",
		    word_ix, use_word);
	    fprintf(vvp_out, "    %%store/reala v%p, %d;\n",
		    var, word_ix);

      } else {
	    unsigned do_store = transient_id++;
	    unsigned end_store = transient_id++;
	    draw_eval_expr_into_integer(word_ex, word_ix);
	    fprintf(vvp_out, "    %%jmp/0 t_%u, 4;\n", do_store);
	    fprintf(vvp_out, "    %%pop/real 1;\n");
	    fprintf(vvp_out, "    %%jmp t_%u;\n", end_store);
	    fprintf(vvp_out, "t_%u ;\n", do_store);
	    fprintf(vvp_out, "    %%store/reala v%p, %d;\n", var, word_ix);
	    fprintf(vvp_out, "t_%u ;\n", end_store);
      }

      clr_word(word_ix);

      return 0;
}
Example #2
0
/*
 * If needed, draw a .delay node to delay the output from the LPM
 * device. Return the "/d" string if we drew this .delay node, or the
 * "" string if the node was not needed. The caller uses that string
 * to modify labels that are generated.
 */
static const char* draw_lpm_output_delay(ivl_lpm_t net)
{
      ivl_expr_t d_rise = ivl_lpm_delay(net, 0);
      ivl_expr_t d_fall = ivl_lpm_delay(net, 1);
      ivl_expr_t d_decay = ivl_lpm_delay(net, 2);

      const char*dly = "";
      if (d_rise != 0) {
	    assert(number_is_immediate(d_rise, 64, 0));
	    assert(number_is_immediate(d_fall, 64, 0));
	    assert(number_is_immediate(d_decay, 64, 0));
	    dly = "/d";
	    fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
	            net, get_number_immediate(d_rise),
	            get_number_immediate(d_rise),
	            get_number_immediate(d_rise), net);
      }

      return dly;
}
Example #3
0
static void draw_delay(ivl_net_logic_t lptr)
{
      ivl_expr_t d0 = ivl_logic_delay(lptr, 0);
      ivl_expr_t d1 = ivl_logic_delay(lptr, 1);
      ivl_expr_t d2 = ivl_logic_delay(lptr, 2);

      if (d0 == 0 && d1 == 0 && d2 == 0)
	    return;

	/* FIXME: Assume that the expression is a constant */
      assert(number_is_immediate(d0, 64, 0));
      assert(number_is_immediate(d1, 64, 0));
      assert(number_is_immediate(d2, 64, 0));

      if (d0 == d1 && d1 == d2)
	    fprintf(vvp_out, " (%lu)", get_number_immediate(d0));
      else
	    fprintf(vvp_out, " (%lu,%lu,%lu)",
		    get_number_immediate(d0),
		    get_number_immediate(d1),
		    get_number_immediate(d2));
}
Example #4
0
static int get_vpi_taskfunc_signal_arg(struct args_info *result,
                                       ivl_expr_t expr)
{
      char buffer[4096];

      switch (ivl_expr_type(expr)) {
	  case IVL_EX_SIGNAL:
	      /* If the signal node is narrower than the signal itself,
	         then this is a part select so I'm going to need to
	         evaluate the expression.

	         Also, if the signedness of the expression is different
	         from the signedness of the signal. This could be
	         caused by a $signed or $unsigned system function.

	         If I don't need to do any evaluating, then skip it as
	         I'll be passing the handle to the signal itself. */
	    if (ivl_expr_width(expr) !=
	        ivl_signal_width(ivl_expr_signal(expr))) {
		    /* This should never happen since we have IVL_EX_SELECT. */
		  return 0;

	    } else if (ivl_expr_signed(expr) !=
	               ivl_signal_signed(ivl_expr_signal(expr))) {
		  return 0;
	    } else if (is_fixed_memory_word(expr)) {
		  /* This is a word of a non-array, or a word of a net
		     array, so we can address the word directly. */
		  ivl_signal_t sig = ivl_expr_signal(expr);
		  unsigned use_word = 0;
		  ivl_expr_t word_ex = ivl_expr_oper1(expr);
		  if (word_ex) {
			  /* Some array select have been evaluated. */
			if (number_is_immediate(word_ex,IMM_WID, 0)) {
			      assert(! number_is_unknown(word_ex));
			      use_word = get_number_immediate(word_ex);
			      word_ex = 0;
			}
		  }
		  if (word_ex) return 0;

		  assert(word_ex == 0);
		  snprintf(buffer, sizeof buffer, "v%p_%u", sig, use_word);
		  result->text = strdup(buffer);
		  return 1;

	    } else {
		  /* What's left, this is the work of a var array.
		     Create the right code to handle it. */
		  ivl_signal_t sig = ivl_expr_signal(expr);
		  unsigned use_word = 0;
		  unsigned use_word_defined = 0;
		  ivl_expr_t word_ex = ivl_expr_oper1(expr);
		  if (word_ex) {
			  /* Some array select have been evaluated. */
			if (number_is_immediate(word_ex, IMM_WID, 0)) {
			      assert(! number_is_unknown(word_ex));
			      use_word = get_number_immediate(word_ex);
			      use_word_defined = 1;
			      word_ex = 0;
			}
		  }
		  if (word_ex && (ivl_expr_type(word_ex)==IVL_EX_SIGNAL ||
		                  ivl_expr_type(word_ex)==IVL_EX_SELECT)) {
			  /* Special case: the index is a signal/select. */
			result->child = calloc(1, sizeof(struct args_info));
			if (get_vpi_taskfunc_signal_arg(result->child,
			                                word_ex)) {
			      snprintf(buffer, sizeof buffer, "&A<v%p, %s >",
			               sig, result->child->text);
			      free(result->child->text);
			} else {
			      free(result->child);
			      result->child = NULL;
			      return 0;
			}
		  } else if (word_ex) {
			/* Fallback case: evaluate expression. */
			struct vector_info av;
			av = draw_eval_expr(word_ex, STUFF_OK_XZ);
			snprintf(buffer, sizeof buffer, "&A<v%p, %u %u \"%s\">",
			         sig, av.base, av.wid,
			         (ivl_expr_signed(word_ex) ? "s" : "u"));
			result->vec = av;
			result->vec_flag = 1;
		  } else {
			assert(use_word_defined);
			snprintf(buffer, sizeof buffer, "&A<v%p, %u>",
			         sig, use_word);
		  }
		  result->text = strdup(buffer);
		  return 1;
	    }

	  case IVL_EX_SELECT: {
	    ivl_expr_t vexpr = ivl_expr_oper1(expr);
	    ivl_expr_t bexpr;
	    ivl_expr_t wexpr;

	    assert(vexpr);

	      /* This code is only for signals or selects. */
	    if (ivl_expr_type(vexpr) != IVL_EX_SIGNAL &&
	        ivl_expr_type(vexpr) != IVL_EX_SELECT) return 0;

	      /* The signal is part of an array. */
	      /* Add &APV<> code here when it is finished. */
	    bexpr = ivl_expr_oper2(expr);

              /* This is a pad operation. */
	    if (!bexpr) return 0;

	    wexpr = ivl_expr_oper1(vexpr);

	      /* If vexpr has an operand, then that operand is a word
		 index and we are taking a select from an array
		 word. This would come up in expressions like
		 "array[<word>][<part>]" where wexpr is <word> */
	    if (wexpr && number_is_immediate(wexpr, 64, 1)
		&& number_is_immediate(bexpr, 64, 1)) {
		  assert(! number_is_unknown(bexpr));
		  assert(! number_is_unknown(wexpr));
		  snprintf(buffer, sizeof buffer, "&APV<v%p, %ld, %ld, %u>",
			   ivl_expr_signal(vexpr),
			   get_number_immediate(wexpr),
			   get_number_immediate(bexpr),
			   ivl_expr_width(expr));

	    } else if (wexpr) {
		  return 0;

	      /* This is a constant bit/part select. */
	    } else if (number_is_immediate(bexpr, 64, 1)) {
		  assert(! number_is_unknown(bexpr));
		  snprintf(buffer, sizeof buffer, "&PV<v%p_0, %ld, %u>",
		           ivl_expr_signal(vexpr),
		           get_number_immediate(bexpr),
		           ivl_expr_width(expr));

	      /* This is an indexed bit/part select. */
	    } else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL ||
	               ivl_expr_type(bexpr) == IVL_EX_SELECT) {
		    /* Special case: the base is a signal/select. */
		  result->child = calloc(1, sizeof(struct args_info));
		  if (get_vpi_taskfunc_signal_arg(result->child, bexpr)) {
			snprintf(buffer, sizeof buffer, "&PV<v%p_0, %s, %u>",
			         ivl_expr_signal(vexpr),
			         result->child->text,
			         ivl_expr_width(expr));
			free(result->child->text);
		  } else {
			free(result->child);
			result->child = NULL;
			return 0;
		  }
	    } else {
		    /* Fallback case: evaluate the expression. */
		  struct vector_info rv;
		  rv = draw_eval_expr(bexpr, STUFF_OK_XZ);
		  snprintf(buffer, sizeof buffer,
		           "&PV<v%p_0, %u %u \"%s\", %u>",
		           ivl_expr_signal(vexpr),
		           rv.base, rv.wid,
		           (ivl_expr_signed(bexpr) ? "s" : "u"),
		           ivl_expr_width(expr));
		  result->vec = rv;
		  result->vec_flag = 1;
	    }
	    result->text = strdup(buffer);
	    return 1;
	  }

	  default:
	    return 0;
      }
}
Example #5
0
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
				    unsigned bit, unsigned wid)
{
      ivl_signal_t sig = ivl_lval_sig(lval);
      ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
      unsigned long part_off = 0;

	/* Although Verilog doesn't support it, we'll handle
	   here the case of an l-value part select of an array
	   word if the address is constant. */
      ivl_expr_t word_ix = ivl_lval_idx(lval);
      unsigned long use_word = 0;

      if (part_off_ex == 0) {
	    part_off = 0;
      } else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
                 !number_is_unknown(part_off_ex)) {
	    part_off = get_number_immediate(part_off_ex);
	    part_off_ex = 0;
      }

	/* If the word index is a constant expression, then evaluate
	   it to select the word, and pay no further heed to the
	   expression itself. */
      if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
	    assert(! number_is_unknown(word_ix));
	    use_word = get_number_immediate(word_ix);
	    word_ix = 0;
      }

      if (ivl_lval_mux(lval))
	    part_off_ex = ivl_lval_mux(lval);

      if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0
	  && part_off==0 && wid==ivl_signal_width(sig)) {

	    slice->type = SLICE_SIMPLE_VECTOR;
	    slice->u_.simple_vector.use_word = use_word;
	    fprintf(vvp_out, "    %%load/v %u, v%p_%lu, %u;\n",
		    bit, sig, use_word, wid);

      } else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) {

	    assert(use_word == 0);

	    slice->type = SLICE_PART_SELECT_STATIC;
	    slice->u_.part_select_static.part_off = part_off;

	    fprintf(vvp_out, "    %%ix/load 1, %lu, 0;\n", part_off);
	    fprintf(vvp_out, "    %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);

      } else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) {

	    unsigned skip_set = transient_id++;
	    unsigned out_set  = transient_id++;

	    assert(use_word == 0);
	    assert(part_off == 0);

	    slice->type = SLICE_PART_SELECT_DYNAMIC;

	    draw_eval_expr_into_integer(part_off_ex, 1);

	    slice->u_.part_select_dynamic.word_idx_reg = allocate_word();
	    slice->u_.part_select_dynamic.x_flag = allocate_vector(1);

	    fprintf(vvp_out, "    %%mov %u, %u, 1;\n",
		    slice->u_.part_select_dynamic.x_flag, 4);
	    fprintf(vvp_out, "    %%mov/wu %d, %d;\n",
		    slice->u_.part_select_dynamic.word_idx_reg, 1);

	    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
	    fprintf(vvp_out, "    %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid);
	    fprintf(vvp_out, "    %%jmp t_%u;\n", out_set);
	    fprintf(vvp_out, "t_%u ;\n", skip_set);
	    fprintf(vvp_out, "    %%mov %u, 2, %u;\n", bit, wid);
	    fprintf(vvp_out, "t_%u ;\n", out_set);

      } else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {

	    slice->type = SLICE_MEMORY_WORD_STATIC;
	    slice->u_.memory_word_static.use_word = use_word;
	    if (use_word < ivl_signal_array_count(sig)) {
		  fprintf(vvp_out, "    %%ix/load 3, %lu, 0;\n",
			  use_word);
		  fprintf(vvp_out, "    %%load/av %u, v%p, %u;\n",
			  bit, sig, wid);
	    } else {
		  fprintf(vvp_out, "    %%mov %u, 2, %u; OUT OF BOUNDS\n",
			  bit, wid);
	    }

      } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {

	    unsigned skip_set = transient_id++;
	    unsigned out_set  = transient_id++;
	    slice->type = SLICE_MEMORY_WORD_DYNAMIC;

	    draw_eval_expr_into_integer(word_ix, 3);
	    slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
	    slice->u_.memory_word_dynamic.x_flag = allocate_vector(1);
	    fprintf(vvp_out, "    %%mov/wu %d, 3;\n",
		    slice->u_.memory_word_dynamic.word_idx_reg);
	    fprintf(vvp_out, "    %%mov %u, 4, 1;\n",
		    slice->u_.memory_word_dynamic.x_flag);

	    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
	    fprintf(vvp_out, "    %%ix/load 1, 0, 0;\n");
	    fprintf(vvp_out, "    %%load/av %u, v%p, %u;\n",
		    bit, sig, wid);
	    fprintf(vvp_out, "    %%jmp t_%u;\n", out_set);
	    fprintf(vvp_out, "t_%u ;\n", skip_set);
	    fprintf(vvp_out, "    %%mov %u, 2, %u;\n", bit, wid);
	    fprintf(vvp_out, "t_%u ;\n", out_set);

      } else {
	    assert(0);
      }
}
Example #6
0
static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid)
{
      ivl_signal_t sig  = ivl_lval_sig(lval);
      ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
      unsigned long part_off = 0;

	/* Although Verilog doesn't support it, we'll handle
	   here the case of an l-value part select of an array
	   word if the address is constant. */
      ivl_expr_t word_ix = ivl_lval_idx(lval);
      unsigned long use_word = 0;

      if (part_off_ex == 0) {
	    part_off = 0;
      } else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
                 !number_is_unknown(part_off_ex)) {
	    part_off = get_number_immediate(part_off_ex);
	    part_off_ex = 0;
      }

	/* If the word index is a constant expression, then evaluate
	   it to select the word, and pay no further heed to the
	   expression itself. Out-of-bounds and undefined indices are
	   converted to a canonical index of 'bx during elaboration,
	   and we don't try to optimise that case. */
      if (word_ix && number_is_immediate(word_ix, IMM_WID, 0) &&
          !number_is_unknown(word_ix)) {
	    use_word = get_number_immediate(word_ix);
	    assert(use_word < ivl_signal_array_count(sig));
	    word_ix = 0;
      }

      if (ivl_lval_mux(lval))
	    part_off_ex = ivl_lval_mux(lval);

      if (part_off_ex && ivl_signal_dimensions(sig) == 0) {
	    unsigned skip_set = transient_id++;

	      /* There is a mux expression, so this must be a write to
		 a bit-select l-val. Presumably, the x0 index register
		 has been loaded wit the result of the evaluated
		 part select base expression. */
	    assert(!word_ix);

	    draw_eval_expr_into_integer(part_off_ex, 0);
	    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);

	    fprintf(vvp_out, "    %%set/x0 v%p_%lu, %u, %u;\n",
		    sig, use_word, bit, wid);
	    fprintf(vvp_out, "t_%u ;\n", skip_set);
	      /* save_signal width of 0 CLEARS the signal from the
	         lookaside. */
	    save_signal_lookaside(bit, sig, use_word, 0);

      } else if (part_off_ex && ivl_signal_dimensions(sig) > 0) {

	      /* Here we have a part select write into an array word. */
	    unsigned skip_set = transient_id++;
	    if (word_ix) {
		  draw_eval_expr_into_integer(word_ix, 3);
		  fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
	    } else {
		  fprintf(vvp_out, "    %%ix/load 3, %lu, 0;\n", use_word);
	    }
	    draw_eval_expr_into_integer(part_off_ex, 1);
	    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
	    fprintf(vvp_out, "    %%set/av v%p, %u, %u;\n",
		    sig, bit, wid);
	    fprintf(vvp_out, "t_%u ;\n", skip_set);

      } else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig))
		 && ivl_signal_dimensions(sig) > 0) {

	      /* Here we have a part select write into an array word. */
	    unsigned skip_set = transient_id++;
	    if (word_ix) {
		  draw_eval_expr_into_integer(word_ix, 3);
		  fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
	    } else {
		  fprintf(vvp_out, "    %%ix/load 3, %lu, 0;\n", use_word);
	    }
	    fprintf(vvp_out, "    %%ix/load 1, %lu, 0;\n", part_off);
	    fprintf(vvp_out, "    %%set/av v%p, %u, %u;\n",
		    sig, bit, wid);
	    if (word_ix) /* Only need this label if word_ix is set. */
		  fprintf(vvp_out, "t_%u ;\n", skip_set);

      } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) {
	      /* There is no mux expression, but a constant part
		 offset. Load that into index x0 and generate a
		 vector set instruction. */
	    assert(ivl_lval_width(lval) == wid);

	      /* If the word index is a constant, then we can write
	         directly to the word and save the index calculation. */
	    if (word_ix == 0) {
		  fprintf(vvp_out, "    %%ix/load 0, %lu, 0;\n", part_off);
		  fprintf(vvp_out, "    %%set/x0 v%p_%lu, %u, %u;\n",
		          sig, use_word, bit, wid);

	    } else {
		  unsigned skip_set = transient_id++;
		  unsigned index_reg = 3;
		  draw_eval_expr_into_integer(word_ix, index_reg);
		  fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
		  fprintf(vvp_out, "    %%ix/load 1, %lu, 0;\n", part_off);
		  fprintf(vvp_out, "    %%set/av v%p, %u, %u;\n",
			  sig, bit, wid);
		  fprintf(vvp_out, "t_%u ;\n", skip_set);
	    }
	      /* save_signal width of 0 CLEARS the signal from the
	         lookaside. */
	    save_signal_lookaside(bit, sig, use_word, 0);

      } else if (ivl_signal_dimensions(sig) > 0) {

	      /* If the word index is a constant, then we can write
	         directly to the word and save the index calculation. */
	    if (word_ix == 0) {
		  fprintf(vvp_out, "    %%ix/load 1, 0, 0;\n");
		  fprintf(vvp_out, "    %%ix/load 3, %lu, 0;\n", use_word);
		  fprintf(vvp_out, "    %%set/av v%p, %u, %u;\n",
			  sig, bit, wid);

	    } else {
		  unsigned skip_set = transient_id++;
		  unsigned index_reg = 3;
		  draw_eval_expr_into_integer(word_ix, index_reg);
		  fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
		  fprintf(vvp_out, "    %%ix/load 1, 0, 0;\n");
		  fprintf(vvp_out, "    %%set/av v%p, %u, %u;\n",
			  sig, bit, wid);
		  fprintf(vvp_out, "t_%u ;\n", skip_set);
	    }
	      /* save_signal width of 0 CLEARS the signal from the
	         lookaside. */
	    save_signal_lookaside(bit, sig, use_word, 0);


      } else {
	    fprintf(vvp_out, "    %%set/v v%p_%lu, %u, %u;\n",
		    sig, use_word, bit, wid);
	      /* save_signal width of 0 CLEARS the signal from the
	         lookaside. */
	    save_signal_lookaside(bit, sig, use_word, 0);

      }
}
Example #7
0
static int eval_darray_new(ivl_expr_t ex)
{
      int errors = 0;
      unsigned size_reg = allocate_word();
      ivl_expr_t size_expr = ivl_expr_oper1(ex);
      ivl_expr_t init_expr = ivl_expr_oper2(ex);
      draw_eval_expr_into_integer(size_expr, size_reg);

	// The new function has a net_type that contains the details
	// of the type.
      ivl_type_t net_type = ivl_expr_net_type(ex);
      assert(net_type);

      ivl_type_t element_type = ivl_type_element(net_type);
      assert(element_type);

      switch (ivl_type_base(element_type)) {
	    int msb, lsb, wid;
	  case IVL_VT_REAL:
	      // REAL objects are not packable.
	    assert(ivl_type_packed_dimensions(element_type) == 0);
	    fprintf(vvp_out, "    %%new/darray %u, \"r\";\n", size_reg);
	    break;
	  case IVL_VT_STRING:
	      // STRING objects are not packable.
	    assert(ivl_type_packed_dimensions(element_type) == 0);
	    fprintf(vvp_out, "    %%new/darray %u, \"S\";\n", size_reg);
	    break;
	  case IVL_VT_BOOL:
	      // bool objects are vectorable, but for now only support
	      // a single dimensions.
	    assert(ivl_type_packed_dimensions(element_type) == 1);
	    msb = ivl_type_packed_msb(element_type, 0);
	    lsb = ivl_type_packed_lsb(element_type, 0);
	    wid = msb>=lsb? msb - lsb : lsb - msb;
	    wid += 1;
	    fprintf(vvp_out, "    %%new/darray %u, \"%sb%d\";\n", size_reg,
	                     ivl_type_signed(element_type) ? "s" : "", wid);
	    break;
	  case IVL_VT_LOGIC:
	      // logic objects are vectorable, but for now only support
	      // a single dimensions.
	    assert(ivl_type_packed_dimensions(element_type) == 1);
	    msb = ivl_type_packed_msb(element_type, 0);
	    lsb = ivl_type_packed_lsb(element_type, 0);
	    wid = msb>=lsb? msb - lsb : lsb - msb;
	    wid += 1;
	    fprintf(vvp_out, "    %%new/darray %u, \"%sv%d\";\n", size_reg,
	                     ivl_type_signed(element_type) ? "s" : "", wid);
	    break;

	  default:
	    assert(0);
	    break;
      }
      clr_word(size_reg);

      if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) {
	    unsigned idx;
	    switch (ivl_type_base(element_type)) {
		case IVL_VT_BOOL:
		case IVL_VT_LOGIC:
		  for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
			draw_eval_vec4(ivl_expr_parm(init_expr,idx));
			fprintf(vvp_out, "    %%ix/load 3, %u, 0;\n", idx);
			fprintf(vvp_out, "    %%set/dar/obj/vec4 3;\n");
			fprintf(vvp_out, "    %%pop/vec4 1;\n");
		  }
		  break;
		case IVL_VT_REAL:
		  for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
			draw_eval_real(ivl_expr_parm(init_expr,idx));
			fprintf(vvp_out, "    %%ix/load 3, %u, 0;\n", idx);
			fprintf(vvp_out, "    %%set/dar/obj/real 3;\n");
			fprintf(vvp_out, "    %%pop/real 1;\n");
		  }
		  break;
		case IVL_VT_STRING:
		  for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) {
			draw_eval_string(ivl_expr_parm(init_expr,idx));
			fprintf(vvp_out, "    %%ix/load 3, %u, 0;\n", idx);
			fprintf(vvp_out, "    %%set/dar/obj/str 3;\n");
			fprintf(vvp_out, "    %%pop/str 1;\n");
		  }
		  break;
		default:
		  fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n");
		  errors += 1;
		  break;
	    }
      } else if (init_expr && (ivl_expr_value(init_expr) == IVL_VT_DARRAY)) {
		  ivl_signal_t sig = ivl_expr_signal(init_expr);
		  fprintf(vvp_out, "    %%load/obj v%p_0;\n", sig);
		  fprintf(vvp_out, "    %%scopy;\n");

      } else if (init_expr && number_is_immediate(size_expr,32,0)) {
	      /* In this case, there is an init expression, the
		 expression is NOT an array_pattern, and the size
		 expression used to calculate the size of the array is
		 a constant. Generate an unrolled set of assignments. */
	    long idx;
	    long cnt = get_number_immediate(size_expr);
	    unsigned wid;
	    switch (ivl_type_base(element_type)) {
		case IVL_VT_BOOL:
		case IVL_VT_LOGIC:
		  wid = width_of_packed_type(element_type);
		  for (idx = 0 ; idx < cnt ; idx += 1) {
			draw_eval_vec4(init_expr);
			fprintf(vvp_out, "    %%parti/%c %u, %ld, 6;\n",
                                ivl_expr_signed(init_expr) ? 's' : 'u', wid, idx * wid);
			fprintf(vvp_out, "    %%ix/load 3, %ld, 0;\n", cnt - idx - 1);
			fprintf(vvp_out, "    %%set/dar/obj/vec4 3;\n");
			fprintf(vvp_out, "    %%pop/vec4 1;\n");
		  }
		  break;
		case IVL_VT_REAL:
		  draw_eval_real(init_expr);
		  for (idx = 0 ; idx < cnt ; idx += 1) {
			fprintf(vvp_out, "    %%ix/load 3, %ld, 0;\n", idx);
			fprintf(vvp_out, "    %%set/dar/obj/real 3;\n");
		  }
		  fprintf(vvp_out, "    %%pop/real 1;\n");
		  break;
		case IVL_VT_STRING:
		  draw_eval_string(init_expr);
		  for (idx = 0 ; idx < cnt ; idx += 1) {
			fprintf(vvp_out, "    %%ix/load 3, %ld, 0;\n", idx);
			fprintf(vvp_out, "    %%set/dar/obj/str 3;\n");
		  }
		  fprintf(vvp_out, "    %%pop/str 1;\n");
		  break;
		default:
		  fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n");
		  errors += 1;
		  break;
	    }

      } else if (init_expr) {
	    fprintf(vvp_out, "; ERROR: Sorry, I don't know how to work with this size expr.\n");
	    errors += 1;
      }

      return errors;
}
Example #8
0
void clsAnalysis::AnalyzeExpression(clsExpression * pExpression, clsEvent * pEvent)
{
  ivl_expr_t                       ivl_Expression;
  clsSignal *                      pSignal;
  vector<clsDataType *>::iterator  it_pDataType;
  unsigned int                     iIndex;
  
  ivl_Expression = pExpression->m_ivl_Expression;
  
  switch (pExpression->m_Type)
  {
  default:
    _Assert(0 && "Frontend Error: Unrecognized expression is encountered.");
    break;
  case CMODELGEN_EXPRESSION_NONE:
    break;
  case CMODELGEN_EXPRESSION_CONCAT:
    for (iIndex = 0; iIndex < pExpression->m_pSubExpressions.size(); ++iIndex)
    {
      AnalyzeExpression(pExpression->m_pSubExpressions[iIndex], pEvent);
    }
    break;
  case CMODELGEN_EXPRESSION_UNARY:
    AnalyzeExpression(pExpression->m_pSubExpressions[0], pEvent);
    break;
  case CMODELGEN_EXPRESSION_BINARY:
    AnalyzeExpression(pExpression->m_pSubExpressions[0], pEvent);
    AnalyzeExpression(pExpression->m_pSubExpressions[1], pEvent);
    break;
  case CMODELGEN_EXPRESSION_CONDITIONAL:
    AnalyzeExpression(pExpression->m_pSubExpressions[0], pEvent);
    AnalyzeExpression(pExpression->m_pSubExpressions[1], pEvent);
    AnalyzeExpression(pExpression->m_pSubExpressions[2], pEvent);
    break;
  case CMODELGEN_EXPRESSION_SELECT:
    AnalyzeExpression(pExpression->m_pSubExpressions[0], pEvent);
    if (pExpression->m_pSubExpressions.size() == 2)
    {
      AnalyzeExpression(pExpression->m_pSubExpressions[1], pEvent);
    }
    break;
  case CMODELGEN_EXPRESSION_NUMBER:
    break;
  case CMODELGEN_EXPRESSION_SIGNAL:
    iIndex = 0;
    if (ivl_expr_oper1(ivl_Expression) != NULL                          &&
        number_is_immediate(ivl_expr_oper1(ivl_Expression), IMM_WID, 0) &&
        !number_is_unknown(ivl_expr_oper1(ivl_Expression) ) )
    {
	    iIndex = get_number_immediate(ivl_expr_oper1(ivl_Expression) );
    }
    pSignal = clsAnalysis::FindSignal(ivl_expr_signal(ivl_Expression), iIndex);
    if (pSignal->m_VectorType == CMODELGEN_VECTOR_VIRTUAL_VECTOR)
    {
      AnalyzeExpression(pExpression->m_pSubExpressions[0], pEvent);
    }
    break;
  case CMODELGEN_EXPRESSION_ARRAY:
    break;
  case CMODELGEN_EXPRESSION_STRING:
    break;
  case CMODELGEN_EXPRESSION_FUNCTION:
  case CMODELGEN_EXPRESSION_SFUNCTION:
    for (iIndex = 0; iIndex < pExpression->m_pSubExpressions.size(); ++iIndex)
    {
      AnalyzeExpression(pExpression->m_pSubExpressions[iIndex], pEvent);
    }
    break;
  }
}
static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope)
{
      ivl_expr_t exp = ivl_stmt_cond_expr(net);
      struct vector_info cond = draw_eval_expr(exp, 0);
      unsigned count = ivl_stmt_case_count(net);

      unsigned local_base = local_count;

      unsigned idx, default_case;

      local_count += count + 1;

	/* First draw the branch table.  All the non-default cases
	   generate a branch out of here, to the code that implements
	   the case. The default will fall through all the tests. */
      default_case = count;

      for (idx = 0 ;  idx < count ;  idx += 1) {
	    ivl_expr_t cex = ivl_stmt_case_expr(net, idx);
	    struct vector_info cvec;

	    if (cex == 0) {
		  default_case = idx;
		  continue;
	    }

	      /* Is the guard expression something I can pass to a
		 %cmpi/u instruction? If so, use that instead. */

	    if ((ivl_statement_type(net) == IVL_ST_CASE)
		&& (ivl_expr_type(cex) == IVL_EX_NUMBER)
		&& (! number_is_unknown(cex))
		&& number_is_immediate(cex, 16)) {

		  unsigned long imm = get_number_immediate(cex);

		  fprintf(vvp_out, "    %%cmpi/u %u, %lu, %u;\n",
			  cond.base, imm, cond.wid);
		  fprintf(vvp_out, "    %%jmp/1 T_%d.%d, 6;\n",
			  thread_count, local_base+idx);

		  continue;
	    }

	      /* Oh well, do this case the hard way. */

	    cvec = draw_eval_expr_wid(cex, cond.wid, 0);
	    assert(cvec.wid == cond.wid);

	    switch (ivl_statement_type(net)) {

		case IVL_ST_CASE:
		  fprintf(vvp_out, "    %%cmp/u %u, %u, %u;\n",
			  cond.base, cvec.base, cond.wid);
		  fprintf(vvp_out, "    %%jmp/1 T_%d.%d, 6;\n",
			  thread_count, local_base+idx);
		  break;

		case IVL_ST_CASEX:
		  fprintf(vvp_out, "    %%cmp/x %u, %u, %u;\n",
			  cond.base, cvec.base, cond.wid);
		  fprintf(vvp_out, "    %%jmp/1 T_%d.%d, 4;\n",
			  thread_count, local_base+idx);
		  break;

		case IVL_ST_CASEZ:
		  fprintf(vvp_out, "    %%cmp/z %u, %u, %u;\n",
			  cond.base, cvec.base, cond.wid);
		  fprintf(vvp_out, "    %%jmp/1 T_%d.%d, 4;\n",
			  thread_count, local_base+idx);
		  break;

		default:
		  assert(0);
	    }
	    
	      /* Done with the case expression */
	    clr_vector(cvec);
      }

	/* Done with the condition expression */
      clr_vector(cond);

	/* Emit code for the default case. */
      if (default_case < count) {
	    ivl_statement_t cst = ivl_stmt_case_stmt(net, default_case);
	    show_statement(cst, sscope);
      }

	/* Jump to the out of the case. */
      fprintf(vvp_out, "    %%jmp T_%d.%d;\n", thread_count,
	      local_base+count);

      for (idx = 0 ;  idx < count ;  idx += 1) {
	    ivl_statement_t cst = ivl_stmt_case_stmt(net, idx);

	    if (idx == default_case)
		  continue;

	    fprintf(vvp_out, "T_%d.%d ;\n", thread_count, local_base+idx);
	    clear_expression_lookaside();
	    show_statement(cst, sscope);

	    fprintf(vvp_out, "    %%jmp T_%d.%d;\n", thread_count,
		    local_base+count);

      }


	/* The out of the case. */
      fprintf(vvp_out, "T_%d.%d ;\n",  thread_count, local_base+count);
      clear_expression_lookaside();

      return 0;
}
Example #10
0
static void draw_logic_in_scope(ivl_net_logic_t lptr)
{
      unsigned pdx;
      const char*ltype = "?";
      const char*lcasc = 0;
      char identity_val = '0';

      int need_delay_flag = ivl_logic_delay(lptr,0)? 1 : 0;

      unsigned vector_width = width_of_nexus(ivl_logic_pin(lptr, 0));

      ivl_drive_t str0, str1;

      int level;
      int ninp = ivl_logic_pins(lptr) - 1;
      typedef const char*const_charp;
      const_charp*input_strings = calloc(ninp, sizeof(const_charp));

      for (pdx = 0 ;  pdx < ninp ;  pdx += 1) {
	    ivl_nexus_t nex = ivl_logic_pin(lptr, pdx+1);
	    if (nex == 0) {
		    /* Only UDPs can have unconnected inputs. */
		  assert(ivl_logic_type(lptr) == IVL_LO_UDP);
		  input_strings[pdx] = 0;
	    } else {
		  input_strings[pdx] = draw_net_input(nex);
	    }
      }

      switch (ivl_logic_type(lptr)) {

          case IVL_LO_UDP:
	    free(input_strings);
	    draw_udp_in_scope(lptr);
	    return;

          case IVL_LO_BUFZ: {
		  /* Draw bufz objects, but only if the gate cannot
		     be elided. If I can elide it, then the
		     draw_nex_input will take care of it for me. */
		ivl_nexus_ptr_t nptr = ivl_logic_pin_ptr(lptr,0);

		ltype = "BUFZ";

		if (can_elide_bufz(lptr, nptr))
		      return;

		break;
	  }

	  case IVL_LO_PULLDOWN:
	  case IVL_LO_PULLUP:
	      /* Skip pullup and pulldown objects. Things that have
		 pull objects as inputs will instead generate the
		 appropriate C<?> symbol. */
	    free(input_strings);
	    return;

	  case IVL_LO_AND:
	    ltype = "AND";
	    identity_val = '1';
	    break;

	  case IVL_LO_BUF:
	    ltype = "BUF";
	    break;

	  case IVL_LO_BUFIF0:
	    ltype = "BUFIF0";
	    break;

	  case IVL_LO_BUFIF1:
	    ltype = "BUFIF1";
	    break;

	  case IVL_LO_NAND:
	    ltype = "NAND";
	    lcasc = "AND";
	    identity_val = '1';
	    break;

	  case IVL_LO_NOR:
	    ltype = "NOR";
	    lcasc = "OR";
	    break;

	  case IVL_LO_NOT:
	    ltype = "NOT";
	    break;

	  case IVL_LO_OR:
	    ltype = "OR";
	    break;

	  case IVL_LO_XNOR:
	    ltype = "XNOR";
	    lcasc = "XOR";
	    break;

	  case IVL_LO_XOR:
	    ltype = "XOR";
	    break;

	  case IVL_LO_CMOS:
	    ltype = "CMOS";
	    break;

	  case IVL_LO_PMOS:
	    ltype = "PMOS";
	    break;

	  case IVL_LO_NMOS:
	    ltype = "NMOS";
	    break;

	  case IVL_LO_RCMOS:
	    ltype = "RCMOS";
	    break;

	  case IVL_LO_RPMOS:
	    ltype = "RPMOS";
	    break;

	  case IVL_LO_RNMOS:
	    ltype = "RNMOS";
	    break;

	  case IVL_LO_NOTIF0:
	    ltype = "NOTIF0";
	    break;

	  case IVL_LO_NOTIF1:
	    ltype = "NOTIF1";
	    break;

	  default:
	    fprintf(stderr, "vvp.tgt: error: Unhandled logic type: %u\n",
		    ivl_logic_type(lptr));
	    ltype = "?";
	    break;
      }

      { ivl_nexus_t nex = ivl_logic_pin(lptr, 0);
        ivl_nexus_ptr_t nptr = 0;
        unsigned idx;
	for (idx = 0 ;  idx < ivl_nexus_ptrs(nex) ;  idx += 1) {
	      nptr = ivl_nexus_ptr(nex,idx);
	      if (ivl_nexus_ptr_log(nptr) != lptr)
		    continue;
	      if (ivl_nexus_ptr_pin(nptr) != 0)
		    continue;
	      break;
	}
        str0 = ivl_nexus_ptr_drive0(nptr);
	str1 = ivl_nexus_ptr_drive1(nptr);
      }

      if (!lcasc)
	lcasc = ltype;

	/* Get all the input label that I will use for parameters to
	   the functor that I create later. */
      ninp = ivl_logic_pins(lptr) - 1;
      input_strings = calloc(ninp, sizeof(char*));
      for (pdx = 0 ;  pdx < ninp ;  pdx += 1)
	    input_strings[pdx] = draw_net_input(ivl_logic_pin(lptr, pdx+1));

      level = 0;
      ninp = ivl_logic_pins(lptr) - 1;
      while (ninp) {
	    int inst;
	    for (inst = 0; inst < ninp; inst += 4) {
		  if (ninp > 4)
			fprintf(vvp_out, "L_%p/%d/%d .functor %s %u",
				lptr, level, inst, lcasc, vector_width);
		  else {
			fprintf(vvp_out, "L_%p%s .functor %s %u",
				lptr, need_delay_flag? "/d" : "",
				ltype, vector_width);

			if (str0 != IVL_DR_STRONG || str1 != IVL_DR_STRONG)
			      fprintf(vvp_out, " [%u %u]", str0, str1);

		  }
		  for (pdx = inst; pdx < ninp && pdx < inst+4 ; pdx += 1) {
			if (level) {
			      fprintf(vvp_out, ", L_%p/%d/%d",
				      lptr, level - 1, pdx*4);
			} else {
			      fprintf(vvp_out, ", %s", input_strings[pdx]);
			}
		  }
		  for ( ;  pdx < inst+4 ;  pdx += 1) {
			unsigned wdx;
			fprintf(vvp_out, ", C4<");
			for (wdx = 0 ; wdx < vector_width ;  wdx += 1)
			      fprintf(vvp_out, "%c", identity_val);
			fprintf(vvp_out, ">");
		  }

		  fprintf(vvp_out, ";\n");
	    }
	    if (ninp > 4)
		  ninp = (ninp+3) / 4;
	    else
		  ninp = 0;
	    level += 1;
      }

	/* Free the array of char*. The strings themselves are
	   persistent, held by the ivl_nexus_t objects. */
      free(input_strings);

	/* If there are delays, then draw the delay functor to carry
	   that delay. This is the final output. */
      if (need_delay_flag) {
	    ivl_expr_t rise_exp  = ivl_logic_delay(lptr,0);
	    ivl_expr_t fall_exp  = ivl_logic_delay(lptr,1);
	    ivl_expr_t decay_exp = ivl_logic_delay(lptr,2);

	    if (number_is_immediate(rise_exp,64,0)
		&& number_is_immediate(fall_exp,64,0)
		&& number_is_immediate(decay_exp,64,0)) {

		  fprintf(vvp_out, "L_%p .delay (%lu,%lu,%lu) L_%p/d;\n",
			  lptr, get_number_immediate(rise_exp),
			  get_number_immediate(rise_exp),
			  get_number_immediate(rise_exp), lptr);
	    } else {
		  ivl_signal_t sig;
		  assert(ivl_expr_type(rise_exp) == IVL_EX_SIGNAL);
		  assert(ivl_expr_type(fall_exp) == IVL_EX_SIGNAL);
		  assert(ivl_expr_type(decay_exp) == IVL_EX_SIGNAL);

		  fprintf(vvp_out, "L_%p .delay  L_%p/d", lptr, lptr);

		  sig = ivl_expr_signal(rise_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0", sig);

		  sig = ivl_expr_signal(fall_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0", sig);

		  sig = ivl_expr_signal(decay_exp);
		  assert(ivl_signal_dimensions(sig) == 0);
		  fprintf(vvp_out, ", v%p_0;\n", sig);
	    }
      }
}
Example #11
0
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
				    unsigned wid)
{
      ivl_signal_t sig = ivl_lval_sig(lval);
      ivl_expr_t part_off_ex = ivl_lval_part_off(lval);
      unsigned long part_off = 0;

	/* Although Verilog doesn't support it, we'll handle
	   here the case of an l-value part select of an array
	   word if the address is constant. */
      ivl_expr_t word_ix = ivl_lval_idx(lval);
      unsigned long use_word = 0;

      if (part_off_ex == 0) {
	    part_off = 0;
      } else if (number_is_immediate(part_off_ex, IMM_WID, 0) &&
                 !number_is_unknown(part_off_ex)) {
	    part_off = get_number_immediate(part_off_ex);
	    part_off_ex = 0;
      }

	/* If the word index is a constant expression, then evaluate
	   it to select the word, and pay no further heed to the
	   expression itself. */
      if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) {
	    assert(! number_is_unknown(word_ix));
	    use_word = get_number_immediate(word_ix);
	    word_ix = 0;
      }

      if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0
	  && part_off==0 && wid==ivl_signal_width(sig)) {

	    slice->type = SLICE_SIMPLE_VECTOR;
	    slice->u_.simple_vector.use_word = use_word;
	    fprintf(vvp_out, "    %%load/vec4 v%p_%lu;\n", sig, use_word);

      } else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) {

	    assert(use_word == 0);

	    slice->type = SLICE_PART_SELECT_STATIC;
	    slice->u_.part_select_static.part_off = part_off;

	    fprintf(vvp_out, "    %%load/vec4 v%p_%lu;\n", sig, use_word);
	    fprintf(vvp_out, "    %%pushi/vec4 %lu, 0, 32;\n", part_off);
	    fprintf(vvp_out, "    %%part/u %u;\n", wid);

      } else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) {

	    assert(use_word == 0);
	    assert(part_off == 0);

	    slice->type = SLICE_PART_SELECT_DYNAMIC;

	    slice->u_.part_select_dynamic.word_idx_reg = allocate_word();
	    slice->u_.part_select_dynamic.x_flag = allocate_flag();

	    fprintf(vvp_out, "    %%load/vec4 v%p_%lu;\n", sig, use_word);
	    draw_eval_vec4(part_off_ex);
	    fprintf(vvp_out, "    %%flag_mov %u, 4;\n", slice->u_.part_select_dynamic.x_flag);
	    fprintf(vvp_out, "    %%dup/vec4;\n");
	    fprintf(vvp_out, "    %%ix/vec4 %u;\n", slice->u_.part_select_dynamic.word_idx_reg);
	    fprintf(vvp_out, "    %%part/u %u;\n", wid);

      } else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) {

	    slice->type = SLICE_MEMORY_WORD_STATIC;
	    slice->u_.memory_word_static.use_word = use_word;
	    if (use_word < ivl_signal_array_count(sig)) {
		  fprintf(vvp_out, "    %%ix/load 3, %lu, 0;\n",
			  use_word);
		  fprintf(vvp_out, "    %%load/vec4a v%p, 3;\n", sig);
	    } else {
		  assert(wid <= 32);
		  fprintf(vvp_out, "    %%pushi/vec4 4294967295, 4294967295, %u;\n", wid);
	    }

      } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) {

	    slice->type = SLICE_MEMORY_WORD_DYNAMIC;

	    slice->u_.memory_word_dynamic.word_idx_reg = allocate_word();
	    slice->u_.memory_word_dynamic.x_flag = allocate_flag();

	    draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg);
	    fprintf(vvp_out, "    %%flag_mov %d, 4;\n", slice->u_.memory_word_dynamic.x_flag);
	    fprintf(vvp_out, "    %%load/vec4a v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg);

      } else {
	    assert(0);
      }
}