2011-01-31 20:16:14 +01:00
|
|
|
/*
|
2013-05-27 03:16:59 +02:00
|
|
|
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
|
|
|
|
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
|
2011-01-31 20:16:14 +01: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-01-31 20:16:14 +01:00
|
|
|
*/
|
|
|
|
|
|
2011-05-31 04:17:40 +02:00
|
|
|
# include "expression.h"
|
|
|
|
|
# include "vtype.h"
|
2011-09-12 02:08:22 +02:00
|
|
|
# include "architec.h"
|
2013-06-08 00:47:14 +02:00
|
|
|
# include "package.h"
|
2012-04-22 20:42:16 +02:00
|
|
|
# include "parse_types.h"
|
2011-01-31 20:16:14 +01:00
|
|
|
# include <typeinfo>
|
|
|
|
|
# include <iostream>
|
2011-09-04 02:11:55 +02:00
|
|
|
# include <cstdlib>
|
2013-05-27 03:16:59 +02:00
|
|
|
# include <cstring>
|
2011-09-12 02:08:22 +02:00
|
|
|
# include "ivl_assert.h"
|
2011-06-12 19:51:31 +02:00
|
|
|
# include <cassert>
|
2011-01-31 20:16:14 +01:00
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
|
int Expression::emit(ostream&out, Entity*, Architecture*)
|
|
|
|
|
{
|
|
|
|
|
out << " /* " << get_fileline() << ": internal error: "
|
|
|
|
|
<< "I don't know how to emit this expression! "
|
|
|
|
|
<< "type=" << typeid(*this).name() << " */ ";
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 04:17:12 +02:00
|
|
|
int Expression::emit_package(ostream&out)
|
|
|
|
|
{
|
|
|
|
|
out << " /* " << get_fileline() << ": internal error: "
|
|
|
|
|
<< "I don't know how to emit_package this expression! "
|
|
|
|
|
<< "type=" << typeid(*this).name() << " */ ";
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
bool Expression::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpBinary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
bool oper_primary = operand1_->is_primary();
|
|
|
|
|
if (! oper_primary) out << "(";
|
|
|
|
|
errors += operand1_->emit(out, ent, arc);
|
|
|
|
|
if (! oper_primary) out << ")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpBinary::emit_operand2(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
bool oper_primary = operand2_->is_primary();
|
|
|
|
|
if (! oper_primary) out << "(";
|
|
|
|
|
errors += operand2_->emit(out, ent, arc);
|
|
|
|
|
if (! oper_primary) out << ")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpUnary::emit_operand1(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
errors += operand1_->emit(out, ent, arc);
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-04 02:11:55 +02:00
|
|
|
int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc)
|
2011-09-12 02:08:22 +02:00
|
|
|
{
|
2012-04-09 04:06:58 +02:00
|
|
|
if (peek_type() == 0) {
|
|
|
|
|
out << "/* " << get_fileline() << ": internal error: "
|
|
|
|
|
<< "Aggregate literal needs well defined type." << endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-13 03:38:49 +02:00
|
|
|
const VType*use_type = peek_type();
|
|
|
|
|
while (const VTypeDef*def = dynamic_cast<const VTypeDef*> (use_type)) {
|
|
|
|
|
use_type = def->peek_definition();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (const VTypeArray*atype = dynamic_cast<const VTypeArray*> (use_type))
|
2011-09-12 02:08:22 +02:00
|
|
|
return emit_array_(out, ent, arc, atype);
|
2014-09-17 11:24:16 +02:00
|
|
|
else if (const VTypeRecord*arecord = dynamic_cast<const VTypeRecord*> (use_type))
|
|
|
|
|
return emit_record_(out, ent, arc, arecord);
|
2011-09-12 02:08:22 +02:00
|
|
|
|
2012-04-09 04:06:58 +02:00
|
|
|
out << "/* " << get_fileline() << ": internal error: "
|
2012-05-13 03:38:49 +02:00
|
|
|
<< "I don't know how to elab/emit aggregate in " << typeid(use_type).name()
|
2012-04-09 04:06:58 +02:00
|
|
|
<< " type context. */";
|
|
|
|
|
return 1;
|
2011-09-12 02:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*atype)
|
2011-09-04 02:11:55 +02:00
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
// Special case: The aggregate is a single "others" item.
|
|
|
|
|
if (aggregate_.size() == 1 && aggregate_[0].choice->others()) {
|
|
|
|
|
assert(atype->dimensions() == 1);
|
|
|
|
|
|
|
|
|
|
const VTypeArray::range_t&rang = atype->dimension(0);
|
|
|
|
|
assert(! rang.is_box());
|
|
|
|
|
|
2011-10-16 02:41:48 +02:00
|
|
|
int64_t use_msb;
|
|
|
|
|
int64_t use_lsb;
|
|
|
|
|
bool rc_msb, rc_lsb;
|
|
|
|
|
rc_msb = rang.msb()->evaluate(ent, arc, use_msb);
|
|
|
|
|
rc_lsb = rang.lsb()->evaluate(ent, arc, use_lsb);
|
|
|
|
|
|
|
|
|
|
if (rc_msb && rc_lsb) {
|
2011-11-12 01:22:56 +01:00
|
|
|
int asize = (use_msb >= use_lsb) ? (use_msb - use_lsb) + 1 :
|
|
|
|
|
(use_lsb - use_msb) + 1;
|
2011-10-16 02:41:48 +02:00
|
|
|
out << "{" << asize << "{";
|
|
|
|
|
errors += aggregate_[0].expr->emit(out, ent, arc);
|
|
|
|
|
out << "}}";
|
|
|
|
|
} else {
|
|
|
|
|
out << "{(";
|
|
|
|
|
if (rc_msb) {
|
|
|
|
|
out << use_msb;
|
|
|
|
|
} else {
|
|
|
|
|
out << "(";
|
|
|
|
|
errors += rang.msb()->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
}
|
|
|
|
|
if (rc_lsb && use_lsb==0) {
|
|
|
|
|
} else if (rc_lsb) {
|
|
|
|
|
out << "-" << use_lsb;
|
|
|
|
|
} else {
|
|
|
|
|
out << "-(";
|
|
|
|
|
errors += rang.lsb()->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
}
|
|
|
|
|
out << "+1){";
|
|
|
|
|
errors += aggregate_[0].expr->emit(out, ent, arc);
|
|
|
|
|
out << "}}";
|
|
|
|
|
}
|
2011-09-04 02:11:55 +02:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
const VTypeArray::range_t&rang = atype->dimension(0);
|
|
|
|
|
assert(! rang.is_box());
|
|
|
|
|
|
2012-04-09 04:06:58 +02:00
|
|
|
// Fully calculate the range numbers.
|
|
|
|
|
int64_t use_msb, use_lsb;
|
|
|
|
|
bool rc;
|
|
|
|
|
rc = rang.msb()->evaluate(ent, arc, use_msb);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
rc = rang.lsb()->evaluate(ent, arc, use_lsb);
|
|
|
|
|
ivl_assert(*this, rc);
|
2014-08-22 16:23:22 +02:00
|
|
|
if(use_msb < use_lsb)
|
|
|
|
|
swap(use_msb, use_lsb);
|
2012-04-09 04:06:58 +02:00
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
map<int64_t,choice_element*> element_map;
|
|
|
|
|
choice_element*element_other = 0;
|
|
|
|
|
|
2012-04-09 04:06:58 +02:00
|
|
|
bool positional_section = true;
|
|
|
|
|
int64_t positional_idx = use_msb;
|
|
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) {
|
2012-04-09 04:06:58 +02:00
|
|
|
|
|
|
|
|
if (aggregate_[idx].choice == 0) {
|
|
|
|
|
// positional association!
|
|
|
|
|
if (!positional_section) {
|
|
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "All positional associations must be before"
|
|
|
|
|
<< " any named associations." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
element_map[positional_idx] = &aggregate_[idx];
|
|
|
|
|
positional_idx -= 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
if (aggregate_[idx].choice->others()) {
|
|
|
|
|
ivl_assert(*this, element_other == 0);
|
|
|
|
|
element_other = &aggregate_[idx];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-22 20:42:16 +02:00
|
|
|
// If this is a range choice, then calculate the bounds
|
|
|
|
|
// of the range and scan through the values, mapping the
|
|
|
|
|
// value to the aggregate_[idx] element.
|
|
|
|
|
if (prange_t*range = aggregate_[idx].choice->range_expressions()) {
|
|
|
|
|
int64_t begin_val, end_val;
|
|
|
|
|
|
|
|
|
|
if (! range->msb()->evaluate(ent, arc, begin_val)) {
|
|
|
|
|
cerr << range->msb()->get_fileline() << ": error: "
|
|
|
|
|
<< "Unable to evaluate aggregate choice expression." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! range->lsb()->evaluate(ent, arc, end_val)) {
|
|
|
|
|
cerr << range->msb()->get_fileline() << ": error: "
|
|
|
|
|
<< "Unable to evaluate aggregate choice expression." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (begin_val < end_val) {
|
|
|
|
|
int64_t tmp = begin_val;
|
|
|
|
|
begin_val = end_val;
|
|
|
|
|
end_val = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (begin_val >= end_val) {
|
|
|
|
|
element_map[begin_val] = &aggregate_[idx];
|
|
|
|
|
begin_val -= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
int64_t tmp_val;
|
2012-04-09 04:06:58 +02:00
|
|
|
Expression*tmp = aggregate_[idx].choice->simple_expression(false);
|
2012-04-22 20:42:16 +02:00
|
|
|
ivl_assert(*this, tmp);
|
2012-04-09 04:06:58 +02:00
|
|
|
|
|
|
|
|
// Named aggregate element. Once we see one of
|
|
|
|
|
// these, we can no longer accept positional
|
|
|
|
|
// elements so disable further positional
|
|
|
|
|
// processing.
|
|
|
|
|
positional_section = false;
|
2011-10-16 02:41:48 +02:00
|
|
|
if (! tmp->evaluate(ent, arc, tmp_val)) {
|
2012-04-09 04:06:58 +02:00
|
|
|
cerr << tmp->get_fileline() << ": error: "
|
|
|
|
|
<< "Unable to evaluate aggregate choice expression." << endl;
|
2011-09-12 02:08:22 +02:00
|
|
|
errors += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
element_map[tmp_val] = &aggregate_[idx];
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-09 04:06:58 +02:00
|
|
|
// Emit the elements as a concatenation. This works great for
|
|
|
|
|
// vectors of bits. We implement VHDL arrays as packed arrays,
|
|
|
|
|
// so this should be generally correct.
|
2014-08-22 16:22:59 +02:00
|
|
|
// TODO uncomment this once ivl supports assignments of '{}
|
|
|
|
|
/*if(!peek_type()->can_be_packed())
|
|
|
|
|
out << "'";*/
|
|
|
|
|
|
2011-09-12 02:08:22 +02:00
|
|
|
out << "{";
|
2011-10-16 02:41:48 +02:00
|
|
|
for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) {
|
2011-09-12 02:08:22 +02:00
|
|
|
choice_element*cur = element_map[idx];
|
|
|
|
|
if (cur == 0)
|
|
|
|
|
cur = element_other;
|
|
|
|
|
|
2011-10-16 02:41:48 +02:00
|
|
|
if (idx < use_msb)
|
2011-09-12 02:08:22 +02:00
|
|
|
out << ", ";
|
2012-04-09 04:06:58 +02:00
|
|
|
if (cur == 0) {
|
|
|
|
|
out << "/* Missing element " << idx << " */";
|
2012-04-22 20:42:16 +02:00
|
|
|
cerr << get_fileline() << ": error: "
|
|
|
|
|
<< "Missing element " << idx << "." << endl;
|
2012-04-09 04:06:58 +02:00
|
|
|
errors += 1;
|
|
|
|
|
} else {
|
|
|
|
|
errors += cur->expr->emit(out, ent, arc);
|
|
|
|
|
}
|
2011-09-12 02:08:22 +02:00
|
|
|
}
|
|
|
|
|
out << "}";
|
|
|
|
|
|
|
|
|
|
return errors;
|
2011-09-04 02:11:55 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-17 16:30:44 +02:00
|
|
|
int ExpAggregate::emit_record_(ostream&out, Entity*ent, Architecture*arc, const VTypeRecord*)
|
2014-09-17 11:24:16 +02:00
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
out << "{";
|
|
|
|
|
|
|
|
|
|
for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) {
|
|
|
|
|
ivl_assert(*this, !aggregate_[idx].choice->others());
|
|
|
|
|
ivl_assert(*this, !aggregate_[idx].choice->range_expressions());
|
|
|
|
|
|
2014-09-17 16:30:44 +02:00
|
|
|
//Expression*name = aggregate_[idx].choice->simple_expression(false);
|
|
|
|
|
//ivl_assert(*this, name);
|
2014-09-17 11:24:16 +02:00
|
|
|
Expression*val = aggregate_[idx].expr;
|
|
|
|
|
ivl_assert(*this, val);
|
|
|
|
|
|
|
|
|
|
if(idx != 0)
|
|
|
|
|
out << ",";
|
|
|
|
|
|
2014-09-17 16:30:44 +02:00
|
|
|
//errors += name->emit(out, ent, arc);
|
|
|
|
|
//out << ": ";
|
2014-09-17 11:24:16 +02:00
|
|
|
errors += val->emit(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << "}";
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-09 01:40:35 +02:00
|
|
|
int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
2011-06-25 03:42:43 +02:00
|
|
|
|
|
|
|
|
if (name_ == "event") {
|
|
|
|
|
out << "$ivlh_attribute_event(";
|
|
|
|
|
errors += base_->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-19 02:45:06 +02:00
|
|
|
/* Special Case: The length attribute can be calculated all
|
|
|
|
|
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.) */
|
2013-05-27 03:16:59 +02:00
|
|
|
if (name_=="length") {
|
|
|
|
|
out << "$bits(";
|
|
|
|
|
errors += base_->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
return errors;
|
2011-09-19 02:45:06 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-27 03:16:59 +02:00
|
|
|
|
2011-05-09 01:40:35 +02:00
|
|
|
out << "$ivl_attribute(";
|
|
|
|
|
errors += base_->emit(out, ent, arc);
|
|
|
|
|
out << ", \"" << name_ << "\")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-20 02:47:30 +01:00
|
|
|
int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
errors += emit_operand1(out, ent, arc);
|
2011-02-20 02:47:30 +01:00
|
|
|
|
|
|
|
|
switch (fun_) {
|
|
|
|
|
case PLUS:
|
|
|
|
|
out << " + ";
|
|
|
|
|
break;
|
|
|
|
|
case MINUS:
|
|
|
|
|
out << " - ";
|
|
|
|
|
break;
|
|
|
|
|
case MULT:
|
|
|
|
|
out << " * ";
|
|
|
|
|
break;
|
|
|
|
|
case DIV:
|
|
|
|
|
out << " / ";
|
|
|
|
|
break;
|
|
|
|
|
case MOD:
|
|
|
|
|
out << " % ";
|
|
|
|
|
break;
|
|
|
|
|
case POW:
|
|
|
|
|
out << " ** ";
|
|
|
|
|
break;
|
|
|
|
|
case REM:
|
|
|
|
|
out << " /* ?remainder? */ ";
|
|
|
|
|
break;
|
2012-04-22 20:42:16 +02:00
|
|
|
case xCONCAT:
|
|
|
|
|
ivl_assert(*this, 0);
|
2011-06-05 22:58:54 +02:00
|
|
|
out << " /* ?concat? */ ";
|
|
|
|
|
break;
|
2011-02-20 02:47:30 +01:00
|
|
|
}
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
errors += emit_operand2(out, ent, arc);
|
2011-02-20 02:47:30 +01:00
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-05 22:58:54 +02:00
|
|
|
int ExpBitstring::emit(ostream&out, Entity*, Architecture*)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
2011-06-12 19:51:31 +02:00
|
|
|
|
|
|
|
|
out << value_.size() << "'b";
|
|
|
|
|
for (size_t idx = 0 ; idx < value_.size() ; idx += 1)
|
|
|
|
|
out << value_[value_.size()-idx-1];
|
|
|
|
|
|
2011-06-05 22:58:54 +02:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-29 02:31:42 +02:00
|
|
|
int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, Architecture*,
|
2011-06-12 19:51:31 +02:00
|
|
|
const VTypePrimitive*etype)
|
2011-05-09 01:40:35 +02:00
|
|
|
{
|
2011-06-12 19:51:31 +02:00
|
|
|
switch (etype->type()) {
|
|
|
|
|
case VTypePrimitive::BOOLEAN:
|
|
|
|
|
case VTypePrimitive::BIT:
|
|
|
|
|
switch (value_) {
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
out << "1'b" << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2011-05-31 04:17:40 +02:00
|
|
|
|
2011-06-12 19:51:31 +02:00
|
|
|
case VTypePrimitive::STDLOGIC:
|
|
|
|
|
switch (value_) {
|
|
|
|
|
case '0':
|
|
|
|
|
case '1':
|
|
|
|
|
out << "1'b" << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
default:
|
2011-05-31 04:17:40 +02:00
|
|
|
break;
|
2011-06-12 19:51:31 +02:00
|
|
|
}
|
2011-05-31 04:17:40 +02:00
|
|
|
|
2011-06-12 19:51:31 +02:00
|
|
|
default:
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-06-25 03:42:43 +02:00
|
|
|
return 1;
|
2011-06-12 19:51:31 +02:00
|
|
|
}
|
2011-05-31 04:17:40 +02:00
|
|
|
|
2011-06-12 19:51:31 +02:00
|
|
|
int ExpCharacter::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
const VType*etype = peek_type();
|
|
|
|
|
|
|
|
|
|
if (const VTypePrimitive*use_type = dynamic_cast<const VTypePrimitive*>(etype)) {
|
|
|
|
|
return emit_primitive_bit_(out, ent, arc, use_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (const VTypeArray*array = dynamic_cast<const VTypeArray*>(etype)) {
|
|
|
|
|
if (const VTypePrimitive*use_type = dynamic_cast<const VTypePrimitive*>(array->element_type())) {
|
|
|
|
|
return emit_primitive_bit_(out, ent, arc, use_type);
|
2011-05-31 04:17:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-09 01:40:35 +02:00
|
|
|
out << "\"" << value_ << "\"";
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExpCharacter::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-22 20:42:16 +02:00
|
|
|
/*
|
|
|
|
|
* This is not exactly a "primary", but it is wrapped in its own
|
|
|
|
|
* parentheses (braces) so we return true here.
|
|
|
|
|
*/
|
|
|
|
|
bool ExpConcat::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpConcat::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
out << "{";
|
|
|
|
|
errors += operand1_->emit(out, ent, arc);
|
|
|
|
|
out << ", ";
|
|
|
|
|
errors += operand2_->emit(out, ent, arc);
|
|
|
|
|
out << "}";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-12 19:51:31 +02:00
|
|
|
int ExpConditional::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
out << "(";
|
|
|
|
|
errors += cond_->emit(out, ent, arc);
|
|
|
|
|
out << ")? (";
|
|
|
|
|
|
|
|
|
|
if (true_clause_.size() > 1) {
|
2012-03-24 18:23:50 +01:00
|
|
|
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
2011-06-12 19:51:31 +02:00
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expression*tmp = true_clause_.front();
|
|
|
|
|
errors += tmp->emit(out, ent, arc);
|
|
|
|
|
|
|
|
|
|
out << ") : (";
|
|
|
|
|
|
2012-03-24 18:23:50 +01:00
|
|
|
// Draw out any when-else expressions. These are all the else_
|
|
|
|
|
// clauses besides the last.
|
2011-06-12 19:51:31 +02:00
|
|
|
if (else_clause_.size() > 1) {
|
2012-03-24 18:23:50 +01:00
|
|
|
list<else_t*>::iterator last = else_clause_.end();
|
|
|
|
|
-- last;
|
|
|
|
|
|
|
|
|
|
for (list<else_t*>::iterator cur = else_clause_.begin()
|
|
|
|
|
; cur != last ; ++cur) {
|
|
|
|
|
errors += (*cur) ->emit_when_else(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors += else_clause_.back()->emit_else(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
|
|
|
|
|
// The emit_when_else() functions do not close the last
|
|
|
|
|
// parentheses so that the following expression can be
|
|
|
|
|
// nested. But that means come the end, we have some
|
|
|
|
|
// expressions to close.
|
|
|
|
|
for (size_t idx = 1 ; idx < else_clause_.size() ; idx += 1)
|
|
|
|
|
out << ")";
|
2012-08-16 20:06:20 +02:00
|
|
|
|
2012-03-24 18:23:50 +01:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpConditional::else_t::emit_when_else(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
assert(cond_ != 0);
|
|
|
|
|
|
|
|
|
|
out << "(";
|
|
|
|
|
errors += cond_->emit(out, ent, arc);
|
|
|
|
|
out << ")? (";
|
|
|
|
|
|
|
|
|
|
if (true_clause_.size() > 1) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
2011-06-12 19:51:31 +02:00
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-24 18:23:50 +01:00
|
|
|
Expression*tmp = true_clause_.front();
|
2011-06-12 19:51:31 +02:00
|
|
|
errors += tmp->emit(out, ent, arc);
|
|
|
|
|
|
2012-03-24 18:23:50 +01:00
|
|
|
out << ") : (";
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpConditional::else_t::emit_else(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
// Trailing else must have no condition.
|
|
|
|
|
assert(cond_ == 0);
|
|
|
|
|
|
|
|
|
|
if (true_clause_.size() > 1) {
|
|
|
|
|
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
|
|
|
|
|
errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Expression*tmp = true_clause_.front();
|
|
|
|
|
errors += tmp->emit(out, ent, arc);
|
2011-06-12 19:51:31 +02:00
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-28 19:49:33 +02:00
|
|
|
int ExpEdge::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
switch (fun_) {
|
|
|
|
|
case NEGEDGE:
|
|
|
|
|
out << "negedge ";
|
|
|
|
|
break;
|
|
|
|
|
case POSEDGE:
|
|
|
|
|
out << "posedge ";
|
|
|
|
|
break;
|
2011-06-12 19:51:31 +02:00
|
|
|
case ANYEDGE:
|
2011-05-28 19:49:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
errors += emit_operand1(out, ent, arc);
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-29 00:30:45 +02:00
|
|
|
int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
if (name_ == "unsigned" && argv_.size()==1) {
|
|
|
|
|
// Handle the special case that this is a cast to
|
|
|
|
|
// unsigned. This function is brought in as part of the
|
|
|
|
|
// std numeric library, but we interpret it as the same
|
|
|
|
|
// as the $unsigned function.
|
|
|
|
|
out << "$unsigned(";
|
|
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
|
|
|
|
|
} else if (name_ == "std_logic_vector" && argv_.size() == 1) {
|
|
|
|
|
// Special case: The std_logic_vector function casts its
|
|
|
|
|
// argument to std_logic_vector. Internally, we don't
|
|
|
|
|
// have to do anything for that to work.
|
|
|
|
|
out << "(";
|
|
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
2011-09-19 02:45:06 +02:00
|
|
|
|
2011-09-19 04:31:28 +02:00
|
|
|
} else if (name_ == "to_unsigned" && argv_.size() == 2) {
|
|
|
|
|
|
2013-05-27 03:16:59 +02:00
|
|
|
out << "$ivlh_to_unsigned(";
|
2011-09-19 04:31:28 +02:00
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
2013-05-27 03:16:59 +02:00
|
|
|
out << ", ";
|
|
|
|
|
errors += argv_[1]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
2011-09-19 04:31:28 +02:00
|
|
|
|
2011-10-29 23:47:39 +02:00
|
|
|
} else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) {
|
|
|
|
|
int64_t use_size;
|
|
|
|
|
bool rc = argv_[1]->evaluate(ent, arc, use_size);
|
|
|
|
|
ivl_assert(*this, rc);
|
|
|
|
|
out << use_size << "'(";
|
|
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
|
2013-06-06 05:39:04 +02:00
|
|
|
} else if (name_ == "rising_edge" && argv_.size()==1) {
|
|
|
|
|
out << "$ivlh_rising_edge(";
|
|
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
|
|
|
|
|
} else if (name_ == "falling_edge" && argv_.size()==1) {
|
|
|
|
|
out << "$ivlh_falling_edge(";
|
|
|
|
|
errors += argv_[0]->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
|
2011-08-29 00:30:45 +02:00
|
|
|
} else {
|
2014-01-29 00:50:27 +01:00
|
|
|
// If this function has an elaborated definition, and if
|
2013-06-08 00:47:14 +02:00
|
|
|
// that definition is in a package, then include the
|
|
|
|
|
// package name as a scope qualifier. This assures that
|
|
|
|
|
// the SV elaborator finds the correct VHDL elaborated
|
|
|
|
|
// definition.
|
|
|
|
|
if (def_) {
|
|
|
|
|
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
|
|
|
|
|
if (pkg != 0)
|
|
|
|
|
out << "\\" << pkg->name() << " ::";
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-19 02:45:06 +02:00
|
|
|
out << "\\" << name_ << " (";
|
|
|
|
|
for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
|
|
|
|
|
if (idx > 0) out << ", ";
|
|
|
|
|
errors += argv_[idx]->emit(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
out << ")";
|
2011-08-29 00:30:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 04:01:21 +01:00
|
|
|
int ExpInteger::emit(ostream&out, Entity*, Architecture*)
|
|
|
|
|
{
|
2011-02-21 02:03:46 +01:00
|
|
|
out << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-13 04:17:12 +02:00
|
|
|
int ExpInteger::emit_package(ostream&out)
|
|
|
|
|
{
|
|
|
|
|
out << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
bool ExpInteger::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
2011-02-14 04:01:21 +01:00
|
|
|
}
|
|
|
|
|
|
2014-08-06 15:00:35 +02:00
|
|
|
int ExpReal::emit(ostream&out, Entity*, Architecture*)
|
|
|
|
|
{
|
|
|
|
|
out << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpReal::emit_package(ostream&out)
|
|
|
|
|
{
|
|
|
|
|
out << value_;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExpReal::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-31 20:16:14 +01:00
|
|
|
int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
errors += emit_operand1(out, ent, arc);
|
2011-01-31 20:16:14 +01:00
|
|
|
|
|
|
|
|
switch (fun_) {
|
|
|
|
|
case AND:
|
|
|
|
|
out << " & ";
|
|
|
|
|
break;
|
|
|
|
|
case OR:
|
|
|
|
|
out << " | ";
|
|
|
|
|
break;
|
|
|
|
|
case XOR:
|
|
|
|
|
out << " ^ ";
|
|
|
|
|
break;
|
|
|
|
|
case NAND:
|
|
|
|
|
out << " ~& ";
|
|
|
|
|
break;
|
|
|
|
|
case NOR:
|
|
|
|
|
out << " ~| ";
|
|
|
|
|
break;
|
|
|
|
|
case XNOR:
|
|
|
|
|
out << " ~^ ";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
errors += emit_operand2(out, ent, arc);
|
2011-01-31 20:16:14 +01:00
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-09 04:06:58 +02:00
|
|
|
int ExpName::emit_as_prefix_(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
if (prefix_.get()) {
|
|
|
|
|
errors += prefix_->emit_as_prefix_(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << "\\" << name_ << " ";
|
2012-09-01 23:51:04 +02:00
|
|
|
if (index_) {
|
|
|
|
|
out << "[";
|
|
|
|
|
errors += index_->emit(out, ent, arc);
|
|
|
|
|
out << "]";
|
|
|
|
|
ivl_assert(*this, lsb_ == 0);
|
|
|
|
|
}
|
2012-04-09 04:06:58 +02:00
|
|
|
out << ".";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-27 21:01:58 +02:00
|
|
|
int ExpName::emit(ostream&out, Entity*ent, Architecture*arc)
|
2011-01-31 20:16:14 +01:00
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
2012-04-01 01:29:40 +02:00
|
|
|
if (prefix_.get()) {
|
2012-04-09 04:06:58 +02:00
|
|
|
errors += prefix_->emit_as_prefix_(out, ent, arc);
|
2012-04-01 01:29:40 +02:00
|
|
|
}
|
|
|
|
|
|
2012-09-08 00:14:48 +02:00
|
|
|
const GenerateStatement*gs = 0;
|
|
|
|
|
if (arc && (gs = arc->probe_genvar_emit(name_)))
|
|
|
|
|
out << "\\" << gs->get_name() << ":" << name_ << " ";
|
|
|
|
|
else
|
|
|
|
|
out << "\\" << name_ << " ";
|
|
|
|
|
|
2011-03-27 21:01:58 +02:00
|
|
|
if (index_) {
|
|
|
|
|
out << "[";
|
|
|
|
|
errors += index_->emit(out, ent, arc);
|
2011-08-22 01:52:18 +02:00
|
|
|
|
|
|
|
|
if (lsb_) {
|
|
|
|
|
out << ":";
|
|
|
|
|
errors += lsb_->emit(out, ent, arc);
|
|
|
|
|
}
|
2011-03-27 21:01:58 +02:00
|
|
|
out << "]";
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-31 20:16:14 +01:00
|
|
|
return errors;
|
|
|
|
|
}
|
2011-02-21 02:03:46 +01:00
|
|
|
|
|
|
|
|
bool ExpName::is_primary(void) const
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-09 01:40:35 +02:00
|
|
|
int ExpRelation::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
errors += emit_operand1(out, ent, arc);
|
|
|
|
|
|
|
|
|
|
switch (fun_) {
|
|
|
|
|
case EQ:
|
|
|
|
|
out << " == ";
|
|
|
|
|
break;
|
|
|
|
|
case LT:
|
|
|
|
|
out << " < ";
|
|
|
|
|
break;
|
|
|
|
|
case GT:
|
|
|
|
|
out << " > ";
|
|
|
|
|
break;
|
|
|
|
|
case NEQ:
|
|
|
|
|
out << " != ";
|
|
|
|
|
break;
|
|
|
|
|
case LE:
|
|
|
|
|
out << " <= ";
|
|
|
|
|
break;
|
|
|
|
|
case GE:
|
|
|
|
|
out << " >= ";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errors += emit_operand2(out, ent, arc);
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-20 20:11:47 +02:00
|
|
|
bool ExpString::is_primary(void) const
|
2011-07-05 12:03:30 +02:00
|
|
|
{
|
2011-08-20 20:11:47 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpString::emit(ostream& out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
const VType*type = peek_type();
|
|
|
|
|
assert(type != 0);
|
|
|
|
|
|
|
|
|
|
if (const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type)) {
|
|
|
|
|
return emit_as_array_(out, ent, arc, arr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << "\"";
|
|
|
|
|
for(vector<char>::const_iterator it = value_.begin()
|
|
|
|
|
; it != value_.end(); ++it)
|
|
|
|
|
out << *it;
|
|
|
|
|
out << "\"";
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeArray*arr)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
assert(arr->dimensions() == 1);
|
|
|
|
|
|
2014-09-15 11:08:14 +02:00
|
|
|
const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->basic_type());
|
2011-08-20 20:11:47 +02:00
|
|
|
assert(etype);
|
|
|
|
|
|
2013-05-27 03:16:59 +02:00
|
|
|
// Detect the special case that this is an array of
|
|
|
|
|
// CHARACTER. In this case, emit at a Verilog string.
|
|
|
|
|
if (etype->type()==VTypePrimitive::CHARACTER) {
|
|
|
|
|
vector<char> tmp (value_.size() + 3);
|
|
|
|
|
tmp[0] = '"';
|
|
|
|
|
memcpy(&tmp[1], &value_[0], value_.size());
|
|
|
|
|
tmp[value_.size()+1] = '"';
|
|
|
|
|
tmp[value_.size()+2] = 0;
|
|
|
|
|
out << &tmp[0];
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-20 20:11:47 +02:00
|
|
|
assert(etype->type() != VTypePrimitive::INTEGER);
|
|
|
|
|
out << value_.size() << "'b";
|
|
|
|
|
for (size_t idx = 0 ; idx < value_.size() ; idx += 1) {
|
|
|
|
|
switch (value_[idx]) {
|
|
|
|
|
case '0':
|
|
|
|
|
out << "0";
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
out << "1";
|
|
|
|
|
break;
|
|
|
|
|
case 'z': case 'Z':
|
|
|
|
|
assert(etype->type() == VTypePrimitive::STDLOGIC);
|
|
|
|
|
out << "z";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2013-05-27 03:16:59 +02:00
|
|
|
cerr << get_fileline() << ": internal error: "
|
|
|
|
|
<< "Don't know how to handle bit " << value_[idx]
|
|
|
|
|
<< " with etype==" << etype->type() << endl;
|
2011-08-20 20:11:47 +02:00
|
|
|
assert(etype->type() == VTypePrimitive::STDLOGIC);
|
|
|
|
|
out << "x";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return errors;
|
2011-07-05 12:03:30 +02:00
|
|
|
}
|
|
|
|
|
|
2011-02-21 02:03:46 +01:00
|
|
|
int ExpUAbs::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
out << "abs(";
|
|
|
|
|
errors += emit_operand1(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ExpUNot::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
out << "~(";
|
|
|
|
|
errors += emit_operand1(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
return errors;
|
|
|
|
|
}
|