/* * Check to see if the statement L-value is a port in the given scope. * If it is return the zero based port number. */ static unsigned utask_in_port_idx(ivl_scope_t scope, ivl_statement_t stmt) { unsigned idx, ports = ivl_scope_ports(scope); ivl_lval_t lval = ivl_stmt_lval(stmt, 0); ivl_signal_t lsig = ivl_lval_sig(lval); const char *sig_name; /* The L-value must be a single signal. */ if (ivl_stmt_lvals(stmt) != 1) return ports; /* It must not have an array select. */ if (ivl_lval_idx(lval)) return ports; /* It must not have a non-zero base. */ if (ivl_lval_part_off(lval)) return ports; /* It must not be part of the signal. */ if (ivl_lval_width(lval) != ivl_signal_width(lsig)) return ports; /* It must have the same scope as the task. */ if (scope != ivl_signal_scope(lsig)) return ports; /* It must be an input or inout port of the task. */ sig_name = ivl_signal_basename(lsig); for (idx = 0; idx < ports; idx += 1) { ivl_signal_t port = ivl_scope_port(scope, idx); ivl_signal_port_t port_type = ivl_signal_port(port); if ((port_type != IVL_SIP_INPUT) && (port_type != IVL_SIP_INOUT)) continue; if (strcmp(sig_name, ivl_signal_basename(port)) == 0) break; } return idx; }
static int show_stmt_assign_sig_darray(ivl_statement_t net) { int errors = 0; ivl_lval_t lval = ivl_stmt_lval(net, 0); ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t part = ivl_lval_part_off(lval); ivl_signal_t var= ivl_lval_sig(lval); ivl_type_t var_type= ivl_signal_net_type(var); assert(ivl_type_base(var_type) == IVL_VT_DARRAY); ivl_type_t element_type = ivl_type_element(var_type); ivl_expr_t mux = ivl_lval_idx(lval); assert(ivl_stmt_lvals(net) == 1); assert(ivl_stmt_opcode(net) == 0); assert(ivl_lval_mux(lval) == 0); assert(part == 0); if (mux && (ivl_type_base(element_type)==IVL_VT_REAL)) { draw_eval_real(rval); /* The %set/dar expects the array index to be in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); } else if (mux && ivl_type_base(element_type)==IVL_VT_STRING) { /* Evaluate the rval into the top of the string stack. */ draw_eval_string(rval); /* The %store/dar/s expects the array index to me in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); } else if (mux) { struct vector_info rvec = draw_eval_expr_wid(rval, ivl_lval_width(lval), STUFF_OK_XZ); /* The %set/dar expects the array index to be in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%set/dar v%p_0, %u, %u;\n", var, rvec.base, rvec.wid); if (rvec.base >= 4) clr_vector(rvec); } else { /* There is no l-value mux, so this must be an assignment to the array as a whole. Evaluate the "object", and store the evaluated result. */ errors += draw_eval_object(rval); fprintf(vvp_out, " %%store/obj v%p_0;\n", var); } return errors; }
/* * This function assigns a value to a real .variable. This is destined * for /dev/null when typed ivl_signal_t takes over all the real * variable support. */ static int show_stmt_assign_sig_real(ivl_statement_t net) { ivl_lval_t lval; ivl_signal_t var; assert(ivl_stmt_opcode(net) == 0); draw_eval_real(ivl_stmt_rval(net)); assert(ivl_stmt_lvals(net) == 1); lval = ivl_stmt_lval(net, 0); var = ivl_lval_sig(lval); assert(var != 0); if (ivl_signal_dimensions(var) == 0) { fprintf(vvp_out, " %%store/real v%p_0;\n", var); return 0; } // For now, only support 1-dimensional arrays. assert(ivl_signal_dimensions(var) == 1); ivl_expr_t word_ex = ivl_lval_idx(lval); int word_ix = allocate_word(); /* If the word index is a constant, then we can write directly to the word and save the index calculation. Out-of-bounds and undefined indices are converted to a canonical index of 'bx during elaboration, and we don't try to optimise that case. */ if (word_ex && number_is_immediate(word_ex, IMM_WID, 0) && !number_is_unknown(word_ex)) { unsigned long use_word = get_number_immediate(word_ex); assert(use_word < ivl_signal_array_count(var)); fprintf(vvp_out, " %%ix/load %u, %lu, 0;\n", word_ix, use_word); fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix); } else { unsigned do_store = transient_id++; unsigned end_store = transient_id++; draw_eval_expr_into_integer(word_ex, word_ix); fprintf(vvp_out, " %%jmp/0 t_%u, 4;\n", do_store); fprintf(vvp_out, " %%pop/real 1;\n"); fprintf(vvp_out, " %%jmp t_%u;\n", end_store); fprintf(vvp_out, "t_%u ;\n", do_store); fprintf(vvp_out, " %%store/reala v%p, %d;\n", var, word_ix); fprintf(vvp_out, "t_%u ;\n", end_store); } clr_word(word_ix); return 0; }
static int show_stmt_assign_sig_string(ivl_statement_t net) { ivl_lval_t lval = ivl_stmt_lval(net, 0); ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t part = ivl_lval_part_off(lval); ivl_expr_t aidx = ivl_lval_idx(lval); ivl_signal_t var= ivl_lval_sig(lval); assert(ivl_stmt_lvals(net) == 1); assert(ivl_stmt_opcode(net) == 0); assert(ivl_lval_mux(lval) == 0); /* Simplest case: no mux. Evaluate the r-value as a string and store the result into the variable. Note that the %store/str opcode pops the string result. */ if (part == 0 && aidx == 0) { draw_eval_string(rval); fprintf(vvp_out, " %%store/str v%p_0;\n", var); return 0; } /* Assign to array. The l-value has an index expression expression so we are assigning to an array word. */ if (aidx != 0) { unsigned ix; assert(part == 0); draw_eval_string(rval); draw_eval_expr_into_integer(aidx, (ix = allocate_word())); fprintf(vvp_out, " %%store/stra v%p, %u;\n", var, ix); clr_word(ix); return 0; } /* Calculate the character select for the word. */ int mux_word = allocate_word(); draw_eval_expr_into_integer(part, mux_word); /* Evaluate the r-value as a vector. */ struct vector_info rvec = draw_eval_expr_wid(rval, 8, STUFF_OK_XZ); assert(rvec.wid == 8); fprintf(vvp_out, " %%putc/str/v v%p_0, %d, %u;\n", var, mux_word, rvec.base); clr_vector(rvec); clr_word(mux_word); return 0; }
static void emit_stmt_lval_name(ivl_scope_t scope, ivl_lval_t lval, ivl_signal_t sig) { ivl_expr_t array_idx = ivl_lval_idx(lval); emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); if (array_idx) { int msb, lsb; assert(ivl_signal_dimensions(sig)); fprintf(vlog_out, "["); /* For an array the LSB/MSB order is not important. They are * always accessed from base counting up. */ lsb = ivl_signal_array_base(sig); msb = lsb + ivl_signal_array_count(sig) - 1; emit_scaled_expr(scope, array_idx, msb, lsb); fprintf(vlog_out, "]"); } }
static ivl_type_t draw_lval_expr(ivl_lval_t lval) { ivl_lval_t lval_nest = ivl_lval_nest(lval); ivl_signal_t lval_sig = ivl_lval_sig(lval); ivl_type_t sub_type; if (lval_nest) { sub_type = draw_lval_expr(lval_nest); } else { assert(lval_sig); sub_type = ivl_signal_net_type(lval_sig); assert(ivl_type_base(sub_type) == IVL_VT_CLASS); fprintf(vvp_out, " %%load/obj v%p_0;\n", lval_sig); } assert(ivl_type_base(sub_type) == IVL_VT_CLASS); if (ivl_lval_idx(lval)) { fprintf(vvp_out, " ; XXXX Don't know how to handle ivl_lval_idx values here.\n"); } fprintf(vvp_out, " %%prop/obj %d, 0; draw_lval_expr\n", ivl_lval_property_idx(lval)); fprintf(vvp_out, " %%pop/obj 1, 1;\n"); return ivl_type_prop_type(sub_type, ivl_lval_property_idx(lval)); }
static void set_vec_to_lval_slice(ivl_lval_t lval, unsigned bit, unsigned wid) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned long part_off = 0; /* Although Verilog doesn't support it, we'll handle here the case of an l-value part select of an array word if the address is constant. */ ivl_expr_t word_ix = ivl_lval_idx(lval); unsigned long use_word = 0; if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, IMM_WID, 0) && !number_is_unknown(part_off_ex)) { part_off = get_number_immediate(part_off_ex); part_off_ex = 0; } /* If the word index is a constant expression, then evaluate it to select the word, and pay no further heed to the expression itself. Out-of-bounds and undefined indices are converted to a canonical index of 'bx during elaboration, and we don't try to optimise that case. */ if (word_ix && number_is_immediate(word_ix, IMM_WID, 0) && !number_is_unknown(word_ix)) { use_word = get_number_immediate(word_ix); assert(use_word < ivl_signal_array_count(sig)); word_ix = 0; } if (ivl_lval_mux(lval)) part_off_ex = ivl_lval_mux(lval); if (part_off_ex && ivl_signal_dimensions(sig) == 0) { unsigned skip_set = transient_id++; /* There is a mux expression, so this must be a write to a bit-select l-val. Presumably, the x0 index register has been loaded wit the result of the evaluated part select base expression. */ assert(!word_ix); draw_eval_expr_into_integer(part_off_ex, 0); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n", sig, use_word, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); /* save_signal width of 0 CLEARS the signal from the lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); } else if (part_off_ex && ivl_signal_dimensions(sig) > 0) { /* Here we have a part select write into an array word. */ unsigned skip_set = transient_id++; if (word_ix) { draw_eval_expr_into_integer(word_ix, 3); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); } else { fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); } draw_eval_expr_into_integer(part_off_ex, 1); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); } else if ((part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) && ivl_signal_dimensions(sig) > 0) { /* Here we have a part select write into an array word. */ unsigned skip_set = transient_id++; if (word_ix) { draw_eval_expr_into_integer(word_ix, 3); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); } else { fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); } fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); if (word_ix) /* Only need this label if word_ix is set. */ fprintf(vvp_out, "t_%u ;\n", skip_set); } else if (part_off>0 || ivl_lval_width(lval)!=ivl_signal_width(sig)) { /* There is no mux expression, but a constant part offset. Load that into index x0 and generate a vector set instruction. */ assert(ivl_lval_width(lval) == wid); /* If the word index is a constant, then we can write directly to the word and save the index calculation. */ if (word_ix == 0) { fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", part_off); fprintf(vvp_out, " %%set/x0 v%p_%lu, %u, %u;\n", sig, use_word, bit, wid); } else { unsigned skip_set = transient_id++; unsigned index_reg = 3; draw_eval_expr_into_integer(word_ix, index_reg); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); } /* save_signal width of 0 CLEARS the signal from the lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); } else if (ivl_signal_dimensions(sig) > 0) { /* If the word index is a constant, then we can write directly to the word and save the index calculation. */ if (word_ix == 0) { fprintf(vvp_out, " %%ix/load 1, 0, 0;\n"); fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); } else { unsigned skip_set = transient_id++; unsigned index_reg = 3; draw_eval_expr_into_integer(word_ix, index_reg); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n"); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); } /* save_signal width of 0 CLEARS the signal from the lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); } else { fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n", sig, use_word, bit, wid); /* save_signal width of 0 CLEARS the signal from the lookaside. */ save_signal_lookaside(bit, sig, use_word, 0); } }
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; }
static int show_stmt_assign_vector(ivl_statement_t net) { ivl_lval_t lval; ivl_expr_t rval = ivl_stmt_rval(net); ivl_memory_t mem; /* Handle the special case that the expression is a real value. Evaluate the real expression, then convert the result to a vector. Then store that vector into the l-value. */ if (ivl_expr_value(rval) == IVL_VT_REAL) { int word = draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ unsigned wid = ivl_stmt_lwidth(net); struct vector_info vec; vec.base = allocate_vector(wid); vec.wid = wid; fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", vec.base, word, vec.wid); clr_word(word); set_vec_to_lval(net, vec); clr_vector(vec); return 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; 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)); /* Generate code to skip around the set if the index has X values. */ 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)); /* Generate code to skip around the set if the index has X values. */ 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) { set_to_memory(mem, idx, bitchar_to_idx(bits[cur_rbit])); cur_rbit += 1; } for (idx = bit_limit ; idx < ivl_lval_pins(lval) ; idx += 1) set_to_memory(mem, idx, 0); } else { idx = 0; while (idx < bit_limit) { unsigned cnt = 1; while (((idx + cnt) < bit_limit) && (bits[cur_rbit] == bits[cur_rbit+cnt])) cnt += 1; set_to_lvariable(lval, idx, bitchar_to_idx(bits[cur_rbit]), cnt); cur_rbit += cnt; idx += cnt; } if (bit_limit < ivl_lval_pins(lval)) { unsigned cnt = ivl_lval_pins(lval) - bit_limit; set_to_lvariable(lval, bit_limit, 0, cnt); } } 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); set_vec_to_lval(net, res); if (res.base > 3) clr_vector(res); } return 0; }
/* * This is a private function to generate %set code for the * statement. At this point, the r-value is evaluated and stored in * the res vector, I just need to generate the %set statements for the * l-values of the assignment. */ static void set_vec_to_lval(ivl_statement_t net, struct vector_info res) { ivl_lval_t lval; ivl_memory_t mem; unsigned wid = res.wid; unsigned lidx; unsigned cur_rbit = 0; 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) { unsigned bidx = res.base < 4 ? res.base : (res.base+cur_rbit); set_to_memory(mem, idx, bidx); cur_rbit += 1; } for (idx = bit_limit; idx < ivl_lval_pins(lval); idx += 1) set_to_memory(mem, idx, 0); } else { unsigned bidx = res.base < 4 ? res.base : (res.base+cur_rbit); set_to_lvariable(lval, 0, bidx, bit_limit); cur_rbit += bit_limit; if (bit_limit < ivl_lval_pins(lval)) { unsigned cnt = ivl_lval_pins(lval) - bit_limit; set_to_lvariable(lval, bit_limit, 0, cnt); } } if (skip_set_flag) { fprintf(vvp_out, "t_%u ;\n", skip_set); clear_expression_lookaside(); } } }
/* * 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; }
static int show_stmt_assign_sig_cobject(ivl_statement_t net) { int errors = 0; ivl_lval_t lval = ivl_stmt_lval(net, 0); ivl_expr_t rval = ivl_stmt_rval(net); ivl_signal_t sig= ivl_lval_sig(lval); unsigned lwid = ivl_lval_width(lval); int prop_idx = ivl_lval_property_idx(lval); if (prop_idx >= 0) { ivl_type_t sig_type = ivl_signal_net_type(sig); ivl_type_t prop_type = ivl_type_prop_type(sig_type, prop_idx); if (ivl_type_base(prop_type) == IVL_VT_BOOL) { assert(ivl_type_packed_dimensions(prop_type) == 1); assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); draw_eval_vec4(rval); if (ivl_expr_value(rval)!=IVL_VT_BOOL) fprintf(vvp_out, " %%cast2;\n"); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/v %d, %u; Store in bool property %s\n", prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx)); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { assert(ivl_type_packed_dimensions(prop_type) == 1); assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); draw_eval_vec4(rval); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/v %d, %u; Store in logic property %s\n", prop_idx, lwid, ivl_type_prop_name(sig_type, prop_idx)); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_REAL) { /* Calculate the real value into the real value stack. The %store/prop/r will pop the stack value. */ draw_eval_real(rval); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/r %d;\n", prop_idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_STRING) { /* Calculate the string value into the string value stack. The %store/prop/r will pop the stack value. */ draw_eval_string(rval); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%store/prop/str %d;\n", prop_idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_DARRAY) { int idx = 0; /* The property is a darray, and there is no mux expression to the assignment is of an entire array object. */ fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_CLASS) { int idx = 0; ivl_expr_t idx_expr; if ( (idx_expr = ivl_lval_idx(lval)) ) { idx = allocate_word(); } /* The property is a class object. */ fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); draw_eval_object(rval); if (idx_expr) draw_eval_expr_into_integer(idx_expr, idx); fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_CLASS\n", prop_idx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); if (idx_expr) clr_word(idx); } else { fprintf(vvp_out, " ; ERROR: ivl_type_base(prop_type) = %d\n", ivl_type_base(prop_type)); assert(0); } } else { /* There is no property select, so evaluate the r-value as an object and assign the entire object to the variable. */ errors += draw_eval_object(rval); if (ivl_signal_array_count(sig) > 1) { unsigned ix; ivl_expr_t aidx = ivl_lval_idx(lval); draw_eval_expr_into_integer(aidx, (ix = allocate_word())); fprintf(vvp_out, " %%store/obja v%p, %u;\n", sig, ix); clr_word(ix); } else { /* Not an array, so no index expression */ fprintf(vvp_out, " %%store/obj v%p_0;\n", sig); } } return errors; }
static int show_stmt_assign_sig_darray(ivl_statement_t net) { int errors = 0; ivl_lval_t lval = ivl_stmt_lval(net, 0); ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t part = ivl_lval_part_off(lval); ivl_signal_t var= ivl_lval_sig(lval); ivl_type_t var_type= ivl_signal_net_type(var); assert(ivl_type_base(var_type) == IVL_VT_DARRAY); ivl_type_t element_type = ivl_type_element(var_type); ivl_expr_t mux = ivl_lval_idx(lval); assert(ivl_stmt_lvals(net) == 1); assert(ivl_stmt_opcode(net) == 0); assert(part == 0); if (mux && (ivl_type_base(element_type)==IVL_VT_REAL)) { draw_eval_real(rval); /* The %set/dar expects the array index to be in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); } else if (mux && ivl_type_base(element_type)==IVL_VT_STRING) { /* Evaluate the rval into the top of the string stack. */ draw_eval_string(rval); /* The %store/dar/s expects the array index to me in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); } else if (mux) { draw_eval_vec4(rval); /* The %store/dar/vec4 expects the array index to be in index register 3. Calculate the index in place. */ draw_eval_expr_into_integer(mux, 3); fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var); } else if (ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN) { /* There is no l-value mux, but the r-value is an array pattern. This is a special case of an assignment to elements of the l-value. */ errors += show_stmt_assign_darray_pattern(net); } else { /* There is no l-value mux, so this must be an assignment to the array as a whole. Evaluate the "object", and store the evaluated result. */ errors += draw_eval_object(rval); fprintf(vvp_out, " %%store/obj v%p_0;\n", var); } return errors; }
/* * Store a vector from the vec4 stack to the statement l-values. This * all assumes that the value to be assigned is already on the top of * the stack. * * NOTE TO SELF: The %store/vec4 takes a width, but the %assign/vec4 * instructions do not, instead relying on the expression width. I * think that it the proper way to do it, so soon I should change the * %store/vec4 to not include the width operand. */ static void store_vec4_to_lval(ivl_statement_t net) { for (unsigned lidx = 0 ; lidx < ivl_stmt_lvals(net) ; lidx += 1) { ivl_lval_t lval = ivl_stmt_lval(net,lidx); ivl_signal_t lsig = ivl_lval_sig(lval); ivl_lval_t nest = ivl_lval_nest(lval); unsigned lwid = ivl_lval_width(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); /* This is non-nil if the l-val is the word of a memory, and nil otherwise. */ ivl_expr_t word_ex = ivl_lval_idx(lval); if (lidx+1 < ivl_stmt_lvals(net)) fprintf(vvp_out, " %%split/vec4 %u;\n", lwid); if (word_ex) { /* Handle index into an array */ int word_index = allocate_word(); int part_index = 0; /* Calculate the word address into word_index */ draw_eval_expr_into_integer(word_ex, word_index); /* If there is a part_offset, calculate it into part_index. */ if (part_off_ex) { int flag_index = allocate_flag(); part_index = allocate_word(); fprintf(vvp_out, " %%flag_mov %d, 4;\n", flag_index); draw_eval_expr_into_integer(part_off_ex, part_index); fprintf(vvp_out, " %%flag_or 4, %d;\n", flag_index); clr_flag(flag_index); } assert(lsig); fprintf(vvp_out, " %%store/vec4a v%p, %d, %d;\n", lsig, word_index, part_index); clr_word(word_index); if (part_index) clr_word(part_index); } else if (part_off_ex) { /* Dynamically calculated part offset */ int offset_index = allocate_word(); draw_eval_expr_into_integer(part_off_ex, offset_index); /* Note that flag4 is set by the eval above. */ assert(lsig); if (ivl_signal_type(lsig)==IVL_SIT_UWIRE) { fprintf(vvp_out, " %%force/vec4/off v%p_0, %u;\n", lsig, offset_index); } else { fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n", lsig, offset_index, lwid); } clr_word(offset_index); } else if (nest) { /* No offset expression, but the l-value is nested, which probably means that it is a class member. We will use a property assign function. */ assert(!lsig); ivl_type_t sub_type = draw_lval_expr(nest); assert(ivl_type_base(sub_type) == IVL_VT_CLASS); fprintf(vvp_out, " %%store/prop/v %u, %u;\n", ivl_lval_property_idx(lval), lwid); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else { /* No offset expression, so use simpler store function. */ assert(lsig); assert(lwid == ivl_signal_width(lsig)); fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", lsig, lwid); } } }
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, unsigned wid) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned long part_off = 0; /* Although Verilog doesn't support it, we'll handle here the case of an l-value part select of an array word if the address is constant. */ ivl_expr_t word_ix = ivl_lval_idx(lval); unsigned long use_word = 0; if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, IMM_WID, 0) && !number_is_unknown(part_off_ex)) { part_off = get_number_immediate(part_off_ex); part_off_ex = 0; } /* If the word index is a constant expression, then evaluate it to select the word, and pay no further heed to the expression itself. */ if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { assert(! number_is_unknown(word_ix)); use_word = get_number_immediate(word_ix); word_ix = 0; } if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0 && part_off==0 && wid==ivl_signal_width(sig)) { slice->type = SLICE_SIMPLE_VECTOR; slice->u_.simple_vector.use_word = use_word; fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word); } else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) { assert(use_word == 0); slice->type = SLICE_PART_SELECT_STATIC; slice->u_.part_select_static.part_off = part_off; fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word); fprintf(vvp_out, " %%pushi/vec4 %lu, 0, 32;\n", part_off); fprintf(vvp_out, " %%part/u %u;\n", wid); } else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) { assert(use_word == 0); assert(part_off == 0); slice->type = SLICE_PART_SELECT_DYNAMIC; slice->u_.part_select_dynamic.word_idx_reg = allocate_word(); slice->u_.part_select_dynamic.x_flag = allocate_flag(); fprintf(vvp_out, " %%load/vec4 v%p_%lu;\n", sig, use_word); draw_eval_vec4(part_off_ex); fprintf(vvp_out, " %%flag_mov %u, 4;\n", slice->u_.part_select_dynamic.x_flag); fprintf(vvp_out, " %%dup/vec4;\n"); fprintf(vvp_out, " %%ix/vec4 %u;\n", slice->u_.part_select_dynamic.word_idx_reg); fprintf(vvp_out, " %%part/u %u;\n", wid); } else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) { slice->type = SLICE_MEMORY_WORD_STATIC; slice->u_.memory_word_static.use_word = use_word; if (use_word < ivl_signal_array_count(sig)) { fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); fprintf(vvp_out, " %%load/vec4a v%p, 3;\n", sig); } else { assert(wid <= 32); fprintf(vvp_out, " %%pushi/vec4 4294967295, 4294967295, %u;\n", wid); } } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) { slice->type = SLICE_MEMORY_WORD_DYNAMIC; slice->u_.memory_word_dynamic.word_idx_reg = allocate_word(); slice->u_.memory_word_dynamic.x_flag = allocate_flag(); draw_eval_expr_into_integer(word_ix, slice->u_.memory_word_dynamic.word_idx_reg); fprintf(vvp_out, " %%flag_mov %d, 4;\n", slice->u_.memory_word_dynamic.x_flag); fprintf(vvp_out, " %%load/vec4a v%p, %d;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg); } else { assert(0); } }
static void get_vec_from_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, unsigned bit, unsigned wid) { ivl_signal_t sig = ivl_lval_sig(lval); ivl_expr_t part_off_ex = ivl_lval_part_off(lval); unsigned long part_off = 0; /* Although Verilog doesn't support it, we'll handle here the case of an l-value part select of an array word if the address is constant. */ ivl_expr_t word_ix = ivl_lval_idx(lval); unsigned long use_word = 0; if (part_off_ex == 0) { part_off = 0; } else if (number_is_immediate(part_off_ex, IMM_WID, 0) && !number_is_unknown(part_off_ex)) { part_off = get_number_immediate(part_off_ex); part_off_ex = 0; } /* If the word index is a constant expression, then evaluate it to select the word, and pay no further heed to the expression itself. */ if (word_ix && number_is_immediate(word_ix, IMM_WID, 0)) { assert(! number_is_unknown(word_ix)); use_word = get_number_immediate(word_ix); word_ix = 0; } if (ivl_lval_mux(lval)) part_off_ex = ivl_lval_mux(lval); if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0 && part_off==0 && wid==ivl_signal_width(sig)) { slice->type = SLICE_SIMPLE_VECTOR; slice->u_.simple_vector.use_word = use_word; fprintf(vvp_out, " %%load/v %u, v%p_%lu, %u;\n", bit, sig, use_word, wid); } else if (ivl_signal_dimensions(sig)==0 && part_off_ex==0 && word_ix==0) { assert(use_word == 0); slice->type = SLICE_PART_SELECT_STATIC; slice->u_.part_select_static.part_off = part_off; fprintf(vvp_out, " %%ix/load 1, %lu, 0;\n", part_off); fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid); } else if (ivl_signal_dimensions(sig)==0 && part_off_ex!=0 && word_ix==0) { unsigned skip_set = transient_id++; unsigned out_set = transient_id++; assert(use_word == 0); assert(part_off == 0); slice->type = SLICE_PART_SELECT_DYNAMIC; draw_eval_expr_into_integer(part_off_ex, 1); slice->u_.part_select_dynamic.word_idx_reg = allocate_word(); slice->u_.part_select_dynamic.x_flag = allocate_vector(1); fprintf(vvp_out, " %%mov %u, %u, 1;\n", slice->u_.part_select_dynamic.x_flag, 4); fprintf(vvp_out, " %%mov/wu %d, %d;\n", slice->u_.part_select_dynamic.word_idx_reg, 1); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%load/x1p %u, v%p_0, %u;\n", bit, sig, wid); fprintf(vvp_out, " %%jmp t_%u;\n", out_set); fprintf(vvp_out, "t_%u ;\n", skip_set); fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid); fprintf(vvp_out, "t_%u ;\n", out_set); } else if (ivl_signal_dimensions(sig) > 0 && word_ix == 0) { slice->type = SLICE_MEMORY_WORD_STATIC; slice->u_.memory_word_static.use_word = use_word; if (use_word < ivl_signal_array_count(sig)) { fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", use_word); fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", bit, sig, wid); } else { fprintf(vvp_out, " %%mov %u, 2, %u; OUT OF BOUNDS\n", bit, wid); } } else if (ivl_signal_dimensions(sig) > 0 && word_ix != 0) { unsigned skip_set = transient_id++; unsigned out_set = transient_id++; slice->type = SLICE_MEMORY_WORD_DYNAMIC; draw_eval_expr_into_integer(word_ix, 3); slice->u_.memory_word_dynamic.word_idx_reg = allocate_word(); slice->u_.memory_word_dynamic.x_flag = allocate_vector(1); fprintf(vvp_out, " %%mov/wu %d, 3;\n", slice->u_.memory_word_dynamic.word_idx_reg); fprintf(vvp_out, " %%mov %u, 4, 1;\n", slice->u_.memory_word_dynamic.x_flag); fprintf(vvp_out, " %%jmp/1 t_%u, 4;\n", skip_set); fprintf(vvp_out, " %%ix/load 1, 0, 0;\n"); fprintf(vvp_out, " %%load/av %u, v%p, %u;\n", bit, sig, wid); fprintf(vvp_out, " %%jmp t_%u;\n", out_set); fprintf(vvp_out, "t_%u ;\n", skip_set); fprintf(vvp_out, " %%mov %u, 2, %u;\n", bit, wid); fprintf(vvp_out, "t_%u ;\n", out_set); } else { assert(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; }