Tidy up blocking assignment code
This commit is contained in:
parent
d1e7e325b7
commit
0b48f69b4e
|
|
@ -58,7 +58,7 @@ static vhdl_var_ref *translate_signal(ivl_expr_t e)
|
|||
|
||||
const char *renamed = get_renamed_signal(sig).c_str();
|
||||
|
||||
const vhdl_decl *decl = scope->get_decl(strip_var(renamed));
|
||||
const vhdl_decl *decl = scope->get_decl(renamed);
|
||||
assert(decl);
|
||||
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
|
|
|||
|
|
@ -24,120 +24,6 @@
|
|||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
/*
|
||||
* Implementing blocking assignment is a little tricky since
|
||||
* the semantics are a little different to VHDL:
|
||||
*
|
||||
* In Verilog a blocking assignment (=) can be used anywhere
|
||||
* non-blocking assignment (<=) can be. In VHDL blocking
|
||||
* assignment (:=) can only be used with variables, and
|
||||
* non-blocking assignment (<=) can only be used with signals.
|
||||
* All Verilog variables are translated into signals in the
|
||||
* VHDL architecture. This means we cannot use the VHDL :=
|
||||
* operator directly. Furthermore, VHDL variables can only
|
||||
* be declared within processes, so it wouldn't help to
|
||||
* make all Verilog variables VHDL variables.
|
||||
*
|
||||
* The solution is to generate a VHDL variable in a process
|
||||
* whenever a blocking assignment is made to a signal. The
|
||||
* assignment is made to this variable instead, and
|
||||
* g_assign_vars below remembers the temporary variables
|
||||
* that have been generated. Any subsequent blocking assignments
|
||||
* are made to the same variable. At either the end of the
|
||||
* process or a `wait' statement, the temporaries are assigned
|
||||
* back to the signals, and the temporaries are forgotten.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* initial begin
|
||||
* a = 5;
|
||||
* b = a + 3;
|
||||
* end
|
||||
*
|
||||
* Is translated to:
|
||||
*
|
||||
* process is
|
||||
* variable a_Var : Some_Type;
|
||||
* variable b_Var : Some_Type;
|
||||
* begin
|
||||
* a_Var := 5;
|
||||
* b_Var := a_Var + 3;
|
||||
* a <= a_Var;
|
||||
* b <= b_Var;
|
||||
* end process;
|
||||
*/
|
||||
typedef std::map<std::string, ivl_signal_t> var_temp_set_t;
|
||||
static var_temp_set_t g_assign_vars;
|
||||
|
||||
/*
|
||||
* Called whenever a blocking assignment is made to sig.
|
||||
*/
|
||||
void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig)
|
||||
{
|
||||
std::string var(get_renamed_signal(sig));
|
||||
std::string tmpname(var + "_Var");
|
||||
|
||||
if (g_assign_vars.find(var) == g_assign_vars.end()) {
|
||||
// This is the first time a non-blocking assignment
|
||||
// has been made to this signal: create a variable
|
||||
// to shadow it.
|
||||
if (!proc->get_scope()->have_declared(tmpname)) {
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(var);
|
||||
assert(decl);
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
||||
proc->get_scope()->add_decl(new vhdl_var_decl(tmpname.c_str(), type));
|
||||
}
|
||||
|
||||
rename_signal(sig, tmpname);
|
||||
g_assign_vars[tmpname] = sig;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign all _Var variables to the corresponding signals. This makes
|
||||
* the new values visible outside the current process. This should be
|
||||
* called before any `wait' statement or the end of the process.
|
||||
*/
|
||||
void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container)
|
||||
{
|
||||
var_temp_set_t::const_iterator it;
|
||||
for (it = g_assign_vars.begin(); it != g_assign_vars.end(); ++it) {
|
||||
std::string stripped(strip_var((*it).first));
|
||||
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(stripped);
|
||||
assert(decl);
|
||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||
|
||||
vhdl_var_ref *lhs = new vhdl_var_ref(stripped.c_str(), NULL);
|
||||
vhdl_expr *rhs = new vhdl_var_ref((*it).first.c_str(), type);
|
||||
|
||||
container->add_stmt(new vhdl_nbassign_stmt(lhs, rhs));
|
||||
|
||||
// Undo the renaming (since the temporary is no longer needed)
|
||||
rename_signal((*it).second, stripped);
|
||||
}
|
||||
|
||||
// If this this wait is within e.g. an `if' statement then
|
||||
// we cannot correctly clear the variables list here (since
|
||||
// they might not be assigned on another path)
|
||||
if (container == proc->get_container())
|
||||
g_assign_vars.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove _Var from the end of a string, if it is present.
|
||||
*/
|
||||
std::string strip_var(const std::string &str)
|
||||
{
|
||||
std::string result(str);
|
||||
size_t pos = result.find("_Var");
|
||||
if (pos != std::string::npos)
|
||||
result.erase(pos, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a Verilog process to VHDL and add it to the architecture
|
||||
|
|
@ -162,10 +48,6 @@ static int generate_vhdl_process(vhdl_entity *ent, ivl_process_t proc)
|
|||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
// Output any remaning blocking assignments
|
||||
draw_blocking_assigns(vhdl_proc, vhdl_proc->get_container());
|
||||
g_assign_vars.clear();
|
||||
|
||||
// Initial processes are translated to VHDL processes with
|
||||
// no sensitivity list and and indefinite wait statement at
|
||||
// the end
|
||||
|
|
|
|||
|
|
@ -102,9 +102,9 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope,
|
||||
ivl_expr_t e, vhdl_expr *base,
|
||||
int lval_width)
|
||||
static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope,
|
||||
ivl_expr_t e, vhdl_expr *base,
|
||||
int lval_width)
|
||||
{
|
||||
string signame(get_renamed_signal(sig));
|
||||
|
||||
|
|
@ -182,11 +182,11 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
// Expand ternary expressions into an if statement
|
||||
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
|
||||
vhdl_expr *true_part =
|
||||
translate_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper2(rval), base, lval_width);
|
||||
make_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper2(rval), base, lval_width);
|
||||
vhdl_expr *false_part =
|
||||
translate_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper3(rval), base, lval_width);
|
||||
make_assign_rhs(sig, proc->get_scope(),
|
||||
ivl_expr_oper3(rval), base, lval_width);
|
||||
|
||||
if (!test || !true_part || !false_part)
|
||||
return NULL;
|
||||
|
|
@ -216,11 +216,11 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
|||
}
|
||||
else {
|
||||
vhdl_expr *rhs =
|
||||
translate_assign_rhs(sig, proc->get_scope(), rval, base, lval_width);
|
||||
make_assign_rhs(sig, proc->get_scope(), rval, base, lval_width);
|
||||
if (NULL == rhs)
|
||||
return NULL;
|
||||
|
||||
std::string signame(get_renamed_signal(sig));
|
||||
string signame(get_renamed_signal(sig));
|
||||
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
|
||||
|
||||
// Where possible, move constant assignments into the
|
||||
|
|
@ -349,11 +349,7 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
|||
if (type == IVL_ST_ASSIGN_NB) {
|
||||
draw_nbassign(proc, container, sub_stmt, time);
|
||||
}
|
||||
else {
|
||||
// All blocking assignments need to be made visible
|
||||
// at this point
|
||||
draw_blocking_assigns(proc, container);
|
||||
|
||||
else {
|
||||
vhdl_wait_stmt *wait =
|
||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||
container->add_stmt(wait);
|
||||
|
|
|
|||
|
|
@ -23,23 +23,19 @@ vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm);
|
|||
vhdl_expr *translate_expr(ivl_expr_t e);
|
||||
|
||||
void remember_entity(vhdl_entity *ent);
|
||||
vhdl_entity *find_entity(const std::string &tname);
|
||||
vhdl_entity *find_entity(const string &tname);
|
||||
|
||||
ivl_design_t get_vhdl_design();
|
||||
vhdl_entity *get_active_entity();
|
||||
//vhdl_entity *get_active_entity();
|
||||
|
||||
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 rename_signal(ivl_signal_t sig, const std::string &renamed);
|
||||
void rename_signal(ivl_signal_t sig, const string &renamed);
|
||||
const 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);
|
||||
|
||||
void blocking_assign_to(vhdl_procedural *proc, ivl_signal_t sig);
|
||||
std::string strip_var(const std::string &str);
|
||||
void draw_blocking_assigns(vhdl_procedural *proc, stmt_container *container);
|
||||
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue