Document blocking assignment behaviour
This commit is contained in:
parent
e0f41198d6
commit
be12f56856
|
|
@ -27,31 +27,75 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Explanation here.
|
* 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. This
|
||||||
|
* has exactly the same (external) behaviour as the Verilog
|
||||||
|
* blocking assignment, since no external process will be able
|
||||||
|
* to observe that the assignment wasn't made immediately.
|
||||||
|
*
|
||||||
|
* 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;
|
typedef std::map<std::string, ivl_signal_t> var_temp_set_t;
|
||||||
static var_temp_set_t g_assign_vars;
|
static var_temp_set_t g_assign_vars;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called whenever a blocking assignment is made to sig.
|
||||||
|
*/
|
||||||
void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig)
|
void blocking_assign_to(vhdl_process *proc, ivl_signal_t sig)
|
||||||
{
|
{
|
||||||
std::string var(get_renamed_signal(sig));
|
std::string var(get_renamed_signal(sig));
|
||||||
|
std::string tmpname(var + "_Var");
|
||||||
std::cout << "blocking_assign_to " << var << std::endl;
|
|
||||||
|
|
||||||
if (g_assign_vars.find(var) == g_assign_vars.end()) {
|
if (g_assign_vars.find(var) == g_assign_vars.end()) {
|
||||||
// This is the first time a non-blocking assignment
|
// This is the first time a non-blocking assignment
|
||||||
// has been made to this signal: create a variable
|
// has been made to this signal: create a variable
|
||||||
// to shadow it.
|
// to shadow it.
|
||||||
|
if (!proc->have_declared_var(tmpname)) {
|
||||||
vhdl_decl *decl = proc->get_parent()->get_decl(var);
|
vhdl_decl *decl = proc->get_parent()->get_decl(var);
|
||||||
assert(decl);
|
assert(decl);
|
||||||
vhdl_type *type = new vhdl_type(*decl->get_type());
|
vhdl_type *type = new vhdl_type(*decl->get_type());
|
||||||
|
|
||||||
var += "_Var";
|
proc->add_decl(new vhdl_var_decl(tmpname.c_str(), type));
|
||||||
proc->add_decl(new vhdl_var_decl(var.c_str(), type));
|
}
|
||||||
|
|
||||||
rename_signal(sig, var);
|
rename_signal(sig, tmpname);
|
||||||
g_assign_vars[var] = sig;
|
g_assign_vars[tmpname] = sig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue