/* * 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; }
void emit_process(ivl_scope_t scope, ivl_process_t proc) { ivl_statement_t stmt; fprintf(vlog_out, "\n%*c", get_indent(), ' '); switch (ivl_process_type(proc)) { case IVL_PR_INITIAL: fprintf(vlog_out, "initial"); break; case IVL_PR_ALWAYS: fprintf(vlog_out, "always"); break; default: fprintf(vlog_out, "<unknown>"); fprintf(stderr, "%s:%u: vlog95 error: Unknown process type (%d).\n", ivl_process_file(proc), ivl_process_lineno(proc), (int)ivl_process_type(proc)); vlog_errors+= 1; break; } if (emit_file_line) { fprintf(vlog_out, " /* %s:%u */", ivl_process_file(proc), ivl_process_lineno(proc)); } stmt = ivl_process_stmt(proc); if (ivl_statement_type(stmt) == IVL_ST_NOOP) { fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' '); } else { single_indent = 1; emit_stmt(scope, stmt); } }
/* * 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 void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt) { char *case_type; unsigned idx, default_case, count = ivl_stmt_case_count(stmt); switch(ivl_statement_type(stmt)) { case IVL_ST_CASE: case IVL_ST_CASER: case_type = "case"; break; case IVL_ST_CASEX: case_type = "casex"; break; case IVL_ST_CASEZ: case_type = "casez"; break; default: assert(0); } fprintf(vlog_out, "%*c%s (", get_indent(), ' ', case_type); emit_expr(scope, ivl_stmt_cond_expr(stmt), 0); fprintf(vlog_out, ")"); emit_stmt_file_line(stmt); fprintf(vlog_out, "\n"); indent += indent_incr; default_case = count; for (idx = 0; idx < count; idx += 1) { ivl_expr_t expr = ivl_stmt_case_expr(stmt, idx); /* This is the default case so emit it last. */ if (expr == 0) { assert(default_case == count); default_case = idx; continue; } fprintf(vlog_out, "%*c", get_indent(), ' '); emit_expr(scope, expr, 0); fprintf(vlog_out, ":"); single_indent = 1; emit_stmt(scope, ivl_stmt_case_stmt(stmt, idx)); } if (default_case < count) { fprintf(vlog_out, "%*cdefault:", get_indent(), ' '); single_indent = 1; emit_stmt(scope, ivl_stmt_case_stmt(stmt, default_case)); } assert(indent >= indent_incr); indent -= indent_incr; fprintf(vlog_out, "%*cendcase\n", get_indent(), ' '); }
static void emit_stmt_condit(ivl_scope_t scope, ivl_statement_t stmt) { ivl_statement_t true_stmt = ivl_stmt_cond_true(stmt); ivl_statement_t false_stmt = ivl_stmt_cond_false(stmt); unsigned nest = 0; fprintf(vlog_out, "%*cif (", get_indent(), ' '); emit_expr(scope, ivl_stmt_cond_expr(stmt), 0); fprintf(vlog_out, ")"); emit_stmt_file_line(stmt); if (true_stmt) { /* If we have a false statement and the true statement is a * condition that does not have a false clause then we need * to add a begin/end pair to keep the else clause attached * to this condition. */ if (false_stmt && (ivl_statement_type(true_stmt) == IVL_ST_CONDIT) && (! ivl_stmt_cond_false(true_stmt))) nest = 1; if (nest) { fprintf(vlog_out, " begin\n"); indent += indent_incr; } else single_indent = 1; emit_stmt(scope, true_stmt); } else { fprintf(vlog_out, ";\n"); } if (false_stmt) { if (nest) { assert(indent >= indent_incr); indent -= indent_incr; } fprintf(vlog_out, "%*c", get_indent(), ' '); if (nest) fprintf(vlog_out, "end "); fprintf(vlog_out, "else"); single_indent = 1; emit_stmt(scope, false_stmt); } }
void clsAnalysis::AnalyzeStatement(clsStatement * pStatement, clsBasicBlock * pBasicBlock, clsEvent * pEvent) { ivl_statement_t ivl_Statement; vector<clsLValue *>::iterator it_pLValue; vector<clsBasicBlock *>::iterator it_pBasicBlock; unsigned int iNumberOfParameters; unsigned int iNumberOfStatements; unsigned int iIndex; ivl_Statement = pStatement->m_ivl_Statement; it_pBasicBlock = pBasicBlock->m_pSuccessors.begin(); switch (pStatement->m_Type) { default: _DebugPrint("/* Unrecognized statement of type %u is encountered. */\n", ivl_statement_type(ivl_Statement) ); _Assert(0 && "Frontend Error: Unrecognized statement is encountered."); break; case CMODELGEN_STATEMENT_NOP: break; case CMODELGEN_STATEMENT_WAIT: if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } break; case CMODELGEN_STATEMENT_CASE: case CMODELGEN_STATEMENT_CASEZ: case CMODELGEN_STATEMENT_CASEX: AnalyzeExpression(pStatement->m_pExpressions[0], pEvent); iNumberOfStatements = ivl_stmt_case_count(ivl_Statement); for(iIndex = 0; iIndex < iNumberOfStatements; ++iIndex) { AnalyzeExpression(pStatement->m_pExpressions[iIndex + 1], pEvent); if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() ) { ++it_pBasicBlock; } } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } break; case CMODELGEN_STATEMENT_COND: AnalyzeExpression(pStatement->m_pExpressions[0], pEvent); if (0 != ivl_stmt_cond_true(ivl_Statement) ) { if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() ) { ++it_pBasicBlock; } } if (0 != ivl_stmt_cond_false(ivl_Statement) ) { if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() ) { ++it_pBasicBlock; } } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } break; case CMODELGEN_STATEMENT_REPEAT: case CMODELGEN_STATEMENT_WHILE: AnalyzeExpression(pStatement->m_pExpressions[0], pEvent); if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } if (it_pBasicBlock != pBasicBlock->m_pSuccessors.end() && *it_pBasicBlock != NULL) { AnalyzeBasicBlock(*it_pBasicBlock, pEvent); } break; case CMODELGEN_STATEMENT_NB_ASSIGN: iIndex = 0; for (it_pLValue = pStatement->m_pLValues.begin(); it_pLValue != pStatement->m_pLValues.end(); ++it_pLValue) { AnalyzeNBLValue(*it_pLValue, pEvent); ++iIndex; } AnalyzeExpression(pStatement->m_pExpressions[0], pEvent); break; case CMODELGEN_STATEMENT_ASSIGN: iIndex = 0; for (it_pLValue = pStatement->m_pLValues.begin(); it_pLValue != pStatement->m_pLValues.end(); ++it_pLValue) { AnalyzeLValue(*it_pLValue, pEvent); ++iIndex; } AnalyzeExpression(pStatement->m_pExpressions[0], pEvent); break; case CMODELGEN_STATEMENT_STASK: iNumberOfParameters = ivl_stmt_parm_count(ivl_Statement); for(iIndex = 0; iIndex < iNumberOfParameters; ++iIndex) { AnalyzeExpression(pStatement->m_pExpressions[iIndex], pEvent); } break; case CMODELGEN_STATEMENT_UTASK: break; case CMODELGEN_STATEMENT_DISABLE: break; case CMODELGEN_STATEMENT_ALLOC: break; case CMODELGEN_STATEMENT_FREE: 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; }
/* * 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; }
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); } }
/* * Icarus encodes a user task call with arguments as: * begin * <input 1> = <arg> * ... * <input n> = <arg> * <task_call> * <arg> = <output 1> * ... * <arg> = <output n> * end * This routine looks for that pattern and translates it into the * appropriate task call. It returns true (1) if it successfully * translated the block to a task call, otherwise it returns false * (0) to indicate the block needs to be emitted. */ static unsigned is_utask_call_with_args(ivl_scope_t scope, ivl_statement_t stmt) { unsigned idx, ports, task_idx = 0; unsigned count = ivl_stmt_block_count(stmt); unsigned lineno = ivl_stmt_lineno(stmt); ivl_scope_t task_scope = 0; port_expr_t port_exprs; /* Check to see if the block is of the basic form first. */ for (idx = 0; idx < count; idx += 1) { ivl_statement_t tmp = ivl_stmt_block_stmt(stmt, idx); if (ivl_statement_type(tmp) == IVL_ST_ASSIGN) continue; if (ivl_statement_type(tmp) == IVL_ST_UTASK && !task_scope) { task_idx = idx; task_scope = ivl_stmt_call(tmp); assert(ivl_scope_type(task_scope) == IVL_SCT_TASK); continue; } return 0; } /* If there is no task call or it takes no argument then return. */ if (!task_scope) return 0; ports = ivl_scope_ports(task_scope); if (ports == 0) return 0; /* Allocate space to save the port information and initialize it. */ port_exprs = (port_expr_t) malloc(sizeof(struct port_expr_s)*ports); for (idx = 0; idx < ports; idx += 1) { port_exprs[idx].type = IVL_SIP_NONE; port_exprs[idx].expr.rval = 0; } /* Check that the input arguments are correct. */ for (idx = 0; idx < task_idx; idx += 1) { ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx); unsigned port = utask_in_port_idx(task_scope, assign); if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) { free(port_exprs); return 0; } port_exprs[port].type = IVL_SIP_INPUT; port_exprs[port].expr.rval = ivl_stmt_rval(assign); } /* Check that the output arguments are correct. */ for (idx = task_idx + 1; idx < count; idx += 1) { ivl_statement_t assign = ivl_stmt_block_stmt(stmt, idx); unsigned port = utask_out_port_idx(task_scope, assign); if ((port == ports) || (lineno != ivl_stmt_lineno(assign))) { free(port_exprs); return 0; } if (port_exprs[port].type == IVL_SIP_INPUT) { port_exprs[port].type = IVL_SIP_INOUT; // HERE: We probably should verify that the current R-value matches the // new L-value. } else { port_exprs[port].type = IVL_SIP_OUTPUT; } port_exprs[port].expr.lval = assign; } /* Check that the task call has the correct line number. */ if (lineno != ivl_stmt_lineno(ivl_stmt_block_stmt(stmt, task_idx))) { free(port_exprs); return 0; } /* Verify that all the ports were defined. */ for (idx = 0; idx < ports; idx += 1) { if (port_exprs[idx].type == IVL_SIP_NONE) { free(port_exprs); return 0; } } /* Now that we have the arguments figured out, print the task call. */ fprintf(vlog_out, "%*c", get_indent(), ' '); emit_scope_path(scope, task_scope); fprintf(vlog_out, "("); emit_port(scope, port_exprs[0]); for (idx = 1; idx < ports; idx += 1) { fprintf(vlog_out, ", "); emit_port(scope, port_exprs[idx]); } free(port_exprs); fprintf(vlog_out, ");"); emit_stmt_file_line(stmt); fprintf(vlog_out, "\n"); return 1; }
/* * 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; }
/* * 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; }
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; } }