Merge pull request #1416 from muhammadjawadkhan/split/01-sv-class-queue-darray-props
SV: class queue/darray property foundation
This commit is contained in:
commit
d15f24ff49
12
PExpr.h
12
PExpr.h
|
|
@ -37,6 +37,7 @@ class NetExpr;
|
|||
class NetScope;
|
||||
class PPackage;
|
||||
struct symbol_search_results;
|
||||
class netclass_t;
|
||||
|
||||
/*
|
||||
* The PExpr class hierarchy supports the description of
|
||||
|
|
@ -976,7 +977,16 @@ class PECallFunction : public PExpr {
|
|||
unsigned elaborate_arguments_(Design*des, NetScope*scope,
|
||||
const NetFuncDef*def, bool need_const,
|
||||
std::vector<NetExpr*>&parms,
|
||||
unsigned parm_off) const;
|
||||
unsigned parm_off,
|
||||
const std::vector<named_pexpr_t>*src_parms = nullptr) const;
|
||||
|
||||
NetExpr* elaborate_class_method_net_(Design*des, NetScope*scope,
|
||||
NetNet*net, const netclass_t*class_type,
|
||||
perm_string method_name,
|
||||
const std::vector<named_pexpr_t>*src_parms) const;
|
||||
|
||||
NetExpr* elaborate_expr_method_chained_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results) const;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
28
Statement.h
28
Statement.h
|
|
@ -40,6 +40,8 @@ class NetCAssign;
|
|||
class NetDeassign;
|
||||
class NetForce;
|
||||
class NetScope;
|
||||
class NetNet;
|
||||
class netdarray_t;
|
||||
|
||||
/*
|
||||
* The PProcess is the root of a behavioral process. Each process gets
|
||||
|
|
@ -261,16 +263,42 @@ class PCallTask : public Statement {
|
|||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names = {}) const;
|
||||
NetProc*elaborate_sys_task_property_method_(Design*des, NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names = {}) const;
|
||||
NetProc*elaborate_queue_method_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const;
|
||||
NetProc*elaborate_queue_property_method_(Design*des, NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const;
|
||||
NetProc*elaborate_method_func_(NetScope*scope,
|
||||
NetNet*net,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const;
|
||||
NetProc*elaborate_method_property_func_(NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const;
|
||||
NetProc*elaborate_queue_method_expr_(Design*des, NetScope*scope,
|
||||
NetExpr*queue_base,
|
||||
const netdarray_t*use_darray,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const;
|
||||
NetProc*elaborate_method_func_expr_(NetScope*scope,
|
||||
NetExpr*queue_base,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const;
|
||||
bool test_task_calls_ok_(Design*des, const NetScope*scope) const;
|
||||
|
||||
PPackage*package_;
|
||||
|
|
|
|||
352
elab_expr.cc
352
elab_expr.cc
|
|
@ -461,7 +461,6 @@ NetExpr* PEAssignPattern::elaborate_expr(Design*des, NetScope*, unsigned, unsign
|
|||
cerr << get_fileline() << ": : Expression is: " << *this
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
ivl_assert(*this, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1551,12 +1550,36 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
|||
<< "search_results.net->net_type: " << *search_results.net->net_type() << endl;
|
||||
}
|
||||
|
||||
// Don't support multiple chained methods yet.
|
||||
// Chained class methods: obj.m1().m2() — width is that of the last call.
|
||||
if (search_results.path_tail.size() > 1) {
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_CLASS) {
|
||||
const netclass_t* cur_class = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
if (cur_class) {
|
||||
size_t ntail = search_results.path_tail.size();
|
||||
size_t idx = 0;
|
||||
for (auto it = search_results.path_tail.begin()
|
||||
; it != search_results.path_tail.end() ; ++it, ++idx) {
|
||||
perm_string mname = it->name;
|
||||
NetScope*meth = cur_class->method_from_name(mname);
|
||||
if (meth == 0) return 0;
|
||||
const NetNet*res = meth->find_signal(meth->basename());
|
||||
if (res == 0) return 0;
|
||||
if (idx + 1 == ntail) {
|
||||
expr_type_ = res->data_type();
|
||||
expr_width_ = res->vector_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = res->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
cur_class = dynamic_cast<const netclass_t*>(res->net_type());
|
||||
if (cur_class == 0) return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::test_width_method_: "
|
||||
<< "Chained path tail (" << search_results.path_tail
|
||||
<< ") not supported." << endl;
|
||||
<< ") not supported for this expression type." << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1593,8 +1616,8 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
|||
// the expr_width for the return value of the queue method. For example:
|
||||
// <scope>.x.size();
|
||||
// In this example, x is a queue.
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE
|
||||
&& search_results.path_head.back().index.empty()) {
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE &&
|
||||
search_results.path_head.back().index.empty()) {
|
||||
|
||||
const NetNet*net = search_results.net;
|
||||
const netdarray_t*darray = net->darray_type();
|
||||
|
|
@ -2743,7 +2766,6 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
unsigned expr_wid,
|
||||
unsigned flags) const
|
||||
{
|
||||
|
||||
const netclass_t *class_type = dynamic_cast<const netclass_t*>(sr.type);
|
||||
const name_component_t comp = sr.path_tail.front();
|
||||
|
||||
|
|
@ -2821,6 +2843,27 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
canon_index = make_canonical_index(des, scope, this,
|
||||
comp.index, tmp_ua, false);
|
||||
}
|
||||
} else if (dynamic_cast<const netdarray_t*>(tmp_type)) {
|
||||
/* Queue or dynamic-array property: optional index, e.g. c.q[i]
|
||||
* or whole-container reference c.q. */
|
||||
const std::list<index_component_t>*idx_list = &comp.index;
|
||||
if (idx_list->empty() && !path_.back().index.empty()) {
|
||||
idx_list = &path_.back().index;
|
||||
}
|
||||
if (idx_list->size() == 0) {
|
||||
canon_index = nullptr;
|
||||
} else if (idx_list->size() != 1) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Got " << idx_list->size() << " indices, "
|
||||
<< "expecting 0 or 1 for the queue/dynamic-array property "
|
||||
<< class_type->get_prop_name(pidx) << "." << endl;
|
||||
des->errors++;
|
||||
} else {
|
||||
const index_component_t&use_index = idx_list->back();
|
||||
ivl_assert(*this, use_index.msb != 0);
|
||||
ivl_assert(*this, use_index.lsb == 0);
|
||||
canon_index = elab_and_eval(des, scope, use_index.msb, -1, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_elaborate && canon_index) {
|
||||
|
|
@ -3139,13 +3182,16 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
|
|||
unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
||||
const NetFuncDef*def, bool need_const,
|
||||
vector<NetExpr*>&parms,
|
||||
unsigned parm_off) const
|
||||
unsigned parm_off,
|
||||
const vector<named_pexpr_t>*src_parms) const
|
||||
{
|
||||
unsigned parm_errors = 0;
|
||||
unsigned missing_parms = 0;
|
||||
|
||||
const vector<named_pexpr_t>&use_parms = src_parms ? *src_parms : parms_;
|
||||
|
||||
const unsigned parm_count = parms.size() - parm_off;
|
||||
const unsigned actual_count = parms_.size();
|
||||
const unsigned actual_count = use_parms.size();
|
||||
|
||||
if (parm_count == 0 && actual_count == 0)
|
||||
return 0;
|
||||
|
|
@ -3158,7 +3204,7 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
|
||||
auto args = map_named_args(des, def, parms_, parm_off);
|
||||
auto args = map_named_args(des, def, use_parms, parm_off);
|
||||
|
||||
for (unsigned idx = 0 ; idx < parm_count ; idx += 1) {
|
||||
unsigned pidx = idx + parm_off;
|
||||
|
|
@ -3213,6 +3259,166 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
return parm_errors;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate a call to a single class method, optionally using an alternate
|
||||
* argument vector (for chained calls where inner methods use no user args).
|
||||
*/
|
||||
NetExpr* PECallFunction::elaborate_class_method_net_(Design*des, NetScope*scope,
|
||||
NetNet*net, const netclass_t*class_type,
|
||||
perm_string method_name,
|
||||
const vector<named_pexpr_t>*src_parms) const
|
||||
{
|
||||
NetScope*method = class_type->method_from_name(method_name);
|
||||
|
||||
if (method == 0) {
|
||||
cerr << get_fileline() << ": Error: " << method_name
|
||||
<< " is not a method of class " << class_type->get_name()
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (method->type() != NetScope::FUNC) {
|
||||
cerr << get_fileline() << ": error: Method " << method_name
|
||||
<< " of class " << class_type->get_name()
|
||||
<< " is not a function." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetFuncDef*def = method->func_def();
|
||||
ivl_assert(*this, def);
|
||||
|
||||
NetNet*res = method->find_signal(method->basename());
|
||||
ivl_assert(*this, res);
|
||||
|
||||
vector<NetExpr*> parms(def->port_count());
|
||||
ivl_assert(*this, def->port_count() >= 1);
|
||||
|
||||
NetESignal*ethis = new NetESignal(net);
|
||||
ethis->set_line(*this);
|
||||
parms[0] = ethis;
|
||||
|
||||
elaborate_arguments_(des, scope, def, false, parms, 1, src_parms);
|
||||
|
||||
NetESignal*eres = new NetESignal(res);
|
||||
NetEUFunc*call = new NetEUFunc(scope, method, eres, parms, false);
|
||||
call->set_line(*this);
|
||||
return call;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle obj.m1().m2(args): arguments apply only to the last call; intermediate
|
||||
* methods must be class methods returning class handles.
|
||||
*/
|
||||
NetExpr* PECallFunction::elaborate_expr_method_chained_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results) const
|
||||
{
|
||||
static const vector<named_pexpr_t> no_parms;
|
||||
|
||||
if (search_results.par_val && search_results.type) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Method name nesting is not supported for parameter methods yet." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr* sub_expr = 0;
|
||||
if (search_results.net) {
|
||||
NetESignal*tmp = new NetESignal(search_results.net);
|
||||
tmp->set_line(*this);
|
||||
sub_expr = tmp;
|
||||
}
|
||||
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE &&
|
||||
search_results.path_head.back().index.size()==1) {
|
||||
|
||||
const NetNet*net = search_results.net;
|
||||
const netdarray_t*darray = net->darray_type();
|
||||
const index_component_t&use_index = search_results.path_head.back().index.back();
|
||||
ivl_assert(*this, use_index.msb != 0);
|
||||
ivl_assert(*this, use_index.lsb == 0);
|
||||
|
||||
NetExpr*mux = elab_and_eval(des, scope, use_index.msb, -1, false);
|
||||
if (!mux) return 0;
|
||||
|
||||
NetESelect*tmp = new NetESelect(sub_expr, mux, darray->element_width(), darray->element_type());
|
||||
tmp->set_line(*this);
|
||||
sub_expr = tmp;
|
||||
}
|
||||
|
||||
if (!sub_expr) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "Method chain elaborate lost base sub-expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sub_expr->expr_type() != IVL_VT_CLASS) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Method name nesting for this expression type is not supported yet "
|
||||
<< "(only class handle chains)." << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "method path: " << search_results.path_tail << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet* cur_net = search_results.net;
|
||||
const netclass_t* cur_class = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
if (cur_class == 0) {
|
||||
cur_class = dynamic_cast<const netclass_t*>(cur_net->net_type());
|
||||
}
|
||||
if (cur_class == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "IVL_VT_CLASS net without netclass_t type." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t chain_len = search_results.path_tail.size() - 1;
|
||||
size_t step_idx = 0;
|
||||
for (auto it = search_results.path_tail.begin()
|
||||
; step_idx < chain_len ; ++it, ++step_idx) {
|
||||
perm_string method_name = it->name;
|
||||
|
||||
NetExpr* step = elaborate_class_method_net_(des, scope, cur_net, cur_class,
|
||||
method_name, &no_parms);
|
||||
if (step == 0) return 0;
|
||||
|
||||
NetEUFunc*uf = dynamic_cast<NetEUFunc*> (step);
|
||||
if (uf == 0) {
|
||||
cerr << get_fileline() << ": internal error: "
|
||||
<< "expected class method call to be NetEUFunc." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetESignal*rs = uf->result_sig();
|
||||
ivl_assert(*this, rs);
|
||||
cur_net = const_cast<NetNet*>(rs->sig());
|
||||
ivl_assert(*this, cur_net);
|
||||
cur_class = dynamic_cast<const netclass_t*>(cur_net->net_type());
|
||||
if (cur_class == 0) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Method chaining requires intermediate results to be class handles; "
|
||||
<< "after `" << method_name << "` the type is not a class." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
symbol_search_results tail_sr;
|
||||
tail_sr.scope = search_results.scope;
|
||||
tail_sr.path_head = search_results.path_head;
|
||||
tail_sr.path_tail.clear();
|
||||
tail_sr.path_tail.push_back(search_results.path_tail.back());
|
||||
tail_sr.net = cur_net;
|
||||
tail_sr.type = cur_class;
|
||||
|
||||
return elaborate_expr_method_(des, scope, tail_sr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for a method of a given object. The search_results gives us the
|
||||
* information we need to look into this case: The net is the object that will
|
||||
|
|
@ -3236,12 +3442,82 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// e.g. c.q.size() — path_tail is {q, size}; q is a queue-typed property
|
||||
if (search_results.path_tail.size() == 2) {
|
||||
const netclass_t*cls = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
if (!cls && search_results.net && search_results.net->net_type()) {
|
||||
cls = dynamic_cast<const netclass_t*>(search_results.net->net_type());
|
||||
}
|
||||
if (cls && search_results.net) {
|
||||
perm_string prop_name = search_results.path_tail.front().name;
|
||||
int pidx = cls->property_idx_from_name(prop_name);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t ptype = cls->get_prop_type(pidx);
|
||||
if (ptype && dynamic_cast<const netqueue_t*>(ptype)) {
|
||||
NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr);
|
||||
prop->set_line(*this);
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
const netqueue_t*queue = dynamic_cast<const netqueue_t*>(ptype);
|
||||
ivl_assert(*this, queue);
|
||||
ivl_type_t element_type = queue->element_type();
|
||||
if (method_name == "size") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: size() method "
|
||||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, prop);
|
||||
return sys_expr;
|
||||
}
|
||||
if (method_name == "pop_back") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: pop_back() method "
|
||||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_back",
|
||||
element_type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, prop);
|
||||
return sys_expr;
|
||||
}
|
||||
if (method_name == "pop_front") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: pop_front() method "
|
||||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_front",
|
||||
element_type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, prop);
|
||||
return sys_expr;
|
||||
}
|
||||
}
|
||||
if (ptype && ptype->base_type() == IVL_VT_DARRAY) {
|
||||
NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr);
|
||||
prop->set_line(*this);
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
if (method_name == "size") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: size() method "
|
||||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, prop);
|
||||
return sys_expr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (search_results.path_tail.size() > 1) {
|
||||
cerr << get_fileline() << ": sorry: "
|
||||
<< "Method name nesting is not supported yet." << endl;
|
||||
cerr << get_fileline() << ": : "
|
||||
<< "method path: " << search_results.path_tail << endl;
|
||||
return 0;
|
||||
return elaborate_expr_method_chained_(des, scope, search_results);
|
||||
}
|
||||
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -3282,8 +3558,8 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
// <scope>.x[e].len()
|
||||
// If x is a queue of strings, then x[e] is a string. Elaborate the x[e]
|
||||
// expression and pass that to the len() method.
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE
|
||||
&& search_results.path_head.back().index.size()==1) {
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE &&
|
||||
search_results.path_head.back().index.size()==1) {
|
||||
|
||||
const NetNet*net = search_results.net;
|
||||
const netdarray_t*darray = net->darray_type();
|
||||
|
|
@ -3337,8 +3613,8 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
|
||||
// Queue methods. This handles the case that the located signal is a
|
||||
// QUEUE object, and there is a method.
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE
|
||||
&& search_results.path_head.back().index.size()==0) {
|
||||
if (search_results.net && search_results.net->data_type()==IVL_VT_QUEUE &&
|
||||
search_results.path_head.back().index.size()==0) {
|
||||
|
||||
// Get the method name that we are looking for.
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
|
|
@ -3405,49 +3681,13 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
// Class methods. Generate function call to the class method.
|
||||
if (sub_expr->expr_type()==IVL_VT_CLASS) {
|
||||
|
||||
// Get the method name that we are looking for.
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
|
||||
NetNet*net = search_results.net;
|
||||
const netclass_t*class_type = dynamic_cast<const netclass_t*>(search_results.type);
|
||||
ivl_assert(*this, class_type);
|
||||
NetScope*method = class_type->method_from_name(method_name);
|
||||
|
||||
if (method == 0) {
|
||||
cerr << get_fileline() << ": Error: " << method_name
|
||||
<< " is not a method of class " << class_type->get_name()
|
||||
<< "." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (method->type() != NetScope::FUNC) {
|
||||
cerr << get_fileline() << ": error: Method " << method_name
|
||||
<< " of class " << class_type->get_name()
|
||||
<< " is not a function." << endl;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const NetFuncDef*def = method->func_def();
|
||||
ivl_assert(*this, def);
|
||||
|
||||
NetNet*res = method->find_signal(method->basename());
|
||||
ivl_assert(*this, res);
|
||||
|
||||
vector<NetExpr*> parms(def->port_count());
|
||||
ivl_assert(*this, def->port_count() >= 1);
|
||||
|
||||
NetESignal*ethis = new NetESignal(net);
|
||||
ethis->set_line(*this);
|
||||
parms[0] = ethis;
|
||||
|
||||
elaborate_arguments_(des, scope, def, false, parms, 1);
|
||||
|
||||
NetESignal*eres = new NetESignal(res);
|
||||
NetEUFunc*call = new NetEUFunc(scope, method, eres, parms, false);
|
||||
call->set_line(*this);
|
||||
return call;
|
||||
return elaborate_class_method_net_(des, scope, net, class_type,
|
||||
method_name, nullptr);
|
||||
}
|
||||
|
||||
// String methods.
|
||||
|
|
|
|||
|
|
@ -404,11 +404,6 @@ void netclass_t::elaborate_sig(Design*des, PClass*pclass)
|
|||
<< " type=" << *use_type << endl;
|
||||
}
|
||||
|
||||
if (dynamic_cast<const netqueue_t *> (use_type)) {
|
||||
cerr << cur->second.get_fileline() << ": sorry: "
|
||||
<< "Queues inside classes are not yet supported." << endl;
|
||||
des->errors++;
|
||||
}
|
||||
set_property(cur->first, cur->second.qual, use_type);
|
||||
|
||||
if (! cur->second.qual.test_static())
|
||||
|
|
|
|||
242
elaborate.cc
242
elaborate.cc
|
|
@ -4065,19 +4065,66 @@ NetProc* PCallTask::elaborate_sys_task_method_(Design*des, NetScope*scope,
|
|||
return sys;
|
||||
}
|
||||
|
||||
/*
|
||||
* This private method is called to elaborate queue push methods. The
|
||||
* sys_task_name is the internal system-task name to use.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const
|
||||
NetProc* PCallTask::elaborate_sys_task_property_method_(Design*des, NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const
|
||||
{
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
sig->set_line(*this);
|
||||
NetEProperty*prop = new NetEProperty(net, property_idx, 0);
|
||||
prop->set_line(*this);
|
||||
|
||||
unsigned nparms = parms_.size();
|
||||
|
||||
vector<NetExpr*>argv (1 + nparms);
|
||||
argv[0] = prop;
|
||||
|
||||
if (method_name == "delete") {
|
||||
const netclass_t*cls = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
ivl_assert(*this, cls);
|
||||
ivl_type_t pt = cls->get_prop_type(property_idx);
|
||||
bool is_queue = pt && pt->base_type() == IVL_VT_QUEUE;
|
||||
if (is_queue) {
|
||||
if (nparms > 1) {
|
||||
cerr << get_fileline() << ": error: queue delete() "
|
||||
<< "method takes zero or one argument." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
} else if (nparms > 0) {
|
||||
cerr << get_fileline() << ": error: darray delete() "
|
||||
<< "method takes no arguments." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
} else if (parm_names.size() != parms_.size()) {
|
||||
cerr << get_fileline() << ": error: " << method_name
|
||||
<< "() method takes " << parm_names.size() << " arguments, got "
|
||||
<< parms_.size() << "." << endl;
|
||||
des->errors++;
|
||||
}
|
||||
|
||||
auto args = map_named_args(des, parm_names, parms_);
|
||||
for (unsigned idx = 0 ; idx < nparms ; idx += 1) {
|
||||
argv[idx + 1] = elab_sys_task_arg(des, scope, method_name,
|
||||
idx, args[idx]);
|
||||
}
|
||||
|
||||
NetSTask*sys = new NetSTask(sys_task_name, IVL_SFUNC_AS_TASK_IGNORE, argv);
|
||||
sys->set_line(*this);
|
||||
return sys;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common implementation for queue push/insert methods. The queue_base
|
||||
* expression is either a NetESignal or NetEProperty; use_darray
|
||||
* supplies the element type.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_queue_method_expr_(Design*des, NetScope*scope,
|
||||
NetExpr*queue_base,
|
||||
const netdarray_t*use_darray,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const
|
||||
{
|
||||
unsigned nparms = parms_.size();
|
||||
// insert() requires two arguments.
|
||||
if ((method_name == "insert") && (nparms != 2)) {
|
||||
|
|
@ -4091,10 +4138,10 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
|
|||
<< "() method requires a single argument." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
ivl_type_t element_type = net->queue_type()->element_type();
|
||||
ivl_type_t element_type = use_darray->element_type();
|
||||
unsigned expected_nparms = method_name == "insert" ? 2 : 1;
|
||||
vector<NetExpr*>argv (expected_nparms+1);
|
||||
argv[0] = sig;
|
||||
argv[0] = queue_base;
|
||||
|
||||
auto args = map_named_args(des, parm_names, parms_);
|
||||
if (method_name != "insert") {
|
||||
|
|
@ -4135,14 +4182,55 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
|
|||
return sys;
|
||||
}
|
||||
|
||||
/*
|
||||
* This private method is called to elaborate queue push methods. The
|
||||
* sys_task_name is the internal system-task name to use.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
|
||||
NetNet*net,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const
|
||||
{
|
||||
NetESignal*sig = new NetESignal(net);
|
||||
sig->set_line(*this);
|
||||
|
||||
const netdarray_t*use_darray = net->darray_type();
|
||||
ivl_assert(*this, use_darray);
|
||||
|
||||
return elaborate_queue_method_expr_(des, scope, sig, use_darray,
|
||||
method_name, sys_task_name,
|
||||
parm_names);
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_queue_property_method_(Design*des, NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
perm_string method_name,
|
||||
const char *sys_task_name,
|
||||
const std::vector<perm_string> &parm_names) const
|
||||
{
|
||||
const netclass_t*cls = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
ivl_assert(*this, cls);
|
||||
ivl_type_t ptype = cls->get_prop_type(property_idx);
|
||||
const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(ptype);
|
||||
ivl_assert(*this, use_darray);
|
||||
|
||||
NetEProperty*prop = new NetEProperty(net, property_idx, 0);
|
||||
prop->set_line(*this);
|
||||
|
||||
return elaborate_queue_method_expr_(des, scope, prop, use_darray,
|
||||
method_name, sys_task_name,
|
||||
parm_names);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used for array/queue function methods called as tasks.
|
||||
*/
|
||||
NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
||||
NetNet*net,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
NetProc* PCallTask::elaborate_method_func_expr_(NetScope*scope,
|
||||
NetExpr*queue_base,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
{
|
||||
if (!void_cast_) {
|
||||
cerr << get_fileline() << ": warning: method function '"
|
||||
|
|
@ -4152,9 +4240,7 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
|||
// Generate the function.
|
||||
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*net);
|
||||
sys_expr->parm(0, arg);
|
||||
sys_expr->parm(0, queue_base);
|
||||
// Create a L-value that matches the function return type.
|
||||
NetNet*tmp;
|
||||
tmp = new NetNet(scope, scope->local_symbol(), NetNet::REG, type);
|
||||
|
|
@ -4166,6 +4252,30 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
|||
return cur;
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
||||
NetNet*net,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
{
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*this);
|
||||
return elaborate_method_func_expr_(scope, arg, type,
|
||||
method_name, sys_task_name);
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_method_property_func_(NetScope*scope,
|
||||
NetNet*net, int property_idx,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
{
|
||||
NetEProperty*prop = new NetEProperty(net, property_idx, 0);
|
||||
prop->set_line(*this);
|
||||
return elaborate_method_func_expr_(scope, prop, type,
|
||||
method_name, sys_task_name);
|
||||
}
|
||||
|
||||
NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
||||
bool add_this_flag) const
|
||||
{
|
||||
|
|
@ -4214,13 +4324,93 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
<< net->name() << ".data_type() --> " << net->data_type() << endl;
|
||||
}
|
||||
|
||||
// Class handle with one path_tail component: queue/darray property method
|
||||
// e.g. c.q.push_back(x) => sr.path_tail = {q}, method_name = push_back
|
||||
if (sr.path_tail.size() == 1) {
|
||||
const netclass_t*cls = dynamic_cast<const netclass_t*>(sr.type);
|
||||
if (!cls && net->net_type()) {
|
||||
cls = dynamic_cast<const netclass_t*>(net->net_type());
|
||||
}
|
||||
if (cls) {
|
||||
perm_string prop_name = sr.path_tail.front().name;
|
||||
int pidx = cls->property_idx_from_name(prop_name);
|
||||
if (pidx >= 0) {
|
||||
ivl_type_t ptype = cls->get_prop_type(pidx);
|
||||
if (ptype && dynamic_cast<const netqueue_t*>(ptype)) {
|
||||
const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(ptype);
|
||||
ivl_assert(*this, use_darray);
|
||||
|
||||
if (method_name == "push_back") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("item")
|
||||
};
|
||||
return elaborate_queue_property_method_(des, scope, net, pidx,
|
||||
method_name,
|
||||
"$ivl_queue_method$push_back",
|
||||
parm_names);
|
||||
}
|
||||
if (method_name == "push_front") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("item")
|
||||
};
|
||||
return elaborate_queue_property_method_(des, scope, net, pidx,
|
||||
method_name,
|
||||
"$ivl_queue_method$push_front",
|
||||
parm_names);
|
||||
}
|
||||
if (method_name == "insert") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("index"),
|
||||
perm_string::literal("item")
|
||||
};
|
||||
return elaborate_queue_property_method_(des, scope, net, pidx,
|
||||
method_name,
|
||||
"$ivl_queue_method$insert",
|
||||
parm_names);
|
||||
}
|
||||
if (method_name == "pop_front") {
|
||||
return elaborate_method_property_func_(scope, net, pidx,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
"$ivl_queue_method$pop_front");
|
||||
}
|
||||
if (method_name == "pop_back") {
|
||||
return elaborate_method_property_func_(scope, net, pidx,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
"$ivl_queue_method$pop_back");
|
||||
}
|
||||
if (method_name == "size") {
|
||||
return elaborate_method_property_func_(scope, net, pidx,
|
||||
&netvector_t::atom2s32,
|
||||
method_name, "$size");
|
||||
}
|
||||
} else if (ptype && ptype->base_type() == IVL_VT_DARRAY) {
|
||||
if (method_name == "delete") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("index")
|
||||
};
|
||||
return elaborate_sys_task_property_method_(des, scope, net, pidx,
|
||||
method_name,
|
||||
"$ivl_darray_method$delete",
|
||||
parm_names);
|
||||
}
|
||||
if (method_name == "size") {
|
||||
return elaborate_method_property_func_(scope, net, pidx,
|
||||
&netvector_t::atom2s32,
|
||||
method_name, "$size");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a method of a "string" type?
|
||||
if (dynamic_cast<const netstring_t*>(net->net_type())) {
|
||||
if (method_name == "itoa") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("i")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_string_method$itoa",
|
||||
parm_names);
|
||||
|
|
@ -4228,7 +4418,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("i")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_string_method$hextoa",
|
||||
parm_names);
|
||||
|
|
@ -4236,7 +4425,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("i")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_string_method$octtoa",
|
||||
parm_names);
|
||||
|
|
@ -4244,7 +4432,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("i")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_string_method$bintoa",
|
||||
parm_names);
|
||||
|
|
@ -4252,7 +4439,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("r")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_string_method$realtoa",
|
||||
parm_names);
|
||||
|
|
@ -4265,7 +4451,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("index")
|
||||
};
|
||||
|
||||
return elaborate_sys_task_method_(des, scope, net, method_name,
|
||||
"$ivl_darray_method$delete",
|
||||
parm_names);
|
||||
|
|
@ -4302,7 +4487,6 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (net->queue_type()) {
|
||||
const netdarray_t*use_darray = net->darray_type();
|
||||
if (method_name == "push_back") {
|
||||
static const std::vector<perm_string> parm_names = {
|
||||
perm_string::literal("item")
|
||||
|
|
@ -4329,11 +4513,13 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
"$ivl_queue_method$insert",
|
||||
parm_names);
|
||||
} else if (method_name == "pop_front") {
|
||||
const netdarray_t*use_darray = net->darray_type();
|
||||
return elaborate_method_func_(scope, net,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
"$ivl_queue_method$pop_front");
|
||||
} else if (method_name == "pop_back") {
|
||||
const netdarray_t*use_darray = net->darray_type();
|
||||
return elaborate_method_func_(scope, net,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
|
|
|
|||
20
eval_tree.cc
20
eval_tree.cc
|
|
@ -26,6 +26,7 @@
|
|||
# include <cmath>
|
||||
|
||||
# include "netlist.h"
|
||||
# include "netclass.h"
|
||||
# include "ivl_assert.h"
|
||||
# include "netmisc.h"
|
||||
|
||||
|
|
@ -2182,6 +2183,25 @@ static bool get_array_info(const NetExpr*arg, long dim,
|
|||
left = range.get_msb();
|
||||
right = range.get_lsb();
|
||||
return false;
|
||||
}
|
||||
/* Class property (e.g. queue field): size is dynamic; defer to runtime
|
||||
* instead of folding to all-X in evaluate_array_funcs_. */
|
||||
if (const NetEProperty*prop = dynamic_cast<const NetEProperty*>(arg)) {
|
||||
const NetNet*obj = prop->get_sig();
|
||||
const netclass_t*cls = dynamic_cast<const netclass_t*>(obj->net_type());
|
||||
if (cls == 0) return true;
|
||||
ivl_type_t ptype = cls->get_prop_type(prop->property_idx());
|
||||
if (ptype == 0) return true;
|
||||
switch (ptype->base_type()) {
|
||||
case IVL_VT_DARRAY:
|
||||
case IVL_VT_QUEUE:
|
||||
case IVL_VT_STRING:
|
||||
defer = true;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/* The argument must be a signal that has enough dimensions. */
|
||||
const NetESignal*esig = dynamic_cast<const NetESignal*>(arg);
|
||||
|
|
|
|||
1
ivl.def
1
ivl.def
|
|
@ -337,6 +337,7 @@ ivl_type_packed_width
|
|||
ivl_type_prop_name
|
||||
ivl_type_prop_type
|
||||
ivl_type_properties
|
||||
ivl_type_queue_max
|
||||
ivl_type_signed
|
||||
|
||||
ivl_udp_init
|
||||
|
|
|
|||
|
|
@ -2400,6 +2400,10 @@ extern int ivl_type_properties(ivl_type_t net);
|
|||
extern const char* ivl_type_prop_name(ivl_type_t net, int idx);
|
||||
extern ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx);
|
||||
|
||||
/* Maximum element count for a queue type (0 = unbounded). Only valid
|
||||
* when ivl_type_base(net) == IVL_VT_QUEUE. */
|
||||
extern unsigned ivl_type_queue_max(ivl_type_t net);
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined (__CYGWIN__)
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,5 @@
|
|||
./ivltests/br1005.v:2: sorry: Queues inside classes are not yet supported.
|
||||
./ivltests/br1005.v:15: error: Enable of unknown task ``a.q.push_back''.
|
||||
./ivltests/br1005.v:16: error: Enable of unknown task ``a.q.push_back''.
|
||||
./ivltests/br1005.v:17: error: Enable of unknown task ``a.q.push_back''.
|
||||
./ivltests/br1005.v:18: error: Enable of unknown task ``a.q.push_back''.
|
||||
./ivltests/br1005.v:19: sorry: Method name nesting is not supported yet.
|
||||
./ivltests/br1005.v:19: : method path: q.pop_front
|
||||
./ivltests/br1005.v:19: error: Object test.a has no method "q.pop_front(...)".
|
||||
./ivltests/br1005.v:22: sorry: Method name nesting is not supported yet.
|
||||
./ivltests/br1005.v:22: : method path: q.pop_front
|
||||
./ivltests/br1005.v:22: error: Object test.a has no method "q.pop_front(...)".
|
||||
./ivltests/br1005.v:25: sorry: Method name nesting is not supported yet.
|
||||
./ivltests/br1005.v:25: : method path: q.pop_front
|
||||
./ivltests/br1005.v:25: error: Object test.a has no method "q.pop_front(...)".
|
||||
./ivltests/br1005.v:28: sorry: Method name nesting is not supported yet.
|
||||
./ivltests/br1005.v:28: : method path: q.pop_front
|
||||
./ivltests/br1005.v:28: error: Object test.a has no method "q.pop_front(...)".
|
||||
9 error(s) during elaboration.
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
PASSED
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// Regression: queue-typed class properties — push_front/push_back and
|
||||
// pop_front/pop_back. (VVP asm must recognize %store/prop/qf/* and
|
||||
// %qpop/prop/*; opcode_table must stay lexicographically sorted.)
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(val, exp) do \
|
||||
if (val !== exp) begin \
|
||||
$display("FAILED(%0d). expected %0d, got %0d", `__LINE__, exp, val); \
|
||||
failed = 1'b1; \
|
||||
end \
|
||||
while(0)
|
||||
|
||||
class C;
|
||||
int q[$];
|
||||
endclass
|
||||
|
||||
C c;
|
||||
int t;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.q.push_back(1);
|
||||
c.q.push_front(0);
|
||||
c.q.push_back(2);
|
||||
t = c.q.pop_back();
|
||||
`check(t, 32'd2);
|
||||
`check(c.q.size(), 32'd2);
|
||||
t = c.q.pop_front();
|
||||
`check(t, 32'd0);
|
||||
`check(c.q[0], 32'd1);
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -274,7 +274,6 @@ array_lval_select3a CE ivltests
|
|||
br605a EF ivltests
|
||||
br605b EF ivltests
|
||||
br971 EF ivltests
|
||||
br1005 CE,-g2009 ivltests
|
||||
br1015b CE,-g2009 ivltests
|
||||
br_ml20150315b CE,-g2009 ivltests
|
||||
sv_deferred_assert1 CE,-g2009 ivltests gold=sv_deferred_assert1.gold
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json
|
|||
sv_class_prop_nest_real1 vvp_tests/sv_class_prop_nest_real1.json
|
||||
sv_class_prop_nest_str1 vvp_tests/sv_class_prop_nest_str1.json
|
||||
sv_class_prop_nest_vec1 vvp_tests/sv_class_prop_nest_vec1.json
|
||||
sv_class_queue_prop_methods vvp_tests/sv_class_queue_prop_methods.json
|
||||
sv_class_task_expr_fail vvp_tests/sv_class_task_expr_fail.json
|
||||
sv_const1 vvp_tests/sv_const1.json
|
||||
sv_const2 vvp_tests/sv_const2.json
|
||||
|
|
@ -387,9 +388,9 @@ sv_queue_method_push_back_too_few_arg_fail vvp_tests/sv_queue_method_push_back_t
|
|||
sv_queue_method_push_back_too_many_arg_fail vvp_tests/sv_queue_method_push_back_too_many_arg_fail.json
|
||||
sv_queue_method_push_front_too_few_arg_fail vvp_tests/sv_queue_method_push_front_too_few_arg_fail.json
|
||||
sv_queue_method_push_front_too_many_arg_fail vvp_tests/sv_queue_method_push_front_too_many_arg_fail.json
|
||||
sv_string_method_substr_too_few_arg_fail vvp_tests/sv_string_method_substr_too_few_arg_fail.json
|
||||
sv_soft_packed_union vvp_tests/sv_soft_packed_union.json
|
||||
sv_soft_packed_union_fail1 vvp_tests/sv_soft_packed_union_fail1.json
|
||||
sv_string_method_substr_too_few_arg_fail vvp_tests/sv_string_method_substr_too_few_arg_fail.json
|
||||
sv_super_member_fail vvp_tests/sv_super_member_fail.json
|
||||
sv_type_identifier_ams_name_fields vvp_tests/sv_type_identifier_ams_name_fields.json
|
||||
sv_type_identifier_attribute_name vvp_tests/sv_type_identifier_attribute_name.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_class_queue_prop_methods.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "Classes are not supported",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
14
t-dll-api.cc
14
t-dll-api.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000-2025 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2000-2026 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2016 CERN Michele Castellana (michele.castellana@cern.ch)
|
||||
*
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
# include "discipline.h"
|
||||
# include "netclass.h"
|
||||
# include "netdarray.h"
|
||||
# include "netqueue.h"
|
||||
# include "netenum.h"
|
||||
# include "netvector.h"
|
||||
# include <cstdlib>
|
||||
|
|
@ -3308,6 +3309,17 @@ extern "C" ivl_type_t ivl_type_prop_type(ivl_type_t net, int idx)
|
|||
return class_type->get_prop_type(idx);
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_type_queue_max(ivl_type_t net)
|
||||
{
|
||||
if (net == 0) return 0;
|
||||
if (const netqueue_t*que = dynamic_cast<const netqueue_t*>(net)) {
|
||||
long max_idx = que->max_idx();
|
||||
if (max_idx < 0) return 0;
|
||||
return (unsigned)(max_idx + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int ivl_type_signed(ivl_type_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ static void show_prop_type(ivl_type_t ptype)
|
|||
show_prop_type_vector(ptype);
|
||||
break;
|
||||
case IVL_VT_DARRAY:
|
||||
case IVL_VT_QUEUE:
|
||||
case IVL_VT_CLASS:
|
||||
fprintf(vvp_out, "\"o\"");
|
||||
if (packed_dimensions > 0) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -375,6 +375,20 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_PROPERTY:
|
||||
if (ivl_expr_oper1(expr) == 0 &&
|
||||
(ivl_expr_value(expr) == IVL_VT_QUEUE ||
|
||||
ivl_expr_value(expr) == IVL_VT_DARRAY)) {
|
||||
ivl_signal_t clas = ivl_expr_signal(expr);
|
||||
unsigned pidx = ivl_expr_property_idx(expr);
|
||||
unsigned isq = ivl_expr_value(expr) == IVL_VT_QUEUE ? 1U : 0U;
|
||||
snprintf(buffer, sizeof buffer, "&PQ<v%p_0,%u,%u>",
|
||||
clas, pidx, isq);
|
||||
args[idx].text = strdup(buffer);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case IVL_EX_SIGNAL:
|
||||
case IVL_EX_SELECT:
|
||||
args[idx].stack = vec4_stack_need;
|
||||
|
|
@ -402,6 +416,10 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
switch (ivl_expr_value(expr)) {
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
case IVL_VT_QUEUE:
|
||||
case IVL_VT_DARRAY:
|
||||
/* Queue/darray element selects may still carry the
|
||||
* container ivl_expr_value; evaluate as vec4 like logic. */
|
||||
draw_eval_vec4(expr);
|
||||
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
|
||||
args[idx].str_flag = 0;
|
||||
|
|
@ -433,6 +451,20 @@ static void draw_vpi_taskfunc_args(const char*call_string,
|
|||
buffer[0] = 0;
|
||||
break;
|
||||
default:
|
||||
/* See eval_vec4.c:draw_eval_vec4 — indexed selects sometimes
|
||||
* carry an unexpected ivl_expr_value (e.g. NO_TYPE). */
|
||||
if (ivl_expr_type(expr) == IVL_EX_SELECT &&
|
||||
ivl_expr_oper2(expr) != 0) {
|
||||
draw_eval_vec4(expr);
|
||||
args[idx].vec_flag = ivl_expr_signed(expr)? 's' : 'u';
|
||||
args[idx].str_flag = 0;
|
||||
args[idx].real_flag = 0;
|
||||
args[idx].stack = vec4_stack_need;
|
||||
args[idx].vec_wid = ivl_expr_width(expr);
|
||||
vec4_stack_need += 1;
|
||||
buffer[0] = 0;
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, "%s:%u: Sorry, cannot generate code for argument %u.\n",
|
||||
ivl_expr_file(expr), ivl_expr_lineno(expr), idx+1);
|
||||
fprintf(vvp_out, "\nXXXX Unexpected argument: call_string=<%s>, arg=%u, type=%d\n",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2024 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -277,6 +277,15 @@ static void real_ex_pop(ivl_expr_t expr)
|
|||
fb = "f";
|
||||
|
||||
arg = ivl_expr_parm(expr, 0);
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%qpop/prop/%s/r %u;\n", fb, pidx);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
|
||||
|
||||
fprintf(vvp_out, " %%qpop/%s/real v%p_0;\n", fb, ivl_expr_signal(arg));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2012-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -167,6 +167,15 @@ static void string_ex_pop(ivl_expr_t expr)
|
|||
fb = "f";
|
||||
|
||||
arg = ivl_expr_parm(expr, 0);
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%qpop/prop/%s/str %u;\n", fb, pidx);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
|
||||
|
||||
fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg));
|
||||
|
|
|
|||
|
|
@ -917,6 +917,29 @@ static void draw_property_vec4(ivl_expr_t expr)
|
|||
{
|
||||
ivl_signal_t sig = ivl_expr_signal(expr);
|
||||
unsigned pidx = ivl_expr_property_idx(expr);
|
||||
/* Queue/dynamic-array property with index: index is oper1 (see
|
||||
* dll_target::expr_property). */
|
||||
ivl_expr_t index_ex = ivl_expr_oper1(expr);
|
||||
|
||||
if (index_ex) {
|
||||
ivl_type_t cls_type = ivl_signal_net_type(sig);
|
||||
ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx);
|
||||
if (ptype) {
|
||||
ivl_variable_type_t pbase = ivl_type_base(ptype);
|
||||
if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) {
|
||||
unsigned wid = ivl_expr_width(expr);
|
||||
draw_eval_expr_into_integer(index_ex, 3);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n",
|
||||
pidx, wid);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
if (ivl_expr_value(expr) == IVL_VT_BOOL) {
|
||||
fprintf(vvp_out, " %%cast2;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%prop/v %u;\n", pidx);
|
||||
|
|
@ -948,7 +971,31 @@ static void draw_select_vec4(ivl_expr_t expr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (ivl_expr_value(subexpr)==IVL_VT_DARRAY) {
|
||||
/* Class property that is a queue or dynamic array: c.q[idx] */
|
||||
if (ivl_expr_type(subexpr) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(subexpr);
|
||||
unsigned pidx = ivl_expr_property_idx(subexpr);
|
||||
ivl_type_t cls_type = ivl_signal_net_type(clas);
|
||||
ivl_type_t ptype = ivl_type_prop_type(cls_type, pidx);
|
||||
if (ptype) {
|
||||
ivl_variable_type_t pbase = ivl_type_base(ptype);
|
||||
if (pbase == IVL_VT_QUEUE || pbase == IVL_VT_DARRAY) {
|
||||
assert(base);
|
||||
draw_eval_expr_into_integer(base, 3);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%load/prop/dar/vec4 %u, %u;\n",
|
||||
pidx, wid);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
if (ivl_expr_value(expr) == IVL_VT_BOOL) {
|
||||
fprintf(vvp_out, " %%cast2;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ivl_expr_value(subexpr) == IVL_VT_DARRAY ||
|
||||
ivl_expr_value(subexpr) == IVL_VT_QUEUE) {
|
||||
ivl_signal_t sig = ivl_expr_signal(subexpr);
|
||||
assert(sig);
|
||||
assert( (ivl_signal_data_type(sig)==IVL_VT_DARRAY)
|
||||
|
|
@ -957,8 +1004,9 @@ static void draw_select_vec4(ivl_expr_t expr)
|
|||
assert(base);
|
||||
draw_eval_expr_into_integer(base, 3);
|
||||
fprintf(vvp_out, " %%load/dar/vec4 v%p_0;\n", sig);
|
||||
if (ivl_expr_value(expr) == IVL_VT_BOOL)
|
||||
if (ivl_expr_value(expr) == IVL_VT_BOOL) {
|
||||
fprintf(vvp_out, " %%cast2;\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -1011,12 +1059,23 @@ static void draw_darray_pop(ivl_expr_t expr)
|
|||
{
|
||||
const char*fb;
|
||||
|
||||
if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0)
|
||||
if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0) {
|
||||
fb = "b";
|
||||
else
|
||||
} else {
|
||||
fb = "f";
|
||||
}
|
||||
|
||||
ivl_expr_t arg = ivl_expr_parm(expr, 0);
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%qpop/prop/%s/v %u, %u;\n", fb, pidx,
|
||||
ivl_expr_width(expr));
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
return;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
|
||||
|
||||
fprintf(vvp_out, " %%qpop/%s/v v%p_0, %u;\n", fb, ivl_expr_signal(arg),
|
||||
|
|
@ -1049,6 +1108,18 @@ static void draw_sfunc_vec4(ivl_expr_t expr)
|
|||
return;
|
||||
}
|
||||
|
||||
if (strcmp(ivl_expr_name(expr), "$size")==0 && parm_count==1) {
|
||||
ivl_expr_t arg = ivl_expr_parm(expr, 0);
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t sig = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
draw_vpi_func_call(expr);
|
||||
}
|
||||
|
||||
|
|
@ -1357,7 +1428,10 @@ void draw_eval_vec4(ivl_expr_t expr)
|
|||
}
|
||||
|
||||
assert(ivl_expr_value(expr) == IVL_VT_BOOL ||
|
||||
ivl_expr_value(expr) == IVL_VT_VECTOR);
|
||||
ivl_expr_value(expr) == IVL_VT_VECTOR ||
|
||||
(ivl_expr_type(expr) == IVL_EX_SELECT &&
|
||||
ivl_expr_oper2(expr) != 0) ||
|
||||
ivl_expr_type(expr) == IVL_EX_PROPERTY);
|
||||
|
||||
switch (ivl_expr_type(expr)) {
|
||||
case IVL_EX_BINARY:
|
||||
|
|
|
|||
|
|
@ -1360,15 +1360,16 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net)
|
|||
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) {
|
||||
} else if (ivl_type_base(prop_type) == IVL_VT_DARRAY ||
|
||||
ivl_type_base(prop_type) == IVL_VT_QUEUE) {
|
||||
|
||||
int idx = 0;
|
||||
|
||||
/* The property is a darray, and there is no mux
|
||||
expression to the assignment is of an entire
|
||||
array object. */
|
||||
/* The property is a darray or queue, and there is no mux
|
||||
expression so the assignment is of an entire
|
||||
array/queue object. */
|
||||
errors += draw_eval_object(rval);
|
||||
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY\n", prop_idx, idx);
|
||||
fprintf(vvp_out, " %%store/prop/obj %d, %d; IVL_VT_DARRAY or QUEUE\n", prop_idx, idx);
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
|
||||
} else if (ivl_type_base(prop_type) == IVL_VT_CLASS) {
|
||||
|
|
|
|||
|
|
@ -1663,6 +1663,24 @@ static int show_delete_method(ivl_statement_t net)
|
|||
return 1;
|
||||
|
||||
ivl_expr_t parm = ivl_stmt_parm(net, 0);
|
||||
if (ivl_expr_type(parm) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(parm);
|
||||
unsigned pidx = ivl_expr_property_idx(parm);
|
||||
ivl_type_t sig_type = ivl_signal_net_type(clas);
|
||||
ivl_type_t queue_type = ivl_type_prop_type(sig_type, pidx);
|
||||
assert(ivl_type_base(queue_type) == IVL_VT_QUEUE);
|
||||
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
if (parm_count == 2) {
|
||||
draw_eval_expr_into_integer(ivl_stmt_parm(net, 1), 3);
|
||||
fprintf(vvp_out, " %%delete/prop/elem %u;\n", pidx);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%delete/prop/obj %u;\n", pidx);
|
||||
}
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(parm) == IVL_EX_SIGNAL);
|
||||
ivl_signal_t var = ivl_expr_signal(parm);
|
||||
|
||||
|
|
@ -1687,6 +1705,47 @@ static int show_insert_method(ivl_statement_t net)
|
|||
return 1;
|
||||
|
||||
ivl_expr_t parm0 = ivl_stmt_parm(net,0);
|
||||
if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(parm0);
|
||||
unsigned pidx = ivl_expr_property_idx(parm0);
|
||||
ivl_type_t sig_type = ivl_signal_net_type(clas);
|
||||
ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx);
|
||||
assert(ivl_type_base(var_type) == IVL_VT_QUEUE);
|
||||
|
||||
int idx = allocate_word();
|
||||
assert(idx >= 0);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx,
|
||||
ivl_type_queue_max(var_type));
|
||||
|
||||
ivl_type_t element_type = ivl_type_element(var_type);
|
||||
|
||||
ivl_expr_t parm1 = ivl_stmt_parm(net,1);
|
||||
draw_eval_expr_into_integer(parm1, 3);
|
||||
ivl_expr_t parm2 = ivl_stmt_parm(net,2);
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(parm2);
|
||||
fprintf(vvp_out, " %%qinsert/prop/r %u, %d;\n",
|
||||
pidx, idx);
|
||||
break;
|
||||
case IVL_VT_STRING:
|
||||
draw_eval_string(parm2);
|
||||
fprintf(vvp_out, " %%qinsert/prop/str %u, %d;\n",
|
||||
pidx, idx);
|
||||
break;
|
||||
default:
|
||||
draw_eval_vec4(parm2);
|
||||
fprintf(vvp_out, " %%qinsert/prop/v %u, %d, %u;\n",
|
||||
pidx, idx,
|
||||
ivl_type_packed_width(element_type));
|
||||
break;
|
||||
}
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
clr_word(idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL);
|
||||
ivl_signal_t var = ivl_expr_signal(parm0);
|
||||
ivl_type_t var_type = ivl_signal_net_type(var);
|
||||
|
|
@ -1740,6 +1799,45 @@ static int show_push_frontback_method(ivl_statement_t net, bool is_front)
|
|||
return 1;
|
||||
|
||||
ivl_expr_t parm0 = ivl_stmt_parm(net,0);
|
||||
if (ivl_expr_type(parm0) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(parm0);
|
||||
unsigned pidx = ivl_expr_property_idx(parm0);
|
||||
ivl_type_t sig_type = ivl_signal_net_type(clas);
|
||||
ivl_type_t var_type = ivl_type_prop_type(sig_type, pidx);
|
||||
assert(ivl_type_base(var_type) == IVL_VT_QUEUE);
|
||||
|
||||
int idx = allocate_word();
|
||||
assert(idx >= 0);
|
||||
fprintf(vvp_out, " %%load/obj v%p_0;\n", clas);
|
||||
fprintf(vvp_out, " %%ix/load %d, %u, 0;\n", idx,
|
||||
ivl_type_queue_max(var_type));
|
||||
|
||||
ivl_type_t element_type = ivl_type_element(var_type);
|
||||
|
||||
ivl_expr_t parm1 = ivl_stmt_parm(net,1);
|
||||
switch (ivl_type_base(element_type)) {
|
||||
case IVL_VT_REAL:
|
||||
draw_eval_real(parm1);
|
||||
fprintf(vvp_out, " %%store/prop/%s/r %u, %d;\n",
|
||||
type_code, pidx, idx);
|
||||
break;
|
||||
case IVL_VT_STRING:
|
||||
draw_eval_string(parm1);
|
||||
fprintf(vvp_out, " %%store/prop/%s/str %u, %d;\n",
|
||||
type_code, pidx, idx);
|
||||
break;
|
||||
default:
|
||||
draw_eval_vec4(parm1);
|
||||
fprintf(vvp_out, " %%store/prop/%s/v %u, %d, %u;\n",
|
||||
type_code, pidx, idx,
|
||||
ivl_type_packed_width(element_type));
|
||||
break;
|
||||
}
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
clr_word(idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ivl_expr_type(parm0) == IVL_EX_SIGNAL);
|
||||
ivl_signal_t var = ivl_expr_signal(parm0);
|
||||
ivl_type_t var_type = ivl_signal_net_type(var);
|
||||
|
|
|
|||
|
|
@ -286,6 +286,11 @@ void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit)
|
|||
assert(vpip_routines);
|
||||
vpip_routines->format_strength(str, value, bit);
|
||||
}
|
||||
char* vpip_format_pretty(vpiHandle ref)
|
||||
{
|
||||
assert(vpip_routines);
|
||||
return vpip_routines->format_pretty(ref);
|
||||
}
|
||||
void vpip_make_systf_system_defined(vpiHandle ref)
|
||||
{
|
||||
assert(vpip_routines);
|
||||
|
|
|
|||
|
|
@ -867,6 +867,35 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
|||
* be a binary string (can contain NULLs). */
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 'P':
|
||||
*idx += 1;
|
||||
if (plus != 0 || prec != -1) {
|
||||
vpi_printf("WARNING: %s:%d: invalid format %s%s.\n",
|
||||
info->filename, info->lineno, info->name, fmtb);
|
||||
}
|
||||
if (*idx >= info->nitems) {
|
||||
vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n",
|
||||
info->filename, info->lineno, info->name, fmtb);
|
||||
} else {
|
||||
char *pp = vpip_format_pretty(info->items[*idx]);
|
||||
if (pp == 0) {
|
||||
vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n",
|
||||
info->filename, info->lineno, info->name, fmtb);
|
||||
} else {
|
||||
char *cp = pp;
|
||||
if (width == -1) width = 0;
|
||||
size = strlen(cp) + 1;
|
||||
if ((signed)size < (width+1)) size = width+1;
|
||||
if (size > ini_size) result = realloc(result, size*sizeof(char));
|
||||
if (ljust == 0) sprintf(result, "%*s", width, cp);
|
||||
else sprintf(result, "%-*s", width, cp);
|
||||
free(pp);
|
||||
size = strlen(result) + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
vpi_printf("WARNING: %s:%d: unknown format %s%s.\n",
|
||||
info->filename, info->lineno, info->name, fmtb);
|
||||
|
|
@ -1215,6 +1244,7 @@ static int sys_check_args(vpiHandle callh, vpiHandle argv, const PLI_BYTE8*name,
|
|||
#endif
|
||||
case vpiClassVar:
|
||||
case vpiSysFuncCall:
|
||||
case vpiRegArray: /* dynamic arrays, queues, SV array vars */
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -641,6 +641,10 @@ extern DLLEXPORT void (*vlog_startup_routines[])(void);
|
|||
/* Format a scalar a la %v. The str points to a 4byte character
|
||||
buffer. The value must be a vpiStrengthVal. */
|
||||
extern void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit);
|
||||
/* Pretty-print a dynamic array or queue (including class property queues)
|
||||
* for %p. Returns a malloc'd string, or NULL if the handle is not
|
||||
* supported. Caller must free the returned pointer when non-NULL. */
|
||||
extern char* vpip_format_pretty(vpiHandle ref);
|
||||
/* Set the return value to return from the vvp run time. This is
|
||||
usually 0 or 1. This is the exit code that the vvp process
|
||||
returns, and in distinct from the finish_number that is an
|
||||
|
|
@ -696,7 +700,7 @@ extern void vpip_count_drivers(vpiHandle ref, unsigned idx,
|
|||
*/
|
||||
|
||||
// Increment the version number any time vpip_routines_s is changed.
|
||||
static const PLI_UINT32 vpip_routines_version = 1;
|
||||
static const PLI_UINT32 vpip_routines_version = 2;
|
||||
|
||||
typedef struct {
|
||||
vpiHandle (*register_cb)(p_cb_data);
|
||||
|
|
@ -737,6 +741,7 @@ typedef struct {
|
|||
s_vpi_vecval(*calc_clog2)(vpiHandle);
|
||||
void (*count_drivers)(vpiHandle, unsigned, unsigned [4]);
|
||||
void (*format_strength)(char*, s_vpi_value*, unsigned);
|
||||
char* (*format_pretty)(vpiHandle);
|
||||
void (*make_systf_system_defined)(vpiHandle);
|
||||
void (*mcd_rawwrite)(PLI_UINT32, const char*, size_t);
|
||||
void (*set_return_value)(int);
|
||||
|
|
|
|||
19
vvp/codes.h
19
vvp/codes.h
|
|
@ -150,6 +150,7 @@ extern bool of_LOAD_REAL(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_PROP_DAR_VEC4(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_OBJA(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_LOAD_STR(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -233,6 +234,24 @@ extern bool of_STORE_PROP_OBJ(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_STORE_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QB_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QB_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QB_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QF_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QF_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_PROP_QF_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QINSERT_PROP_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QINSERT_PROP_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QINSERT_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_B_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_B_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_B_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELETE_PROP_ELEM(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_DELETE_PROP_OBJ(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_R(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_STORE_QB_V(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -48,9 +48,13 @@ unsigned compile_errors = 0;
|
|||
|
||||
/*
|
||||
* The opcode table lists all the code mnemonics, along with their
|
||||
* opcode and operand types. The table is written sorted by mnemonic
|
||||
* so that it can be searched by binary search. The opcode_compare
|
||||
* function is a helper function for that lookup.
|
||||
* opcode and operand types. The table must be sorted lexicographically
|
||||
* by mnemonic string: compile_code() uses bsearch() on this array.
|
||||
* If the order is wrong, lookup fails and the assembler reports
|
||||
* "Invalid opcode" for otherwise valid instructions (e.g. class
|
||||
* property queue ops must sort among all %delete/*, %qpop/*, %store/*
|
||||
* names, not grouped by feature).
|
||||
* The opcode_compare function is a helper for that lookup.
|
||||
*/
|
||||
|
||||
enum operand_e {
|
||||
|
|
@ -151,6 +155,8 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%delayx", of_DELAYX, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%delete/elem",of_DELETE_ELEM,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
||||
{ "%delete/obj",of_DELETE_OBJ,1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%delete/prop/elem", of_DELETE_PROP_ELEM, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%delete/prop/obj", of_DELETE_PROP_OBJ, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%delete/tail",of_DELETE_TAIL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%disable", of_DISABLE, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%disable/flow", of_DISABLE_FLOW, 1, {OA_VPI_PTR,OA_NONE, OA_NONE} },
|
||||
|
|
@ -204,6 +210,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%load/dar/vec4",of_LOAD_DAR_VEC4,1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/obj", of_LOAD_OBJ, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/obja", of_LOAD_OBJA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%load/prop/dar/vec4", of_LOAD_PROP_DAR_VEC4, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%load/real", of_LOAD_REAL, 1,{OA_VPI_PTR, OA_NONE, OA_NONE} },
|
||||
{ "%load/str", of_LOAD_STR, 1,{OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%load/stra", of_LOAD_STRA, 2,{OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
|
|
@ -242,6 +249,7 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%pow/s", of_POW_S, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%pow/wr", of_POW_WR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%prop/obj",of_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%prop/queue/size", of_PROP_QUEUE_SIZE, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/r", of_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/str",of_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%prop/v", of_PROP_V, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
|
|
@ -250,6 +258,9 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%pushi/vec4",of_PUSHI_VEC4,3,{OA_BIT1, OA_BIT2, OA_NUMBER} },
|
||||
{ "%pushv/str", of_PUSHV_STR, 0,{OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%putc/str/vec4",of_PUTC_STR_VEC4,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%qinsert/prop/r", of_QINSERT_PROP_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%qinsert/prop/str", of_QINSERT_PROP_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%qinsert/prop/v", of_QINSERT_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%qinsert/real",of_QINSERT_REAL,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%qinsert/str", of_QINSERT_STR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%qinsert/v", of_QINSERT_V, 3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
|
|
@ -259,6 +270,12 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%qpop/f/real",of_QPOP_F_REAL,1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
||||
{ "%qpop/f/str", of_QPOP_F_STR, 1,{OA_FUNC_PTR,OA_NONE,OA_NONE} },
|
||||
{ "%qpop/f/v", of_QPOP_F_V, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
{ "%qpop/prop/b/r", of_QPOP_PROP_B_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%qpop/prop/b/str", of_QPOP_PROP_B_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%qpop/prop/b/v", of_QPOP_PROP_B_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%qpop/prop/f/r", of_QPOP_PROP_F_REAL, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%qpop/prop/f/str", of_QPOP_PROP_F_STR, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%qpop/prop/f/v", of_QPOP_PROP_F_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} },
|
||||
{ "%release/wr", of_RELEASE_WR, 2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} },
|
||||
|
|
@ -283,6 +300,12 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%store/obj", of_STORE_OBJ, 1, {OA_FUNC_PTR,OA_NONE, OA_NONE} },
|
||||
{ "%store/obja", of_STORE_OBJA, 2, {OA_ARR_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/obj",of_STORE_PROP_OBJ,2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/qb/r", of_STORE_PROP_QB_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/qb/str", of_STORE_PROP_QB_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/qb/v", of_STORE_PROP_QB_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%store/prop/qf/r", of_STORE_PROP_QF_R, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/qf/str", of_STORE_PROP_QF_STR, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%store/prop/qf/v", of_STORE_PROP_QF_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%store/prop/r", of_STORE_PROP_R, 1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/str",of_STORE_PROP_STR,1, {OA_NUMBER, OA_NONE, OA_NONE} },
|
||||
{ "%store/prop/v", of_STORE_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
|
|
|
|||
|
|
@ -344,6 +344,10 @@ class resolv_list_s {
|
|||
*/
|
||||
extern void functor_ref_lookup(vvp_net_t**ref, char*lab);
|
||||
|
||||
extern vpiHandle vpip_make_prop_queue_ref(char* class_label,
|
||||
unsigned prop_idx,
|
||||
unsigned is_queue_flag);
|
||||
|
||||
/*
|
||||
* This function schedules a lookup of the labeled instruction. The
|
||||
* code points to a code structure that points to the instruction
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ inline uint64_t strtouint64(const char*str, char**endptr, int base)
|
|||
|
||||
"&A" { return K_A; }
|
||||
"&APV" { return K_APV; }
|
||||
"&PQ" { return K_PQ; }
|
||||
"&PV" { return K_PV; }
|
||||
|
||||
"%"[.$_/a-zA-Z0-9]+ {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_NET K_NET_S K_NET_R K_NET_2S K_NET_2U
|
||||
%token K_NET8 K_NET8_2S K_NET8_2U K_NET8_S
|
||||
%token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV
|
||||
%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
|
||||
%token K_PART_V K_PART_V_S K_PORT K_PORT_INFO K_PQ K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
|
||||
%token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT
|
||||
%token K_RESOLV K_RTRAN K_RTRANIF0 K_RTRANIF1
|
||||
%token K_SCOPE K_SFUNC K_SFUNC_E K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
|
|
@ -1122,6 +1122,8 @@ symbol_access
|
|||
{ $$ = vpip_make_PV($3, $5, $7); }
|
||||
| K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_vthr_APV($3, $5, $7, $9); }
|
||||
| K_PQ '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER '>'
|
||||
{ $$ = vpip_make_prop_queue_ref($3, $5, $7); }
|
||||
;
|
||||
|
||||
/* functor operands can only be a list of symbols. */
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
# include "vpi_priv.h"
|
||||
# include "vvp_net_sig.h"
|
||||
# include "vvp_darray.h"
|
||||
# include "vvp_cobject.h"
|
||||
# include "array_common.h"
|
||||
# include "schedule.h"
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
|
|
@ -294,38 +295,23 @@ vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net)
|
|||
}
|
||||
|
||||
__vpiQueueVar::__vpiQueueVar(__vpiScope*sc, const char*na, vvp_net_t*ne)
|
||||
: __vpiBaseVar(sc, na, ne)
|
||||
: __vpiDarrayVar(sc, na, ne)
|
||||
{
|
||||
}
|
||||
|
||||
int __vpiQueueVar::get_type_code(void) const
|
||||
{ return vpiArrayVar; }
|
||||
|
||||
|
||||
int __vpiQueueVar::vpi_get(int code)
|
||||
{
|
||||
vvp_fun_signal_object*fun = dynamic_cast<vvp_fun_signal_object*> (get_net()->fun);
|
||||
assert(fun);
|
||||
vvp_object_t val = fun->get_object();
|
||||
const vvp_queue*aval = val.peek<vvp_queue>();
|
||||
|
||||
switch (code) {
|
||||
case vpiArrayType:
|
||||
return vpiQueueArray;
|
||||
case vpiSize:
|
||||
if (aval == 0)
|
||||
return 0;
|
||||
else
|
||||
return aval->get_size();
|
||||
|
||||
default:
|
||||
return 0;
|
||||
return __vpiDarrayVar::vpi_get(code);
|
||||
}
|
||||
}
|
||||
|
||||
void __vpiQueueVar::vpi_get_value(p_vpi_value val)
|
||||
{
|
||||
val->format = vpiSuppressVal;
|
||||
__vpiDarrayVar::vpi_get_value(val);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -339,9 +325,94 @@ vpiHandle vpip_make_queue_var(const char*name, vvp_net_t*net)
|
|||
return obj;
|
||||
}
|
||||
|
||||
__vpiPropQueueRef::__vpiPropQueueRef(__vpiScope*scope, unsigned pidx,
|
||||
bool is_queue)
|
||||
: class_net_(0), prop_idx_(pidx), is_queue_(is_queue), scope_(scope)
|
||||
{
|
||||
}
|
||||
|
||||
int __vpiPropQueueRef::get_type_code(void) const
|
||||
{ return vpiArrayVar; }
|
||||
|
||||
static vvp_darray* get_live_darray_from_prop(vvp_net_t* class_net, unsigned pid)
|
||||
{
|
||||
if (!class_net) return 0;
|
||||
vvp_fun_signal_object* fun = dynamic_cast<vvp_fun_signal_object*>(class_net->fun);
|
||||
if (!fun) return 0;
|
||||
vvp_object_t obj = fun->get_object();
|
||||
vvp_cobject* cobj = obj.peek<vvp_cobject>();
|
||||
if (!cobj) return 0;
|
||||
vvp_object_t qobj;
|
||||
cobj->get_object(pid, qobj, 0);
|
||||
return qobj.peek<vvp_darray>();
|
||||
}
|
||||
|
||||
int __vpiPropQueueRef::vpi_get(int code)
|
||||
{
|
||||
vvp_darray* aobj = get_live_darray_from_prop(class_net_, prop_idx_);
|
||||
switch (code) {
|
||||
case vpiArrayType:
|
||||
return is_queue_ ? vpiQueueArray : vpiDynamicArray;
|
||||
case vpiLeftRange:
|
||||
return 0;
|
||||
case vpiRightRange:
|
||||
return aobj ? (int) (aobj->get_size() - 1) : 0;
|
||||
case vpiSize:
|
||||
return aobj ? (int) aobj->get_size() : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char* __vpiPropQueueRef::vpi_get_str(int code)
|
||||
{
|
||||
if (code == vpiFile) {
|
||||
return simple_set_rbuf_str(file_names[0]);
|
||||
}
|
||||
return generic_get_str(code, scope_, "prop_darray", NULL);
|
||||
}
|
||||
|
||||
void __vpiPropQueueRef::vpi_get_value(p_vpi_value val)
|
||||
{
|
||||
val->format = vpiSuppressVal;
|
||||
}
|
||||
|
||||
vpiHandle vpip_make_prop_queue_ref(char* class_label, unsigned prop_idx,
|
||||
unsigned is_queue_flag)
|
||||
{
|
||||
__vpiPropQueueRef* obj = new __vpiPropQueueRef(vpip_peek_current_scope(),
|
||||
prop_idx,
|
||||
is_queue_flag != 0);
|
||||
functor_ref_lookup(&obj->class_net_, class_label);
|
||||
return obj;
|
||||
}
|
||||
|
||||
vvp_darray* vpip_vpi_darray_from_handle(vpiHandle ref)
|
||||
{
|
||||
if (!ref) return 0;
|
||||
|
||||
if (__vpiPropQueueRef* pr = dynamic_cast<__vpiPropQueueRef*>(ref)) {
|
||||
return get_live_darray_from_prop(pr->class_net_, pr->prop_idx_);
|
||||
}
|
||||
|
||||
if (__vpiDarrayVar* dv = dynamic_cast<__vpiDarrayVar*>(ref)) {
|
||||
vvp_fun_signal_object* fun = dynamic_cast<vvp_fun_signal_object*>(dv->get_net()->fun);
|
||||
if (!fun) return 0;
|
||||
vvp_object_t obj = fun->get_object();
|
||||
return obj.peek<vvp_darray>();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void array_delete(vpiHandle item)
|
||||
{
|
||||
if (__vpiPropQueueRef* pq = dynamic_cast<__vpiPropQueueRef*>(item)) {
|
||||
delete pq;
|
||||
return;
|
||||
}
|
||||
|
||||
__vpiDarrayVar*dobj = dynamic_cast<__vpiDarrayVar*>(item);
|
||||
if (dobj) {
|
||||
if (dobj->vals_words) delete [] (dobj->vals_words-1);
|
||||
|
|
@ -349,12 +420,6 @@ void array_delete(vpiHandle item)
|
|||
return;
|
||||
}
|
||||
|
||||
__vpiQueueVar*qobj = dynamic_cast<__vpiQueueVar*>(item);
|
||||
if (qobj) {
|
||||
delete qobj;
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Need support for deleting array type: %d\n", item->vpi_get(vpiArrayType));
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2098,6 +2098,7 @@ vpip_routines_s vpi_routines = {
|
|||
.calc_clog2 = vpip_calc_clog2,
|
||||
.count_drivers = vpip_count_drivers,
|
||||
.format_strength = vpip_format_strength,
|
||||
.format_pretty = vpip_format_pretty,
|
||||
.make_systf_system_defined = vpip_make_systf_system_defined,
|
||||
.mcd_rawwrite = vpip_mcd_rawwrite,
|
||||
.set_return_value = vpip_set_return_value,
|
||||
|
|
|
|||
|
|
@ -870,18 +870,40 @@ class __vpiDarrayVar : public __vpiBaseVar, public __vpiArrayBase {
|
|||
|
||||
extern vpiHandle vpip_make_darray_var(const char*name, vvp_net_t*net);
|
||||
|
||||
class __vpiQueueVar : public __vpiBaseVar {
|
||||
class __vpiQueueVar : public __vpiDarrayVar {
|
||||
|
||||
public:
|
||||
__vpiQueueVar(__vpiScope*scope, const char*name, vvp_net_t*net);
|
||||
|
||||
int get_type_code(void) const override;
|
||||
int vpi_get(int code) override;
|
||||
void vpi_get_value(p_vpi_value val) override;
|
||||
};
|
||||
|
||||
extern vpiHandle vpip_make_queue_var(const char*name, vvp_net_t*net);
|
||||
|
||||
class __vpiPropQueueRef : public __vpiHandle {
|
||||
|
||||
public:
|
||||
explicit __vpiPropQueueRef(__vpiScope*scope, unsigned pidx, bool is_queue);
|
||||
|
||||
int get_type_code(void) const override;
|
||||
int vpi_get(int code) override;
|
||||
char* vpi_get_str(int code) override;
|
||||
void vpi_get_value(p_vpi_value val) override;
|
||||
|
||||
vvp_net_t* class_net_;
|
||||
unsigned prop_idx_;
|
||||
bool is_queue_;
|
||||
|
||||
private:
|
||||
__vpiScope* scope_;
|
||||
};
|
||||
|
||||
extern vpiHandle vpip_make_prop_queue_ref(char* class_label,
|
||||
unsigned prop_idx,
|
||||
unsigned is_queue_flag);
|
||||
extern vvp_darray* vpip_vpi_darray_from_handle(vpiHandle ref);
|
||||
|
||||
class __vpiCobjectVar : public __vpiBaseVar {
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2003-2026 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -18,7 +18,15 @@
|
|||
*/
|
||||
|
||||
# include "vpi_user.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "vvp_darray.h"
|
||||
# include "vvp_net_sig.h"
|
||||
# include <cassert>
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <cstring>
|
||||
# include <string>
|
||||
# include "ivl_alloc.h"
|
||||
|
||||
static const char str_char1_table[257] = {
|
||||
".HS1M222" "W3333333" /* 00 0F */ "L4444444" "44444444" /* 10 1F */
|
||||
|
|
@ -104,3 +112,60 @@ extern "C" void vpip_format_strength(char*str, s_vpi_value*value, unsigned bit)
|
|||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
static char* vpip_format_pretty_string(const char*msg)
|
||||
{
|
||||
return strdup(msg);
|
||||
}
|
||||
|
||||
static char* format_darray_pretty(vvp_darray* aobj)
|
||||
{
|
||||
if (!aobj || aobj->get_size() == 0) return strdup("{}");
|
||||
|
||||
std::string out = "{";
|
||||
|
||||
for (size_t i = 0; i < aobj->get_size(); i += 1) {
|
||||
if (i > 0) out += ", ";
|
||||
if (dynamic_cast<vvp_darray_real*>(aobj)) {
|
||||
double d;
|
||||
aobj->get_word((unsigned) i, d);
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "%g", d);
|
||||
out += buf;
|
||||
} else if (dynamic_cast<vvp_darray_string*>(aobj)) {
|
||||
std::string s;
|
||||
aobj->get_word((unsigned) i, s);
|
||||
out += "\"";
|
||||
out += s;
|
||||
out += "\"";
|
||||
} else {
|
||||
vvp_vector4_t v;
|
||||
aobj->get_word((unsigned) i, v);
|
||||
s_vpi_value val;
|
||||
val.format = vpiDecStrVal;
|
||||
vpip_vec4_get_value(v, v.size(), false, &val);
|
||||
out += val.value.str;
|
||||
}
|
||||
}
|
||||
|
||||
out += "}";
|
||||
return strdup(out.c_str());
|
||||
}
|
||||
|
||||
extern "C" char* vpip_format_pretty(vpiHandle ref)
|
||||
{
|
||||
if (!ref) {
|
||||
return vpip_format_pretty_string("Handle is NULL");
|
||||
}
|
||||
|
||||
if (dynamic_cast<__vpiPropQueueRef*>(ref) ||
|
||||
dynamic_cast<__vpiDarrayVar*>(ref)) {
|
||||
vvp_darray* aobj = vpip_vpi_darray_from_handle(ref);
|
||||
if (!aobj) {
|
||||
return vpip_format_pretty_string("Object not found");
|
||||
}
|
||||
return format_darray_pretty(aobj);
|
||||
}
|
||||
|
||||
return vpip_format_pretty_string("Unsupported object type");
|
||||
}
|
||||
|
|
|
|||
316
vvp/vthread.cc
316
vvp/vthread.cc
|
|
@ -3873,6 +3873,36 @@ bool of_LOAD_DAR_VEC4(vthread_t thr, vvp_code_t cp)
|
|||
return load_dar<vvp_vector4_t>(thr, cp);
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/prop/dar/vec4 <pid>, <wid>;
|
||||
* Indexed read of queue/dynamic-array class property; object on stack,
|
||||
* index in words[3] (same as %load/dar/vec4).
|
||||
*/
|
||||
bool of_LOAD_PROP_DAR_VEC4(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
int64_t adr = thr->words[3].w_int;
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
vvp_object_t pobj;
|
||||
cobj->get_object(pid, pobj, 0);
|
||||
vvp_darray*darray = pobj.peek<vvp_darray>();
|
||||
|
||||
vvp_vector4_t word;
|
||||
if (darray && (adr >= 0) && (thr->flags[4] == BIT4_0)) {
|
||||
darray->get_word(adr, word);
|
||||
} else {
|
||||
dq_default(word, wid);
|
||||
}
|
||||
|
||||
thr->push_vec4(word);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* %load/obj <var-label>
|
||||
*/
|
||||
|
|
@ -5897,6 +5927,292 @@ bool of_STORE_PROP_V(vthread_t thr, vvp_code_t cp)
|
|||
return store_prop<vvp_vector4_t>(thr, cp, cp->bit_idx[0]);
|
||||
}
|
||||
|
||||
template <class QTYPE>
|
||||
static QTYPE* get_queue_prop(vvp_cobject*cobj, size_t pid)
|
||||
{
|
||||
vvp_object_t qobj;
|
||||
cobj->get_object(pid, qobj, 0);
|
||||
QTYPE* queue = qobj.peek<QTYPE>();
|
||||
if (queue == 0) {
|
||||
queue = new QTYPE;
|
||||
vvp_object_t val(queue);
|
||||
cobj->set_object(pid, val, 0);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool store_prop_qb(vthread_t thr, vvp_code_t cp, unsigned wid)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
ELEM value;
|
||||
unsigned max_size = thr->words[cp->bit_idx[0]].w_uint;
|
||||
pop_value(thr, value, wid);
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
QTYPE* queue = get_queue_prop<QTYPE>(cobj, pid);
|
||||
assert(queue);
|
||||
queue->push_back(value, max_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool store_prop_qf(vthread_t thr, vvp_code_t cp, unsigned wid)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
ELEM value;
|
||||
unsigned max_size = thr->words[cp->bit_idx[0]].w_uint;
|
||||
pop_value(thr, value, wid);
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
QTYPE* queue = get_queue_prop<QTYPE>(cobj, pid);
|
||||
assert(queue);
|
||||
queue->push_front(value, max_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QB_R(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qb<double, vvp_queue_real>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QB_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qb<string, vvp_queue_string>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QB_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qb<vvp_vector4_t, vvp_queue_vec4>(thr, cp, cp->bit_idx[1]);
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QF_R(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qf<double, vvp_queue_real>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QF_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qf<string, vvp_queue_string>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_STORE_PROP_QF_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return store_prop_qf<vvp_vector4_t, vvp_queue_vec4>(thr, cp, cp->bit_idx[1]);
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool qinsert_prop(vthread_t thr, vvp_code_t cp, unsigned wid)
|
||||
{
|
||||
int64_t idx = thr->words[3].w_int;
|
||||
ELEM value;
|
||||
size_t pid = cp->number;
|
||||
pop_value(thr, value, wid);
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
QTYPE* queue = get_queue_prop<QTYPE>(cobj, pid);
|
||||
assert(queue);
|
||||
if (idx < 0) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: cannot insert at a negative "
|
||||
<< get_queue_type(value)
|
||||
<< " index (" << idx << "). ";
|
||||
print_queue_value(value);
|
||||
cerr << " was not added." << endl;
|
||||
} else if (thr->flags[4] != BIT4_0) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: cannot insert at an undefined "
|
||||
<< get_queue_type(value) << " index. ";
|
||||
print_queue_value(value);
|
||||
cerr << " was not added." << endl;
|
||||
} else {
|
||||
unsigned max_size = thr->words[cp->bit_idx[0]].w_int;
|
||||
queue->insert(idx, value, max_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QINSERT_PROP_R(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qinsert_prop<double, vvp_queue_real>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QINSERT_PROP_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qinsert_prop<string, vvp_queue_string>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QINSERT_PROP_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qinsert_prop<vvp_vector4_t, vvp_queue_vec4>(thr, cp, cp->bit_idx[1]);
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool q_pop_prop(vthread_t thr, vvp_code_t cp,
|
||||
void (*get_val_func)(vvp_queue*, ELEM&),
|
||||
const char*loc, unsigned wid)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
QTYPE* queue = get_queue_prop<QTYPE>(cobj, pid);
|
||||
assert(queue);
|
||||
|
||||
size_t size = queue->get_size();
|
||||
|
||||
ELEM value;
|
||||
if (size) {
|
||||
get_val_func(queue, value);
|
||||
} else {
|
||||
dq_default(value, wid);
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: pop_" << loc << "() on empty "
|
||||
<< get_queue_type(value) << "." << endl;
|
||||
}
|
||||
|
||||
push_value(thr, value, wid);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool qpop_b_prop(vthread_t thr, vvp_code_t cp, unsigned wid)
|
||||
{
|
||||
return q_pop_prop<ELEM, QTYPE>(thr, cp, get_back_value<ELEM>, "back", wid);
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool qpop_f_prop(vthread_t thr, vvp_code_t cp, unsigned wid)
|
||||
{
|
||||
return q_pop_prop<ELEM, QTYPE>(thr, cp, get_front_value<ELEM>, "front", wid);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_B_REAL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_b_prop<double, vvp_queue_real>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_B_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_b_prop<string, vvp_queue_string>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_B_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_b_prop<vvp_vector4_t, vvp_queue_vec4>(thr, cp, cp->bit_idx[0]);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_F_REAL(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_f_prop<double, vvp_queue_real>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_F_STR(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_f_prop<string, vvp_queue_string>(thr, cp, 0);
|
||||
}
|
||||
|
||||
bool of_QPOP_PROP_F_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
return qpop_f_prop<vvp_vector4_t, vvp_queue_vec4>(thr, cp, cp->bit_idx[0]);
|
||||
}
|
||||
|
||||
bool of_PROP_QUEUE_SIZE(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
vvp_object_t qobj;
|
||||
cobj->get_object(pid, qobj, 0);
|
||||
vvp_queue* queue = qobj.peek<vvp_queue>();
|
||||
|
||||
size_t sz = queue ? queue->get_size() : 0;
|
||||
|
||||
vvp_vector4_t val(32, BIT4_0);
|
||||
unsigned long ul = sz;
|
||||
for (unsigned idx = 0; idx < 32; idx++) {
|
||||
if (ul & 1UL) {
|
||||
val.set_bit(idx, BIT4_1);
|
||||
} else {
|
||||
val.set_bit(idx, BIT4_0);
|
||||
}
|
||||
ul >>= 1;
|
||||
}
|
||||
thr->push_vec4(val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_DELETE_PROP_ELEM(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
|
||||
int64_t idx_val = thr->words[3].w_int;
|
||||
if (thr->flags[4] == BIT4_1) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: skipping queue delete() with undefined index."
|
||||
<< endl;
|
||||
return true;
|
||||
}
|
||||
if (idx_val < 0) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: skipping queue delete() with negative index."
|
||||
<< endl;
|
||||
return true;
|
||||
}
|
||||
size_t idx = idx_val;
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
vvp_object_t qobj;
|
||||
cobj->get_object(pid, qobj, 0);
|
||||
vvp_queue* queue = qobj.peek<vvp_queue>();
|
||||
if (queue == 0) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: skipping delete(" << idx
|
||||
<< ") on empty queue." << endl;
|
||||
} else {
|
||||
size_t size = queue->get_size();
|
||||
if (idx >= size) {
|
||||
cerr << thr->get_fileline()
|
||||
<< "Warning: skipping out of range delete(" << idx
|
||||
<< ") on queue of size " << size << "." << endl;
|
||||
} else {
|
||||
queue->erase(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_DELETE_PROP_OBJ(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
|
||||
vvp_object_t& top = thr->peek_object();
|
||||
vvp_cobject*cobj = top.peek<vvp_cobject>();
|
||||
assert(cobj);
|
||||
|
||||
cobj->set_object(pid, vvp_object_t(), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ELEM, class QTYPE>
|
||||
static bool store_qb(vthread_t thr, vvp_code_t cp, unsigned wid=0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ vpi_vprintf
|
|||
vpip_calc_clog2
|
||||
vpip_count_drivers
|
||||
vpip_format_strength
|
||||
vpip_format_pretty
|
||||
vpip_make_systf_system_defined
|
||||
vpip_mcd_rawwrite
|
||||
vpip_set_return_value
|
||||
|
|
|
|||
Loading…
Reference in New Issue