2011-01-31 20:16:14 +01:00
|
|
|
/*
|
2013-12-11 23:59:20 +01:00
|
|
|
* Copyright (c) 2011-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
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "architec.h"
|
|
|
|
|
# include "entity.h"
|
|
|
|
|
# include "expression.h"
|
2011-05-15 20:07:42 +02:00
|
|
|
# include "sequential.h"
|
2014-09-29 11:31:18 +02:00
|
|
|
# include "subprogram.h"
|
2011-03-27 21:01:58 +02:00
|
|
|
# include "vsignal.h"
|
2016-01-08 14:30:58 +01:00
|
|
|
# include "std_types.h"
|
2011-01-31 20:16:14 +01:00
|
|
|
# include <iostream>
|
|
|
|
|
# include <typeinfo>
|
2011-10-24 02:08:48 +02:00
|
|
|
# include <ivl_assert.h>
|
2011-01-31 20:16:14 +01:00
|
|
|
|
2011-04-18 02:19:09 +02:00
|
|
|
int Scope::emit_signals(ostream&out, Entity*entity, Architecture*arc)
|
2011-01-31 20:16:14 +01:00
|
|
|
{
|
|
|
|
|
int errors = 0;
|
2011-03-27 21:01:58 +02:00
|
|
|
|
Use separate containers for current and previous scopes
This patch introduces in ScopeBase separate containers
for declarations coming from the current scope and from
the previous scopes.
Until now, in one scope, all objects were kept in an stl map.
When a scope was created inside other scopes, a shallow
copy of the map was made. This solution was nice for
name shadowing (in new scopes, when a name was
encountered, the old objects were overridden by a new
one), but didn't allow for distinguishing where the objects
were allocated. As a result, it is impossible to know who
the owner is and who should delete them.
In this commit ScopeBase gets two containers: for old
and new objects. If a ScopeBase is made from another
ScopeBase object, all objects from the copied object
go to an old_XXX container, where XXX depends on the
type of the copied objects. When a ScopeBase object
is deleted, the objects from new_XXX are deleted and
the ones from old_XXX are not touched.
This patch adds some complexity to the internals
of ScopeBase, but leaves its interface unchanged.
2011-07-20 16:34:36 +02:00
|
|
|
for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
|
|
|
|
|
; cur != old_signals_.end() ; ++cur) {
|
2011-03-27 21:01:58 +02:00
|
|
|
|
2011-04-18 02:19:09 +02:00
|
|
|
errors += cur->second->emit(out, entity, arc);
|
|
|
|
|
}
|
Use separate containers for current and previous scopes
This patch introduces in ScopeBase separate containers
for declarations coming from the current scope and from
the previous scopes.
Until now, in one scope, all objects were kept in an stl map.
When a scope was created inside other scopes, a shallow
copy of the map was made. This solution was nice for
name shadowing (in new scopes, when a name was
encountered, the old objects were overridden by a new
one), but didn't allow for distinguishing where the objects
were allocated. As a result, it is impossible to know who
the owner is and who should delete them.
In this commit ScopeBase gets two containers: for old
and new objects. If a ScopeBase is made from another
ScopeBase object, all objects from the copied object
go to an old_XXX container, where XXX depends on the
type of the copied objects. When a ScopeBase object
is deleted, the objects from new_XXX are deleted and
the ones from old_XXX are not touched.
This patch adds some complexity to the internals
of ScopeBase, but leaves its interface unchanged.
2011-07-20 16:34:36 +02:00
|
|
|
for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
|
|
|
|
|
; cur != new_signals_.end() ; ++cur) {
|
2011-04-18 02:19:09 +02:00
|
|
|
|
Use separate containers for current and previous scopes
This patch introduces in ScopeBase separate containers
for declarations coming from the current scope and from
the previous scopes.
Until now, in one scope, all objects were kept in an stl map.
When a scope was created inside other scopes, a shallow
copy of the map was made. This solution was nice for
name shadowing (in new scopes, when a name was
encountered, the old objects were overridden by a new
one), but didn't allow for distinguishing where the objects
were allocated. As a result, it is impossible to know who
the owner is and who should delete them.
In this commit ScopeBase gets two containers: for old
and new objects. If a ScopeBase is made from another
ScopeBase object, all objects from the copied object
go to an old_XXX container, where XXX depends on the
type of the copied objects. When a ScopeBase object
is deleted, the objects from new_XXX are deleted and
the ones from old_XXX are not touched.
This patch adds some complexity to the internals
of ScopeBase, but leaves its interface unchanged.
2011-07-20 16:34:36 +02:00
|
|
|
errors += cur->second->emit(out, entity, arc);
|
|
|
|
|
}
|
2011-04-18 02:19:09 +02:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-18 05:19:15 +02:00
|
|
|
int Scope::emit_variables(ostream&out, Entity*entity, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
|
|
|
|
|
; cur != old_variables_.end() ; ++cur) {
|
|
|
|
|
|
|
|
|
|
errors += cur->second->emit(out, entity, arc);
|
|
|
|
|
}
|
|
|
|
|
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
|
|
|
|
|
; cur != new_variables_.end() ; ++cur) {
|
|
|
|
|
|
|
|
|
|
errors += cur->second->emit(out, entity, arc);
|
|
|
|
|
}
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-18 02:19:09 +02:00
|
|
|
int Architecture::emit(ostream&out, Entity*entity)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
2011-10-10 00:25:35 +02:00
|
|
|
// Find typedefs that are present in the architecture body and
|
|
|
|
|
// emit them, so that following code can use the name instead
|
|
|
|
|
// of the full definition.
|
2012-05-13 03:38:49 +02:00
|
|
|
|
|
|
|
|
typedef_context_t typedef_ctx;
|
2016-01-08 14:30:58 +01:00
|
|
|
for (map<perm_string,const VType*>::iterator cur = use_types_.begin()
|
|
|
|
|
; cur != use_types_.end() ; ++cur) {
|
|
|
|
|
if(is_global_type(cur->first))
|
|
|
|
|
continue;
|
2014-10-15 11:13:04 +02:00
|
|
|
|
2016-01-08 14:30:58 +01:00
|
|
|
if(const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second))
|
|
|
|
|
errors += def->emit_typedef(out, typedef_ctx);
|
|
|
|
|
}
|
2013-05-13 04:17:12 +02:00
|
|
|
for (map<perm_string,const VType*>::iterator cur = cur_types_.begin()
|
|
|
|
|
; cur != cur_types_.end() ; ++cur) {
|
2014-10-15 11:13:04 +02:00
|
|
|
if(const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second))
|
|
|
|
|
errors += def->emit_typedef(out, typedef_ctx);
|
2011-10-10 00:25:35 +02:00
|
|
|
}
|
|
|
|
|
|
2013-05-13 04:17:12 +02:00
|
|
|
for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
|
|
|
|
|
; cur != use_constants_.end() ; ++cur) {
|
Use separate containers for current and previous scopes
This patch introduces in ScopeBase separate containers
for declarations coming from the current scope and from
the previous scopes.
Until now, in one scope, all objects were kept in an stl map.
When a scope was created inside other scopes, a shallow
copy of the map was made. This solution was nice for
name shadowing (in new scopes, when a name was
encountered, the old objects were overridden by a new
one), but didn't allow for distinguishing where the objects
were allocated. As a result, it is impossible to know who
the owner is and who should delete them.
In this commit ScopeBase gets two containers: for old
and new objects. If a ScopeBase is made from another
ScopeBase object, all objects from the copied object
go to an old_XXX container, where XXX depends on the
type of the copied objects. When a ScopeBase object
is deleted, the objects from new_XXX are deleted and
the ones from old_XXX are not touched.
This patch adds some complexity to the internals
of ScopeBase, but leaves its interface unchanged.
2011-07-20 16:34:36 +02:00
|
|
|
|
|
|
|
|
out << "localparam " << cur->first << " = ";
|
|
|
|
|
errors += cur->second->val->emit(out, entity, this);
|
|
|
|
|
out << ";" << endl;
|
|
|
|
|
}
|
2013-05-13 04:17:12 +02:00
|
|
|
for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
|
|
|
|
|
; cur != cur_constants_.end() ; ++cur) {
|
2011-04-18 02:19:09 +02:00
|
|
|
|
Use separate containers for current and previous scopes
This patch introduces in ScopeBase separate containers
for declarations coming from the current scope and from
the previous scopes.
Until now, in one scope, all objects were kept in an stl map.
When a scope was created inside other scopes, a shallow
copy of the map was made. This solution was nice for
name shadowing (in new scopes, when a name was
encountered, the old objects were overridden by a new
one), but didn't allow for distinguishing where the objects
were allocated. As a result, it is impossible to know who
the owner is and who should delete them.
In this commit ScopeBase gets two containers: for old
and new objects. If a ScopeBase is made from another
ScopeBase object, all objects from the copied object
go to an old_XXX container, where XXX depends on the
type of the copied objects. When a ScopeBase object
is deleted, the objects from new_XXX are deleted and
the ones from old_XXX are not touched.
This patch adds some complexity to the internals
of ScopeBase, but leaves its interface unchanged.
2011-07-20 16:34:36 +02:00
|
|
|
out << "localparam " << cur->first << " = ";
|
|
|
|
|
errors += cur->second->val->emit(out, entity, this);
|
|
|
|
|
out << ";" << endl;
|
2011-03-27 21:01:58 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-18 02:19:09 +02:00
|
|
|
errors += emit_signals(out, entity, this);
|
2011-08-18 05:19:15 +02:00
|
|
|
errors += emit_variables(out, entity, this);
|
2011-04-18 02:19:09 +02:00
|
|
|
|
2016-01-29 16:34:10 +01:00
|
|
|
for (map<perm_string,SubHeaderList>::const_iterator cur = cur_subprograms_.begin()
|
2013-12-11 23:59:20 +01:00
|
|
|
; cur != cur_subprograms_.end() ; ++ cur) {
|
2016-01-29 16:34:10 +01:00
|
|
|
const SubHeaderList& subp_list = cur->second;
|
|
|
|
|
|
|
|
|
|
for(SubHeaderList::const_iterator it = subp_list.begin();
|
|
|
|
|
it != subp_list.end(); ++it) {
|
|
|
|
|
SubprogramHeader*subp = *it;
|
|
|
|
|
|
|
|
|
|
// Do not emit unbounded functions, we will just need fixed instances later
|
|
|
|
|
if(!subp->unbounded())
|
|
|
|
|
errors += subp->emit_package(out);
|
|
|
|
|
}
|
2013-12-11 23:59:20 +01:00
|
|
|
}
|
|
|
|
|
|
2011-01-31 20:16:14 +01:00
|
|
|
for (list<Architecture::Statement*>::iterator cur = statements_.begin()
|
|
|
|
|
; cur != statements_.end() ; ++cur) {
|
|
|
|
|
|
|
|
|
|
errors += (*cur)->emit(out, entity, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int Architecture::Statement::emit(ostream&out, Entity*, Architecture*)
|
|
|
|
|
{
|
|
|
|
|
out << " // " << get_fileline() << ": internal error: "
|
|
|
|
|
<< "I don't know how to emit this statement! "
|
|
|
|
|
<< "type=" << typeid(*this).name() << endl;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
2011-10-24 02:08:48 +02:00
|
|
|
ivl_assert(*this, rval_.size() == 1);
|
2016-01-21 10:52:18 +01:00
|
|
|
const Expression*rval = rval_.front();
|
2011-01-31 20:16:14 +01:00
|
|
|
|
|
|
|
|
out << "// " << get_fileline() << endl;
|
2011-03-27 21:01:58 +02:00
|
|
|
out << "assign ";
|
2016-01-21 10:52:18 +01:00
|
|
|
if(const ExpDelay*delayed = dynamic_cast<const ExpDelay*>(rval)) {
|
|
|
|
|
out << "#(";
|
|
|
|
|
delayed->peek_delay()->emit(out, ent, arc);
|
|
|
|
|
out << ") ";
|
|
|
|
|
rval = delayed->peek_expr();
|
|
|
|
|
}
|
2011-03-27 21:01:58 +02:00
|
|
|
errors += lval_->emit(out, ent, arc);
|
|
|
|
|
out << " = ";
|
2011-01-31 20:16:14 +01:00
|
|
|
errors += rval->emit(out, ent, arc);
|
|
|
|
|
out << ";" << endl;
|
2016-01-21 10:52:18 +01:00
|
|
|
|
2011-01-31 20:16:14 +01:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-22 10:20:03 +01:00
|
|
|
int CondSignalAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
out << "// " << get_fileline() << endl;
|
|
|
|
|
out << "always @(";
|
|
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
|
for(list<const ExpName*>::const_iterator it = sens_list_.begin();
|
|
|
|
|
it != sens_list_.end(); ++it) {
|
|
|
|
|
if(first)
|
|
|
|
|
first = false;
|
|
|
|
|
else
|
|
|
|
|
out << ",";
|
|
|
|
|
|
|
|
|
|
errors += (*it)->emit(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << ") begin" << endl;
|
|
|
|
|
|
|
|
|
|
first = true;
|
|
|
|
|
for(list<ExpConditional::case_t*>::iterator it = options_.begin();
|
|
|
|
|
it != options_.end(); ++it) {
|
|
|
|
|
ExpConditional::case_t*cas = *it;
|
|
|
|
|
ivl_assert(*this, cas->true_clause().size() == 1);
|
|
|
|
|
const Expression*rval = cas->true_clause().front();
|
|
|
|
|
|
|
|
|
|
if(first)
|
|
|
|
|
first = false;
|
|
|
|
|
else
|
|
|
|
|
out << "else ";
|
|
|
|
|
|
|
|
|
|
if(Expression*cond = cas->condition()) {
|
|
|
|
|
out << "if(";
|
|
|
|
|
cond->emit(out, ent, arc);
|
|
|
|
|
out << ") ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << endl;
|
|
|
|
|
lval_->emit(out, ent, arc);
|
|
|
|
|
out << " = ";
|
|
|
|
|
rval->emit(out, ent, arc);
|
|
|
|
|
out << ";" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << "end" << endl;
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-01 03:50:48 +02:00
|
|
|
int ComponentInstantiation::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
2011-10-24 02:08:48 +02:00
|
|
|
const char*comma = "";
|
2011-04-01 03:50:48 +02:00
|
|
|
int errors = 0;
|
|
|
|
|
|
2015-03-06 16:59:30 +01:00
|
|
|
arc->set_cur_component(this);
|
|
|
|
|
|
2015-05-21 01:25:34 +02:00
|
|
|
if(ComponentBase*comp = arc->find_component(cname_)) {
|
|
|
|
|
const std::vector<InterfacePort*>& generics = comp->get_generics();
|
|
|
|
|
|
|
|
|
|
if(generics.size() != generic_map_.size())
|
|
|
|
|
// Display an error for generics that do not have neither
|
|
|
|
|
// default nor component specific value defined
|
|
|
|
|
for(vector<InterfacePort*>::const_iterator it = generics.begin();
|
|
|
|
|
it != generics.end(); ++it) {
|
|
|
|
|
if(!(*it)->expr && generic_map_.count((*it)->name) == 0) {
|
|
|
|
|
cerr << get_fileline() << ": generic " << (*it)->name <<
|
|
|
|
|
"value is not defined" << endl;
|
|
|
|
|
++errors;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 02:08:48 +02:00
|
|
|
out << cname_;
|
2011-11-23 04:44:13 +01:00
|
|
|
if (! generic_map_.empty()) {
|
2011-10-24 02:08:48 +02:00
|
|
|
out << " #(";
|
|
|
|
|
comma = "";
|
|
|
|
|
for (map<perm_string,Expression*>::iterator cur = generic_map_.begin()
|
|
|
|
|
; cur != generic_map_.end() ; ++cur) {
|
|
|
|
|
ivl_assert(*this, cur->second);
|
|
|
|
|
out << comma << ".\\" << cur->first << " (";
|
|
|
|
|
errors += cur->second->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
comma = ", ";
|
|
|
|
|
}
|
|
|
|
|
out << ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << " \\" << iname_ << " (";
|
|
|
|
|
comma = "";
|
|
|
|
|
for (map<perm_string,Expression*>::iterator cur = port_map_.begin()
|
2011-04-01 03:50:48 +02:00
|
|
|
; cur != port_map_.end() ; ++cur) {
|
2011-06-13 01:59:07 +02:00
|
|
|
// Skip unconnected ports
|
|
|
|
|
if (cur->second == 0)
|
|
|
|
|
continue;
|
2011-10-24 02:08:48 +02:00
|
|
|
out << comma << ".\\" << cur->first << " (";
|
2011-04-01 03:50:48 +02:00
|
|
|
errors += cur->second->emit(out, ent, arc);
|
|
|
|
|
out << ")";
|
|
|
|
|
comma = ", ";
|
|
|
|
|
}
|
|
|
|
|
out << ");" << endl;
|
|
|
|
|
|
2015-03-06 16:59:30 +01:00
|
|
|
arc->set_cur_component(NULL);
|
|
|
|
|
|
2011-04-01 03:50:48 +02:00
|
|
|
return errors;
|
|
|
|
|
}
|
2011-05-15 20:07:42 +02:00
|
|
|
|
2011-10-31 01:10:19 +01:00
|
|
|
int GenerateStatement::emit_statements(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
for (list<Architecture::Statement*>::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;
|
2012-09-08 00:14:48 +02:00
|
|
|
out << "genvar \\" << get_name() << ":" << genvar_ << " ;" << endl;
|
|
|
|
|
out << "for (\\" << get_name() << ":" << genvar_ << " = ";
|
2011-10-31 01:10:19 +01:00
|
|
|
errors += lsb_->emit(out, ent, arc);
|
2012-09-08 00:14:48 +02:00
|
|
|
out << "; \\" << get_name() << ":" << genvar_ << " <= ";
|
2011-10-31 01:10:19 +01:00
|
|
|
errors += msb_->emit(out, ent, arc);
|
2012-09-08 00:14:48 +02:00
|
|
|
out << "; \\" << get_name() << ":" << genvar_ << " = \\" << get_name() << ":" << genvar_ << " + 1)"
|
2011-10-31 01:10:19 +01:00
|
|
|
<< " begin : \\" << get_name() << endl;
|
|
|
|
|
|
2012-09-08 00:14:48 +02:00
|
|
|
arc->push_genvar_emit(genvar_, this);
|
|
|
|
|
|
2011-10-31 01:10:19 +01:00
|
|
|
errors += emit_statements(out, ent, arc);
|
|
|
|
|
|
2012-09-08 00:14:48 +02:00
|
|
|
arc->pop_genvar_emit();
|
2011-10-31 01:10:19 +01:00
|
|
|
out << "end" << endl;
|
2012-03-19 01:37:19 +01:00
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int IfGenerate::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
out << "if (";
|
|
|
|
|
cond_->emit(out, ent, arc);
|
|
|
|
|
out << ") begin : \\" << get_name() << endl;
|
|
|
|
|
|
|
|
|
|
errors += emit_statements(out, ent, arc);
|
|
|
|
|
|
|
|
|
|
out << "end" << endl;
|
|
|
|
|
|
2011-10-31 01:10:19 +01:00
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 18:15:09 +01:00
|
|
|
int StatementList::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
int errors = 0;
|
|
|
|
|
|
|
|
|
|
for (std::list<SequentialStmt*>::iterator it = statements_.begin();
|
|
|
|
|
it != statements_.end(); ++it) {
|
|
|
|
|
errors += (*it)->emit(out, ent, arc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int InitialStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
out << "initial begin" << endl;
|
|
|
|
|
int errors = StatementList::emit(out, ent, arc);
|
|
|
|
|
out << "end" << endl;
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int FinalStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
|
|
|
|
out << "final begin" << endl;
|
|
|
|
|
int errors = StatementList::emit(out, ent, arc);
|
|
|
|
|
out << "end" << endl;
|
|
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-31 19:42:35 +02:00
|
|
|
/*
|
|
|
|
|
* Emit a process statement using "always" syntax.
|
|
|
|
|
*
|
|
|
|
|
* Note that VHDL is different from Verilog, in that the sensitivity
|
|
|
|
|
* list goes at the END of the statement list, not at the
|
|
|
|
|
* beginning. In VHDL, all the statements are initially executed once
|
|
|
|
|
* before blocking in the first wait on the sensitivity list.
|
|
|
|
|
*/
|
2011-05-15 20:07:42 +02:00
|
|
|
int ProcessStatement::emit(ostream&out, Entity*ent, Architecture*arc)
|
|
|
|
|
{
|
2016-01-19 11:20:17 +01:00
|
|
|
/* Check if the process has no sensitivity list and ends up with
|
|
|
|
|
* a final wait. If so, convert the process to an initial block. */
|
|
|
|
|
const WaitStmt*wait_stmt = NULL;
|
|
|
|
|
if (! stmt_list().empty())
|
|
|
|
|
wait_stmt = dynamic_cast<const WaitStmt*>(stmt_list().back());
|
|
|
|
|
|
|
|
|
|
if (wait_stmt && wait_stmt->type() == WaitStmt::FINAL)
|
|
|
|
|
out << "initial begin" << endl;
|
|
|
|
|
else
|
|
|
|
|
out << "always begin" << endl;
|
2012-03-31 19:42:35 +02:00
|
|
|
|
2015-11-25 18:15:09 +01:00
|
|
|
int errors = StatementList::emit(out, ent, arc);
|
2011-05-15 20:07:42 +02:00
|
|
|
|
2011-07-29 02:07:49 +02:00
|
|
|
if (! sensitivity_list_.empty()) {
|
2012-03-31 19:42:35 +02:00
|
|
|
out << "@(";
|
2011-05-15 20:07:42 +02:00
|
|
|
const char*comma = 0;
|
|
|
|
|
for (list<Expression*>::iterator cur = sensitivity_list_.begin()
|
|
|
|
|
; cur != sensitivity_list_.end() ; ++cur) {
|
|
|
|
|
|
|
|
|
|
if (comma) out << comma;
|
|
|
|
|
errors += (*cur)->emit(out, ent, arc);
|
|
|
|
|
comma = ", ";
|
|
|
|
|
}
|
2012-03-31 19:42:35 +02:00
|
|
|
out << ") /* sensitivity list for process */;" << endl;
|
2011-05-15 20:07:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out << "end" << endl;
|
|
|
|
|
return errors;
|
|
|
|
|
}
|