/*
 * This function handles the case of non-blocking assign to word
 * variables such as real, i.e:
 *
 *     read foo;
 *     foo <= 1.0;
 *
 * In this case we know (by Verilog syntax) that there is only exactly
 * 1 l-value, the target identifier, so it should be relatively easy.
 */
static int show_stmt_assign_nb_var(ivl_statement_t net)
{
      ivl_lval_t lval;
      ivl_variable_t var;
      ivl_expr_t rval = ivl_stmt_rval(net);
      ivl_expr_t del  = ivl_stmt_delay_expr(net);

      int word;
      unsigned long delay;

	/* Must be exactly 1 l-value. */
      assert(ivl_stmt_lvals(net) == 1);

      delay = 0;
      if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
	    delay = ivl_expr_uvalue(del);
	    del = 0;
      }

	/* XXXX For now, presume delays are constant. */
      assert(del == 0);

	/* Evaluate the r-value */
      word = draw_eval_real(rval);

      lval = ivl_stmt_lval(net, 0);
      var = ivl_lval_var(lval);
      assert(var != 0);

      fprintf(vvp_out, "    %%assign/wr W_%s, %lu, %u;\n",
	      vvp_word_label(var), delay, word);

      return 0;
}
Exemplo n.º 2
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;
}
Exemplo n.º 3
0
static void emit_stmt_inter_delay(ivl_scope_t scope, ivl_statement_t stmt)
{
      ivl_expr_t delay = ivl_stmt_delay_expr(stmt);
      unsigned nevents = ivl_stmt_nevent(stmt);
      if (nevents) {
	    ivl_expr_t count = ivl_stmt_cond_expr(stmt);
	    if (count) {
		  if (ivl_expr_type(count) == IVL_EX_ULONG) {
			unsigned long repeat = ivl_expr_uvalue(count);
			if (repeat != 1) {
			      fprintf(vlog_out, "repeat(%lu) ", repeat);
			}
		  } else {
			fprintf(vlog_out, "repeat(");
			emit_expr(scope, count, 0);
			fprintf(vlog_out, ") ");
		  }
	    }
	    assert(delay == 0);
	    fprintf(vlog_out, "@(");
	    emit_event(scope, stmt);
	    fprintf(vlog_out, ") ");
      }
      if (delay) {
	    assert(nevents == 0);
	    fprintf(vlog_out, "#(");
	    emit_scaled_delayx(scope, delay, 1);
	    fprintf(vlog_out, ") ");
      }
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
static void lpm_show_dff(ivl_lpm_t net)
{
      char name[64];
      edif_cell_t cell;
      edif_cellref_t ref;
      edif_joint_t jnt;

      unsigned idx;
      unsigned pin, wid = ivl_lpm_width(net);

      sprintf(name, "fd%s%s%s%s%s%u",
	      ivl_lpm_enable(net)? "ce" : "",
	      ivl_lpm_async_clr(net)? "cl" : "",
	      ivl_lpm_sync_clr(net)? "sc" : "",
	      ivl_lpm_async_set(net)? "se" : "",
	      ivl_lpm_sync_set(net)? "ss" : "",
	      wid);

      cell = edif_xlibrary_findcell(xlib, name);

      if (cell == 0) {
	    unsigned nports = 2 * wid + 1;
	    pin = 0;
	    if (ivl_lpm_enable(net))
		  nports += 1;
	    if (ivl_lpm_async_clr(net))
		  nports += 1;
	    if (ivl_lpm_sync_clr(net))
		  nports += 1;
	    if (ivl_lpm_async_set(net))
		  nports += 1;
	    if (ivl_lpm_sync_set(net))
		  nports += 1;

	    cell = edif_xcell_create(xlib, strdup(name), nports);
	    edif_cell_pstring(cell,  "LPM_Type", "LPM_FF");
	    edif_cell_pinteger(cell, "LPM_Width", wid);

	    for (idx = 0 ;  idx < wid ;  idx += 1) {

		  sprintf(name, "Q%u", idx);
		  edif_cell_portconfig(cell, idx*2+0, strdup(name),
				       IVL_SIP_OUTPUT);

		  sprintf(name, "Data%u", idx);
		  edif_cell_portconfig(cell, idx*2+1, strdup(name),
				       IVL_SIP_INPUT);
	    }

	    pin = wid*2;

	    if (ivl_lpm_enable(net)) {
		  edif_cell_portconfig(cell, pin, "Enable", IVL_SIP_INPUT);
		  pin += 1;
	    }

	    if (ivl_lpm_async_clr(net)) {
		  edif_cell_portconfig(cell, pin, "Aclr", IVL_SIP_INPUT);
		  pin += 1;
	    }

	    if (ivl_lpm_sync_clr(net)) {
		  edif_cell_portconfig(cell, pin, "Sclr", IVL_SIP_INPUT);
		  pin += 1;
	    }

	    if (ivl_lpm_async_set(net)) {
		  edif_cell_portconfig(cell, pin, "Aset", IVL_SIP_INPUT);
		  pin += 1;
	    }

	    if (ivl_lpm_sync_set(net)) {
		  edif_cell_portconfig(cell, pin, "Sset", IVL_SIP_INPUT);
		  pin += 1;
	    }

	    edif_cell_portconfig(cell, pin, "Clock", IVL_SIP_INPUT);
	    pin += 1;

	    assert(pin == nports);
      }

      ref = edif_cellref_create(edf, cell);

      pin = edif_cell_port_byname(cell, "Clock");

      jnt = edif_joint_of_nexus(edf, ivl_lpm_clk(net));
      edif_add_to_joint(jnt, ref, pin);

      if (ivl_lpm_enable(net)) {
	    pin = edif_cell_port_byname(cell, "Enable");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_enable(net));
	    edif_add_to_joint(jnt, ref, pin);
      }

      if (ivl_lpm_async_clr(net)) {
	    pin = edif_cell_port_byname(cell, "Aclr");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_async_clr(net));
	    edif_add_to_joint(jnt, ref, pin);
      }

      if (ivl_lpm_sync_clr(net)) {
	    pin = edif_cell_port_byname(cell, "Sclr");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_clr(net));
	    edif_add_to_joint(jnt, ref, pin);
      }

      if (ivl_lpm_async_set(net)) {
	    pin = edif_cell_port_byname(cell, "Aset");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_async_set(net));
	    edif_add_to_joint(jnt, ref, pin);
      }

      if (ivl_lpm_sync_set(net)) {
	    ivl_expr_t svalue = ivl_lpm_sset_value(net);

	    pin = edif_cell_port_byname(cell, "Sset");

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_sync_set(net));
	    edif_add_to_joint(jnt, ref, pin);

	    edif_cellref_pinteger(ref, "LPM_Svalue", ivl_expr_uvalue(svalue));
      }

      for (idx = 0 ;  idx < wid ;  idx += 1) {

	    sprintf(name, "Q%u", idx);
	    pin = edif_cell_port_byname(cell, name);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_q(net, idx));
	    edif_add_to_joint(jnt, ref, pin);

	    sprintf(name, "Data%u", idx);
	    pin = edif_cell_port_byname(cell, name);

	    jnt = edif_joint_of_nexus(edf, ivl_lpm_data(net, idx));
	    edif_add_to_joint(jnt, ref, pin);
      }
}
static int show_stmt_assign_nb(ivl_statement_t net)
{
      ivl_lval_t lval;
      ivl_expr_t rval = ivl_stmt_rval(net);
      ivl_expr_t del  = ivl_stmt_delay_expr(net);
      ivl_memory_t mem;

      unsigned long delay = 0;

	/* Catch the case we are assigning to a real/word
	   l-value. Handle that elsewhere. */
      if (ivl_lval_var(ivl_stmt_lval(net, 0))) {
	    return show_stmt_assign_nb_var(net);
      }

      if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) {
	    delay = ivl_expr_uvalue(del);
	    del = 0;
      }

	/* Handle the special case that the r-value is a constant. We
	   can generate the %set statement directly, without any worry
	   about generating code to evaluate the r-value expressions. */

      if (ivl_expr_type(rval) == IVL_EX_NUMBER) {
	    unsigned lidx;
	    const char*bits = ivl_expr_bits(rval);
	    unsigned wid = ivl_expr_width(rval);
	    unsigned cur_rbit = 0;

	    if (del != 0)
		  calculate_into_x1(del);

	    for (lidx = 0 ;  lidx < ivl_stmt_lvals(net) ;  lidx += 1) {
		  unsigned skip_set = transient_id++;
		  unsigned skip_set_flag = 0;
		  unsigned idx;
		  unsigned bit_limit = wid - cur_rbit;
		  lval = ivl_stmt_lval(net, lidx);

		    /* If there is a mux for the lval, calculate the
		       value and write it into index0. */
		  if (ivl_lval_mux(lval)) {
			calculate_into_x0(ivl_lval_mux(lval));
			fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
			skip_set_flag = 1;
		  }

		  mem = ivl_lval_mem(lval);
		  if (mem) {
			draw_memory_index_expr(mem, ivl_lval_idx(lval));
			fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
			skip_set_flag = 1;
		  }

		  if (bit_limit > ivl_lval_pins(lval))
			bit_limit = ivl_lval_pins(lval);

		  if (mem) {
			for (idx = 0 ;  idx < bit_limit ;  idx += 1) {
			      assign_to_memory(mem, idx, 
					       bitchar_to_idx(bits[cur_rbit]),
					       delay);
			      cur_rbit += 1;
			}

			for (idx = bit_limit
				   ; idx < ivl_lval_pins(lval)
				   ; idx += 1) {
			      assign_to_memory(mem, idx, 0, delay);
			}

		  } else if ((del == 0) && (bit_limit > 2)) {

			  /* We have a vector, but no runtime
			     calculated delays, to try to use vector
			     assign instructions. */
			idx = 0;
			while (idx < bit_limit) {
			      unsigned wid = 0;

			      do {
				    wid += 1;
				    if ((idx + wid) == bit_limit)
					  break;

			      } while (bits[cur_rbit] == bits[cur_rbit+wid]);

			      switch (wid) {
				  case 1:
				    assign_to_lvariable(lval, idx,
					       bitchar_to_idx(bits[cur_rbit]),
					       delay, 0);
				    break;
				  case 2:
				    assign_to_lvariable(lval, idx,
					       bitchar_to_idx(bits[cur_rbit]),
					       delay, 0);
				    assign_to_lvariable(lval, idx+1,
					       bitchar_to_idx(bits[cur_rbit]),
					       delay, 0);
				    break;
				  default:
				    assign_to_lvector(lval, idx,
					      bitchar_to_idx(bits[cur_rbit]),
					      delay, wid);
				    break;
			      }

			      idx += wid;
			      cur_rbit += wid;
			}

			if (bit_limit < ivl_lval_pins(lval)) {
			      unsigned wid = ivl_lval_pins(lval) - bit_limit;
			      assign_to_lvector(lval, bit_limit,
						0, delay, wid);
			}

		  } else {
			for (idx = 0 ;  idx < bit_limit ;  idx += 1) {
			      if (del != 0)
				    assign_to_lvariable(lval, idx,
					       bitchar_to_idx(bits[cur_rbit]),
					       1, 1);
			      else
				    assign_to_lvariable(lval, idx,
					       bitchar_to_idx(bits[cur_rbit]),
					       delay, 0);
			      cur_rbit += 1;
			}

			for (idx = bit_limit
				   ; idx < ivl_lval_pins(lval)
				   ; idx += 1) {
			      if (del != 0)
				    assign_to_lvariable(lval, idx, 0,
							1, 1);
			      else
				    assign_to_lvariable(lval, idx, 0,
							delay, 0);
			}
		  }

		  if (skip_set_flag) {
			fprintf(vvp_out, "t_%u ;\n", skip_set);
			clear_expression_lookaside();
		  }
	    }
	    return 0;
      }


      { struct vector_info res = draw_eval_expr(rval, 0);
        unsigned wid = res.wid;
	unsigned lidx;
	unsigned cur_rbit = 0;

	if (del != 0)
	      calculate_into_x1(del);

	for (lidx = 0 ;  lidx < ivl_stmt_lvals(net) ;  lidx += 1) {
	      unsigned skip_set = transient_id++;
	      unsigned skip_set_flag = 0;
	      unsigned idx;
	      unsigned bit_limit = wid - cur_rbit;
	      lval = ivl_stmt_lval(net, lidx);

		/* If there is a mux for the lval, calculate the
		   value and write it into index0. */
	      if (ivl_lval_mux(lval)) {
		    calculate_into_x0(ivl_lval_mux(lval));
		    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
		    skip_set_flag = 1;
	      }

	      mem = ivl_lval_mem(lval);
	      if (mem) {
		    draw_memory_index_expr(mem, ivl_lval_idx(lval));
		    fprintf(vvp_out, "    %%jmp/1 t_%u, 4;\n", skip_set);
		    skip_set_flag = 1;
	      }

	      if (bit_limit > ivl_lval_pins(lval))
		    bit_limit = ivl_lval_pins(lval);

	      if ((bit_limit > 2) && (mem == 0) && (del == 0)) {

		    unsigned bidx = res.base < 4
			  ? res.base
			  : (res.base+cur_rbit);
		    assign_to_lvector(lval, 0, bidx, delay, bit_limit);
		    cur_rbit += bit_limit;

	      } else {
		    for (idx = 0 ;  idx < bit_limit ;  idx += 1) {
			  unsigned bidx = res.base < 4
				? res.base
				: (res.base+cur_rbit);
			  if (mem)
				assign_to_memory(mem, idx, bidx, delay);
			  else if (del != 0)
				assign_to_lvariable(lval, idx, bidx,
						    1, 1);
			  else
				assign_to_lvariable(lval, idx, bidx,
						    delay, 0);

			  cur_rbit += 1;
		    }
	      }

	      for (idx = bit_limit; idx < ivl_lval_pins(lval); idx += 1)
			  if (mem)
				assign_to_memory(mem, idx, 0, delay);
			  else if (del != 0)
				assign_to_lvariable(lval, idx, 0, 1, 1);
			  else
				assign_to_lvariable(lval, idx, 0, delay, 0);


	      if (skip_set_flag) {
		    fprintf(vvp_out, "t_%u ;\n", skip_set);
		    clear_expression_lookaside();
	      }
	}

	if (res.base > 3)
	      clr_vector(res);
      }

      return 0;
}