Document blocking assignment behaviour

This commit is contained in:
Nick Gasson 2008-06-18 14:04:16 +01:00
parent e0f41198d6
commit be12f56856
1 changed files with 58 additions and 14 deletions

View File

@ -27,31 +27,75 @@
#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;
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)
{
std::string var(get_renamed_signal(sig));
std::cout << "blocking_assign_to " << var << std::endl;
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->have_declared_var(tmpname)) {
vhdl_decl *decl = proc->get_parent()->get_decl(var);
assert(decl);
vhdl_type *type = new vhdl_type(*decl->get_type());
vhdl_decl *decl = proc->get_parent()->get_decl(var);
assert(decl);
vhdl_type *type = new vhdl_type(*decl->get_type());
proc->add_decl(new vhdl_var_decl(tmpname.c_str(), type));
}
var += "_Var";
proc->add_decl(new vhdl_var_decl(var.c_str(), type));
rename_signal(sig, var);
g_assign_vars[var] = sig;
rename_signal(sig, tmpname);
g_assign_vars[tmpname] = sig;
}
}