/* * 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; }
/* * 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; }
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, ") "); } }
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)); }
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; }
/* * 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; }