Add some synthesis checks for the always_comb/ff/latch blocks
This commit is contained in:
parent
0caa109174
commit
2bbd077dc9
70
elaborate.cc
70
elaborate.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
NetEvent::NetEvent(perm_string n)
|
||||
: name_(n)
|
||||
{
|
||||
local_flag_ = false;
|
||||
scope_ = 0;
|
||||
snext_ = 0;
|
||||
probes_ = 0;
|
||||
|
|
|
|||
190
net_nex_input.cc
190
net_nex_input.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
564
netlist.cc
564
netlist.cc
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
44
netlist.h
44
netlist.h
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue