Merge d2d16717d3 into a4989d023d
This commit is contained in:
commit
098afa608c
357
elab_expr.cc
357
elab_expr.cc
|
|
@ -47,6 +47,7 @@
|
|||
using namespace std;
|
||||
|
||||
static netqueue_t ivl_queue_unique_index_ret(&netvector_t::atom2s32, -1);
|
||||
static netqueue_t ivl_queue_string_ret(&netstring_t::type_string, -1);
|
||||
|
||||
static bool queue_method_element_is_integral_vec4(ivl_type_t et)
|
||||
{
|
||||
|
|
@ -54,6 +55,106 @@ static bool queue_method_element_is_integral_vec4(ivl_type_t et)
|
|||
return bt == IVL_VT_BOOL || bt == IVL_VT_LOGIC;
|
||||
}
|
||||
|
||||
/* Locator methods: integral vec4 always; string only for find*. */
|
||||
static bool locator_method_element_supported(ivl_type_t et, perm_string method)
|
||||
{
|
||||
if (queue_method_element_is_integral_vec4(et))
|
||||
return true;
|
||||
if (ivl_type_base(et) != IVL_VT_STRING)
|
||||
return false;
|
||||
return method == "find" || method == "find_index" ||
|
||||
method == "find_first" || method == "find_first_index" ||
|
||||
method == "find_last" || method == "find_last_index";
|
||||
}
|
||||
|
||||
/*
|
||||
* No-parens forms (e.g. qi = s.unique) elaborate as PEIdent. Build the
|
||||
* same NetESFunc used for s.unique() / queue methods.
|
||||
*/
|
||||
static NetExpr* elab_array_locator_noparens(Design* des, const LineInfo& loc,
|
||||
NetNet* net, perm_string method_name,
|
||||
const char* kind)
|
||||
{
|
||||
const netdarray_t* dar = net->darray_type();
|
||||
ivl_assert(loc, dar);
|
||||
ivl_type_t element_type = dar->element_type();
|
||||
const netqueue_t* queue = net->queue_type();
|
||||
ivl_type_t value_rtype = queue
|
||||
? static_cast<ivl_type_t>(queue)
|
||||
: (ivl_type_base(element_type) == IVL_VT_STRING
|
||||
? static_cast<ivl_type_t>(&ivl_queue_string_ret)
|
||||
: static_cast<ivl_type_t>(dar));
|
||||
|
||||
if (method_name == "size") {
|
||||
NetESFunc*fun = new NetESFunc("$size", &netvector_t::atom2s32, 1);
|
||||
fun->set_line(loc);
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
|
||||
if (method_name == "unique" || method_name == "unique_index" ||
|
||||
method_name == "min" || method_name == "max" ||
|
||||
method_name == "sum" || method_name == "product" ||
|
||||
method_name == "and" || method_name == "or" ||
|
||||
method_name == "xor") {
|
||||
if (method_name == "sum" || method_name == "product" ||
|
||||
method_name == "and" || method_name == "or" ||
|
||||
method_name == "xor") {
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << loc.get_fileline() << ": sorry: " << kind << " "
|
||||
<< method_name << "() for this "
|
||||
<< "element type is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
} else if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << loc.get_fileline() << ": sorry: " << kind << " "
|
||||
<< method_name << "() for this "
|
||||
<< "element type is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ivl_type_t result_type;
|
||||
char sfunc[64];
|
||||
if (method_name == "unique_index") {
|
||||
result_type = &ivl_queue_unique_index_ret;
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$unique_index");
|
||||
} else if (method_name == "sum" || method_name == "product" ||
|
||||
method_name == "and" || method_name == "or" ||
|
||||
method_name == "xor") {
|
||||
result_type = element_type;
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
|
||||
method_name.str());
|
||||
} else {
|
||||
result_type = value_rtype;
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
|
||||
method_name.str());
|
||||
}
|
||||
NetESFunc*fun = new NetESFunc(sfunc, result_type, 1);
|
||||
fun->set_line(loc);
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
|
||||
if (method_name == "find" || method_name == "find_index" ||
|
||||
method_name == "find_first" || method_name == "find_first_index" ||
|
||||
method_name == "find_last" || method_name == "find_last_index") {
|
||||
cerr << loc.get_fileline() << ": error: Array locator method `"
|
||||
<< method_name << "' must be called with one "
|
||||
<< "argument, e.g. " << method_name << "(value)."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* One argument: value to match using == (same as find with (item == arg)). */
|
||||
static NetExpr* elab_queue_locator_cmp_arg(Design* des, NetScope* scope,
|
||||
const LineInfo& loc,
|
||||
|
|
@ -91,12 +192,19 @@ static NetExpr* elab_queue_locator_with_predicate(
|
|||
NetScope::BEGIN_END);
|
||||
ws->set_line(&loc);
|
||||
|
||||
unsigned ew = ivl_type_packed_width(element_type);
|
||||
const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type),
|
||||
(long)ew - 1, 0,
|
||||
ivl_type_signed(element_type));
|
||||
NetNet* item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
|
||||
item_vec);
|
||||
NetNet* item_net;
|
||||
unsigned ew = 0;
|
||||
if (ivl_type_base(element_type) == IVL_VT_STRING) {
|
||||
item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
|
||||
&netstring_t::type_string);
|
||||
} else {
|
||||
ew = ivl_type_packed_width(element_type);
|
||||
const netvector_t* item_vec = new netvector_t(ivl_type_base(element_type),
|
||||
(long)ew - 1, 0,
|
||||
ivl_type_signed(element_type));
|
||||
item_net = new NetNet(ws, lex_strings.make("item"), NetNet::REG,
|
||||
item_vec);
|
||||
}
|
||||
item_net->set_line(loc);
|
||||
item_net->local_flag(true);
|
||||
|
||||
|
|
@ -106,7 +214,9 @@ static NetExpr* elab_queue_locator_with_predicate(
|
|||
index_net->local_flag(true);
|
||||
|
||||
NetExpr* pred = 0;
|
||||
if (method_suffix == "sum" || method_suffix == "product") {
|
||||
if (method_suffix == "sum" || method_suffix == "product" ||
|
||||
method_suffix == "and" || method_suffix == "or" ||
|
||||
method_suffix == "xor") {
|
||||
pred = elab_and_eval(des, ws, with_expr, (int)ew, false, false,
|
||||
ivl_type_base(element_type));
|
||||
} else {
|
||||
|
|
@ -140,6 +250,12 @@ static NetExpr* elab_queue_locator_with_predicate(
|
|||
sfunc_name = lex_strings.make("$ivl_queue_method$sum_with");
|
||||
} else if (method_suffix == "product") {
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$product_with");
|
||||
} else if (method_suffix == "and") {
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$and_with");
|
||||
} else if (method_suffix == "or") {
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$or_with");
|
||||
} else if (method_suffix == "xor") {
|
||||
sfunc_name = lex_strings.make("$ivl_queue_method$xor_with");
|
||||
} else {
|
||||
ivl_assert(loc, 0);
|
||||
}
|
||||
|
|
@ -182,7 +298,7 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
|
|||
const vector<named_pexpr_t>& parms,
|
||||
PExpr* with_expr, const char* kind)
|
||||
{
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
if (!locator_method_element_supported(element_type, method_name)) {
|
||||
cerr << loc.get_fileline() << ": sorry: " << kind << " "
|
||||
<< method_name << "() for this "
|
||||
<< "element type is not yet supported." << endl;
|
||||
|
|
@ -190,9 +306,16 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
ivl_type_t use_value_type = value_queue_type;
|
||||
if (!locator_returns_indices(method_name) &&
|
||||
ivl_type_base(element_type) == IVL_VT_STRING &&
|
||||
ivl_type_base(value_queue_type) == IVL_VT_DARRAY) {
|
||||
use_value_type = &ivl_queue_string_ret;
|
||||
}
|
||||
|
||||
ivl_type_t result_type = locator_returns_indices(method_name)
|
||||
? static_cast<ivl_type_t>(&ivl_queue_unique_index_ret)
|
||||
: value_queue_type;
|
||||
: use_value_type;
|
||||
|
||||
char sfunc[64];
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str());
|
||||
|
|
@ -237,11 +360,41 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
|
|||
|
||||
static bool is_array_reduction_method(perm_string name)
|
||||
{
|
||||
return name == "sum" || name == "product";
|
||||
return name == "sum" || name == "product" ||
|
||||
name == "and" || name == "or" || name == "xor";
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate sum()/product() on a queue or dynamic array expression.
|
||||
* LRM 7.12.4: iterator index querying. In `with` predicates the iterator
|
||||
* exposes `.index`. Icarus models that as a sibling local net named `index`
|
||||
* in the synthetic `$ivl_qwith*` scope; map `item.index` to that net.
|
||||
*/
|
||||
static NetExpr* elab_array_iterator_index_query(const LineInfo& loc,
|
||||
const symbol_search_results& sr)
|
||||
{
|
||||
if (!sr.net || sr.path_tail.size() != 1)
|
||||
return 0;
|
||||
if (sr.path_tail.front().name != "index" ||
|
||||
!sr.path_tail.front().index.empty())
|
||||
return 0;
|
||||
if (sr.net->name() != "item")
|
||||
return 0;
|
||||
NetScope* sc = sr.net->scope();
|
||||
if (!sc)
|
||||
return 0;
|
||||
perm_string sn = sc->basename();
|
||||
if (!sn.str() || strncmp(sn.str(), "$ivl_qwith", 10) != 0)
|
||||
return 0;
|
||||
NetNet* idx = sc->find_signal(lex_strings.make("index"));
|
||||
if (!idx)
|
||||
return 0;
|
||||
NetESignal* tmp = new NetESignal(idx);
|
||||
tmp->set_line(loc);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate sum()/product()/and()/or()/xor() on a queue or dynamic array.
|
||||
* Returns an integral value with the element type/width.
|
||||
*/
|
||||
static NetExpr* elab_array_reduction_method(Design* des, NetScope* scope,
|
||||
|
|
@ -1900,7 +2053,9 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
|||
return expr_width_;
|
||||
}
|
||||
|
||||
if (method_name == "sum" || method_name == "product") {
|
||||
if (method_name == "sum" || method_name == "product" ||
|
||||
method_name == "and" || method_name == "or" ||
|
||||
method_name == "xor") {
|
||||
expr_type_ = darray->element_base_type();
|
||||
expr_width_ = darray->element_width();
|
||||
min_width_ = expr_width_;
|
||||
|
|
@ -5145,6 +5300,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
NetNet *net = sr.net;
|
||||
|
||||
if (NetExpr* idxq = elab_array_iterator_index_query(*this, sr))
|
||||
return idxq;
|
||||
|
||||
if (!sr.path_tail.empty()) {
|
||||
if (net->struct_type()) {
|
||||
return check_for_struct_members(this, des, scope, net,
|
||||
|
|
@ -5261,6 +5419,24 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
if (member_comp.name == "and" || member_comp.name == "or" ||
|
||||
member_comp.name == "xor") {
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
||||
<< "() for this element type is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
char sfunc[64];
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
|
||||
member_comp.name.str());
|
||||
NetESFunc*fun = new NetESFunc(sfunc, element_type, 1);
|
||||
fun->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
arg->set_line(*sr.net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
if (member_comp.name == "min" || member_comp.name == "max") {
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
||||
|
|
@ -5284,6 +5460,21 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Dynamic array methods without parentheses (e.g. qi = s.unique).
|
||||
// Must run before the typed assign fallthrough that treats path_tail
|
||||
// as a field and compares the array to the context queue type.
|
||||
if (sr.net->darray_type() && !sr.net->queue_type() &&
|
||||
(path_.size() > 1 || !sr.path_tail.empty())) {
|
||||
const name_component_t member_comp = !sr.path_tail.empty()
|
||||
? sr.path_tail.front()
|
||||
: path_.back();
|
||||
NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net,
|
||||
member_comp.name,
|
||||
"dynamic array");
|
||||
if (tmp) return tmp;
|
||||
if (des->errors) return 0;
|
||||
}
|
||||
|
||||
ivl_type_t check_type = ntype;
|
||||
if (const netdarray_t*array_type = dynamic_cast<const netdarray_t*> (ntype)) {
|
||||
if (array_type->type_compatible(net->net_type()) &&
|
||||
|
|
@ -5473,6 +5664,9 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
if (!check_interface_modport_access(this, des, sr, false))
|
||||
return 0;
|
||||
|
||||
if (NetExpr* idxq = elab_array_iterator_index_query(*this, sr))
|
||||
return idxq;
|
||||
|
||||
if (NEED_CONST & flags) {
|
||||
cerr << get_fileline() << ": error: A reference to a net "
|
||||
"or variable (`" << path_ << "') is not allowed in "
|
||||
|
|
@ -5611,6 +5805,27 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
if (member_comp.name == "product" ||
|
||||
member_comp.name == "and" || member_comp.name == "or" ||
|
||||
member_comp.name == "xor") {
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue "
|
||||
<< member_comp.name
|
||||
<< "() for this element type is not yet supported."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
char sfunc[64];
|
||||
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s",
|
||||
member_comp.name.str());
|
||||
NetESFunc*fun = new NetESFunc(sfunc, element_type, 1);
|
||||
fun->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
arg->set_line(*sr.net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
}
|
||||
if (member_comp.name == "min" || member_comp.name == "max") {
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
||||
|
|
@ -5632,118 +5847,24 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
|||
|
||||
// Dynamic array (not queue) — array location / reduction methods.
|
||||
if (sr.net->darray_type() && !sr.net->queue_type() &&
|
||||
!sr.path_tail.empty()) {
|
||||
(path_.size() > 1 || !sr.path_tail.empty())) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_expr: "
|
||||
"Ident " << sr.path_head
|
||||
<< " looking for array property " << sr.path_tail
|
||||
<< " looking for array property "
|
||||
<< (sr.path_tail.empty() ? path_.back().name
|
||||
: sr.path_tail.front().name)
|
||||
<< endl;
|
||||
}
|
||||
|
||||
ivl_assert(*this, sr.path_tail.size() == 1);
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
if (member_comp.name == "size") {
|
||||
NetESFunc*fun = new NetESFunc("$size",
|
||||
&netvector_t::atom2s32,
|
||||
1);
|
||||
fun->set_line(*this);
|
||||
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
arg->set_line(*sr.net);
|
||||
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
} else if (member_comp.name == "find" ||
|
||||
member_comp.name == "find_index" ||
|
||||
member_comp.name == "find_first" ||
|
||||
member_comp.name == "find_first_index" ||
|
||||
member_comp.name == "find_last" ||
|
||||
member_comp.name == "find_last_index") {
|
||||
cerr << get_fileline() << ": error: Array locator method `"
|
||||
<< member_comp.name << "' must be called with one "
|
||||
<< "argument, e.g. " << member_comp.name << "(value)."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "min") {
|
||||
cerr << get_fileline() << ": sorry: 'min()' "
|
||||
"array location method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "max") {
|
||||
cerr << get_fileline() << ": sorry: 'max()' "
|
||||
"array location method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "unique") {
|
||||
cerr << get_fileline() << ": sorry: 'unique()' "
|
||||
"array location method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "unique_index") {
|
||||
cerr << get_fileline() << ": sorry: 'unique_index()' "
|
||||
"array location method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
// FIXME: Check this is a real or integral type.
|
||||
} else if (member_comp.name == "sum") {
|
||||
const netdarray_t* dar_sum = sr.net->darray_type();
|
||||
ivl_assert(*this, dar_sum);
|
||||
ivl_type_t element_type = dar_sum->element_type();
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: dynamic array sum() for this "
|
||||
<< "element type is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetESFunc*fun = new NetESFunc("$ivl_queue_method$sum",
|
||||
element_type, 1);
|
||||
fun->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
arg->set_line(*sr.net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
} else if (member_comp.name == "product") {
|
||||
const netdarray_t* dar_sum = sr.net->darray_type();
|
||||
ivl_assert(*this, dar_sum);
|
||||
ivl_type_t element_type = dar_sum->element_type();
|
||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||
cerr << get_fileline() << ": sorry: dynamic array product() for this "
|
||||
<< "element type is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
NetESFunc*fun = new NetESFunc("$ivl_queue_method$product",
|
||||
element_type, 1);
|
||||
fun->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
arg->set_line(*sr.net);
|
||||
fun->parm(0, arg);
|
||||
return fun;
|
||||
// FIXME: Check this is only an integral type.
|
||||
} else if (member_comp.name == "and") {
|
||||
cerr << get_fileline() << ": sorry: 'and()' "
|
||||
"array reduction method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "or") {
|
||||
cerr << get_fileline() << ": sorry: 'or()' "
|
||||
"array reduction method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
} else if (member_comp.name == "xor") {
|
||||
cerr << get_fileline() << ": sorry: 'xor()' "
|
||||
"array reduction method is not currently "
|
||||
"implemented." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
const name_component_t member_comp = !sr.path_tail.empty()
|
||||
? sr.path_tail.front()
|
||||
: path_.back();
|
||||
NetExpr*tmp = elab_array_locator_noparens(des, *this, sr.net,
|
||||
member_comp.name,
|
||||
"dynamic array");
|
||||
if (tmp) return tmp;
|
||||
if (des->errors) return 0;
|
||||
}
|
||||
|
||||
if ((sr.net->data_type() == IVL_VT_STRING) && !sr.path_tail.empty()) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
// Regression: dynamic array and()/or()/xor() reductions (LRM 7.12.3).
|
||||
|
||||
module top;
|
||||
|
||||
bit failed = 0;
|
||||
|
||||
`define CHK(cond) \
|
||||
if (!(cond)) begin \
|
||||
$display("FAILED line %0d", `__LINE__); \
|
||||
failed = 1; \
|
||||
end
|
||||
|
||||
byte b[];
|
||||
int y;
|
||||
|
||||
initial begin
|
||||
b = '{1, 3, 5, 7};
|
||||
y = b.and;
|
||||
`CHK(y === 1);
|
||||
|
||||
b = '{1, 2, 3, 4};
|
||||
y = b.or;
|
||||
`CHK(y === 7);
|
||||
y = b.xor;
|
||||
`CHK(y === 4);
|
||||
|
||||
b = new[0];
|
||||
y = b.and;
|
||||
`CHK(y === -1);
|
||||
y = b.or;
|
||||
`CHK(y === 0);
|
||||
y = b.xor;
|
||||
`CHK(y === 0);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -12,6 +12,9 @@ module top;
|
|||
|
||||
int array[] = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
|
||||
int res[$];
|
||||
string s[] = '{"hello", "sad", "hello", "world"};
|
||||
string qs[$];
|
||||
int qi[$];
|
||||
|
||||
initial begin
|
||||
res = array.find() with (item > 3);
|
||||
|
|
@ -42,6 +45,30 @@ module top;
|
|||
`CHK(res.size == 1);
|
||||
`CHK(res[0] == 8);
|
||||
|
||||
qs = s.find with (item == "sad");
|
||||
`CHK(qs.size == 1);
|
||||
`CHK(qs[0] == "sad");
|
||||
|
||||
qs = s.find_first with (item == "hello");
|
||||
`CHK(qs.size == 1);
|
||||
`CHK(qs[0] == "hello");
|
||||
|
||||
qs = s.find_last with (item == "hello");
|
||||
`CHK(qs.size == 1);
|
||||
`CHK(qs[0] == "hello");
|
||||
|
||||
qi = s.find_index with (item == "world");
|
||||
`CHK(qi.size == 1);
|
||||
`CHK(qi[0] == 3);
|
||||
|
||||
qi = s.find_first_index with (item == "hello");
|
||||
`CHK(qi.size == 1);
|
||||
`CHK(qi[0] == 0);
|
||||
|
||||
qi = s.find_last_index with (item == "hello");
|
||||
`CHK(qi.size == 1);
|
||||
`CHK(qi[0] == 2);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// Regression: iterator index querying item.index in with() (LRM 7.12.4).
|
||||
|
||||
module top;
|
||||
|
||||
bit failed = 0;
|
||||
|
||||
`define CHK(cond) \
|
||||
if (!(cond)) begin \
|
||||
$display("FAILED line %0d", `__LINE__); \
|
||||
failed = 1; \
|
||||
end
|
||||
|
||||
int arr[] = '{0, 1, 3, 3};
|
||||
int q[$];
|
||||
|
||||
initial begin
|
||||
q = arr.find with (item == item.index);
|
||||
`CHK(q.size == 3);
|
||||
`CHK(q[0] == 0);
|
||||
`CHK(q[1] == 1);
|
||||
`CHK(q[2] == 3);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -25,6 +25,13 @@ module top;
|
|||
`CHK(r[0] == 7);
|
||||
`CHK(r[1] == 7);
|
||||
|
||||
r = a.min;
|
||||
`CHK(r.size == 2);
|
||||
`CHK(r[0] == 1);
|
||||
r = a.max;
|
||||
`CHK(r.size == 2);
|
||||
`CHK(r[0] == 7);
|
||||
|
||||
r = empty.min();
|
||||
`CHK(r.size == 0);
|
||||
r = empty.max();
|
||||
|
|
|
|||
|
|
@ -23,6 +23,21 @@ module top;
|
|||
`CHK(ix[1] == 1);
|
||||
`CHK(ix[2] == 3);
|
||||
|
||||
// No-parentheses forms (sv-tests style), including assign to queue then sort.
|
||||
u = a.unique;
|
||||
u.sort;
|
||||
`CHK(u.size == 3);
|
||||
`CHK(u[0] == 1);
|
||||
`CHK(u[1] == 2);
|
||||
`CHK(u[2] == 3);
|
||||
|
||||
ix = a.unique_index;
|
||||
ix.sort;
|
||||
`CHK(ix.size == 3);
|
||||
`CHK(ix[0] == 0);
|
||||
`CHK(ix[1] == 1);
|
||||
`CHK(ix[2] == 3);
|
||||
|
||||
if (!failed)
|
||||
$display("PASSED");
|
||||
end
|
||||
|
|
|
|||
|
|
@ -314,7 +314,9 @@ sv_const_fail7 vvp_tests/sv_const_fail7.json
|
|||
sv_const_fail8 vvp_tests/sv_const_fail8.json
|
||||
sv_const_fail9 vvp_tests/sv_const_fail9.json
|
||||
sv_darray_assign_op vvp_tests/sv_darray_assign_op.json
|
||||
sv_darray_and_or_xor vvp_tests/sv_darray_and_or_xor.json
|
||||
sv_darray_find_locators vvp_tests/sv_darray_find_locators.json
|
||||
sv_darray_item_index vvp_tests/sv_darray_item_index.json
|
||||
sv_darray_min_max vvp_tests/sv_darray_min_max.json
|
||||
sv_darray_min_max_with vvp_tests/sv_darray_min_max_with.json
|
||||
sv_darray_product vvp_tests/sv_darray_product.json
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_and_or_xor.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog dynamic array and/or/xor reductions",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sv_darray_item_index.v",
|
||||
"iverilog-args" : [ "-g2005-sv" ],
|
||||
"vlog95" : {
|
||||
"__comment" : "SystemVerilog array iterator item.index querying",
|
||||
"type" : "CE"
|
||||
}
|
||||
}
|
||||
|
|
@ -359,6 +359,25 @@ static unsigned queue_unique_src_elem_wid(ivl_expr_t arg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int queue_src_elem_is_string(ivl_expr_t arg)
|
||||
{
|
||||
ivl_type_t src_q = 0;
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t cl = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
src_q = ivl_type_prop_type(ivl_signal_net_type(cl), pidx);
|
||||
} else if (ivl_expr_type(arg) == IVL_EX_SIGNAL) {
|
||||
src_q = ivl_signal_net_type(ivl_expr_signal(arg));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if (ivl_type_base(src_q) == IVL_VT_QUEUE ||
|
||||
ivl_type_base(src_q) == IVL_VT_DARRAY) {
|
||||
return ivl_type_base(ivl_type_element(src_q)) == IVL_VT_STRING;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit a queue locator opcode. Plain signal uses `op_v`; class property
|
||||
* uses `op_prop_v`. Returning a queue object leaves it on the object stack.
|
||||
|
|
@ -431,7 +450,10 @@ enum queue_locator_with_mode_e {
|
|||
QUEUE_WITH_UNIQUE,
|
||||
QUEUE_WITH_UNIQUE_INDEX,
|
||||
QUEUE_WITH_SUM,
|
||||
QUEUE_WITH_PRODUCT
|
||||
QUEUE_WITH_PRODUCT,
|
||||
QUEUE_WITH_AND,
|
||||
QUEUE_WITH_OR,
|
||||
QUEUE_WITH_XOR
|
||||
};
|
||||
|
||||
static enum queue_locator_with_mode_e queue_locator_with_mode_from_name(
|
||||
|
|
@ -461,6 +483,12 @@ static enum queue_locator_with_mode_e queue_locator_with_mode_from_name(
|
|||
return QUEUE_WITH_SUM;
|
||||
} else if (strcmp(name, "$ivl_queue_method$product_with") == 0) {
|
||||
return QUEUE_WITH_PRODUCT;
|
||||
} else if (strcmp(name, "$ivl_queue_method$and_with") == 0) {
|
||||
return QUEUE_WITH_AND;
|
||||
} else if (strcmp(name, "$ivl_queue_method$or_with") == 0) {
|
||||
return QUEUE_WITH_OR;
|
||||
} else if (strcmp(name, "$ivl_queue_method$xor_with") == 0) {
|
||||
return QUEUE_WITH_XOR;
|
||||
}
|
||||
return (enum queue_locator_with_mode_e) -1;
|
||||
}
|
||||
|
|
@ -480,12 +508,19 @@ static int queue_with_multi(enum queue_locator_with_mode_e mode)
|
|||
mode == QUEUE_WITH_UNIQUE ||
|
||||
mode == QUEUE_WITH_UNIQUE_INDEX ||
|
||||
mode == QUEUE_WITH_SUM ||
|
||||
mode == QUEUE_WITH_PRODUCT;
|
||||
mode == QUEUE_WITH_PRODUCT ||
|
||||
mode == QUEUE_WITH_AND ||
|
||||
mode == QUEUE_WITH_OR ||
|
||||
mode == QUEUE_WITH_XOR;
|
||||
}
|
||||
|
||||
static int queue_with_expr_value(enum queue_locator_with_mode_e mode)
|
||||
{
|
||||
return mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT;
|
||||
return mode == QUEUE_WITH_SUM ||
|
||||
mode == QUEUE_WITH_PRODUCT ||
|
||||
mode == QUEUE_WITH_AND ||
|
||||
mode == QUEUE_WITH_OR ||
|
||||
mode == QUEUE_WITH_XOR;
|
||||
}
|
||||
|
||||
static int queue_with_as_index(enum queue_locator_with_mode_e mode)
|
||||
|
|
@ -499,17 +534,24 @@ static int queue_with_as_index(enum queue_locator_with_mode_e mode)
|
|||
/* On predicate match: append value/index and continue or stop. */
|
||||
static void emit_queue_with_on_match(enum queue_locator_with_mode_e mode,
|
||||
ivl_signal_t item_sig, int i_reg,
|
||||
unsigned elem_wid, unsigned match_lab)
|
||||
unsigned elem_wid, unsigned match_lab,
|
||||
int is_string)
|
||||
{
|
||||
int multi = queue_with_multi(mode);
|
||||
int as_index = queue_with_as_index(mode);
|
||||
|
||||
if (!multi) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
if (is_string && !as_index)
|
||||
fprintf(vvp_out, " %%queue/new_empty/str;\n");
|
||||
else
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
}
|
||||
if (as_index) {
|
||||
fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%queue/append_word/v 32;\n");
|
||||
} else if (is_string) {
|
||||
fprintf(vvp_out, " %%load/str v%p_0;\n", item_sig);
|
||||
fprintf(vvp_out, " %%queue/append_word/str;\n");
|
||||
} else {
|
||||
fprintf(vvp_out, " %%load/vec4 v%p_0;\n", item_sig);
|
||||
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
|
||||
|
|
@ -554,7 +596,8 @@ static void emit_queue_with_step_index(int reverse, int i_reg, unsigned lab_top)
|
|||
}
|
||||
|
||||
static void emit_queue_with_finish(enum queue_locator_with_mode_e mode,
|
||||
int is_prop, unsigned elem_wid)
|
||||
int is_prop, unsigned elem_wid,
|
||||
int is_string)
|
||||
{
|
||||
if (mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX) {
|
||||
unsigned wid = (mode == QUEUE_WITH_UNIQUE_INDEX) ? 32 : elem_wid;
|
||||
|
|
@ -586,13 +629,37 @@ static void emit_queue_with_finish(enum queue_locator_with_mode_e mode,
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (mode == QUEUE_WITH_AND) {
|
||||
fprintf(vvp_out, " %%queue/and/obj/v %u;\n", elem_wid);
|
||||
if (is_prop) {
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mode == QUEUE_WITH_OR) {
|
||||
fprintf(vvp_out, " %%queue/or/obj/v %u;\n", elem_wid);
|
||||
if (is_prop) {
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (mode == QUEUE_WITH_XOR) {
|
||||
fprintf(vvp_out, " %%queue/xor/obj/v %u;\n", elem_wid);
|
||||
if (is_prop) {
|
||||
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (queue_with_multi(mode)) {
|
||||
if (is_prop) {
|
||||
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
if (is_string && !queue_with_as_index(mode))
|
||||
fprintf(vvp_out, " %%queue/new_empty/str;\n");
|
||||
else
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
if (is_prop) {
|
||||
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
||||
}
|
||||
|
|
@ -610,13 +677,28 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
ivl_expr_t pred = ivl_expr_parm(expr, 1);
|
||||
ivl_signal_t item_sig = ivl_expr_signal(ivl_expr_parm(expr, 2));
|
||||
ivl_signal_t idx_sig = ivl_expr_signal(ivl_expr_parm(expr, 3));
|
||||
unsigned elem_wid = queue_unique_src_elem_wid(qarg);
|
||||
if (elem_wid == 0) return 1;
|
||||
int is_string = queue_src_elem_is_string(qarg);
|
||||
unsigned elem_wid = is_string ? 0 : queue_unique_src_elem_wid(qarg);
|
||||
if (!is_string && elem_wid == 0) return 1;
|
||||
|
||||
enum queue_locator_with_mode_e mode =
|
||||
queue_locator_with_mode_from_name(name);
|
||||
if ((int) mode < 0) return 1;
|
||||
|
||||
/* String unique/min/max/sum/product/and/or/xor with() not implemented yet. */
|
||||
if (is_string &&
|
||||
(mode == QUEUE_WITH_UNIQUE || mode == QUEUE_WITH_UNIQUE_INDEX ||
|
||||
mode == QUEUE_WITH_MIN || mode == QUEUE_WITH_MAX ||
|
||||
mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT ||
|
||||
mode == QUEUE_WITH_AND || mode == QUEUE_WITH_OR ||
|
||||
mode == QUEUE_WITH_XOR)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Class-property string locators need %load/prop/dar/str (not yet). */
|
||||
if (is_string && (ivl_expr_type(qarg) == IVL_EX_PROPERTY))
|
||||
return 1;
|
||||
|
||||
int i_reg = allocate_word();
|
||||
int n_reg = allocate_word();
|
||||
unsigned lab_top = local_count++;
|
||||
|
|
@ -630,6 +712,10 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
/* First/last stop label: property path needs an extra pop. */
|
||||
unsigned stop_lab = is_prop ? lab_found : lab_end;
|
||||
unsigned match_lab = multi ? lab_nom : stop_lab;
|
||||
int as_index = queue_with_as_index(mode);
|
||||
const char* new_empty = (is_string && !as_index)
|
||||
? "%queue/new_empty/str"
|
||||
: "%queue/new_empty/v";
|
||||
|
||||
if (is_prop) {
|
||||
ivl_signal_t cl = ivl_expr_signal(qarg);
|
||||
|
|
@ -638,7 +724,7 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%prop/queue/size %u;\n", pidx);
|
||||
fprintf(vvp_out, " %%ix/vec4/s %d;\n", n_reg);
|
||||
if (multi) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
fprintf(vvp_out, " %s;\n", new_empty);
|
||||
}
|
||||
emit_queue_with_init_index(reverse, i_reg, n_reg);
|
||||
fprintf(vvp_out, "T_%u.%u ; queue with loop\n", thread_count, lab_top);
|
||||
|
|
@ -652,18 +738,27 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
fprintf(vvp_out, " %%queue/size/v v%p_0;\n", sig);
|
||||
fprintf(vvp_out, " %%ix/vec4/s %d;\n", n_reg);
|
||||
if (multi) {
|
||||
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||
fprintf(vvp_out, " %s;\n", new_empty);
|
||||
}
|
||||
emit_queue_with_init_index(reverse, i_reg, n_reg);
|
||||
fprintf(vvp_out, "T_%u.%u ; queue with loop (var)\n", thread_count,
|
||||
lab_top);
|
||||
emit_queue_with_loop_test(reverse, i_reg, n_reg, lab_loop_end);
|
||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||
fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid,
|
||||
i_reg);
|
||||
if (is_string) {
|
||||
fprintf(vvp_out, " %%ix/mov 3, %d;\n", i_reg);
|
||||
fprintf(vvp_out, " %%load/dar/str v%p_0;\n", sig);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%queue/word/v v%p_0, %u, %d;\n", sig, elem_wid,
|
||||
i_reg);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid);
|
||||
if (is_string) {
|
||||
fprintf(vvp_out, " %%store/str v%p_0;\n", item_sig);
|
||||
} else {
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, %u;\n", item_sig, elem_wid);
|
||||
}
|
||||
fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg);
|
||||
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
|
||||
|
||||
|
|
@ -675,7 +770,8 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
int pf = draw_eval_condition(pred);
|
||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom, pf);
|
||||
clr_flag(pf);
|
||||
emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab);
|
||||
emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab,
|
||||
is_string);
|
||||
}
|
||||
|
||||
fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom);
|
||||
|
|
@ -689,12 +785,12 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
|||
|
||||
fprintf(vvp_out, "T_%u.%u ; loop end (prop)\n", thread_count,
|
||||
lab_loop_end);
|
||||
emit_queue_with_finish(mode, 1, elem_wid);
|
||||
emit_queue_with_finish(mode, 1, elem_wid, is_string);
|
||||
fprintf(vvp_out, "T_%u.%u ; with end (prop)\n", thread_count, lab_end);
|
||||
} else {
|
||||
fprintf(vvp_out, "T_%u.%u ; loop end (var)\n", thread_count,
|
||||
lab_loop_end);
|
||||
emit_queue_with_finish(mode, 0, elem_wid);
|
||||
emit_queue_with_finish(mode, 0, elem_wid, is_string);
|
||||
fprintf(vvp_out, "T_%u.%u ; with end (var)\n", thread_count, lab_end);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1131,13 +1131,23 @@ static void draw_sfunc_vec4(ivl_expr_t expr)
|
|||
}
|
||||
|
||||
if ((strcmp(ivl_expr_name(expr), "$ivl_queue_method$sum") == 0 ||
|
||||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0) &&
|
||||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0 ||
|
||||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$and") == 0 ||
|
||||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$or") == 0 ||
|
||||
strcmp(ivl_expr_name(expr), "$ivl_queue_method$xor") == 0) &&
|
||||
parm_count == 1) {
|
||||
ivl_expr_t arg = ivl_expr_parm(expr, 0);
|
||||
unsigned wid = ivl_expr_width(expr);
|
||||
const char* op = strcmp(ivl_expr_name(expr), "$ivl_queue_method$product") == 0
|
||||
? "product"
|
||||
: "sum";
|
||||
const char* name = ivl_expr_name(expr);
|
||||
const char* op = "sum";
|
||||
if (strcmp(name, "$ivl_queue_method$product") == 0)
|
||||
op = "product";
|
||||
else if (strcmp(name, "$ivl_queue_method$and") == 0)
|
||||
op = "and";
|
||||
else if (strcmp(name, "$ivl_queue_method$or") == 0)
|
||||
op = "or";
|
||||
else if (strcmp(name, "$ivl_queue_method$xor") == 0)
|
||||
op = "xor";
|
||||
if (ivl_expr_type(arg) == IVL_EX_PROPERTY) {
|
||||
ivl_signal_t clas = ivl_expr_signal(arg);
|
||||
unsigned pidx = ivl_expr_property_idx(arg);
|
||||
|
|
|
|||
11
vvp/codes.h
11
vvp/codes.h
|
|
@ -258,8 +258,16 @@ 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_QUEUE_AND_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_AND_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_AND_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_APPEND_WORD_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_NEW_EMPTY_STR(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_OR_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_OR_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_OR_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_PRODUCT_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_PRODUCT_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_PRODUCT_V(vthread_t thr, vvp_code_t code);
|
||||
|
|
@ -269,6 +277,9 @@ extern bool of_QUEUE_SUM_PROP_V(vthread_t thr, vvp_code_t code);
|
|||
extern bool of_QUEUE_SUM_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_WORD_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_WORD_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_XOR_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_XOR_PROP_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_QUEUE_XOR_V(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIX_LTU(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_CMPIX_SLT0(vthread_t thr, vvp_code_t code);
|
||||
extern bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t code);
|
||||
|
|
|
|||
|
|
@ -279,6 +279,10 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%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} },
|
||||
{ "%queue/and/obj/v", of_QUEUE_AND_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/and/prop/v", of_QUEUE_AND_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/and/v", of_QUEUE_AND_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/append_word/str", of_QUEUE_APPEND_WORD_STR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%queue/append_word/v", of_QUEUE_APPEND_WORD_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/find/index/prop/v", of_QUEUE_FIND_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/find/index/v", of_QUEUE_FIND_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
|
|
@ -298,7 +302,11 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%queue/min/obj/v", of_QUEUE_MIN_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/min/prop/v", of_QUEUE_MIN_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/min/v", of_QUEUE_MIN_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/new_empty/str", of_QUEUE_NEW_EMPTY_STR, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
||||
{ "%queue/or/obj/v", of_QUEUE_OR_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/or/prop/v", of_QUEUE_OR_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/or/v", of_QUEUE_OR_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/product/obj/v", of_QUEUE_PRODUCT_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/product/prop/v", of_QUEUE_PRODUCT_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/product/v", of_QUEUE_PRODUCT_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
|
|
@ -314,6 +322,9 @@ static const struct opcode_table_s opcode_table[] = {
|
|||
{ "%queue/unique/v", of_QUEUE_UNIQUE_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/word/prop/v", of_QUEUE_WORD_PROP_V, 3, {OA_NUMBER, OA_BIT1, OA_BIT2} },
|
||||
{ "%queue/word/v", of_QUEUE_WORD_V, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} },
|
||||
{ "%queue/xor/obj/v", of_QUEUE_XOR_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||
{ "%queue/xor/prop/v", of_QUEUE_XOR_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||
{ "%queue/xor/v", of_QUEUE_XOR_V, 2, {OA_FUNC_PTR, 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} },
|
||||
|
|
|
|||
225
vvp/vthread.cc
225
vvp/vthread.cc
|
|
@ -6551,6 +6551,45 @@ static vvp_vector4_t queue_product_words_src(SRC* src, unsigned wid)
|
|||
return acc;
|
||||
}
|
||||
|
||||
template <class SRC>
|
||||
static vvp_vector4_t queue_and_words_src(SRC* src, unsigned wid)
|
||||
{
|
||||
vvp_vector4_t acc(wid, BIT4_1);
|
||||
if (!src) return acc;
|
||||
for (size_t i = 0; i < src->get_size(); i += 1) {
|
||||
vvp_vector4_t vi(wid);
|
||||
src->get_word(i, vi);
|
||||
acc &= vi;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
template <class SRC>
|
||||
static vvp_vector4_t queue_or_words_src(SRC* src, unsigned wid)
|
||||
{
|
||||
vvp_vector4_t acc(wid, BIT4_0);
|
||||
if (!src) return acc;
|
||||
for (size_t i = 0; i < src->get_size(); i += 1) {
|
||||
vvp_vector4_t vi(wid);
|
||||
src->get_word(i, vi);
|
||||
acc |= vi;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
template <class SRC>
|
||||
static vvp_vector4_t queue_xor_words_src(SRC* src, unsigned wid)
|
||||
{
|
||||
vvp_vector4_t acc(wid, BIT4_0);
|
||||
if (!src) return acc;
|
||||
for (size_t i = 0; i < src->get_size(); i += 1) {
|
||||
vvp_vector4_t vi(wid);
|
||||
src->get_word(i, vi);
|
||||
acc ^= vi;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
bool of_QUEUE_PRODUCT_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t* net = cp->net;
|
||||
|
|
@ -6663,6 +6702,174 @@ bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_AND_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t* net = cp->net;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc);
|
||||
vvp_vector4_t acc;
|
||||
if (qsrc) acc = queue_and_words_src(qsrc, wid);
|
||||
else if (dsrc) acc = queue_and_words_src(dsrc, wid);
|
||||
else {
|
||||
vvp_queue* src_q = get_queue_object<vvp_queue_vec4>(thr, net);
|
||||
vvp_queue_vec4* src = dynamic_cast<vvp_queue_vec4*>(src_q);
|
||||
acc = queue_and_words_src(src, wid);
|
||||
}
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_AND_PROP_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
|
||||
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_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_and_words_src(qsrc, wid)
|
||||
: queue_and_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_AND_OBJ_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_object_t src_obj;
|
||||
thr->pop_object(src_obj);
|
||||
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_and_words_src(qsrc, wid)
|
||||
: queue_and_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_OR_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t* net = cp->net;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc);
|
||||
vvp_vector4_t acc;
|
||||
if (qsrc) acc = queue_or_words_src(qsrc, wid);
|
||||
else if (dsrc) acc = queue_or_words_src(dsrc, wid);
|
||||
else {
|
||||
vvp_queue* src_q = get_queue_object<vvp_queue_vec4>(thr, net);
|
||||
vvp_queue_vec4* src = dynamic_cast<vvp_queue_vec4*>(src_q);
|
||||
acc = queue_or_words_src(src, wid);
|
||||
}
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_OR_PROP_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
|
||||
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_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_or_words_src(qsrc, wid)
|
||||
: queue_or_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_OR_OBJ_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_object_t src_obj;
|
||||
thr->pop_object(src_obj);
|
||||
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_or_words_src(qsrc, wid)
|
||||
: queue_or_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_XOR_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_net_t* net = cp->net;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_net(thr, net, qsrc, dsrc);
|
||||
vvp_vector4_t acc;
|
||||
if (qsrc) acc = queue_xor_words_src(qsrc, wid);
|
||||
else if (dsrc) acc = queue_xor_words_src(dsrc, wid);
|
||||
else {
|
||||
vvp_queue* src_q = get_queue_object<vvp_queue_vec4>(thr, net);
|
||||
vvp_queue_vec4* src = dynamic_cast<vvp_queue_vec4*>(src_q);
|
||||
acc = queue_xor_words_src(src, wid);
|
||||
}
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_XOR_PROP_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
size_t pid = cp->number;
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
|
||||
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_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(qobj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_xor_words_src(qsrc, wid)
|
||||
: queue_xor_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_XOR_OBJ_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
vvp_object_t src_obj;
|
||||
thr->pop_object(src_obj);
|
||||
|
||||
vvp_queue_vec4* qsrc = 0;
|
||||
vvp_darray* dsrc = 0;
|
||||
get_queue_or_darray_vec4_from_object(src_obj, qsrc, dsrc);
|
||||
vvp_vector4_t acc =
|
||||
qsrc ? queue_xor_words_src(qsrc, wid)
|
||||
: queue_xor_words_src(dsrc, wid);
|
||||
thr->push_vec4(acc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
vvp_vector4_t cmp = thr->pop_vec4();
|
||||
|
|
@ -7343,12 +7550,30 @@ bool of_PUSH_IX_VEC4(vthread_t thr, vvp_code_t cp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_NEW_EMPTY_STR(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
thr->push_object(vvp_object_t(new vvp_queue_string()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_NEW_EMPTY_V(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
thr->push_object(vvp_object_t(new vvp_queue_vec4()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_APPEND_WORD_STR(vthread_t thr, vvp_code_t)
|
||||
{
|
||||
string elem = thr->pop_str();
|
||||
vvp_object_t qobj;
|
||||
thr->pop_object(qobj);
|
||||
vvp_queue_string* q = qobj.peek<vvp_queue_string>();
|
||||
assert(q);
|
||||
q->push_back(elem, 0);
|
||||
thr->push_object(qobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool of_QUEUE_APPEND_WORD_V(vthread_t thr, vvp_code_t cp)
|
||||
{
|
||||
unsigned wid = cp->bit_idx[0];
|
||||
|
|
|
|||
Loading…
Reference in New Issue