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:
parent
752a90dc2f
commit
9448c5939c
136
tgt-vhdl/stmt.cc
136
tgt-vhdl/stmt.cc
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue