Draw nexus in multiple passes

This commit is contained in:
Nick Gasson 2008-07-29 12:00:26 +01:00
parent 65c2ceb89d
commit 8a5f129e56
5 changed files with 147 additions and 25 deletions

View File

@ -59,7 +59,7 @@ enum vhdl_nexus_obj_t {
* If a vhdl_var_ref is returned, the reference is guaranteed to be
* to a signal in arch_scope or its parent (the entity's ports).
*/
static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus,
/*static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus,
int allowed = NEXUS_TO_ANY)
{
int nptrs = ivl_nexus_ptrs(nexus);
@ -112,17 +112,132 @@ static vhdl_expr *nexus_to_expr(vhdl_scope *arch_scope, ivl_nexus_t nexus,
}
return NULL;
}
}*/
/*
* Guarantees the result will never be NULL.
*/
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus)
/*vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus)
{
return dynamic_cast<vhdl_var_ref*>
(nexus_to_expr(arch_scope, nexus, NEXUS_TO_VAR_REF));
}*/
/*
* This structure is stored in the private part of each nexus.
* It stores a signal for each VHDL scope which is connected to
* that nexus. It's stored as a list so we can use contained_within
* to allow several nested scopes to reference the same signal.
*/
struct nexus_private_t {
struct scope_signal_map_t {
vhdl_scope *scope;
ivl_signal_t sig;
};
list<scope_signal_map_t> signals;
};
/*
* Remember that sig is the representative of this nexus in scope.
*/
static void link_scope_to_nexus_signal(nexus_private_t *priv, vhdl_scope *scope,
ivl_signal_t sig)
{
nexus_private_t::scope_signal_map_t sigmap = { scope, sig };
priv->signals.push_back(sigmap);
}
/*
* Find a signal that is connected to this nexus that is visible
* in this scope.
*/
static ivl_signal_t visible_nexus_signal(nexus_private_t *priv, vhdl_scope *scope)
{
list<nexus_private_t::scope_signal_map_t>::iterator it;
for (it = priv->signals.begin(); it != priv->signals.end(); ++it) {
if (scope->contained_within((*it).scope))
return (*it).sig;
}
return NULL;
}
/*
* Generates VHDL code to fully represent a nexus.
*/
void draw_nexus(ivl_nexus_t nexus)
{
nexus_private_t *priv = new nexus_private_t;
int nptrs = ivl_nexus_ptrs(nexus);
// First pass through connect all the signals up
for (int i = 0; i < nptrs; i++) {
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
ivl_signal_t sig;
if ((sig = ivl_nexus_ptr_sig(nexus_ptr))) {
cout << "signal " << ivl_signal_basename(sig) << endl;
vhdl_scope *scope = find_scope_for_signal(sig);
ivl_signal_t linked;
if ((linked = visible_nexus_signal(priv, scope))) {
cout << "...should be linked to " << ivl_signal_name(linked) << endl;
assert(false);
}
else {
cout << "...represents this nexus in scope " << hex << scope << endl;
link_scope_to_nexus_signal(priv, scope, sig);
}
}
}
// Second pass through make sure logic/LPMs have signal
// inputs and outputs
for (int i = 0; i < nptrs; i++) {
ivl_nexus_ptr_t nexus_ptr = ivl_nexus_ptr(nexus, i);
ivl_net_logic_t log;
ivl_lpm_t lpm;
ivl_net_const_t con;
if ((log = ivl_nexus_ptr_log(nexus_ptr))) {
/*
ivl_signal_t linked;
if ((linked = visible_nexus_signal(*/
}
else if ((lpm = ivl_nexus_ptr_lpm(nexus_ptr))) {
assert(false);
}
}
// Save the private data in the nexus
ivl_nexus_set_private(nexus, priv);
}
/*
* Translate a nexus to a variable reference. Given a nexus and a
* scope, this function returns a reference to a signal that is
* connected to the nexus and within the given scope. This signal
* might not exist in the original Verilog source (even as a
* compiler-generated temporary). If this nexus hasn't been
* encountered before, the necessary code to connect up the nexus
* will be generated.
*/
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *scope, ivl_nexus_t nexus)
{
cout << "nexus_to_var_ref " << ivl_nexus_name(nexus) << endl;
if (ivl_nexus_get_private(nexus) == NULL) {
cout << "first time we've seen this nexus" << endl;
draw_nexus(nexus);
}
assert(false);
}
/*
* Convert the inputs of a logic gate to a binary expression.
*/
@ -137,7 +252,7 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
int npins = ivl_logic_pins(log);
for (int i = 1; i < npins; i++) {
ivl_nexus_t input = ivl_logic_pin(log, i);
gate->add_expr(nexus_to_expr(scope, input));
gate->add_expr(nexus_to_var_ref(scope, input));
}
return gate;
@ -152,7 +267,7 @@ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
ivl_nexus_t input = ivl_logic_pin(log, 1);
assert(input);
vhdl_expr *operand = nexus_to_expr(scope, input);
vhdl_expr *operand = nexus_to_var_ref(scope, input);
return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}
@ -162,10 +277,10 @@ static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
assert(lhs);
vhdl_expr *val = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 1));
vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
assert(val);
vhdl_expr *sel = nexus_to_expr(arch->get_scope(), ivl_logic_pin(log, 2));
vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
assert(val);
vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
@ -205,7 +320,7 @@ static vhdl_expr *translate_logic(vhdl_scope *scope, ivl_net_logic_t log)
return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
case IVL_LO_BUF:
case IVL_LO_BUFZ:
return nexus_to_expr(scope, ivl_logic_pin(log, 1));
return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
case IVL_LO_PULLUP:
return new vhdl_const_bit('1');
case IVL_LO_PULLDOWN:
@ -238,10 +353,7 @@ static void declare_logic(vhdl_arch *arch, ivl_scope_t scope)
{
// The output is always pin zero
ivl_nexus_t output = ivl_logic_pin(log, 0);
vhdl_var_ref *lhs =
dynamic_cast<vhdl_var_ref*>(nexus_to_expr(arch->get_scope(), output));
if (NULL == lhs)
continue; // Not suitable for continuous assignment
vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
vhdl_expr *rhs = translate_logic(arch->get_scope(), log);
vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);
@ -331,11 +443,10 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
// A local signal can have a constant initializer in VHDL
// This may be found in the signal's nexus
// TODO: Make this work for multiple words
vhdl_expr *init =
nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0),
NEXUS_TO_CONST);
/*vhdl_expr *init =
nexus_to_var_ref(ent->get_scope(), ivl_signal_nex(sig, 0));
if (init != NULL)
decl->set_initial(init);
decl->set_initial(init);*/
ent->get_arch()->get_scope()->add_decl(decl);
}
@ -352,13 +463,13 @@ static void declare_signals(vhdl_entity *ent, ivl_scope_t scope)
// Check for constant values
// For outputs these must be continuous assigns of
// the constant to the port
vhdl_expr *init =
/*vhdl_expr *init =
nexus_to_expr(ent->get_scope(), ivl_signal_nex(sig, 0),
NEXUS_TO_CONST);
if (init != NULL) {
vhdl_var_ref *ref = new vhdl_var_ref(name.c_str(), NULL);
ent->get_arch()->add_stmt(new vhdl_cassign_stmt(ref, init));
}
}*/
ent->get_scope()->add_decl(decl);
}
@ -418,8 +529,8 @@ static void map_signal(ivl_signal_t to, vhdl_entity *parent,
// TODO: Work for multiple words
ivl_nexus_t nexus = ivl_signal_nex(to, 0);
vhdl_expr *to_e = nexus_to_expr(parent->get_arch()->get_scope(),
nexus, NEXUS_TO_ANY);
vhdl_expr *to_e = nexus_to_var_ref(parent->get_arch()->get_scope(),
nexus);
assert(to_e);
// The expressions in a VHDL port map must be 'globally static'

View File

@ -39,7 +39,7 @@
*/
struct signal_defn_t {
std::string renamed; // The name of the VHDL signal
const vhdl_scope *scope; // The scope where it is defined
vhdl_scope *scope; // The scope where it is defined
};
typedef std::map<ivl_signal_t, signal_defn_t> signal_defn_map_t;
@ -98,7 +98,7 @@ bool seen_signal_before(ivl_signal_t sig)
/*
* Remeber the association of signal to entity.
*/
void remember_signal(ivl_signal_t sig, const vhdl_scope *scope)
void remember_signal(ivl_signal_t sig, vhdl_scope *scope)
{
assert(!seen_signal_before(sig));
@ -116,7 +116,7 @@ void rename_signal(ivl_signal_t sig, const std::string &renamed)
g_known_signals[sig].renamed = renamed;
}
const vhdl_scope *find_scope_for_signal(ivl_signal_t sig)
vhdl_scope *find_scope_for_signal(ivl_signal_t sig)
{
assert(seen_signal_before(sig));

View File

@ -64,6 +64,16 @@ bool vhdl_scope::have_declared(const std::string &name) const
return get_decl(name) != NULL;
}
bool vhdl_scope::contained_within(const vhdl_scope *other) const
{
if (this == other)
return true;
else if (NULL == parent_)
return false;
else
return parent_->contained_within(other);
}
vhdl_scope *vhdl_scope::get_parent() const
{
assert(parent_);

View File

@ -608,6 +608,7 @@ public:
void add_decl(vhdl_decl *decl);
vhdl_decl *get_decl(const std::string &name) const;
bool have_declared(const std::string &name) const;
bool contained_within(const vhdl_scope *other) const;
vhdl_scope *get_parent() const;
bool empty() const { return decls_.empty(); }

View File

@ -35,9 +35,9 @@ void set_active_entity(vhdl_entity *ent);
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, const vhdl_scope *scope);
void remember_signal(ivl_signal_t sig, vhdl_scope *scope);
void rename_signal(ivl_signal_t sig, const string &renamed);
const vhdl_scope *find_scope_for_signal(ivl_signal_t sig);
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);