Rework VHDL assignment statement generation

This changes the assignment statement generator so that
each VHDL declaration "knows" which type of assignment
statement can/should be used on (i.e. signals must be
assigned with <=). This will help us catch cases when
we try to use, for example, := with signals. This occurs
in pr2362211 where we try to assign to a signal within
a function (where only := can be used).
This commit is contained in:
Nick Gasson 2008-12-07 17:08:29 +00:00 committed by Stephen Williams
parent c06c49c992
commit d689c93879
2 changed files with 54 additions and 12 deletions

View File

@ -162,10 +162,26 @@ static bool assignment_lvals(ivl_statement_t stmt, vhdl_procedural *proc,
return true;
}
/*
* Generate the right sort of assignment statement for assigning
* `lhs' to `rhs'.
*/
static vhdl_abstract_assign_stmt *
assign_for(vhdl_decl::assign_type_t atype, vhdl_var_ref *lhs, vhdl_expr *rhs)
{
switch (atype) {
case vhdl_decl::ASSIGN_BLOCK:
return new vhdl_assign_stmt(lhs, rhs);
case vhdl_decl::ASSIGN_NONBLOCK:
return new vhdl_nbassign_stmt(lhs, rhs);
default:
assert(false);
}
}
/*
* Generate an assignment of type T for the Verilog statement stmt.
*/
template <class T>
void make_assignment(vhdl_procedural *proc, stmt_container *container,
ivl_statement_t stmt, bool blocking)
{
@ -192,6 +208,11 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
vhdl_expr *after = NULL;
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
// Find the declaration of the LHS so we know what type
// of assignment statement to generate (is it a signal,
// a variable, etc?)
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
// A small optimisation is to expand ternary RHSs into an
// if statement (eliminates a function call and produces
@ -209,7 +230,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
// True part
{
T *a = new T(lhs, rhs);
vhdl_abstract_assign_stmt *a =
assign_for(decl->assignment_type(), lhs, rhs);
if (after)
a->set_after(after);
vhdif->get_then_container()->add_stmt(a);
@ -217,7 +239,8 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
// False part
{
T *a = new T(lhs2, rhs2);
vhdl_abstract_assign_stmt *a =
assign_for(decl->assignment_type(), lhs2, rhs2);
if (after)
a->set_after(translate_time_expr(i_delay));
vhdif->get_else_container()->add_stmt(a);
@ -242,7 +265,6 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
// The second test ensures that we only try to initialise
// internal signals not ports
ivl_lval_t lval = ivl_stmt_lval(stmt, 0);
vhdl_decl *decl = proc->get_scope()->get_decl(lhs->get_name());
if (proc->get_scope()->initializing()
&& ivl_signal_port(ivl_lval_sig(lval)) == IVL_SIP_NONE
&& !decl->has_initial()
@ -260,8 +282,9 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
return;
}
}
T *a = new T(lhs, rhs);
vhdl_abstract_assign_stmt *a =
assign_for(decl->assignment_type(), lhs, rhs);
container->add_stmt(a);
if (after != NULL)
@ -276,7 +299,7 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
ostringstream ss;
ss << "Verilog_Assign_Tmp_" << tmp_count++;
string tmpname = ss.str();
proc->get_scope()->add_decl
(new vhdl_var_decl(tmpname.c_str(), new vhdl_type(*rhs->get_type())));
@ -299,7 +322,13 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container,
if ((i_delay = ivl_stmt_delay_expr(stmt)) != NULL)
after = translate_time_expr(i_delay);
T *a = new T(*it, tmp_rhs);
// Find the declaration of the LHS so we know what type
// of assignment statement to generate (is it a signal,
// a variable, etc?)
vhdl_decl *decl = proc->get_scope()->get_decl((*it)->get_name());
vhdl_abstract_assign_stmt *a =
assign_for(decl->assignment_type(), *it, tmp_rhs);
if (after)
a->set_after(after);
@ -320,7 +349,7 @@ static int draw_nbassign(vhdl_procedural *proc, stmt_container *container,
{
assert(proc->get_scope()->allow_signal_assignment());
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
make_assignment(proc, container, stmt, false);
return 0;
}
@ -333,7 +362,7 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container,
// followed by a zero-time wait
// This follows the Verilog semantics fairly closely.
make_assignment<vhdl_nbassign_stmt>(proc, container, stmt, false);
make_assignment(proc, container, stmt, false);
// Don't generate a zero-wait if this is the last statement in
// the process
@ -342,7 +371,7 @@ static int draw_assign(vhdl_procedural *proc, stmt_container *container,
(new vhdl_wait_stmt(VHDL_WAIT_FOR, new vhdl_const_time(0)));
}
else
make_assignment<vhdl_assign_stmt>(proc, container, stmt, true);
make_assignment(proc, container, stmt, true);
return 0;
}

View File

@ -22,6 +22,7 @@
#define INC_VHDL_SYNTAX_HH
#include <inttypes.h>
#include <cassert>
#include "vhdl_element.hh"
#include "vhdl_type.hh"
@ -542,6 +543,16 @@ public:
void set_type(vhdl_type *t) { type_ = t; }
void set_initial(vhdl_expr *initial);
bool has_initial() const { return has_initial_; }
// The different sorts of assignment statement
enum assign_type_t { ASSIGN_BLOCK, ASSIGN_NONBLOCK };
// Get the sort of assignment statement to generate for
// assignemnts to this declaration
// For some sorts of declarations it doesn't make sense
// to assign to it so calling assignment_type just raises
// an assertion failure
virtual assign_type_t assignment_type() const { assert(false); }
protected:
std::string name_;
vhdl_type *type_;
@ -577,7 +588,6 @@ public:
void emit(std::ostream &of, int level) const;
};
/*
* A variable declaration inside a process (although this isn't
* enforced here).
@ -587,6 +597,7 @@ public:
vhdl_var_decl(const char *name, vhdl_type *type)
: vhdl_decl(name, type) {}
void emit(std::ostream &of, int level) const;
assign_type_t assignment_type() const { return ASSIGN_BLOCK; }
};
@ -598,6 +609,7 @@ public:
vhdl_signal_decl(const char *name, vhdl_type *type)
: vhdl_decl(name, type) {}
virtual void emit(std::ostream &of, int level) const;
assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; }
};
@ -632,6 +644,7 @@ public:
void emit(std::ostream &of, int level) const;
vhdl_port_mode_t get_mode() const { return mode_; }
void set_mode(vhdl_port_mode_t m) { mode_ = m; }
assign_type_t assignment_type() const { return ASSIGN_NONBLOCK; }
private:
vhdl_port_mode_t mode_;
};