diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index df6acccc0..cd9f46422 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -245,7 +245,9 @@ void draw_nexus(ivl_nexus_t nexus) ivl_lpm_signed(lpm) != 0); ostringstream ss; ss << "LPM" << ivl_lpm_basename(lpm); - vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); + + if (!vhdl_scope->have_declared(ss.str())) + vhdl_scope->add_decl(new vhdl_signal_decl(ss.str().c_str(), type)); link_scope_to_nexus_tmp(priv, vhdl_scope, ss.str()); } @@ -382,10 +384,28 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) */ static string make_safe_name(ivl_signal_t sig) { - const char *base = ivl_signal_basename(sig); - if (base[0] == '_') - return string("VL") + base; + string base(ivl_signal_basename(sig)); + if (ivl_signal_local(sig)) + base = "Tmp" + base; + + if (base[0] == '_') + base = "Sig" + base; + + if (*base.rbegin() == '_') + base += "Sig"; + + // Can't have two consecutive underscores + size_t pos = base.find("__"); + while (pos != string::npos) { + base.replace(pos, 2, "_"); + pos = base.find("__"); + } + + // A signal name may not be the same as a component name + if (find_entity(base) != NULL) + base += "_Sig"; + // This is the complete list of VHDL reserved words const char *vhdl_reserved[] = { "abs", "access", "after", "alias", "all", "and", "architecture", @@ -405,14 +425,32 @@ static string make_safe_name(ivl_signal_t sig) }; for (const char **p = vhdl_reserved; *p != NULL; p++) { - if (strcasecmp(*p, base) == 0) { - return string("VL_") + base; + if (strcasecmp(*p, base.c_str()) == 0) { + return "Sig_" + base; break; } } return string(base); } +// Check if `name' differs from an existing name only in case and +// make it unique if it does. +static void avoid_name_collision(string& name, vhdl_scope* scope) +{ + if (scope->name_collides(name)) { + name += "_"; + ostringstream ss; + int i = 1; + do { + // Keep adding an extra number until we get a unique name + ss.str(""); + ss << name << i++; + } while (scope->name_collides(ss.str())); + + name = ss.str(); + } +} + /* * Declare all signals and ports for a scope. */ @@ -426,6 +464,8 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) remember_signal(sig, ent->get_arch()->get_scope()); string name(make_safe_name(sig)); + avoid_name_collision(name, ent->get_arch()->get_scope()); + rename_signal(sig, name); vhdl_type *sig_type; @@ -549,40 +589,49 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent, nexus_private_t *priv = static_cast(ivl_nexus_get_private(nexus)); assert(priv); - if (!visible_nexus(priv, arch_scope)) { + + vhdl_expr *map_to = NULL; + const string name(make_safe_name(to)); + + // We can only map ports to signals or constants + if (visible_nexus(priv, arch_scope)) { + vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus); + + // If we're mapping an output of this entity to an output of + // the child entity, then VHDL will not let us read the value + // of the signal (i.e. it must pass straight through). + // However, Verilog allows the signal to be read in the parent. + // The solution used here is to create an intermediate signal + // and connect it to both ports. + vhdl_decl* from_decl = + parent->get_arch()->get_scope()->get_decl(ref->get_name()); + if (!from_decl->is_readable() + && !arch_scope->have_declared(name + "_Readable")) { + vhdl_decl* tmp_decl = + new vhdl_signal_decl(name + "_Readable", ref->get_type()); + + // Add a comment to explain what this is for + tmp_decl->set_comment("Needed to connect outputs"); + + arch_scope->add_decl(tmp_decl); + parent->get_arch()->add_stmt + (new vhdl_cassign_stmt(from_decl->make_ref(), tmp_decl->make_ref())); + + map_to = tmp_decl->make_ref(); + } + else + map_to = ref; + } + else if (priv->const_driver && ivl_signal_port(to) == IVL_SIP_INPUT) { + map_to = priv->const_driver; + priv->const_driver = NULL; + } + else { // This nexus isn't attached to anything in the parent return; - } + } - vhdl_var_ref *ref = nexus_to_var_ref(parent->get_arch()->get_scope(), nexus); - - string name = make_safe_name(to); - - // If we're mapping an output of this entity to an output of - // the child entity, then VHDL will not let us read the value - // of the signal (i.e. it must pass straight through). - // However, Verilog allows the signal to be read in the parent. - // The solution used here is to create an intermediate signal - // and connect it to both ports. - vhdl_decl* from_decl = - parent->get_arch()->get_scope()->get_decl(ref->get_name()); - from_decl->print(); - if (!from_decl->is_readable() - && !arch_scope->have_declared(name + "_Readable")) { - vhdl_decl* tmp_decl = - new vhdl_signal_decl(name + "_Readable", ref->get_type()); - - // Add a comment to explain what this is for - tmp_decl->set_comment("Needed to connect outputs"); - - arch_scope->add_decl(tmp_decl); - parent->get_arch()->add_stmt - (new vhdl_cassign_stmt(from_decl->make_ref(), tmp_decl->make_ref())); - - ref = tmp_decl->make_ref(); - } - - inst->map_port(name.c_str(), ref); + inst->map_port(name, map_to); } /* @@ -976,7 +1025,11 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) loc = inst_name.find(']', 0); if (loc != string::npos) - inst_name.erase(loc, 1); + inst_name.erase(loc, 1); + + // Make sure the name doesn't collide with anything we've + // already declared + avoid_name_collision(inst_name, parent_arch->get_scope()); vhdl_comp_inst *inst = new vhdl_comp_inst(inst_name.c_str(), ent->get_name().c_str()); diff --git a/tgt-vhdl/state.cc b/tgt-vhdl/state.cc index 7263873cc..97d99ac0f 100644 --- a/tgt-vhdl/state.cc +++ b/tgt-vhdl/state.cc @@ -149,6 +149,19 @@ struct cmp_ent_name { const string& name_; }; +// Find an entity given its name. +vhdl_entity* find_entity(const string& name) +{ + entity_list_t::const_iterator it + = find_if(g_entities.begin(), g_entities.end(), + cmp_ent_name(name)); + + if (it != g_entities.end()) + return *it; + else + return NULL; +} + // Find a VHDL entity given a Verilog module scope. The VHDL entity // name should be the same as the Verilog module type name. // Note that this will return NULL if no entity has been recorded @@ -157,14 +170,7 @@ vhdl_entity* find_entity(const ivl_scope_t scope) { assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - entity_list_t::const_iterator it - = find_if(g_entities.begin(), g_entities.end(), - cmp_ent_name(ivl_scope_tname(scope))); - - if (it != g_entities.end()) - return *it; - else - return NULL; + return find_entity(ivl_scope_tname(scope)); } // Add an entity/architecture pair to the list of entities to emit. diff --git a/tgt-vhdl/state.hh b/tgt-vhdl/state.hh index 018af5b43..7edb3d812 100644 --- a/tgt-vhdl/state.hh +++ b/tgt-vhdl/state.hh @@ -39,7 +39,8 @@ ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) // Manage the set of VHDL entities void remember_entity(vhdl_entity *ent); -vhdl_entity *find_entity(const ivl_scope_t scope); +vhdl_entity* find_entity(const ivl_scope_t scope); +vhdl_entity* find_entity(const std::string& name); void emit_all_entities(std::ostream& os, int max_depth); void free_all_vhdl_objects(); diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index c642c07b9..5bd7490f2 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -74,6 +74,16 @@ bool vhdl_scope::have_declared(const std::string &name) const return get_decl(name) != NULL; } +// True if `name' differs in all but case from another declaration +bool vhdl_scope::name_collides(const string& name) const +{ + const vhdl_decl* decl = get_decl(name); + if (decl) + return decl->get_name() != name; + else + return false; +} + bool vhdl_scope::contained_within(const vhdl_scope *other) const { if (this == other) @@ -238,7 +248,7 @@ vhdl_comp_inst::~vhdl_comp_inst() } -void vhdl_comp_inst::map_port(const char *name, vhdl_expr *expr) +void vhdl_comp_inst::map_port(const string& name, vhdl_expr *expr) { port_map_t pmap = { name, expr }; mapping_.push_back(pmap); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 9f5bd8af2..3603c2e6e 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -695,7 +695,7 @@ public: ~vhdl_comp_inst(); void emit(std::ostream &of, int level) const; - void map_port(const char *name, vhdl_expr *expr); + void map_port(const string& name, vhdl_expr *expr); const std::string &get_comp_name() const { return comp_name_; } const std::string &get_inst_name() const { return inst_name_; } @@ -719,6 +719,7 @@ public: void add_forward_decl(vhdl_decl *decl); vhdl_decl *get_decl(const std::string &name) const; bool have_declared(const std::string &name) const; + bool name_collides(const string& name) const; bool contained_within(const vhdl_scope *other) const; vhdl_scope *get_parent() const;