2012-05-29 19:02:10 +02:00
|
|
|
/*
|
2021-01-02 23:04:06 +01:00
|
|
|
* Copyright (c) 2012-2021 Stephen Williams (steve@icarus.com)
|
2012-05-29 19:02:10 +02:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2012-05-29 19:02:10 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "netlist.h"
|
2012-05-30 02:59:29 +02:00
|
|
|
# include "netmisc.h"
|
2012-05-29 22:56:16 +02:00
|
|
|
# include "compiler.h"
|
2012-05-29 19:02:10 +02:00
|
|
|
# include <typeinfo>
|
|
|
|
|
# include "ivl_assert.h"
|
|
|
|
|
|
2018-10-06 18:15:31 +02:00
|
|
|
#if __cplusplus < 201103L
|
|
|
|
|
#define unique_ptr auto_ptr
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
using namespace std;
|
|
|
|
|
|
2013-03-09 13:24:50 +01:00
|
|
|
/*
|
|
|
|
|
* We only evaluate one function at a time, so to support the disable
|
|
|
|
|
* statement, we just need to record the target block and then early
|
|
|
|
|
* terminate each enclosing block or loop statement until we get back
|
|
|
|
|
* to the target block.
|
|
|
|
|
*/
|
|
|
|
|
static const NetScope*disable = 0;
|
|
|
|
|
|
2013-03-06 19:28:43 +01:00
|
|
|
static NetExpr* fix_assign_value(const NetNet*lhs, NetExpr*rhs)
|
|
|
|
|
{
|
|
|
|
|
NetEConst*ce = dynamic_cast<NetEConst*>(rhs);
|
|
|
|
|
if (ce == 0) return rhs;
|
|
|
|
|
|
|
|
|
|
unsigned lhs_width = lhs->vector_width();
|
|
|
|
|
unsigned rhs_width = rhs->expr_width();
|
|
|
|
|
if (rhs_width < lhs_width) {
|
|
|
|
|
rhs = pad_to_width(rhs, lhs_width, *rhs);
|
|
|
|
|
} else if (rhs_width > lhs_width) {
|
|
|
|
|
verinum value(ce->value(), lhs_width);
|
|
|
|
|
ce = new NetEConst(value);
|
|
|
|
|
ce->set_line(*rhs);
|
|
|
|
|
delete rhs;
|
|
|
|
|
rhs = ce;
|
|
|
|
|
}
|
|
|
|
|
rhs->cast_signed(lhs->get_signed());
|
|
|
|
|
return rhs;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<NetExpr*>&args) const
|
|
|
|
|
{
|
2013-04-19 23:07:30 +02:00
|
|
|
// Make the context map.
|
|
|
|
|
map<perm_string,LocalVar>::iterator ptr;
|
|
|
|
|
map<perm_string,LocalVar>context_map;
|
2012-05-29 19:02:10 +02:00
|
|
|
|
2012-05-29 22:56:16 +02:00
|
|
|
if (debug_eval_tree) {
|
2013-06-03 01:56:46 +02:00
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
2013-09-19 03:48:16 +02:00
|
|
|
<< "Evaluate function " << scope()->basename() << endl;
|
2012-05-29 22:56:16 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
// Put the return value into the map...
|
2013-09-19 03:48:16 +02:00
|
|
|
LocalVar&return_var = context_map[scope()->basename()];
|
2013-04-19 23:07:30 +02:00
|
|
|
return_var.nwords = 0;
|
|
|
|
|
return_var.value = 0;
|
2012-05-30 02:59:29 +02:00
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
// Load the input ports into the map...
|
2013-09-19 03:48:16 +02:00
|
|
|
ivl_assert(loc, port_count() == args.size());
|
|
|
|
|
for (size_t idx = 0 ; idx < port_count() ; idx += 1) {
|
|
|
|
|
const NetNet*pnet = port(idx);
|
|
|
|
|
perm_string aname = pnet->name();
|
2013-04-19 23:07:30 +02:00
|
|
|
LocalVar&input_var = context_map[aname];
|
|
|
|
|
input_var.nwords = 0;
|
2013-09-19 03:48:16 +02:00
|
|
|
input_var.value = fix_assign_value(pnet, args[idx]);
|
2012-05-29 22:56:16 +02:00
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
2013-06-03 01:56:46 +02:00
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
2012-06-05 10:13:06 +02:00
|
|
|
<< " input " << aname << " = " << *args[idx] << endl;
|
2012-05-29 22:56:16 +02:00
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-30 02:59:29 +02:00
|
|
|
// Ask the scope to collect definitions for local values. This
|
|
|
|
|
// fills in the context_map with local variables held by the scope.
|
2013-09-19 03:48:16 +02:00
|
|
|
scope()->evaluate_function_find_locals(loc, context_map);
|
2012-05-30 02:59:29 +02:00
|
|
|
|
2016-03-19 14:04:38 +01:00
|
|
|
// Execute any variable initialization statements.
|
|
|
|
|
if (const NetProc*init_proc = scope()->var_init())
|
|
|
|
|
init_proc->evaluate_function(loc, context_map);
|
|
|
|
|
|
2013-09-19 03:48:16 +02:00
|
|
|
if (debug_eval_tree && proc_==0) {
|
2013-06-01 23:39:43 +02:00
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
2013-09-19 03:48:16 +02:00
|
|
|
<< "Function " << scope_path(scope())
|
2013-06-01 23:39:43 +02:00
|
|
|
<< " has no statement?" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-06 10:33:29 +01:00
|
|
|
// Perform the evaluation. Note that if there were errors
|
|
|
|
|
// when compiling the function definition, we may not have
|
|
|
|
|
// a valid statement.
|
2013-09-19 03:48:16 +02:00
|
|
|
bool flag = proc_ && proc_->evaluate_function(loc, context_map);
|
2012-05-29 19:02:10 +02:00
|
|
|
|
2013-06-01 23:39:43 +02:00
|
|
|
if (debug_eval_tree && !flag) {
|
|
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
2013-09-19 03:48:16 +02:00
|
|
|
<< "Cannot evaluate " << scope_path(scope()) << "." << endl;
|
2013-06-01 23:39:43 +02:00
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
// Extract the result...
|
2013-09-19 03:48:16 +02:00
|
|
|
ptr = context_map.find(scope()->basename());
|
2013-04-19 23:07:30 +02:00
|
|
|
NetExpr*res = ptr->second.value;
|
2012-05-29 19:02:10 +02:00
|
|
|
context_map.erase(ptr);
|
|
|
|
|
|
|
|
|
|
// Cleanup the rest of the context.
|
|
|
|
|
for (ptr = context_map.begin() ; ptr != context_map.end() ; ++ptr) {
|
2013-04-19 23:07:30 +02:00
|
|
|
|
|
|
|
|
unsigned nwords = ptr->second.nwords;
|
|
|
|
|
if (nwords > 0) {
|
|
|
|
|
NetExpr**array = ptr->second.array;
|
|
|
|
|
for (unsigned idx = 0 ; idx < nwords ; idx += 1) {
|
|
|
|
|
delete array[idx];
|
|
|
|
|
}
|
|
|
|
|
delete [] ptr->second.array;
|
|
|
|
|
} else {
|
|
|
|
|
delete ptr->second.value;
|
|
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 01:56:46 +02:00
|
|
|
if (disable) {
|
|
|
|
|
if (debug_eval_tree)
|
|
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
|
|
|
|
<< "disable of " << scope_path(disable)
|
2013-09-19 03:48:16 +02:00
|
|
|
<< " trapped in function " << scope_path(scope())
|
2013-06-03 01:56:46 +02:00
|
|
|
<< "." << endl;
|
2013-09-19 03:48:16 +02:00
|
|
|
ivl_assert(loc, disable==scope());
|
2013-06-03 01:56:46 +02:00
|
|
|
disable = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
// Done.
|
2013-06-03 01:56:46 +02:00
|
|
|
if (flag) {
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
2014-01-29 00:50:27 +01:00
|
|
|
<< "Evaluated to ";
|
2013-06-03 01:56:46 +02:00
|
|
|
if (res) cerr << *res;
|
|
|
|
|
else cerr << "<nil>";
|
|
|
|
|
cerr << endl;
|
|
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
return res;
|
2013-06-03 01:56:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
|
|
|
|
<< "Evaluation failed." << endl;
|
|
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
|
|
|
|
|
delete res;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-30 02:59:29 +02:00
|
|
|
void NetScope::evaluate_function_find_locals(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-30 02:59:29 +02:00
|
|
|
{
|
|
|
|
|
for (map<perm_string,NetNet*>::const_iterator cur = signals_map_.begin()
|
|
|
|
|
; cur != signals_map_.end() ; ++cur) {
|
|
|
|
|
|
|
|
|
|
const NetNet*tmp = cur->second;
|
|
|
|
|
// Skip ports, which are handled elsewhere.
|
|
|
|
|
if (tmp->port_type() != NetNet::NOT_A_PORT)
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
unsigned nwords = 0;
|
|
|
|
|
if (tmp->unpacked_dimensions() > 0)
|
|
|
|
|
nwords = tmp->unpacked_count();
|
|
|
|
|
|
|
|
|
|
LocalVar&local_var = context_map[tmp->name()];
|
|
|
|
|
local_var.nwords = nwords;
|
|
|
|
|
|
|
|
|
|
if (nwords > 0) {
|
|
|
|
|
NetExpr**array = new NetExpr*[nwords];
|
|
|
|
|
for (unsigned idx = 0 ; idx < nwords ; idx += 1) {
|
|
|
|
|
array[idx] = 0;
|
|
|
|
|
}
|
|
|
|
|
local_var.array = array;
|
|
|
|
|
} else {
|
|
|
|
|
local_var.value = 0;
|
|
|
|
|
}
|
2012-05-30 02:59:29 +02:00
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << loc.get_fileline() << ": debug: "
|
2013-04-19 23:07:30 +02:00
|
|
|
<< " (local) " << tmp->name()
|
|
|
|
|
<< (nwords > 0 ? "[]" : "") << endl;
|
2012-05-30 02:59:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
NetExpr* NetExpr::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2012-05-29 19:02:10 +02:00
|
|
|
{
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't know how to evaluate this expression at compile time." << endl;
|
|
|
|
|
cerr << get_fileline() << ": : Expression type:" << typeid(*this).name() << endl;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetProc::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2012-05-29 19:02:10 +02:00
|
|
|
{
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't know how to evaluate this statement at compile time." << endl;
|
|
|
|
|
cerr << get_fileline() << ": : Statement type:" << typeid(*this).name() << endl;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-23 00:31:35 +01:00
|
|
|
void NetAssign::eval_func_lval_op_real_(const LineInfo&loc,
|
2021-01-02 23:04:06 +01:00
|
|
|
verireal&lv, const verireal&rv) const
|
2016-02-23 00:31:35 +01:00
|
|
|
{
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '+':
|
|
|
|
|
lv = lv + rv;
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
lv = lv - rv;
|
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
lv = lv * rv;
|
|
|
|
|
break;
|
|
|
|
|
case '/':
|
|
|
|
|
lv = lv / rv;
|
|
|
|
|
break;
|
|
|
|
|
case '%':
|
|
|
|
|
lv = lv % rv;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cerr << "Illegal assignment operator: "
|
|
|
|
|
<< human_readable_op(op_) << endl;
|
|
|
|
|
ivl_assert(loc, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-22 23:22:22 +01:00
|
|
|
void NetAssign::eval_func_lval_op_(const LineInfo&loc,
|
|
|
|
|
verinum&lv, verinum&rv) const
|
|
|
|
|
{
|
|
|
|
|
unsigned lv_width = lv.len();
|
|
|
|
|
bool lv_sign = lv.has_sign();
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case 'l':
|
|
|
|
|
case 'R':
|
|
|
|
|
// The left operand is self-determined.
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
// The left operand is self-determined, but we need to
|
|
|
|
|
// cast it to unsigned to get a logical shift.
|
|
|
|
|
lv.has_sign(false);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// The left operand must be cast to the expression type/size
|
|
|
|
|
lv.has_sign(rv.has_sign());
|
2016-02-23 17:46:26 +01:00
|
|
|
lv = cast_to_width(lv, rv.len());
|
2016-02-22 23:22:22 +01:00
|
|
|
}
|
|
|
|
|
switch (op_) {
|
|
|
|
|
case '+':
|
|
|
|
|
lv = lv + rv;
|
|
|
|
|
break;
|
|
|
|
|
case '-':
|
|
|
|
|
lv = lv - rv;
|
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
lv = lv * rv;
|
|
|
|
|
break;
|
|
|
|
|
case '/':
|
|
|
|
|
lv = lv / rv;
|
|
|
|
|
break;
|
|
|
|
|
case '%':
|
|
|
|
|
lv = lv % rv;
|
|
|
|
|
break;
|
|
|
|
|
case '&':
|
|
|
|
|
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
|
|
|
|
lv.set(idx, lv[idx] & rv[idx]);
|
|
|
|
|
break;
|
|
|
|
|
case '|':
|
|
|
|
|
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
|
|
|
|
lv.set(idx, lv[idx] | rv[idx]);
|
|
|
|
|
break;
|
|
|
|
|
case '^':
|
|
|
|
|
for (unsigned idx = 0 ; idx < lv.len() ; idx += 1)
|
|
|
|
|
lv.set(idx, lv[idx] ^ rv[idx]);
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
|
|
|
|
lv = lv << rv.as_unsigned();
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
lv = lv >> rv.as_unsigned();
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
lv = lv >> rv.as_unsigned();
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2016-02-23 00:31:35 +01:00
|
|
|
cerr << "Illegal assignment operator: "
|
|
|
|
|
<< human_readable_op(op_) << endl;
|
2016-02-22 23:22:22 +01:00
|
|
|
ivl_assert(loc, 0);
|
|
|
|
|
}
|
|
|
|
|
lv = cast_to_width(lv, lv_width);
|
|
|
|
|
lv.has_sign(lv_sign);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 18:46:14 +02:00
|
|
|
bool NetAssign::eval_func_lval_(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map,
|
2013-04-16 18:46:14 +02:00
|
|
|
const NetAssign_*lval, NetExpr*rval_result) const
|
2012-05-29 19:02:10 +02:00
|
|
|
{
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>::iterator ptr = context_map.find(lval->name());
|
2012-05-30 02:59:29 +02:00
|
|
|
ivl_assert(*this, ptr != context_map.end());
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
LocalVar*var = & ptr->second;
|
|
|
|
|
while (var->nwords == -1) {
|
|
|
|
|
assert(var->ref);
|
|
|
|
|
var = var->ref;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
NetExpr*old_lval;
|
2013-06-06 04:28:51 +02:00
|
|
|
int word = 0;
|
|
|
|
|
if (var->nwords > 0) {
|
2013-04-19 23:07:30 +02:00
|
|
|
NetExpr*word_result = lval->word()->evaluate_function(loc, context_map);
|
|
|
|
|
if (word_result == 0) {
|
|
|
|
|
delete rval_result;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*word_const = dynamic_cast<NetEConst*>(word_result);
|
|
|
|
|
ivl_assert(loc, word_const);
|
|
|
|
|
|
2013-05-18 20:39:24 +02:00
|
|
|
if (!word_const->value().is_defined())
|
|
|
|
|
return true;
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
word = word_const->value().as_long();
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
if (word >= var->nwords)
|
2013-04-19 23:07:30 +02:00
|
|
|
return true;
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
old_lval = var->array[word];
|
2013-04-19 23:07:30 +02:00
|
|
|
} else {
|
2013-06-06 04:28:51 +02:00
|
|
|
assert(var->nwords == 0);
|
|
|
|
|
old_lval = var->value;
|
2013-04-19 23:07:30 +02:00
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
|
2012-05-30 02:59:29 +02:00
|
|
|
if (const NetExpr*base_expr = lval->get_base()) {
|
|
|
|
|
NetExpr*base_result = base_expr->evaluate_function(loc, context_map);
|
|
|
|
|
if (base_result == 0) {
|
|
|
|
|
delete rval_result;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*base_const = dynamic_cast<NetEConst*>(base_result);
|
|
|
|
|
ivl_assert(loc, base_const);
|
|
|
|
|
|
|
|
|
|
long base = base_const->value().as_long();
|
|
|
|
|
|
|
|
|
|
list<long>prefix (0);
|
|
|
|
|
base = lval->sig()->sb_to_idx(prefix, base);
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
if (old_lval == 0)
|
|
|
|
|
old_lval = make_const_x(lval->sig()->vector_width());
|
2012-05-30 02:59:29 +02:00
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
ivl_assert(loc, base + lval->lwidth() <= old_lval->expr_width());
|
2012-05-30 02:59:29 +02:00
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
|
2016-02-23 00:31:35 +01:00
|
|
|
ivl_assert(loc, lval_const);
|
2013-04-19 23:07:30 +02:00
|
|
|
verinum lval_v = lval_const->value();
|
2012-05-30 02:59:29 +02:00
|
|
|
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
2016-02-23 00:31:35 +01:00
|
|
|
ivl_assert(loc, rval_const);
|
2016-02-22 23:22:22 +01:00
|
|
|
verinum rval_v = rval_const->value();
|
2012-05-30 02:59:29 +02:00
|
|
|
|
2016-02-22 23:22:22 +01:00
|
|
|
verinum lpart(verinum::Vx, lval->lwidth());
|
|
|
|
|
if (op_) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
|
|
|
|
|
lpart.set(idx, lval_v[base+idx]);
|
|
|
|
|
|
|
|
|
|
eval_func_lval_op_(loc, lpart, rval_v);
|
|
|
|
|
} else {
|
|
|
|
|
lpart = cast_to_width(rval_v, lval->lwidth());
|
|
|
|
|
}
|
|
|
|
|
for (unsigned idx = 0 ; idx < lpart.len() ; idx += 1)
|
|
|
|
|
lval_v.set(idx+base, lpart[idx]);
|
2012-05-30 02:59:29 +02:00
|
|
|
|
|
|
|
|
delete base_result;
|
|
|
|
|
delete rval_result;
|
|
|
|
|
rval_result = new NetEConst(lval_v);
|
2013-02-26 23:39:04 +01:00
|
|
|
} else {
|
2016-02-23 00:31:35 +01:00
|
|
|
if (op_ == 0) {
|
|
|
|
|
rval_result = fix_assign_value(lval->sig(), rval_result);
|
|
|
|
|
} else if (dynamic_cast<NetECReal*>(rval_result)) {
|
|
|
|
|
NetECReal*lval_const = dynamic_cast<NetECReal*>(old_lval);
|
|
|
|
|
ivl_assert(loc, lval_const);
|
|
|
|
|
verireal lval_r = lval_const->value();
|
|
|
|
|
NetECReal*rval_const = dynamic_cast<NetECReal*>(rval_result);
|
|
|
|
|
ivl_assert(loc, rval_const);
|
|
|
|
|
verireal rval_r = rval_const->value();
|
|
|
|
|
|
|
|
|
|
eval_func_lval_op_real_(loc, lval_r, rval_r);
|
|
|
|
|
|
|
|
|
|
delete rval_result;
|
|
|
|
|
rval_result = new NetECReal(lval_r);
|
|
|
|
|
} else {
|
2016-02-22 23:22:22 +01:00
|
|
|
NetEConst*lval_const = dynamic_cast<NetEConst*>(old_lval);
|
2016-02-23 00:31:35 +01:00
|
|
|
ivl_assert(loc, lval_const);
|
2016-02-22 23:22:22 +01:00
|
|
|
verinum lval_v = lval_const->value();
|
|
|
|
|
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
2016-02-23 00:31:35 +01:00
|
|
|
ivl_assert(loc, rval_const);
|
2016-02-22 23:22:22 +01:00
|
|
|
verinum rval_v = rval_const->value();
|
|
|
|
|
|
|
|
|
|
eval_func_lval_op_(loc, lval_v, rval_v);
|
|
|
|
|
|
|
|
|
|
delete rval_result;
|
|
|
|
|
rval_result = new NetEConst(lval_v);
|
|
|
|
|
}
|
2012-05-30 02:59:29 +02:00
|
|
|
}
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
if (old_lval)
|
|
|
|
|
delete old_lval;
|
2012-05-29 22:56:16 +02:00
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
2013-06-03 01:56:46 +02:00
|
|
|
cerr << get_fileline() << ": NetAssign::evaluate_function: "
|
|
|
|
|
<< lval->name() << " = " << *rval_result << endl;
|
2012-05-29 22:56:16 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
if (var->nwords > 0) {
|
|
|
|
|
var->array[word] = rval_result;
|
|
|
|
|
} else {
|
|
|
|
|
assert(var->nwords == 0);
|
|
|
|
|
var->value = rval_result;
|
|
|
|
|
}
|
2012-05-29 19:02:10 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 18:46:14 +02:00
|
|
|
bool NetAssign::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-16 18:46:14 +02:00
|
|
|
{
|
|
|
|
|
// Evaluate the r-value expression.
|
|
|
|
|
NetExpr*rval_result = rval()->evaluate_function(loc, context_map);
|
|
|
|
|
if (rval_result == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Handle the easy case of a single variable on the LHS.
|
|
|
|
|
if (l_val_count() == 1)
|
|
|
|
|
return eval_func_lval_(loc, context_map, l_val(0), rval_result);
|
|
|
|
|
|
|
|
|
|
// If we get here, the LHS must be a concatenation, so we
|
|
|
|
|
// expect the RHS to be a vector value.
|
|
|
|
|
NetEConst*rval_const = dynamic_cast<NetEConst*>(rval_result);
|
|
|
|
|
ivl_assert(*this, rval_const);
|
|
|
|
|
|
2016-02-23 00:31:35 +01:00
|
|
|
if (op_) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: Assignment operators "
|
|
|
|
|
"inside a constant function are not currently "
|
|
|
|
|
"supported if the LHS is a concatenation." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 18:46:14 +02:00
|
|
|
verinum rval_full = rval_const->value();
|
|
|
|
|
delete rval_result;
|
|
|
|
|
|
|
|
|
|
unsigned base = 0;
|
|
|
|
|
for (unsigned ldx = 0 ; ldx < l_val_count() ; ldx += 1) {
|
|
|
|
|
const NetAssign_*lval = l_val(ldx);
|
|
|
|
|
|
|
|
|
|
verinum rval_part(verinum::Vx, lval->lwidth());
|
|
|
|
|
for (unsigned idx = 0 ; idx < rval_part.len() ; idx += 1)
|
|
|
|
|
rval_part.set(idx, rval_full[base+idx]);
|
|
|
|
|
|
|
|
|
|
bool flag = eval_func_lval_(loc, context_map, lval,
|
|
|
|
|
new NetEConst(rval_part));
|
|
|
|
|
if (!flag) return false;
|
|
|
|
|
|
|
|
|
|
base += lval->lwidth();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
/*
|
|
|
|
|
* Evaluating a NetBlock in a function is a simple matter of
|
|
|
|
|
* evaluating the statements in order.
|
|
|
|
|
*/
|
|
|
|
|
bool NetBlock::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-29 19:02:10 +02:00
|
|
|
{
|
2013-06-06 04:28:51 +02:00
|
|
|
if (last_ == 0) return true;
|
|
|
|
|
|
|
|
|
|
// If we need to make a local scope, then this context map
|
|
|
|
|
// will be filled in and used for statements within this block.
|
|
|
|
|
map<perm_string,LocalVar>local_context_map;
|
|
|
|
|
bool use_local_context_map = false;
|
|
|
|
|
|
|
|
|
|
if (subscope_!=0) {
|
|
|
|
|
// First, copy the containing scope symbols into the new
|
|
|
|
|
// scope as references.
|
|
|
|
|
for (map<perm_string,LocalVar>::iterator cur = context_map.begin()
|
|
|
|
|
; cur != context_map.end() ; ++cur) {
|
|
|
|
|
LocalVar&cur_var = local_context_map[cur->first];
|
|
|
|
|
cur_var.nwords = -1;
|
|
|
|
|
if (cur->second.nwords == -1)
|
|
|
|
|
cur_var.ref = cur->second.ref;
|
|
|
|
|
else
|
|
|
|
|
cur_var.ref = &cur->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now collect the new locals.
|
|
|
|
|
subscope_->evaluate_function_find_locals(loc, local_context_map);
|
|
|
|
|
use_local_context_map = true;
|
2016-03-19 14:04:38 +01:00
|
|
|
|
|
|
|
|
// Execute any variable initialization statements.
|
|
|
|
|
if (const NetProc*init_proc = subscope_->var_init())
|
|
|
|
|
init_proc->evaluate_function(loc, local_context_map);
|
2013-06-06 04:28:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Now use the local context map if there is any local
|
|
|
|
|
// context, or the containing context map.
|
|
|
|
|
map<perm_string,LocalVar>&use_context_map = use_local_context_map? local_context_map : context_map;
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
NetProc*cur = last_;
|
|
|
|
|
do {
|
|
|
|
|
cur = cur->next_;
|
2013-06-06 04:28:51 +02:00
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetBlock::evaluate_function: "
|
|
|
|
|
<< "Execute statement (" << typeid(*cur).name()
|
|
|
|
|
<< ") at " << cur->get_fileline() << "." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool cur_flag = cur->evaluate_function(loc, use_context_map);
|
2012-05-29 19:02:10 +02:00
|
|
|
flag = flag && cur_flag;
|
2013-03-09 13:24:50 +01:00
|
|
|
} while (cur != last_ && !disable);
|
|
|
|
|
|
2013-06-03 01:56:46 +02:00
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetBlock::evaluate_function: "
|
2013-06-06 04:28:51 +02:00
|
|
|
<< "subscope_=" << subscope_
|
|
|
|
|
<< ", disable=" << disable
|
|
|
|
|
<< ", flag=" << (flag?"true":"false") << endl;
|
2013-06-03 01:56:46 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
if (disable == subscope_) disable = 0;
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-07 20:13:30 +02:00
|
|
|
bool NetCase::evaluate_function_vect_(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-07 20:13:30 +02:00
|
|
|
{
|
|
|
|
|
NetExpr*case_expr = expr_->evaluate_function(loc, context_map);
|
|
|
|
|
if (case_expr == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
NetEConst*case_const = dynamic_cast<NetEConst*> (case_expr);
|
|
|
|
|
ivl_assert(loc, case_const);
|
|
|
|
|
|
|
|
|
|
verinum case_val = case_const->value();
|
|
|
|
|
delete case_expr;
|
|
|
|
|
|
|
|
|
|
NetProc*default_statement = 0;
|
|
|
|
|
|
2014-06-14 03:01:41 +02:00
|
|
|
for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) {
|
|
|
|
|
const Item*item = &items_[cnt];
|
2013-04-07 20:13:30 +02:00
|
|
|
|
|
|
|
|
if (item->guard == 0) {
|
|
|
|
|
default_statement = item->statement;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*item_expr = item->guard->evaluate_function(loc, context_map);
|
|
|
|
|
if (item_expr == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
NetEConst*item_const = dynamic_cast<NetEConst*> (item_expr);
|
|
|
|
|
ivl_assert(loc, item_const);
|
|
|
|
|
|
|
|
|
|
verinum item_val = item_const->value();
|
|
|
|
|
delete item_expr;
|
|
|
|
|
|
|
|
|
|
ivl_assert(loc, item_val.len() == case_val.len());
|
|
|
|
|
|
|
|
|
|
bool match = true;
|
|
|
|
|
for (unsigned idx = 0 ; idx < item_val.len() ; idx += 1) {
|
|
|
|
|
verinum::V bit_a = case_val.get(idx);
|
|
|
|
|
verinum::V bit_b = item_val.get(idx);
|
|
|
|
|
|
|
|
|
|
if (bit_a == verinum::Vx && type_ == EQX) continue;
|
|
|
|
|
if (bit_b == verinum::Vx && type_ == EQX) continue;
|
|
|
|
|
|
|
|
|
|
if (bit_a == verinum::Vz && type_ != EQ) continue;
|
|
|
|
|
if (bit_b == verinum::Vz && type_ != EQ) continue;
|
|
|
|
|
|
|
|
|
|
if (bit_a != bit_b) {
|
|
|
|
|
match = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!match) continue;
|
|
|
|
|
|
|
|
|
|
return item->statement->evaluate_function(loc, context_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (default_statement)
|
|
|
|
|
return default_statement->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetCase::evaluate_function_real_(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-07 20:13:30 +02:00
|
|
|
{
|
|
|
|
|
NetExpr*case_expr = expr_->evaluate_function(loc, context_map);
|
|
|
|
|
if (case_expr == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
NetECReal*case_const = dynamic_cast<NetECReal*> (case_expr);
|
|
|
|
|
ivl_assert(loc, case_const);
|
|
|
|
|
|
|
|
|
|
double case_val = case_const->value().as_double();
|
|
|
|
|
delete case_expr;
|
|
|
|
|
|
|
|
|
|
NetProc*default_statement = 0;
|
|
|
|
|
|
2014-06-14 03:01:41 +02:00
|
|
|
for (unsigned cnt = 0 ; cnt < items_.size() ; cnt += 1) {
|
|
|
|
|
const Item*item = &items_[cnt];
|
2013-04-07 20:13:30 +02:00
|
|
|
|
|
|
|
|
if (item->guard == 0) {
|
|
|
|
|
default_statement = item->statement;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*item_expr = item->guard->evaluate_function(loc, context_map);
|
|
|
|
|
if (item_expr == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
NetECReal*item_const = dynamic_cast<NetECReal*> (item_expr);
|
|
|
|
|
ivl_assert(loc, item_const);
|
|
|
|
|
|
|
|
|
|
double item_val = item_const->value().as_double();
|
|
|
|
|
delete item_expr;
|
|
|
|
|
|
|
|
|
|
if (item_val != case_val) continue;
|
|
|
|
|
|
|
|
|
|
return item->statement->evaluate_function(loc, context_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (default_statement)
|
|
|
|
|
return default_statement->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetCase::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-07 20:13:30 +02:00
|
|
|
{
|
|
|
|
|
if (expr_->expr_type() == IVL_VT_REAL)
|
|
|
|
|
return evaluate_function_real_(loc, context_map);
|
|
|
|
|
else
|
|
|
|
|
return evaluate_function_vect_(loc, context_map);
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-05 10:13:06 +02:00
|
|
|
bool NetCondit::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-06-05 10:13:06 +02:00
|
|
|
{
|
|
|
|
|
NetExpr*cond = expr_->evaluate_function(loc, context_map);
|
2013-06-03 01:56:46 +02:00
|
|
|
if (cond == 0) {
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetCondit::evaluate_function: "
|
|
|
|
|
<< "Unable to evaluate condition (" << *expr_ <<")" << endl;
|
|
|
|
|
}
|
2012-06-05 10:13:06 +02:00
|
|
|
return false;
|
2013-06-03 01:56:46 +02:00
|
|
|
}
|
2012-06-05 10:13:06 +02:00
|
|
|
|
|
|
|
|
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
|
|
|
|
|
ivl_assert(loc, cond_const);
|
|
|
|
|
|
|
|
|
|
long val = cond_const->value().as_long();
|
|
|
|
|
delete cond;
|
|
|
|
|
|
2013-06-03 01:56:46 +02:00
|
|
|
bool flag;
|
|
|
|
|
|
2012-06-05 10:13:06 +02:00
|
|
|
if (val)
|
|
|
|
|
// The condition is true, so evaluate the if clause
|
2013-06-03 01:56:46 +02:00
|
|
|
flag = (if_ == 0) || if_->evaluate_function(loc, context_map);
|
2012-06-05 10:13:06 +02:00
|
|
|
else
|
|
|
|
|
// The condition is false, so evaluate the else clause
|
2013-06-03 01:56:46 +02:00
|
|
|
flag = (else_ == 0) || else_->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetCondit::evaluate_function: "
|
|
|
|
|
<< "Finished, flag=" << (flag?"true":"false") << endl;
|
|
|
|
|
}
|
|
|
|
|
return flag;
|
2012-06-05 10:13:06 +02:00
|
|
|
}
|
|
|
|
|
|
2013-03-09 13:24:50 +01:00
|
|
|
bool NetDisable::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2013-03-09 13:24:50 +01:00
|
|
|
{
|
|
|
|
|
disable = target_;
|
2013-06-03 01:56:46 +02:00
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetDisable::evaluate_function: "
|
|
|
|
|
<< "disable " << scope_path(disable) << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-09 13:24:50 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-17 05:01:06 +02:00
|
|
|
bool NetDoWhile::evaluate_function(const LineInfo&loc,
|
|
|
|
|
map<perm_string,LocalVar>&context_map) const
|
|
|
|
|
{
|
|
|
|
|
bool flag = true;
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetDoWhile::evaluate_function: "
|
|
|
|
|
<< "Start loop" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!disable) {
|
|
|
|
|
// Evaluate the statement.
|
|
|
|
|
flag = proc_->evaluate_function(loc, context_map);
|
|
|
|
|
if (! flag)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// Evaluate the condition expression to try and get the
|
|
|
|
|
// condition for the loop.
|
|
|
|
|
NetExpr*cond = cond_->evaluate_function(loc, context_map);
|
|
|
|
|
if (cond == 0) {
|
|
|
|
|
flag = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
|
|
|
|
|
ivl_assert(loc, cond_const);
|
|
|
|
|
|
|
|
|
|
long val = cond_const->value().as_long();
|
|
|
|
|
delete cond;
|
|
|
|
|
|
|
|
|
|
// If the condition is false, then the loop is done.
|
|
|
|
|
if (val == 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": NetDoWhile::evaluate_function: "
|
|
|
|
|
<< "Done loop, flag=" << (flag?"true":"false") << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-07 20:13:30 +02:00
|
|
|
bool NetForever::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-07 20:13:30 +02:00
|
|
|
{
|
|
|
|
|
bool flag = true;
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": debug: NetForever::evaluate_function: "
|
|
|
|
|
<< "Start loop" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (flag && !disable) {
|
|
|
|
|
flag = flag && statement_->evaluate_function(loc, context_map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": debug: NetForever::evaluate_function: "
|
|
|
|
|
<< "Done loop" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-02 05:37:33 +02:00
|
|
|
/*
|
|
|
|
|
* For now, resort to the block form of the statement until we learn
|
|
|
|
|
* to do this directly.
|
|
|
|
|
*/
|
|
|
|
|
bool NetForLoop::evaluate_function(const LineInfo&loc,
|
|
|
|
|
map<perm_string,LocalVar>&context_map) const
|
|
|
|
|
{
|
|
|
|
|
return as_block_->evaluate_function(loc, context_map);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-07 20:13:30 +02:00
|
|
|
bool NetRepeat::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-04-07 20:13:30 +02:00
|
|
|
{
|
|
|
|
|
bool flag = true;
|
|
|
|
|
|
|
|
|
|
// Evaluate the condition expression to try and get the
|
|
|
|
|
// condition for the loop.
|
|
|
|
|
NetExpr*count_expr = expr_->evaluate_function(loc, context_map);
|
|
|
|
|
if (count_expr == 0) return false;
|
|
|
|
|
|
|
|
|
|
NetEConst*count_const = dynamic_cast<NetEConst*> (count_expr);
|
|
|
|
|
ivl_assert(loc, count_const);
|
|
|
|
|
|
|
|
|
|
long count = count_const->value().as_long();
|
|
|
|
|
delete count_expr;
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": debug: NetRepeat::evaluate_function: "
|
|
|
|
|
<< "Repeating " << count << " times." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ((count > 0) && flag && !disable) {
|
|
|
|
|
flag = flag && statement_->evaluate_function(loc, context_map);
|
|
|
|
|
count -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
|
|
|
|
cerr << get_fileline() << ": debug: NetRepeat::evaluate_function: "
|
|
|
|
|
<< "Finished loop" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-09 13:24:50 +01:00
|
|
|
bool NetSTask::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2013-03-09 13:24:50 +01:00
|
|
|
{
|
|
|
|
|
// system tasks within a constant function are ignored
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 22:56:16 +02:00
|
|
|
bool NetWhile::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-29 22:56:16 +02:00
|
|
|
{
|
|
|
|
|
bool flag = true;
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
2013-06-03 01:56:46 +02:00
|
|
|
cerr << get_fileline() << ": NetWhile::evaluate_function: "
|
2012-05-29 22:56:16 +02:00
|
|
|
<< "Start loop" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-09 13:24:50 +01:00
|
|
|
while (flag && !disable) {
|
2012-05-29 22:56:16 +02:00
|
|
|
// Evaluate the condition expression to try and get the
|
|
|
|
|
// condition for the loop.
|
|
|
|
|
NetExpr*cond = cond_->evaluate_function(loc, context_map);
|
|
|
|
|
if (cond == 0) {
|
|
|
|
|
flag = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
|
|
|
|
|
ivl_assert(loc, cond_const);
|
|
|
|
|
|
|
|
|
|
long val = cond_const->value().as_long();
|
|
|
|
|
delete cond;
|
|
|
|
|
|
|
|
|
|
// If the condition is false, then break.
|
|
|
|
|
if (val == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
2012-07-11 00:36:33 +02:00
|
|
|
// The condition is true, so evaluate the statement
|
2012-05-29 22:56:16 +02:00
|
|
|
// another time.
|
|
|
|
|
bool tmp_flag = proc_->evaluate_function(loc, context_map);
|
|
|
|
|
if (! tmp_flag)
|
|
|
|
|
flag = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (debug_eval_tree) {
|
2013-06-03 01:56:46 +02:00
|
|
|
cerr << get_fileline() << ": NetWhile::evaluate_function: "
|
|
|
|
|
<< "Done loop, flag=" << (flag?"true":"false") << endl;
|
2012-05-29 22:56:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-03 10:32:49 +01:00
|
|
|
NetExpr* NetEBinary::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-30 02:59:29 +02:00
|
|
|
{
|
|
|
|
|
NetExpr*lval = left_->evaluate_function(loc, context_map);
|
|
|
|
|
NetExpr*rval = right_->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
if (lval == 0 || rval == 0) {
|
|
|
|
|
delete lval;
|
|
|
|
|
delete rval;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*res = eval_arguments_(lval, rval);
|
|
|
|
|
delete lval;
|
|
|
|
|
delete rval;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-06 10:33:29 +01:00
|
|
|
NetExpr* NetEConcat::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-02-06 10:33:29 +01:00
|
|
|
{
|
|
|
|
|
vector<NetExpr*>vals(parms_.size());
|
|
|
|
|
unsigned gap = 0;
|
|
|
|
|
|
|
|
|
|
unsigned valid_vals = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
|
|
|
|
|
ivl_assert(*this, parms_[idx]);
|
|
|
|
|
vals[idx] = parms_[idx]->evaluate_function(loc, context_map);
|
|
|
|
|
if (vals[idx] == 0) continue;
|
|
|
|
|
|
|
|
|
|
gap += vals[idx]->expr_width();
|
|
|
|
|
|
|
|
|
|
valid_vals += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*res = 0;
|
|
|
|
|
if (valid_vals == parms_.size()) {
|
|
|
|
|
res = eval_arguments_(vals, gap);
|
|
|
|
|
}
|
|
|
|
|
for (unsigned idx = 0 ; idx < vals.size() ; idx += 1) {
|
|
|
|
|
delete vals[idx];
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-29 19:02:10 +02:00
|
|
|
NetExpr* NetEConst::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2012-05-29 19:02:10 +02:00
|
|
|
{
|
|
|
|
|
NetEConst*res = new NetEConst(value_);
|
|
|
|
|
res->set_line(*this);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2012-05-29 22:56:16 +02:00
|
|
|
|
2013-02-03 14:51:39 +01:00
|
|
|
NetExpr* NetECReal::evaluate_function(const LineInfo&,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&) const
|
2013-02-03 14:51:39 +01:00
|
|
|
{
|
|
|
|
|
NetECReal*res = new NetECReal(value_);
|
|
|
|
|
res->set_line(*this);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-30 02:59:29 +02:00
|
|
|
NetExpr* NetESelect::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-30 02:59:29 +02:00
|
|
|
{
|
|
|
|
|
NetExpr*sub_exp = expr_->evaluate_function(loc, context_map);
|
|
|
|
|
ivl_assert(loc, sub_exp);
|
|
|
|
|
|
|
|
|
|
NetEConst*sub_const = dynamic_cast<NetEConst*> (sub_exp);
|
|
|
|
|
ivl_assert(loc, sub_exp);
|
|
|
|
|
|
|
|
|
|
verinum sub = sub_const->value();
|
|
|
|
|
delete sub_exp;
|
|
|
|
|
|
|
|
|
|
long base = 0;
|
|
|
|
|
if (base_) {
|
|
|
|
|
NetExpr*base_val = base_->evaluate_function(loc, context_map);
|
|
|
|
|
ivl_assert(loc, base_val);
|
|
|
|
|
|
|
|
|
|
NetEConst*base_const = dynamic_cast<NetEConst*>(base_val);
|
|
|
|
|
ivl_assert(loc, base_const);
|
|
|
|
|
|
|
|
|
|
base = base_const->value().as_long();
|
|
|
|
|
delete base_val;
|
|
|
|
|
} else {
|
2013-04-07 20:13:30 +02:00
|
|
|
sub.has_sign(has_sign());
|
2012-05-30 02:59:29 +02:00
|
|
|
sub = pad_to_width(sub, expr_width());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
verinum res (verinum::Vx, expr_width());
|
|
|
|
|
for (unsigned idx = 0 ; idx < res.len() ; idx += 1)
|
|
|
|
|
res.set(idx, sub[base+idx]);
|
|
|
|
|
|
|
|
|
|
NetEConst*res_const = new NetEConst(res);
|
|
|
|
|
return res_const;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
|
|
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-29 22:56:16 +02:00
|
|
|
{
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>::iterator ptr = context_map.find(name());
|
2012-05-29 22:56:16 +02:00
|
|
|
if (ptr == context_map.end()) {
|
|
|
|
|
cerr << get_fileline() << ": error: Cannot evaluate " << name()
|
|
|
|
|
<< " in this context." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
// Follow indirect references to the actual variable.
|
|
|
|
|
LocalVar*var = & ptr->second;
|
|
|
|
|
while (var->nwords == -1) {
|
|
|
|
|
assert(var->ref);
|
|
|
|
|
var = var->ref;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
NetExpr*value = 0;
|
2013-06-06 04:28:51 +02:00
|
|
|
if (var->nwords > 0) {
|
2013-04-19 23:07:30 +02:00
|
|
|
ivl_assert(loc, word_);
|
|
|
|
|
NetExpr*word_result = word_->evaluate_function(loc, context_map);
|
|
|
|
|
if (word_result == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
NetEConst*word_const = dynamic_cast<NetEConst*>(word_result);
|
|
|
|
|
ivl_assert(loc, word_const);
|
|
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
int word = word_const->value().as_long();
|
2013-04-19 23:07:30 +02:00
|
|
|
|
2013-06-06 04:28:51 +02:00
|
|
|
if (word_const->value().is_defined() && (word < var->nwords))
|
|
|
|
|
value = var->array[word];
|
2013-04-19 23:07:30 +02:00
|
|
|
} else {
|
2013-06-06 04:28:51 +02:00
|
|
|
value = var->value;
|
2013-04-19 23:07:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value == 0) {
|
2013-03-06 19:32:05 +01:00
|
|
|
switch (expr_type()) {
|
|
|
|
|
case IVL_VT_REAL:
|
2013-04-19 23:07:30 +02:00
|
|
|
return new NetECReal( verireal(0.0) );
|
2013-03-06 19:32:05 +01:00
|
|
|
case IVL_VT_BOOL:
|
2013-04-19 23:07:30 +02:00
|
|
|
return make_const_0(expr_width());
|
2013-03-06 19:32:05 +01:00
|
|
|
case IVL_VT_LOGIC:
|
2013-04-19 23:07:30 +02:00
|
|
|
return make_const_x(expr_width());
|
2013-03-06 19:32:05 +01:00
|
|
|
default:
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't know how to initialize " << *this << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-19 23:07:30 +02:00
|
|
|
return value->dup_expr();
|
2012-05-29 22:56:16 +02:00
|
|
|
}
|
2012-05-30 02:59:29 +02:00
|
|
|
|
|
|
|
|
NetExpr* NetETernary::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-05-30 02:59:29 +02:00
|
|
|
{
|
2018-10-06 18:15:31 +02:00
|
|
|
unique_ptr<NetExpr> cval (cond_->evaluate_function(loc, context_map));
|
2012-05-30 02:59:29 +02:00
|
|
|
|
|
|
|
|
switch (const_logical(cval.get())) {
|
|
|
|
|
|
|
|
|
|
case C_0:
|
|
|
|
|
return false_val_->evaluate_function(loc, context_map);
|
|
|
|
|
case C_1:
|
|
|
|
|
return true_val_->evaluate_function(loc, context_map);
|
|
|
|
|
case C_X:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cerr << get_fileline() << ": error: Condition expression is not constant here." << endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetExpr*tval = true_val_->evaluate_function(loc, context_map);
|
|
|
|
|
NetExpr*fval = false_val_->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
NetExpr*res = blended_arguments_(tval, fval);
|
|
|
|
|
delete tval;
|
|
|
|
|
delete fval;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2012-06-05 10:13:06 +02:00
|
|
|
|
2013-02-03 14:51:39 +01:00
|
|
|
NetExpr* NetEUnary::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-02-03 14:51:39 +01:00
|
|
|
{
|
|
|
|
|
NetExpr*val = expr_->evaluate_function(loc, context_map);
|
|
|
|
|
if (val == 0) return 0;
|
|
|
|
|
|
|
|
|
|
NetExpr*res = eval_arguments_(val);
|
|
|
|
|
delete val;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-07 22:07:10 +01:00
|
|
|
NetExpr* NetESFunc::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2013-02-07 22:07:10 +01:00
|
|
|
{
|
|
|
|
|
ID id = built_in_id_();
|
2013-03-11 20:46:00 +01:00
|
|
|
ivl_assert(*this, id != NOT_BUILT_IN);
|
2013-02-07 22:07:10 +01:00
|
|
|
|
|
|
|
|
NetExpr*val0 = 0;
|
|
|
|
|
NetExpr*val1 = 0;
|
|
|
|
|
NetExpr*res = 0;
|
2013-10-11 19:50:45 +02:00
|
|
|
switch (parms_.size()) {
|
2013-02-07 22:07:10 +01:00
|
|
|
case 1:
|
|
|
|
|
val0 = parms_[0]->evaluate_function(loc, context_map);
|
|
|
|
|
if (val0 == 0) break;
|
|
|
|
|
res = evaluate_one_arg_(id, val0);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
val0 = parms_[0]->evaluate_function(loc, context_map);
|
|
|
|
|
val1 = parms_[1]->evaluate_function(loc, context_map);
|
|
|
|
|
if (val0 == 0 || val1 == 0) break;
|
|
|
|
|
res = evaluate_two_arg_(id, val0, val1);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ivl_assert(*this, 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
delete val0;
|
|
|
|
|
delete val1;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-05 10:13:06 +02:00
|
|
|
NetExpr* NetEUFunc::evaluate_function(const LineInfo&loc,
|
2013-04-19 23:07:30 +02:00
|
|
|
map<perm_string,LocalVar>&context_map) const
|
2012-06-05 10:13:06 +02:00
|
|
|
{
|
|
|
|
|
NetFuncDef*def = func_->func_def();
|
|
|
|
|
ivl_assert(*this, def);
|
|
|
|
|
|
|
|
|
|
vector<NetExpr*>args(parms_.size());
|
|
|
|
|
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1)
|
|
|
|
|
args[idx] = parms_[idx]->evaluate_function(loc, context_map);
|
|
|
|
|
|
|
|
|
|
NetExpr*res = def->evaluate_function(*this, args);
|
|
|
|
|
return res;
|
|
|
|
|
}
|