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 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"); }
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 draw_ufunc_epilogue(ivl_expr_t expr) { ivl_scope_t def = ivl_expr_def(expr); /* If this is an automatic function, free the local storage. */ if (ivl_scope_is_auto(def)) { fprintf(vvp_out, " %%free S_%p;\n", def); } }
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; }
int draw_scope(ivl_scope_t net, ivl_scope_t parent) { unsigned idx; const char *type; const char*prefix = ivl_scope_is_auto(net) ? "auto" : ""; switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: type = "module"; break; case IVL_SCT_FUNCTION: type = "function"; break; case IVL_SCT_TASK: type = "task"; break; case IVL_SCT_BEGIN: type = "begin"; break; case IVL_SCT_FORK: type = "fork"; break; case IVL_SCT_GENERATE: type = "generate"; break; default: type = "?"; assert(0); } fprintf(vvp_out, "S_%p .scope %s%s, \"%s\" \"%s\" %d %d", net, prefix, type, vvp_mangle_name(ivl_scope_basename(net)), ivl_scope_tname(net), ivl_file_table_index(ivl_scope_file(net)), ivl_scope_lineno(net)); if (parent) { fprintf(vvp_out, ", %d %d, S_%p;\n", ivl_file_table_index(ivl_scope_def_file(net)), ivl_scope_def_lineno(net), parent); } else { fprintf(vvp_out, ";\n"); } fprintf(vvp_out, " .timescale %d %d;\n", ivl_scope_time_units(net), ivl_scope_time_precision(net)); for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) { ivl_parameter_t par = ivl_scope_param(net, idx); ivl_expr_t pex = ivl_parameter_expr(par); switch (ivl_expr_type(pex)) { case IVL_EX_STRING: fprintf(vvp_out, "P_%p .param/str \"%s\" %d %d, \"%s\";\n", par, ivl_parameter_basename(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), ivl_expr_string(pex)); break; case IVL_EX_NUMBER: fprintf(vvp_out, "P_%p .param/l \"%s\" %d %d, %sC4<", par, ivl_parameter_basename(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), ivl_expr_signed(pex)? "+":""); { const char*bits = ivl_expr_bits(pex); unsigned nbits = ivl_expr_width(pex); unsigned bb; for (bb = 0 ; bb < nbits; bb += 1) fprintf(vvp_out, "%c", bits[nbits-bb-1]); } fprintf(vvp_out, ">;\n"); break; case IVL_EX_REALNUM: fprintf(vvp_out, "P_%p .param/real \"%s\" %d %d, %s; value=%g\n", par, ivl_parameter_basename(par), ivl_file_table_index(ivl_parameter_file(par)), ivl_parameter_lineno(par), draw_Cr_to_string(ivl_expr_dvalue(pex)), ivl_expr_dvalue(pex)); break; default: fprintf(vvp_out, "; parameter type %d unsupported\n", ivl_expr_type(pex)); break; } } /* Scan the scope for logic devices. For each device, draw out a functor that connects pin 0 to the output, and the remaining pins to inputs. */ for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1) { ivl_net_logic_t lptr = ivl_scope_log(net, idx); draw_logic_in_scope(lptr); } /* Scan the signals (reg and net) and draw the appropriate statements to make the signal function. */ for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1) { ivl_signal_t sig = ivl_scope_sig(net, idx); switch (ivl_signal_type(sig)) { case IVL_SIT_REG: draw_reg_in_scope(sig); break; default: draw_net_in_scope(sig); break; } } for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1) { ivl_event_t event = ivl_scope_event(net, idx); draw_event_in_scope(event); } for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) { ivl_lpm_t lpm = ivl_scope_lpm(net, idx); draw_lpm_in_scope(lpm); } for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) { ivl_switch_t sw = ivl_scope_switch(net, idx); draw_switch_in_scope(sw); } if (ivl_scope_type(net) == IVL_SCT_TASK) draw_task_definition(net); if (ivl_scope_type(net) == IVL_SCT_FUNCTION) draw_func_definition(net); ivl_scope_children(net, (ivl_scope_f*) draw_scope, net); return 0; }
static int show_scope(ivl_scope_t net, void*x) { unsigned idx; const char *is_auto; fprintf(out, "scope: %s (%u parameters, %u signals, %u logic)", ivl_scope_name(net), ivl_scope_params(net), ivl_scope_sigs(net), ivl_scope_logs(net)); is_auto = ivl_scope_is_auto(net) ? "automatic " : ""; switch (ivl_scope_type(net)) { case IVL_SCT_MODULE: fprintf(out, " module %s%s", ivl_scope_tname(net), ivl_scope_is_cell(net) ? " (cell)" : ""); break; case IVL_SCT_FUNCTION: fprintf(out, " function %s%s", is_auto, ivl_scope_tname(net)); break; case IVL_SCT_BEGIN: fprintf(out, " begin : %s", ivl_scope_tname(net)); break; case IVL_SCT_FORK: fprintf(out, " fork : %s", ivl_scope_tname(net)); break; case IVL_SCT_TASK: fprintf(out, " task %s%s", is_auto, ivl_scope_tname(net)); break; default: fprintf(out, " type(%u) %s", ivl_scope_type(net), ivl_scope_tname(net)); break; } fprintf(out, " time units = 1e%d\n", ivl_scope_time_units(net)); fprintf(out, " time precision = 1e%d\n", ivl_scope_time_precision(net)); for (idx = 0 ; idx < ivl_scope_attr_cnt(net) ; idx += 1) { ivl_attribute_t attr = ivl_scope_attr_val(net, idx); switch (attr->type) { case IVL_ATT_VOID: fprintf(out, " (* %s *)\n", attr->key); break; case IVL_ATT_STR: fprintf(out, " (* %s = \"%s\" *)\n", attr->key, attr->val.str); break; case IVL_ATT_NUM: fprintf(out, " (* %s = %ld *)\n", attr->key, attr->val.num); break; } } for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) show_parameter(ivl_scope_param(net, idx)); for (idx = 0 ; idx < ivl_scope_enumerates(net) ; idx += 1) show_enumerate(ivl_scope_enumerate(net, idx)); for (idx = 0 ; idx < ivl_scope_sigs(net) ; idx += 1) show_signal(ivl_scope_sig(net, idx)); for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1) show_event(ivl_scope_event(net, idx)); for (idx = 0 ; idx < ivl_scope_logs(net) ; idx += 1) show_logic(ivl_scope_log(net, idx)); for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) show_lpm(ivl_scope_lpm(net, idx)); for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) show_switch(ivl_scope_switch(net, idx)); switch (ivl_scope_type(net)) { case IVL_SCT_FUNCTION: case IVL_SCT_TASK: fprintf(out, " scope function/task definition\n"); if (ivl_scope_def(net) == 0) { fprintf(out, " ERROR: scope missing required task definition\n"); stub_errors += 1; } else { show_statement(ivl_scope_def(net), 6); } break; default: if (ivl_scope_def(net)) { fprintf(out, " ERROR: scope has an attached task definition:\n"); show_statement(ivl_scope_def(net), 6); stub_errors += 1; } break; } fprintf(out, "end scope %s\n", ivl_scope_name(net)); return ivl_scope_children(net, show_scope, 0); }