Files
iverilog/vhdlpp/expression_emit.cc
T
Stephen Williams d630e4dfe9 Elaborate VHDL entity port types/expressions.
We need to elaborate expressions so that function calls in
expressions (i.e. ranges) get bound to their proper scope.
This binding is in turn used to emit package scopes. This
is particularly interesting for ports of entities.
2013-06-12 14:21:35 -07:00

807 lines
20 KiB
C++

/*
* Copyright (c) 2011-2013 Stephen Williams ([email protected])
* Copyright CERN 2012-2013 / Stephen Williams ([email protected])
*
* 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "expression.h"
# include "vtype.h"
# include "architec.h"
# include "package.h"
# include "parse_types.h"
# include <typeinfo>
# include <iostream>
# include <cstdlib>
# include <cstring>
# include "ivl_assert.h"
# include <cassert>
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;
}
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;
}
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;
}
int ExpAggregate::emit(ostream&out, Entity*ent, Architecture*arc)
{
if (peek_type() == 0) {
out << "/* " << get_fileline() << ": internal error: "
<< "Aggregate literal needs well defined type." << endl;
return 1;
}
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))
return emit_array_(out, ent, arc, atype);
out << "/* " << get_fileline() << ": internal error: "
<< "I don't know how to elab/emit aggregate in " << typeid(use_type).name()
<< " type context. */";
return 1;
}
int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*atype)
{
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());
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) {
int asize = (use_msb >= use_lsb) ? (use_msb - use_lsb) + 1 :
(use_lsb - use_msb) + 1;
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 << "}}";
}
return errors;
}
const VTypeArray::range_t&rang = atype->dimension(0);
assert(! rang.is_box());
// 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);
ivl_assert(*this, use_msb >= use_lsb);
map<int64_t,choice_element*> element_map;
choice_element*element_other = 0;
bool positional_section = true;
int64_t positional_idx = use_msb;
for (size_t idx = 0 ; idx < aggregate_.size() ; idx += 1) {
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;
}
if (aggregate_[idx].choice->others()) {
ivl_assert(*this, element_other == 0);
element_other = &aggregate_[idx];
continue;
}
// 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;
}
int64_t tmp_val;
Expression*tmp = aggregate_[idx].choice->simple_expression(false);
ivl_assert(*this, tmp);
// Named aggregate element. Once we see one of
// these, we can no longer accept positional
// elements so disable further positional
// processing.
positional_section = false;
if (! tmp->evaluate(ent, arc, tmp_val)) {
cerr << tmp->get_fileline() << ": error: "
<< "Unable to evaluate aggregate choice expression." << endl;
errors += 1;
continue;
}
element_map[tmp_val] = &aggregate_[idx];
}
// 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.
out << "{";
for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) {
choice_element*cur = element_map[idx];
if (cur == 0)
cur = element_other;
if (idx < use_msb)
out << ", ";
if (cur == 0) {
out << "/* Missing element " << idx << " */";
cerr << get_fileline() << ": error: "
<< "Missing element " << idx << "." << endl;
errors += 1;
} else {
errors += cur->expr->emit(out, ent, arc);
}
}
out << "}";
return errors;
}
int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
if (name_ == "event") {
out << "$ivlh_attribute_event(";
errors += base_->emit(out, ent, arc);
out << ")";
return errors;
}
/* 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.) */
if (name_=="length") {
out << "$bits(";
errors += base_->emit(out, ent, arc);
out << ")";
return errors;
}
out << "$ivl_attribute(";
errors += base_->emit(out, ent, arc);
out << ", \"" << name_ << "\")";
return errors;
}
int ExpArithmetic::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
errors += emit_operand1(out, ent, arc);
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;
case xCONCAT:
ivl_assert(*this, 0);
out << " /* ?concat? */ ";
break;
}
errors += emit_operand2(out, ent, arc);
return errors;
}
int ExpBitstring::emit(ostream&out, Entity*, Architecture*)
{
int errors = 0;
out << value_.size() << "'b";
for (size_t idx = 0 ; idx < value_.size() ; idx += 1)
out << value_[value_.size()-idx-1];
return errors;
}
int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, Architecture*,
const VTypePrimitive*etype)
{
switch (etype->type()) {
case VTypePrimitive::BOOLEAN:
case VTypePrimitive::BIT:
switch (value_) {
case '0':
case '1':
out << "1'b" << value_;
return 0;
default:
break;
}
break;
case VTypePrimitive::STDLOGIC:
switch (value_) {
case '0':
case '1':
out << "1'b" << value_;
return 0;
default:
break;
}
default:
return 1;
}
return 1;
}
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);
}
}
out << "\"" << value_ << "\"";
return 0;
}
bool ExpCharacter::is_primary(void) const
{
return true;
}
/*
* 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;
}
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) {
cerr << get_fileline() << ": sorry: Multiple expression waveforms not supported here." << endl;
errors += 1;
}
Expression*tmp = true_clause_.front();
errors += tmp->emit(out, ent, arc);
out << ") : (";
// Draw out any when-else expressions. These are all the else_
// clauses besides the last.
if (else_clause_.size() > 1) {
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 << ")";
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;
errors += 1;
}
Expression*tmp = true_clause_.front();
errors += tmp->emit(out, ent, arc);
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);
return errors;
}
int ExpEdge::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
switch (fun_) {
case NEGEDGE:
out << "negedge ";
break;
case POSEDGE:
out << "posedge ";
break;
case ANYEDGE:
break;
}
errors += emit_operand1(out, ent, arc);
return errors;
}
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 << ")";
} else if (name_ == "to_unsigned" && argv_.size() == 2) {
out << "$ivlh_to_unsigned(";
errors += argv_[0]->emit(out, ent, arc);
out << ", ";
errors += argv_[1]->emit(out, ent, arc);
out << ")";
} 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 << ")";
} 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 << ")";
} else {
// If this function has an elaborated defintion, and if
// 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() << " ::";
}
out << "\\" << name_ << " (";
for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
if (idx > 0) out << ", ";
errors += argv_[idx]->emit(out, ent, arc);
}
out << ")";
}
return errors;
}
int ExpInteger::emit(ostream&out, Entity*, Architecture*)
{
out << value_;
return 0;
}
int ExpInteger::emit_package(ostream&out)
{
out << value_;
return 0;
}
bool ExpInteger::is_primary(void) const
{
return true;
}
int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
errors += emit_operand1(out, ent, arc);
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;
}
errors += emit_operand2(out, ent, arc);
return errors;
}
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_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, arc);
out << "]";
ivl_assert(*this, lsb_ == 0);
}
out << ".";
return errors;
}
int ExpName::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
if (prefix_.get()) {
errors += prefix_->emit_as_prefix_(out, ent, arc);
}
const GenerateStatement*gs = 0;
if (arc && (gs = arc->probe_genvar_emit(name_)))
out << "\\" << gs->get_name() << ":" << name_ << " ";
else
out << "\\" << name_ << " ";
if (index_) {
out << "[";
errors += index_->emit(out, ent, arc);
if (lsb_) {
out << ":";
errors += lsb_->emit(out, ent, arc);
}
out << "]";
}
return errors;
}
bool ExpName::is_primary(void) const
{
return true;
}
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;
}
bool ExpString::is_primary(void) const
{
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);
const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type());
assert(etype);
// 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;
}
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:
cerr << get_fileline() << ": internal error: "
<< "Don't know how to handle bit " << value_[idx]
<< " with etype==" << etype->type() << endl;
assert(etype->type() == VTypePrimitive::STDLOGIC);
out << "x";
break;
}
}
return errors;
}
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;
}