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 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);
|
assert(decl);
|
||||||
|
|
||||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||||
|
|
|
||||||
|
|
@ -24,120 +24,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <sstream>
|
#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
|
* 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)
|
if (rc != 0)
|
||||||
return rc;
|
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
|
// Initial processes are translated to VHDL processes with
|
||||||
// no sensitivity list and and indefinite wait statement at
|
// no sensitivity list and and indefinite wait statement at
|
||||||
// the end
|
// the end
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ static int draw_noop(vhdl_procedural *proc, stmt_container *container,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static vhdl_expr *translate_assign_rhs(ivl_signal_t sig, vhdl_scope *scope,
|
static vhdl_expr *make_assign_rhs(ivl_signal_t sig, vhdl_scope *scope,
|
||||||
ivl_expr_t e, vhdl_expr *base,
|
ivl_expr_t e, vhdl_expr *base,
|
||||||
int lval_width)
|
int lval_width)
|
||||||
{
|
{
|
||||||
|
|
@ -182,10 +182,10 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
// Expand ternary expressions into an if statement
|
// Expand ternary expressions into an if statement
|
||||||
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
|
vhdl_expr *test = translate_expr(ivl_expr_oper1(rval));
|
||||||
vhdl_expr *true_part =
|
vhdl_expr *true_part =
|
||||||
translate_assign_rhs(sig, proc->get_scope(),
|
make_assign_rhs(sig, proc->get_scope(),
|
||||||
ivl_expr_oper2(rval), base, lval_width);
|
ivl_expr_oper2(rval), base, lval_width);
|
||||||
vhdl_expr *false_part =
|
vhdl_expr *false_part =
|
||||||
translate_assign_rhs(sig, proc->get_scope(),
|
make_assign_rhs(sig, proc->get_scope(),
|
||||||
ivl_expr_oper3(rval), base, lval_width);
|
ivl_expr_oper3(rval), base, lval_width);
|
||||||
|
|
||||||
if (!test || !true_part || !false_part)
|
if (!test || !true_part || !false_part)
|
||||||
|
|
@ -216,11 +216,11 @@ static T *make_assignment(vhdl_procedural *proc, stmt_container *container,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
vhdl_expr *rhs =
|
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)
|
if (NULL == rhs)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
std::string signame(get_renamed_signal(sig));
|
string signame(get_renamed_signal(sig));
|
||||||
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
|
vhdl_decl *decl = proc->get_scope()->get_decl(signame);
|
||||||
|
|
||||||
// Where possible, move constant assignments into the
|
// Where possible, move constant assignments into the
|
||||||
|
|
@ -350,10 +350,6 @@ static int draw_delay(vhdl_procedural *proc, stmt_container *container,
|
||||||
draw_nbassign(proc, container, sub_stmt, time);
|
draw_nbassign(proc, container, sub_stmt, time);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// All blocking assignments need to be made visible
|
|
||||||
// at this point
|
|
||||||
draw_blocking_assigns(proc, container);
|
|
||||||
|
|
||||||
vhdl_wait_stmt *wait =
|
vhdl_wait_stmt *wait =
|
||||||
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
new vhdl_wait_stmt(VHDL_WAIT_FOR, time);
|
||||||
container->add_stmt(wait);
|
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);
|
vhdl_expr *translate_expr(ivl_expr_t e);
|
||||||
|
|
||||||
void remember_entity(vhdl_entity *ent);
|
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();
|
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);
|
vhdl_var_ref *nexus_to_var_ref(vhdl_scope *arch_scope, ivl_nexus_t nexus);
|
||||||
|
|
||||||
bool seen_signal_before(ivl_signal_t sig);
|
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, 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 vhdl_scope *find_scope_for_signal(ivl_signal_t sig);
|
||||||
const std::string &get_renamed_signal(ivl_signal_t sig);
|
const string &get_renamed_signal(ivl_signal_t sig);
|
||||||
ivl_signal_t find_signal_named(const std::string &name, const vhdl_scope *scope);
|
ivl_signal_t find_signal_named(const 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);
|
|
||||||
|
|
||||||
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
int draw_stask_display(vhdl_procedural *proc, stmt_container *container,
|
||||||
ivl_statement_t stmt, bool newline = true);
|
ivl_statement_t stmt, bool newline = true);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue