vlog95: Emit initial blocks for tasks or functions.

In SystemVerilog a task or function can initialize a variable in a task or
function. In Icarus this is done by creating an initial block that does
the assignment. We can translate this by emitting the initial block in the
enclosing module scope. This is not 100% correct since SystemVerilog
requires the initialization to be done before the other initial/always
blocks are processed. For SystemVerilog the current Icarus behavior is
incorrect, but even if it had a new process type that ran before the other
ones the best I can do for vlog95 is emit it before the normal module
processes which currently works.
This commit is contained in:
Cary R 2013-02-15 19:29:29 -08:00
parent 51112131ad
commit c4386da666
1 changed files with 42 additions and 0 deletions

View File

@ -627,6 +627,44 @@ static void emit_named_block_scope(ivl_scope_t scope)
fprintf(vlog_out, " */\n");
}
/*
* In SystemVerilog a task or function can have a process to initialize
* variables. In reality SystemVerilog requires this to be before the
* initial/always blocks are processed, but that's not how it is currently
* implemented in Icarus!
*/
static int find_tf_process(ivl_process_t proc, ivl_scope_t scope)
{
if (scope == ivl_process_scope(proc)) {
ivl_scope_t mod_scope = scope;
/* A task or function can only have initial processes that
* are used to set local variables. */
assert(ivl_process_type(proc) == IVL_PR_INITIAL);
/* Find the module scope for this task/function. */
while (ivl_scope_type(mod_scope) != IVL_SCT_MODULE) {
mod_scope = ivl_scope_parent(mod_scope);
assert(mod_scope);
}
/* Emit the process in the module scope since that is where
* this all started. */
emit_process(mod_scope, proc);
}
return 0;
}
/*
* Emit any initial blocks for the tasks or functions in a module.
*/
static int emit_tf_process(ivl_scope_t scope, ivl_scope_t parent)
{
ivl_scope_type_t sc_type = ivl_scope_type(scope);
if ((sc_type == IVL_SCT_FUNCTION) || (sc_type == IVL_SCT_TASK)) {
/* Output the initial/always blocks for this module. */
ivl_design_process(design, (ivl_process_f)find_tf_process, scope);
}
return 0;
}
/*
* This search method may be slow for a large structural design with a
* large number of gate types. That's not what this converter was built
@ -801,6 +839,10 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent)
emit_tran(scope, ivl_scope_switch(scope, idx));
}
/* Output any initial blocks for tasks or functions defined
* in this module. Used to initialize local variables. */
ivl_scope_children(scope, (ivl_scope_f*) emit_tf_process, scope);
/* Output the initial/always blocks for this module. */
ivl_design_process(design, (ivl_process_f)find_process, scope);
}