static void string_ex_concat(ivl_expr_t expr) { unsigned repeat; assert(ivl_expr_parms(expr) != 0); assert(ivl_expr_repeat(expr) != 0); /* Push the first string onto the stack, no matter what. */ draw_eval_string(ivl_expr_parm(expr,0)); for (repeat = 0 ; repeat < ivl_expr_repeat(expr) ; repeat += 1) { unsigned idx; for (idx = (repeat==0)? 1 : 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_expr_t sub = ivl_expr_parm(expr,idx); /* Special case: If operand is a string literal, then concat it using the %concati/str instruction. */ if (ivl_expr_type(sub) == IVL_EX_STRING) { fprintf(vvp_out, " %%concati/str \"%s\";\n", ivl_expr_string(sub)); continue; } draw_eval_string(sub); fprintf(vvp_out, " %%concat/str;\n"); } } }
static void draw_concat_vec4(ivl_expr_t expr) { /* Repeat the concatenation this many times to make a super-concatenation. */ unsigned repeat = ivl_expr_repeat(expr); /* This is the number of expressions that go into the concatenation. */ unsigned num_sube = ivl_expr_parms(expr); unsigned sub_idx; assert(num_sube > 0); /* Start with the most-significant bits. */ draw_eval_vec4(ivl_expr_parm(expr, 0)); for (sub_idx = 1 ; sub_idx < num_sube ; sub_idx += 1) { /* Concatenate progressively lower parts. */ ivl_expr_t sube = ivl_expr_parm(expr, sub_idx); /* Special case: The next expression is a NUMBER that can be concatenated using %concati/vec4 instructions. */ if (ivl_expr_type(sube) == IVL_EX_NUMBER) { draw_concat_number_vec4(sube, 1); continue; } draw_eval_vec4(sube); fprintf(vvp_out, " %%concat/vec4; draw_concat_vec4\n"); } if (repeat > 1) { fprintf(vvp_out, " %%replicate %u;\n", repeat); } }
/* * This function handles the special case that we assign an array * pattern to a dynamic array. Handle this by assigning each * element. The array pattern will have a fixed size. */ static int show_stmt_assign_darray_pattern(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 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); unsigned idx; #if 0 unsigned element_width = 1; if (ivl_type_base(element_type) == IVL_VT_BOOL) element_width = width_of_packed_type(element_type); else if (ivl_type_base(element_type) == IVL_VT_LOGIC) element_width = width_of_packed_type(element_type); #endif assert(ivl_expr_type(rval) == IVL_EX_ARRAY_PATTERN); for (idx = 0 ; idx < ivl_expr_parms(rval) ; idx += 1) { switch (ivl_type_base(element_type)) { case IVL_VT_BOOL: case IVL_VT_LOGIC: draw_eval_vec4(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%store/dar/vec4 v%p_0;\n", var); break; case IVL_VT_REAL: draw_eval_real(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%store/dar/r v%p_0;\n", var); break; case IVL_VT_STRING: draw_eval_string(ivl_expr_parm(rval,idx)); fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx); fprintf(vvp_out, " %%store/dar/str v%p_0;\n", var); break; default: fprintf(vvp_out, "; ERROR: show_stmt_assign_darray_pattern: type_base=%d not implemented\n", ivl_type_base(element_type)); errors += 1; break; } } return errors; }
/* * This routine is used to emit both system and user functions. */ static void emit_expr_func(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { unsigned count = ivl_expr_parms(expr); if (count) { unsigned idx; fprintf(vlog_out, "("); count -= 1; for (idx = 0; idx < count; idx += 1) { emit_expr(scope, ivl_expr_parm(expr, idx), 0); fprintf(vlog_out, ", "); } emit_expr(scope, ivl_expr_parm(expr, count), 0); fprintf(vlog_out, ")"); } }
static void draw_ufunc_preamble(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } /* Evaluate the expressions and send the results to the function ports. Do this in two passes - evaluate, then send - this avoids the function input variables being overwritten if the same (non-automatic) function is called in one of the exressions. */ assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_eval_function_argument(port, ivl_expr_parm(expr, idx)); } for (idx = ivl_expr_parms(expr) ; idx > 0 ; idx -= 1) { ivl_signal_t port = ivl_scope_port(def, idx); draw_send_function_argument(port); } /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); }
void draw_ufunc_real(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_function_argument(port, ivl_expr_parm(expr, idx)); } /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); /* Return value signal cannot be an array. */ assert(ivl_signal_dimensions(retval) == 0); /* Load the result into a word. */ fprintf(vvp_out, " %%load/real v%p_0;\n", retval); /* If this is an automatic function, free the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%free S_%p;\n", def); } }
static void draw_ufunc_preamble(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } /* evaluate the expressions and send the results to the function ports. */ assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_function_argument(port, ivl_expr_parm(expr, idx)); } /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); }
static void emit_expr_concat(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { unsigned repeat = ivl_expr_repeat(expr); unsigned idx, count = ivl_expr_parms(expr); if (repeat != 1) fprintf(vlog_out, "{%u", repeat); fprintf(vlog_out, "{"); count -= 1; for (idx = 0; idx < count; idx += 1) { emit_expr(scope, ivl_expr_parm(expr, idx), 0); fprintf(vlog_out, ", "); } emit_expr(scope, ivl_expr_parm(expr, count), 0); fprintf(vlog_out, "}"); if (repeat != 1) fprintf(vlog_out, "}"); }
static void draw_ufunc_preamble(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); unsigned idx; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } /* Evaluate the expressions and send the results to the function ports. Do this in two passes - evaluate, then send - this avoids the function input variables being overwritten if the same (non-automatic) function is called in one of the expressions. */ assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_eval_function_argument(port, ivl_expr_parm(expr, idx)); } for (idx = ivl_expr_parms(expr) ; idx > 0 ; idx -= 1) { ivl_signal_t port = ivl_scope_port(def, idx); draw_send_function_argument(port); } /* Call the function */ switch (ivl_expr_value(expr)) { case IVL_VT_VOID: fprintf(vvp_out, " %%callf/void TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); break; case IVL_VT_REAL: fprintf(vvp_out, " %%callf/real TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); break; case IVL_VT_BOOL: case IVL_VT_LOGIC: fprintf(vvp_out, " %%callf/vec4 TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); break; case IVL_VT_STRING: fprintf(vvp_out, " %%callf/str TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); break; case IVL_VT_CLASS: case IVL_VT_DARRAY: case IVL_VT_QUEUE: fprintf(vvp_out, " %%callf/obj TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); break; default: fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); break; } }
static void show_array_pattern_expression(ivl_expr_t net, unsigned ind) { size_t idx; fprintf(out, "%*sArrayPattern (%s): %u expressions\n", ind, "", vt_type_string(net), ivl_expr_parms(net)); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) { show_expression(ivl_expr_parm(net,idx), ind+4); } }
static void show_function_call(ivl_expr_t net, unsigned ind) { ivl_scope_t def = ivl_expr_def(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*vt = vt_type_string(net); unsigned idx; fprintf(out, "%*s<%s %s function %s with %u arguments (width=%u)>\n", ind, "", vt, sign, ivl_scope_name(def), ivl_expr_parms(net), ivl_expr_width(net)); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) show_expression(ivl_expr_parm(net,idx), ind+4); }
/* * This function handles the special case of a call to the internal * functions $ivl_darray_method$pop_back et al. The first (and only) * argument is the signal that represents a dynamic queue. Generate a * %qpop instruction to pop a value and push it to the vec4 stack. */ static void draw_darray_pop(ivl_expr_t expr) { const char*fb; if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_back")==0) fb = "b"; else fb = "f"; ivl_expr_t arg = ivl_expr_parm(expr, 0); assert(ivl_expr_type(arg) == IVL_EX_SIGNAL); fprintf(vvp_out, " %%qpop/%s/v v%p_0;\n", fb, ivl_expr_signal(arg)); }
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); }
void show_expression(ivl_expr_t net, unsigned ind) { assert(net); unsigned idx; ivl_parameter_t par = ivl_expr_parameter(net); const ivl_expr_type_t code = ivl_expr_type(net); unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*sized = ivl_expr_sized(net)? "sized" : "unsized"; const char*vt = vt_type_string(net); switch (code) { case IVL_EX_ARRAY: show_array_expression(net, ind); break; case IVL_EX_ARRAY_PATTERN: show_array_pattern_expression(net, ind); break; case IVL_EX_BACCESS: show_branch_access_expression(net, ind); break; case IVL_EX_BINARY: show_binary_expression(net, ind); break; case IVL_EX_CONCAT: fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n", ind, "", ivl_expr_repeat(net), width, sign, vt); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) show_expression(ivl_expr_parm(net, idx), ind+3); break; case IVL_EX_ENUMTYPE: show_enumtype_expression(net, ind); break; case IVL_EX_MEMORY: show_memory_expression(net, ind); break; case IVL_EX_NEW: show_new_expression(net, ind); break; case IVL_EX_NULL: show_null_expression(net, ind); break; case IVL_EX_PROPERTY: show_property_expression(net, ind); break; case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(net); fprintf(out, "%*s<number=%u'b", ind, "", width); for (idx = width ; idx > 0 ; idx -= 1) fprintf(out, "%c", bits[idx-1]); fprintf(out, ", %s %s %s", sign, sized, vt); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); break; } case IVL_EX_SELECT: show_select_expression(net, ind); break; case IVL_EX_STRING: fprintf(out, "%*s<string=\"%s\", width=%u", ind, "", ivl_expr_string(net), ivl_expr_width(net)); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ", type=%s>\n", vt); break; case IVL_EX_SFUNC: fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s file=%s:%u>\n", ind, "", ivl_expr_name(net), width, sign, vt, ivl_expr_file(net), ivl_expr_lineno(net)); { unsigned cnt = ivl_expr_parms(net); unsigned jdx; for (jdx = 0 ; jdx < cnt ; jdx += 1) show_expression(ivl_expr_parm(net, jdx), ind+3); } break; case IVL_EX_SIGNAL: show_signal_expression(net, ind); break; case IVL_EX_TERNARY: show_ternary_expression(net, ind); break; case IVL_EX_UNARY: show_unary_expression(net, ind); break; case IVL_EX_UFUNC: show_function_call(net, ind); break; case IVL_EX_REALNUM: { int jdx; union foo { double rv; unsigned char bv[sizeof(double)]; } tmp; tmp.rv = ivl_expr_dvalue(net); fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv); for (jdx = sizeof(double) ; jdx > 0 ; jdx -= 1) fprintf(out, "%02x", tmp.bv[jdx-1]); fprintf(out, ")"); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); } break; case IVL_EX_SHALLOWCOPY: show_shallowcopy(net, ind); break; default: fprintf(out, "%*s<expr_type=%d>\n", ind, "", code); break; } }
static void show_expression(ivl_expr_t net) { if (net == 0) return; switch (ivl_expr_type(net)) { case IVL_EX_BINARY: { char code = ivl_expr_opcode(net); show_expression(ivl_expr_oper1(net)); switch (code) { case 'e': fprintf(out, "=="); break; case 'n': fprintf(out, "!="); break; case 'N': fprintf(out, "!=="); break; case 'r': fprintf(out, ">>"); break; default: fprintf(out, "%c", code); } show_expression(ivl_expr_oper2(net)); break; } case IVL_EX_CONCAT: { unsigned idx; fprintf(out, "{"); show_expression(ivl_expr_parm(net, 0)); for (idx = 1 ; idx < ivl_expr_parms(net) ; idx += 1) { fprintf(out, ", "); show_expression(ivl_expr_parm(net, idx)); } fprintf(out, "}"); break; } case IVL_EX_NUMBER: { int sigflag = ivl_expr_signed(net); unsigned idx, width = ivl_expr_width(net); const char*bits = ivl_expr_bits(net); fprintf(out, "%u'%sb", width, sigflag? "s" : ""); for (idx = width ; idx > 0 ; idx -= 1) fprintf(out, "%c", bits[idx-1]); break; } case IVL_EX_SFUNC: fprintf(out, "%s", ivl_expr_name(net)); break; case IVL_EX_STRING: fprintf(out, "\"%s\"", ivl_expr_string(net)); break; case IVL_EX_SIGNAL: fprintf(out, "%s", ivl_expr_name(net)); break; default: fprintf(out, "..."); } }
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 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"); }
struct vector_info draw_ufunc_expr(ivl_expr_t expr, unsigned wid) { unsigned idx; unsigned swid = ivl_expr_width(expr); ivl_scope_t def = ivl_expr_def(expr); ivl_signal_t retval = ivl_scope_port(def, 0); struct vector_info res; unsigned load_wid; /* If this is an automatic function, allocate the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%alloc S_%p;\n", def); } /* evaluate the expressions and send the results to the function ports. */ assert(ivl_expr_parms(expr) == (ivl_scope_ports(def)-1)); for (idx = 0 ; idx < ivl_expr_parms(expr) ; idx += 1) { ivl_signal_t port = ivl_scope_port(def, idx+1); draw_function_argument(port, ivl_expr_parm(expr, idx)); } /* Call the function */ fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def))); fprintf(vvp_out, ", S_%p;\n", def); fprintf(vvp_out, " %%join;\n"); /* Fresh basic block starts after the join. */ clear_expression_lookaside(); /* The return value is in a signal that has the name of the expression. Load that into the thread and return the vector result. */ res.base = allocate_vector(wid); res.wid = wid; if (res.base == 0) { fprintf(stderr, "%s:%u: vvp.tgt error: " "Unable to allocate %u thread bits for function result.\n", ivl_expr_file(expr), ivl_expr_lineno(expr), wid); vvp_errors += 1; return res; } assert(res.base != 0); load_wid = swid; if (load_wid > ivl_signal_width(retval)) load_wid = ivl_signal_width(retval); assert(ivl_signal_dimensions(retval) == 0); fprintf(vvp_out, " %%load/v %u, v%p_0, %u;\n", res.base, retval, load_wid); /* Pad the signal value with zeros. */ if (load_wid < wid) pad_expr_in_place(expr, res, swid); /* If this is an automatic function, free the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%free S_%p;\n", def); } return res; }
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; }
void show_expression(ivl_expr_t net, unsigned ind) { unsigned idx; const ivl_expr_type_t code = ivl_expr_type(net); ivl_parameter_t par = ivl_expr_parameter(net); unsigned width = ivl_expr_width(net); const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; const char*sized = ivl_expr_sized(net)? "sized" : "unsized"; const char*vt = vt_type_string(net); switch (code) { case IVL_EX_ARRAY: show_array_expression(net, ind); break; case IVL_EX_BACCESS: show_branch_access_expression(net, ind); break; case IVL_EX_BINARY: show_binary_expression(net, ind); break; case IVL_EX_CONCAT: fprintf(out, "%*s<concat repeat=%u, width=%u, %s, type=%s>\n", ind, "", ivl_expr_repeat(net), width, sign, vt); for (idx = 0 ; idx < ivl_expr_parms(net) ; idx += 1) show_expression(ivl_expr_parm(net, idx), ind+3); break; case IVL_EX_MEMORY: show_memory_expression(net, ind); break; case IVL_EX_NUMBER: { const char*bits = ivl_expr_bits(net); fprintf(out, "%*s<number=%u'b", ind, "", width); for (idx = width ; idx > 0 ; idx -= 1) fprintf(out, "%c", bits[idx-1]); fprintf(out, ", %s %s %s", sign, sized, vt); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); break; } case IVL_EX_SELECT: /* The SELECT expression can be used to express part select, or if the base is null vector extension. */ if (ivl_expr_oper2(net)) { fprintf(out, "%*s<select: width=%u, %s>\n", ind, "", width, sign); show_expression(ivl_expr_oper1(net), ind+3); show_expression(ivl_expr_oper2(net), ind+3); } else { fprintf(out, "%*s<expr pad: width=%u, %s>\n", ind, "", width, sign); show_expression(ivl_expr_oper1(net), ind+3); } break; case IVL_EX_STRING: fprintf(out, "%*s<string=\"%s\", width=%u", ind, "", ivl_expr_string(net), ivl_expr_width(net)); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ", type=%s>\n", vt); break; case IVL_EX_SFUNC: fprintf(out, "%*s<function=\"%s\", width=%u, %s, type=%s file=%s:%u>\n", ind, "", ivl_expr_name(net), width, sign, vt, ivl_expr_file(net), ivl_expr_lineno(net)); { unsigned cnt = ivl_expr_parms(net); unsigned jdx; for (jdx = 0 ; jdx < cnt ; jdx += 1) show_expression(ivl_expr_parm(net, jdx), ind+3); } break; case IVL_EX_SIGNAL: show_signal_expression(net, ind); break; case IVL_EX_TERNARY: show_ternary_expression(net, ind); break; case IVL_EX_UNARY: show_unary_expression(net, ind); break; case IVL_EX_UFUNC: show_function_call(net, ind); break; case IVL_EX_REALNUM: { int jdx; union foo { double rv; unsigned char bv[sizeof(double)]; } tmp; tmp.rv = ivl_expr_dvalue(net); fprintf(out, "%*s<realnum=%f (", ind, "", tmp.rv); for (jdx = sizeof(double) ; jdx > 0 ; jdx -= 1) fprintf(out, "%02x", tmp.bv[jdx-1]); fprintf(out, ")"); if (par != 0) fprintf(out, ", parameter=%s", ivl_parameter_basename(par)); fprintf(out, ">\n"); } break; default: fprintf(out, "%*s<expr_type=%u>\n", ind, "", code); break; } }