Put off array bound evaluation / describe entity generics as parameters

Entity generics are easily implemented as module parameters, so make
it so. Give the parameters their default values from the generic declaration.

Array bounds may use values that cannot be evaluated right away, so
put off their evaluation.
This commit is contained in:
Stephen Williams 2011-10-15 17:41:48 -07:00
parent a6f63b8a54
commit d9acfe57b1
16 changed files with 252 additions and 100 deletions

View File

@ -55,6 +55,27 @@ void dump_design_entities(ostream&file)
}
}
void ComponentBase::dump_generics(ostream&out, int indent) const
{
if (parms_.empty()) {
out << setw(indent) << "" << "No generics" << endl;
} else {
out << setw(indent) << "" << "GENERICS:" << endl;
for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
; cur != parms_.end() ; ++cur) {
InterfacePort*item = *cur;
out << setw(indent+2) << "" << item->name
<< " : " << item->mode
<< ", type=";
if (item->type)
item->type->show(out);
else
out << "<nil>";
out << ", file=" << item->get_fileline() << endl;
}
}
}
void ComponentBase::dump_ports(ostream&out, int indent) const
{
if (ports_.empty()) {
@ -122,6 +143,7 @@ void Scope::dump_scope(ostream&out) const
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()
; cur != old_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl;
cur->second->dump_generics(out);
cur->second->dump_ports(out);
out << " end component " << cur->first << endl;
}

View File

@ -63,6 +63,16 @@ const InterfacePort* ComponentBase::find_port(perm_string my_name) const
return 0;
}
const InterfacePort* ComponentBase::find_generic(perm_string my_name) const
{
for (size_t idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx]->name == my_name)
return parms_[idx];
}
return 0;
}
Entity::Entity(perm_string name)
: ComponentBase(name)
{

View File

@ -60,7 +60,9 @@ class ComponentBase : public LineInfo {
// Entities have names.
perm_string get_name() const { return name_; }
const InterfacePort* find_port(perm_string by_name) const;
const InterfacePort* find_generic(perm_string by_name) const;
// Declare the ports for the entity. The parser calls this
// method with a list of interface elements that were parsed
@ -73,14 +75,12 @@ class ComponentBase : public LineInfo {
void write_to_stream(std::ostream&fd) const;
public:
void dump_generics(std::ostream&out, int indent =0) const;
void dump_ports(std::ostream&out, int indent = 0) const;
protected:
// This is really only used by the Entity derived class.
const std::vector<InterfacePort*>&get_ports() const { return ports_; }
private:
perm_string name_;
protected:
std::vector<InterfacePort*> parms_;
std::vector<InterfacePort*> ports_;
};

View File

@ -87,10 +87,8 @@ int Entity::elaborate()
int Entity::elaborate_ports_(void)
{
int errors = 0;
const std::vector<InterfacePort*>&ports = get_ports();
for (std::vector<InterfacePort*>::const_iterator cur = ports.begin()
; cur != ports.end() ; ++cur) {
for (std::vector<InterfacePort*>::const_iterator cur = ports_.begin()
; cur != ports_.end() ; ++cur) {
InterfacePort*cur_port = *cur;

View File

@ -22,6 +22,7 @@
# include <iostream>
# include <fstream>
# include <iomanip>
# include <ivl_assert.h>
int emit_entities(void)
{
@ -39,16 +40,30 @@ int Entity::emit(ostream&out)
{
int errors = 0;
const std::vector<InterfacePort*>&ports = get_ports();
out << "module ";
// If there are generics, emit them
if (parms_.size() > 0) {
out << "#(";
for (vector<InterfacePort*>::const_iterator cur = parms_.begin()
; cur != parms_.end() ; ++cur) {
const InterfacePort*curp = *cur;
if (cur != parms_.begin())
out << ", ";
out << "parameter \\" << curp->name << " = ";
ivl_assert(*this, curp->expr);
errors += curp->expr->emit(out, this, 0);
}
out << ") ";
}
out << "module " << get_name();
out << get_name();
// If there are ports, emit them.
if (ports.size() > 0) {
if (ports_.size() > 0) {
out << "(";
const char*sep = 0;
for (vector<InterfacePort*>::const_iterator cur = ports.begin()
; cur != ports.end() ; ++cur) {
for (vector<InterfacePort*>::const_iterator cur = ports_.begin()
; cur != ports_.end() ; ++cur) {
InterfacePort*port = *cur;
VType::decl_t&decl = declarations_[port->name];

View File

@ -42,11 +42,6 @@ void Expression::set_type(const VType*typ)
type_ = typ;
}
bool Expression::evaluate(ScopeBase*, int64_t&) const
{
return false;
}
bool Expression::symbolic_compare(const Expression*) const
{
cerr << get_fileline() << ": internal error: "
@ -87,40 +82,6 @@ ExpAttribute::~ExpAttribute()
delete base_;
}
bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const
{
/* 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") {
const VType*base_type = base_->peek_type();
//if (base_type == 0)
// base_type = base_->probe_type(ent,arc);
ivl_assert(*this, base_type);
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
if (arr == 0) {
cerr << get_fileline() << ": error: "
<< "Cannot apply the 'length attribute to non-array objects"
<< endl;
return false;
}
int64_t size = 1;
for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) {
const VTypeArray::range_t&dim = arr->dimension(idx);
ivl_assert(*this, ! dim.is_box());
size *= 1 + labs(dim.msb() - dim.lsb());
}
val = size;
return true;
}
return false;
}
ExpBinary::ExpBinary(Expression*op1, Expression*op2)
: operand1_(op1), operand2_(op2)
{
@ -402,18 +363,6 @@ const char* ExpName::name() const
return name_;
}
bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
{
const VType*type;
Expression*exp;
bool rc = scope->find_constant(name_, type, exp);
if (rc == false)
return false;
return exp->evaluate(scope, val);
}
ExpRelation::ExpRelation(ExpRelation::fun_t ty, Expression*op1, Expression*op2)
: ExpBinary(op1, op2), fun_(ty)
{

View File

@ -80,6 +80,8 @@ class Expression : public LineInfo {
// argument if the evaluation works, or return false if it
// cannot be done.
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
virtual bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;
// The symbolic compare returns true if the two expressions
// are equal without actually calculating the value.
@ -266,6 +268,7 @@ class ExpAttribute : public Expression {
int emit(ostream&out, Entity*ent, Architecture*arc);
// Some attributes can be evaluated at compile time
bool evaluate(ScopeBase*scope, int64_t&val) const;
bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
private:
@ -427,6 +430,7 @@ class ExpName : public Expression {
int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
bool evaluate(ScopeBase*scope, int64_t&val) const;
bool evaluate(Entity*ent, Architecture*arc, int64_t&val) const;
bool symbolic_compare(const Expression*that) const;
void dump(ostream&out, int indent = 0) const;
const char* name() const;

View File

@ -30,7 +30,7 @@ using namespace std;
int Expression::elaborate_lval(Entity*, Architecture*, bool)
{
cerr << get_fileline() << ": error: Expression is not a valie l-value." << endl;
cerr << get_fileline() << ": error: Expression is not a valid l-value." << endl;
return 1;
}
@ -57,6 +57,13 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ)
found_type = cur->type;
} else if (ent->find_generic(name_)) {
cerr << get_fileline() << ": error: Assignment to generic "
<< name_ << " from entity "
<< ent->get_name() << "." << endl;
return 1;
} else if (Signal*sig = arc->find_signal(name_)) {
// Tell the target signal that this may be a sequential l-value.
if (is_sequ) sig->count_ref_sequ();
@ -93,8 +100,10 @@ int ExpName::elaborate_lval(Entity*ent, Architecture*arc, bool is_sequ)
flag = lsb_->evaluate(arc, use_lsb);
ivl_assert(*this, flag);
Expression*exp_msb = new ExpInteger(use_msb);
Expression*exp_lsb = new ExpInteger(use_lsb);
vector<VTypeArray::range_t> use_dims (1);
use_dims[0] = VTypeArray::range_t(use_msb, use_lsb);
use_dims[0] = VTypeArray::range_t(exp_msb, exp_lsb);
found_type = new VTypeArray(array->element_type(), use_dims);
}
}
@ -366,8 +375,15 @@ int ExpLogical::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype)
const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const
{
if (const InterfacePort*cur = ent->find_port(name_))
if (const InterfacePort*cur = ent->find_port(name_)) {
ivl_assert(*this, cur->type);
return cur->type;
}
if (const InterfacePort*cur = ent->find_generic(name_)) {
ivl_assert(*this, cur->type);
return cur->type;
}
if (Signal*sig = arc->find_signal(name_))
return sig->peek_type();

View File

@ -87,11 +87,38 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
const VTypeArray::range_t&rang = atype->dimension(0);
assert(! rang.is_box());
int asize = abs(rang.msb() - rang.lsb()) + 1;
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);
out << "{" << asize << "{";
errors += aggregate_[0].expr->emit(out, ent, arc);
out << "}}";
if (rc_msb && rc_lsb) {
int asize = abs(use_msb - use_lsb) + 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;
}
@ -110,7 +137,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
Expression*tmp = aggregate_[idx].choice->simple_expression(false);
int64_t tmp_val;
if (! tmp->evaluate(arc, tmp_val)) {
if (! tmp->evaluate(ent, arc, tmp_val)) {
cerr << tmp->get_fileline() << ": error: Unable to evaluate aggregate choice expression." << endl;
errors += 1;
continue;
@ -119,16 +146,22 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
element_map[tmp_val] = &aggregate_[idx];
}
ivl_assert(*this, rang.msb() >= rang.lsb());
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);
out << "{";
for (int idx = rang.msb() ; idx >= rang.lsb() ; idx -= 1) {
for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) {
choice_element*cur = element_map[idx];
if (cur == 0)
cur = element_other;
ivl_assert(*this, cur != 0);
if (idx < rang.msb())
if (idx < use_msb)
out << ", ";
errors += cur->expr->emit(out, ent, arc);
}
@ -154,7 +187,7 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
expression doesn't even need to be evaluated.) */
if (name_ == "length") {
int64_t val;
bool rc = evaluate(arc, val);
bool rc = evaluate(ent, arc, val);
out << val;
if (rc)
return errors;
@ -356,7 +389,7 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
} else if (name_ == "to_unsigned" && argv_.size() == 2) {
int64_t use_size;
bool rc = argv_[1]->evaluate(arc, use_size);
bool rc = argv_[1]->evaluate(ent, arc, use_size);
ivl_assert(*this, rc);
out << "$unsigned(" << use_size << "'(";

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "expression.h"
# include "architec.h"
# include <ivl_assert.h>
bool Expression::evaluate(ScopeBase*, int64_t&) const
{
return false;
}
bool Expression::evaluate(Entity*, Architecture*arc, int64_t&val) const
{
return evaluate(arc, val);
}
bool ExpAttribute::evaluate(ScopeBase*, int64_t&val) const
{
/* 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") {
const VType*base_type = base_->peek_type();
//if (base_type == 0)
// base_type = base_->probe_type(ent,arc);
ivl_assert(*this, base_type);
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
if (arr == 0) {
cerr << get_fileline() << ": error: "
<< "Cannot apply the 'length attribute to non-array objects"
<< endl;
return false;
}
int64_t size = 1;
for (size_t idx = 0 ; idx < arr->dimensions() ; idx += 1) {
const VTypeArray::range_t&dim = arr->dimension(idx);
ivl_assert(*this, ! dim.is_box());
size *= 1 + labs(dim.msb() - dim.lsb());
}
val = size;
return true;
}
return false;
}
bool ExpAttribute::evaluate(Entity*, Architecture*arc, int64_t&val) const
{
return evaluate(arc, val);
}
bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
{
const VType*type;
Expression*exp;
bool rc = scope->find_constant(name_, type, exp);
if (rc == false)
return false;
return exp->evaluate(scope, val);
}
bool ExpName::evaluate(Entity*ent, Architecture*arc, int64_t&val) const
{
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)
return gen->expr->evaluate(ent, arc, val);
}
return evaluate(arc, val);
}

View File

@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# define __STDC_LIMIT_MACROS
# include "parse_misc.h"
# include "compiler.h"
# include "package.h"
@ -24,6 +25,7 @@
# include <list>
# include <map>
# include <string>
# include <stdint.h>
# include <sys/stat.h>
# include <cassert>
@ -312,6 +314,8 @@ const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BI
const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER);
const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC);
const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0);
const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector<VTypeArray::range_t> (1));
const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector<VTypeArray::range_t> (1));
@ -322,6 +326,7 @@ void generate_global_types(ActiveScope*res)
res->bind_name(perm_string::literal("integer"), primitive_INTEGER);
res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC);
res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR);
res->bind_name(perm_string::literal("natural"), primitive_NATURAL);
}
void library_set_work_path(const char*path)

View File

@ -43,6 +43,7 @@
# include <map>
# include <vector>
# include "parse_types.h"
# include <ivl_assert.h>
# include <assert.h>
inline void FILE_NAME(LineInfo*tmp, const struct yyltype&where)
@ -1095,6 +1096,7 @@ interface_element
port->name = *(cur);
port->type = $4;
port->expr = $5;
ivl_assert(*port, port->type);
tmp->push_back(port);
}
delete $1;
@ -1746,6 +1748,9 @@ subtype_declaration
subtype_indication
: IDENTIFIER
{ const VType*tmp = parse_type_by_name(lex_strings.make($1));
if (tmp == 0) {
errormsg(@1, "Can't find type name `%s'\n", $1);
}
delete[]$1;
$$ = tmp;
}

View File

@ -66,7 +66,7 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch)
}
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
ScopeBase* /* scope */,
Expression*array_left,
bool /* downto*/ ,
Expression*array_right)
@ -89,17 +89,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
// For now, I only know how to handle 1 dimension
assert(base_array->dimensions() == 1);
int64_t left_val;
int64_t right_val;
bool rc = array_left->evaluate(scope, left_val);
if (rc == false)
return 0;
rc = array_right->evaluate(scope, right_val);
if (rc == false)
return 0;
range[0] = VTypeArray::range_t(left_val, right_val);
range[0] = VTypeArray::range_t(array_left, array_right);
VTypeArray*subtype = new VTypeArray(base_array->element_type(), range, base_array->signed_vector());
return subtype;

View File

@ -195,10 +195,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc)
ivl_assert(*this, range_);
int64_t start_val;
bool start_rc = range_->msb()->evaluate(arc, start_val);
bool start_rc = range_->msb()->evaluate(ent, arc, start_val);
int64_t finish_val;
bool finish_rc = range_->lsb()->evaluate(arc, finish_val);
bool finish_rc = range_->lsb()->evaluate(ent, arc, finish_val);
ivl_assert(*this, start_rc);
ivl_assert(*this, finish_rc);

View File

@ -26,6 +26,8 @@
# include <inttypes.h>
# include "StringHeap.h"
class Expression;
/*
* A description of a VHDL type consists of a graph of VType
* objects. Derived types are specific kinds of types, and those that
@ -123,17 +125,17 @@ class VTypeArray : public VType {
public:
class range_t {
public:
range_t() : msb_(INT_MAX), lsb_(INT_MIN) { }
range_t(int m, int l) : msb_(m), lsb_(l) { }
range_t() : msb_(0), lsb_(0) { }
range_t(Expression*m, Expression*l) : msb_(m), lsb_(l) { }
bool is_box() const { return msb_==INT_MAX && lsb_==INT_MIN; }
bool is_box() const { return msb_==0 && lsb_==0; }
int msb() const { return msb_; }
int lsb() const { return lsb_; }
Expression* msb() const { return msb_; }
Expression* lsb() const { return lsb_; }
private:
int msb_;
int lsb_;
Expression* msb_;
Expression* lsb_;
};
public:

View File

@ -19,7 +19,8 @@
# include "vtype.h"
# include <iostream>
# include "expression.h"
# include <iostream>
# include <typeinfo>
# include <cassert>
@ -43,7 +44,11 @@ int VTypeArray::emit_def(ostream&out, perm_string name) const
if (signed_flag_)
out << "signed ";
out << "[" << dimension(0).msb() << ":" << dimension(0).lsb() << "] ";
out << "[";
errors += dimension(0).msb()->emit(out, 0, 0);
out << ":";
errors += dimension(0).lsb()->emit(out, 0, 0);
out << "] ";
out << "\\" << name << " ";