Always user Ternary_* support functions for ternary assignments

Previously the code generator expanded ternary assignments to
and `if' statement. This patch replaces that with a single assignment
and a call to a Ternary_* support function. This will make it
much easier to support multiple lvals later.
This commit is contained in:
Nick Gasson 2008-08-02 15:46:36 +01:00
parent 752a90dc2f
commit 9448c5939c
2 changed files with 56 additions and 90 deletions

View File

@ -186,97 +186,59 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
unsigned lval_width = ivl_lval_width(lval);
ivl_expr_t rval = ivl_stmt_rval(stmt);
if (ivl_expr_type(rval) == IVL_EX_TERNARY) {
// Expand ternary expressions into an if statement
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
vhdl_expr *true_part =
make_assign_rhs(sig, proc->get_scope(),
ivl_expr_oper2(rval), base, lval_width);
vhdl_expr *false_part =
make_assign_rhs(sig, proc->get_scope(),
ivl_expr_oper3(rval), base, lval_width);
if (!test || !true_part || !false_part)
return NULL;
vhdl_if_stmt *vhdif = new vhdl_if_stmt(test);
// True part
{
vhdl_var_ref *lval_ref =
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
T *a = new T(lval_ref, true_part);
vhdif->get_then_container()->add_stmt(a);
}
// False part
{
vhdl_var_ref *lval_ref =
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
T *a = new T(lval_ref, false_part);
vhdif->get_else_container()->add_stmt(a);
}
container->add_stmt(vhdif);
vhdl_expr *rhs =
make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width);
if (NULL == rhs)
return NULL;
}
else {
vhdl_expr *rhs =
make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width);
if (NULL == rhs)
string signame(get_renamed_signal(sig));
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
// Where possible, move constant assignments into the
// declaration as initializers. This optimisation is only
// performed on assignments of constant values to prevent
// ordering problems.
// This also has another application: If this is an `inital'
// process and we haven't yet generated a `wait' statement then
// moving the assignment to the initialization preserves the
// expected Verilog behaviour: VHDL does not distinguish
// `initial' and `always' processes so an `always' process might
// be activatated before an `initial' process at time 0. The
// `always' process may then use the uninitialized signal value.
// The second test ensures that we only try to initialise
// internal signals not ports
if (proc->get_scope()->initializing()
&& ivl_signal_port(sig) == IVL_SIP_NONE
&& !decl->has_initial()
&& rhs->constant()
&& decl->get_type()->get_name() != VHDL_TYPE_ARRAY) {
// If this assignment is not in the top-level container
// it will not be made on all paths through the code
// This precludes any future extraction of an initialiser
if (container != proc->get_container())
decl->set_initial(NULL); // Default initial value
else {
decl->set_initial(rhs);
return NULL;
string signame(get_renamed_signal(sig));
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
// Where possible, move constant assignments into the
// declaration as initializers. This optimisation is only
// performed on assignments of constant values to prevent
// ordering problems.
// This also has another application: If this is an `inital'
// process and we haven't yet generated a `wait' statement then
// moving the assignment to the initialization preserves the
// expected Verilog behaviour: VHDL does not distinguish
// `initial' and `always' processes so an `always' process might
// be activatated before an `initial' process at time 0. The
// `always' process may then use the uninitialized signal value.
// The second test ensures that we only try to initialise
// internal signals not ports
if (proc->get_scope()->initializing()
&& ivl_signal_port(sig) == IVL_SIP_NONE
&& !decl->has_initial()
&& rhs->constant()
&& decl->get_type()->get_name() != VHDL_TYPE_ARRAY) {
// If this assignment is not in the top-level container
// it will not be made on all paths through the code
// This precludes any future extraction of an initialiser
if (container != proc->get_container())
decl->set_initial(NULL); // Default initial value
else {
decl->set_initial(rhs);
return NULL;
}
}
vhdl_var_ref *lval_ref =
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
T *a = new T(lval_ref, rhs);
container->add_stmt(a);
ivl_expr_t i_delay;
if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt)))
after = translate_time_expr(i_delay);
if (after != NULL)
a->set_after(after);
return a;
}
vhdl_var_ref *lval_ref =
make_assign_lhs(sig, proc->get_scope(), base, lval_width);
T *a = new T(lval_ref, rhs);
container->add_stmt(a);
ivl_expr_t i_delay;
if (NULL == after && (i_delay = ivl_stmt_delay_expr(stmt)))
after = translate_time_expr(i_delay);
if (after != NULL)
a->set_after(after);
return a;
}
else {
error("Only signals as lvals supported at the moment");

View File

@ -61,6 +61,10 @@ vhdl_type *support_function::function_type(support_function_t type)
case SF_REDUCE_XOR:
case SF_TERNARY_LOGIC:
return vhdl_type::std_logic();
case SF_TERNARY_SIGNED:
return new vhdl_type(VHDL_TYPE_SIGNED);
case SF_TERNARY_UNSIGNED:
return new vhdl_type(VHDL_TYPE_UNSIGNED);
case SF_LOGIC_TO_INTEGER:
return vhdl_type::integer();
default:
@ -76,7 +80,7 @@ void support_function::emit_ternary(std::ostream &of, int level) const
void support_function::emit(std::ostream &of, int level) const
{
of << "function " << function_name(type_);
of << nl_string(level) << "function " << function_name(type_);
switch (type_) {
case SF_UNSIGNED_TO_BOOLEAN:
@ -137,7 +141,7 @@ void support_function::emit(std::ostream &of, int level) const
emit_ternary(of, level);
break;
case SF_TERNARY_UNSIGNED:
of << "(T : Boolean; X, Y : signed) return unsigned is";
of << "(T : Boolean; X, Y : unsigned) return unsigned is";
emit_ternary(of, level);
break;
case SF_LOGIC_TO_INTEGER:
@ -149,5 +153,5 @@ void support_function::emit(std::ostream &of, int level) const
assert(false);
}
of << nl_string(level) << "end function;" << nl_string(level);
of << nl_string(level) << "end function;";
}