Add .ufunc/real functor to handle functions with return value on stack.
This commit is contained in:
parent
bfc9cd8715
commit
0c91a6b041
|
|
@ -1942,6 +1942,19 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
||||||
ivl_variable_type_t dt = data_type_of_nexus(ivl_lpm_q(net));
|
ivl_variable_type_t dt = data_type_of_nexus(ivl_lpm_q(net));
|
||||||
const char*dly = draw_lpm_output_delay(net, dt);
|
const char*dly = draw_lpm_output_delay(net, dt);
|
||||||
|
|
||||||
|
const char*type_string = "";
|
||||||
|
switch (dt) {
|
||||||
|
case IVL_VT_REAL:
|
||||||
|
type_string = "/real";
|
||||||
|
break;
|
||||||
|
case IVL_VT_BOOL:
|
||||||
|
case IVL_VT_LOGIC:
|
||||||
|
type_string = "/vec4";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get all the input labels that I will use for net signals that
|
/* Get all the input labels that I will use for net signals that
|
||||||
connect to the inputs of the function. */
|
connect to the inputs of the function. */
|
||||||
ninp = ivl_lpm_size(net);
|
ninp = ivl_lpm_size(net);
|
||||||
|
|
@ -1954,7 +1967,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
||||||
vvp_mangle_id(ivl_scope_name(def)),
|
vvp_mangle_id(ivl_scope_name(def)),
|
||||||
ivl_lpm_width(net), ivl_lpm_trigger(net));
|
ivl_lpm_width(net), ivl_lpm_trigger(net));
|
||||||
else
|
else
|
||||||
fprintf(vvp_out, "L_%p%s .ufunc TD_%s, %u", net, dly,
|
fprintf(vvp_out, "L_%p%s .ufunc%s TD_%s, %u", net, dly, type_string,
|
||||||
vvp_mangle_id(ivl_scope_name(def)),
|
vvp_mangle_id(ivl_scope_name(def)),
|
||||||
ivl_lpm_width(net));
|
ivl_lpm_width(net));
|
||||||
|
|
||||||
|
|
@ -1982,7 +1995,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(vvp_out, ")");
|
fprintf(vvp_out, ")");
|
||||||
|
#if 0
|
||||||
/* Now print the reference to the signal from which the
|
/* Now print the reference to the signal from which the
|
||||||
result is collected. */
|
result is collected. */
|
||||||
{ ivl_signal_t psig = ivl_scope_port(def, 0);
|
{ ivl_signal_t psig = ivl_scope_port(def, 0);
|
||||||
|
|
@ -1991,7 +2004,7 @@ static void draw_lpm_ufunc(ivl_lpm_t net)
|
||||||
|
|
||||||
fprintf(vvp_out, " v%p_0", psig);
|
fprintf(vvp_out, " v%p_0", psig);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/* Finally, print the scope identifier. */
|
/* Finally, print the scope identifier. */
|
||||||
fprintf(vvp_out, " S_%p;\n", def);
|
fprintf(vvp_out, " S_%p;\n", def);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,8 @@ extern bool of_XORR(vthread_t thr, vvp_code_t code);
|
||||||
|
|
||||||
extern bool of_ZOMBIE(vthread_t thr, vvp_code_t code);
|
extern bool of_ZOMBIE(vthread_t thr, vvp_code_t code);
|
||||||
|
|
||||||
extern bool of_EXEC_UFUNC(vthread_t thr, vvp_code_t code);
|
extern bool of_EXEC_UFUNC_REAL(vthread_t thr, vvp_code_t code);
|
||||||
|
extern bool of_EXEC_UFUNC_VEC4(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_REAP_UFUNC(vthread_t thr, vvp_code_t code);
|
extern bool of_REAP_UFUNC(vthread_t thr, vvp_code_t code);
|
||||||
|
|
||||||
extern bool of_CHUNK_LINK(vthread_t thr, vvp_code_t code);
|
extern bool of_CHUNK_LINK(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -393,11 +393,14 @@ extern void compile_array_cleanup(void);
|
||||||
/*
|
/*
|
||||||
* Compile the .ufunc statement.
|
* Compile the .ufunc statement.
|
||||||
*/
|
*/
|
||||||
extern void compile_ufunc(char*label, char*code, unsigned wid,
|
extern void compile_ufunc_real(char*label, char*code, unsigned wid,
|
||||||
unsigned argc, struct symb_s*argv,
|
unsigned argc, struct symb_s*argv,
|
||||||
unsigned portc, struct symb_s*portv,
|
unsigned portc, struct symb_s*portv,
|
||||||
struct symb_s retv, char*scope_label,
|
char*scope_label, char*trigger_label);
|
||||||
char*trigger_label);
|
extern void compile_ufunc_vec4(char*label, char*code, unsigned wid,
|
||||||
|
unsigned argc, struct symb_s*argv,
|
||||||
|
unsigned portc, struct symb_s*portv,
|
||||||
|
char*scope_label, char*trigger_label);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The compile_event function takes the parts of the event statement
|
* The compile_event function takes the parts of the event statement
|
||||||
|
|
|
||||||
|
|
@ -208,7 +208,7 @@ static char* strdupnew(char const *str)
|
||||||
".tranif0" { return K_TRANIF0; }
|
".tranif0" { return K_TRANIF0; }
|
||||||
".tranif1" { return K_TRANIF1; }
|
".tranif1" { return K_TRANIF1; }
|
||||||
".tranvp" { return K_TRANVP; }
|
".tranvp" { return K_TRANVP; }
|
||||||
".ufunc" { return K_UFUNC; }
|
".ufunc/real" { return K_UFUNC_REAL; }
|
||||||
".ufunc/e" { return K_UFUNC_E; }
|
".ufunc/e" { return K_UFUNC_E; }
|
||||||
".var" { return K_VAR; }
|
".var" { return K_VAR; }
|
||||||
".var/cobj" { return K_VAR_COBJECT; }
|
".var/cobj" { return K_VAR_COBJECT; }
|
||||||
|
|
|
||||||
20
vvp/parse.y
20
vvp/parse.y
|
|
@ -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_RESOLV K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||||
%token K_SUBSTITUTE
|
%token K_SUBSTITUTE
|
||||||
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
|
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP
|
||||||
%token K_UFUNC K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
%token K_UFUNC_REAL K_UFUNC_E K_UDP K_UDP_C K_UDP_S
|
||||||
%token K_VAR K_VAR_COBJECT K_VAR_DARRAY
|
%token K_VAR K_VAR_COBJECT K_VAR_DARRAY
|
||||||
%token K_VAR_QUEUE
|
%token K_VAR_QUEUE
|
||||||
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
||||||
|
|
@ -250,23 +250,15 @@ statement
|
||||||
| T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';'
|
| T_LABEL K_ARRAY T_STRING ',' T_SYMBOL ';'
|
||||||
{ compile_array_alias($1, $3, $5); }
|
{ compile_array_alias($1, $3, $5); }
|
||||||
|
|
||||||
/* The .ufunc functor is for implementing user defined functions, or
|
/* The .ufunc functors are for implementing user defined functions, or
|
||||||
other thread code that is automatically invoked if any of the
|
other thread code that is automatically invoked if any of the
|
||||||
bits in the symbols list change. */
|
bits in the symbols list change. */
|
||||||
|
|
||||||
| T_LABEL K_UFUNC T_SYMBOL ',' T_NUMBER ','
|
| T_LABEL K_UFUNC_REAL T_SYMBOL ',' T_NUMBER ',' symbols '(' symbols ')' T_SYMBOL ';'
|
||||||
symbols '(' symbols ')' symbol T_SYMBOL ';'
|
{ compile_ufunc_real($1, $3, $5, $7.cnt, $7.vect, $9.cnt, $9.vect, $11, 0); }
|
||||||
{ compile_ufunc($1, $3, $5,
|
|
||||||
$7.cnt, $7.vect,
|
|
||||||
$9.cnt, $9.vect,
|
|
||||||
$11, $12, 0); }
|
|
||||||
|
|
||||||
| T_LABEL K_UFUNC_E T_SYMBOL ',' T_NUMBER ',' T_SYMBOL ','
|
| T_LABEL K_UFUNC_E T_SYMBOL ',' T_NUMBER ',' T_SYMBOL ',' symbols '(' symbols ')' T_SYMBOL ';'
|
||||||
symbols '(' symbols ')' symbol T_SYMBOL ';'
|
{ compile_ufunc_vec4($1, $3, $5, $9.cnt, $9.vect, $11.cnt, $11.vect, $13, $7); }
|
||||||
{ compile_ufunc($1, $3, $5,
|
|
||||||
$9.cnt, $9.vect,
|
|
||||||
$11.cnt, $11.vect,
|
|
||||||
$13, $14, $7); }
|
|
||||||
|
|
||||||
/* Resolver statements are very much like functors. They are
|
/* Resolver statements are very much like functors. They are
|
||||||
compiled to functors of a different mode. */
|
compiled to functors of a different mode. */
|
||||||
|
|
|
||||||
55
vvp/ufunc.cc
55
vvp/ufunc.cc
|
|
@ -41,7 +41,7 @@
|
||||||
ufunc_core::ufunc_core(unsigned owid, vvp_net_t*ptr,
|
ufunc_core::ufunc_core(unsigned owid, vvp_net_t*ptr,
|
||||||
unsigned nports, vvp_net_t**ports,
|
unsigned nports, vvp_net_t**ports,
|
||||||
vvp_code_t sa, __vpiScope*call_scope__,
|
vvp_code_t sa, __vpiScope*call_scope__,
|
||||||
char*result_label, char*scope_label)
|
char*scope_label)
|
||||||
: vvp_wide_fun_core(ptr, nports)
|
: vvp_wide_fun_core(ptr, nports)
|
||||||
{
|
{
|
||||||
owid_ = owid;
|
owid_ = owid;
|
||||||
|
|
@ -50,8 +50,6 @@ ufunc_core::ufunc_core(unsigned owid, vvp_net_t*ptr,
|
||||||
thread_ = 0;
|
thread_ = 0;
|
||||||
call_scope_ = call_scope__;
|
call_scope_ = call_scope__;
|
||||||
|
|
||||||
functor_ref_lookup(&result_, result_label);
|
|
||||||
|
|
||||||
/* A __vpiScope starts with a __vpiHandle structure so this is
|
/* A __vpiScope starts with a __vpiHandle structure so this is
|
||||||
a safe cast. We need the (void*) to avoid a dereferenced
|
a safe cast. We need the (void*) to avoid a dereferenced
|
||||||
type punned pointer warning from some gcc compilers. */
|
type punned pointer warning from some gcc compilers. */
|
||||||
|
|
@ -104,14 +102,16 @@ void ufunc_core::assign_bits_to_ports(vvp_context_t context)
|
||||||
* result from the return code variable and deliver it to the output
|
* result from the return code variable and deliver it to the output
|
||||||
* of the functor, back into the netlist.
|
* of the functor, back into the netlist.
|
||||||
*/
|
*/
|
||||||
void ufunc_core::finish_thread()
|
void ufunc_core::finish_thread_real_()
|
||||||
{
|
{
|
||||||
thread_ = 0;
|
assert(thread_);
|
||||||
if (vvp_fun_signal_real*sig = dynamic_cast<vvp_fun_signal_real*>(result_->fun))
|
|
||||||
propagate_real(sig->real_unfiltered_value());
|
|
||||||
|
|
||||||
if (vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(result_->fun))
|
double val = vthread_get_real_stack(thread_, 0);
|
||||||
propagate_vec4(sig->vec4_unfiltered_value());
|
vthread_pop_real(thread_, 1);
|
||||||
|
|
||||||
|
propagate_real(val);
|
||||||
|
|
||||||
|
thread_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -147,6 +147,24 @@ void ufunc_core::invoke_thread_()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ufunc_real::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_core(ow, ptr, nports, ports, start_address, call_scope, scope_label)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ufunc_real::~ufunc_real()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ufunc_real::finish_thread()
|
||||||
|
{
|
||||||
|
finish_thread_real_();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function compiles the .ufunc statement that is discovered in
|
* This function compiles the .ufunc statement that is discovered in
|
||||||
* the source file. Create all the functors and the thread, and
|
* the source file. Create all the functors and the thread, and
|
||||||
|
|
@ -157,11 +175,10 @@ void ufunc_core::invoke_thread_()
|
||||||
* The portv list is a list of variables that the function reads as
|
* The portv list is a list of variables that the function reads as
|
||||||
* inputs. The core assigns values to these nets as part of the startup.
|
* inputs. The core assigns values to these nets as part of the startup.
|
||||||
*/
|
*/
|
||||||
void compile_ufunc(char*label, char*code, unsigned wid,
|
void compile_ufunc_real(char*label, char*code, unsigned wid,
|
||||||
unsigned argc, struct symb_s*argv,
|
unsigned argc, struct symb_s*argv,
|
||||||
unsigned portc, struct symb_s*portv,
|
unsigned portc, struct symb_s*portv,
|
||||||
struct symb_s retv, char*scope_label,
|
char*scope_label, char*trigger_label)
|
||||||
char*trigger_label)
|
|
||||||
{
|
{
|
||||||
/* The input argument list and port list must have the same
|
/* The input argument list and port list must have the same
|
||||||
sizes, since internally we will be mapping the inputs list
|
sizes, since internally we will be mapping the inputs list
|
||||||
|
|
@ -187,7 +204,7 @@ void compile_ufunc(char*label, char*code, unsigned wid,
|
||||||
the output value to the destination net functor. */
|
the output value to the destination net functor. */
|
||||||
|
|
||||||
vvp_code_t exec_code = codespace_allocate();
|
vvp_code_t exec_code = codespace_allocate();
|
||||||
exec_code->opcode = of_EXEC_UFUNC;
|
exec_code->opcode = of_EXEC_UFUNC_REAL;
|
||||||
code_label_lookup(exec_code, code, false);
|
code_label_lookup(exec_code, code, false);
|
||||||
|
|
||||||
vvp_code_t reap_code = codespace_allocate();
|
vvp_code_t reap_code = codespace_allocate();
|
||||||
|
|
@ -208,9 +225,9 @@ void compile_ufunc(char*label, char*code, unsigned wid,
|
||||||
it about the start address of the code stub, and the scope
|
it about the start address of the code stub, and the scope
|
||||||
that will contain the execution. */
|
that will contain the execution. */
|
||||||
vvp_net_t*ptr = new vvp_net_t;
|
vvp_net_t*ptr = new vvp_net_t;
|
||||||
ufunc_core*fcore = new ufunc_core(wid, ptr, portc, ports,
|
ufunc_core*fcore = new ufunc_real(wid, ptr, portc, ports,
|
||||||
exec_code, call_scope,
|
exec_code, call_scope,
|
||||||
retv.text, scope_label);
|
scope_label);
|
||||||
ptr->fun = fcore;
|
ptr->fun = fcore;
|
||||||
define_functor_symbol(label, ptr);
|
define_functor_symbol(label, ptr);
|
||||||
free(label);
|
free(label);
|
||||||
|
|
@ -229,6 +246,14 @@ void compile_ufunc(char*label, char*code, unsigned wid,
|
||||||
free(portv);
|
free(portv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compile_ufunc_vec4(char*label, char*code, unsigned wid,
|
||||||
|
unsigned argc, struct symb_s*argv,
|
||||||
|
unsigned portc, struct symb_s*portv,
|
||||||
|
char*scope_label, char*trigger_label)
|
||||||
|
{
|
||||||
|
// XXXX NOT IMPLEMENTED
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
#ifdef CHECK_WITH_VALGRIND
|
#ifdef CHECK_WITH_VALGRIND
|
||||||
static map<ufunc_core*, bool> ufunc_map;
|
static map<ufunc_core*, bool> ufunc_map;
|
||||||
|
|
||||||
|
|
|
||||||
21
vvp/ufunc.h
21
vvp/ufunc.h
|
|
@ -56,19 +56,21 @@ class ufunc_core : public vvp_wide_fun_core {
|
||||||
unsigned nports, vvp_net_t**ports,
|
unsigned nports, vvp_net_t**ports,
|
||||||
vvp_code_t start_address,
|
vvp_code_t start_address,
|
||||||
__vpiScope*call_scope,
|
__vpiScope*call_scope,
|
||||||
char*result_label,
|
|
||||||
char*scope_label);
|
char*scope_label);
|
||||||
~ufunc_core();
|
virtual ~ufunc_core() =0;
|
||||||
|
|
||||||
__vpiScope*call_scope() { return call_scope_; }
|
__vpiScope*call_scope() { return call_scope_; }
|
||||||
__vpiScope*func_scope() { return func_scope_; }
|
__vpiScope*func_scope() { return func_scope_; }
|
||||||
|
|
||||||
void assign_bits_to_ports(vvp_context_t context);
|
void assign_bits_to_ports(vvp_context_t context);
|
||||||
void finish_thread();
|
virtual void finish_thread() =0;
|
||||||
|
|
||||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||||
vvp_context_t context);
|
vvp_context_t context);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void finish_thread_real_();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void recv_vec4_from_inputs(unsigned port);
|
void recv_vec4_from_inputs(unsigned port);
|
||||||
void recv_real_from_inputs(unsigned port);
|
void recv_real_from_inputs(unsigned port);
|
||||||
|
|
@ -90,9 +92,18 @@ class ufunc_core : public vvp_wide_fun_core {
|
||||||
__vpiScope*call_scope_;
|
__vpiScope*call_scope_;
|
||||||
__vpiScope*func_scope_;
|
__vpiScope*func_scope_;
|
||||||
vvp_code_t code_;
|
vvp_code_t code_;
|
||||||
|
};
|
||||||
|
|
||||||
// Where the result will be.
|
class ufunc_real : public ufunc_core {
|
||||||
vvp_net_t*result_;
|
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 */
|
#endif /* IVL_ufunc_H */
|
||||||
|
|
|
||||||
|
|
@ -5911,13 +5911,15 @@ bool of_ZOMBIE(vthread_t thr, vvp_code_t)
|
||||||
* a ufunc_core object that has all the port information about the
|
* a ufunc_core object that has all the port information about the
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
bool of_EXEC_UFUNC(vthread_t thr, vvp_code_t cp)
|
static bool do_exec_ufunc(vthread_t thr, vvp_code_t cp, vthread_t child)
|
||||||
{
|
{
|
||||||
__vpiScope*child_scope = cp->ufunc_core_ptr->func_scope();
|
__vpiScope*child_scope = cp->ufunc_core_ptr->func_scope();
|
||||||
assert(child_scope);
|
assert(child_scope);
|
||||||
|
|
||||||
|
assert(child_scope->get_type_code() == vpiFunction);
|
||||||
assert(thr->children.empty());
|
assert(thr->children.empty());
|
||||||
|
|
||||||
|
|
||||||
/* We can take a number of shortcuts because we know that a
|
/* We can take a number of shortcuts because we know that a
|
||||||
continuous assignment can only occur in a static scope. */
|
continuous assignment can only occur in a static scope. */
|
||||||
assert(thr->wt_context == 0);
|
assert(thr->wt_context == 0);
|
||||||
|
|
@ -5930,28 +5932,48 @@ bool of_EXEC_UFUNC(vthread_t thr, vvp_code_t cp)
|
||||||
thr->wt_context = child_context;
|
thr->wt_context = child_context;
|
||||||
thr->rd_context = child_context;
|
thr->rd_context = child_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
child->wt_context = child_context;
|
||||||
|
child->rd_context = child_context;
|
||||||
|
|
||||||
/* Copy all the inputs to the ufunc object to the port
|
/* Copy all the inputs to the ufunc object to the port
|
||||||
variables of the function. This copies all the values
|
variables of the function. This copies all the values
|
||||||
atomically. */
|
atomically. */
|
||||||
cp->ufunc_core_ptr->assign_bits_to_ports(child_context);
|
cp->ufunc_core_ptr->assign_bits_to_ports(child_context);
|
||||||
|
child->delay_delete = 1;
|
||||||
/* Create a temporary thread and run it immediately. */
|
|
||||||
vthread_t child = vthread_new(cp->cptr, child_scope);
|
|
||||||
child->wt_context = child_context;
|
|
||||||
child->rd_context = child_context;
|
|
||||||
|
|
||||||
child->is_scheduled = 1;
|
|
||||||
child->delay_delete = 1;
|
|
||||||
vthread_run(child);
|
|
||||||
running_thread = thr;
|
|
||||||
|
|
||||||
if (child->i_have_ended)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
child->parent = thr;
|
child->parent = thr;
|
||||||
thr->children.insert(child);
|
thr->children.insert(child);
|
||||||
thr->i_am_joining = 1;
|
// This should be the only child
|
||||||
return false;
|
assert(thr->children.size()==1);
|
||||||
|
|
||||||
|
child->is_scheduled = 1;
|
||||||
|
child->i_am_in_function = 1;
|
||||||
|
vthread_run(child);
|
||||||
|
running_thread = thr;
|
||||||
|
|
||||||
|
assert(test_joinable(thr, child));
|
||||||
|
|
||||||
|
if (child->i_have_ended) {
|
||||||
|
do_join(thr, child);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
thr->i_am_joining = 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_EXEC_UFUNC_REAL(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_real(0.0);
|
||||||
|
child->args_real.push_back(0.0);
|
||||||
|
|
||||||
|
return do_exec_ufunc(thr, cp, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue