diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 818bb2ffc..78050084f 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -376,6 +376,28 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope) draw_logic(arch, ivl_scope_log(scope, i)); } +// Replace consecutive underscores with a single underscore +static void replace_consecutive_underscores(string& str) +{ + size_t pos = str.find("__"); + while (pos != string::npos) { + str.replace(pos, 2, "_"); + pos = str.find("__"); + } +} + +// Return a valid VHDL name for a Verilog module +string valid_entity_name(const string& module_name) +{ + string name(module_name); + replace_consecutive_underscores(name); + if (name[0] == '_') + name = "Mod" + name; + if (*name.rbegin() == '_') + name += "Mod"; + return name; +} + // Make sure a signal name conforms to VHDL naming rules. string make_safe_name(ivl_signal_t sig) { @@ -391,11 +413,7 @@ string make_safe_name(ivl_signal_t sig) base += "Sig"; // Can't have two consecutive underscores - size_t pos = base.find("__"); - while (pos != string::npos) { - base.replace(pos, 2, "_"); - pos = base.find("__"); - } + replace_consecutive_underscores(base); // A signal name may not be the same as a component name if (find_entity(base) != NULL) @@ -446,9 +464,111 @@ static void avoid_name_collision(string& name, vhdl_scope* scope) } } -/* - * Declare all signals and ports for a scope. - */ +// Declare a single signal in a scope +static void declare_one_signal(vhdl_entity *ent, ivl_signal_t sig) +{ + 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; + unsigned dimensions = ivl_signal_dimensions(sig); + if (dimensions > 0) { + // Arrays are implemented by generating a separate type + // declaration for each array, and then declaring a + // signal of that type + + if (dimensions > 1) { + error("> 1 dimension arrays not implemented yet"); + return; + } + + string type_name = name + "_Type"; + vhdl_type *base_type = + vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); + + int lsb = ivl_signal_array_base(sig); + int msb = lsb + ivl_signal_array_count(sig) - 1; + + vhdl_type *array_type = + vhdl_type::array_of(base_type, type_name, msb, lsb); + vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); + ent->get_arch()->get_scope()->add_decl(array_decl); + + sig_type = new vhdl_type(*array_type); + } + else + sig_type = + vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); + + ivl_signal_port_t mode = ivl_signal_port(sig); + switch (mode) { + case IVL_SIP_NONE: + { + vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); + + ostringstream ss; + if (ivl_signal_local(sig)) { + ss << "Temporary created at " << ivl_signal_file(sig) << ":" + << ivl_signal_lineno(sig); + } else { + ss << "Declared at " << ivl_signal_file(sig) << ":" + << ivl_signal_lineno(sig); + } + decl->set_comment(ss.str().c_str()); + + ent->get_arch()->get_scope()->add_decl(decl); + } + break; + case IVL_SIP_INPUT: + ent->get_scope()->add_decl + (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); + break; + case IVL_SIP_OUTPUT: + { + vhdl_port_decl *decl = + new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); + ent->get_scope()->add_decl(decl); + } + + if (ivl_signal_type(sig) == IVL_SIT_REG) { + // A registered output + // In Verilog the output and reg can have the + // same name: this is not valid in VHDL + // Instead a new signal foo_Reg is created + // which represents the register + std::string newname(name); + newname += "_Reg"; + rename_signal(sig, newname.c_str()); + + vhdl_type *reg_type = new vhdl_type(*sig_type); + ent->get_arch()->get_scope()->add_decl + (new vhdl_signal_decl(newname.c_str(), reg_type)); + + // Create a concurrent assignment statement to + // connect the register to the output + ent->get_arch()->add_stmt + (new vhdl_cassign_stmt + (new vhdl_var_ref(name.c_str(), NULL), + new vhdl_var_ref(newname.c_str(), NULL))); + } + break; + case IVL_SIP_INOUT: + ent->get_scope()->add_decl + (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); + break; + default: + assert(false); + } +} + +// Declare all signals and ports for a scope. +// This is done in two phases: first the ports are added then then +// internal signals. Making two passes like this ensures ports get +// first pick of names when there is a collision. static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) { debug_msg("Declaring signals in scope type %s", ivl_scope_tname(scope)); @@ -456,102 +576,16 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope) int nsigs = ivl_scope_sigs(scope); for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - 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; - unsigned dimensions = ivl_signal_dimensions(sig); - if (dimensions > 0) { - // Arrays are implemented by generating a separate type - // declaration for each array, and then declaring a - // signal of that type + if (ivl_signal_port(sig) != IVL_SIP_NONE) + declare_one_signal(ent, sig); + } + + for (int i = 0; i < nsigs; i++) { + ivl_signal_t sig = ivl_scope_sig(scope, i); - if (dimensions > 1) { - error("> 1 dimension arrays not implemented yet"); - return; - } - - string type_name = name + "_Type"; - vhdl_type *base_type = - vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - - int lsb = ivl_signal_array_base(sig); - int msb = lsb + ivl_signal_array_count(sig) - 1; - - vhdl_type *array_type = - vhdl_type::array_of(base_type, type_name, msb, lsb); - vhdl_decl *array_decl = new vhdl_type_decl(type_name.c_str(), array_type); - ent->get_arch()->get_scope()->add_decl(array_decl); - - sig_type = new vhdl_type(*array_type); - } - else - sig_type = - vhdl_type::type_for(ivl_signal_width(sig), ivl_signal_signed(sig) != 0); - - ivl_signal_port_t mode = ivl_signal_port(sig); - switch (mode) { - case IVL_SIP_NONE: - { - vhdl_decl *decl = new vhdl_signal_decl(name.c_str(), sig_type); - - ostringstream ss; - if (ivl_signal_local(sig)) { - ss << "Temporary created at " << ivl_signal_file(sig) << ":" - << ivl_signal_lineno(sig); - } else { - ss << "Declared at " << ivl_signal_file(sig) << ":" - << ivl_signal_lineno(sig); - } - decl->set_comment(ss.str().c_str()); - - ent->get_arch()->get_scope()->add_decl(decl); - } - break; - case IVL_SIP_INPUT: - ent->get_scope()->add_decl - (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_IN)); - break; - case IVL_SIP_OUTPUT: - { - vhdl_port_decl *decl = - new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_OUT); - ent->get_scope()->add_decl(decl); - } - - if (ivl_signal_type(sig) == IVL_SIT_REG) { - // A registered output - // In Verilog the output and reg can have the - // same name: this is not valid in VHDL - // Instead a new signal foo_Reg is created - // which represents the register - std::string newname(name); - newname += "_Reg"; - rename_signal(sig, newname.c_str()); - - vhdl_type *reg_type = new vhdl_type(*sig_type); - ent->get_arch()->get_scope()->add_decl - (new vhdl_signal_decl(newname.c_str(), reg_type)); - - // Create a concurrent assignment statement to - // connect the register to the output - ent->get_arch()->add_stmt - (new vhdl_cassign_stmt - (new vhdl_var_ref(name.c_str(), NULL), - new vhdl_var_ref(newname.c_str(), NULL))); - } - break; - case IVL_SIP_INOUT: - ent->get_scope()->add_decl - (new vhdl_port_decl(name.c_str(), sig_type, VHDL_PORT_INOUT)); - break; - default: - assert(false); - } + if (ivl_signal_port(sig) == IVL_SIP_NONE) + declare_one_signal(ent, sig); } } @@ -788,7 +822,7 @@ static void create_skeleton_entity_for(ivl_scope_t scope, int depth) assert(ivl_scope_type(scope) == IVL_SCT_MODULE); // The type name will become the entity name - const char *tname = ivl_scope_tname(scope);; + const string tname = valid_entity_name(ivl_scope_tname(scope)); // Verilog does not have the entity/architecture distinction // so we always create a pair and associate the architecture @@ -1011,7 +1045,7 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) // Cannot have instance name the same as type in VHDL inst_name += "_Inst"; } - + // Need to replace any [ and ] characters that result // from generate statements string::size_type loc = inst_name.find('[', 0); @@ -1022,6 +1056,15 @@ static int draw_hierarchy(ivl_scope_t scope, void *_parent) if (loc != string::npos) inst_name.erase(loc, 1); + // No leading or trailing underscores + if (inst_name[0] == '_') + inst_name = "Inst" + inst_name; + if (*inst_name.rbegin() == '_') + inst_name += "Inst"; + + // Can't have two consecutive underscores + replace_consecutive_underscores(inst_name); + // Make sure the name doesn't collide with anything we've // already declared avoid_name_collision(inst_name, parent_arch->get_scope()); diff --git a/tgt-vhdl/state.cc b/tgt-vhdl/state.cc index 97d99ac0f..a4ad0d5dc 100644 --- a/tgt-vhdl/state.cc +++ b/tgt-vhdl/state.cc @@ -170,7 +170,7 @@ vhdl_entity* find_entity(const ivl_scope_t scope) { assert(ivl_scope_type(scope) == IVL_SCT_MODULE); - return find_entity(ivl_scope_tname(scope)); + return find_entity(valid_entity_name(ivl_scope_tname(scope))); } // Add an entity/architecture pair to the list of entities to emit. diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 5bd7490f2..c674e8a0c 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -100,7 +100,7 @@ vhdl_scope *vhdl_scope::get_parent() const return parent_; } -vhdl_entity::vhdl_entity(const char *name, vhdl_arch *arch, int depth__) +vhdl_entity::vhdl_entity(const string& name, vhdl_arch *arch, int depth__) : depth(depth__), name_(name), arch_(arch) { arch->get_scope()->set_parent(&ports_); diff --git a/tgt-vhdl/vhdl_syntax.hh b/tgt-vhdl/vhdl_syntax.hh index 3603c2e6e..12d027e1e 100644 --- a/tgt-vhdl/vhdl_syntax.hh +++ b/tgt-vhdl/vhdl_syntax.hh @@ -806,7 +806,7 @@ private: */ class vhdl_arch : public vhdl_element { public: - vhdl_arch(const char *entity, const char *name) + vhdl_arch(const string& entity, const string& name) : name_(name), entity_(entity) {} virtual ~vhdl_arch(); @@ -828,7 +828,7 @@ private: */ class vhdl_entity : public vhdl_element { public: - vhdl_entity(const char *name, vhdl_arch *arch, int depth=0); + vhdl_entity(const string& name, vhdl_arch *arch, int depth=0); virtual ~vhdl_entity(); void emit(std::ostream &of, int level=0) const; diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index a70980493..9dd5488b4 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -28,6 +28,7 @@ ivl_design_t get_vhdl_design(); vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); vhdl_var_ref* readable_ref(vhdl_scope* scope, ivl_nexus_t nex); string make_safe_name(ivl_signal_t sig); +string valid_entity_name(const string& module_name); int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true);