2011-10-16 02:41:48 +02:00
|
|
|
/*
|
2013-04-18 02:12:17 +02:00
|
|
|
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
2015-01-26 17:09:00 +01:00
|
|
|
* Copyright CERN 2015
|
|
|
|
|
* @author Maciej Suminski (maciej.suminski@cern.ch)
|
2011-10-16 02:41:48 +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.
|
2011-10-16 02:41:48 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "expression.h"
|
|
|
|
|
# include "architec.h"
|
|
|
|
|
# include <ivl_assert.h>
|
2015-05-20 18:53:29 +02:00
|
|
|
# include <limits>
|
2011-10-16 02:41:48 +02:00
|
|
|
|
|
|
|
|
bool Expression::evaluate(ScopeBase*, int64_t&) const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 15:00:51 +01:00
|
|
|
bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const
|
2011-10-16 02:41:48 +02:00
|
|
|
{
|
2015-01-26 15:00:51 +01:00
|
|
|
return evaluate(scope, val);
|
2011-10-16 02:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-22 20:42:16 +02:00
|
|
|
bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
|
|
|
|
{
|
|
|
|
|
int64_t val1, val2;
|
|
|
|
|
bool rc;
|
|
|
|
|
|
|
|
|
|
rc = eval_operand1(scope, val1);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
rc = eval_operand2(scope, val2);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch (fun_) {
|
|
|
|
|
case PLUS:
|
|
|
|
|
val = val1 + val2;
|
|
|
|
|
break;
|
|
|
|
|
case MINUS:
|
|
|
|
|
val = val1 - val2;
|
|
|
|
|
break;
|
|
|
|
|
case MULT:
|
|
|
|
|
val = val1 * val2;
|
|
|
|
|
break;
|
|
|
|
|
case DIV:
|
|
|
|
|
if (val2 == 0)
|
|
|
|
|
return false;
|
|
|
|
|
val = val1 / val2;
|
|
|
|
|
break;
|
|
|
|
|
case MOD:
|
|
|
|
|
if (val2 == 0)
|
|
|
|
|
return false;
|
|
|
|
|
val = val1 % val2;
|
|
|
|
|
break;
|
|
|
|
|
case REM:
|
|
|
|
|
return false;
|
|
|
|
|
case POW:
|
|
|
|
|
return false;
|
|
|
|
|
case xCONCAT: // not possible
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 17:09:00 +01:00
|
|
|
bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const
|
2011-10-16 02:41:48 +02:00
|
|
|
{
|
2015-01-26 17:09:00 +01:00
|
|
|
/* Special Case: The array attributes can sometimes be calculated all
|
2011-10-16 02:41:48 +02:00
|
|
|
the down to a literal integer at compile time, and all it
|
|
|
|
|
needs is the type of the base expression. (The base
|
|
|
|
|
expression doesn't even need to be evaluated.) */
|
2015-01-26 17:09:00 +01:00
|
|
|
if (name_ == "length" || name_ == "right" || name_ == "left") {
|
2011-10-16 02:41:48 +02:00
|
|
|
const VType*base_type = base_->peek_type();
|
|
|
|
|
|
2015-01-26 17:09:00 +01:00
|
|
|
if(!base_type) {
|
|
|
|
|
const ExpName*name = NULL;
|
|
|
|
|
|
|
|
|
|
if(scope && (name = dynamic_cast<const ExpName*>(base_))) {
|
|
|
|
|
const perm_string& n = name->peek_name();
|
|
|
|
|
if(const Variable*var = scope->find_variable(n))
|
|
|
|
|
base_type = var->peek_type();
|
|
|
|
|
else if(const Signal*sig = scope->find_signal(n))
|
|
|
|
|
base_type = sig->peek_type();
|
|
|
|
|
else if(const InterfacePort*port = scope->find_param(n))
|
|
|
|
|
base_type = port->type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!base_type)
|
|
|
|
|
return false; // I tried really hard, sorry
|
2011-10-16 02:41:48 +02:00
|
|
|
|
|
|
|
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
|
|
|
|
|
if (arr == 0) {
|
2015-04-20 10:57:49 +02:00
|
|
|
cerr << endl << get_fileline() << ": error: "
|
2015-05-20 12:02:22 +02:00
|
|
|
<< "Cannot apply the '" << name_ << " attribute to non-array objects"
|
2011-10-16 02:41:48 +02:00
|
|
|
<< endl;
|
2015-04-20 10:57:49 +02:00
|
|
|
ivl_assert(*this, false);
|
2011-10-16 02:41:48 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 17:09:00 +01:00
|
|
|
if(name_ == "length") {
|
2015-03-02 14:33:26 +01:00
|
|
|
int64_t size = arr->get_width(scope);
|
2015-01-26 17:09:00 +01:00
|
|
|
|
2015-03-02 14:33:26 +01:00
|
|
|
if(size > 0)
|
|
|
|
|
val = size;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2015-01-26 17:09:00 +01:00
|
|
|
} else if(name_ == "left") {
|
|
|
|
|
arr->dimension(0).msb()->evaluate(scope, val);
|
|
|
|
|
} else if(name_ == "right") {
|
|
|
|
|
arr->dimension(0).lsb()->evaluate(scope, val);
|
|
|
|
|
} else ivl_assert(*this, false);
|
|
|
|
|
|
2011-10-16 02:41:48 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 15:00:51 +01:00
|
|
|
bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
2011-10-16 02:41:48 +02:00
|
|
|
{
|
2015-01-26 15:00:51 +01:00
|
|
|
if (!ent || !scope) { // it's impossible to evaluate, probably it is inside a subprogram
|
2015-01-13 18:00:41 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-10 18:35:17 +02:00
|
|
|
if (name_ == "left" || name_ == "right") {
|
|
|
|
|
const VType*base_type = base_->peek_type();
|
|
|
|
|
if (base_type == 0)
|
2015-01-26 15:00:51 +01:00
|
|
|
base_type = base_->probe_type(ent, scope);
|
2014-10-10 18:35:17 +02:00
|
|
|
|
|
|
|
|
ivl_assert(*this, base_type);
|
|
|
|
|
|
|
|
|
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
|
|
|
|
|
if (arr == 0) {
|
2015-04-20 10:57:49 +02:00
|
|
|
cerr << endl << get_fileline() << ": error: "
|
2014-10-14 10:58:01 +02:00
|
|
|
<< "Cannot apply the '" << name_
|
|
|
|
|
<< " attribute to non-array objects" << endl;
|
2015-04-20 10:57:49 +02:00
|
|
|
ivl_assert(*this, false);
|
2014-10-10 18:35:17 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ivl_assert(*this, arr->dimensions() == 1);
|
|
|
|
|
if(name_ == "left")
|
2015-01-26 15:00:51 +01:00
|
|
|
arr->dimension(0).msb()->evaluate(ent, scope, val);
|
2015-01-13 18:00:41 +01:00
|
|
|
else // "right"
|
2015-01-26 15:00:51 +01:00
|
|
|
arr->dimension(0).lsb()->evaluate(ent, scope, val);
|
2014-10-10 18:35:17 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 15:00:51 +01:00
|
|
|
return evaluate(scope, val);
|
2011-10-16 02:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2012-04-22 20:42:16 +02:00
|
|
|
/*
|
|
|
|
|
* I don't yet know how to evaluate concatenations. It is not likely
|
|
|
|
|
* to come up anyhow.
|
|
|
|
|
*/
|
2013-04-18 02:12:17 +02:00
|
|
|
bool ExpConcat::evaluate(ScopeBase*, int64_t&) const
|
2012-04-22 20:42:16 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-16 02:41:48 +02:00
|
|
|
bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
|
|
|
|
{
|
|
|
|
|
const VType*type;
|
|
|
|
|
Expression*exp;
|
|
|
|
|
|
2012-04-01 01:29:40 +02:00
|
|
|
if (prefix_.get()) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-06 16:59:30 +01:00
|
|
|
if (!scope)
|
2015-02-24 16:06:55 +01:00
|
|
|
return false;
|
|
|
|
|
|
2015-03-06 16:59:30 +01:00
|
|
|
if (!scope->find_constant(name_, type, exp))
|
2011-10-16 02:41:48 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return exp->evaluate(scope, val);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-26 15:00:51 +01:00
|
|
|
bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
2011-10-16 02:41:48 +02:00
|
|
|
{
|
2012-04-01 01:29:40 +02:00
|
|
|
if (prefix_.get()) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-16 02:41:48 +02:00
|
|
|
const InterfacePort*gen = ent->find_generic(name_);
|
|
|
|
|
if (gen) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl;
|
|
|
|
|
|
|
|
|
|
// Evaluate the default expression and use that.
|
|
|
|
|
if (gen->expr)
|
2015-01-26 15:00:51 +01:00
|
|
|
return gen->expr->evaluate(ent, scope, val);
|
2011-10-16 02:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
2015-01-26 15:00:51 +01:00
|
|
|
return evaluate(scope, val);
|
2011-10-16 02:41:48 +02:00
|
|
|
}
|
2015-02-10 14:11:56 +01:00
|
|
|
|
|
|
|
|
bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
|
|
|
|
{
|
|
|
|
|
int64_t val1, val2;
|
|
|
|
|
bool rc;
|
|
|
|
|
|
|
|
|
|
rc = eval_operand1(scope, val1);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
rc = eval_operand2(scope, val2);
|
|
|
|
|
if (rc == false)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch (shift_) {
|
|
|
|
|
case SRL:
|
|
|
|
|
val = (uint64_t)val1 >> (uint64_t)val2;
|
|
|
|
|
break;
|
|
|
|
|
case SLL:
|
|
|
|
|
val = (uint64_t)val1 << (uint64_t)val2;
|
|
|
|
|
break;
|
|
|
|
|
case SRA:
|
|
|
|
|
val = (int64_t)val1 >> (int64_t)val2;
|
|
|
|
|
break;
|
|
|
|
|
case SLA:
|
|
|
|
|
val = (int64_t)val1 << (int64_t)val2;
|
|
|
|
|
break;
|
|
|
|
|
case ROR:
|
|
|
|
|
case ROL:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-05-20 18:53:29 +02:00
|
|
|
|
|
|
|
|
bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
|
|
|
|
{
|
|
|
|
|
double v = to_fs();
|
|
|
|
|
|
|
|
|
|
if(v > std::numeric_limits<int64_t>::max()) {
|
|
|
|
|
val = std::numeric_limits<int64_t>::max();
|
|
|
|
|
cerr << get_fileline() << ": sorry: Time value is higher than the "
|
|
|
|
|
<< "handled limit, reduced to " << val << " fs." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val = v;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
|
|
|
|
{
|
|
|
|
|
return evaluate(NULL, NULL, val);
|
|
|
|
|
}
|