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:
parent
51112131ad
commit
c4386da666
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue