Merge pull request #1421 from muhammadjawadkhan/split/05-sv-sum-product
SV: sum() and product() reductions on queues/darrays
This commit is contained in:
commit
f0b6d3addc
213
elab_expr.cc
213
elab_expr.cc
|
|
@ -105,8 +105,14 @@ static NetExpr* elab_queue_locator_with_predicate(
|
||||||
index_net->set_line(loc);
|
index_net->set_line(loc);
|
||||||
index_net->local_flag(true);
|
index_net->local_flag(true);
|
||||||
|
|
||||||
NetExpr* pred = elab_and_eval(des, ws, with_expr, 1, false, false,
|
NetExpr* pred = 0;
|
||||||
IVL_VT_BOOL);
|
if (method_suffix == "sum" || method_suffix == "product") {
|
||||||
|
pred = elab_and_eval(des, ws, with_expr, (int)ew, false, false,
|
||||||
|
ivl_type_base(element_type));
|
||||||
|
} else {
|
||||||
|
pred = elab_and_eval(des, ws, with_expr, 1, false, false,
|
||||||
|
IVL_VT_BOOL);
|
||||||
|
}
|
||||||
if (!pred) return 0;
|
if (!pred) return 0;
|
||||||
|
|
||||||
perm_string sfunc_name;
|
perm_string sfunc_name;
|
||||||
|
|
@ -130,6 +136,10 @@ static NetExpr* elab_queue_locator_with_predicate(
|
||||||
sfunc_name = lex_strings.make("$ivl_queue_method$min_with");
|
sfunc_name = lex_strings.make("$ivl_queue_method$min_with");
|
||||||
} else if (method_suffix == "max") {
|
} else if (method_suffix == "max") {
|
||||||
sfunc_name = lex_strings.make("$ivl_queue_method$max_with");
|
sfunc_name = lex_strings.make("$ivl_queue_method$max_with");
|
||||||
|
} else if (method_suffix == "sum") {
|
||||||
|
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 {
|
} else {
|
||||||
ivl_assert(loc, 0);
|
ivl_assert(loc, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -225,6 +235,58 @@ static NetExpr* elab_array_locator_method(Design* des, NetScope* scope,
|
||||||
return sys_expr;
|
return sys_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_array_reduction_method(perm_string name)
|
||||||
|
{
|
||||||
|
return name == "sum" || name == "product";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Elaborate sum()/product() on a queue or dynamic array expression.
|
||||||
|
* Returns an integral value with the element type/width.
|
||||||
|
*/
|
||||||
|
static NetExpr* elab_array_reduction_method(Design* des, NetScope* scope,
|
||||||
|
const LineInfo& loc,
|
||||||
|
perm_string method_name,
|
||||||
|
NetExpr* array_arg,
|
||||||
|
ivl_type_t element_type,
|
||||||
|
const vector<named_pexpr_t>& parms,
|
||||||
|
PExpr* with_expr, const char* kind)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
char sfunc[64];
|
||||||
|
snprintf(sfunc, sizeof sfunc, "$ivl_queue_method$%s", method_name.str());
|
||||||
|
|
||||||
|
if (with_expr) {
|
||||||
|
if (!parms.empty()) {
|
||||||
|
cerr << loc.get_fileline() << ": error: array locator "
|
||||||
|
<< "`with` clause cannot be combined with a "
|
||||||
|
<< "method argument." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return elab_queue_locator_with_predicate(des, scope, loc, with_expr,
|
||||||
|
array_arg, element_type,
|
||||||
|
element_type, method_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parms.size() != 0) {
|
||||||
|
cerr << loc.get_fileline() << ": error: " << method_name
|
||||||
|
<< "() method takes no arguments" << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
}
|
||||||
|
NetESFunc*sys_expr = new NetESFunc(sfunc, element_type, 1);
|
||||||
|
sys_expr->set_line(loc);
|
||||||
|
sys_expr->parm(0, array_arg);
|
||||||
|
return sys_expr;
|
||||||
|
}
|
||||||
|
|
||||||
bool type_is_vectorable(ivl_variable_type_t type)
|
bool type_is_vectorable(ivl_variable_type_t type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -1830,6 +1892,21 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method_name == "sum") {
|
||||||
|
expr_type_ = darray->element_base_type();
|
||||||
|
expr_width_ = darray->element_width();
|
||||||
|
min_width_ = expr_width_;
|
||||||
|
signed_flag_ = darray->get_signed();
|
||||||
|
return expr_width_;
|
||||||
|
}
|
||||||
|
if (method_name == "product") {
|
||||||
|
expr_type_ = darray->element_base_type();
|
||||||
|
expr_width_ = darray->element_width();
|
||||||
|
min_width_ = expr_width_;
|
||||||
|
signed_flag_ = darray->get_signed();
|
||||||
|
return expr_width_;
|
||||||
|
}
|
||||||
|
|
||||||
if (method_name == "find" || method_name == "find_index" ||
|
if (method_name == "find" || method_name == "find_index" ||
|
||||||
method_name == "unique" || method_name == "unique_index" ||
|
method_name == "unique" || method_name == "unique_index" ||
|
||||||
method_name == "min" || method_name == "max") {
|
method_name == "min" || method_name == "max") {
|
||||||
|
|
@ -1887,6 +1964,21 @@ unsigned PECallFunction::test_width_method_(Design*, NetScope*,
|
||||||
return expr_width_;
|
return expr_width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (method_name == "sum") {
|
||||||
|
expr_type_ = darray->element_base_type();
|
||||||
|
expr_width_ = darray->element_width();
|
||||||
|
min_width_ = expr_width_;
|
||||||
|
signed_flag_ = darray->get_signed();
|
||||||
|
return expr_width_;
|
||||||
|
}
|
||||||
|
if (method_name == "product") {
|
||||||
|
expr_type_ = darray->element_base_type();
|
||||||
|
expr_width_ = darray->element_width();
|
||||||
|
min_width_ = expr_width_;
|
||||||
|
signed_flag_ = darray->get_signed();
|
||||||
|
return expr_width_;
|
||||||
|
}
|
||||||
|
|
||||||
if (method_name == "unique" || method_name == "unique_index" ||
|
if (method_name == "unique" || method_name == "unique_index" ||
|
||||||
method_name == "min" || method_name == "max" ||
|
method_name == "min" || method_name == "max" ||
|
||||||
method_name == "find" || method_name == "find_index") {
|
method_name == "find" || method_name == "find_index") {
|
||||||
|
|
@ -3838,8 +3930,15 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||||
static_cast<ivl_type_t>(queue),
|
static_cast<ivl_type_t>(queue),
|
||||||
parms_, with_expr_, "queue");
|
parms_, with_expr_, "queue");
|
||||||
}
|
}
|
||||||
|
if (is_array_reduction_method(method_name)) {
|
||||||
|
return elab_array_reduction_method(des, scope, *this,
|
||||||
|
method_name, prop, element_type,
|
||||||
|
parms_, with_expr_, "queue");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ptype && ptype->base_type() == IVL_VT_DARRAY) {
|
if (ptype &&
|
||||||
|
(ptype->base_type() == IVL_VT_DARRAY ||
|
||||||
|
ptype->base_type() == IVL_VT_QUEUE)) {
|
||||||
NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr);
|
NetEProperty*prop = new NetEProperty(search_results.net, pidx, nullptr);
|
||||||
prop->set_line(*this);
|
prop->set_line(*this);
|
||||||
perm_string method_name = search_results.path_tail.back().name;
|
perm_string method_name = search_results.path_tail.back().name;
|
||||||
|
|
@ -3859,7 +3958,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||||
return elab_array_locator_method(des, scope, *this,
|
return elab_array_locator_method(des, scope, *this,
|
||||||
method_name, prop, element_type,
|
method_name, prop, element_type,
|
||||||
ptype, parms_, with_expr_,
|
ptype, parms_, with_expr_,
|
||||||
"dynamic array");
|
"array");
|
||||||
|
}
|
||||||
|
if (is_array_reduction_method(method_name)) {
|
||||||
|
return elab_array_reduction_method(des, scope, *this,
|
||||||
|
method_name, prop, element_type,
|
||||||
|
parms_, with_expr_, "array");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3968,6 +4072,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||||
queue_rtype, parms_, with_expr_,
|
queue_rtype, parms_, with_expr_,
|
||||||
"dynamic array");
|
"dynamic array");
|
||||||
}
|
}
|
||||||
|
if (is_array_reduction_method(method_name)) {
|
||||||
|
return elab_array_reduction_method(des, scope, *this, method_name,
|
||||||
|
sub_expr, element_type,
|
||||||
|
parms_, with_expr_,
|
||||||
|
"dynamic array");
|
||||||
|
}
|
||||||
|
|
||||||
cerr << get_fileline() << ": error: Method " << method_name
|
cerr << get_fileline() << ": error: Method " << method_name
|
||||||
<< " is not a dynamic array method." << endl;
|
<< " is not a dynamic array method." << endl;
|
||||||
|
|
@ -4027,6 +4137,11 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||||
static_cast<ivl_type_t>(queue),
|
static_cast<ivl_type_t>(queue),
|
||||||
parms_, with_expr_, "queue");
|
parms_, with_expr_, "queue");
|
||||||
}
|
}
|
||||||
|
if (is_array_reduction_method(method_name)) {
|
||||||
|
return elab_array_reduction_method(des, scope, *this, method_name,
|
||||||
|
sub_expr, element_type,
|
||||||
|
parms_, with_expr_, "queue");
|
||||||
|
}
|
||||||
|
|
||||||
cerr << get_fileline() << ": error: Method " << method_name
|
cerr << get_fileline() << ": error: Method " << method_name
|
||||||
<< " is not a queue method." << endl;
|
<< " is not a queue method." << endl;
|
||||||
|
|
@ -5252,6 +5367,38 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||||
fun->parm(0, arg);
|
fun->parm(0, arg);
|
||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
if (member_comp.name == "sum") {
|
||||||
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
|
cerr << get_fileline() << ": sorry: queue 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;
|
||||||
|
}
|
||||||
|
if (member_comp.name == "product") {
|
||||||
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
|
cerr << get_fileline() << ": sorry: queue 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;
|
||||||
|
}
|
||||||
if (member_comp.name == "min" || member_comp.name == "max") {
|
if (member_comp.name == "min" || member_comp.name == "max") {
|
||||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
||||||
|
|
@ -5586,6 +5733,22 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
||||||
fun->parm(0, arg);
|
fun->parm(0, arg);
|
||||||
return fun;
|
return fun;
|
||||||
}
|
}
|
||||||
|
if (member_comp.name == "sum") {
|
||||||
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
|
cerr << get_fileline() << ": sorry: queue 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;
|
||||||
|
}
|
||||||
if (member_comp.name == "min" || member_comp.name == "max") {
|
if (member_comp.name == "min" || member_comp.name == "max") {
|
||||||
if (!queue_method_element_is_integral_vec4(element_type)) {
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
cerr << get_fileline() << ": sorry: queue " << member_comp.name
|
||||||
|
|
@ -5666,17 +5829,39 @@ NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
||||||
return 0;
|
return 0;
|
||||||
// FIXME: Check this is a real or integral type.
|
// FIXME: Check this is a real or integral type.
|
||||||
} else if (member_comp.name == "sum") {
|
} else if (member_comp.name == "sum") {
|
||||||
cerr << get_fileline() << ": sorry: 'sum()' "
|
const netdarray_t* dar_sum = sr.net->darray_type();
|
||||||
"array reduction method is not currently "
|
ivl_assert(*this, dar_sum);
|
||||||
"implemented." << endl;
|
ivl_type_t element_type = dar_sum->element_type();
|
||||||
des->errors += 1;
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
return 0;
|
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") {
|
} else if (member_comp.name == "product") {
|
||||||
cerr << get_fileline() << ": sorry: 'product()' "
|
const netdarray_t* dar_sum = sr.net->darray_type();
|
||||||
"array reduction method is not currently "
|
ivl_assert(*this, dar_sum);
|
||||||
"implemented." << endl;
|
ivl_type_t element_type = dar_sum->element_type();
|
||||||
des->errors += 1;
|
if (!queue_method_element_is_integral_vec4(element_type)) {
|
||||||
return 0;
|
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.
|
// FIXME: Check this is only an integral type.
|
||||||
} else if (member_comp.name == "and") {
|
} else if (member_comp.name == "and") {
|
||||||
cerr << get_fileline() << ": sorry: 'and()' "
|
cerr << get_fileline() << ": sorry: 'and()' "
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@ module test;
|
||||||
`check(r.size, 1);
|
`check(r.size, 1);
|
||||||
`check(r[0], 6);
|
`check(r[0], 6);
|
||||||
|
|
||||||
|
c.d = '{2, 3, 4};
|
||||||
|
`check(c.d.product(), 24);
|
||||||
|
|
||||||
if (!failed)
|
if (!failed)
|
||||||
$display("PASSED");
|
$display("PASSED");
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Regression: class queue property locator methods.
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
bit failed = 1'b0;
|
||||||
|
|
||||||
|
`define check(val, exp) do if ((val) !== (exp)) begin $display("FAILED(%0d). '%s' expected %0d, got %0d", `__LINE__, `"val`", exp, val); failed = 1'b1; end while (0)
|
||||||
|
|
||||||
|
class C;
|
||||||
|
int q[$];
|
||||||
|
endclass
|
||||||
|
|
||||||
|
C c;
|
||||||
|
int r[$];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
c = new;
|
||||||
|
c.q = '{4, 7, 2, 5, 7, 1, 6, 3, 1};
|
||||||
|
|
||||||
|
r = c.q.find() with (item > 3);
|
||||||
|
`check(r.size, 5);
|
||||||
|
`check(r[0], 4);
|
||||||
|
`check(r[4], 6);
|
||||||
|
|
||||||
|
r = c.q.find_last_index() with (item < 3);
|
||||||
|
`check(r.size, 1);
|
||||||
|
`check(r[0], 8);
|
||||||
|
|
||||||
|
r = c.q.unique() with (item > 2);
|
||||||
|
`check(r.size, 5);
|
||||||
|
`check(r[0], 4);
|
||||||
|
`check(r[4], 3);
|
||||||
|
|
||||||
|
r = c.q.unique_index() with (item > 2);
|
||||||
|
`check(r.size, 6);
|
||||||
|
`check(r[0], 0);
|
||||||
|
`check(r[5], 7);
|
||||||
|
|
||||||
|
r = c.q.min();
|
||||||
|
`check(r.size, 2);
|
||||||
|
`check(r[0], 1);
|
||||||
|
`check(r[1], 1);
|
||||||
|
|
||||||
|
r = c.q.max() with (item < 7);
|
||||||
|
`check(r.size, 1);
|
||||||
|
`check(r[0], 6);
|
||||||
|
|
||||||
|
r = c.q.max();
|
||||||
|
`check(r.size, 2);
|
||||||
|
`check(r[0], 7);
|
||||||
|
|
||||||
|
c.q = '{2, 3, 4};
|
||||||
|
`check(c.q.product(), 24);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: dynamic array product() reduction (integral).
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int a[];
|
||||||
|
int p;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
a = '{2, 3, 4};
|
||||||
|
p = a.product();
|
||||||
|
`CHK(p === 24);
|
||||||
|
|
||||||
|
a = '{-2, 3, 5};
|
||||||
|
p = a.product();
|
||||||
|
`CHK(p === -30);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: dynamic array product() reduction with expression.
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int a[];
|
||||||
|
int p;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
a = '{10, -3, 5};
|
||||||
|
|
||||||
|
p = a.product() with (item > 0);
|
||||||
|
`CHK(p === 0);
|
||||||
|
|
||||||
|
p = a.product() with (item + 1);
|
||||||
|
`CHK(p === -132);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Regression: dynamic array sum() reduction (integral).
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) \
|
||||||
|
if (!(cond)) begin \
|
||||||
|
$display("FAILED line %0d", `__LINE__); \
|
||||||
|
failed = 1; \
|
||||||
|
end
|
||||||
|
|
||||||
|
int a[];
|
||||||
|
int s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
a = new[0];
|
||||||
|
s = a.sum();
|
||||||
|
`CHK(s === 0);
|
||||||
|
|
||||||
|
a = '{10, -3, 5};
|
||||||
|
s = a.sum();
|
||||||
|
`CHK(s === 12);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: dynamic array sum() reduction with expression.
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int a[];
|
||||||
|
int s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
a = '{10, -3, 5};
|
||||||
|
|
||||||
|
s = a.sum() with (item > 0);
|
||||||
|
`CHK(s === 2);
|
||||||
|
|
||||||
|
s = a.sum() with (item + 1);
|
||||||
|
`CHK(s === 15);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: queue product() reduction (integral).
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int q[$];
|
||||||
|
int p;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
q = '{2, 3, 4};
|
||||||
|
p = q.product();
|
||||||
|
`CHK(p === 24);
|
||||||
|
|
||||||
|
q = '{-2, 3, 5};
|
||||||
|
p = q.product();
|
||||||
|
`CHK(p === -30);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: queue product() reduction with expression.
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int q[$];
|
||||||
|
int p;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
q = '{4, 7, 2};
|
||||||
|
|
||||||
|
p = q.product() with (item > 3);
|
||||||
|
`CHK(p === 0);
|
||||||
|
|
||||||
|
p = q.product() with (item + 1);
|
||||||
|
`CHK(p === 120);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Regression: queue sum() reduction (integral).
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) \
|
||||||
|
if (!(cond)) begin \
|
||||||
|
$display("FAILED line %0d", `__LINE__); \
|
||||||
|
failed = 1; \
|
||||||
|
end
|
||||||
|
|
||||||
|
int q[$];
|
||||||
|
int s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
q = '{};
|
||||||
|
s = q.sum();
|
||||||
|
`CHK(s === 0);
|
||||||
|
|
||||||
|
q = '{4, 7, 2};
|
||||||
|
s = q.sum();
|
||||||
|
`CHK(s === 13);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Regression: queue sum() reduction with expression.
|
||||||
|
|
||||||
|
module top;
|
||||||
|
|
||||||
|
bit failed = 0;
|
||||||
|
|
||||||
|
`define CHK(cond) if (!(cond)) begin $display("FAILED line %0d", `__LINE__); failed = 1; end
|
||||||
|
|
||||||
|
int q[$];
|
||||||
|
int s;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
q = '{4, 7, 2, 5};
|
||||||
|
|
||||||
|
s = q.sum() with (item > 3);
|
||||||
|
`CHK(s === 3);
|
||||||
|
|
||||||
|
s = q.sum() with (item * 2);
|
||||||
|
`CHK(s === 36);
|
||||||
|
|
||||||
|
if (!failed)
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -291,6 +291,7 @@ sv_class_darray_prop_locators vvp_tests/sv_class_darray_prop_locators.json
|
||||||
sv_class_prop_packed_dims vvp_tests/sv_class_prop_packed_dims.json
|
sv_class_prop_packed_dims vvp_tests/sv_class_prop_packed_dims.json
|
||||||
sv_class_prop_type_name vvp_tests/sv_class_prop_type_name.json
|
sv_class_prop_type_name vvp_tests/sv_class_prop_type_name.json
|
||||||
sv_class_prop_wildcard_type_name vvp_tests/sv_class_prop_wildcard_type_name.json
|
sv_class_prop_wildcard_type_name vvp_tests/sv_class_prop_wildcard_type_name.json
|
||||||
|
sv_class_queue_prop_locators vvp_tests/sv_class_queue_prop_locators.json
|
||||||
sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json
|
sv_class_prop_nest_darray1 vvp_tests/sv_class_prop_nest_darray1.json
|
||||||
sv_class_prop_nest_obj1 vvp_tests/sv_class_prop_nest_obj1.json
|
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_real1 vvp_tests/sv_class_prop_nest_real1.json
|
||||||
|
|
@ -316,6 +317,10 @@ sv_darray_assign_op vvp_tests/sv_darray_assign_op.json
|
||||||
sv_darray_find_locators vvp_tests/sv_darray_find_locators.json
|
sv_darray_find_locators vvp_tests/sv_darray_find_locators.json
|
||||||
sv_darray_min_max vvp_tests/sv_darray_min_max.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_min_max_with vvp_tests/sv_darray_min_max_with.json
|
||||||
|
sv_darray_product vvp_tests/sv_darray_product.json
|
||||||
|
sv_darray_product_with vvp_tests/sv_darray_product_with.json
|
||||||
|
sv_darray_sum vvp_tests/sv_darray_sum.json
|
||||||
|
sv_darray_sum_with vvp_tests/sv_darray_sum_with.json
|
||||||
sv_darray_unique vvp_tests/sv_darray_unique.json
|
sv_darray_unique vvp_tests/sv_darray_unique.json
|
||||||
sv_darray_unique_with vvp_tests/sv_darray_unique_with.json
|
sv_darray_unique_with vvp_tests/sv_darray_unique_with.json
|
||||||
sv_declaration_after_null_statement_fail vvp_tests/sv_declaration_after_null_statement_fail.json
|
sv_declaration_after_null_statement_fail vvp_tests/sv_declaration_after_null_statement_fail.json
|
||||||
|
|
@ -415,6 +420,10 @@ sv_queue_method_push_front_too_few_arg_fail vvp_tests/sv_queue_method_push_front
|
||||||
sv_queue_method_push_front_too_many_arg_fail vvp_tests/sv_queue_method_push_front_too_many_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_queue_min_max vvp_tests/sv_queue_min_max.json
|
sv_queue_min_max vvp_tests/sv_queue_min_max.json
|
||||||
sv_queue_min_max_with vvp_tests/sv_queue_min_max_with.json
|
sv_queue_min_max_with vvp_tests/sv_queue_min_max_with.json
|
||||||
|
sv_queue_product vvp_tests/sv_queue_product.json
|
||||||
|
sv_queue_product_with vvp_tests/sv_queue_product_with.json
|
||||||
|
sv_queue_sum vvp_tests/sv_queue_sum.json
|
||||||
|
sv_queue_sum_with vvp_tests/sv_queue_sum_with.json
|
||||||
sv_queue_unique vvp_tests/sv_queue_unique.json
|
sv_queue_unique vvp_tests/sv_queue_unique.json
|
||||||
sv_queue_unique_with vvp_tests/sv_queue_unique_with.json
|
sv_queue_unique_with vvp_tests/sv_queue_unique_with.json
|
||||||
sv_soft_packed_union vvp_tests/sv_soft_packed_union.json
|
sv_soft_packed_union vvp_tests/sv_soft_packed_union.json
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_class_queue_prop_locators.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog class queue property locator methods",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_darray_product.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog dynamic array product() reduction",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_darray_product_with.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog dynamic array product() with expression",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_darray_sum.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog dynamic array sum() reduction",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_darray_sum_with.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog dynamic array sum() with expression",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_queue_product.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog queue product() reduction",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_queue_product_with.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog queue product() with expression",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_queue_sum.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog queue sum() reduction",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "sv_queue_sum_with.v",
|
||||||
|
"iverilog-args" : [ "-g2005-sv" ],
|
||||||
|
"vlog95" : {
|
||||||
|
"__comment" : "SystemVerilog queue sum() with expression",
|
||||||
|
"type" : "CE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -173,33 +173,59 @@ static int eval_darray_new(ivl_expr_t ex)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build a dynamic-array object value from an array pattern expression. */
|
/* Build a queue/dynamic-array object value from an array pattern expression. */
|
||||||
static int eval_darray_pattern_object(ivl_expr_t ex)
|
static int eval_array_pattern_object(ivl_expr_t ex)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
ivl_type_t net_type = ivl_expr_net_type(ex);
|
ivl_type_t net_type = ivl_expr_net_type(ex);
|
||||||
if (!net_type || ivl_type_base(net_type) != IVL_VT_DARRAY) return 1;
|
if (!net_type) return 1;
|
||||||
|
ivl_variable_type_t base_type = ivl_type_base(net_type);
|
||||||
|
if (base_type != IVL_VT_DARRAY && base_type != IVL_VT_QUEUE) return 1;
|
||||||
|
|
||||||
ivl_type_t element_type = ivl_type_element(net_type);
|
ivl_type_t element_type = ivl_type_element(net_type);
|
||||||
if (!element_type) return 1;
|
if (!element_type) return 1;
|
||||||
|
|
||||||
unsigned size_reg = allocate_word();
|
unsigned max_elems = ivl_expr_parms(ex);
|
||||||
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, ivl_expr_parms(ex));
|
if (base_type == IVL_VT_QUEUE) {
|
||||||
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
unsigned max_size = ivl_type_queue_max(net_type);
|
||||||
darray_new(element_type, size_reg);
|
if (max_size != 0 && max_elems > max_size) {
|
||||||
|
fprintf(stderr, "%s:%u: Warning: Array pattern assignment has more "
|
||||||
|
"elements (%u) than bounded queue supports (%u).\n"
|
||||||
|
" Only using first %u elements.\n",
|
||||||
|
ivl_expr_file(ex), ivl_expr_lineno(ex), max_elems, max_size, max_size);
|
||||||
|
max_elems = max_size;
|
||||||
|
}
|
||||||
|
fprintf(vvp_out, " %%queue/new_empty/v;\n");
|
||||||
|
} else {
|
||||||
|
unsigned size_reg = allocate_word();
|
||||||
|
fprintf(vvp_out, " %%ix/load %u, %u, 0;\n", size_reg, max_elems);
|
||||||
|
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
||||||
|
darray_new(element_type, size_reg);
|
||||||
|
}
|
||||||
|
|
||||||
switch (ivl_type_base(element_type)) {
|
switch (ivl_type_base(element_type)) {
|
||||||
case IVL_VT_BOOL:
|
case IVL_VT_BOOL:
|
||||||
case IVL_VT_LOGIC:
|
case IVL_VT_LOGIC:
|
||||||
for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) {
|
for (unsigned idx = 0; idx < max_elems; idx += 1) {
|
||||||
draw_eval_vec4(ivl_expr_parm(ex, idx));
|
draw_eval_vec4(ivl_expr_parm(ex, idx));
|
||||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
if (base_type == IVL_VT_QUEUE) {
|
||||||
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
fprintf(vvp_out, " %%queue/append_word/v %u;\n",
|
||||||
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
ivl_type_packed_width(element_type));
|
||||||
|
} else {
|
||||||
|
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||||
|
fprintf(vvp_out, " %%set/dar/obj/vec4 3;\n");
|
||||||
|
fprintf(vvp_out, " %%pop/vec4 1;\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IVL_VT_REAL:
|
case IVL_VT_REAL:
|
||||||
for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) {
|
for (unsigned idx = 0; idx < max_elems; idx += 1) {
|
||||||
|
if (base_type == IVL_VT_QUEUE) {
|
||||||
|
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue real "
|
||||||
|
"element type not implemented\n");
|
||||||
|
errors += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
draw_eval_real(ivl_expr_parm(ex, idx));
|
draw_eval_real(ivl_expr_parm(ex, idx));
|
||||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||||
fprintf(vvp_out, " %%set/dar/obj/real 3;\n");
|
fprintf(vvp_out, " %%set/dar/obj/real 3;\n");
|
||||||
|
|
@ -207,7 +233,13 @@ static int eval_darray_pattern_object(ivl_expr_t ex)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IVL_VT_STRING:
|
case IVL_VT_STRING:
|
||||||
for (unsigned idx = 0; idx < ivl_expr_parms(ex); idx += 1) {
|
for (unsigned idx = 0; idx < max_elems; idx += 1) {
|
||||||
|
if (base_type == IVL_VT_QUEUE) {
|
||||||
|
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: queue string "
|
||||||
|
"element type not implemented\n");
|
||||||
|
errors += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
draw_eval_string(ivl_expr_parm(ex, idx));
|
draw_eval_string(ivl_expr_parm(ex, idx));
|
||||||
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
fprintf(vvp_out, " %%ix/load 3, %u, 0;\n", idx);
|
||||||
fprintf(vvp_out, " %%set/dar/obj/str 3;\n");
|
fprintf(vvp_out, " %%set/dar/obj/str 3;\n");
|
||||||
|
|
@ -215,7 +247,7 @@ static int eval_darray_pattern_object(ivl_expr_t ex)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(vvp_out, "; ERROR: eval_darray_pattern_object: unsupported "
|
fprintf(vvp_out, "; ERROR: eval_array_pattern_object: unsupported "
|
||||||
"element type %d\n", ivl_type_base(element_type));
|
"element type %d\n", ivl_type_base(element_type));
|
||||||
errors += 1;
|
errors += 1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -397,7 +429,9 @@ enum queue_locator_with_mode_e {
|
||||||
QUEUE_WITH_MIN,
|
QUEUE_WITH_MIN,
|
||||||
QUEUE_WITH_MAX,
|
QUEUE_WITH_MAX,
|
||||||
QUEUE_WITH_UNIQUE,
|
QUEUE_WITH_UNIQUE,
|
||||||
QUEUE_WITH_UNIQUE_INDEX
|
QUEUE_WITH_UNIQUE_INDEX,
|
||||||
|
QUEUE_WITH_SUM,
|
||||||
|
QUEUE_WITH_PRODUCT
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum queue_locator_with_mode_e queue_locator_with_mode_from_name(
|
static enum queue_locator_with_mode_e queue_locator_with_mode_from_name(
|
||||||
|
|
@ -423,6 +457,10 @@ static enum queue_locator_with_mode_e queue_locator_with_mode_from_name(
|
||||||
return QUEUE_WITH_UNIQUE;
|
return QUEUE_WITH_UNIQUE;
|
||||||
} else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0) {
|
} else if (strcmp(name, "$ivl_queue_method$unique_index_with") == 0) {
|
||||||
return QUEUE_WITH_UNIQUE_INDEX;
|
return QUEUE_WITH_UNIQUE_INDEX;
|
||||||
|
} else if (strcmp(name, "$ivl_queue_method$sum_with") == 0) {
|
||||||
|
return QUEUE_WITH_SUM;
|
||||||
|
} else if (strcmp(name, "$ivl_queue_method$product_with") == 0) {
|
||||||
|
return QUEUE_WITH_PRODUCT;
|
||||||
}
|
}
|
||||||
return (enum queue_locator_with_mode_e) -1;
|
return (enum queue_locator_with_mode_e) -1;
|
||||||
}
|
}
|
||||||
|
|
@ -440,7 +478,14 @@ static int queue_with_multi(enum queue_locator_with_mode_e mode)
|
||||||
mode == QUEUE_WITH_MIN ||
|
mode == QUEUE_WITH_MIN ||
|
||||||
mode == QUEUE_WITH_MAX ||
|
mode == QUEUE_WITH_MAX ||
|
||||||
mode == QUEUE_WITH_UNIQUE ||
|
mode == QUEUE_WITH_UNIQUE ||
|
||||||
mode == QUEUE_WITH_UNIQUE_INDEX;
|
mode == QUEUE_WITH_UNIQUE_INDEX ||
|
||||||
|
mode == QUEUE_WITH_SUM ||
|
||||||
|
mode == QUEUE_WITH_PRODUCT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int queue_with_expr_value(enum queue_locator_with_mode_e mode)
|
||||||
|
{
|
||||||
|
return mode == QUEUE_WITH_SUM || mode == QUEUE_WITH_PRODUCT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int queue_with_as_index(enum queue_locator_with_mode_e mode)
|
static int queue_with_as_index(enum queue_locator_with_mode_e mode)
|
||||||
|
|
@ -527,6 +572,20 @@ static void emit_queue_with_finish(enum queue_locator_with_mode_e mode,
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (mode == QUEUE_WITH_SUM) {
|
||||||
|
fprintf(vvp_out, " %%queue/sum/obj/v %u;\n", elem_wid);
|
||||||
|
if (is_prop) {
|
||||||
|
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mode == QUEUE_WITH_PRODUCT) {
|
||||||
|
fprintf(vvp_out, " %%queue/product/obj/v %u;\n", elem_wid);
|
||||||
|
if (is_prop) {
|
||||||
|
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (queue_with_multi(mode)) {
|
if (queue_with_multi(mode)) {
|
||||||
if (is_prop) {
|
if (is_prop) {
|
||||||
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
fprintf(vvp_out, " %%pop/obj 1, 1;\n");
|
||||||
|
|
@ -608,11 +667,16 @@ static int eval_queue_method_find_with(ivl_expr_t expr)
|
||||||
fprintf(vvp_out, " %%push/ix/vec4 %d, 32, 1;\n", i_reg);
|
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);
|
fprintf(vvp_out, " %%store/vec4 v%p_0, 0, 32;\n", idx_sig);
|
||||||
|
|
||||||
int pf = draw_eval_condition(pred);
|
if (queue_with_expr_value(mode)) {
|
||||||
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d;\n", thread_count, lab_nom, pf);
|
draw_eval_vec4(pred);
|
||||||
clr_flag(pf);
|
fprintf(vvp_out, " %%queue/append_word/v %u;\n", elem_wid);
|
||||||
|
fprintf(vvp_out, " %%jmp T_%u.%u;\n", thread_count, lab_nom);
|
||||||
emit_queue_with_on_match(mode, item_sig, i_reg, elem_wid, match_lab);
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom);
|
fprintf(vvp_out, "T_%u.%u ; nomatch\n", thread_count, lab_nom);
|
||||||
emit_queue_with_step_index(reverse, i_reg, lab_top);
|
emit_queue_with_step_index(reverse, i_reg, lab_top);
|
||||||
|
|
@ -720,7 +784,7 @@ int draw_eval_object(ivl_expr_t ex)
|
||||||
return eval_object_ufunc(ex);
|
return eval_object_ufunc(ex);
|
||||||
|
|
||||||
case IVL_EX_ARRAY_PATTERN:
|
case IVL_EX_ARRAY_PATTERN:
|
||||||
return eval_darray_pattern_object(ex);
|
return eval_array_pattern_object(ex);
|
||||||
|
|
||||||
case IVL_EX_SFUNC:
|
case IVL_EX_SFUNC:
|
||||||
/* Queue locator `with` may report IVL_VT_DARRAY in ivl; handle by name. */
|
/* Queue locator `with` may report IVL_VT_DARRAY in ivl; handle by name. */
|
||||||
|
|
|
||||||
|
|
@ -1130,6 +1130,28 @@ 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) &&
|
||||||
|
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";
|
||||||
|
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, " %%queue/%s/prop/v %u, %u;\n", op, pidx, wid);
|
||||||
|
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
|
||||||
|
fprintf(vvp_out, " %%queue/%s/v v%p_0, %u;\n",
|
||||||
|
op, ivl_expr_signal(arg), wid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
draw_vpi_func_call(expr);
|
draw_vpi_func_call(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,13 @@ 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_PROP_QUEUE_SIZE(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_APPEND_WORD_V(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_NEW_EMPTY_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);
|
||||||
extern bool of_QUEUE_SIZE_V(vthread_t thr, vvp_code_t code);
|
extern bool of_QUEUE_SIZE_V(vthread_t thr, vvp_code_t code);
|
||||||
|
extern bool of_QUEUE_SUM_OBJ_V(vthread_t thr, vvp_code_t code);
|
||||||
|
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_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_WORD_V(vthread_t thr, vvp_code_t code);
|
||||||
extern bool of_CMPIX_LTU(vthread_t thr, vvp_code_t code);
|
extern bool of_CMPIX_LTU(vthread_t thr, vvp_code_t code);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ unsigned compile_errors = 0;
|
||||||
* by mnemonic string: compile_code() uses bsearch() on this array.
|
* by mnemonic string: compile_code() uses bsearch() on this array.
|
||||||
* If the order is wrong, lookup fails and the assembler reports
|
* If the order is wrong, lookup fails and the assembler reports
|
||||||
* "Invalid opcode" for otherwise valid instructions (e.g. class
|
* "Invalid opcode" for otherwise valid instructions (e.g. class
|
||||||
* property queue ops must sort among all %delete/*, %qpop/*, %store/*
|
* property queue ops must sort among all %delete*, %qpop*, %store*
|
||||||
* names, not grouped by feature).
|
* names, not grouped by feature).
|
||||||
* The opcode_compare function is a helper for that lookup.
|
* The opcode_compare function is a helper for that lookup.
|
||||||
*/
|
*/
|
||||||
|
|
@ -299,7 +299,13 @@ static const struct opcode_table_s opcode_table[] = {
|
||||||
{ "%queue/min/prop/v", of_QUEUE_MIN_PROP_V, 2, {OA_NUMBER, OA_BIT1, 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/min/v", of_QUEUE_MIN_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||||
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, OA_NONE} },
|
{ "%queue/new_empty/v", of_QUEUE_NEW_EMPTY_V, 0, {OA_NONE, OA_NONE, 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} },
|
||||||
{ "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
{ "%queue/size/v", of_QUEUE_SIZE_V, 1, {OA_FUNC_PTR, OA_NONE, OA_NONE} },
|
||||||
|
{ "%queue/sum/obj/v", of_QUEUE_SUM_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||||
|
{ "%queue/sum/prop/v", of_QUEUE_SUM_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||||
|
{ "%queue/sum/v", of_QUEUE_SUM_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||||
{ "%queue/unique/index/obj/v", of_QUEUE_UNIQUE_INDEX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
{ "%queue/unique/index/obj/v", of_QUEUE_UNIQUE_INDEX_OBJ_V, 1, {OA_BIT1, OA_NONE, OA_NONE} },
|
||||||
{ "%queue/unique/index/prop/v", of_QUEUE_UNIQUE_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
{ "%queue/unique/index/prop/v", of_QUEUE_UNIQUE_INDEX_PROP_V, 2, {OA_NUMBER, OA_BIT1, OA_NONE} },
|
||||||
{ "%queue/unique/index/v", of_QUEUE_UNIQUE_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
{ "%queue/unique/index/v", of_QUEUE_UNIQUE_INDEX_V, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} },
|
||||||
|
|
|
||||||
139
vvp/vthread.cc
139
vvp/vthread.cc
|
|
@ -6326,6 +6326,145 @@ static vvp_queue_vec4* queue_run_min_max_src(SRC* src, unsigned wid, bool want_m
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sum() reduction returns the scalar sum (Verilog-style addition per word). */
|
||||||
|
template <class SRC>
|
||||||
|
static vvp_vector4_t queue_sum_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.add(vi);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class SRC>
|
||||||
|
static vvp_vector4_t queue_product_words_src(SRC* src, unsigned wid)
|
||||||
|
{
|
||||||
|
vvp_vector4_t acc = queue_unique_ulong_to_vec4(1UL, wid);
|
||||||
|
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.mul(vi);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_PRODUCT_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 prod;
|
||||||
|
if (qsrc) prod = queue_product_words_src(qsrc, wid);
|
||||||
|
else if (dsrc) prod = queue_product_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);
|
||||||
|
prod = queue_product_words_src(src, wid);
|
||||||
|
}
|
||||||
|
thr->push_vec4(prod);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_PRODUCT_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 prod =
|
||||||
|
qsrc ? queue_product_words_src(qsrc, wid)
|
||||||
|
: queue_product_words_src(dsrc, wid);
|
||||||
|
thr->push_vec4(prod);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_PRODUCT_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 prod =
|
||||||
|
qsrc ? queue_product_words_src(qsrc, wid)
|
||||||
|
: queue_product_words_src(dsrc, wid);
|
||||||
|
thr->push_vec4(prod);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_SUM_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 sum;
|
||||||
|
if (qsrc) sum = queue_sum_words_src(qsrc, wid);
|
||||||
|
else if (dsrc) sum = queue_sum_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);
|
||||||
|
sum = queue_sum_words_src(src, wid);
|
||||||
|
}
|
||||||
|
thr->push_vec4(sum);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_SUM_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 sum =
|
||||||
|
qsrc ? queue_sum_words_src(qsrc, wid)
|
||||||
|
: queue_sum_words_src(dsrc, wid);
|
||||||
|
thr->push_vec4(sum);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool of_QUEUE_SUM_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 sum =
|
||||||
|
qsrc ? queue_sum_words_src(qsrc, wid)
|
||||||
|
: queue_sum_words_src(dsrc, wid);
|
||||||
|
thr->push_vec4(sum);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp)
|
bool of_QUEUE_FIND_V(vthread_t thr, vvp_code_t cp)
|
||||||
{
|
{
|
||||||
vvp_vector4_t cmp = thr->pop_vec4();
|
vvp_vector4_t cmp = thr->pop_vec4();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue