Fully support variable initialization in tasks/functions/named blocks.
This commit is contained in:
parent
28b446ca30
commit
635adfc01e
10
PScope.h
10
PScope.h
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef IVL_PScope_H
|
||||
#define IVL_PScope_H
|
||||
/*
|
||||
* Copyright (c) 2008-2014 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-2016 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -36,6 +36,7 @@ class PProcess;
|
|||
class PClass;
|
||||
class PTask;
|
||||
class PWire;
|
||||
class Statement;
|
||||
|
||||
class Design;
|
||||
class NetScope;
|
||||
|
|
@ -108,6 +109,9 @@ class LexicalScope {
|
|||
// creating implicit nets.
|
||||
map<perm_string,LineInfo*> genvars;
|
||||
|
||||
// Variable initializations in this scope
|
||||
vector<Statement*> var_inits;
|
||||
|
||||
// Behaviors (processes) in this scope
|
||||
list<PProcess*> behaviors;
|
||||
list<AProcess*> analog_behaviors;
|
||||
|
|
@ -130,6 +134,10 @@ class LexicalScope {
|
|||
|
||||
void dump_wires_(ostream&out, unsigned indent) const;
|
||||
|
||||
void dump_var_inits_(ostream&out, unsigned indent) const;
|
||||
|
||||
bool elaborate_var_inits_(Design*des, NetScope*scope) const;
|
||||
|
||||
private:
|
||||
LexicalScope*parent_;
|
||||
};
|
||||
|
|
|
|||
112
elaborate.cc
112
elaborate.cc
|
|
@ -2871,14 +2871,27 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(nscope);
|
||||
|
||||
elaborate_behaviors_(des, nscope);
|
||||
}
|
||||
|
||||
NetBlock*cur = new NetBlock(type, nscope);
|
||||
|
||||
if (nscope) {
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic scopes these statements need to be executed
|
||||
// each time the block is entered, so add them to the main
|
||||
// block. For static scopes, put them in a separate process
|
||||
// that will be executed at the start of simulation.
|
||||
if (nscope->is_auto()) {
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
NetProc*tmp = var_inits[idx]->elaborate(des, nscope);
|
||||
if (tmp) cur->append(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, nscope);
|
||||
}
|
||||
}
|
||||
|
||||
if (nscope == 0)
|
||||
nscope = scope;
|
||||
|
||||
|
|
@ -5000,7 +5013,6 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
|
|||
des->errors += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(def);
|
||||
|
||||
ivl_assert(*this, statement_);
|
||||
|
|
@ -5013,6 +5025,31 @@ void PFunction::elaborate(Design*des, NetScope*scope) const
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic functions, these statements need to be executed
|
||||
// each time the function is called, so insert them at the start
|
||||
// of the elaborated definition. For static functions, put them
|
||||
// in a separate process that will be executed before the start
|
||||
// of simulation.
|
||||
if (is_auto_) {
|
||||
// Get the NetBlock of the statement. If it is not a
|
||||
// NetBlock then create one to wrap the initialization
|
||||
// statements and the original statement.
|
||||
NetBlock*blk = dynamic_cast<NetBlock*> (st);
|
||||
if ((blk == 0) && (var_inits.size() > 0)) {
|
||||
blk = new NetBlock(NetBlock::SEQU, scope);
|
||||
blk->set_line(*this);
|
||||
blk->append(st);
|
||||
st = blk;
|
||||
}
|
||||
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
|
||||
NetProc*tmp = var_inits[idx-1]->elaborate(des, scope);
|
||||
if (tmp) blk->prepend(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, scope);
|
||||
}
|
||||
|
||||
def->set_proc(st);
|
||||
}
|
||||
|
||||
|
|
@ -5175,11 +5212,6 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
|
|||
|
||||
void PTask::elaborate(Design*des, NetScope*task) const
|
||||
{
|
||||
// Elaborate any processes that are part of this scope that
|
||||
// aren't the definition itself. This can happen, for example,
|
||||
// with variable initialization statements in this scope.
|
||||
elaborate_behaviors_(des, task);
|
||||
|
||||
NetTaskDef*def = task->task_def();
|
||||
assert(def);
|
||||
|
||||
|
|
@ -5198,6 +5230,31 @@ void PTask::elaborate(Design*des, NetScope*task) const
|
|||
}
|
||||
}
|
||||
|
||||
// Handle any variable initialization statements in this scope.
|
||||
// For automatic tasks , these statements need to be executed
|
||||
// each time the task is called, so insert them at the start
|
||||
// of the elaborated definition. For static tasks, put them
|
||||
// in a separate process that will be executed before the start
|
||||
// of simulation.
|
||||
if (is_auto_) {
|
||||
// Get the NetBlock of the statement. If it is not a
|
||||
// NetBlock then create one to wrap the initialization
|
||||
// statements and the original statement.
|
||||
NetBlock*blk = dynamic_cast<NetBlock*> (st);
|
||||
if ((blk == 0) && (var_inits.size() > 0)) {
|
||||
blk = new NetBlock(NetBlock::SEQU, task);
|
||||
blk->set_line(*this);
|
||||
blk->append(st);
|
||||
st = blk;
|
||||
}
|
||||
for (unsigned idx = var_inits.size(); idx > 0; idx -= 1) {
|
||||
NetProc*tmp = var_inits[idx-1]->elaborate(des, task);
|
||||
if (tmp) blk->prepend(tmp);
|
||||
}
|
||||
} else {
|
||||
elaborate_var_inits_(des, task);
|
||||
}
|
||||
|
||||
def->set_proc(st);
|
||||
}
|
||||
|
||||
|
|
@ -5654,6 +5711,10 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
|||
(*gt)->elaborate(des, scope);
|
||||
}
|
||||
|
||||
// Elaborate the variable initialization statements, making a
|
||||
// single initial process out of them.
|
||||
result_flag &= elaborate_var_inits_(des, scope);
|
||||
|
||||
// Elaborate the behaviors, making processes out of them. This
|
||||
// involves scanning the PProcess* list, creating a NetProcTop
|
||||
// for each process.
|
||||
|
|
@ -5844,6 +5905,8 @@ bool PGenerate::elaborate_(Design*des, NetScope*scope) const
|
|||
for (gates_it_t cur = gates.begin() ; cur != gates.end() ; ++ cur )
|
||||
(*cur)->elaborate(des, scope);
|
||||
|
||||
elaborate_var_inits_(des, scope);
|
||||
|
||||
typedef list<PProcess*>::const_iterator proc_it_t;
|
||||
for (proc_it_t cur = behaviors.begin(); cur != behaviors.end(); ++ cur )
|
||||
(*cur)->elaborate(des, scope);
|
||||
|
|
@ -5879,6 +5942,37 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const
|
|||
return result_flag;
|
||||
}
|
||||
|
||||
bool LexicalScope::elaborate_var_inits_(Design*des, NetScope*scope) const
|
||||
{
|
||||
if (var_inits.size() == 0)
|
||||
return true;
|
||||
|
||||
NetProc*proc = 0;
|
||||
if (var_inits.size() == 1) {
|
||||
proc = var_inits[0]->elaborate(des, scope);
|
||||
} else {
|
||||
NetBlock*blk = new NetBlock(NetBlock::SEQU, scope);
|
||||
bool flag = true;
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
NetProc*tmp = var_inits[idx]->elaborate(des, scope);
|
||||
if (tmp)
|
||||
blk->append(tmp);
|
||||
else
|
||||
flag = false;
|
||||
}
|
||||
if (flag) proc = blk;
|
||||
}
|
||||
if (proc == 0)
|
||||
return false;
|
||||
|
||||
NetProcTop*top = new NetProcTop(scope, IVL_PR_INITIAL, proc);
|
||||
des->add_process(top);
|
||||
|
||||
scope->set_var_init(proc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class elaborate_package_t : public elaborator_work_item_t {
|
||||
public:
|
||||
elaborate_package_t(Design*d, NetScope*scope, PPackage*p)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,10 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
|
|||
// fills in the context_map with local variables held by the scope.
|
||||
scope()->evaluate_function_find_locals(loc, context_map);
|
||||
|
||||
// Execute any variable initialization statements.
|
||||
if (const NetProc*init_proc = scope()->var_init())
|
||||
init_proc->evaluate_function(loc, context_map);
|
||||
|
||||
if (debug_eval_tree && proc_==0) {
|
||||
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
|
||||
<< "Function " << scope_path(scope())
|
||||
|
|
@ -505,6 +509,10 @@ bool NetBlock::evaluate_function(const LineInfo&loc,
|
|||
// Now collect the new locals.
|
||||
subscope_->evaluate_function_find_locals(loc, local_context_map);
|
||||
use_local_context_map = true;
|
||||
|
||||
// Execute any variable initialization statements.
|
||||
if (const NetProc*init_proc = subscope_->var_init())
|
||||
init_proc->evaluate_function(loc, local_context_map);
|
||||
}
|
||||
|
||||
// Now use the local context map if there is any local
|
||||
|
|
|
|||
11
net_proc.cc
11
net_proc.cc
|
|
@ -56,6 +56,17 @@ void NetBlock::append(NetProc*cur)
|
|||
}
|
||||
}
|
||||
|
||||
void NetBlock::prepend(NetProc*cur)
|
||||
{
|
||||
if (last_ == 0) {
|
||||
last_ = cur;
|
||||
cur->next_ = cur;
|
||||
} else {
|
||||
cur->next_ = last_->next_;
|
||||
last_->next_ = cur;
|
||||
}
|
||||
}
|
||||
|
||||
const NetProc* NetBlock::proc_first() const
|
||||
{
|
||||
if (last_ == 0)
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@ NetScope::NetScope(NetScope*up, const hname_t&n, NetScope::TYPE t, bool nest,
|
|||
time_from_timescale_ = false;
|
||||
}
|
||||
|
||||
var_init_ = 0;
|
||||
switch (t) {
|
||||
case NetScope::TASK:
|
||||
task_ = 0;
|
||||
|
|
|
|||
10
netlist.h
10
netlist.h
|
|
@ -1027,6 +1027,13 @@ class NetScope : public Definitions, public Attrib {
|
|||
TYPE type() const;
|
||||
void print_type(ostream&) const;
|
||||
|
||||
// This provides a link to the variable initialisation process
|
||||
// for use when evaluating a constant function. Note this is
|
||||
// only used for static functions - the variable initialization
|
||||
// for automatic functions is included in the function definition.
|
||||
void set_var_init(const NetProc*proc) { var_init_ = proc; }
|
||||
const NetProc* var_init() const { return var_init_; }
|
||||
|
||||
void set_task_def(NetTaskDef*);
|
||||
void set_func_def(NetFuncDef*);
|
||||
void set_class_def(netclass_t*);
|
||||
|
|
@ -1263,6 +1270,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
|
||||
vector<PortInfo> ports_;
|
||||
|
||||
const NetProc*var_init_;
|
||||
|
||||
union {
|
||||
NetTaskDef*task_;
|
||||
NetFuncDef*func_;
|
||||
|
|
@ -2967,6 +2976,7 @@ class NetBlock : public NetProc {
|
|||
NetScope* subscope() const { return subscope_; }
|
||||
|
||||
void append(NetProc*);
|
||||
void prepend(NetProc*);
|
||||
|
||||
const NetProc*proc_first() const;
|
||||
const NetProc*proc_next(const NetProc*cur) const;
|
||||
|
|
|
|||
6
parse.y
6
parse.y
|
|
@ -4227,7 +4227,7 @@ port_declaration
|
|||
port_declaration_context.port_net_type = use_type;
|
||||
port_declaration_context.data_type = $4;
|
||||
|
||||
pform_make_reginit(@5, name, $7);
|
||||
pform_make_var_init(@5, name, $7);
|
||||
|
||||
delete[]$5;
|
||||
$$ = ptmp;
|
||||
|
|
@ -4626,7 +4626,7 @@ module_item
|
|||
IVL_VT_NO_TYPE, $1, SR_BOTH);
|
||||
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
|
||||
if ((*pp).second) {
|
||||
pform_make_reginit(@2, (*pp).first, (*pp).second);
|
||||
pform_make_var_init(@2, (*pp).first, (*pp).second);
|
||||
}
|
||||
}
|
||||
delete $6;
|
||||
|
|
@ -5490,7 +5490,7 @@ register_variable
|
|||
pform_makewire(@1, name, NetNet::REG,
|
||||
NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0);
|
||||
pform_set_reg_idx(name, $2);
|
||||
pform_make_reginit(@1, name, $4);
|
||||
pform_make_var_init(@1, name, $4);
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
|
|
|||
29
pform.cc
29
pform.cc
|
|
@ -2253,22 +2253,29 @@ void pform_make_pgassign_list(list<PExpr*>*alist,
|
|||
}
|
||||
|
||||
/*
|
||||
* this function makes the initial assignment to a register as given
|
||||
* in the source. It handles the case where a reg variable is assigned
|
||||
* where it it declared:
|
||||
* This function makes the initial assignment to a variable as given
|
||||
* in the source. It handles the case where a variable is assigned
|
||||
* where it is declared, e.g.
|
||||
*
|
||||
* reg foo = <expr>;
|
||||
*
|
||||
* This is equivalent to the combination of statements:
|
||||
* In Verilog-2001 this is only supported at the module level, and is
|
||||
* equivalent to the combination of statements:
|
||||
*
|
||||
* reg foo;
|
||||
* initial foo = <expr>;
|
||||
*
|
||||
* and that is how it is parsed. This syntax is not part of the
|
||||
* IEEE1364-1995 standard, but is approved by OVI as enhancement
|
||||
* BTF-B14.
|
||||
* In SystemVerilog, variable initializations are allowed in any scope.
|
||||
* For static variables, initializations are performed before the start
|
||||
* of simulation. For automatic variables, initializations are performed
|
||||
* each time the enclosing block is entered. Here we store the variable
|
||||
* assignments in the current scope, and later elaboration creates an
|
||||
* initialization block that will be executed at the appropriate time.
|
||||
*
|
||||
* This syntax is not part of the IEEE1364-1995 standard, but is
|
||||
* approved by OVI as enhancement BTF-B14.
|
||||
*/
|
||||
void pform_make_reginit(const struct vlltype&li,
|
||||
void pform_make_var_init(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr)
|
||||
{
|
||||
if (! pform_at_module_level() && !gn_system_verilog()) {
|
||||
|
|
@ -2280,7 +2287,7 @@ void pform_make_reginit(const struct vlltype&li,
|
|||
|
||||
PWire*cur = pform_get_wire_in_scope(name);
|
||||
if (cur == 0) {
|
||||
VLerror(li, "internal error: reginit to non-register?");
|
||||
VLerror(li, "internal error: var_init to non-register?");
|
||||
delete expr;
|
||||
return;
|
||||
}
|
||||
|
|
@ -2289,10 +2296,8 @@ void pform_make_reginit(const struct vlltype&li,
|
|||
FILE_NAME(lval, li);
|
||||
PAssign*ass = new PAssign(lval, expr, true);
|
||||
FILE_NAME(ass, li);
|
||||
PProcess*top = new PProcess(IVL_PR_INITIAL, ass);
|
||||
FILE_NAME(top, li);
|
||||
|
||||
pform_put_behavior_in_scope(top);
|
||||
lexical_scope->var_inits.push_back(ass);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -351,7 +351,7 @@ extern void pform_makewire(const struct vlltype&li,
|
|||
list<perm_string>*names,
|
||||
list<named_pexpr_t>*attr);
|
||||
|
||||
extern void pform_make_reginit(const struct vlltype&li,
|
||||
extern void pform_make_var_init(const struct vlltype&li,
|
||||
perm_string name, PExpr*expr);
|
||||
|
||||
/* Look up the names of the wires, and set the port type,
|
||||
|
|
|
|||
|
|
@ -789,6 +789,8 @@ void PBlock::dump(ostream&out, unsigned ind) const
|
|||
dump_events_(out, ind+2);
|
||||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
}
|
||||
|
||||
for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) {
|
||||
|
|
@ -1030,6 +1032,8 @@ void PFunction::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
|
|
@ -1072,6 +1076,8 @@ void PTask::dump(ostream&out, unsigned ind) const
|
|||
|
||||
dump_wires_(out, ind+2);
|
||||
|
||||
dump_var_inits_(out, ind+2);
|
||||
|
||||
if (statement_)
|
||||
statement_->dump(out, ind+2);
|
||||
else
|
||||
|
|
@ -1269,6 +1275,8 @@ void PGenerate::dump(ostream&out, unsigned indent) const
|
|||
(*idx)->dump(out, indent+2);
|
||||
}
|
||||
|
||||
dump_var_inits_(out, indent+2);
|
||||
|
||||
for (list<PProcess*>::const_iterator idx = behaviors.begin()
|
||||
; idx != behaviors.end() ; ++ idx ) {
|
||||
(*idx)->dump(out, indent+2);
|
||||
|
|
@ -1408,6 +1416,14 @@ void LexicalScope::dump_wires_(ostream&out, unsigned indent) const
|
|||
}
|
||||
}
|
||||
|
||||
void LexicalScope::dump_var_inits_(ostream&out, unsigned indent) const
|
||||
{
|
||||
// Iterate through and display all the register initializations.
|
||||
for (unsigned idx = 0; idx < var_inits.size(); idx += 1) {
|
||||
var_inits[idx]->dump(out, indent);
|
||||
}
|
||||
}
|
||||
|
||||
void PScopeExtra::dump_classes_(ostream&out, unsigned indent) const
|
||||
{
|
||||
// Dump the task definitions.
|
||||
|
|
@ -1564,6 +1580,7 @@ void Module::dump(ostream&out) const
|
|||
(*gate)->dump(out);
|
||||
}
|
||||
|
||||
dump_var_inits_(out, 4);
|
||||
|
||||
for (list<PProcess*>::const_iterator behav = behaviors.begin()
|
||||
; behav != behaviors.end() ; ++ behav ) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue