From f1f9274bb99d019c2eba0594681b2ad49c1fa59c Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 17 Jan 2009 13:38:11 +0000 Subject: [PATCH] Move VHDL global state management to a single file The new state.cc/hh file now manages all the global state that we maintain while generating VHDL. This should make the code a bit tidier. --- tgt-vhdl/Makefile.in | 2 +- tgt-vhdl/expr.cc | 1 + tgt-vhdl/logic.cc | 2 +- tgt-vhdl/lpm.cc | 1 + tgt-vhdl/process.cc | 1 + tgt-vhdl/scope.cc | 57 +--------- tgt-vhdl/state.cc | 241 +++++++++++++++++++++++++++++++++++++++++ tgt-vhdl/state.hh | 54 +++++++++ tgt-vhdl/stmt.cc | 1 + tgt-vhdl/support.cc | 1 + tgt-vhdl/vhdl.cc | 134 +---------------------- tgt-vhdl/vhdl_target.h | 14 --- 12 files changed, 306 insertions(+), 203 deletions(-) create mode 100644 tgt-vhdl/state.cc create mode 100644 tgt-vhdl/state.hh diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index a363353d6..398b91c28 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -49,7 +49,7 @@ dep: $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = vhdl.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ +O = vhdl.o state.o vhdl_element.o vhdl_type.o vhdl_syntax.o scope.o process.o \ stmt.o expr.o lpm.o display.o support.o cast.o logic.o ifeq (@WIN32@,yes) diff --git a/tgt-vhdl/expr.cc b/tgt-vhdl/expr.cc index c32249a09..038419d8a 100644 --- a/tgt-vhdl/expr.cc +++ b/tgt-vhdl/expr.cc @@ -20,6 +20,7 @@ #include "vhdl_target.h" #include "support.hh" +#include "state.hh" #include #include diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 269497b0d..aa9a442d4 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -20,6 +20,7 @@ #include "vhdl_target.h" #include "vhdl_element.hh" +#include "state.hh" #include #include @@ -82,7 +83,6 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0) cmp = new vhdl_binop_expr(sel, op, zero, NULL); } - ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope()); char zbit; switch (ivl_signal_type(sig)) { diff --git a/tgt-vhdl/lpm.cc b/tgt-vhdl/lpm.cc index 2d0fc46e6..ba7297bae 100644 --- a/tgt-vhdl/lpm.cc +++ b/tgt-vhdl/lpm.cc @@ -19,6 +19,7 @@ */ #include "vhdl_target.h" +#include "state.hh" #include #include diff --git a/tgt-vhdl/process.cc b/tgt-vhdl/process.cc index 881ee50aa..fca19dafa 100644 --- a/tgt-vhdl/process.cc +++ b/tgt-vhdl/process.cc @@ -20,6 +20,7 @@ #include "vhdl_target.h" #include "vhdl_element.hh" +#include "state.hh" #include #include diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 6bc4f5f6f..8e4c28e2d 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -20,70 +20,15 @@ #include "vhdl_target.h" #include "vhdl_element.hh" +#include "state.hh" #include #include #include #include -#include -#include static string make_safe_name(ivl_signal_t sig); -static vhdl_entity *g_active_entity = NULL; - -vhdl_entity *get_active_entity() -{ - return g_active_entity; -} - -void set_active_entity(vhdl_entity *ent) -{ - g_active_entity = ent; -} - -/* - * Set of scopes that are treated as the default examples of - * that type. Any other scopes of the same type are ignored. - */ -typedef set default_scopes_t; -static default_scopes_t g_default_scopes; - -/* - * True if two scopes have the same type name. - */ -static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b) -{ - return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0; -} - -/* - * True if we have already seen a scope with this type before. - * If the result is `false' then s is stored in the set of seen - * scopes. - */ -static bool seen_this_scope_type(ivl_scope_t s) -{ - debug_msg("Seen scope type? %s", ivl_scope_tname(s)); - if (find_if(g_default_scopes.begin(), g_default_scopes.end(), - bind1st(ptr_fun(same_scope_type_name), s)) - == g_default_scopes.end()) { - g_default_scopes.insert(s); - return false; - } - else - return true; -} - -/* - * True if this scope is the default example of this scope type. - * All other instances of this scope type are ignored. - */ -bool is_default_scope_instance(ivl_scope_t s) -{ - return find(g_default_scopes.begin(), g_default_scopes.end(), s) - != g_default_scopes.end(); -} /* * This represents the portion of a nexus that is visible within diff --git a/tgt-vhdl/state.cc b/tgt-vhdl/state.cc new file mode 100644 index 000000000..42c89a22e --- /dev/null +++ b/tgt-vhdl/state.cc @@ -0,0 +1,241 @@ +/* + * Managing global state for the VHDL code generator. + * + * Copyright (C) 2009 Nick Gasson (nick@nickg.me.uk) + * + * This program is free software; you can redistribute it and/or modify + * it 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 Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "state.hh" +#include "vhdl_syntax.hh" + +#include +#include +#include +#include +#include + +using namespace std; + +/* + * This file stores all the global state required during VHDL code + * generation. At present we store the following: + * + * - A mapping from Verilog signals to the VHDL scope (entity, etc.) + * where it is found, and the name of the corresponding VHDL signal. + * This allows us to support renaming invalid Verilog signal names + * to valid VHDL ones. + * + * - The set of all VHDL entities generated. + * + * - The currently active entity. "Active" here means that we are + * currently generating code for a process inside the corresponding + * scope. This is useful, for example, if a statement or expression + * in a process needs to add are referencing something in the containing + * architecture object. + */ + +/* + * Maps a signal to the scope it is defined within. Also + * provides a mechanism for renaming signals -- i.e. when + * an output has the same name as register: valid in Verilog + * but not in VHDL, so two separate signals need to be + * defined. + */ +struct signal_defn_t { + std::string renamed; // The name of the VHDL signal + vhdl_scope *scope; // The scope where it is defined +}; + +// All entities to emit. +// These are stored in a list rather than a set so the first +// entity added will correspond to the first (top) Verilog module +// encountered and hence it will appear first in the output file. +static entity_list_t g_entities; + +typedef std::map signal_defn_map_t; +static signal_defn_map_t g_known_signals; + +static vhdl_entity *g_active_entity = NULL; + +// Set of scopes that are treated as the default examples of +// that type. Any other scopes of the same type are ignored. +typedef set default_scopes_t; +static default_scopes_t g_default_scopes; + + +// True if signal `sig' has already been encountered by the code +// generator. This means we have already assigned it to a VHDL code +// object and possibly renamed it. +bool seen_signal_before(ivl_signal_t sig) +{ + return g_known_signals.find(sig) != g_known_signals.end(); +} + +// Remember the association of signal to a VHDL code object (typically +// an entity). +void remember_signal(ivl_signal_t sig, vhdl_scope *scope) +{ + assert(!seen_signal_before(sig)); + + signal_defn_t defn = { ivl_signal_basename(sig), scope }; + g_known_signals[sig] = defn; +} + +// Change the VHDL name of a Verilog signal. +void rename_signal(ivl_signal_t sig, const std::string &renamed) +{ + assert(seen_signal_before(sig)); + + g_known_signals[sig].renamed = renamed; +} + +// Given a Verilog signal, return the VHDL code object where it should +// be defined. Note that this can return a NULL pointer if `sig' hasn't +// be encountered yet. +vhdl_scope *find_scope_for_signal(ivl_signal_t sig) +{ + if (seen_signal_before(sig)) + return g_known_signals[sig].scope; + else + return NULL; +} + +// Get the name of the VHDL signal corresponding to Verilog signal `sig'. +const std::string &get_renamed_signal(ivl_signal_t sig) +{ + assert(seen_signal_before(sig)); + + return g_known_signals[sig].renamed; +} + +// TODO: Can we dispose of this??? +// -> This is only used in logic.cc to get the type of a signal connected +// to a logic device -> we should be able to get this from the nexus +ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) +{ + signal_defn_map_t::const_iterator it; + for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) { + if (((*it).second.scope == scope + || (*it).second.scope == scope->get_parent()) + && (*it).second.renamed == name) + return (*it).first; + } + assert(false); +} + +// Compare the name of an entity against a string +struct cmp_ent_name { + cmp_ent_name(const string& n) : name_(n) {} + + bool operator()(const vhdl_entity* ent) const + { + return ent->get_name() == name_; + } + + const string& name_; +}; + +// 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 +// for this scope type. +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; +} + +// Add an entity/architecture pair to the list of entities to emit. +void remember_entity(vhdl_entity* ent) +{ + g_entities.push_back(ent); +} + +// Print all VHDL entities, in order, to the specified output stream. +void emit_all_entities(std::ostream& os, int max_depth) +{ + for (entity_list_t::iterator it = g_entities.begin(); + it != g_entities.end(); + ++it) { + if ((max_depth == 0 || (*it)->depth < max_depth)) + (*it)->emit(os); + } +} + +// Release all memory for the VHDL objects. No vhdl_element pointers +// will be valid after this call. +void free_all_vhdl_objects() +{ + for (entity_list_t::iterator it = g_entities.begin(); + it != g_entities.end(); + ++it) + delete (*it); + g_entities.clear(); +} + +// Return the currently active entity +vhdl_entity *get_active_entity() +{ + return g_active_entity; +} + +// Change the currently active entity +void set_active_entity(vhdl_entity *ent) +{ + g_active_entity = ent; +} +/* + * True if two scopes have the same type name. + */ +static bool same_scope_type_name(ivl_scope_t a, ivl_scope_t b) +{ + return strcmp(ivl_scope_tname(a), ivl_scope_tname(b)) == 0; +} + +/* + * True if we have already seen a scope with this type before. + * If the result is `false' then s is stored in the set of seen + * scopes. + */ +bool seen_this_scope_type(ivl_scope_t s) +{ + if (find_if(g_default_scopes.begin(), g_default_scopes.end(), + bind1st(ptr_fun(same_scope_type_name), s)) + == g_default_scopes.end()) { + g_default_scopes.insert(s); + return false; + } + else + return true; +} + +/* + * True if this scope is the default example of this scope type. + * All other instances of this scope type are ignored. + */ +bool is_default_scope_instance(ivl_scope_t s) +{ + return find(g_default_scopes.begin(), g_default_scopes.end(), s) + != g_default_scopes.end(); +} diff --git a/tgt-vhdl/state.hh b/tgt-vhdl/state.hh new file mode 100644 index 000000000..018af5b43 --- /dev/null +++ b/tgt-vhdl/state.hh @@ -0,0 +1,54 @@ +/* + * Managing global state for the VHDL code generator. + * + * Copyright (C) 2009 Nick Gasson (nick@nickg.me.uk) + * + * This program is free software; you can redistribute it and/or modify + * it 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 Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INC_VHDL_STATE_HH +#define INC_VHDL_STATE_HH + +#include "ivl_target.h" + +#include +#include + +class vhdl_scope; +class vhdl_entity; + +// Mapping of Verilog to VHDL signals +bool seen_signal_before(ivl_signal_t sig); +void remember_signal(ivl_signal_t sig, vhdl_scope *scope); +void rename_signal(ivl_signal_t sig, const std::string &renamed); +vhdl_scope *find_scope_for_signal(ivl_signal_t sig); +const std::string &get_renamed_signal(ivl_signal_t sig); +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); +void emit_all_entities(std::ostream& os, int max_depth); +void free_all_vhdl_objects(); + +// Get and set the active entity +vhdl_entity *get_active_entity(); +void set_active_entity(vhdl_entity *ent); + +// Manage mapping of scopes to a single VHDL entity +bool is_default_scope_instance(ivl_scope_t s); +bool seen_this_scope_type(ivl_scope_t s); + +#endif // #ifndef INC_VHDL_STATE_HH diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index c8f69ea41..ad0f1269b 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -19,6 +19,7 @@ */ #include "vhdl_target.h" +#include "state.hh" #include #include diff --git a/tgt-vhdl/support.cc b/tgt-vhdl/support.cc index c0df2a09a..01eb16869 100644 --- a/tgt-vhdl/support.cc +++ b/tgt-vhdl/support.cc @@ -20,6 +20,7 @@ #include "vhdl_target.h" #include "support.hh" +#include "state.hh" #include #include diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index 168a19863..e6ea20786 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -21,6 +21,7 @@ #include "version.h" #include "vhdl_target.h" #include "vhdl_element.hh" +#include "state.hh" #include #include @@ -29,10 +30,6 @@ #include #include #include -#include -#include -#include -#include static const char*version_string = "Icarus Verilog VHDL Code Generator " VERSION " (" VERSION_TAG ")\n\n" @@ -52,24 +49,8 @@ static const char*version_string = " 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n" ; -/* - * Maps a signal to the scope it is defined within. Also - * provides a mechanism for renaming signals -- i.e. when - * an output has the same name as register: valid in Verilog - * but not in VHDL, so two separate signals need to be - * defined. - */ -struct signal_defn_t { - std::string renamed; // The name of the VHDL signal - vhdl_scope *scope; // The scope where it is defined -}; - -typedef std::map signal_defn_map_t; - static int g_errors = 0; // Total number of errors encountered -static entity_list_t g_entities; // All entities to emit -static signal_defn_map_t g_known_signals; static ivl_design_t g_design; @@ -107,98 +88,6 @@ void debug_msg(const char *fmt, ...) va_end(args); } -// Compare the name of an entity against a string -struct cmp_ent_name { - cmp_ent_name(const string& n) : name_(n) {} - - bool operator()(const vhdl_entity* ent) const - { - return ent->get_name() == name_; - } - - const string& name_; -}; - -/* - * Find a VHDL entity given a Verilog module scope. The VHDL entity - * name should be the same the Verilog module type name. - */ -vhdl_entity *find_entity(const ivl_scope_t scope) -{ - debug_msg("find_entity %s", ivl_scope_tname(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; -} - -/* - * Add an entity/architecture pair to the list of entities to emit. - */ -void remember_entity(vhdl_entity* ent) -{ - g_entities.push_back(ent); -} - -bool seen_signal_before(ivl_signal_t sig) -{ - return g_known_signals.find(sig) != g_known_signals.end(); -} - -/* - * Remember the association of signal to entity. - */ -void remember_signal(ivl_signal_t sig, vhdl_scope *scope) -{ - assert(!seen_signal_before(sig)); - - signal_defn_t defn = { ivl_signal_basename(sig), scope }; - g_known_signals[sig] = defn; -} - -/* - * Change the VHDL name of a Verilog signal. - */ -void rename_signal(ivl_signal_t sig, const std::string &renamed) -{ - assert(seen_signal_before(sig)); - - g_known_signals[sig].renamed = renamed; -} - -vhdl_scope *find_scope_for_signal(ivl_signal_t sig) -{ - if (seen_signal_before(sig)) - return g_known_signals[sig].scope; - else - return NULL; -} - -const std::string &get_renamed_signal(ivl_signal_t sig) -{ - assert(seen_signal_before(sig)); - - return g_known_signals[sig].renamed; -} - -ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope) -{ - signal_defn_map_t::const_iterator it; - for (it = g_known_signals.begin(); it != g_known_signals.end(); ++it) { - if (((*it).second.scope == scope - || (*it).second.scope == scope->get_parent()) - && (*it).second.renamed == name) - return (*it).first; - } - assert(false); -} - ivl_design_t get_vhdl_design() { return g_design; @@ -236,28 +125,11 @@ extern "C" int target_design(ivl_design_t des) // (This is handy since it means we can use atoi ;-) int max_depth = std::atoi(ivl_design_flag(des, "depth")); - // Make sure we only emit one example of each type of entity - set seen_entities; - - for (entity_list_t::iterator it = g_entities.begin(); - it != g_entities.end(); - ++it) { - if (seen_entities.find((*it)->get_name()) == seen_entities.end() - && (max_depth == 0 || (*it)->depth < max_depth)) { - (*it)->emit(outfile); - seen_entities.insert((*it)->get_name()); - } - } - - outfile.close(); + emit_all_entities(outfile, max_depth); } // Clean up - for (entity_list_t::iterator it = g_entities.begin(); - it != g_entities.end(); - ++it) - delete (*it); - g_entities.clear(); + free_all_vhdl_objects(); return g_errors; } diff --git a/tgt-vhdl/vhdl_target.h b/tgt-vhdl/vhdl_target.h index 90fd4e31c..636954b4b 100644 --- a/tgt-vhdl/vhdl_target.h +++ b/tgt-vhdl/vhdl_target.h @@ -26,23 +26,9 @@ void draw_logic(vhdl_arch *arch, ivl_net_logic_t log); vhdl_expr *translate_expr(ivl_expr_t e); vhdl_expr *translate_time_expr(ivl_expr_t e); -void remember_entity(vhdl_entity *ent); -vhdl_entity *find_entity(const ivl_scope_t scope); - ivl_design_t get_vhdl_design(); -vhdl_entity *get_active_entity(); -void set_active_entity(vhdl_entity *ent); -bool is_default_scope_instance(ivl_scope_t s); - vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus); -bool seen_signal_before(ivl_signal_t sig); -void remember_signal(ivl_signal_t sig, vhdl_scope *scope); -void rename_signal(ivl_signal_t sig, const string &renamed); -vhdl_scope *find_scope_for_signal(ivl_signal_t sig); -const string &get_renamed_signal(ivl_signal_t sig); -ivl_signal_t find_signal_named(const string &name, const vhdl_scope *scope); - int draw_stask_display(vhdl_procedural *proc, stmt_container *container, ivl_statement_t stmt, bool newline = true); void prune_wait_for_0(stmt_container *container);