Handle genvar variables in expressions.

In generate for blocks, there is a genvar that can be used in
expressions within the generate block. Generate this genvar in
the generated output, matched to the generate scope.
This commit is contained in:
Stephen Williams 2012-09-07 15:14:48 -07:00
parent 9cca1378bb
commit c14134aa2e
6 changed files with 99 additions and 7 deletions

View File

@ -22,6 +22,7 @@
# include "parse_types.h"
// Need this for parse_errors?
# include "parse_api.h"
# include <cassert>
using namespace std;
@ -38,6 +39,54 @@ Architecture::~Architecture()
ScopeBase::cleanup();
}
void Architecture::push_genvar_type(perm_string gname, const VType*gtype)
{
genvar_type_t tmp;
tmp.name = gname;
tmp.vtype = gtype;
genvar_type_stack_.push_back(tmp);
}
void Architecture::pop_genvar_type(void)
{
assert(! genvar_type_stack_.empty());
genvar_type_stack_.pop_back();
}
const VType* Architecture::probe_genvar_type(perm_string gname)
{
for (std::list<genvar_type_t>::reverse_iterator cur = genvar_type_stack_.rbegin()
; cur != genvar_type_stack_.rend() ; ++cur) {
if (cur->name == gname)
return cur->vtype;
}
return 0;
}
void Architecture::push_genvar_emit(perm_string gname, const GenerateStatement*gen)
{
genvar_emit_t tmp;
tmp.name = gname;
tmp.gen = gen;
genvar_emit_stack_.push_back(tmp);
}
void Architecture::pop_genvar_emit(void)
{
assert(! genvar_emit_stack_.empty());
genvar_emit_stack_.pop_back();
}
const GenerateStatement* Architecture::probe_genvar_emit(perm_string gname)
{
for (std::list<genvar_emit_t>::reverse_iterator cur = genvar_emit_stack_.rbegin()
; cur != genvar_emit_stack_.rend() ; ++cur) {
if (cur->name == gname)
return cur->gen;
}
return 0;
}
Architecture::Statement::Statement()
{
}

View File

@ -29,6 +29,7 @@ class ComponentBase;
class Entity;
class Expression;
class ExpName;
class GenerateStatement;
class SequentialStmt;
class Signal;
class named_expr_t;
@ -71,6 +72,18 @@ class Architecture : public Scope, public LineInfo {
// Elaborate this architecture in the context of the given entity.
int elaborate(Entity*entity);
// These methods are used while in the scope of a generate
// block to mark that a name is a genvar at this point.
const VType* probe_genvar_type(perm_string);
void push_genvar_type(perm_string gname, const VType*gtype);
void pop_genvar_type(void);
// These methods are used during EMIT to check for names that
// are genvar names.
const GenerateStatement* probe_genvar_emit(perm_string);
void push_genvar_emit(perm_string gname, const GenerateStatement*);
void pop_genvar_emit(void);
// Emit this architecture to the given out file in the context
// of the specified entity. This method is used by the
// elaborate code to display generated code to the specified
@ -85,6 +98,18 @@ class Architecture : public Scope, public LineInfo {
// Concurrent statements local to this architecture
std::list<Architecture::Statement*> statements_;
struct genvar_type_t {
perm_string name;
const VType*vtype;
};
std::list<genvar_type_t> genvar_type_stack_;
struct genvar_emit_t {
perm_string name;
const GenerateStatement*gen;
};
std::list<genvar_emit_t> genvar_emit_stack_;
private: // Not implemented
};
@ -98,9 +123,9 @@ class GenerateStatement : public Architecture::Statement {
GenerateStatement(perm_string gname, std::list<Architecture::Statement*>&s);
~GenerateStatement();
protected:
inline perm_string get_name() { return name_; }
inline perm_string get_name() const { return name_; }
protected:
int elaborate_statements(Entity*ent, Architecture*arc);
int emit_statements(ostream&out, Entity*ent, Architecture*arc);
void dump_statements(ostream&out, int indent) const;

View File

@ -133,7 +133,9 @@ int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc)
int ForGenerate::elaborate(Entity*ent, Architecture*arc)
{
int errors = 0;
arc->push_genvar_type(genvar_, lsb_->probe_type(ent, arc));
errors += elaborate_statements(ent, arc);
arc->pop_genvar_type();
return errors;
}

View File

@ -183,16 +183,19 @@ int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc
int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "genvar \\" << genvar_ << " ;" << endl;
out << "for (\\" << genvar_ << " = ";
out << "genvar \\" << get_name() << ":" << genvar_ << " ;" << endl;
out << "for (\\" << get_name() << ":" << genvar_ << " = ";
errors += lsb_->emit(out, ent, arc);
out << "; \\" << genvar_ << " <= ";
out << "; \\" << get_name() << ":" << genvar_ << " <= ";
errors += msb_->emit(out, ent, arc);
out << "; \\" << genvar_ << " = \\" << genvar_ << " + 1)"
out << "; \\" << get_name() << ":" << genvar_ << " = \\" << get_name() << ":" << genvar_ << " + 1)"
<< " begin : \\" << get_name() << endl;
arc->push_genvar_emit(genvar_, this);
errors += emit_statements(out, ent, arc);
arc->pop_genvar_emit();
out << "end" << endl;
return errors;

View File

@ -700,6 +700,10 @@ const VType* ExpName::probe_prefixed_type_(Entity*ent, Architecture*arc) const
return 0;
}
while (const VTypeDef*def = dynamic_cast<const VTypeDef*> (prefix_type)) {
prefix_type = def->peek_definition();
}
// If the prefix type is a record, then the current name is
// the name of a member.
if (const VTypeRecord*pref_record = dynamic_cast<const VTypeRecord*> (prefix_type)) {
@ -745,6 +749,10 @@ const VType* ExpName::probe_type(Entity*ent, Architecture*arc) const
if (arc->find_constant(name_, ctype, cval))
return ctype;
if (const VType*gtype = arc->probe_genvar_type(name_)) {
return gtype;
}
cerr << get_fileline() << ": error: Signal/variable " << name_
<< " not found in this context." << endl;
return 0;

View File

@ -628,7 +628,12 @@ int ExpName::emit(ostream&out, Entity*ent, Architecture*arc)
errors += prefix_->emit_as_prefix_(out, ent, arc);
}
out << "\\" << name_ << " ";
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);