Add some synthesis checks for the always_comb/ff/latch blocks

This commit is contained in:
Cary R 2017-12-27 14:41:43 -08:00
parent 0caa109174
commit 2bbd077dc9
7 changed files with 785 additions and 138 deletions

View File

@ -2906,11 +2906,12 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
if (nscope == 0)
nscope = scope;
// Handle the special case that the block contains only one
// statement. There is no need to keep the block node. Also,
// don't elide named blocks, because they might be referenced
// elsewhere.
if ((list_.size() == 1) && (pscope_name() == 0)) {
// Handle the special case that the sequential block contains
// only one statement. There is no need to keep the block node.
// Also, don't elide named blocks, because they might be
// referenced elsewhere.
if ((type == NetBlock::SEQU) && (list_.size() == 1) &&
(pscope_name() == 0)) {
assert(list_[0]);
NetProc*tmp = list_[0]->elaborate(des, nscope);
return tmp;
@ -4190,6 +4191,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
NetEvent*ev = new NetEvent(scope->local_symbol());
ev->set_line(*this);
ev->local_flag(true);
unsigned expr_count = 0;
NetEvWait*wa = new NetEvWait(enet);
@ -4470,6 +4472,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
/* Create an event wait and an otherwise unreferenced
event variable to force a perpetual wait. */
NetEvent*wait_event = new NetEvent(scope->local_symbol());
wait_event->set_line(*this);
wait_event->local_flag(true);
scope->add_event(wait_event);
NetEvWait*wait = new NetEvWait(0);
@ -4490,6 +4494,8 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
eval_expr(expr);
NetEvent*wait_event = new NetEvent(scope->local_symbol());
wait_event->set_line(*this);
wait_event->local_flag(true);
scope->add_event(wait_event);
NetEvWait*wait = new NetEvWait(0 /* noop */);
@ -6110,10 +6116,10 @@ class later_defparams : public elaborator_work_item_t {
bool Design::check_proc_delay() const
{
bool result_flag = true;
bool result = false;
for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) {
/* If this is an always block and we have no or zero delay then
/* If this is an always process and we have no or zero delay then
* a runtime infinite loop will happen. If we possibly have some
* delay then print a warning that an infinite loop is possible.
*/
@ -6128,7 +6134,7 @@ bool Design::check_proc_delay() const
<< " statement does not have any delay." << endl;
cerr << pr->get_fileline() << ": : A runtime"
<< " infinite loop will occur." << endl;
result_flag = false;
result = true;
} else if (dly_type == POSSIBLE_DELAY && warn_inf_loop) {
cerr << pr->get_fileline() << ": warning: always"
@ -6137,20 +6143,20 @@ bool Design::check_proc_delay() const
<< " infinite loop may be possible." << endl;
}
// The always_comb/ff/latch blocks have special delay
// rules that need to be checked.
// The always_comb/ff/latch processes also have special
// delay rules that need to be checked.
if ((pr->type() == IVL_PR_ALWAYS_COMB) ||
(pr->type() == IVL_PR_ALWAYS_FF) ||
(pr->type() == IVL_PR_ALWAYS_LATCH)) {
const NetEvWait *wait = dynamic_cast<const NetEvWait*> (pr->statement());
if (! wait) {
// The always_comb/latch have an event wait
// added automatically by the compiler.
// The always_comb/latch processes have an event
// control added automatically by the compiler.
assert(pr->type() == IVL_PR_ALWAYS_FF);
cerr << pr->get_fileline() << ": error: the "
<< "first statement of an always_ff must "
<< "be an event control." << endl;
result_flag = false;
result = true;
} else if (wait->statement()->delay_type(true) != NO_DELAY) {
cerr << pr->get_fileline() << ": error: there "
<< "must ";
@ -6165,7 +6171,7 @@ bool Design::check_proc_delay() const
<< "process.";
}
cerr << endl;
result_flag = false;
result = true;
}
}
}
@ -6180,12 +6186,30 @@ bool Design::check_proc_delay() const
if (dly_type != NO_DELAY && dly_type != ZERO_DELAY) {
cerr << pr->get_fileline() << ": error: final"
<< " statement contains a delay." << endl;
result_flag = false;
result = true;
}
}
}
return result_flag;
return result;
}
/*
* Check to see if the always_* processes only contain synthesizable
* constructs.
*/
bool Design::check_proc_synth() const
{
bool result = false;
for (const NetProcTop*pr = procs_ ; pr ; pr = pr->next_) {
if ((pr->type() == IVL_PR_ALWAYS_COMB) ||
(pr->type() == IVL_PR_ALWAYS_FF) ||
(pr->type() == IVL_PR_ALWAYS_LATCH)) {
result |= pr->statement()->check_synth(pr->type(),
pr->scope());
}
}
return result;
}
/*
@ -6589,10 +6613,11 @@ Design* elaborate(list<perm_string>roots)
// Now that everything is fully elaborated verify that we do
// not have an always block with no delay (an infinite loop),
// or a final block with a delay.
if (des->check_proc_delay() == false) {
delete des;
des = 0;
}
bool has_failure = des->check_proc_delay();
// Check to see if the always_comb/ff/latch processes only have
// synthesizable constructs
has_failure |= des->check_proc_synth();
if (debug_elaborate) {
cerr << "<toplevel>" << ": debug: "
@ -6600,5 +6625,10 @@ Design* elaborate(list<perm_string>roots)
<< des->find_root_scopes().size() << " root scopes " << endl;
}
if (has_failure) {
delete des;
des = 0;
}
return des;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2015 Stephen Williams (steve@icarus.com)
* Copyright (c) 1999-2017 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
@ -1358,6 +1358,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root)
if (nset && (nset->size() > 0)) {
NetEvent*ev = new NetEvent(scope->local_symbol());
ev->set_line(*root);
ev->local_flag(true);
NetEvProbe*pr = new NetEvProbe(scope, scope->local_symbol(),
ev, NetEvProbe::ANYEDGE,

View File

@ -28,6 +28,7 @@
NetEvent::NetEvent(perm_string n)
: name_(n)
{
local_flag_ = false;
scope_ = 0;
snext_ = 0;
probes_ = 0;

View File

@ -32,7 +32,7 @@ NexusSet* NetExpr::nex_input(bool, bool) const
cerr << get_fileline()
<< ": internal error: nex_input not implemented: "
<< *this << endl;
return 0;
return new NexusSet;
}
NexusSet* NetProc::nex_input(bool, bool) const
@ -40,7 +40,7 @@ NexusSet* NetProc::nex_input(bool, bool) const
cerr << get_fileline()
<< ": internal error: NetProc::nex_input not implemented"
<< endl;
return 0;
return new NexusSet;
}
NexusSet* NetEArrayPattern::nex_input(bool rem_out, bool search_funcs) const
@ -69,12 +69,12 @@ NexusSet* NetEBinary::nex_input(bool rem_out, bool search_funcs) const
NexusSet* NetEConcat::nex_input(bool rem_out, bool search_funcs) const
{
if (parms_[0] == NULL) return NULL;
if (parms_[0] == NULL) return new NexusSet;
NexusSet*result = parms_[0]->nex_input(rem_out, search_funcs);
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx] == NULL) {
delete result;
return NULL;
return new NexusSet;
}
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
result->add(*tmp);
@ -140,10 +140,6 @@ NexusSet* NetESelect::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = base_? base_->nex_input(rem_out, search_funcs) : new NexusSet();
NexusSet*tmp = expr_->nex_input(rem_out, search_funcs);
if (tmp == NULL) {
delete result;
return NULL;
}
result->add(*tmp);
delete tmp;
/* See the comment for NetESignal below. */
@ -159,19 +155,18 @@ NexusSet* NetESelect::nex_input(bool rem_out, bool search_funcs) const
*/
NexusSet* NetESFunc::nex_input(bool rem_out, bool search_funcs) const
{
if (parms_.empty())
return new NexusSet;
NexusSet*result = new NexusSet;
NexusSet*result;
if (parms_[0]) result = parms_[0]->nex_input(rem_out, search_funcs);
else result = new NexusSet;
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_.empty()) return result;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx]) {
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
}
return result;
}
@ -259,9 +254,16 @@ NexusSet* NetEUnary::nex_input(bool rem_out, bool search_funcs) const
return expr_->nex_input(rem_out, search_funcs);
}
NexusSet* NetAlloc::nex_input(bool, bool) const
{
return new NexusSet;
}
NexusSet* NetAssign_::nex_input(bool rem_out, bool search_funcs) const
{
assert(! nest_);
NexusSet*result = new NexusSet;
if (word_) {
NexusSet*tmp = word_->nex_input(rem_out, search_funcs);
result->add(*tmp);
@ -278,7 +280,13 @@ NexusSet* NetAssign_::nex_input(bool rem_out, bool search_funcs) const
NexusSet* NetAssignBase::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = rval_->nex_input(rem_out, search_funcs);
NexusSet*result = new NexusSet;
// For the deassign and release statements there is no R-value.
if (rval_) {
NexusSet*tmp = rval_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
/* It is possible that the lval_ can have nex_input values. In
particular, index expressions are statement inputs as well,
@ -311,14 +319,13 @@ NexusSet* NetAssignBase::nex_input(bool rem_out, bool search_funcs) const
*/
NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const
{
if (last_ == 0)
return new NexusSet;
if (last_ == 0) return new NexusSet;
if (type_ != SEQU) {
if (! search_funcs && (type_ != SEQU)) {
cerr << get_fileline() << ": internal error: Sorry, "
<< "I don't know how to synthesize fork/join blocks."
<< endl;
return 0;
return new NexusSet;
}
NetProc*cur = last_->next_;
@ -332,7 +339,7 @@ NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const
NexusSet*tmp = cur->nex_input(rem_out, search_funcs);
/* Add the current input set to the accumulated input set. */
if (tmp != 0) result->add(*tmp);
result->add(*tmp);
delete tmp;
/* Add the current outputs to the accumulated output set if
@ -359,8 +366,6 @@ NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const
NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
if (result == 0)
return 0;
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
@ -369,7 +374,6 @@ NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const
continue;
NexusSet*tmp = items_[idx].statement->nex_input(rem_out, search_funcs);
assert(tmp);
result->add(*tmp);
delete tmp;
@ -378,7 +382,6 @@ NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const
guard. The default guard obviously has no input. */
if (items_[idx].guard) {
tmp = items_[idx].guard->nex_input(rem_out, search_funcs);
assert(tmp);
result->add(*tmp);
delete tmp;
}
@ -387,16 +390,10 @@ NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const
return result;
}
NexusSet* NetCAssign::nex_input(bool, bool) const
{
cerr << get_fileline() << ": internal warning: NetCAssign::nex_input()"
<< " not implemented." << endl;
return new NexusSet;
}
NexusSet* NetCondit::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
if (if_ != 0) {
NexusSet*tmp = if_->nex_input(rem_out, search_funcs);
result->add(*tmp);
@ -412,51 +409,85 @@ NexusSet* NetCondit::nex_input(bool rem_out, bool search_funcs) const
return result;
}
NexusSet* NetDisable::nex_input(bool, bool) const
{
return new NexusSet;
}
NexusSet* NetDoWhile::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = proc_->nex_input(rem_out, search_funcs);
NexusSet*tmp = cond_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
NexusSet*result = cond_->nex_input(rem_out, search_funcs);
if (proc_) {
NexusSet*tmp = proc_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}
NexusSet* NetEvTrig::nex_input(bool, bool) const
{
return new NexusSet;
}
NexusSet* NetEvWait::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result;
if (statement_)
result = statement_->nex_input(rem_out, search_funcs);
else
result = new NexusSet;
NexusSet*result = new NexusSet;
if (statement_) {
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}
NexusSet* NetForce::nex_input(bool, bool) const
NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const
{
cerr << get_fileline() << ": internal warning: NetForce::nex_input()"
<< " not implemented." << endl;
return new NexusSet;
NexusSet*result = new NexusSet;
if (statement_) {
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}
NexusSet* NetForLoop::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = init_expr_->nex_input(rem_out, search_funcs);
NexusSet*result = new NexusSet;
NexusSet*tmp = condition_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
if (init_expr_) {
NexusSet*tmp = init_expr_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
if (condition_) {
NexusSet*tmp = condition_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
tmp = step_statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
if (step_statement_) {
NexusSet*tmp = step_statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
if (statement_) {
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
if (gn_shared_loop_index_flag) {
tmp = new NexusSet();
NexusSet*tmp = new NexusSet();
for (unsigned idx = 0 ; idx < index_->pin_count() ; idx += 1)
tmp->add(index_->pin(idx).nexus(), 0, index_->vector_width());
@ -467,10 +498,9 @@ NexusSet* NetForLoop::nex_input(bool rem_out, bool search_funcs) const
return result;
}
NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const
NexusSet* NetFree::nex_input(bool, bool) const
{
NexusSet*result = statement_->nex_input(rem_out, search_funcs);
return result;
return new NexusSet;
}
/*
@ -484,17 +514,27 @@ NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const
*/
NexusSet* NetPDelay::nex_input(bool rem_out, bool search_funcs) const
{
if (statement_ == 0) return 0;
NexusSet*result = statement_->nex_input(rem_out, search_funcs);
NexusSet*result = new NexusSet;
if (statement_) {
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}
NexusSet* NetRepeat::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = statement_->nex_input(rem_out, search_funcs);
NexusSet*tmp = expr_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
NexusSet*result = expr_->nex_input(rem_out, search_funcs);
if (statement_) {
NexusSet*tmp = statement_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}
@ -503,13 +543,11 @@ NexusSet* NetRepeat::nex_input(bool rem_out, bool search_funcs) const
*/
NexusSet* NetSTask::nex_input(bool rem_out, bool search_funcs) const
{
if (parms_.empty())
return new NexusSet;
NexusSet*result = new NexusSet;
NexusSet*result;
if (parms_[0]) result = parms_[0]->nex_input(rem_out, search_funcs);
else result = new NexusSet;
for (unsigned idx = 1 ; idx < parms_.size() ; idx += 1) {
if (parms_.empty()) return result;
for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
if (parms_[idx]) {
NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs);
result->add(*tmp);
@ -532,9 +570,13 @@ NexusSet* NetUTask::nex_input(bool, bool) const
NexusSet* NetWhile::nex_input(bool rem_out, bool search_funcs) const
{
NexusSet*result = proc_->nex_input(rem_out, search_funcs);
NexusSet*tmp = cond_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
NexusSet*result = cond_->nex_input(rem_out, search_funcs);
if (proc_) {
NexusSet*tmp = proc_->nex_input(rem_out, search_funcs);
result->add(*tmp);
delete tmp;
}
return result;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002-2013 Stephen Williams (steve@icarus.com)
* Copyright (c) 2002-2017 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,8 +36,13 @@ void NetProc::nex_output(NexusSet&)
<< endl;
}
void NetAlloc::nex_output(NexusSet&)
{
}
void NetAssign_::nex_output(NexusSet&out)
{
assert(! nest_);
assert(sig_);
unsigned use_word = 0;
unsigned use_base = 0;
@ -89,8 +94,7 @@ void NetAssignBase::nex_output(NexusSet&out)
void NetBlock::nex_output(NexusSet&out)
{
if (last_ == 0)
return;
if (last_ == 0) return;
NetProc*cur = last_;
do {
@ -104,10 +108,8 @@ void NetCase::nex_output(NexusSet&out)
for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
// Empty statements clearly have no output.
if (items_[idx].statement == 0)
continue;
if (items_[idx].statement == 0) continue;
assert(items_[idx].statement);
items_[idx].statement->nex_output(out);
}
@ -115,22 +117,31 @@ void NetCase::nex_output(NexusSet&out)
void NetCondit::nex_output(NexusSet&out)
{
if (if_ != 0)
if_->nex_output(out);
if (else_ != 0)
else_->nex_output(out);
if (if_) if_->nex_output(out);
if (else_) else_->nex_output(out);
}
void NetDisable::nex_output(NexusSet&)
{
}
void NetDoWhile::nex_output(NexusSet&out)
{
if (proc_ != 0)
proc_->nex_output(out);
if (proc_) proc_->nex_output(out);
}
void NetEvTrig::nex_output(NexusSet&)
{
}
void NetEvWait::nex_output(NexusSet&out)
{
assert(statement_);
statement_->nex_output(out);
if (statement_) statement_->nex_output(out);
}
void NetForever::nex_output(NexusSet&out)
{
if (statement_) statement_->nex_output(out);
}
void NetForLoop::nex_output(NexusSet&out)
@ -138,11 +149,20 @@ void NetForLoop::nex_output(NexusSet&out)
if (statement_) statement_->nex_output(out);
}
void NetFree::nex_output(NexusSet&)
{
}
void NetPDelay::nex_output(NexusSet&out)
{
if (statement_) statement_->nex_output(out);
}
void NetRepeat::nex_output(NexusSet&out)
{
if (statement_) statement_->nex_output(out);
}
/*
* For the purposes of synthesis, system task calls have no output at
* all. This is OK because most system tasks are not synthesizable in
@ -163,6 +183,5 @@ void NetUTask::nex_output(NexusSet&)
void NetWhile::nex_output(NexusSet&out)
{
if (proc_ != 0)
proc_->nex_output(out);
if (proc_) proc_->nex_output(out);
}

View File

@ -2779,12 +2779,20 @@ static DelayType get_loop_delay_type(const NetExpr*expr, const NetProc*proc, boo
break;
/* We have a constant true expression so the body always runs. */
case DEFINITE_DELAY:
result = proc->delay_type(print_delay);
if (proc) {
result = proc->delay_type(print_delay);
} else {
result = NO_DELAY;
}
break;
/* We don't know if the body will run so reduce a DEFINITE_DELAY
* to a POSSIBLE_DELAY. All other stay the same. */
case POSSIBLE_DELAY:
result = combine_delays(NO_DELAY, proc->delay_type(print_delay));
if (proc) {
result = combine_delays(NO_DELAY, proc->delay_type(print_delay));
} else {
result = NO_DELAY;
}
break;
/* This should never happen since delay_type_from_expr() only
* returns three different values. */
@ -2814,7 +2822,7 @@ DelayType NetBlock::delay_type(bool print_delay) const
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
DelayType dt = cur->delay_type(print_delay);
if (dt < result) result = dt;
if (dt == NO_DELAY) break;
if ((dt == NO_DELAY) && !print_delay) break;
}
// A begin or join has the maximum delay.
@ -2823,7 +2831,7 @@ DelayType NetBlock::delay_type(bool print_delay) const
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
DelayType dt = cur->delay_type(print_delay);
if (dt > result) result = dt;
if (dt == DEFINITE_DELAY) break;
if ((dt == DEFINITE_DELAY) && !print_delay) break;
}
}
@ -2846,6 +2854,7 @@ DelayType NetCase::delay_type(bool print_delay) const
}
}
// FIXME: If all the cases are covered (e.g. an enum) then this is not true.
/* If we don't have a default statement we don't know for sure
* that we have a delay. */
if (!def_stmt) result = combine_delays(NO_DELAY, result);
@ -2865,29 +2874,31 @@ DelayType NetCondit::delay_type(bool print_delay) const
*/
DelayType NetDoWhile::delay_type(bool print_delay) const
{
ivl_assert(*this, proc_);
return proc_->delay_type(print_delay);
if (proc_) return proc_->delay_type(print_delay);
return ZERO_DELAY;
}
DelayType NetEvWait::delay_type(bool print_delay) const
{
if (print_delay) {
cerr << get_fileline() << ": error: an event control is not allowed "
<< "in an always_comb, always_ff or always_latch process."
"in an always_comb, always_ff or always_latch process."
<< endl;
}
return DEFINITE_DELAY;
}
DelayType NetForever::delay_type(bool print_delay) const
{
ivl_assert(*this, statement_);
return statement_->delay_type(print_delay);
if (statement_) return statement_->delay_type(print_delay);
return ZERO_DELAY;
}
DelayType NetForLoop::delay_type(bool print_delay) const
{
ivl_assert(*this, statement_);
return get_loop_delay_type(condition_, statement_, print_delay);
}
@ -2895,28 +2906,31 @@ DelayType NetPDelay::delay_type(bool print_delay) const
{
if (print_delay) {
cerr << get_fileline() << ": error: a blocking delay is not allowed "
<< "in an always_comb, always_ff or always_latch process."
"in an always_comb, always_ff or always_latch process."
<< endl;
}
if (expr_) {
return delay_type_from_expr(expr_);
} else {
if (delay() > 0) {
return DEFINITE_DELAY;
if (statement_) {
return combine_delays(delay_type_from_expr(expr_),
statement_->delay_type(print_delay));
} else {
if (statement_) {
return combine_delays(ZERO_DELAY,
statement_->delay_type(print_delay));
} else {
return ZERO_DELAY;
}
return delay_type_from_expr(expr_);
}
}
if (delay() > 0) return DEFINITE_DELAY;
if (statement_) {
return combine_delays(ZERO_DELAY,
statement_->delay_type(print_delay));
} else {
return ZERO_DELAY;
}
}
DelayType NetRepeat::delay_type(bool print_delay) const
{
ivl_assert(*this, statement_);
return get_loop_delay_type(expr_, statement_, print_delay);
}
@ -2930,8 +2944,512 @@ DelayType NetUTask::delay_type(bool print_delay) const
return task()->task_def()->delay_type(print_delay);
}
static bool do_expr_event_match(const NetExpr*expr, const NetEvWait*evwt)
{
// The event wait should only have a single event.
if (evwt->nevents() != 1) return false;
// The event should have a single probe.
const NetEvent* evt = evwt->event(0);
if (evt->nprobe() != 1) return false;
// The probe should be for any edge.
const NetEvProbe *prb = evt->probe(0);
if (prb->edge() != NetEvProbe::ANYEDGE) return false;
// Create a NexusSet from the event probe signals.
NexusSet *ns_evwt = new NexusSet;
for (unsigned idx =0; idx < prb->pin_count(); idx += 1) {
if (! prb->pin(idx).is_linked()) {
delete ns_evwt;
return false;
}
// Casting away const is safe since this nexus set is only being read.
ns_evwt->add(const_cast<Nexus*> (prb->pin(idx).nexus()),
0, prb->pin(idx).nexus()->vector_width());
}
// Get the NexusSet for the expression
NexusSet *ns_expr = expr->nex_input();
// Make sure the event and expression NexusSets match exactly
if (ns_evwt->size() != ns_expr->size()) {
delete ns_evwt;
delete ns_expr;
return false;
}
ns_expr->rem(*ns_evwt);
delete ns_evwt;
if (ns_expr->size() != 0) {
delete ns_expr;
return false;
}
delete ns_expr;
return true;
}
static bool while_is_wait(const NetExpr*expr, const NetProc*stmt)
{
if (const NetEvWait*evwt = dynamic_cast<const NetEvWait*>(stmt)) {
if (evwt->statement()) return false;
const NetEBComp*cond = dynamic_cast<const NetEBComp*>(expr);
if (! cond) return false;
if (cond->op() != 'N') return false;
const NetEConst*cval = dynamic_cast<const NetEConst*>(cond->right());
if (! cval) return false;
const verinum val = cval->value();
if (val.len() != 1) return false;
if (val.get(0) != verinum::V1) return false;
if (! do_expr_event_match(cond->left(), evwt)) return false;
if (evwt->get_lineno() != cond->get_lineno()) return false;
if (evwt->get_file() != cond->get_file()) return false;
return true;
}
return false;
}
DelayType NetWhile::delay_type(bool print_delay) const
{
ivl_assert(*this, proc_);
// If the wait was a constant value the compiler already removed it
// so we know we can only have a possible delay.
if (while_is_wait(cond_, proc_)) {
if (print_delay) {
cerr << get_fileline() << ": error: a wait statement is "
"not allowed in an "
"always_comb, always_ff or always_latch process."
<< endl;
}
return POSSIBLE_DELAY;
}
return get_loop_delay_type(cond_, proc_, print_delay);
}
/*
* These are the check_synth() functions. They are used to print
* a warning if the item is not synthesizable.
*/
static const char * get_process_type_as_string(ivl_process_type_t pr_type)
{
switch (pr_type) {
case IVL_PR_ALWAYS_COMB:
return "in an always_comb process.";
break;
case IVL_PR_ALWAYS_FF:
return "in an always_ff process.";
break;
case IVL_PR_ALWAYS_LATCH:
return "in an always_latch process.";
break;
default:
assert(0);
return 0;
}
}
static void print_synth_warning(const NetProc *net_proc, const char *name,
ivl_process_type_t pr_type)
{
cerr << net_proc->get_fileline() << ": warning: " << name
<< " statement cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
static void check_if_logic_l_value(const NetAssignBase *base,
ivl_process_type_t pr_type)
{
if (base->l_val_count() != 1) return;
const NetAssign_*lval = base->l_val(0);
if (! lval) return;
NetNet*sig = lval->sig();
if (! sig) return;
if ((sig->data_type() != IVL_VT_BOOL) &&
(sig->data_type() != IVL_VT_LOGIC)) {
cerr << base->get_fileline() << ": warning: Assinging to a "
"non-integral variable ("<< sig->name()
<< ") cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
}
/* By default elements can be synthesized or ignored. */
bool NetProc::check_synth(ivl_process_type_t /* pr_type */,
const NetScope* /* scope */ ) const
{
return false;
}
/* By default assign elements can be synthesized. */
bool NetAssignBase::check_synth(ivl_process_type_t /* pr_type */,
const NetScope* /* scope */ ) const
{
return false;
}
bool NetAssign::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
check_if_logic_l_value(this, pr_type);
// FIXME: Check that ff/latch only use this for internal signals.
return false;
}
bool NetAssignNB::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
bool result = false;
if (pr_type == IVL_PR_ALWAYS_COMB) {
cerr << get_fileline() << ": warning: A non-blocking assignment "
"should not be used in an always_comb process." << endl;
}
if (event_) {
cerr << get_fileline() << ": error: A non-blocking assignment "
"cannot be synthesized with an event control "
<< get_process_type_as_string(pr_type) << endl;
result = true;
}
check_if_logic_l_value(this, pr_type);
return result;
}
bool NetBlock::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
// Only a begin/end can be synthesized.
if (type() != SEQU) {
cerr << get_fileline() << ": error: A fork/";
switch (type()) {
case PARA:
cerr << "join";
break;
case PARA_JOIN_ANY:
cerr << "join_any";
break;
case PARA_JOIN_NONE:
cerr << "join_none";
break;
default:
assert(0);
}
cerr << " statement cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
result = true;
}
const NetScope*save_scope = scope;
if (subscope()) scope = subscope();
if (scope != save_scope) {
result |= scope->check_synth(pr_type, scope);
}
for (const NetProc*cur = proc_first(); cur; cur = proc_next(cur)) {
result |= cur->check_synth(pr_type, scope);
}
scope = save_scope;
return result;
}
bool NetCase::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
for (unsigned idx = 0; idx < nitems(); idx += 1) {
if (stat(idx)) result |= stat(idx)->check_synth(pr_type, scope);
}
// FIXME: Check for ff/latch/comb structures.
return result;
}
bool NetCAssign::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
print_synth_warning(this, "A procedural assign", pr_type);
return false;
}
bool NetCondit::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
if (if_) result |= if_->check_synth(pr_type, scope);
if (else_) result |= else_->check_synth(pr_type, scope);
// FIXME: Check for ff/latch/comb structures.
return result;
}
bool NetDeassign::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
print_synth_warning(this, "A procedural deassign", pr_type);
return false;
}
bool NetDisable::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
while (scope) {
if (scope != target_) scope = scope->parent();
else break;
}
if (! scope) {
cerr << get_fileline() << ": warning: A disable statement can "
"only be synthesized when disabling an enclosing block "
<< get_process_type_as_string(pr_type) << endl;
}
return false;
}
bool NetDoWhile::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
print_synth_warning(this, "A do/while", pr_type);
if (proc_) result |= proc_->check_synth(pr_type, scope);
return result;
}
bool NetEvTrig::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
print_synth_warning(this, "An event trigger", pr_type);
return false;
}
// The delay check above has already marked this as an error.
bool NetEvWait::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
if (statement_) result |= statement_->check_synth(pr_type, scope);
return result;
}
bool NetForce::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
print_synth_warning(this, "A force", pr_type);
return false;
}
bool NetForever::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
print_synth_warning(this, "A forever", pr_type);
if (statement_) result |= statement_->check_synth(pr_type, scope);
return result;
}
/*
* A bunch of private routines to verify that a for loop has the correct
* structure for synthesis.
*/
static void print_for_idx_warning(const NetProc*proc, const char*check,
ivl_process_type_t pr_type, NetNet*idx)
{
cerr << proc->get_fileline() << ": warning: A for statement must use "
"the index (" << idx->name() << ") in the " << check
<< " expression to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
static void check_for_const_synth(const NetExpr*expr, const NetProc*proc,
const char*str, ivl_process_type_t pr_type)
{
if (! dynamic_cast<const NetEConst*>(expr)) {
cerr << proc-> get_fileline() << ": warning: A for "
"statement must " << str
<< " value to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
}
static void check_for_bin_synth(const NetExpr*left,const NetExpr*right,
const char*str, const char*check,
const NetProc*proc,
ivl_process_type_t pr_type, NetNet*index)
{
const NetESignal*lsig = dynamic_cast<const NetESignal*>(left);
const NetESignal*rsig = dynamic_cast<const NetESignal*>(right);
if (lsig && (lsig->sig() == index)) {
check_for_const_synth(right, proc, str, pr_type);
} else if (rsig && (rsig->sig() == index)) {
check_for_const_synth(left, proc, str, pr_type);
} else {
print_for_idx_warning(proc, check, pr_type, index);
}
}
static void print_for_step_warning(const NetProc*proc,
ivl_process_type_t pr_type)
{
cerr << proc->get_fileline() << ": warning: A for statement step must "
"be a simple assignment statement to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
static void print_for_step_warning(const NetProc*proc,
ivl_process_type_t pr_type, NetNet*idx)
{
cerr << proc->get_fileline() << ": warning: A for statement step must "
"be an assignment to the index variable ("
<< idx->name() << ") to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
static void check_for_bstep_synth(const NetExpr*expr, const NetProc*proc,
ivl_process_type_t pr_type, NetNet*index)
{
if (const NetECast*tmp = dynamic_cast<const NetECast*>(expr)) {
expr = tmp->expr();
}
if (const NetEBAdd*tmp = dynamic_cast<const NetEBAdd*>(expr)) {
check_for_bin_synth(tmp->left(), tmp->right(),
"change by a constant", "step", proc, pr_type,
index);
} else {
cerr << proc->get_fileline() << ": warning: A for statement "
"step must be a simple binary +/- "
"to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
}
static void check_for_step_synth(const NetAssign*assign, const NetProc*proc,
ivl_process_type_t pr_type, NetNet*index)
{
if (assign->l_val_count() != 1) {
print_for_step_warning(proc, pr_type);
} else if (assign->l_val(0)->sig() != index) {
print_for_step_warning(proc, pr_type, index);
} else {
switch (assign->assign_operator()) {
case '+':
case '-':
check_for_const_synth(assign->rval(), proc,
"have a constant step", pr_type);
break;
case 0:
check_for_bstep_synth(assign->rval(), proc, pr_type, index);
break;
default:
cerr << proc->get_fileline() << ": warning: A for statement "
"step does not support operator '"
<< assign->assign_operator()
<< "' it must be +/- to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
break;
}
}
}
bool NetForLoop::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
// FIXME: What about an enum (NetEConstEnum)?
if (! dynamic_cast<const NetEConst*>(init_expr_)) {
cerr << get_fileline() << ": warning: A for statement must "
"have a constant initial value to be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
// FIXME: Do the following also need to be supported in the condition?
// It would seem like they are hard to use to find the bounds.
// From NetEBinary
// What about NetEBits sig & constant, etc.
// From NetEUnary
// What about NetEUBits ! sig or ! (sig == constat)
// What about NetEUReduce &signal
if (const NetESignal*tmp = dynamic_cast<const NetESignal*>(condition_)) {
if (tmp->sig() != index_) {
print_for_idx_warning(this, "condition", pr_type, index_);
}
} else if (const NetEBComp*cmp = dynamic_cast<const NetEBComp*>(condition_)) {
check_for_bin_synth(cmp->left(), cmp->right(),
"compare against a constant", "condition",
this, pr_type, index_);
} else {
print_for_idx_warning(this, "condition", pr_type, index_);
}
if (const NetAssign*tmp = dynamic_cast<const NetAssign*>(step_statement_)) {
check_for_step_synth(tmp, this, pr_type, index_);
} else {
print_for_step_warning(this, pr_type);
}
if (statement_) result |= statement_->check_synth(pr_type, scope);
return result;
}
// The delay check above has already marked this as an error.
bool NetPDelay::check_synth(ivl_process_type_t /* pr_type */,
const NetScope* /* scope */ ) const
{
return false;
}
bool NetRelease::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */ ) const
{
print_synth_warning(this, "A release", pr_type);
return false;
}
bool NetRepeat::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
print_synth_warning(this, "A repeat", pr_type);
if (statement_) result |= statement_->check_synth(pr_type, scope);
return result;
}
bool NetScope::check_synth(ivl_process_type_t pr_type,
const NetScope* /* scope */) const
{
bool result = false;
// Skip local events/signals
for (NetEvent*cur = events_ ; cur ; cur = cur->snext_) {
if (cur->local_flag()) continue;
cerr << cur->get_fileline() << ": warning: An event ("
<< cur->name() << ") cannot be synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
for (signals_map_iter_t cur = signals_map_.begin();
cur != signals_map_.end() ; ++ cur) {
const NetNet*sig = cur->second;
if ((sig->data_type() != IVL_VT_BOOL) &&
(sig->data_type() != IVL_VT_LOGIC)) {
cerr << sig->get_fileline() << ": warning: A non-integral "
"variable (" << sig->name() << ") cannot be "
"synthesized "
<< get_process_type_as_string(pr_type) << endl;
}
}
return result;
}
// FIXME: User task and function calls still need to be checked.
// : System task enables should be ignored and constant system functions
// : should also be okay. Non-constant system functions are an error.
bool NetWhile::check_synth(ivl_process_type_t pr_type,
const NetScope* scope) const
{
bool result = false;
// A wait is already maked as an error in the delay check above.
if (! while_is_wait(cond_, proc_)) {
print_synth_warning(this, "A while", pr_type);
if (proc_) result |= proc_->check_synth(pr_type, scope);
}
return result;
}

View File

@ -1158,6 +1158,9 @@ class NetScope : public Definitions, public Attrib {
perm_string local_symbol();
void dump(ostream&) const;
// Check to see if the scope has items that are not allowed
// in an always_comb/ff/latch process.
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
void emit_scope(struct target_t*tgt) const;
bool emit_defs(struct target_t*tgt) const;
@ -2716,6 +2719,8 @@ class NetProc : public virtual LineInfo {
// Recursively checks to see if there is delay in this element.
virtual DelayType delay_type(bool print_delay=false) const;
// Check to see if the item is synthesizable.
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
protected:
bool synth_async_block_substatement_(Design*des, NetScope*scope,
@ -2743,6 +2748,8 @@ class NetAlloc : public NetProc {
const NetScope* scope() const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
@ -2913,6 +2920,7 @@ class NetAssignBase : public NetProc {
// This dumps all the lval structures.
void dump_lval(ostream&) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private:
NetAssign_*lval_;
@ -2934,6 +2942,7 @@ class NetAssign : public NetAssignBase {
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -2956,6 +2965,7 @@ class NetAssignNB : public NetAssignBase {
virtual bool emit_proc(struct target_t*) const;
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
unsigned nevents() const;
const NetEvent*event(unsigned) const;
@ -3019,6 +3029,7 @@ class NetBlock : public NetProc {
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private:
const Type type_;
@ -3066,6 +3077,7 @@ class NetCase : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3102,9 +3114,9 @@ class NetCAssign : public NetAssignBase {
explicit NetCAssign(NetAssign_*lv, NetExpr*rv);
~NetCAssign();
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool emit_proc(struct target_t*) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private: // not implemented
NetCAssign(const NetCAssign&);
@ -3156,6 +3168,7 @@ class NetCondit : public NetProc {
virtual int match_proc(struct proc_match_t*);
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3201,6 +3214,7 @@ class NetDeassign : public NetAssignBase {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private: // not implemented
NetDeassign(const NetDeassign&);
@ -3224,8 +3238,11 @@ class NetDisable : public NetProc {
const NetScope*target() const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3257,6 +3274,7 @@ class NetDoWhile : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3313,6 +3331,9 @@ class NetEvent : public LineInfo {
perm_string name() const;
bool local_flag() const { return local_flag_; }
void local_flag(bool f) { local_flag_ = f; }
// Get information about probes connected to me.
unsigned nprobe() const;
NetEvProbe* probe(unsigned);
@ -3344,6 +3365,7 @@ class NetEvent : public LineInfo {
private:
perm_string name_;
bool local_flag_;
// The NetScope class uses these to list the events.
NetScope*scope_;
@ -3381,8 +3403,11 @@ class NetEvTrig : public NetProc {
const NetEvent*event() const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private:
NetEvent*event_;
@ -3440,6 +3465,7 @@ class NetEvWait : public NetProc {
// This will ignore any statement.
virtual void dump_inline(ostream&) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private:
NetProc*statement_;
@ -3488,10 +3514,9 @@ class NetForce : public NetAssignBase {
explicit NetForce(NetAssign_*l, NetExpr*r);
~NetForce();
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool emit_proc(struct target_t*) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
};
/*
@ -3507,9 +3532,11 @@ class NetForever : public NetProc {
void emit_recurse(struct target_t*) const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3533,6 +3560,7 @@ class NetForLoop : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3565,6 +3593,8 @@ class NetFree : public NetProc {
const NetScope* scope() const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
@ -3634,6 +3664,7 @@ class NetPDelay : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
bool emit_proc_recurse(struct target_t*) const;
@ -3656,9 +3687,11 @@ class NetRepeat : public NetProc {
void emit_recurse(struct target_t*) const;
virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const;
virtual void nex_output(NexusSet&);
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
@ -3681,6 +3714,7 @@ class NetRelease : public NetAssignBase {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
private:
};
@ -3882,11 +3916,12 @@ class NetWhile : public NetProc {
virtual bool emit_proc(struct target_t*) const;
virtual void dump(ostream&, unsigned ind) const;
virtual DelayType delay_type(bool print_delay=false) const;
virtual bool check_synth(ivl_process_type_t pr_type, const NetScope*scope) const;
virtual bool evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&ctx) const;
private:
NetExpr* cond_;
NetExpr*cond_;
NetProc*proc_;
};
@ -4954,6 +4989,7 @@ class Design {
void add_process(NetAnalogTop*);
void delete_process(NetProcTop*);
bool check_proc_delay() const;
bool check_proc_synth() const;
NetNet* find_discipline_reference(ivl_discipline_t dis, NetScope*scope);