static int show_stmt_repeat(ivl_statement_t net, ivl_scope_t sscope)
{
      int rc = 0;
      unsigned lab_top = local_count++, lab_out = local_count++;
      ivl_expr_t exp = ivl_stmt_cond_expr(net);
      struct vector_info cnt = draw_eval_expr(exp, 0);

	/* Test that 0 < expr */
      fprintf(vvp_out, "T_%u.%u %%cmp/u 0, %u, %u;\n", thread_count,
	      lab_top, cnt.base, cnt.wid);
      clear_expression_lookaside();
      fprintf(vvp_out, "    %%jmp/0xz T_%u.%u, 5;\n", thread_count, lab_out);
	/* This adds -1 (all ones in 2's complement) to the count. */
      fprintf(vvp_out, "    %%add %u, 1, %u;\n", cnt.base, cnt.wid);

      rc += show_statement(ivl_stmt_sub_stmt(net), sscope);

      fprintf(vvp_out, "    %%jmp T_%u.%u;\n", thread_count, lab_top);
      fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
      clear_expression_lookaside();

      clr_vector(cnt);

      return rc;
}
static int show_stmt_wait(ivl_statement_t net, ivl_scope_t sscope)
{
      if (ivl_stmt_nevent(net) == 1) {
	    ivl_event_t ev = ivl_stmt_events(net, 0);
	    fprintf(vvp_out, "    %%wait E_%p;\n", ev);

      } else {
	    unsigned idx;
	    static unsigned int cascade_counter = 0;
	    ivl_event_t ev = ivl_stmt_events(net, 0);
	    fprintf(vvp_out, "Ewait_%u .event/or E_%p", cascade_counter, ev);

	    for (idx = 1 ;  idx < ivl_stmt_nevent(net) ;  idx += 1) {
		  ev = ivl_stmt_events(net, idx);
		  fprintf(vvp_out, ", E_%p", ev);
	    }
	    fprintf(vvp_out, ";\n    %%wait Ewait_%u;\n", cascade_counter);
	    cascade_counter += 1;
      }
	/* Always clear the expression lookaside after a
	   %wait. Anything can happen while the thread is waiting. */
      clear_expression_lookaside();

      return show_statement(ivl_stmt_sub_stmt(net), sscope);
}
/*
 * The delayx statement is slightly more complex in that it is
 * necessary to calculate the delay first. Load the calculated delay
 * into and index register and use the %delayx instruction to do the
 * actual delay.
 */
static int show_stmt_delayx(ivl_statement_t net, ivl_scope_t sscope)
{
      int rc = 0;
      ivl_expr_t exp = ivl_stmt_delay_expr(net);
      ivl_statement_t stmt = ivl_stmt_sub_stmt(net);

      switch (ivl_expr_value(exp)) {

	  case IVL_VT_VECTOR: {
		struct vector_info del = draw_eval_expr(exp, 0);
		fprintf(vvp_out, "    %%ix/get 0, %u, %u;\n",
			del.base, del.wid);
		clr_vector(del);
		break;
	  }

	  case IVL_VT_REAL: {
		int word = draw_eval_real(exp);
		fprintf(vvp_out, "    %%cvt/ir 0, %d;\n", word);
		clr_word(word);
		break;
	  }

	  default:
	    assert(0);
      }

      fprintf(vvp_out, "    %%delayx 0;\n");
	/* Lots of things can happen during a delay. */
      clear_expression_lookaside();

      rc += show_statement(stmt, sscope);
      return rc;
}
Beispiel #4
0
static void emit_stmt_forever(ivl_scope_t scope, ivl_statement_t stmt)
{
      fprintf(vlog_out, "%*cforever", get_indent(), ' ');
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
}
Beispiel #5
0
/*
 * Icarus translated for(<assign>; <cond>; <incr_assign>) <body> into
 *
 *   begin
 *     <assign>;
 *     while (<cond>) begin
 *       <body>
 *       <incr_assign>
 *     end
 *   end
 * This routine looks for this pattern and turns it back into the
 * appropriate for loop.
 */
static unsigned is_for_loop(ivl_scope_t scope, ivl_statement_t stmt)
{
      unsigned wid;
      ivl_statement_t assign, while_lp, while_blk, body, incr_assign;

	/* We must have two block elements. */
      if (ivl_stmt_block_count(stmt) != 2) return 0;
	/* The first must be an assign. */
      assign = ivl_stmt_block_stmt(stmt, 0);
      if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
	/* The second must be a while. */
      while_lp = ivl_stmt_block_stmt(stmt, 1);
      if (ivl_statement_type(while_lp) != IVL_ST_WHILE) return 0;
	/* The while statement must be a block. */
      while_blk = ivl_stmt_sub_stmt(while_lp);
      if (ivl_statement_type(while_blk) != IVL_ST_BLOCK) return 0;
	/* It must not be a named block. */
      if (ivl_stmt_block_scope(while_blk)) return 0;
	/* It must have two elements. */
      if (ivl_stmt_block_count(while_blk) != 2) return 0;
	/* The first block element (the body) can be anything. */
      body = ivl_stmt_block_stmt(while_blk, 0);
	/* The second block element must be the increment assign. */
      incr_assign = ivl_stmt_block_stmt(while_blk, 1);
      if (ivl_statement_type(incr_assign) != IVL_ST_ASSIGN) return 0;
	/* And finally the for statements must have the same line number
	 * as the block. */
      if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_lp)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(while_blk)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(incr_assign))) {
	    return 0;
      }

	/* The pattern matched so generate the appropriate code. */
      fprintf(vlog_out, "%*cfor(", get_indent(), ' ');
	/* Emit the initialization statement. */
// HERE: Do we need to calculate the width? The compiler should have already
//       done this for us.
      wid = emit_stmt_lval(scope, assign);
      fprintf(vlog_out, " = ");
      emit_expr(scope, ivl_stmt_rval(assign), wid);
      fprintf(vlog_out, "; ");
	/* Emit the condition. */
      emit_expr(scope, ivl_stmt_cond_expr(while_lp), 0);
      fprintf(vlog_out, "; ");
	/* Emit in increment statement. */
// HERE: Do we need to calculate the width? The compiler should have already
//       done this for us.
      wid = emit_stmt_lval(scope, incr_assign);
      fprintf(vlog_out, " = ");
      emit_expr(scope, ivl_stmt_rval(incr_assign), wid);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
	/* Now emit the body. */
      single_indent = 1;
      emit_stmt(scope, body);

      return 1;
}
Beispiel #6
0
static void emit_stmt_delay(ivl_scope_t scope, ivl_statement_t stmt)
{
      fprintf(vlog_out, "%*c#", get_indent(), ' ');
      emit_scaled_delay(scope, ivl_stmt_delay_val(stmt));
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
}
Beispiel #7
0
static void emit_stmt_repeat(ivl_scope_t scope, ivl_statement_t stmt)
{
      fprintf(vlog_out, "%*crepeat (", get_indent(), ' ');
      emit_expr(scope, ivl_stmt_cond_expr(stmt), 0);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
}
Beispiel #8
0
static void emit_stmt_delayx(ivl_scope_t scope, ivl_statement_t stmt)
{
      fprintf(vlog_out, "%*c#(", get_indent(), ' ');
      emit_scaled_delayx(scope, ivl_stmt_delay_expr(stmt), 1);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
}
Beispiel #9
0
static void emit_stmt_wait(ivl_scope_t scope, ivl_statement_t stmt)
{
      fprintf(vlog_out, "%*c@(", get_indent(), ' ');
      emit_event(scope, stmt);
      fprintf(vlog_out, ")");
      emit_stmt_file_line(stmt);
      single_indent = 1;
      emit_stmt(scope, ivl_stmt_sub_stmt(stmt));
}
Beispiel #10
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;
}
static int show_stmt_forever(ivl_statement_t net, ivl_scope_t sscope)
{
      int rc = 0;
      ivl_statement_t stmt = ivl_stmt_sub_stmt(net);
      unsigned lab_top = local_count++;

      fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_top);
      rc += show_statement(stmt, sscope);
      fprintf(vvp_out, "    %%jmp T_%u.%u;\n", thread_count, lab_top);

      return rc;
}
/*
 * The delay statement is easy. Simply write a ``%delay <n>''
 * instruction to delay the thread, then draw the included statement.
 * The delay statement comes from verilog code like this:
 *
 *        ...
 *        #<delay> <stmt>;
 */
static int show_stmt_delay(ivl_statement_t net, ivl_scope_t sscope)
{
      int rc = 0;
      unsigned long delay = ivl_stmt_delay_val(net);
      ivl_statement_t stmt = ivl_stmt_sub_stmt(net);

      fprintf(vvp_out, "    %%delay %lu;\n", delay);
	/* Lots of things can happen during a delay. */
      clear_expression_lookaside();

      rc += show_statement(stmt, sscope);

      return rc;
}
static int show_stmt_while(ivl_statement_t net, ivl_scope_t sscope)
{
      int rc = 0;
      struct vector_info cvec;

      unsigned top_label = local_count++;
      unsigned out_label = local_count++;

	/* Start the loop. The top of the loop starts a basic block
	   because it can be entered from above or from the bottom of
	   the loop. */
      fprintf(vvp_out, "T_%d.%d ;\n", thread_count, top_label);
      clear_expression_lookaside();

	/* Draw the evaluation of the condition expression, and test
	   the result. If the expression evaluates to false, then
	   branch to the out label. */
      cvec = draw_eval_expr(ivl_stmt_cond_expr(net), STUFF_OK_XZ|STUFF_OK_47);
      if (cvec.wid > 1)
	    cvec = reduction_or(cvec);

      fprintf(vvp_out, "    %%jmp/0xz T_%d.%d, %u;\n",
	      thread_count, out_label, cvec.base);
      if (cvec.base >= 8)
	    clr_vector(cvec);

	/* Draw the body of the loop. */
      rc += show_statement(ivl_stmt_sub_stmt(net), sscope);

	/* This is the bottom of the loop. branch to the top where the
	   test is repeased, and also draw the out label. */
      fprintf(vvp_out, "    %%jmp T_%d.%d;\n", thread_count, top_label);
      fprintf(vvp_out, "T_%d.%d ;\n", thread_count, out_label);
      clear_expression_lookaside();
      return rc;
}
Beispiel #14
0
static void show_statement(ivl_statement_t net, unsigned ind)
{
      const ivl_statement_type_t code = ivl_statement_type(net);

      switch (code) {
	  case IVL_ST_ASSIGN:
	    fprintf(out, "%*s", ind, "");
	    show_assign_lvals(net);
	    fprintf(out, " = ");
	    show_expression(ivl_stmt_rval(net));
	    fprintf(out, ";\n");
	    break;

	  case IVL_ST_BLOCK: {
		unsigned cnt = ivl_stmt_block_count(net);
		unsigned idx;
		fprintf(out, "%*sbegin\n", ind, "");
		for (idx = 0 ;  idx < cnt ;  idx += 1) {
		      ivl_statement_t cur = ivl_stmt_block_stmt(net, idx);
		      show_statement(cur, ind+4);
		}
		fprintf(out, "%*send\n", ind, "");
		break;
	  }

	  case IVL_ST_CONDIT: {
		ivl_statement_t t = ivl_stmt_cond_true(net);
		ivl_statement_t f = ivl_stmt_cond_false(net);

		fprintf(out, "%*sif (", ind, "");
		show_expression(ivl_stmt_cond_expr(net));
		fprintf(out, ")\n");

		if (t)
		      show_statement(t, ind+4);
		else
		      fprintf(out, "%*s;\n", ind+4, "");

		if (f) {
		      fprintf(out, "%*selse\n", ind, "");
		      show_statement(f, ind+4);
		}

		break;
	  }

	  case IVL_ST_DELAY:
	    fprintf(out, "%*s#%lu\n", ind, "", ivl_stmt_delay_val(net));
	    show_statement(ivl_stmt_sub_stmt(net), ind+2);
	    break;

	  case IVL_ST_NOOP:
	    fprintf(out, "%*s/* noop */;\n", ind, "");
	    break;

	  case IVL_ST_STASK:
	    if (ivl_stmt_parm_count(net) == 0) {
		  fprintf(out, "%*s%s;\n", ind, "", ivl_stmt_name(net));

	    } else {
		  unsigned idx;
		  fprintf(out, "%*s%s(", ind, "", ivl_stmt_name(net));
		  show_expression(ivl_stmt_parm(net, 0));
		  for (idx = 1 ;  idx < ivl_stmt_parm_count(net) ; idx += 1) {
			fprintf(out, ", ");
			show_expression(ivl_stmt_parm(net, idx));
		  }
		  fprintf(out, ");\n");
	    }
	    break;

	  case IVL_ST_WAIT:
	    fprintf(out, "%*s@(...)\n", ind, "");
	    show_statement(ivl_stmt_sub_stmt(net), ind+2);
	    break;

	  case IVL_ST_WHILE:
	    fprintf(out, "%*swhile (<?>)\n", ind, "");
	    show_statement(ivl_stmt_sub_stmt(net), ind+2);
	    break;

	  default:
	    fprintf(out, "%*sunknown statement type (%d)\n", ind, "", code);
      }
}
Beispiel #15
0
/*
 * Icarus translated <var> = repeat(<count>) <event> <value> into
 *   begin
 *    <tmp> = <value>;
 *    repeat(<count>) <event>;
 *    <var> = <tmp>;
 *   end
 * This routine looks for this pattern and turns it back into the
 * appropriate blocking assignment.
 */
static unsigned is_repeat_event_assign(ivl_scope_t scope, ivl_statement_t stmt)
{
      unsigned wid;
      ivl_statement_t assign, event, event_assign, repeat;
      ivl_lval_t lval;
      ivl_expr_t rval;
      ivl_signal_t lsig, rsig;

	/* We must have three block elements. */
      if (ivl_stmt_block_count(stmt) != 3) return 0;
	/* The first must be an assign. */
      assign = ivl_stmt_block_stmt(stmt, 0);
      if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
	/* The second must be a repeat with an event or an event. */
      repeat = ivl_stmt_block_stmt(stmt, 1);
      if (ivl_statement_type(repeat) != IVL_ST_REPEAT) return 0;
	/* The repeat must have an event statement. */
      event = ivl_stmt_sub_stmt(repeat);
      if (ivl_statement_type(event) != IVL_ST_WAIT) return 0;
	/* The third must be an assign. */
      event_assign = ivl_stmt_block_stmt(stmt, 2);
      if (ivl_statement_type(event_assign) != IVL_ST_ASSIGN) return 0;
	/* The L-value must be a single signal. */
      if (ivl_stmt_lvals(assign) != 1) return 0;
      lval = ivl_stmt_lval(assign, 0);
	/* It must not have an array select. */
      if (ivl_lval_idx(lval)) return 0;
	/* It must not have a non-zero base. */
      if (ivl_lval_part_off(lval)) return 0;
      lsig = ivl_lval_sig(lval);
	/* It must not be part of the signal. */
      if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
	/* The R-value must be a single signal. */
      rval = ivl_stmt_rval(event_assign);
      if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
	/* It must not be an array word. */
      if (ivl_expr_oper1(rval)) return 0;
      rsig = ivl_expr_signal(rval);
	/* The two signals must be the same. */
      if (lsig != rsig) return 0;
	/* And finally the four statements must have the same line number
	 * as the block. */
      if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(repeat)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(event_assign))) {
	    return 0;
      }

	/* The pattern matched so generate the appropriate code. */
      fprintf(vlog_out, "%*c", get_indent(), ' ');
      wid = emit_stmt_lval(scope, event_assign);
      fprintf(vlog_out, " =");
      if (repeat) {
	    fprintf(vlog_out, " repeat (");
	    emit_expr(scope, ivl_stmt_cond_expr(repeat), 0);
	    fprintf(vlog_out, ")");
      }
      fprintf(vlog_out, " @(");
      emit_event(scope, event);
      fprintf(vlog_out, ") ");
      emit_expr(scope, ivl_stmt_rval(assign), wid);
      fprintf(vlog_out, ";");
      emit_stmt_file_line(stmt);
      fprintf(vlog_out, "\n");

      return 1;
}
Beispiel #16
0
/*
 * Icarus translated <var> = <delay or event> <value> into
 *   begin
 *    <tmp> = <value>;
 *    <delay or event> <var> = <tmp>;
 *   end
 * This routine looks for this pattern and turns it back into the
 * appropriate blocking assignment.
 */
static unsigned is_delayed_or_event_assign(ivl_scope_t scope,
                                           ivl_statement_t stmt)
{
      unsigned wid;
      ivl_statement_t assign, delay, delayed_assign;
      ivl_statement_type_t delay_type;
      ivl_lval_t lval;
      ivl_expr_t rval;
      ivl_signal_t lsig, rsig;

	/* We must have two block elements. */
      if (ivl_stmt_block_count(stmt) != 2) return 0;
	/* The first must be an assign. */
      assign = ivl_stmt_block_stmt(stmt, 0);
      if (ivl_statement_type(assign) != IVL_ST_ASSIGN) return 0;
	/* The second must be a delayx. */
      delay = ivl_stmt_block_stmt(stmt, 1);
      delay_type = ivl_statement_type(delay);
      if ((delay_type != IVL_ST_DELAYX) &&
          (delay_type != IVL_ST_WAIT)) return 0;
	/* The statement for the delayx must be an assign. */
      delayed_assign = ivl_stmt_sub_stmt(delay);
      if (ivl_statement_type(delayed_assign) != IVL_ST_ASSIGN) return 0;
	/* The L-value must be a single signal. */
      if (ivl_stmt_lvals(assign) != 1) return 0;
      lval = ivl_stmt_lval(assign, 0);
	/* It must not have an array select. */
      if (ivl_lval_idx(lval)) return 0;
	/* It must not have a non-zero base. */
      if (ivl_lval_part_off(lval)) return 0;
      lsig = ivl_lval_sig(lval);
	/* It must not be part of the signal. */
      if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return 0;
	/* The R-value must be a single signal. */
      rval = ivl_stmt_rval(delayed_assign);
      if (ivl_expr_type(rval) != IVL_EX_SIGNAL) return 0;
	/* It must not be an array word. */
      if (ivl_expr_oper1(rval)) return 0;
      rsig = ivl_expr_signal(rval);
	/* The two signals must be the same. */
      if (lsig != rsig) return 0;
	/* And finally the three statements must have the same line number
	 * as the block. */
      if ((ivl_stmt_lineno(stmt) != ivl_stmt_lineno(assign)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delay)) ||
          (ivl_stmt_lineno(stmt) != ivl_stmt_lineno(delayed_assign))) {
	    return 0;
      }

	/* The pattern matched so generate the appropriate code. */
      fprintf(vlog_out, "%*c", get_indent(), ' ');
      wid = emit_stmt_lval(scope, delayed_assign);
      fprintf(vlog_out, " = ");
      if (delay_type == IVL_ST_DELAYX) {
	    fprintf(vlog_out, "#(");
	    emit_scaled_delayx(scope, ivl_stmt_delay_expr(delay), 1);
      } else {
	    fprintf(vlog_out, "@(");
	    emit_event(scope, delay);
      }
      fprintf(vlog_out, ") ");
      emit_expr(scope, ivl_stmt_rval(assign), wid);
      fprintf(vlog_out, ";");
      emit_stmt_file_line(stmt);
      fprintf(vlog_out, "\n");

      return 1;
}