static int show_stmt_fork(ivl_statement_t net, ivl_scope_t sscope)
{
      unsigned idx;
      int rc = 0;
      unsigned cnt = ivl_stmt_block_count(net);
      ivl_scope_t scope = ivl_stmt_block_scope(net);

      unsigned out = transient_id++;
      unsigned id_base = transient_id;

	/* cnt is the number of sub-threads. If the fork-join has no
	   name, then we can put one of the sub-threads in the current
	   thread, so decrement the count by one. */
      if (scope == 0) {
	    cnt -= 1;
	    scope = sscope;
      }

      transient_id += cnt;

	/* If no subscope use provided */
      if (!scope) scope = sscope;

	/* Draw a fork statement for all but one of the threads of the
	   fork/join. Send the threads off to a bit of code where they
	   are implemented. */
      for (idx = 0 ;  idx < cnt ;  idx += 1) {
	    fprintf(vvp_out, "    %%fork t_%u, S_%p;\n",
		    id_base+idx, scope);
      }

	/* If we are putting one sub-thread into the current thread,
	   then draw its code here. */
      if (ivl_stmt_block_scope(net) == 0)
	    rc += show_statement(ivl_stmt_block_stmt(net, cnt), scope);


	/* Generate enough joins to collect all the sub-threads. */
      for (idx = 0 ;  idx < cnt ;  idx += 1) {
	    fprintf(vvp_out, "    %%join;\n");
      }
      fprintf(vvp_out, "    %%jmp t_%u;\n", out);

	/* Generate the sub-threads themselves. */
      for (idx = 0 ;  idx < cnt ;  idx += 1) {
	    fprintf(vvp_out, "t_%u ;\n", id_base+idx);
	    clear_expression_lookaside();
	    rc += show_statement(ivl_stmt_block_stmt(net, idx), scope);
	    fprintf(vvp_out, "    %%end;\n");
      }

	/* This is the label for the out. Use this to branch around
	   the implementations of all the child threads. */
      clear_expression_lookaside();
      fprintf(vvp_out, "t_%u ;\n", out);

      return rc;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
static void emit_stmt_fork_named(ivl_scope_t scope, ivl_statement_t stmt)
{
      ivl_scope_t my_scope = ivl_stmt_block_scope(stmt);
      fprintf(vlog_out, "%*cfork: ", get_indent(), ' ');
      emit_id(ivl_scope_basename(my_scope));
      emit_stmt_file_line(stmt);
      fprintf(vlog_out, "\n");
      emit_stmt_block_body(scope, stmt);
      fprintf(vlog_out, "%*cjoin  /* %s */\n", get_indent(), ' ',
                        ivl_scope_basename(my_scope));
}
Ejemplo n.º 4
0
static void emit_stmt_block_body(ivl_scope_t scope, ivl_statement_t stmt)
{
      unsigned idx, count = ivl_stmt_block_count(stmt);
      ivl_scope_t my_scope = ivl_stmt_block_scope(stmt);
      indent += indent_incr;
      if (my_scope) emit_scope_variables(my_scope);
      else my_scope = scope;
      for (idx = 0; idx < count; idx += 1) {
	    emit_stmt(my_scope, ivl_stmt_block_stmt(stmt, idx));
      }
      assert(indent >= indent_incr);
      indent -= indent_incr;
}
/*
 * This draws an invocation of a named block. This is a little
 * different because a subscope is created. We do that by creating
 * a thread to deal with this.
 */
static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope)
{
      int rc;
      int out_id, sub_id;
      ivl_scope_t subscope = ivl_stmt_block_scope(net);

      out_id = transient_id++;
      sub_id = transient_id++;

      fprintf(vvp_out, "    %%fork t_%u, S_%p;\n",
	      sub_id, subscope);
      fprintf(vvp_out, "    %%jmp t_%u;\n", out_id);
      fprintf(vvp_out, "t_%u ;\n", sub_id);

      rc = show_stmt_block(net, subscope);
      fprintf(vvp_out, "    %%end;\n");

      fprintf(vvp_out, "t_%u %%join;\n", out_id);
      clear_expression_lookaside();

      return rc;
}
/*
 * This function draws a statement as vvp assembly. It basically
 * switches on the statement type and draws code based on the type and
 * further specifics.
 */
static int show_statement(ivl_statement_t net, ivl_scope_t sscope)
{
      const ivl_statement_type_t code = ivl_statement_type(net);
      int rc = 0;

      switch (code) {

	  case IVL_ST_ASSIGN:
	    rc += show_stmt_assign(net);
	    break;

	  case IVL_ST_ASSIGN_NB:
	    rc += show_stmt_assign_nb(net);
	    break;

	  case IVL_ST_BLOCK:
	    if (ivl_stmt_block_scope(net))
		  rc += show_stmt_block_named(net, sscope);
	    else
		  rc += show_stmt_block(net, sscope);
	    break;

	  case IVL_ST_CASE:
	  case IVL_ST_CASEX:
	  case IVL_ST_CASEZ:
	    rc += show_stmt_case(net, sscope);
	    break;

	  case IVL_ST_CASER:
	    rc += show_stmt_case_r(net, sscope);
	    break;

	  case IVL_ST_CASSIGN:
	    rc += show_stmt_cassign(net);
	    break;

	  case IVL_ST_CONDIT:
	    rc += show_stmt_condit(net, sscope);
	    break;

	  case IVL_ST_DEASSIGN:
	    rc += show_stmt_deassign(net);
	    break;

	  case IVL_ST_DELAY:
	    rc += show_stmt_delay(net, sscope);
	    break;

	  case IVL_ST_DELAYX:
	    rc += show_stmt_delayx(net, sscope);
	    break;

	  case IVL_ST_DISABLE:
	    rc += show_stmt_disable(net, sscope);
	    break;

	  case IVL_ST_FORCE:
	    rc += show_stmt_force(net);
	    break;

	  case IVL_ST_FOREVER:
	    rc += show_stmt_forever(net, sscope);
	    break;

	  case IVL_ST_FORK:
	    rc += show_stmt_fork(net, sscope);
	    break;

	  case IVL_ST_NOOP:
	    rc += show_stmt_noop(net);
	    break;

	  case IVL_ST_RELEASE:
	    rc += show_stmt_release(net);
	    break;

	  case IVL_ST_REPEAT:
	    rc += show_stmt_repeat(net, sscope);
	    break;

	  case IVL_ST_STASK:
	    rc += show_system_task_call(net);
	    break;

	  case IVL_ST_TRIGGER:
	    rc += show_stmt_trigger(net);
	    break;

	  case IVL_ST_UTASK:
	    rc += show_stmt_utask(net);
	    break;

	  case IVL_ST_WAIT:
	    rc += show_stmt_wait(net, sscope);
	    break;

	  case IVL_ST_WHILE:
	    rc += show_stmt_while(net, sscope);
	    break;

	  default:
	    fprintf(stderr, "vvp.tgt: Unable to draw statement type %u\n",
		    code);
	    rc += 1;
	    break;
      }

      return rc;
}
Ejemplo n.º 7
0
void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt)
{
      switch(ivl_statement_type(stmt)) {
	case IVL_ST_NOOP:
	      /* If this is a statement termination then just finish the
	       * statement, otherwise print an empty begin/end pair. */
	    if (single_indent) {
		  single_indent = 0;
		  fprintf(vlog_out, ";\n");
	    } else {
		  fprintf(vlog_out, "%*cbegin\n", get_indent(), ' ');
		  fprintf(vlog_out, "%*cend\n", get_indent(), ' ');
	    }
	    break;
	case IVL_ST_ALLOC:
	      /* This statement is only used with an automatic task so we
	       * can safely skip it. The automatic task definition will
	       * generate an appropriate error message.*/
	    break;
	case IVL_ST_ASSIGN:
	    emit_stmt_assign(scope, stmt);
	    break;
	case IVL_ST_ASSIGN_NB:
	    emit_stmt_assign_nb(scope, stmt);
	    break;
	case IVL_ST_BLOCK:
	    if (ivl_stmt_block_scope(stmt)) {
		  emit_stmt_block_named(scope, stmt);
	    } else {
		  if (is_delayed_or_event_assign(scope, stmt)) break;
		  if (is_for_loop(scope, stmt)) break;
		  if (is_repeat_event_assign(scope, stmt)) break;
		  if (is_wait(scope, stmt)) break;
		  if (is_utask_call_with_args(scope, stmt)) break;
		  emit_stmt_block(scope, stmt);
	    }
	    break;
	case IVL_ST_CASE:
	case IVL_ST_CASER:
	case IVL_ST_CASEX:
	case IVL_ST_CASEZ:
	    emit_stmt_case(scope, stmt);
	    break;
	case IVL_ST_CASSIGN:
	    emit_stmt_cassign(scope, stmt);
	    break;
	case IVL_ST_CONDIT:
	    emit_stmt_condit(scope, stmt);
	    break;
	case IVL_ST_DEASSIGN:
	    emit_stmt_deassign(scope, stmt);
	    break;
	case IVL_ST_DELAY:
	    emit_stmt_delay(scope, stmt);
	    break;
	case IVL_ST_DELAYX:
	    emit_stmt_delayx(scope, stmt);
	    break;
	case IVL_ST_DISABLE:
	    emit_stmt_disable(scope, stmt);
	    break;
	case IVL_ST_FORCE:
	    emit_stmt_force(scope, stmt);
	    break;
	case IVL_ST_FOREVER:
	    emit_stmt_forever(scope, stmt);
	    break;
	case IVL_ST_FORK:
	    if (ivl_stmt_block_scope(stmt)) {
		  emit_stmt_fork_named(scope, stmt);
	    } else {
		  emit_stmt_fork(scope, stmt);
	    }
	    break;
	case IVL_ST_FREE:
	      /* This statement is only used with an automatic task so we
	       * can safely skip it. The automatic task definition will
	       * generate an appropriate error message.*/
	    break;
	case IVL_ST_RELEASE:
	    emit_stmt_release(scope, stmt);
	    break;
	case IVL_ST_REPEAT:
	    emit_stmt_repeat(scope, stmt);
	    break;
	case IVL_ST_STASK:
	    emit_stmt_stask(scope, stmt);
	    break;
	case IVL_ST_TRIGGER:
	    emit_stmt_trigger(scope, stmt);
	    break;
	case IVL_ST_UTASK:
	    emit_stmt_utask(scope, stmt);
	    break;
	case IVL_ST_WAIT:
	    emit_stmt_wait(scope, stmt);
	    break;
	case IVL_ST_WHILE:
	    emit_stmt_while(scope, stmt);
	    break;
	default:
	    fprintf(vlog_out, "%*c<unknown>;\n", get_indent(), ' ');
	    fprintf(stderr, "%s:%u: vlog95 error: Unknown statement "
	                    "type (%d).\n",
	                    ivl_stmt_file(stmt),
	                    ivl_stmt_lineno(stmt),
	                    (int)ivl_statement_type(stmt));
	    vlog_errors += 1;
	    break;
      }
}