From 98d928f6e07fd9b94e18f782b2e21fe77b70256e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 30 Oct 2011 17:10:19 -0700 Subject: [PATCH] Add support for VHDL for-generate --- vhdlpp/architec.cc | 23 ++++++++++++++++++++ vhdlpp/architec.h | 41 ++++++++++++++++++++++++++++++++++++ vhdlpp/architec_debug.cc | 25 +++++++++++++++++++++- vhdlpp/architec_elaborate.cc | 18 ++++++++++++++++ vhdlpp/architec_emit.cc | 29 +++++++++++++++++++++++++ vhdlpp/parse.y | 30 ++++++++++++++++++++++++-- 6 files changed, 163 insertions(+), 3 deletions(-) diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index 85fef32a4..ea60fe801 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -46,6 +46,29 @@ Architecture::Statement::~Statement() { } +GenerateStatement::GenerateStatement(perm_string gname, + std::list&s) +: name_(gname) +{ + statements_.splice(statements_.end(), s); +} + +GenerateStatement::~GenerateStatement() +{ + for_each(statements_.begin(), statements_.end(), ::delete_object()); +} + +ForGenerate::ForGenerate(perm_string gname, perm_string genvar, + range_t*rang, std::list&s) +: GenerateStatement(gname, s), genvar_(genvar), + lsb_(rang->lsb()), msb_(rang->msb()) +{ +} + +ForGenerate::~ForGenerate() +{ +} + SignalAssignment::SignalAssignment(ExpName*name, list&rv) : lval_(name) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 328590b9f..af23766c6 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -32,6 +32,7 @@ class ExpName; class SequentialStmt; class Signal; class named_expr_t; +class range_t; /* * The Architecture class carries the contents (name, statements, @@ -87,6 +88,46 @@ class Architecture : public Scope, public LineInfo { private: // Not implemented }; +/* + * This is a base class for various generate statement types. It holds + * the generate statement name, and a list of substatements. + */ +class GenerateStatement : public Architecture::Statement { + + public: + GenerateStatement(perm_string gname, std::list&s); + ~GenerateStatement(); + + protected: + inline perm_string get_name() { return name_; } + + int elaborate_statements(Entity*ent, Architecture*arc); + int emit_statements(ostream&out, Entity*ent, Architecture*arc); + void dump_statements(ostream&out, int indent) const; + + private: + perm_string name_; + std::list statements_; +}; + +class ForGenerate : public GenerateStatement { + + public: + ForGenerate(perm_string gname, perm_string genvar, + range_t*rang, std::list&s); + ~ForGenerate(); + + int elaborate(Entity*ent, Architecture*arc); + int emit(ostream&out, Entity*entity, Architecture*arc); + void dump(ostream&out, int ident =0) const; + + private: + perm_string genvar_; + Expression*lsb_; + Expression*msb_; +}; + + /* * The SignalAssignment class represents the * concurrent_signal_assignment that is placed in an architecture. diff --git a/vhdlpp/architec_debug.cc b/vhdlpp/architec_debug.cc index 41a11ae02..c2dcfce26 100644 --- a/vhdlpp/architec_debug.cc +++ b/vhdlpp/architec_debug.cc @@ -47,7 +47,10 @@ void Architecture::Statement::dump(ostream&out, int indent) const void ComponentInstantiation::dump(ostream&out, int indent) const { - out << setw(indent) << "" << "Component Instantiation file=" << get_fileline() << endl; + out << setw(indent) << "" << "Component Instantiation " + << "instance=" << iname_ + << " of component=" << cname_ + << ", file=" << get_fileline() << endl; for (map::const_iterator cur = port_map_.begin() ; cur != port_map_.end() ; ++cur) { @@ -60,6 +63,26 @@ void ComponentInstantiation::dump(ostream&out, int indent) const } +void GenerateStatement::dump_statements(ostream&out, int indent) const +{ + for (list::const_iterator cur = statements_.begin() + ; cur != statements_.end() ; ++cur) { + Statement*curp = *cur; + curp->dump(out, indent); + } +} + +void ForGenerate::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "for " << genvar_ + << " in" << endl; + msb_->dump(out, indent+4); + lsb_->dump(out, indent+4); + out << setw(indent) << "" << "generate" << endl; + dump_statements(out, indent+4); + out << setw(indent) << "" << "end generate" << endl; +} + void SignalAssignment::dump(ostream&out, int indent) const { out << setw(indent) << "" << "SignalAssignment file=" << get_fileline() << endl; diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 175732d20..4a289a466 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -99,6 +99,24 @@ int ComponentInstantiation::elaborate(Entity*ent, Architecture*arc) return errors; } +int GenerateStatement::elaborate_statements(Entity*ent, Architecture*arc) +{ + int errors = 0; + for (list::iterator cur = statements_.begin() + ; cur != statements_.end() ; ++cur) { + Architecture::Statement*curp = *cur; + errors += curp->elaborate(ent, arc); + } + return errors; +} + +int ForGenerate::elaborate(Entity*ent, Architecture*arc) +{ + int errors = 0; + errors += elaborate_statements(ent, arc); + return errors; +} + /* * This method attempts to rewrite the process content as an * always-@(n-edge ) version of the same statement. This makes diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 0f8831f3d..5a8e5f2e0 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -167,6 +167,35 @@ int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc) return errors; } +int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + for (list::iterator cur = statements_.begin() + ; cur != statements_.end() ; ++cur) { + Architecture::Statement*curp = *cur; + errors += curp->emit(out, ent, arc); + } + return errors; +} + +int ForGenerate::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "generate genvar \\" << genvar_ << " ;" << endl; + out << "for (\\" << genvar_ << " = "; + errors += lsb_->emit(out, ent, arc); + out << "; \\" << genvar_ << " <= "; + errors += msb_->emit(out, ent, arc); + out << "; \\" << genvar_ << " = \\" << genvar_ << " + 1)" + << " begin : \\" << get_name() << endl; + + errors += emit_statements(out, ent, arc); + + out << "end" << endl; + out << "endgenerate" << endl; + return errors; +} + int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3a6df7ca1..6b2386357 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -239,8 +239,8 @@ const VType*parse_type_by_name(perm_string name) %type component_specification %type concurrent_statement component_instantiation_statement concurrent_signal_assignment_statement -%type process_statement -%type architecture_statement_part +%type for_generate_statement process_statement +%type architecture_statement_part generate_statement_body %type choice %type choices @@ -633,6 +633,7 @@ concurrent_signal_assignment_statement concurrent_statement : component_instantiation_statement | concurrent_signal_assignment_statement + | for_generate_statement | process_statement ; @@ -955,6 +956,31 @@ factor } ; +for_generate_statement + : IDENTIFIER ':' K_for IDENTIFIER K_in range + K_generate generate_statement_body + K_end K_generate identifier_opt ';' + { perm_string name = lex_strings.make($1); + perm_string gvar = lex_strings.make($4); + ForGenerate*tmp = new ForGenerate(name, gvar, $6, *$8); + FILE_NAME(tmp, @1); + + if ($11 && name != $11) { + errormsg(@1, "for-generate name %s does not match closing name %s\n", + name.str(), $11); + } + delete $1; + delete $4; + delete $8; + delete $11; + $$ = tmp; + } + ; + +generate_statement_body + : architecture_statement_part { $$ = $1; } + ; + generic_clause_opt : generic_clause { $$ = $1;}