Add ability to read back return value / Add vec4 stacked user functions.
Also: - handle functions as arguments to system tasks. - Cleanup detect of signal as return value.
This commit is contained in:
parent
0c91a6b041
commit
e435a879fc
|
|
@ -191,9 +191,6 @@ void draw_ufunc_vec4(ivl_expr_t expr)
|
|||
/* Take in arguments to function and call function code. */
|
||||
draw_ufunc_preamble(expr);
|
||||
|
||||
assert(ivl_signal_dimensions(retval) == 0);
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", retval);
|
||||
|
||||
draw_ufunc_epilogue(expr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,12 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result,
|
|||
/* This should never happen since we have IVL_EX_SELECT. */
|
||||
return 0;
|
||||
|
||||
} else if (signal_is_return_value(ivl_expr_signal(expr))) {
|
||||
/* If the signal is the return value of a function,
|
||||
then this can't be handled as a true signal, so
|
||||
fall back on general expression processing. */
|
||||
return 0;
|
||||
|
||||
} else if (ivl_expr_signed(expr) !=
|
||||
ivl_signal_signed(ivl_expr_signal(expr))) {
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1005,6 +1005,15 @@ static void draw_signal_vec4(ivl_expr_t expr)
|
|||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
|
||||
/* Special Case: If the signal is the return value of the function,
|
||||
then use a different opcode to get the value. */
|
||||
if (signal_is_return_value(sig)) {
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, " %%retload/vec4 0; Load %s (draw_signal_vec4)\n",
|
||||
ivl_signal_basename(sig));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle the simple case, a signal expression that is a
|
||||
simple vector, no array dimensions. */
|
||||
if (ivl_signal_dimensions(sig) == 0) {
|
||||
|
|
|
|||
|
|
@ -209,6 +209,17 @@ static void put_vec_to_lval_slice(ivl_lval_t lval, struct vec_slice_info*slice,
|
|||
ivl_signal_t sig = ivl_lval_sig(lval);
|
||||
int part_off_idx;
|
||||
|
||||
|
||||
/* Special Case: If the l-value signal is named after its scope,
|
||||
and the scope is a function, then this is an assign to a return
|
||||
value and should be handled differently. */
|
||||
if (signal_is_return_value(sig)) {
|
||||
assert(ivl_signal_dimensions(sig) == 0);
|
||||
fprintf(vvp_out, " %%ret/vec4 0; Assign to %s\n",
|
||||
ivl_signal_basename(sig));
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
|
@ -345,6 +356,16 @@ static void store_vec4_to_lval(ivl_statement_t net)
|
|||
if (lidx+1 < ivl_stmt_lvals(net))
|
||||
fprintf(vvp_out, " %%split/vec4 %u;\n", lwid);
|
||||
|
||||
/* Special Case: If the l-value signal is named after its scope,
|
||||
and the scope is a function, then this is an assign to a return
|
||||
value and should be handled differently. */
|
||||
if (signal_is_return_value(lsig)) {
|
||||
assert(ivl_signal_dimensions(lsig) == 0);
|
||||
fprintf(vvp_out, " %%ret/vec4 0; Assign to %s (store_vec4_to_lval)\n",
|
||||
ivl_signal_basename(lsig));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (word_ex) {
|
||||
/* Handle index into an array */
|
||||
int word_index = allocate_word();
|
||||
|
|
|
|||
|
|
@ -208,6 +208,10 @@ extern void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix);
|
|||
*/
|
||||
extern int draw_eval_condition(ivl_expr_t expr);
|
||||
|
||||
/*
|
||||
* Return true if the signal is the return value of a function.
|
||||
*/
|
||||
extern int signal_is_return_value(ivl_signal_t sig);
|
||||
|
||||
extern int number_is_unknown(ivl_expr_t ex);
|
||||
extern int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_is_ok);
|
||||
|
|
|
|||
|
|
@ -290,6 +290,16 @@ static unsigned is_netlist_signal(ivl_net_logic_t net, ivl_nexus_t nex)
|
|||
return rtn;
|
||||
}
|
||||
|
||||
int signal_is_return_value(ivl_signal_t sig)
|
||||
{
|
||||
ivl_scope_t sig_scope = ivl_signal_scope(sig);
|
||||
if (ivl_scope_type(sig_scope) != IVL_SCT_FUNCTION)
|
||||
return 0;
|
||||
if (strcmp(ivl_signal_basename(sig), ivl_scope_basename(sig_scope)) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This tests a bufz device against an output receiver, and determines
|
||||
* if the device can be skipped. If this function returns false, then a
|
||||
|
|
@ -458,6 +468,13 @@ static void draw_reg_in_scope(ivl_signal_t sig)
|
|||
ivl_signal_basename(sig), ivl_signal_scope(sig));
|
||||
return;
|
||||
}
|
||||
if ((ivl_signal_data_type(sig)==IVL_VT_LOGIC)
|
||||
&& (ivl_scope_type(ivl_signal_scope(sig))==IVL_SCT_FUNCTION)
|
||||
&& (strcmp(ivl_signal_basename(sig),ivl_scope_basename(ivl_signal_scope(sig))) == 0)) {
|
||||
fprintf(vvp_out, "; Variable %s is vec4 return value of scope S_%p\n",
|
||||
ivl_signal_basename(sig), ivl_signal_scope(sig));
|
||||
return;
|
||||
}
|
||||
|
||||
const char *datatype_flag = ivl_signal_integer(sig) ? "/i" :
|
||||
ivl_signal_signed(sig)? "/s" : "";
|
||||
|
|
|
|||
|
|
@ -702,11 +702,14 @@ STRUCTURAL FUNCTION CALLS:
|
|||
|
||||
The .ufunc statements define a call to a user defined function.
|
||||
|
||||
<label> .ufunc <flabel>, <wid>,
|
||||
<isymbols> ( <psymbols> ) <rsymbol> <ssymbol>;
|
||||
<label> .ufunc/real <flabel>, <wid>,
|
||||
<isymbols> ( <psymbols> ) <ssymbol>;
|
||||
|
||||
<label> .ufunc/vec4 <flabel>, <wid>,
|
||||
<isymbols> ( <psymbols> ) <ssymbol>;
|
||||
|
||||
<label> .ufunc/e <flabel>, <wid>, <trigger>,
|
||||
<isymbols> ( <psymbols> ) <rsymbol> <ssymbol>;
|
||||
<isymbols> ( <psymbols> ) <ssymbol>;
|
||||
|
||||
The first variant is used for functions that only need to be called
|
||||
when one of their inputs changes value. The second variant is used
|
||||
|
|
@ -729,10 +732,6 @@ list. The <psymbols> are variables that represent the input ports for
|
|||
the function. The ufunc performs an assignment to these variables
|
||||
before calling the function.
|
||||
|
||||
The <rsymbol> is the variable within the function where the result
|
||||
will be found when the function code ends. This value is picked up
|
||||
and propagated to the output of the functor.
|
||||
|
||||
The <ssymbol> is the function scope name.
|
||||
|
||||
THREAD STATEMENTS:
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_REPLICATE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RET_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RET_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RETLOAD_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_RETLOAD_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SCOPY(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_SET_DAR_OBJ_STR(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -250,6 +250,9 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%replicate", of_REPLICATE, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%ret/real", of_RET_REAL, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%ret/vec4", of_RET_VEC4, 1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%retload/real",of_RETLOAD_REAL,1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%retload/vec4",of_RETLOAD_VEC4,1,{OA_NUMBER, OA_NONE,OA_NONE} },
|
||||
{ "%scopy", of_SCOPY, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%set/dar/obj/real",of_SET_DAR_OBJ_REAL,1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||
{ "%set/dar/obj/str", of_SET_DAR_OBJ_STR, 1,{OA_NUMBER,OA_NONE,OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ static char* strdupnew(char const *str)
|
|||
".tranif1" { return K_TRANIF1; }
|
||||
".tranvp" { return K_TRANVP; }
|
||||
".ufunc/real" { return K_UFUNC_REAL; }
|
||||
".ufunc/vec4" { return K_UFUNC_VEC4; }
|
||||
".ufunc/e" { return K_UFUNC_E; }
|
||||
".var" { return K_VAR; }
|
||||
".var/cobj" { return K_VAR_COBJECT; }
|
||||
|
|
|
|||
|
|
@ -1016,6 +1016,11 @@ for example to store the return value for a real function, use
|
|||
"%ret/real 0;". It is up to the function caller to set up the argument
|
||||
references.
|
||||
|
||||
* %retload/vec4 <index>
|
||||
|
||||
Read a value from the indexed function argument. The value is read
|
||||
from the argument and pushed to the appropriate stack.
|
||||
|
||||
* %set/dar/obj/real <index>
|
||||
* %set/dar/obj/str <index>
|
||||
* %set/dar/obj/vec4 <index>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_SUBSTITUTE
|
||||
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
|
||||
%token K_UFUNC_REAL K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
||||
%token K_UFUNC_REAL K_UFUNC_VEC4 K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
||||
%token K_VAR K_VAR_COBJECT K_VAR_DARRAY
|
||||
%token K_VAR_QUEUE
|
||||
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
||||
|
|
@ -257,6 +257,9 @@ statement
|
|||
| T_LABEL K_UFUNC_REAL T_SYMBOL ',' T_NUMBER ',' symbols '(' symbols ')' T_SYMBOL ';'
|
||||
{ compile_ufunc_real($1, $3, $5, $7.cnt, $7.vect, $9.cnt, $9.vect, $11, 0); }
|
||||
|
||||
| T_LABEL K_UFUNC_VEC4 T_SYMBOL ',' T_NUMBER ',' symbols '(' symbols ')' T_SYMBOL ';'
|
||||
{ compile_ufunc_vec4($1, $3, $5, $7.cnt, $7.vect, $9.cnt, $9.vect, $11, 0); }
|
||||
|
||||
| T_LABEL K_UFUNC_E T_SYMBOL ',' T_NUMBER ',' T_SYMBOL ',' symbols '(' symbols ')' T_SYMBOL ';'
|
||||
{ compile_ufunc_vec4($1, $3, $5, $9.cnt, $9.vect, $11.cnt, $11.vect, $13, $7); }
|
||||
|
||||
|
|
|
|||
124
vvp/ufunc.cc
124
vvp/ufunc.cc
|
|
@ -38,6 +38,30 @@
|
|||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
class ufunc_real : public ufunc_core {
|
||||
public:
|
||||
ufunc_real(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
__vpiScope*call_scope,
|
||||
char*scope_label);
|
||||
~ufunc_real();
|
||||
|
||||
void finish_thread();
|
||||
};
|
||||
|
||||
class ufunc_vec4 : public ufunc_core {
|
||||
public:
|
||||
ufunc_vec4(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
__vpiScope*call_scope,
|
||||
char*scope_label);
|
||||
~ufunc_vec4();
|
||||
|
||||
void finish_thread();
|
||||
};
|
||||
|
||||
ufunc_core::ufunc_core(unsigned owid, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t sa, __vpiScope*call_scope__,
|
||||
|
|
@ -114,6 +138,18 @@ void ufunc_core::finish_thread_real_()
|
|||
thread_ = 0;
|
||||
}
|
||||
|
||||
void ufunc_core::finish_thread_vec4_()
|
||||
{
|
||||
assert(thread_);
|
||||
|
||||
vvp_vector4_t val = vthread_get_vec4_stack(thread_, 0);
|
||||
vthread_pop_vec4(thread_, 1);
|
||||
|
||||
propagate_vec4(val);
|
||||
|
||||
thread_ = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is only called when a trigger event occurs. Just arrange for
|
||||
* the function to be called.
|
||||
|
|
@ -147,6 +183,24 @@ void ufunc_core::invoke_thread_()
|
|||
}
|
||||
}
|
||||
|
||||
ufunc_vec4::ufunc_vec4(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
__vpiScope*call_scope,
|
||||
char*scope_label)
|
||||
: ufunc_core(ow, ptr, nports, ports, start_address, call_scope, scope_label)
|
||||
{
|
||||
}
|
||||
|
||||
ufunc_vec4::~ufunc_vec4()
|
||||
{
|
||||
}
|
||||
|
||||
void ufunc_vec4::finish_thread()
|
||||
{
|
||||
finish_thread_vec4_();
|
||||
}
|
||||
|
||||
ufunc_real::ufunc_real(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
|
|
@ -195,8 +249,8 @@ void compile_ufunc_real(char*label, char*code, unsigned wid,
|
|||
last instruction is the usual %end. So the thread looks
|
||||
like this:
|
||||
|
||||
%exec_ufunc <core>;
|
||||
%reap_ufunc <core>;
|
||||
%exec_ufunc/real <core>;
|
||||
%reap_ufunc;
|
||||
%end;
|
||||
|
||||
The %exec_ufunc copies the input values into local regs
|
||||
|
|
@ -251,8 +305,70 @@ void compile_ufunc_vec4(char*label, char*code, unsigned wid,
|
|||
unsigned portc, struct symb_s*portv,
|
||||
char*scope_label, char*trigger_label)
|
||||
{
|
||||
// XXXX NOT IMPLEMENTED
|
||||
assert(0);
|
||||
/* The input argument list and port list must have the same
|
||||
sizes, since internally we will be mapping the inputs list
|
||||
to the ports list. */
|
||||
assert(argc == portc);
|
||||
|
||||
__vpiScope*call_scope = vpip_peek_current_scope();
|
||||
assert(call_scope);
|
||||
|
||||
/* Construct some phantom code that is the thread of the
|
||||
function call. The first instruction, at the start_address
|
||||
of the function, loads the ports and calls the function.
|
||||
The second instruction collects the function result. The
|
||||
last instruction is the usual %end. So the thread looks
|
||||
like this:
|
||||
|
||||
%exec_ufunc/vec4 <core>;
|
||||
%reap_ufunc;
|
||||
%end;
|
||||
|
||||
The %exec_ufunc copies the input values into local regs
|
||||
and runs the function code. The %reap_ufunc then copies
|
||||
the output value to the destination net functor. */
|
||||
|
||||
vvp_code_t exec_code = codespace_allocate();
|
||||
exec_code->opcode = of_EXEC_UFUNC_VEC4;
|
||||
code_label_lookup(exec_code, code, false);
|
||||
|
||||
vvp_code_t reap_code = codespace_allocate();
|
||||
reap_code->opcode = of_REAP_UFUNC;
|
||||
|
||||
vvp_code_t end_code = codespace_allocate();
|
||||
end_code->opcode = &of_END;
|
||||
|
||||
/* Run through the function ports (which are related to but
|
||||
not the same as the input ports) and arrange for their
|
||||
binding. */
|
||||
vvp_net_t**ports = new vvp_net_t*[portc];
|
||||
for (unsigned idx = 0 ; idx < portc ; idx += 1) {
|
||||
functor_ref_lookup(&ports[idx], portv[idx].text);
|
||||
}
|
||||
|
||||
/* Create the output functor and attach it to the label. Tell
|
||||
it about the start address of the code stub, and the scope
|
||||
that will contain the execution. */
|
||||
vvp_net_t*ptr = new vvp_net_t;
|
||||
ufunc_core*fcore = new ufunc_vec4(wid, ptr, portc, ports,
|
||||
exec_code, call_scope,
|
||||
scope_label);
|
||||
ptr->fun = fcore;
|
||||
define_functor_symbol(label, ptr);
|
||||
free(label);
|
||||
|
||||
exec_code->ufunc_core_ptr = fcore;
|
||||
reap_code->ufunc_core_ptr = fcore;
|
||||
|
||||
wide_inputs_connect(fcore, argc, argv);
|
||||
|
||||
/* If this function has a trigger event, connect the functor to
|
||||
that event. */
|
||||
if (trigger_label)
|
||||
input_connect(ptr, 0, trigger_label);
|
||||
|
||||
free(argv);
|
||||
free(portv);
|
||||
}
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
static map<ufunc_core*, bool> ufunc_map;
|
||||
|
|
|
|||
13
vvp/ufunc.h
13
vvp/ufunc.h
|
|
@ -70,6 +70,7 @@ class ufunc_core : public vvp_wide_fun_core {
|
|||
|
||||
protected:
|
||||
void finish_thread_real_();
|
||||
void finish_thread_vec4_();
|
||||
|
||||
private:
|
||||
void recv_vec4_from_inputs(unsigned port);
|
||||
|
|
@ -94,16 +95,4 @@ class ufunc_core : public vvp_wide_fun_core {
|
|||
vvp_code_t code_;
|
||||
};
|
||||
|
||||
class ufunc_real : public ufunc_core {
|
||||
public:
|
||||
ufunc_real(unsigned ow, vvp_net_t*ptr,
|
||||
unsigned nports, vvp_net_t**ports,
|
||||
vvp_code_t start_address,
|
||||
__vpiScope*call_scope,
|
||||
char*scope_label);
|
||||
~ufunc_real();
|
||||
|
||||
void finish_thread();
|
||||
};
|
||||
|
||||
#endif /* IVL_ufunc_H */
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ struct vthread_s {
|
|||
// corresponding stack. This is how the %ret/* instructions
|
||||
// get at parent thread arguments.
|
||||
vector<unsigned> args_real;
|
||||
vector<unsigned> args_vec4;
|
||||
|
||||
private:
|
||||
vector<vvp_vector4_t>stack_vec4_;
|
||||
|
|
@ -143,6 +144,12 @@ struct vthread_s {
|
|||
assert(use_index >= 1);
|
||||
return stack_vec4_[use_index-1];
|
||||
}
|
||||
inline void poke_vec4(unsigned depth, const vvp_vector4_t&val)
|
||||
{
|
||||
assert(depth < stack_vec4_.size());
|
||||
unsigned use_index = stack_vec4_.size()-1-depth;
|
||||
stack_vec4_[use_index] = val;
|
||||
}
|
||||
inline void pop_vec4(unsigned cnt)
|
||||
{
|
||||
while (cnt > 0) {
|
||||
|
|
@ -1348,9 +1355,13 @@ bool of_CALLF_STR(vthread_t thr, vvp_code_t cp)
|
|||
bool of_CALLF_VEC4(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vthread_t child = vthread_new(cp->cptr2, cp->scope);
|
||||
return do_callf_void(thr, child);
|
||||
|
||||
// XXXX NOT IMPLEMENTED
|
||||
// This is the return value. Push a place-holder value. The function
|
||||
// will replace this with the actual value using a %ret/real instruction.
|
||||
thr->push_vec4(vvp_vector4_t());
|
||||
child->args_vec4.push_back(0);
|
||||
|
||||
return do_callf_void(thr, child);
|
||||
}
|
||||
|
||||
bool of_CALLF_VOID(vthread_t thr, vvp_code_t cp)
|
||||
|
|
@ -4964,6 +4975,47 @@ bool of_RET_REAL(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %ret/vec4 <index>
|
||||
*/
|
||||
bool of_RET_VEC4(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t index = cp->number;
|
||||
vvp_vector4_t val = thr->pop_vec4();
|
||||
|
||||
assert(index >= 0 && index < thr->args_vec4.size());
|
||||
unsigned depth = thr->args_vec4[index];
|
||||
// Use the depth to put the value into the stack of
|
||||
// the parent thread.
|
||||
thr->parent->poke_vec4(depth, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %retload/real <index>
|
||||
*/
|
||||
bool of_RETLOAD_REAL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
// NOT IMPLEMENTED
|
||||
assert(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %retload/vec4 <index>
|
||||
*/
|
||||
bool of_RETLOAD_VEC4(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t index = cp->number;
|
||||
|
||||
assert(index >= 0 && index < thr->args_vec4.size());
|
||||
unsigned depth = thr->args_vec4[index];
|
||||
// Use the depth to put the value into the stack of
|
||||
// the parent thread.
|
||||
thr->push_vec4(thr->parent->peek_vec4(depth));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_SCOPY(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
vvp_object_t tmp;
|
||||
|
|
@ -5971,7 +6023,20 @@ bool of_EXEC_UFUNC_REAL(vthread_t thr, vvp_code_t cp)
|
|||
/* Create a temporary thread and run it immediately. */
|
||||
vthread_t child = vthread_new(cp->cptr, child_scope);
|
||||
thr->push_real(0.0);
|
||||
child->args_real.push_back(0.0);
|
||||
child->args_real.push_back(0);
|
||||
|
||||
return do_exec_ufunc(thr, cp, child);
|
||||
}
|
||||
|
||||
bool of_EXEC_UFUNC_VEC4(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
__vpiScope*child_scope = cp->ufunc_core_ptr->func_scope();
|
||||
assert(child_scope);
|
||||
|
||||
/* Create a temporary thread and run it immediately. */
|
||||
vthread_t child = vthread_new(cp->cptr, child_scope);
|
||||
thr->push_vec4(vvp_vector4_t());
|
||||
child->args_vec4.push_back(0);
|
||||
|
||||
return do_exec_ufunc(thr, cp, child);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue