/* * 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 draw_binary_vec4_lrs(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); // Push the left expression onto the stack. draw_eval_vec4(le); // Calculate the shift amount into an index register. int use_index_reg = allocate_word(); assert(use_index_reg >= 0); draw_eval_expr_into_integer(re, use_index_reg); // Emit the actual shift instruction. This will pop the top of // the stack and replace it with the result of the shift. switch (ivl_expr_opcode(expr)) { case 'l': /* << */ fprintf(vvp_out, " %%shiftl %d;\n", use_index_reg); break; case 'r': /* >> */ fprintf(vvp_out, " %%shiftr %d;\n", use_index_reg); break; case 'R': /* >>> */ if (ivl_expr_signed(le)) fprintf(vvp_out, " %%shiftr/s %d;\n", use_index_reg); else fprintf(vvp_out, " %%shiftr %d;\n", use_index_reg); break; default: assert(0); break; } clr_word(use_index_reg); }
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; }
/* * 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 void draw_select_vec4(ivl_expr_t expr) { // This is the sub-expression to part-select. ivl_expr_t subexpr = ivl_expr_oper1(expr); // This is the base of the part select ivl_expr_t base = ivl_expr_oper2(expr); // This is the part select width unsigned wid = ivl_expr_width(expr); // Is the select base expression signed or unsigned? char sign_suff = ivl_expr_signed(base)? 's' : 'u'; // Special Case: If the sub-expression is a STRING, then this // is a select from that string. if (ivl_expr_value(subexpr)==IVL_VT_STRING) { assert(base); assert(wid==8); draw_eval_string(subexpr); int base_idx = allocate_word(); draw_eval_expr_into_integer(base, base_idx); fprintf(vvp_out, " %%substr/vec4 %d, %u;\n", base_idx, wid); fprintf(vvp_out, " %%pop/str 1;\n"); clr_word(base_idx); return; } if (ivl_expr_value(subexpr)==IVL_VT_DARRAY) { ivl_signal_t sig = ivl_expr_signal(subexpr); assert(sig); assert( (ivl_signal_data_type(sig)==IVL_VT_DARRAY) || (ivl_signal_data_type(sig)==IVL_VT_QUEUE) ); assert(base); draw_eval_expr_into_integer(base, 3); fprintf(vvp_out, " %%load/dar/vec4 v%p_0;\n", sig); return; } if (test_immediate_vec4_ok(base)) { unsigned long val0, valx; unsigned base_wid; make_immediate_vec4_words(base, &val0, &valx, &base_wid); assert(valx == 0); draw_eval_vec4(subexpr); fprintf(vvp_out, " %%parti/%c %u, %lu, %u;\n", sign_suff, wid, val0, base_wid); } else { draw_eval_vec4(subexpr); draw_eval_vec4(base); fprintf(vvp_out, " %%part/%c %u;\n", sign_suff, wid); } }
static int draw_realnum_real(ivl_expr_t exp) { int res = allocate_word(); double value = ivl_expr_dvalue(exp); double fract; int expo, vexp; unsigned long mant; int sign = 0; if (value < 0) { sign = 0x4000; value *= -1; } fract = frexp(value, &expo); fract = ldexp(fract, 31); mant = fract; expo -= 31; vexp = expo + 0x1000; assert(vexp >= 0); assert(vexp < 0x2000); vexp += sign; fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%f\n", res, mant, vexp, ivl_expr_dvalue(exp)); /* Capture the residual bits, if there are any. Note that an IEEE754 mantissa has 52 bits, 31 of which were accounted for already. */ fract -= floor(fract); fract = ldexp(fract, 22); mant = fract; expo -= 22; vexp = expo + 0x1000; assert(vexp >= 0); assert(vexp < 0x2000); vexp += sign; if (mant != 0) { int tmp_word = allocate_word(); fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%f\n", tmp_word, mant, vexp, ivl_expr_dvalue(exp)); fprintf(vvp_out, " %%add/wr %d, %d;\n", res, tmp_word); clr_word(tmp_word); } return res; }
static void string_ex_substr(ivl_expr_t expr) { ivl_expr_t arg; unsigned arg1; unsigned arg2; assert(ivl_expr_parms(expr) == 3); arg = ivl_expr_parm(expr,0); draw_eval_string(arg); /* Evaluate the arguments... */ arg = ivl_expr_parm(expr, 1); arg1 = allocate_word(); draw_eval_expr_into_integer(arg, arg1); arg = ivl_expr_parm(expr, 2); arg2 = allocate_word(); draw_eval_expr_into_integer(arg, arg2); fprintf(vvp_out, " %%substr %u, %u;\n", arg1, arg2); clr_word(arg1); clr_word(arg2); }
static int eval_darray_new(ivl_expr_t ex) { unsigned size_reg = allocate_word(); ivl_expr_t size_expr = ivl_expr_oper1(ex); draw_eval_expr_into_integer(size_expr, size_reg); clr_word(size_reg); // The new function has a net_type that contains the details // of the type. ivl_type_t net_type = ivl_expr_net_type(ex); assert(net_type); ivl_type_t element_type = ivl_type_element(net_type); assert(element_type); switch (ivl_type_base(element_type)) { case IVL_VT_REAL: // REAL objects are not packable. assert(ivl_type_packed_dimensions(element_type) == 0); fprintf(vvp_out, " %%new/darray %u, \"r\";\n", size_reg); break; case IVL_VT_STRING: // STRING objects are not packable. assert(ivl_type_packed_dimensions(element_type) == 0); fprintf(vvp_out, " %%new/darray %u, \"S\";\n", size_reg); break; case IVL_VT_BOOL: // bool objects are vectorable, but for now only support // a single dimensions. assert(ivl_type_packed_dimensions(element_type) == 1); int msb = ivl_type_packed_msb(element_type, 0); int lsb = ivl_type_packed_lsb(element_type, 0); int wid = msb>=lsb? msb - lsb : lsb - msb; wid += 1; fprintf(vvp_out, " %%new/darray %u, \"sb%d\";\n", size_reg, wid); break; default: assert(0); break; } return 0; }
static int draw_binary_real(ivl_expr_t exp) { int l, r = -1; l = draw_eval_real(ivl_expr_oper1(exp)); r = draw_eval_real(ivl_expr_oper2(exp)); switch (ivl_expr_opcode(exp)) { case '+': fprintf(vvp_out, " %%add/wr %d, %d;\n", l, r); break; case '-': fprintf(vvp_out, " %%sub/wr %d, %d;\n", l, r); break; case '*': fprintf(vvp_out, " %%mul/wr %d, %d;\n", l, r); break; case '/': fprintf(vvp_out, " %%div/wr %d, %d;\n", l, r); break; case '%': { struct vector_info res = draw_eval_expr(exp, STUFF_OK_XZ); l = allocate_word(); fprintf(vvp_out, " %%ix/get %d, %u, %u;\n", l, res.base, res.wid); fprintf(vvp_out, " %%cvt/ri %d, %d;\n", l, l); clr_vector(res); } break; default: fprintf(stderr, "XXXX draw_binary_real(%c)\n", ivl_expr_opcode(exp)); assert(0); } if (r >= 0) clr_word(r); return l; }
static void draw_signal_vec4(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); /* Handle the simple case, a signal expression that is a simple vector, no array dimensions. */ if (ivl_signal_dimensions(sig) == 0) { fprintf(vvp_out, " %%load/vec4 v%p_0;\n", sig); return; } /* calculate the array index... */ int addr_index = allocate_word(); draw_eval_expr_into_integer(ivl_expr_oper1(expr), addr_index); fprintf(vvp_out, " %%load/vec4a v%p, %d;\n", sig, addr_index); clr_word(addr_index); }
static int show_stmt_assign_real(ivl_statement_t net) { int res; ivl_lval_t lval; ivl_variable_t var; res = draw_eval_real(ivl_stmt_rval(net)); clr_word(res); assert(ivl_stmt_lvals(net) == 1); lval = ivl_stmt_lval(net, 0); var = ivl_lval_var(lval); assert(var != 0); fprintf(vvp_out, " %%set/wr W_%s, %d;\n", vvp_word_label(var), res); return 0; }
static int eval_object_signal(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); /* Simple case: This is a simple variable. Generate a load statement to load the string into the stack. */ if (ivl_signal_dimensions(sig) == 0) { fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); return 0; } /* There is a word select expression, so load the index into a register and load from the array. */ ivl_expr_t word_ex = ivl_expr_oper1(expr); int word_ix = allocate_word(); draw_eval_expr_into_integer(word_ex, word_ix); fprintf(vvp_out, " %%load/obja v%p, %d;\n", sig, word_ix); clr_word(word_ix); return 0; }
static int eval_object_property(ivl_expr_t expr) { ivl_signal_t sig = ivl_expr_signal(expr); unsigned pidx = ivl_expr_property_idx(expr); int idx = 0; ivl_expr_t idx_expr = 0; /* If there is an array index expression, then this is an array'ed property, and we need to calculate the index for the expression. */ if ( (idx_expr = ivl_expr_oper1(expr)) ) { idx = allocate_word(); draw_eval_expr_into_integer(idx_expr, idx); } fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%prop/obj %u, %d; eval_object_property\n", pidx, idx); fprintf(vvp_out, " %%pop/obj 1, 1;\n"); if (idx != 0) clr_word(idx); return 0; }
static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, unsigned wid) { //unsigned skip_set = transient_id++; ivl_signal_t sig = ivl_lval_sig(lval); int part_off_idx; /* If the slice of the l-value is a BOOL variable, then cast the data to a BOOL vector so that the stores can be valid. */ if (ivl_signal_data_type(sig) == IVL_VT_BOOL) { fprintf(vvp_out, " %%cast2;\n"); } switch (slice->type) { default: fprintf(vvp_out, " ; XXXX slice->type=%d\n", slice->type); assert(0); break; case SLICE_SIMPLE_VECTOR: fprintf(vvp_out, " %%store/vec4 v%p_%lu, 0, %u;\n", sig, slice->u_.simple_vector.use_word, wid); break; case SLICE_PART_SELECT_STATIC: part_off_idx = allocate_word(); fprintf(vvp_out, " %%ix/load %d, %lu, 0;\n", part_off_idx, slice->u_.part_select_static.part_off); fprintf(vvp_out, " %%flag_set/imm 4, 0;\n"); fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n", sig, part_off_idx, wid); clr_word(part_off_idx); break; case SLICE_PART_SELECT_DYNAMIC: fprintf(vvp_out, " %%flag_mov 4, %u;\n", slice->u_.part_select_dynamic.x_flag); fprintf(vvp_out, " %%store/vec4 v%p_0, %d, %u;\n", sig, slice->u_.part_select_dynamic.word_idx_reg, wid); clr_word(slice->u_.part_select_dynamic.word_idx_reg); clr_flag(slice->u_.part_select_dynamic.x_flag); break; case SLICE_MEMORY_WORD_STATIC: if (slice->u_.memory_word_static.use_word < ivl_signal_array_count(sig)) { int word_idx = allocate_word(); fprintf(vvp_out," %%flag_set/imm 4, 0;\n"); fprintf(vvp_out," %%ix/load %d, %lu, 0;\n", word_idx, slice->u_.memory_word_static.use_word); fprintf(vvp_out," %%store/vec4a v%p, %d, 0;\n", sig, word_idx); clr_word(word_idx); } else { fprintf(vvp_out," ; Skip this slice write to v%p [%lu]\n", sig, slice->u_.memory_word_static.use_word); } break; case SLICE_MEMORY_WORD_DYNAMIC: fprintf(vvp_out, " %%flag_mov 4, %d;\n", slice->u_.memory_word_dynamic.x_flag); fprintf(vvp_out, " %%store/vec4a v%p, %d, 0;\n", sig, slice->u_.memory_word_dynamic.word_idx_reg); clr_word(slice->u_.memory_word_dynamic.word_idx_reg); clr_flag(slice->u_.memory_word_dynamic.x_flag); break; } }
static int show_stmt_assign_vector(ivl_statement_t net) { ivl_expr_t rval = ivl_stmt_rval(net); //struct vector_info res; //struct vector_info lres = {0, 0}; struct vec_slice_info*slices = 0; int idx_reg; /* If this is a compressed assignment, then get the contents of the l-value. We need these values as part of the r-value calculation. */ if (ivl_stmt_opcode(net) != 0) { slices = calloc(ivl_stmt_lvals(net), sizeof(struct vec_slice_info)); get_vec_from_lval(net, slices); } /* 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) { draw_eval_real(rval); /* This is the accumulated with of the l-value of the assignment. */ unsigned wid = ivl_stmt_lwidth(net); /* Convert a calculated real value to a vec4 value of the given width. We need to include the width of the result because real values to not have any inherit width. The real value will be popped, and a vec4 value pushed. */ fprintf(vvp_out, " %%cvt/vr %u;\n", wid); } else if (ivl_expr_value(rval) == IVL_VT_STRING) { /* Special case: vector to string casting */ ivl_lval_t lval = ivl_stmt_lval(net, 0); fprintf(vvp_out, " %%vpi_call %u %u \"$ivl_string_method$to_vec\", v%p_0, v%p_0 {0 0 0};\n", ivl_file_table_index(ivl_stmt_file(net)), ivl_stmt_lineno(net), ivl_expr_signal(rval), ivl_lval_sig(lval)); return 0; } else { unsigned wid = ivl_stmt_lwidth(net); draw_eval_vec4(rval); resize_vec4_wid(rval, wid); } switch (ivl_stmt_opcode(net)) { case 0: store_vec4_to_lval(net); break; case '+': fprintf(vvp_out, " %%add;\n"); put_vec_to_lval(net, slices); break; case '-': fprintf(vvp_out, " %%sub;\n"); put_vec_to_lval(net, slices); break; case '*': fprintf(vvp_out, " %%mul;\n"); put_vec_to_lval(net, slices); break; case '/': fprintf(vvp_out, " %%div%s;\n", ivl_expr_signed(rval)? "/s":""); put_vec_to_lval(net, slices); break; case '%': fprintf(vvp_out, " %%mod%s;\n", ivl_expr_signed(rval)? "/s":""); put_vec_to_lval(net, slices); break; case '&': fprintf(vvp_out, " %%and;\n"); put_vec_to_lval(net, slices); break; case '|': fprintf(vvp_out, " %%or;\n"); put_vec_to_lval(net, slices); break; case '^': fprintf(vvp_out, " %%xor;\n"); put_vec_to_lval(net, slices); break; case 'l': /* lval <<= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftl %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; case 'r': /* lval >>= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftr %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; case 'R': /* lval >>>= expr */ idx_reg = allocate_word(); fprintf(vvp_out, " %%ix/vec4 %d;\n", idx_reg); fprintf(vvp_out, " %%shiftr/s %d;\n", idx_reg); clr_word(idx_reg); put_vec_to_lval(net, slices); break; default: fprintf(vvp_out, "; UNSUPPORTED ASSIGNMENT OPCODE: %c\n", ivl_stmt_opcode(net)); assert(0); break; } if (slices) free(slices); return 0; }
static void draw_vpi_taskfunc_args(const char*call_string, ivl_statement_t tnet, ivl_expr_t fnet) { unsigned idx; unsigned parm_count = tnet ? ivl_stmt_parm_count(tnet) : ivl_expr_parms(fnet); struct args_info *args = calloc(parm_count, sizeof(struct args_info)); char buffer[4096]; ivl_parameter_t par; /* Figure out how many expressions are going to be evaluated for this task call. I won't need to evaluate expressions for items that are VPI objects directly. */ for (idx = 0 ; idx < parm_count ; idx += 1) { ivl_expr_t expr = tnet ? ivl_stmt_parm(tnet, idx) : ivl_expr_parm(fnet, idx); switch (ivl_expr_type(expr)) { /* These expression types can be handled directly, with VPI handles of their own. Therefore, skip them in the process of evaluating expressions. */ case IVL_EX_NONE: args[idx].text = strdup("\" \""); continue; case IVL_EX_ARRAY: snprintf(buffer, sizeof buffer, "v%p", ivl_expr_signal(expr)); args[idx].text = strdup(buffer); continue; case IVL_EX_NUMBER: { if (( par = ivl_expr_parameter(expr) )) { snprintf(buffer, sizeof buffer, "P_%p", par); } else { unsigned bit, wid = ivl_expr_width(expr); const char*bits = ivl_expr_bits(expr); char*dp; snprintf(buffer, sizeof buffer, "%u'%sb", wid, ivl_expr_signed(expr)? "s" : ""); dp = buffer + strlen(buffer); for (bit = wid ; bit > 0 ; bit -= 1) *dp++ = bits[bit-1]; *dp++ = 0; assert(dp >= buffer); assert((unsigned)(dp - buffer) <= sizeof buffer); } args[idx].text = strdup(buffer); continue; } case IVL_EX_STRING: if (( par = ivl_expr_parameter(expr) )) { snprintf(buffer, sizeof buffer, "P_%p", par); } else { snprintf(buffer, sizeof buffer, "\"%s\"", ivl_expr_string(expr)); } args[idx].text = strdup(buffer); continue; case IVL_EX_REALNUM: if (( par = ivl_expr_parameter(expr) )) { snprintf(buffer, sizeof buffer, "P_%p", par); args[idx].text = strdup(buffer); continue; } break; case IVL_EX_ENUMTYPE: snprintf(buffer, sizeof buffer, "enum%p", ivl_expr_enumtype(expr)); args[idx].text = strdup(buffer); continue; case IVL_EX_EVENT: snprintf(buffer, sizeof buffer, "E_%p", ivl_expr_event(expr)); args[idx].text = strdup(buffer); continue; case IVL_EX_SCOPE: snprintf(buffer, sizeof buffer, "S_%p", ivl_expr_scope(expr)); args[idx].text = strdup(buffer); continue; case IVL_EX_SFUNC: if (is_magic_sfunc(ivl_expr_name(expr))) { snprintf(buffer, sizeof buffer, "%s", ivl_expr_name(expr)); args[idx].text = strdup(buffer); continue; } break; case IVL_EX_SIGNAL: case IVL_EX_SELECT: if (get_vpi_taskfunc_signal_arg(&args[idx], expr)) continue; else break; /* Everything else will need to be evaluated and passed as a constant to the vpi task. */ default: break; } switch (ivl_expr_value(expr)) { case IVL_VT_LOGIC: case IVL_VT_BOOL: args[idx].vec_flag = 1; args[idx].vec = draw_eval_expr(expr, 0); snprintf(buffer, sizeof buffer, "T<%u,%u,%s>", args[idx].vec.base, args[idx].vec.wid, ivl_expr_signed(expr)? "s" : "u"); break; case IVL_VT_REAL: args[idx].vec_flag = 1; args[idx].vec.base = draw_eval_real(expr); args[idx].vec.wid = 0; snprintf(buffer, sizeof buffer, "W<%u,r>", args[idx].vec.base); break; case IVL_VT_STRING: /* STRING expressions not supported yet. */ default: assert(0); } args[idx].text = strdup(buffer); } fprintf(vvp_out, "%s", call_string); for (idx = 0 ; idx < parm_count ; idx += 1) { struct args_info*ptr; fprintf(vvp_out, ", %s", args[idx].text); free(args[idx].text); /* Clear the nested children vectors. */ for (ptr = &args[idx]; ptr != NULL; ptr = ptr->child) { if (ptr->vec_flag) { if (ptr->vec.wid > 0) clr_vector(ptr->vec); else clr_word(ptr->vec.base); } } /* Free the nested children. */ ptr = args[idx].child; while (ptr != NULL) { struct args_info*tptr = ptr; ptr = ptr->child; free(tptr); } } free(args); fprintf(vvp_out, ";\n"); }
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_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; }
static void draw_binary_vec4_compare_class(ivl_expr_t expr) { ivl_expr_t le = ivl_expr_oper1(expr); ivl_expr_t re = ivl_expr_oper2(expr); if (ivl_expr_type(le) == IVL_EX_NULL) { ivl_expr_t tmp = le; le = re; re = tmp; } /* Special case: If both operands are null, then the expression has a constant value. */ if (ivl_expr_type(le)==IVL_EX_NULL && ivl_expr_type(re)==IVL_EX_NULL) { switch (ivl_expr_opcode(expr)) { case 'e': /* == */ fprintf(vvp_out, " %%pushi/vec4 1, 0, 1;\n"); break; case 'n': /* != */ fprintf(vvp_out, " %%pushi/vec4 0, 0, 1;\n"); break; default: assert(0); break; } return; } /* A signal/variable is compared to null. Implement this with the %test_nul statement, which peeks at the variable contents directly. */ if (ivl_expr_type(re)==IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_SIGNAL) { ivl_signal_t sig= ivl_expr_signal(le); if (ivl_signal_dimensions(sig) == 0) { fprintf(vvp_out, " %%test_nul v%p_0;\n", sig); } else { ivl_expr_t word_ex = ivl_expr_oper1(le); int word_ix = allocate_word(); draw_eval_expr_into_integer(word_ex, word_ix); fprintf(vvp_out, " %%test_nul/a v%p, %d;\n", sig, word_ix); clr_word(word_ix); } if (ivl_expr_opcode(expr) == 'n') fprintf(vvp_out, " %%flag_inv 4;\n"); fprintf(vvp_out, " %%flag_get/vec4 4;\n"); return; } if (ivl_expr_type(re)==IVL_EX_NULL && ivl_expr_type(le)==IVL_EX_PROPERTY) { ivl_signal_t sig = ivl_expr_signal(le); unsigned pidx = ivl_expr_property_idx(le); ivl_expr_t idx_expr = ivl_expr_oper1(le); int idx = 0; /* If the property has an array index, then evaluate it into an index register. */ if ( idx_expr ) { idx = allocate_word(); draw_eval_expr_into_integer(idx_expr, idx); } fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%test_nul/prop %u, %d;\n", pidx, idx); fprintf(vvp_out, " %%pop/obj 1, 0;\n"); if (ivl_expr_opcode(expr) == 'n') fprintf(vvp_out, " %%flag_inv 4;\n"); fprintf(vvp_out, " %%flag_get/vec4 4;\n"); if (idx != 0) clr_word(idx); return; } fprintf(stderr, "SORRY: Compare class handles not implemented\n"); fprintf(vvp_out, " ; XXXX compare class handles. re-type=%d, le-type=%d\n", ivl_expr_type(re), ivl_expr_type(le)); vvp_errors += 1; }
static int show_stmt_case_r(ivl_statement_t net, ivl_scope_t sscope) { ivl_expr_t exp = ivl_stmt_cond_expr(net); int cond = draw_eval_real(exp); 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); int cvec; if (cex == 0) { default_case = idx; continue; } cvec = draw_eval_real(cex); fprintf(vvp_out, " %%cmp/wr %d, %d;\n", cond, cvec); fprintf(vvp_out, " %%jmp/1 T_%d.%d, 4;\n", thread_count, local_base+idx); /* Done with the guard expression value. */ clr_word(cvec); } /* Done with the case expression. */ clr_word(cond); /* Emit code for the case default. The above jump table will fall through to this statement. */ 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); return 0; }
static void draw_vpi_taskfunc_args(const char*call_string, ivl_statement_t tnet, ivl_expr_t fnet) { unsigned idx; unsigned parm_count = tnet ? ivl_stmt_parm_count(tnet) : ivl_expr_parms(fnet); struct vector_info *vec = 0x0; unsigned int vecs= 0; unsigned int veci= 0; ivl_parameter_t par; /* Figure out how many expressions are going to be evaluated for this task call. I won't need to evaluate expressions for items that are VPI objects directly. */ for (idx = 0 ; idx < parm_count ; idx += 1) { ivl_expr_t expr = tnet ? ivl_stmt_parm(tnet, idx) : ivl_expr_parm(fnet, idx); switch (ivl_expr_type(expr)) { /* These expression types can be handled directly, with VPI handles of their own. Therefore, skip them in the process of evaluating expressions. */ case IVL_EX_NONE: case IVL_EX_NUMBER: case IVL_EX_STRING: case IVL_EX_EVENT: case IVL_EX_SCOPE: case IVL_EX_VARIABLE: continue; case IVL_EX_SFUNC: if (is_magic_sfunc(ivl_expr_name(expr))) continue; break; case IVL_EX_SIGNAL: /* If the signal node is narrower then the signal itself, then this is a part select so I'm going to need to evaluate the expression. Also, if the signedness of the expression is different from the signedness of the signal. This could be caused by a $signed or $unsigned system function. If I don't need to do any evaluating, then skip it as I'll be passing the handle to the signal itself. */ if (ivl_expr_width(expr) != ivl_signal_pins(ivl_expr_signal(expr))) { break; } else if (ivl_expr_signed(expr) != ivl_signal_signed(ivl_expr_signal(expr))) { break; } else { continue; } case IVL_EX_MEMORY: if (!ivl_expr_oper1(expr)) { continue; } /* Everything else will need to be evaluated and passed as a constant to the vpi task. */ default: break; } vec = (struct vector_info *) realloc(vec, (vecs+1)*sizeof(struct vector_info)); switch (ivl_expr_value(expr)) { case IVL_VT_VECTOR: vec[vecs] = draw_eval_expr(expr, 0); break; case IVL_VT_REAL: vec[vecs].base = draw_eval_real(expr); vec[vecs].wid = 0; break; default: assert(0); } vecs++; } fprintf(vvp_out, "%s", call_string); for (idx = 0 ; idx < parm_count ; idx += 1) { ivl_expr_t expr = tnet ? ivl_stmt_parm(tnet, idx) : ivl_expr_parm(fnet, idx); switch (ivl_expr_type(expr)) { case IVL_EX_NONE: fprintf(vvp_out, ", \" \""); continue; case IVL_EX_NUMBER: { unsigned bit, wid = ivl_expr_width(expr); const char*bits = ivl_expr_bits(expr); fprintf(vvp_out, ", %u'%sb", wid, ivl_expr_signed(expr)? "s" : ""); for (bit = wid ; bit > 0 ; bit -= 1) fputc(bits[bit-1], vvp_out); continue; } case IVL_EX_SIGNAL: /* If this is a part select, then the value was calculated above. Otherwise, just pass the signal. */ if (ivl_expr_width(expr) != ivl_signal_pins(ivl_expr_signal(expr))) { break; } else if (ivl_expr_signed(expr) != ivl_signal_signed(ivl_expr_signal(expr))) { break; } else { fprintf(vvp_out, ", V_%s", vvp_signal_label(ivl_expr_signal(expr))); continue; } case IVL_EX_VARIABLE: { ivl_variable_t var = ivl_expr_variable(expr); fprintf(vvp_out, ", W_%s", vvp_word_label(var)); continue; } case IVL_EX_STRING: if (( par = ivl_expr_parameter(expr) )) { fprintf(vvp_out, ", P_%p", par); } else { fprintf(vvp_out, ", \"%s\"", ivl_expr_string(expr)); } continue; case IVL_EX_EVENT: fprintf(vvp_out, ", E_%p", ivl_expr_event(expr)); continue; case IVL_EX_SCOPE: fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr)); continue; case IVL_EX_SFUNC: if (is_magic_sfunc(ivl_expr_name(expr))) { fprintf(vvp_out, ", %s", ivl_expr_name(expr)); continue; } break; case IVL_EX_MEMORY: if (!ivl_expr_oper1(expr)) { fprintf(vvp_out, ", M_%s", vvp_memory_label(ivl_expr_memory(expr))); continue; } break; default: break; } assert(veci < vecs); switch (ivl_expr_value(expr)) { case IVL_VT_VECTOR: fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base, vec[veci].wid, ivl_expr_signed(expr)? "s" : "u"); break; case IVL_VT_REAL: fprintf(vvp_out, ", W<%u,r>", vec[veci].base); break; default: assert(0); } veci++; } assert(veci == vecs); if (vecs) { for (idx = 0; idx < vecs; idx++) { if (vec[idx].wid > 0) clr_vector(vec[idx]); else if (vec[idx].wid == 0) clr_word(vec[idx].base); } free(vec); } fprintf(vvp_out, ";\n"); }
static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice, unsigned bit, unsigned wid) { unsigned skip_set = transient_id++; struct vector_info tmp; ivl_signal_t sig = ivl_lval_sig(lval); /* If the slice of the l-value is a BOOL variable, then cast the data to a BOOL vector so that the stores can be valid. */ if (ivl_signal_data_type(sig) == IVL_VT_BOOL) { fprintf(vvp_out, " %%cast2 %u, %u, %u;\n", bit, bit, wid); } switch (slice->type) { default: assert(0); break; case SLICE_SIMPLE_VECTOR: fprintf(vvp_out, " %%set/v v%p_%lu, %u, %u;\n", sig, slice->u_.simple_vector.use_word, bit, wid); break; case SLICE_PART_SELECT_STATIC: fprintf(vvp_out, " %%ix/load 0, %lu, 0;\n", slice->u_.part_select_static.part_off); fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid); break; case SLICE_PART_SELECT_DYNAMIC: fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set, slice->u_.part_select_dynamic.x_flag); fprintf(vvp_out, " %%mov/wu 0, %d;\n", slice->u_.part_select_dynamic.word_idx_reg); fprintf(vvp_out, " %%set/x0 v%p_0, %u, %u;\n", sig, bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); break; case SLICE_MEMORY_WORD_STATIC: if (slice->u_.simple_vector.use_word >= ivl_signal_array_count(sig)) break; fprintf(vvp_out, " %%ix/load 3, %lu, 0;\n", slice->u_.simple_vector.use_word); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", sig, bit, wid); break; case SLICE_MEMORY_WORD_DYNAMIC: fprintf(vvp_out, " %%jmp/1 t_%u, %u;\n", skip_set, slice->u_.memory_word_dynamic.x_flag); fprintf(vvp_out, " %%mov/wu 3, %d;\n", slice->u_.memory_word_dynamic.word_idx_reg); fprintf(vvp_out, " %%set/av v%p, %u, %u;\n", ivl_lval_sig(lval), bit, wid); fprintf(vvp_out, "t_%u ;\n", skip_set); tmp.base = slice->u_.memory_word_dynamic.x_flag; tmp.wid = 1; clr_vector(tmp); clr_word(slice->u_.memory_word_dynamic.word_idx_reg); break; } }
static int eval_darray_new(ivl_expr_t ex) { int errors = 0; unsigned size_reg = allocate_word(); ivl_expr_t size_expr = ivl_expr_oper1(ex); ivl_expr_t init_expr = ivl_expr_oper2(ex); draw_eval_expr_into_integer(size_expr, size_reg); // The new function has a net_type that contains the details // of the type. ivl_type_t net_type = ivl_expr_net_type(ex); assert(net_type); ivl_type_t element_type = ivl_type_element(net_type); assert(element_type); switch (ivl_type_base(element_type)) { int msb, lsb, wid; case IVL_VT_REAL: // REAL objects are not packable. assert(ivl_type_packed_dimensions(element_type) == 0); fprintf(vvp_out, " %%new/darray %u, \"r\";\n", size_reg); break; case IVL_VT_STRING: // STRING objects are not packable. assert(ivl_type_packed_dimensions(element_type) == 0); fprintf(vvp_out, " %%new/darray %u, \"S\";\n", size_reg); break; case IVL_VT_BOOL: // bool objects are vectorable, but for now only support // a single dimensions. assert(ivl_type_packed_dimensions(element_type) == 1); msb = ivl_type_packed_msb(element_type, 0); lsb = ivl_type_packed_lsb(element_type, 0); wid = msb>=lsb? msb - lsb : lsb - msb; wid += 1; fprintf(vvp_out, " %%new/darray %u, \"%sb%d\";\n", size_reg, ivl_type_signed(element_type) ? "s" : "", wid); break; case IVL_VT_LOGIC: // logic objects are vectorable, but for now only support // a single dimensions. assert(ivl_type_packed_dimensions(element_type) == 1); msb = ivl_type_packed_msb(element_type, 0); lsb = ivl_type_packed_lsb(element_type, 0); wid = msb>=lsb? msb - lsb : lsb - msb; wid += 1; fprintf(vvp_out, " %%new/darray %u, \"%sv%d\";\n", size_reg, ivl_type_signed(element_type) ? "s" : "", wid); break; default: assert(0); break; } clr_word(size_reg); if (init_expr && ivl_expr_type(init_expr)==IVL_EX_ARRAY_PATTERN) { unsigned idx; switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: case IVL_VT_LOGIC: for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) { draw_eval_vec4(ivl_expr_parm(init_expr,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n"); fprintf(vvp_out, " %%pop/vec4 1;\n"); } break; case IVL_VT_REAL: for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) { draw_eval_real(ivl_expr_parm(init_expr,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/real 3;\n"); fprintf(vvp_out, " %%pop/real 1;\n"); } break; case IVL_VT_STRING: for (idx = 0 ; idx < ivl_expr_parms(init_expr) ; idx += 1) { draw_eval_string(ivl_expr_parm(init_expr,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/str 3;\n"); fprintf(vvp_out, " %%pop/str 1;\n"); } break; default: fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n"); errors += 1; break; } } else if (init_expr && (ivl_expr_value(init_expr) == IVL_VT_DARRAY)) { ivl_signal_t sig = ivl_expr_signal(init_expr); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); fprintf(vvp_out, " %%scopy;\n"); } else if (init_expr && number_is_immediate(size_expr,32,0)) { /* In this case, there is an init expression, the expression is NOT an array_pattern, and the size expression used to calculate the size of the array is a constant. Generate an unrolled set of assignments. */ long idx; long cnt = get_number_immediate(size_expr); unsigned wid; switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: case IVL_VT_LOGIC: wid = width_of_packed_type(element_type); for (idx = 0 ; idx < cnt ; idx += 1) { draw_eval_vec4(init_expr); fprintf(vvp_out, " %%parti/%c %u, %ld, 6;\n", ivl_expr_signed(init_expr) ? 's' : 'u', wid, idx * wid); fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", cnt - idx - 1); fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n"); fprintf(vvp_out, " %%pop/vec4 1;\n"); } break; case IVL_VT_REAL: draw_eval_real(init_expr); for (idx = 0 ; idx < cnt ; idx += 1) { fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/real 3;\n"); } fprintf(vvp_out, " %%pop/real 1;\n"); break; case IVL_VT_STRING: draw_eval_string(init_expr); for (idx = 0 ; idx < cnt ; idx += 1) { fprintf(vvp_out, " %%ix/load 3, %ld, 0;\n", idx); fprintf(vvp_out, " %%set/dar/obj/str 3;\n"); } fprintf(vvp_out, " %%pop/str 1;\n"); break; default: fprintf(vvp_out, "; ERROR: Sorry, this type not supported here.\n"); errors += 1; break; } } else if (init_expr) { fprintf(vvp_out, "; ERROR: Sorry, I don't know how to work with this size expr.\n"); errors += 1; } 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); } } }