static int draw_condition_fallback(ivl_expr_t expr) { int use_flag = allocate_flag(); /* Evaluate the condition expression, including optionally reducing it to a single bit. Put the result into a flag bit for use by all the tests. */ draw_eval_vec4(expr); if (ivl_expr_width(expr) > 1) fprintf(vvp_out, " %%or/r;\n"); fprintf(vvp_out, " %%flag_set/vec4 %d;\n", use_flag); return use_flag; }
static void draw_ternary_vec4(ivl_expr_t expr) { ivl_expr_t cond = ivl_expr_oper1(expr); ivl_expr_t true_ex = ivl_expr_oper2(expr); ivl_expr_t false_ex = ivl_expr_oper3(expr); unsigned lab_true = local_count++; unsigned lab_out = local_count++; int use_flag = draw_eval_condition(cond); /* The condition flag is used after possibly other statements, so we need to put it into a non-common place. Allocate a safe flag bit and move the condition to the flag position. */ if (use_flag < 8) { int tmp_flag = allocate_flag(); assert(tmp_flag >= 8); fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp_flag, use_flag); use_flag = tmp_flag; } fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_true, use_flag); /* If the condition is true or xz (not false), we need the true expression. If the condition is true, then we ONLY need the true expression. */ draw_eval_vec4(true_ex); fprintf(vvp_out, " %%jmp/1 T_%u.%u, %d;\n", thread_count, lab_out, use_flag); fprintf(vvp_out, "T_%u.%u ; End of true expr.\n", thread_count, lab_true); /* If the condition is false or xz (not true), we need the false expression. If the condition is false, then we ONLY need the false expression. */ draw_eval_vec4(false_ex); fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_out, use_flag); fprintf(vvp_out, " ; End of false expr.\n"); /* Here, the condition is not true or false, it is xz. Both the true and false expressions have been pushed onto the stack, we just need to blend the bits. */ fprintf(vvp_out, " %%blend;\n"); fprintf(vvp_out, "T_%u.%u;\n", thread_count, lab_out); clr_flag(use_flag); }
static int draw_condition_binary_lor(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); int lx = draw_eval_condition(le); if (lx < 8) { int tmp = allocate_flag(); fprintf(vvp_out, " %%flag_mov %d, %d;\n", tmp, lx); lx = tmp; } int rx = draw_eval_condition(re); fprintf(vvp_out, " %%flag_or %d, %d;\n", rx, lx); clr_flag(lx); return rx; }
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); } }
/* * 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); } } }