Merge pull request #685 from larsclausen/signed-method
Handle signedness and width expansion for class properties and methods
This commit is contained in:
commit
72b0498af4
22
PExpr.h
22
PExpr.h
|
|
@ -430,6 +430,9 @@ class PEIdent : public PExpr {
|
|||
NetAssign_*) const;
|
||||
|
||||
private:
|
||||
NetExpr* elaborate_expr_(Design *des, NetScope *scope,
|
||||
unsigned expr_wid, unsigned flags) const;
|
||||
|
||||
NetExpr*elaborate_expr_param_or_specparam_(Design*des,
|
||||
NetScope*scope,
|
||||
const NetExpr*par,
|
||||
|
|
@ -926,22 +929,25 @@ class PECallFunction : public PExpr {
|
|||
|
||||
NetExpr* cast_to_width_(NetExpr*expr, unsigned wid) const;
|
||||
|
||||
NetExpr* elaborate_expr_(Design *des, NetScope *scope,
|
||||
unsigned flags) const;
|
||||
|
||||
NetExpr*elaborate_expr_pkg_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags)const;
|
||||
unsigned flags)const;
|
||||
|
||||
NetExpr* elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const;
|
||||
symbol_search_results&search_results)
|
||||
const;
|
||||
NetExpr* elaborate_expr_method_par_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const;
|
||||
symbol_search_results&search_results)
|
||||
const;
|
||||
|
||||
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const;
|
||||
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t,
|
||||
unsigned expr_wid) const;
|
||||
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, ivl_nature_t)
|
||||
const;
|
||||
unsigned test_width_sfunc_(Design*des, NetScope*scope,
|
||||
width_mode_t&mode);
|
||||
unsigned test_width_method_(Design*des, NetScope*scope,
|
||||
|
|
@ -949,7 +955,7 @@ class PECallFunction : public PExpr {
|
|||
width_mode_t&mode);
|
||||
|
||||
NetExpr*elaborate_base_(Design*des, NetScope*scope, NetScope*dscope,
|
||||
unsigned expr_wid, unsigned flags) const;
|
||||
unsigned flags) const;
|
||||
|
||||
unsigned elaborate_arguments_(Design*des, NetScope*scope,
|
||||
NetFuncDef*def, bool need_const,
|
||||
|
|
|
|||
|
|
@ -249,9 +249,7 @@ class PCallTask : public Statement {
|
|||
const char*sys_task_name) const;
|
||||
NetProc*elaborate_method_func_(NetScope*scope,
|
||||
NetNet*net,
|
||||
ivl_variable_type_t type,
|
||||
unsigned width,
|
||||
bool signed_flag,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const;
|
||||
bool test_task_calls_ok_(Design*des, NetScope*scope) const;
|
||||
|
|
|
|||
147
elab_expr.cc
147
elab_expr.cc
|
|
@ -1873,8 +1873,7 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
||||
ivl_nature_t nature,
|
||||
unsigned expr_wid) const
|
||||
ivl_nature_t nature) const
|
||||
{
|
||||
// An access function must have 1 or 2 arguments.
|
||||
ivl_assert(*this, parms_.size()==2 || parms_.size()==1);
|
||||
|
|
@ -1925,8 +1924,7 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
|||
|
||||
NetExpr*tmp = new NetEAccess(branch, nature);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1938,7 +1936,6 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
|
|||
const pform_name_t&use_path,
|
||||
perm_string method_name,
|
||||
NetExpr*expr,
|
||||
unsigned rtn_wid,
|
||||
PExpr*parg, unsigned args)
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -1948,8 +1945,6 @@ static NetExpr* check_for_enum_methods(const LineInfo*li,
|
|||
<< endl;
|
||||
cerr << li->get_fileline() << ": " << __func__ << ": "
|
||||
<< "use_path=" << use_path << endl;
|
||||
cerr << li->get_fileline() << ": " << __func__ << ": "
|
||||
<< "rtn_wid=" << rtn_wid << endl;
|
||||
cerr << li->get_fileline() << ": " << __func__ << ": "
|
||||
<< "expr=" << *expr << endl;
|
||||
}
|
||||
|
|
@ -2569,7 +2564,6 @@ NetExpr* PEIdent::elaborate_expr_class_field_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr_pkg_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
|
|
@ -2594,7 +2588,7 @@ NetExpr* PECallFunction::elaborate_expr_pkg_(Design*des, NetScope*scope,
|
|||
if (! check_call_matches_definition_(des, dscope))
|
||||
return 0;
|
||||
|
||||
return elaborate_base_(des, scope, dscope, expr_wid, flags);
|
||||
return elaborate_base_(des, scope, dscope, flags);
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
|
|
@ -2611,14 +2605,24 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< " at " << package_->get_fileline() << endl;
|
||||
}
|
||||
|
||||
if (package_)
|
||||
return elaborate_expr_pkg_(des, scope, expr_wid, flags);
|
||||
|
||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||
|
||||
if (peek_tail_name(path_)[0] == '$')
|
||||
return elaborate_sfunc_(des, scope, expr_wid, flags);
|
||||
|
||||
NetExpr *result = elaborate_expr_(des, scope, flags);
|
||||
if (!result || !type_is_vectorable(expr_type_))
|
||||
return result;
|
||||
|
||||
return pad_to_width(result, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr_(Design*des, NetScope*scope,
|
||||
unsigned flags) const
|
||||
{
|
||||
if (package_)
|
||||
return elaborate_expr_pkg_(des, scope, flags);
|
||||
|
||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||
|
||||
// Search for the symbol. This should turn up a scope.
|
||||
symbol_search_results search_results;
|
||||
bool search_flag = symbol_search(this, des, scope, path_, &search_results);
|
||||
|
|
@ -2655,7 +2659,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
// Maybe this is a method of an object? Give it a try.
|
||||
if (!search_results.path_tail.empty()) {
|
||||
NetExpr*tmp = elaborate_expr_method_(des, scope, search_results, expr_wid);
|
||||
NetExpr*tmp = elaborate_expr_method_(des, scope, search_results);
|
||||
if (tmp) {
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PECallFunction::elaborate_expr: "
|
||||
|
|
@ -2688,8 +2692,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
// way.
|
||||
ivl_nature_t access_nature = find_access_function(path_);
|
||||
if (access_nature)
|
||||
return elaborate_access_func_(des, scope, access_nature,
|
||||
expr_wid);
|
||||
return elaborate_access_func_(des, scope, access_nature);
|
||||
|
||||
// Nothing was found so report this as an error.
|
||||
cerr << get_fileline() << ": error: No function named `" << path_
|
||||
|
|
@ -2726,8 +2729,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
use_search_results.net = scope->find_signal(perm_string::literal(THIS_TOKEN));
|
||||
ivl_assert(*this, use_search_results.net);
|
||||
|
||||
NetExpr*tmp = elaborate_expr_method_(des, scope, use_search_results, expr_wid);
|
||||
return tmp;
|
||||
return elaborate_expr_method_(des, scope, use_search_results);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2753,7 +2755,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
scope->is_const_func(false);
|
||||
}
|
||||
|
||||
return elaborate_base_(des, scope, dscope, expr_wid, flags);
|
||||
return elaborate_base_(des, scope, dscope, flags);
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
|
|
@ -2766,7 +2768,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*dscope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
unsigned flags) const
|
||||
{
|
||||
|
||||
if (! check_call_matches_definition_(des, dscope))
|
||||
|
|
@ -2845,11 +2847,7 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
|
|||
NetESignal*eres = new NetESignal(res);
|
||||
NetEUFunc*func = new NetEUFunc(scope, dscope, eres, parms, need_const);
|
||||
func->set_line(*this);
|
||||
|
||||
if(res->darray_type())
|
||||
return func;
|
||||
|
||||
return pad_to_width(func, expr_wid, signed_flag_, *this);
|
||||
return func;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": internal error: Unable to locate "
|
||||
|
|
@ -2960,8 +2958,8 @@ unsigned PECallFunction::elaborate_arguments_(Design*des, NetScope*scope,
|
|||
* "len" in path_tail, and if x is a string object, we can handle the case.
|
||||
*/
|
||||
NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const
|
||||
symbol_search_results&search_results)
|
||||
const
|
||||
{
|
||||
if (!gn_system_verilog()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
|
|
@ -3000,7 +2998,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (search_results.par_val && search_results.par_type) {
|
||||
return elaborate_expr_method_par_(des, scope, search_results, expr_wid);
|
||||
return elaborate_expr_method_par_(des, scope, search_results);
|
||||
}
|
||||
|
||||
NetExpr* sub_expr = 0;
|
||||
|
|
@ -3058,7 +3056,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", IVL_VT_BOOL, 32, 1);
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
|
|
@ -3076,19 +3074,20 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
|
||||
// Get the method name that we are looking for.
|
||||
perm_string method_name = search_results.path_tail.back().name;
|
||||
|
||||
if (method_name == "size") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: size() method "
|
||||
<< "takes no arguments" << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", IVL_VT_BOOL, 32, 1);
|
||||
NetESFunc*sys_expr = new NetESFunc("$size", &netvector_t::atom2u32, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
const netqueue_t*queue = search_results.net->queue_type();
|
||||
ivl_type_t element_type = queue->element_type();
|
||||
if (method_name == "pop_back") {
|
||||
if (parms_.size() != 0) {
|
||||
cerr << get_fileline() << ": error: pop_back() method "
|
||||
|
|
@ -3096,7 +3095,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_back",
|
||||
expr_type_, expr_width_, 1);
|
||||
element_type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
|
|
@ -3109,7 +3108,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_queue_method$pop_front",
|
||||
expr_type_, expr_width_, 1);
|
||||
element_type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
|
|
@ -3134,8 +3133,7 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
return check_for_enum_methods(this, des, scope,
|
||||
netenum, path_,
|
||||
method_name, sub_expr,
|
||||
expr_wid, tmp,
|
||||
parms_.size());
|
||||
tmp, parms_.size());
|
||||
}
|
||||
|
||||
// Class methods. Generate function call to the class method.
|
||||
|
|
@ -3186,35 +3184,35 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
|
||||
if (method_name == "len") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$len",
|
||||
IVL_VT_BOOL, 32, 1);
|
||||
&netvector_t::atom2u32, 1);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atoi") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atoi",
|
||||
IVL_VT_BOOL, integer_width, 1);
|
||||
netvector_t::integer_type(), 1);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atoreal") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atoreal",
|
||||
IVL_VT_REAL, 1, 1);
|
||||
&netreal_t::type_real, 1);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "atohex") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$atohex",
|
||||
IVL_VT_BOOL, integer_width, 1);
|
||||
netvector_t::integer_type(), 1);
|
||||
sys_expr->parm(0, sub_expr);
|
||||
return sys_expr;
|
||||
}
|
||||
|
||||
if (method_name == "substr") {
|
||||
NetESFunc*sys_expr = new NetESFunc("$ivl_string_method$substr",
|
||||
IVL_VT_STRING, 1, 3);
|
||||
&netstring_t::type_string, 3);
|
||||
sys_expr->set_line(*this);
|
||||
|
||||
// First argument is the source string.
|
||||
|
|
@ -3249,8 +3247,8 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
|
|||
* stable in the sense that they generate a constant value for a constant input.
|
||||
*/
|
||||
NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, NetScope*scope,
|
||||
symbol_search_results&search_results,
|
||||
unsigned expr_wid) const
|
||||
symbol_search_results&search_results)
|
||||
const
|
||||
{
|
||||
ivl_assert(*this, search_results.par_val);
|
||||
ivl_assert(*this, search_results.par_type);
|
||||
|
|
@ -3272,13 +3270,13 @@ NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, NetScope*scope,
|
|||
if (method_name=="len") {
|
||||
NetEConst*use_val = make_const_val(par_value.size());
|
||||
use_val->set_line(*this);
|
||||
return pad_to_width(use_val, expr_wid, *this);
|
||||
return use_val;
|
||||
}
|
||||
|
||||
if (method_name == "atoi") {
|
||||
NetEConst*use_val = make_const_val(atoi(par_value.c_str()));
|
||||
use_val->set_line(*this);
|
||||
return pad_to_width(use_val, expr_wid, true, *this);
|
||||
return use_val;
|
||||
}
|
||||
|
||||
if (method_name == "atoreal") {
|
||||
|
|
@ -3290,7 +3288,7 @@ NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, NetScope*scope,
|
|||
if (method_name == "atohex") {
|
||||
NetEConst*use_val = make_const_val(strtoul(par_value.c_str(),0,16));
|
||||
use_val->set_line(*this);
|
||||
return pad_to_width(use_val, expr_wid, true, *this);
|
||||
return use_val;
|
||||
}
|
||||
|
||||
// Returning 0 here will cause the caller to print an error
|
||||
|
|
@ -3964,6 +3962,16 @@ unsigned PEIdent::test_width_method_(Design*des, NetScope*scope, width_mode_t&)
|
|||
}
|
||||
}
|
||||
|
||||
if (const struct netqueue_t *queue = net->queue_type()) {
|
||||
if (member_name == "pop_back" || member_name == "pop_front") {
|
||||
expr_type_ = queue->element_base_type();
|
||||
expr_width_ = queue->element_width();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = queue->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the enumeration attributes.
|
||||
if (const netenum_t*netenum = net->enumeration()) {
|
||||
if (member_name == "num") {
|
||||
|
|
@ -4531,6 +4539,18 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
|
|||
*/
|
||||
NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
NetExpr *result;
|
||||
|
||||
result = elaborate_expr_(des, scope, expr_wid, flags);
|
||||
if (!result || !type_is_vectorable(expr_type_))
|
||||
return result;
|
||||
|
||||
return pad_to_width(result, expr_wid, signed_flag_, *this);
|
||||
}
|
||||
|
||||
NetExpr* PEIdent::elaborate_expr_(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
ivl_assert(*this, scope);
|
||||
|
||||
|
|
@ -4596,13 +4616,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetExpr*tmp = elaborate_expr_param_or_specparam_(des, scope, sr.par_val,
|
||||
sr.scope, sr.par_type,
|
||||
expr_wid, flags);
|
||||
|
||||
if (!tmp) return 0;
|
||||
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
return elaborate_expr_param_or_specparam_(des, scope, sr.par_val,
|
||||
sr.scope, sr.par_type,
|
||||
expr_wid, flags);
|
||||
}
|
||||
|
||||
// If the identifier names a signal (a variable or a net)
|
||||
|
|
@ -4637,11 +4653,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< endl;
|
||||
}
|
||||
|
||||
NetExpr*tmp = check_for_struct_members(this, des, use_scope,
|
||||
sr.net, sr.path_head.back().index,
|
||||
sr.path_tail);
|
||||
if (!tmp) return 0;
|
||||
else return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
return check_for_struct_members(this, des, use_scope, sr.net,
|
||||
sr.path_head.back().index,
|
||||
sr.path_tail);
|
||||
}
|
||||
|
||||
// If this is an array object, and there are members in
|
||||
|
|
@ -4657,7 +4671,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
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", IVL_VT_BOOL, 32, 1);
|
||||
NetESFunc*fun = new NetESFunc("$size",
|
||||
&netvector_t::atom2s32,
|
||||
1);
|
||||
fun->set_line(*this);
|
||||
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
|
|
@ -4773,11 +4789,10 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
ivl_assert(*this, sr.path_tail.size() == 1);
|
||||
const name_component_t member_comp = sr.path_tail.front();
|
||||
const netqueue_t*queue = sr.net->queue_type();
|
||||
ivl_variable_type_t qelem_type = queue->element_base_type();
|
||||
unsigned qelem_width = queue->element_width();
|
||||
ivl_type_t element_type = queue->element_type();
|
||||
if (member_comp.name == "pop_back") {
|
||||
NetESFunc*fun = new NetESFunc("$ivl_queue_method$pop_back",
|
||||
qelem_type, qelem_width, 1);
|
||||
element_type, 1);
|
||||
fun->set_line(*this);
|
||||
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
|
|
@ -4789,7 +4804,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
if (member_comp.name == "pop_front") {
|
||||
NetESFunc*fun = new NetESFunc("$ivl_queue_method$pop_front",
|
||||
qelem_type, qelem_width, 1);
|
||||
element_type, 1);
|
||||
fun->set_line(*this);
|
||||
|
||||
NetESignal*arg = new NetESignal(sr.net);
|
||||
|
|
@ -4849,7 +4864,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
return check_for_enum_methods(this, des, use_scope,
|
||||
netenum, sr.path_head,
|
||||
member_comp.name,
|
||||
expr, expr_wid, NULL, 0);
|
||||
expr, NULL, 0);
|
||||
}
|
||||
|
||||
ivl_assert(*this, sr.path_tail.empty());
|
||||
|
|
@ -4865,7 +4880,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< ", tmp=" << *tmp << endl;
|
||||
}
|
||||
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// If the identifier is a named event
|
||||
|
|
@ -5496,8 +5511,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des,
|
|||
<< "Elaborate parameter <" << path_
|
||||
<< "> as enumeration constant." << *etmp << endl;
|
||||
tmp = etmp->dup_expr();
|
||||
tmp = pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
|
||||
} else {
|
||||
perm_string name = peek_tail_name(path_);
|
||||
|
||||
|
|
|
|||
28
elaborate.cc
28
elaborate.cc
|
|
@ -3676,9 +3676,7 @@ NetProc* PCallTask::elaborate_queue_method_(Design*des, NetScope*scope,
|
|||
*/
|
||||
NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
||||
NetNet*net,
|
||||
ivl_variable_type_t type,
|
||||
unsigned width,
|
||||
bool signed_flag,
|
||||
ivl_type_t type,
|
||||
perm_string method_name,
|
||||
const char*sys_task_name) const
|
||||
{
|
||||
|
|
@ -3686,15 +3684,14 @@ NetProc* PCallTask::elaborate_method_func_(NetScope*scope,
|
|||
<< method_name << "' is being called as a task." << endl;
|
||||
|
||||
// Generate the function.
|
||||
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, width, 1);
|
||||
NetESFunc*sys_expr = new NetESFunc(sys_task_name, type, 1);
|
||||
sys_expr->set_line(*this);
|
||||
NetESignal*arg = new NetESignal(net);
|
||||
arg->set_line(*net);
|
||||
sys_expr->parm(0, arg);
|
||||
// Create a L-value that matches the function return type.
|
||||
NetNet*tmp;
|
||||
netvector_t*tmp_vec = new netvector_t(type, width-1, 0, signed_flag);
|
||||
tmp = new NetNet(scope, scope->local_symbol(), NetNet::REG, tmp_vec);
|
||||
tmp = new NetNet(scope, scope->local_symbol(), NetNet::REG, type);
|
||||
tmp->set_line(*this);
|
||||
NetAssign_*lv = new NetAssign_(tmp);
|
||||
// Generate an assign to the fake L-value.
|
||||
|
|
@ -3782,9 +3779,8 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
else if (method_name=="size")
|
||||
// This returns an int. It could be removed, but keep for now.
|
||||
return elaborate_method_func_(scope, net,
|
||||
IVL_VT_BOOL, 32,
|
||||
true, method_name,
|
||||
"$size");
|
||||
&netvector_t::atom2s32,
|
||||
method_name, "$size");
|
||||
else if (method_name=="reverse") {
|
||||
cerr << get_fileline() << ": sorry: 'reverse()' "
|
||||
"array sorting method is not currently supported."
|
||||
|
|
@ -3825,15 +3821,13 @@ NetProc* PCallTask::elaborate_method_(Design*des, NetScope*scope,
|
|||
"$ivl_queue_method$insert");
|
||||
else if (method_name == "pop_front")
|
||||
return elaborate_method_func_(scope, net,
|
||||
use_darray->element_base_type(),
|
||||
use_darray->element_width(),
|
||||
false, method_name,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
"$ivl_queue_method$pop_front");
|
||||
else if (method_name == "pop_back")
|
||||
return elaborate_method_func_(scope, net,
|
||||
use_darray->element_base_type(),
|
||||
use_darray->element_width(),
|
||||
false, method_name,
|
||||
use_darray->element_type(),
|
||||
method_name,
|
||||
"$ivl_queue_method$pop_back");
|
||||
}
|
||||
|
||||
|
|
@ -5324,12 +5318,12 @@ NetProc* PForeach::elaborate(Design*des, NetScope*scope) const
|
|||
idx_exp->set_line(*this);
|
||||
|
||||
// Make an initialization expression for the index.
|
||||
NetESFunc*init_expr = new NetESFunc("$low", IVL_VT_BOOL, 32, 1);
|
||||
NetESFunc*init_expr = new NetESFunc("$low", &netvector_t::atom2s32, 1);
|
||||
init_expr->set_line(*this);
|
||||
init_expr->parm(0, array_exp);
|
||||
|
||||
// Make a condition expression: idx <= $high(array)
|
||||
NetESFunc*high_exp = new NetESFunc("$high", IVL_VT_BOOL, 32, 1);
|
||||
NetESFunc*high_exp = new NetESFunc("$high", &netvector_t::atom2s32, 1);
|
||||
high_exp->set_line(*this);
|
||||
high_exp->parm(0, array_exp);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
// Check that the signedness of methods on the built-in enum type is handled
|
||||
// correctly when calling the method with parenthesis.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
|
||||
enum shortint {
|
||||
A = -1,
|
||||
B = -2,
|
||||
C = -3
|
||||
} es;
|
||||
|
||||
enum bit [15:0] {
|
||||
X = 65535,
|
||||
Y = 65534,
|
||||
Z = 65533
|
||||
} eu;
|
||||
|
||||
initial begin
|
||||
es = B;
|
||||
eu = Y;
|
||||
|
||||
// These all evaluate as signed
|
||||
`check($signed(eu.first()) < 0)
|
||||
`check(es.first() < 0)
|
||||
|
||||
`check($signed(eu.last()) < 0)
|
||||
`check(es.last() < 0)
|
||||
|
||||
`check($signed(eu.prev()) < 0)
|
||||
`check(es.prev() < 0)
|
||||
|
||||
`check($signed(eu.next()) < 0)
|
||||
`check(es.next() < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(eu.first() > 0)
|
||||
`check({es.first()} > 0)
|
||||
`check($unsigned(es.first()) > 0)
|
||||
`check(es.first() > 16'h0)
|
||||
|
||||
`check(eu.last() > 0)
|
||||
`check({es.last()} > 0)
|
||||
`check($unsigned(es.last()) > 0)
|
||||
`check(es.last() > 16'h0)
|
||||
|
||||
`check(eu.prev() > 0)
|
||||
`check({es.prev()} > 0)
|
||||
`check($unsigned(es.prev()) > 0)
|
||||
`check(es.prev() > 16'h0)
|
||||
|
||||
`check(eu.next() > 0)
|
||||
`check({es.next()} > 0)
|
||||
`check($unsigned(es.next()) > 0)
|
||||
`check(es.next() > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = eu.first() + x;
|
||||
`check(z === 65545)
|
||||
z = eu.first() + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = eu.last() + x;
|
||||
`check(z === 65543)
|
||||
z = eu.last() + y;
|
||||
`check(z === 65543)
|
||||
|
||||
z = eu.prev() + x;
|
||||
`check(z === 65545)
|
||||
z = eu.prev() + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = eu.next() + x;
|
||||
`check(z === 65543)
|
||||
z = eu.next() + y;
|
||||
`check(z === 65543)
|
||||
|
||||
z = es.first() + x;
|
||||
`check(z === 65545)
|
||||
z = es.first() + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = es.last() + x;
|
||||
`check(z === 65543)
|
||||
z = es.last() + y;
|
||||
`check(z === 7)
|
||||
|
||||
z = es.prev() + x;
|
||||
`check(z === 65545)
|
||||
z = es.prev() + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = es.next() + x;
|
||||
`check(z === 65543)
|
||||
z = es.next() + y;
|
||||
`check(z === 7)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? eu.first() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? eu.first() : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? eu.last() : x;
|
||||
`check(z === 65533)
|
||||
z = x ? eu.last() : y;
|
||||
`check(z === 65533)
|
||||
|
||||
z = x ? eu.prev() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? eu.prev() : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? eu.next() : x;
|
||||
`check(z === 65533)
|
||||
z = x ? eu.next() : y;
|
||||
`check(z === 65533)
|
||||
|
||||
z = x ? es.first() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? es.first() : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? es.last() : x;
|
||||
`check(z === 65533)
|
||||
z = x ? es.last() : y;
|
||||
`check(z === -3)
|
||||
|
||||
z = x ? es.prev() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? es.prev() : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? es.next() : x;
|
||||
`check(z === 65533)
|
||||
z = x ? es.next() : y;
|
||||
`check(z === -3)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Check that the signedness of methods on the built-in enum type is handled
|
||||
// correctly when calling the function with parenthesis and passing the result
|
||||
// to a system function.
|
||||
|
||||
module test;
|
||||
|
||||
enum shortint {
|
||||
A = -1,
|
||||
B = -2,
|
||||
C = -3
|
||||
} es;
|
||||
|
||||
enum bit [15:0] {
|
||||
X = 65535,
|
||||
Y = 65534,
|
||||
Z = 65533
|
||||
} eu;
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
es = B;
|
||||
eu = Y;
|
||||
|
||||
s = $sformatf("%0d %0d %0d %0d %0d %0d %0d %0d",
|
||||
es.first(), es.last(), es.prev(), es.next(),
|
||||
eu.first(), eu.last(), eu.prev(), eu.next());
|
||||
if (s == "-1 -3 -1 -3 65535 65533 65535 65533") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
// Check that the signedness of methods on the built-in enum type is handled
|
||||
// correctly when calling the method without parenthesis.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
|
||||
enum shortint {
|
||||
A = -1,
|
||||
B = -2,
|
||||
C = -3
|
||||
} es;
|
||||
|
||||
enum bit [15:0] {
|
||||
X = 65535,
|
||||
Y = 65534,
|
||||
Z = 65533
|
||||
} eu;
|
||||
|
||||
initial begin
|
||||
es = B;
|
||||
eu = Y;
|
||||
|
||||
// These all evaluate as signed
|
||||
`check($signed(eu.first) < 0)
|
||||
`check(es.first < 0)
|
||||
|
||||
`check($signed(eu.last) < 0)
|
||||
`check(es.last < 0)
|
||||
|
||||
`check($signed(eu.prev) < 0)
|
||||
`check(es.prev < 0)
|
||||
|
||||
`check($signed(eu.next) < 0)
|
||||
`check(es.next < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(eu.first > 0)
|
||||
`check({es.first} > 0)
|
||||
`check($unsigned(es.first) > 0)
|
||||
`check(es.first > 16'h0)
|
||||
|
||||
`check(eu.last > 0)
|
||||
`check({es.last} > 0)
|
||||
`check($unsigned(es.last) > 0)
|
||||
`check(es.last > 16'h0)
|
||||
|
||||
`check(eu.prev > 0)
|
||||
`check({es.prev} > 0)
|
||||
`check($unsigned(es.prev) > 0)
|
||||
`check(es.prev > 16'h0)
|
||||
|
||||
`check(eu.next > 0)
|
||||
`check({es.next} > 0)
|
||||
`check($unsigned(es.next) > 0)
|
||||
`check(es.next > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = eu.first + x;
|
||||
`check(z === 65545)
|
||||
z = eu.first + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = eu.last + x;
|
||||
`check(z === 65543)
|
||||
z = eu.last + y;
|
||||
`check(z === 65543)
|
||||
|
||||
z = eu.prev + x;
|
||||
`check(z === 65545)
|
||||
z = eu.prev + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = eu.next + x;
|
||||
`check(z === 65543)
|
||||
z = eu.next + y;
|
||||
`check(z === 65543)
|
||||
|
||||
z = es.first + x;
|
||||
`check(z === 65545)
|
||||
z = es.first + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = es.last + x;
|
||||
`check(z === 65543)
|
||||
z = es.last + y;
|
||||
`check(z === 7)
|
||||
|
||||
z = es.prev + x;
|
||||
`check(z === 65545)
|
||||
z = es.prev + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = es.next + x;
|
||||
`check(z === 65543)
|
||||
z = es.next + y;
|
||||
`check(z === 7)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? eu.first : x;
|
||||
`check(z === 65535)
|
||||
z = x ? eu.first : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? eu.last : x;
|
||||
`check(z === 65533)
|
||||
z = x ? eu.last : y;
|
||||
`check(z === 65533)
|
||||
|
||||
z = x ? eu.prev : x;
|
||||
`check(z === 65535)
|
||||
z = x ? eu.prev : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? eu.next : x;
|
||||
`check(z === 65533)
|
||||
z = x ? eu.next : y;
|
||||
`check(z === 65533)
|
||||
|
||||
z = x ? es.first : x;
|
||||
`check(z === 65535)
|
||||
z = x ? es.first : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? es.last : x;
|
||||
`check(z === 65533)
|
||||
z = x ? es.last : y;
|
||||
`check(z === -3)
|
||||
|
||||
z = x ? es.prev : x;
|
||||
`check(z === 65535)
|
||||
z = x ? es.prev : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? es.next : x;
|
||||
`check(z === 65533)
|
||||
z = x ? es.next : y;
|
||||
`check(z === -3)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
// Check that the signedness of methods on the built-in enum type is handled
|
||||
// correctly when calling the function without parenthesis and passing the
|
||||
// result to a system function.
|
||||
|
||||
module test;
|
||||
|
||||
enum shortint {
|
||||
A = -1,
|
||||
B = -2,
|
||||
C = -3
|
||||
} es;
|
||||
|
||||
enum bit [15:0] {
|
||||
X = 65535,
|
||||
Y = 65534,
|
||||
Z = 65533
|
||||
} eu;
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
es = B;
|
||||
eu = Y;
|
||||
|
||||
s = $sformatf("%0d %0d %0d %0d %0d %0d %0d %0d",
|
||||
es.first, es.last, es.prev, es.next,
|
||||
eu.first, eu.last, eu.prev, eu.next);
|
||||
if (s == "-1 -3 -1 -3 65535 65533 65535 65533") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Check that the signedness of methods on user defined classes is handled
|
||||
// correctly.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
class C;
|
||||
function shortint s;
|
||||
return -1;
|
||||
endfunction
|
||||
|
||||
function bit [15:0] u;
|
||||
return -1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
C c;
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
|
||||
// These all evaluate as signed
|
||||
`check($signed(c.u()) < 0)
|
||||
`check(c.s() < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(c.u() > 0)
|
||||
`check({c.s()} > 0)
|
||||
`check($unsigned(c.s()) > 0)
|
||||
`check(c.s() > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = c.u() + x;
|
||||
`check(z === 65545)
|
||||
z = c.u() + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = c.s() + x;
|
||||
`check(z === 65545)
|
||||
z = c.s() + y;
|
||||
`check(z === 9)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? c.u() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? c.u() : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? c.s() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? c.s() : y;
|
||||
`check(z === -1)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Check that the signedness of methods on user defined classes is handled
|
||||
// correctly when passing the result to a system function.
|
||||
|
||||
module test;
|
||||
|
||||
class C;
|
||||
function shortint s;
|
||||
return -1;
|
||||
endfunction
|
||||
|
||||
function bit [15:0] u;
|
||||
return -1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
C c;
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
|
||||
s = $sformatf("%0d %0d", c.s(), c.u());
|
||||
if (s == "-1 65535") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Check that the signedness of class properties are handled correctly when
|
||||
// accessing the property on a class object.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
class C;
|
||||
shortint s = -1;
|
||||
bit [15:0] u = -1;
|
||||
endclass
|
||||
|
||||
C c;
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
|
||||
// These all evaluate as signed
|
||||
`check(c.s < 0)
|
||||
`check($signed(c.u) < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(c.u > 0)
|
||||
`check({c.s} > 0)
|
||||
`check($unsigned(c.s) > 0)
|
||||
`check(c.s > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = c.u + x;
|
||||
`check(z === 65545)
|
||||
z = c.u + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = c.s + x;
|
||||
`check(z === 65545)
|
||||
z = c.s + y;
|
||||
`check(z === 9)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? c.u : x;
|
||||
`check(z === 65535)
|
||||
z = x ? c.u : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? c.s : x;
|
||||
`check(z === 65535)
|
||||
z = x ? c.s : y;
|
||||
`check(z === -1)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// Check that the signedness of class properties are handled correctly when
|
||||
// accessing the property on a class object and passing it to a system function.
|
||||
|
||||
module test;
|
||||
|
||||
class C;
|
||||
shortint s = -1;
|
||||
bit [15:0] u = -1;
|
||||
endclass
|
||||
|
||||
C c;
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
|
||||
s = $sformatf("%0d %0d", c.s, c.u);
|
||||
if (s == "-1 65535") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
// Check that the signedness of class properties are handled correctly when
|
||||
// accessing the property in a class method.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED: ", `"x`", `__LINE__); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
|
||||
class C;
|
||||
shortint s = -1;
|
||||
bit [15:0] u = -1;
|
||||
|
||||
task test;
|
||||
|
||||
// These all evaluate as signed
|
||||
`check(s < 0)
|
||||
`check($signed(u) < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(u > 0)
|
||||
`check({s} > 0)
|
||||
`check($unsigned(s) > 0)
|
||||
`check(s > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = u + x;
|
||||
`check(z === 65545)
|
||||
z = u + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = s + x;
|
||||
`check(z === 65545)
|
||||
z = s + y;
|
||||
`check(z === 9)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? u : x;
|
||||
`check(z === 65535)
|
||||
z = x ? u : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? s : x;
|
||||
`check(z === 65535)
|
||||
z = x ? s : y;
|
||||
`check(z === -1)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
||||
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.test();
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Check that the signedness of class properties are handled correctly when
|
||||
// accessing the property in a class method and passing it to a system function.
|
||||
|
||||
module test;
|
||||
|
||||
class C;
|
||||
shortint s = -1;
|
||||
bit [15:0] u = -1;
|
||||
|
||||
task test;
|
||||
string str;
|
||||
|
||||
str = $sformatf("%0d %0d", s, u);
|
||||
if (str == "-1 65535") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
endtask
|
||||
|
||||
endclass
|
||||
|
||||
C c;
|
||||
|
||||
initial begin
|
||||
c = new;
|
||||
c.test();
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Check that the signedness of the element type of a queue is correctly handled
|
||||
// whenn calling one of the pop methods with parenthesis.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
longint w;
|
||||
|
||||
shortint qs[$];
|
||||
bit [15:0] qu[$];
|
||||
|
||||
initial begin
|
||||
for (int i = 0; i < 16; i++) begin
|
||||
qu.push_back(-1);
|
||||
qs.push_back(-1);
|
||||
end
|
||||
|
||||
// These all evaluate as signed
|
||||
`check($signed(qu.pop_back()) < 0)
|
||||
`check(qs.pop_back() < 0)
|
||||
|
||||
`check($signed(qu.pop_front()) < 0)
|
||||
`check(qs.pop_front() < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(qu.pop_back() > 0)
|
||||
`check({qs.pop_back()} > 0)
|
||||
`check($unsigned(qs.pop_back()) > 0)
|
||||
`check(qs.pop_back() > 16'h0)
|
||||
|
||||
`check(qu.pop_front() > 0)
|
||||
`check({qs.pop_front()} > 0)
|
||||
`check($unsigned(qs.pop_front()) > 0)
|
||||
`check(qs.pop_front() > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = qu.pop_back() + x;
|
||||
`check(z === 65545)
|
||||
z = qu.pop_back() + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = qu.pop_front() + x;
|
||||
`check(z === 65545)
|
||||
z = qu.pop_front() + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = qs.pop_back() + x;
|
||||
`check(z === 65545)
|
||||
z = qs.pop_back() + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = qs.pop_front() + x;
|
||||
`check(z === 65545)
|
||||
z = qs.pop_front() + y;
|
||||
`check(z === 9)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? qu.pop_back() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qu.pop_back() : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? qu.pop_front() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qu.pop_front() : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? qs.pop_back() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qs.pop_back() : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? qs.pop_front() : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qs.pop_front() : y;
|
||||
`check(z === -1)
|
||||
|
||||
// Size return value is always positive, but check that it gets padded
|
||||
// properly
|
||||
w = x ? qu.size() : 64'h123;
|
||||
`check(w === 64'h4)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Check that the signedness of the element type of a queue is correctly handled
|
||||
// when passing the result of one of the pop methods as an argument to a system
|
||||
// function.
|
||||
|
||||
module test;
|
||||
|
||||
shortint qs[$];
|
||||
bit [15:0] qu[$];
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
qs.push_back(-1);
|
||||
qs.push_back(-2);
|
||||
qu.push_back(-1);
|
||||
qu.push_back(-2);
|
||||
|
||||
// Values popped from qs should be treated as signed, values popped from qu
|
||||
// should be treated as unsigned
|
||||
s = $sformatf("%0d %0d %0d %0d", qs.pop_front(), qs.pop_back(),
|
||||
qu.pop_front(), qu.pop_back());
|
||||
if (s == "-1 -2 65535 65534") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// Check that the signedness of the element type of a queue is correctly handled
|
||||
// whenn calling one of the pop methods with parenthesis.
|
||||
|
||||
module test;
|
||||
|
||||
bit failed = 1'b0;
|
||||
|
||||
`define check(x) \
|
||||
if (!(x)) begin \
|
||||
$display("FAILED(%0d): ", `__LINE__, `"x`"); \
|
||||
failed = 1'b1; \
|
||||
end
|
||||
|
||||
int unsigned x = 10;
|
||||
int y = 10;
|
||||
int z;
|
||||
longint w;
|
||||
|
||||
shortint qs[$];
|
||||
bit [15:0] qu[$];
|
||||
|
||||
initial begin
|
||||
for (int i = 0; i < 16; i++) begin
|
||||
qu.push_back(-1);
|
||||
qs.push_back(-1);
|
||||
end
|
||||
|
||||
// These all evaluate as signed
|
||||
`check($signed(qu.pop_back) < 0)
|
||||
`check(qs.pop_back < 0)
|
||||
|
||||
`check($signed(qu.pop_front) < 0)
|
||||
`check(qs.pop_front < 0)
|
||||
|
||||
// These all evaluate as unsigned
|
||||
`check(qu.pop_back > 0)
|
||||
`check({qs.pop_back} > 0)
|
||||
`check($unsigned(qs.pop_back) > 0)
|
||||
`check(qs.pop_back > 16'h0)
|
||||
|
||||
`check(qu.pop_front > 0)
|
||||
`check({qs.pop_front} > 0)
|
||||
`check($unsigned(qs.pop_front) > 0)
|
||||
`check(qs.pop_front > 16'h0)
|
||||
|
||||
// In arithmetic expressions if one operand is unsigned all operands are
|
||||
// considered unsigned
|
||||
z = qu.pop_back + x;
|
||||
`check(z === 65545)
|
||||
z = qu.pop_back + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = qu.pop_front + x;
|
||||
`check(z === 65545)
|
||||
z = qu.pop_front + y;
|
||||
`check(z === 65545)
|
||||
|
||||
z = qs.pop_back + x;
|
||||
`check(z === 65545)
|
||||
z = qs.pop_back + y;
|
||||
`check(z === 9)
|
||||
|
||||
z = qs.pop_front + x;
|
||||
`check(z === 65545)
|
||||
z = qs.pop_front + y;
|
||||
`check(z === 9)
|
||||
|
||||
// For ternary operators if one operand is unsigned the result is unsigend
|
||||
z = x ? qu.pop_back : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qu.pop_back : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? qu.pop_front : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qu.pop_front : y;
|
||||
`check(z === 65535)
|
||||
|
||||
z = x ? qs.pop_back : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qs.pop_back : y;
|
||||
`check(z === -1)
|
||||
|
||||
z = x ? qs.pop_front : x;
|
||||
`check(z === 65535)
|
||||
z = x ? qs.pop_front : y;
|
||||
`check(z === -1)
|
||||
|
||||
// Size return value is always positive, but check that it gets padded
|
||||
// properly
|
||||
w = x ? qu.size : 64'h123;
|
||||
`check(w === 64'h4)
|
||||
|
||||
if (!failed) begin
|
||||
$display("PASSED");
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// Check that the signedness of the element type of a queue is correctly handled
|
||||
// when passing the result of one of the pop methods as an argument to a system
|
||||
// function.
|
||||
|
||||
module test;
|
||||
|
||||
shortint qs[$];
|
||||
bit [15:0] qu[$];
|
||||
|
||||
string s;
|
||||
|
||||
initial begin
|
||||
qs.push_back(-1);
|
||||
qs.push_back(-2);
|
||||
qu.push_back(-1);
|
||||
qu.push_back(-2);
|
||||
|
||||
// Values popped from qs should be treated as signed, values popped from qu
|
||||
// should be treated as unsigned
|
||||
s = $sformatf("%0d %0d %0d %0d", qs.pop_front, qs.pop_back,
|
||||
qu.pop_front, qu.pop_back);
|
||||
if (s == "-1 -2 65535 65534") begin
|
||||
$display("PASSED");
|
||||
end else begin
|
||||
$display("FAILED s=%s", s);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -265,6 +265,10 @@ enum_in_struct normal,-g2005-sv ivltests
|
|||
enum_in_class normal,-g2005-sv ivltests
|
||||
enum_in_class_name_coll CE,-g2005-sv ivltests
|
||||
enum_line_info CE,-g2005-sv ivltests gold=enum_line_info.gold
|
||||
enum_method_signed1 normal,-g2005-sv ivltests
|
||||
enum_method_signed2 normal,-g2005-sv ivltests
|
||||
enum_method_signed3 normal,-g2005-sv ivltests
|
||||
enum_method_signed4 normal,-g2005-sv ivltests
|
||||
enum_next normal,-g2005-sv ivltests
|
||||
enum_order normal,-g2005-sv ivltests
|
||||
enum_ports normal,-g2005-sv ivltests
|
||||
|
|
@ -488,6 +492,12 @@ sv_class_extends_scoped normal,-g2009 ivltests
|
|||
sv_class_localparam normal,-g2009 ivltests
|
||||
sv_class_new_init normal,-g2009 ivltests
|
||||
sv_class_in_module_decl normal,-g2009 ivltests
|
||||
sv_class_method_signed1 normal,-g2009 ivltests
|
||||
sv_class_method_signed2 normal,-g2009 ivltests
|
||||
sv_class_property_signed1 normal,-g2009 ivltests
|
||||
sv_class_property_signed2 normal,-g2009 ivltests
|
||||
sv_class_property_signed3 normal,-g2009 ivltests
|
||||
sv_class_property_signed4 normal,-g2009 ivltests
|
||||
sv_class_static_prop1 normal,-g2009 ivltests
|
||||
sv_class_static_prop2 normal,-g2009 ivltests
|
||||
sv_class_static_prop3 normal,-g2009 ivltests
|
||||
|
|
@ -571,6 +581,10 @@ sv_queue_parray_fail CE,-g2009 ivltests gold=sv_queue_parray_fail.gold
|
|||
sv_queue_real normal,-g2009,-pfileline=1 ivltests gold=sv_queue_real.gold
|
||||
sv_queue_real_bounded normal,-g2009,-pfileline=1 ivltests gold=sv_queue_real_bounded.gold
|
||||
sv_queue_real_fail CE,-g2009 ivltests gold=sv_queue_real_fail.gold
|
||||
sv_queue_method_signed1 normal,-g2009 ivltests
|
||||
sv_queue_method_signed2 normal,-g2009 ivltests
|
||||
sv_queue_method_signed3 normal,-g2009 ivltests
|
||||
sv_queue_method_signed4 normal,-g2009 ivltests
|
||||
sv_queue_string normal,-g2009,-pfileline=1 ivltests gold=sv_queue_string.gold
|
||||
sv_queue_string_bounded normal,-g2009,-pfileline=1 ivltests gold=sv_queue_string_bounded.gold
|
||||
sv_queue_string_fail CE,-g2009 ivltests gold=sv_queue_string_fail.gold
|
||||
|
|
|
|||
|
|
@ -384,6 +384,12 @@ sv_class_extends_scoped CE,-g2009 ivltests
|
|||
sv_class_localparam CE,-g2009 ivltests
|
||||
sv_class_new_init CE,-g2009 ivltests
|
||||
sv_class_in_module_decl CE,-g2009 ivltests
|
||||
sv_class_method_signed1 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_method_signed2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_property_signed1 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_property_signed2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_property_signed3 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_property_signed4 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_class_static_prop1 CE,-g2009 ivltests
|
||||
sv_class_static_prop2 CE,-g2009 ivltests
|
||||
sv_class_static_prop3 CE,-g2009 ivltests
|
||||
|
|
@ -438,6 +444,10 @@ br_gh436 CE,-g2012,-pallowsigned=1 ivltests # queues/strings
|
|||
br_gh672 CE,-g2009 ivltests # join_none
|
||||
br_mw20200501 CE,-g2009 ivltests # queues
|
||||
disable_fork_cmd CE,-g2009 ivltests # disable fork and join_*
|
||||
enum_method_signed1 CE,-g2009,-pallowsigned=1 ivltests
|
||||
enum_method_signed2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
enum_method_signed3 CE,-g2009,-pallowsigned=1 ivltests
|
||||
enum_method_signed4 CE,-g2009,-pallowsigned=1 ivltests
|
||||
enum_next CE,-g2009,-pallowsigned=1 ivltests # enum
|
||||
enum_test1 CE,-g2009 ivltests # enum
|
||||
fork_join_any CE,-g2009,-pallowsigned=1 ivltests # join_any
|
||||
|
|
@ -611,6 +621,10 @@ br_gh433 CE,-g2009,-pallowsigned=1 ivltests
|
|||
sv_queue1 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue3 CE,-g2009 ivltests
|
||||
sv_queue_method_signed1 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue_method_signed2 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue_method_signed3 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue_method_signed4 CE,-g2009,-pallowsigned=1 ivltests
|
||||
sv_queue_real CE,-g2009 ivltests
|
||||
sv_queue_real_bounded CE,-g2009 ivltests
|
||||
sv_queue_real_fail CE,-g2009 ivltests
|
||||
|
|
|
|||
24
net_expr.cc
24
net_expr.cc
|
|
@ -487,28 +487,13 @@ NetESFunc::NetESFunc(const char*n, ivl_variable_type_t t,
|
|||
}
|
||||
|
||||
NetESFunc::NetESFunc(const char*n, ivl_type_t rtype, unsigned np)
|
||||
: NetExpr(rtype), name_(0), type_(IVL_VT_NO_TYPE), enum_type_(0), parms_(np), is_overridden_(false)
|
||||
: NetExpr(rtype), name_(0), type_(rtype->base_type()),
|
||||
enum_type_(dynamic_cast<const netenum_t*>(rtype)), parms_(np),
|
||||
is_overridden_(false)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(rtype->packed_width());
|
||||
// FIXME: For now, assume that all uses of this constructor
|
||||
// are for the IVL_VT_DARRAY type. Eventually, the type_
|
||||
// member will go away.
|
||||
if (dynamic_cast<const netdarray_t*>(rtype))
|
||||
type_ = IVL_VT_DARRAY;
|
||||
else if (dynamic_cast<const netclass_t*>(rtype))
|
||||
type_ = IVL_VT_CLASS;
|
||||
else if (dynamic_cast<const netstring_t*>(rtype))
|
||||
type_ = IVL_VT_STRING;
|
||||
else
|
||||
ivl_assert(*this, 0);
|
||||
}
|
||||
|
||||
NetESFunc::NetESFunc(const char*n, const netenum_t*enum_type, unsigned np)
|
||||
: name_(0), type_(enum_type->base_type()), enum_type_(enum_type), parms_(np), is_overridden_(false)
|
||||
{
|
||||
name_ = lex_strings.add(n);
|
||||
expr_width(enum_type->packed_width());
|
||||
cast_signed_base_(rtype->get_signed());
|
||||
}
|
||||
|
||||
NetESFunc::~NetESFunc()
|
||||
|
|
@ -576,6 +561,7 @@ ivl_variable_type_t NetEShallowCopy::expr_type() const
|
|||
NetEAccess::NetEAccess(NetBranch*br, ivl_nature_t nat)
|
||||
: branch_(br), nature_(nat)
|
||||
{
|
||||
cast_signed_base_(true);
|
||||
}
|
||||
|
||||
NetEAccess::~NetEAccess()
|
||||
|
|
|
|||
40
netlist.cc
40
netlist.cc
|
|
@ -549,6 +549,9 @@ template <class T> static unsigned calculate_count(T*type)
|
|||
void NetNet::calculate_slice_widths_from_packed_dims_(void)
|
||||
{
|
||||
ivl_assert(*this, net_type_);
|
||||
if (!net_type_->packed())
|
||||
return;
|
||||
|
||||
slice_dims_ = net_type_->slice_dimensions();
|
||||
|
||||
// Special case: There are no actual packed dimensions, so
|
||||
|
|
@ -598,42 +601,10 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t,
|
|||
s->add_signal(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* When we create a netnet for a packed struct, create a single
|
||||
* vector with the msb_/lsb_ chosen to name enough bits for the entire
|
||||
* packed structure.
|
||||
*/
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty)
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t, ivl_type_t type)
|
||||
: NetObj(s, n, 1),
|
||||
type_(t), port_type_(NOT_A_PORT),
|
||||
local_flag_(false), net_type_(ty),
|
||||
discipline_(0),
|
||||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
//XXXX packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0));
|
||||
calculate_slice_widths_from_packed_dims_();
|
||||
|
||||
initialize_dir_();
|
||||
|
||||
s->add_signal(this);
|
||||
}
|
||||
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t, netdarray_t*ty)
|
||||
: NetObj(s, n, 1),
|
||||
type_(t), port_type_(NOT_A_PORT),
|
||||
local_flag_(false), net_type_(ty),
|
||||
discipline_(0),
|
||||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
initialize_dir_();
|
||||
|
||||
s->add_signal(this);
|
||||
}
|
||||
|
||||
NetNet::NetNet(NetScope*s, perm_string n, Type t, netvector_t*ty)
|
||||
: NetObj(s, n, 1),
|
||||
type_(t), port_type_(NOT_A_PORT),
|
||||
local_flag_(false), net_type_(ty),
|
||||
local_flag_(false), net_type_(type),
|
||||
discipline_(0),
|
||||
eref_count_(0), lref_count_(0)
|
||||
{
|
||||
|
|
@ -2188,6 +2159,7 @@ NetEUFunc::NetEUFunc(NetScope*scope, NetScope*def, NetESignal*res,
|
|||
: scope_(scope), func_(def), result_sig_(res), parms_(p), need_const_(nc)
|
||||
{
|
||||
expr_width(result_sig_->expr_width());
|
||||
cast_signed_base_(result_sig_->has_sign());
|
||||
}
|
||||
|
||||
NetEUFunc::~NetEUFunc()
|
||||
|
|
|
|||
|
|
@ -679,12 +679,7 @@ class NetNet : public NetObj, public PortType {
|
|||
const std::list<netrange_t>&unpacked,
|
||||
ivl_type_t type);
|
||||
|
||||
// This form builds a NetNet from its record/enum/darray
|
||||
// definition. They should probably be replaced with a single
|
||||
// version that takes an ivl_type_s* base.
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type);
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, netdarray_t*type);
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, netvector_t*type);
|
||||
explicit NetNet(NetScope*s, perm_string n, Type t, ivl_type_t type);
|
||||
|
||||
virtual ~NetNet();
|
||||
|
||||
|
|
@ -4646,7 +4641,6 @@ class NetESFunc : public NetExpr {
|
|||
NetESFunc(const char*name, ivl_variable_type_t t,
|
||||
unsigned width, unsigned nprms, bool is_overridden =false);
|
||||
NetESFunc(const char*name, ivl_type_t rtype, unsigned nprms);
|
||||
NetESFunc(const char*name, const netenum_t*enum_type, unsigned nprms);
|
||||
~NetESFunc();
|
||||
|
||||
const char* name() const;
|
||||
|
|
|
|||
Loading…
Reference in New Issue