From 585a0232cbd54e20d1dc41d2cb7712e18784bb8d Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 20 Nov 2017 07:48:35 -0800 Subject: [PATCH] Add preliminary support for always_comb, always_ff and always_latch --- Statement.cc | 10 +-- Statement.h | 8 +- design_dump.cc | 19 +++++ elaborate.cc | 19 +++-- ivl_target.h | 9 ++- net_nex_input.cc | 177 +++++++++++++++++++++++------------------- netlist.h | 76 +++++++++--------- parse.y | 14 +++- pform.cc | 16 +++- pform_dump.cc | 14 ++++ synth.cc | 5 +- t-dll.h | 4 +- tgt-stub/stub.c | 18 +++++ tgt-verilog/verilog.c | 5 +- tgt-vlog95/stmt.c | 5 +- tgt-vvp/vvp_process.c | 6 ++ 16 files changed, 262 insertions(+), 143 deletions(-) diff --git a/Statement.cc b/Statement.cc index 942558107..92a87a12d 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -294,20 +294,20 @@ PDoWhile::~PDoWhile() } PEventStatement::PEventStatement(const svector&ee) -: expr_(ee), statement_(0) +: expr_(ee), statement_(0), search_funcs_(false) { assert(expr_.count() > 0); } PEventStatement::PEventStatement(PEEvent*ee) -: expr_(1), statement_(0) +: expr_(1), statement_(0), search_funcs_(false) { expr_[0] = ee; } -PEventStatement::PEventStatement(void) -: statement_(0) +PEventStatement::PEventStatement(bool search_funcs) +: statement_(0), search_funcs_(search_funcs) { } diff --git a/Statement.h b/Statement.h index a6835b03e..30f3b8229 100644 --- a/Statement.h +++ b/Statement.h @@ -1,7 +1,7 @@ #ifndef IVL_Statement_H #define IVL_Statement_H /* - * Copyright (c) 1998-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -402,8 +402,9 @@ class PEventStatement : public Statement { explicit PEventStatement(const svector&ee); explicit PEventStatement(PEEvent*ee); - // Make an @* statement. - explicit PEventStatement(void); + // Make an @* statement or make a special @* version with the items + // from functions added and ouputs removed for always_comb/latch. + explicit PEventStatement(bool search_funcs = false); ~PEventStatement(); @@ -429,6 +430,7 @@ class PEventStatement : public Statement { private: svectorexpr_; Statement*statement_; + bool search_funcs_; }; ostream& operator << (ostream&o, const PEventStatement&obj); diff --git a/design_dump.cc b/design_dump.cc index 590ec1e07..b5f52cfad 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -990,6 +990,18 @@ void NetProcTop::dump(ostream&o, unsigned ind) const o << "always /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; break; + case IVL_PR_ALWAYS_COMB: + o << "always_comb /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + case IVL_PR_ALWAYS_FF: + o << "always_ff /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + case IVL_PR_ALWAYS_LATCH: + o << "always_latch /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; case IVL_PR_FINAL: o << "final /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; @@ -1017,6 +1029,13 @@ void NetAnalogTop::dump(ostream&o, unsigned ind) const << scope_path(scope_) << " */" << endl; break; + // These are not used in an analog context. + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: + assert(0); + break; + case IVL_PR_FINAL: o << "analog final /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; diff --git a/elaborate.cc b/elaborate.cc index 7db362504..0fb01c6b4 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -4200,14 +4200,15 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, if (expr_.count() == 0) { assert(enet); - /* For synthesis we want just the inputs, but for the rest we - * want inputs and outputs that may cause a value to change. */ + /* For synthesis or always_comb/latch we want just the inputs, + * but for the rest we want inputs and outputs that may cause + * a value to change. */ extern bool synthesis; /* Synthesis flag from main.cc */ bool rem_out = false; - if (synthesis) { + if (synthesis || search_funcs_) { rem_out = true; } - NexusSet*nset = enet->nex_input(rem_out); + NexusSet*nset = enet->nex_input(rem_out, search_funcs_); if (nset == 0) { cerr << get_fileline() << ": error: Unable to elaborate:" << endl; @@ -5356,7 +5357,10 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const gets into its wait statement before non-combinational code is executed. */ do { - if (top->type() != IVL_PR_ALWAYS) + if ((top->type() != IVL_PR_ALWAYS) && + (top->type() != IVL_PR_ALWAYS_COMB) && + (top->type() != IVL_PR_ALWAYS_FF) && + (top->type() != IVL_PR_ALWAYS_LATCH)) break; NetEvWait*st = dynamic_cast(top->statement()); @@ -6110,7 +6114,10 @@ bool Design::check_proc_delay() const * a runtime infinite loop will happen. If we possible have some * delay then print a warning that an infinite loop is possible. */ - if (pr->type() == IVL_PR_ALWAYS) { + if ((pr->type() == IVL_PR_ALWAYS) || + (pr->type() == IVL_PR_ALWAYS_COMB) || + (pr->type() == IVL_PR_ALWAYS_FF) || + (pr->type() == IVL_PR_ALWAYS_LATCH)) { DelayType dly_type = pr->statement()->delay_type(); if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) { diff --git a/ivl_target.h b/ivl_target.h index f23c3fb58..22342affb 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -355,9 +355,12 @@ typedef enum ivl_path_edge_e { /* Processes are initial, always, or final blocks with a statement. This is the type of the ivl_process_t object. */ typedef enum ivl_process_type_e ENUM_UNSIGNED_INT { - IVL_PR_INITIAL = 0, - IVL_PR_ALWAYS = 1, - IVL_PR_FINAL = 2 + IVL_PR_INITIAL = 0, + IVL_PR_ALWAYS = 1, + IVL_PR_ALWAYS_COMB = 3, + IVL_PR_ALWAYS_FF = 4, + IVL_PR_ALWAYS_LATCH = 5, + IVL_PR_FINAL = 2 } ivl_process_type_t; /* These are the sorts of reasons a scope may come to be. These types diff --git a/net_nex_input.cc b/net_nex_input.cc index 3e37b7b95..f11ffad7e 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2016 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 @@ -27,7 +27,7 @@ # include "netlist.h" # include "netmisc.h" -NexusSet* NetExpr::nex_input(bool) +NexusSet* NetExpr::nex_input(bool, bool) const { cerr << get_fileline() << ": internal error: nex_input not implemented: " @@ -35,7 +35,7 @@ NexusSet* NetExpr::nex_input(bool) return 0; } -NexusSet* NetProc::nex_input(bool) +NexusSet* NetProc::nex_input(bool, bool) const { cerr << get_fileline() << ": internal error: NetProc::nex_input not implemented" @@ -43,13 +43,13 @@ NexusSet* NetProc::nex_input(bool) return 0; } -NexusSet* NetEArrayPattern::nex_input(bool rem_out) +NexusSet* NetEArrayPattern::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result = new NexusSet; for (size_t idx = 0 ; idx < items_.size() ; idx += 1) { if (items_[idx]==0) continue; - NexusSet*tmp = items_[idx]->nex_input(rem_out); + NexusSet*tmp = items_[idx]->nex_input(rem_out, search_funcs); if (tmp == 0) continue; result->add(*tmp); @@ -58,32 +58,32 @@ NexusSet* NetEArrayPattern::nex_input(bool rem_out) return result; } -NexusSet* NetEBinary::nex_input(bool rem_out) +NexusSet* NetEBinary::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = left_->nex_input(rem_out); - NexusSet*tmp = right_->nex_input(rem_out); + NexusSet*result = left_->nex_input(rem_out, search_funcs); + NexusSet*tmp = right_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; } -NexusSet* NetEConcat::nex_input(bool rem_out) +NexusSet* NetEConcat::nex_input(bool rem_out, bool search_funcs) const { if (parms_[0] == NULL) return NULL; - NexusSet*result = parms_[0]->nex_input(rem_out); + 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; } - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } return result; } -NexusSet* NetEAccess::nex_input(bool) +NexusSet* NetEAccess::nex_input(bool, bool) const { return new NexusSet; } @@ -91,55 +91,55 @@ NexusSet* NetEAccess::nex_input(bool) /* * A constant has not inputs, so always return an empty set. */ -NexusSet* NetEConst::nex_input(bool) +NexusSet* NetEConst::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetECReal::nex_input(bool) +NexusSet* NetECReal::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEEvent::nex_input(bool) +NexusSet* NetEEvent::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetELast::nex_input(bool) +NexusSet* NetELast::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENetenum::nex_input(bool) +NexusSet* NetENetenum::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENew::nex_input(bool) +NexusSet* NetENew::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetENull::nex_input(bool) +NexusSet* NetENull::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEProperty::nex_input(bool) +NexusSet* NetEProperty::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetEScope::nex_input(bool) +NexusSet* NetEScope::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetESelect::nex_input(bool rem_out) +NexusSet* NetESelect::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = base_? base_->nex_input(rem_out) : new NexusSet(); - NexusSet*tmp = expr_->nex_input(rem_out); + 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; @@ -157,17 +157,17 @@ NexusSet* NetESelect::nex_input(bool rem_out) /* * The $fread, etc. system functions can have NULL arguments. */ -NexusSet* NetESFunc::nex_input(bool rem_out) +NexusSet* NetESFunc::nex_input(bool rem_out, bool search_funcs) const { if (parms_.empty()) return new NexusSet; NexusSet*result; - if (parms_[0]) result = parms_[0]->nex_input(rem_out); + 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_[idx]) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -175,12 +175,12 @@ NexusSet* NetESFunc::nex_input(bool rem_out) return result; } -NexusSet* NetEShallowCopy::nex_input(bool) +NexusSet* NetEShallowCopy::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetESignal::nex_input(bool rem_out) +NexusSet* NetESignal::nex_input(bool rem_out, bool search_funcs) const { /* * This is not what I would expect for the various selects (bit, @@ -194,7 +194,7 @@ NexusSet* NetESignal::nex_input(bool rem_out) /* If we have an array index add it to the sensitivity list. */ if (word_) { NexusSet*tmp; - tmp = word_->nex_input(rem_out); + tmp = word_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; if (warn_sens_entire_arr) { @@ -209,27 +209,44 @@ NexusSet* NetESignal::nex_input(bool rem_out) return result; } -NexusSet* NetETernary::nex_input(bool rem_out) +NexusSet* NetETernary::nex_input(bool rem_out, bool search_funcs) const { NexusSet*tmp; - NexusSet*result = cond_->nex_input(rem_out); + NexusSet*result = cond_->nex_input(rem_out, search_funcs); - tmp = true_val_->nex_input(rem_out); + tmp = true_val_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; - tmp = false_val_->nex_input(rem_out); + tmp = false_val_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; } -NexusSet* NetEUFunc::nex_input(bool rem_out) +NexusSet* NetEUFunc::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result = new NexusSet; for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); + result->add(*tmp); + delete tmp; + } + + if (search_funcs) { + NetFuncDef*func = func_->func_def(); + NexusSet*tmp = func->proc()->nex_input(rem_out, search_funcs); + // Remove the function inputs + NexusSet*in = new NexusSet; + for (unsigned idx = 0 ; idx < func->port_count() ; idx += 1) { + NetNet*net = func->port(idx); + assert(net->pin_count() == 1); + in->add(net->pin(0).nexus(), 0, net->vector_width()); + } + tmp->rem(*in); + delete in; + result->add(*tmp); delete tmp; } @@ -237,21 +254,21 @@ NexusSet* NetEUFunc::nex_input(bool rem_out) return result; } -NexusSet* NetEUnary::nex_input(bool rem_out) +NexusSet* NetEUnary::nex_input(bool rem_out, bool search_funcs) const { - return expr_->nex_input(rem_out); + return expr_->nex_input(rem_out, search_funcs); } -NexusSet* NetAssign_::nex_input(bool rem_out) +NexusSet* NetAssign_::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result = new NexusSet; if (word_) { - NexusSet*tmp = word_->nex_input(rem_out); + NexusSet*tmp = word_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } if (base_) { - NexusSet*tmp = base_->nex_input(rem_out); + NexusSet*tmp = base_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -259,15 +276,15 @@ NexusSet* NetAssign_::nex_input(bool rem_out) return result; } -NexusSet* NetAssignBase::nex_input(bool rem_out) +NexusSet* NetAssignBase::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = rval_->nex_input(rem_out); + NexusSet*result = rval_->nex_input(rem_out, search_funcs); /* It is possible that the lval_ can have nex_input values. In particular, index expressions are statement inputs as well, so should be addressed here. */ for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { - NexusSet*tmp = cur->nex_input(rem_out); + NexusSet*tmp = cur->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -292,7 +309,7 @@ NexusSet* NetAssignBase::nex_input(bool rem_out) * In this example, "t" should not be in the input set because it is * used by the sequence as a temporary value. */ -NexusSet* NetBlock::nex_input(bool rem_out) +NexusSet* NetBlock::nex_input(bool rem_out, bool search_funcs) const { if (last_ == 0) return new NexusSet; @@ -312,7 +329,7 @@ NexusSet* NetBlock::nex_input(bool rem_out) do { /* Get the inputs for the current statement. */ - NexusSet*tmp = cur->nex_input(rem_out); + 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); @@ -339,9 +356,9 @@ NexusSet* NetBlock::nex_input(bool rem_out) * the inputs to all the guards, and the inputs to all the guarded * statements. */ -NexusSet* NetCase::nex_input(bool rem_out) +NexusSet* NetCase::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = expr_->nex_input(rem_out); + NexusSet*result = expr_->nex_input(rem_out, search_funcs); if (result == 0) return 0; @@ -351,7 +368,7 @@ NexusSet* NetCase::nex_input(bool rem_out) if (items_[idx].statement == 0) continue; - NexusSet*tmp = items_[idx].statement->nex_input(rem_out); + NexusSet*tmp = items_[idx].statement->nex_input(rem_out, search_funcs); assert(tmp); result->add(*tmp); delete tmp; @@ -360,7 +377,7 @@ NexusSet* NetCase::nex_input(bool rem_out) case is special and is identified by a null guard. The default guard obviously has no input. */ if (items_[idx].guard) { - tmp = items_[idx].guard->nex_input(rem_out); + tmp = items_[idx].guard->nex_input(rem_out, search_funcs); assert(tmp); result->add(*tmp); delete tmp; @@ -370,24 +387,24 @@ NexusSet* NetCase::nex_input(bool rem_out) return result; } -NexusSet* NetCAssign::nex_input(bool) +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) +NexusSet* NetCondit::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = expr_->nex_input(rem_out); + NexusSet*result = expr_->nex_input(rem_out, search_funcs); if (if_ != 0) { - NexusSet*tmp = if_->nex_input(rem_out); + NexusSet*tmp = if_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } if (else_ != 0) { - NexusSet*tmp = else_->nex_input(rem_out); + NexusSet*tmp = else_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -395,46 +412,46 @@ NexusSet* NetCondit::nex_input(bool rem_out) return result; } -NexusSet* NetDoWhile::nex_input(bool rem_out) +NexusSet* NetDoWhile::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = proc_->nex_input(rem_out); - NexusSet*tmp = cond_->nex_input(rem_out); + NexusSet*result = proc_->nex_input(rem_out, search_funcs); + NexusSet*tmp = cond_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; } -NexusSet* NetEvWait::nex_input(bool rem_out) +NexusSet* NetEvWait::nex_input(bool rem_out, bool search_funcs) const { NexusSet*result; if (statement_) - result = statement_->nex_input(rem_out); + result = statement_->nex_input(rem_out, search_funcs); else result = new NexusSet; return result; } -NexusSet* NetForce::nex_input(bool) +NexusSet* NetForce::nex_input(bool, bool) const { cerr << get_fileline() << ": internal warning: NetForce::nex_input()" << " not implemented." << endl; return new NexusSet; } -NexusSet* NetForLoop::nex_input(bool rem_out) +NexusSet* NetForLoop::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = init_expr_->nex_input(rem_out); + NexusSet*result = init_expr_->nex_input(rem_out, search_funcs); - NexusSet*tmp = condition_->nex_input(rem_out); + NexusSet*tmp = condition_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; - tmp = statement_->nex_input(rem_out); + tmp = statement_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; - tmp = step_statement_->nex_input(rem_out); + tmp = step_statement_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; @@ -450,9 +467,9 @@ NexusSet* NetForLoop::nex_input(bool rem_out) return result; } -NexusSet* NetForever::nex_input(bool rem_out) +NexusSet* NetForever::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = statement_->nex_input(rem_out); + NexusSet*result = statement_->nex_input(rem_out, search_funcs); return result; } @@ -465,17 +482,17 @@ NexusSet* NetForever::nex_input(bool rem_out) * include the input set of the because it does not affect the * result. The statement can be omitted. */ -NexusSet* NetPDelay::nex_input(bool rem_out) +NexusSet* NetPDelay::nex_input(bool rem_out, bool search_funcs) const { if (statement_ == 0) return 0; - NexusSet*result = statement_->nex_input(rem_out); + NexusSet*result = statement_->nex_input(rem_out, search_funcs); return result; } -NexusSet* NetRepeat::nex_input(bool rem_out) +NexusSet* NetRepeat::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = statement_->nex_input(rem_out); - NexusSet*tmp = expr_->nex_input(rem_out); + NexusSet*result = statement_->nex_input(rem_out, search_funcs); + NexusSet*tmp = expr_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; @@ -484,17 +501,17 @@ NexusSet* NetRepeat::nex_input(bool rem_out) /* * The $display, etc. system tasks can have NULL arguments. */ -NexusSet* NetSTask::nex_input(bool rem_out) +NexusSet* NetSTask::nex_input(bool rem_out, bool search_funcs) const { if (parms_.empty()) return new NexusSet; NexusSet*result; - if (parms_[0]) result = parms_[0]->nex_input(rem_out); + 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_[idx]) { - NexusSet*tmp = parms_[idx]->nex_input(rem_out); + NexusSet*tmp = parms_[idx]->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; } @@ -508,15 +525,15 @@ NexusSet* NetSTask::nex_input(bool rem_out) * parameters to consider, because the compiler already removed them * and converted them to blocking assignments. */ -NexusSet* NetUTask::nex_input(bool) +NexusSet* NetUTask::nex_input(bool, bool) const { return new NexusSet; } -NexusSet* NetWhile::nex_input(bool rem_out) +NexusSet* NetWhile::nex_input(bool rem_out, bool search_funcs) const { - NexusSet*result = proc_->nex_input(rem_out); - NexusSet*tmp = cond_->nex_input(rem_out); + NexusSet*result = proc_->nex_input(rem_out, search_funcs); + NexusSet*tmp = cond_->nex_input(rem_out, search_funcs); result->add(*tmp); delete tmp; return result; diff --git a/netlist.h b/netlist.h index 4ba553407..18abc161b 100644 --- a/netlist.h +++ b/netlist.h @@ -2045,7 +2045,7 @@ class NetExpr : public LineInfo { // Get the Nexus that are the input to this // expression. Normally this descends down to the reference to // a signal that reads from its input. - virtual NexusSet* nex_input(bool rem_out = true) =0; + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const =0; // Return a version of myself that is structural. This is used // for converting expressions to gates. The arguments are: @@ -2088,7 +2088,7 @@ class NetEArrayPattern : public NetExpr { void dump(ostream&) const; NetEArrayPattern* dup_expr() const; - NexusSet* nex_input(bool rem_out =true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: std::vector items_; @@ -2121,7 +2121,7 @@ class NetEConst : public NetExpr { virtual NetEConst* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -2193,7 +2193,7 @@ class NetECReal : public NetExpr { virtual NetECReal* dup_expr() const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -2637,7 +2637,7 @@ class NetProc : public virtual LineInfo { // Find the nexa that are input by the statement. This is used // for example by @* to find the inputs to the process for the // sensitivity list. - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; // Find the nexa that are set by the statement. Add the output // values to the set passed as a parameter. @@ -2850,7 +2850,7 @@ class NetAssign_ { // being outputs. For example foo[idx] = ... is the l-value // (NetAssign_ object) with a foo l-value and the input // expression idx. - NexusSet* nex_input(bool rem_out = true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; // Figuring out nex_output to process ultimately comes down to // this method. @@ -2898,7 +2898,7 @@ class NetAssignBase : public NetProc { void set_delay(NetExpr*); const NetExpr* get_delay() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&o); @@ -3013,7 +3013,7 @@ class NetBlock : public NetProc { // for sequential blocks. void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + 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 int match_proc(struct proc_match_t*); @@ -3056,7 +3056,7 @@ class NetCase : public NetProc { inline const NetExpr*expr(unsigned idx) const { return items_[idx].guard;} inline const NetProc*stat(unsigned idx) const { return items_[idx].statement; } - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&out); bool synth_async(Design*des, NetScope*scope, @@ -3102,7 +3102,7 @@ class NetCAssign : public NetAssignBase { explicit NetCAssign(NetAssign_*lv, NetExpr*rv); ~NetCAssign(); - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3135,7 +3135,7 @@ class NetCondit : public NetProc { bool emit_recurse_if(struct target_t*) const; bool emit_recurse_else(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&o); bool is_asynchronous(); @@ -3252,7 +3252,7 @@ class NetDoWhile : public NetProc { void emit_proc_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3417,7 +3417,7 @@ class NetEvWait : public NetProc { // process? This method checks. virtual bool is_synchronous(); - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void nex_output(NexusSet&out); virtual bool synth_async(Design*des, NetScope*scope, @@ -3484,7 +3484,7 @@ class NetForce : public NetAssignBase { explicit NetForce(NetAssign_*l, NetExpr*r); ~NetForce(); - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3502,7 +3502,7 @@ class NetForever : public NetProc { void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; @@ -3524,7 +3524,7 @@ class NetForLoop : public NetProc { void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3624,7 +3624,7 @@ class NetPDelay : public NetProc { uint64_t delay() const; const NetExpr*expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3651,7 +3651,7 @@ class NetRepeat : public NetProc { const NetExpr*expr() const; void emit_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool emit_proc(struct target_t*) const; virtual void dump(ostream&, unsigned ind) const; virtual DelayType delay_type() const; @@ -3702,7 +3702,7 @@ class NetSTask : public NetProc { const NetExpr* parm(unsigned idx) const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3761,7 +3761,7 @@ class NetELast : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetELast*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: NetNet*sig_; @@ -3790,7 +3790,7 @@ class NetEUFunc : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEUFunc*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual NetExpr* eval_tree(); virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; @@ -3826,7 +3826,7 @@ class NetEAccess : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEAccess*dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; private: NetBranch*branch_; @@ -3848,7 +3848,7 @@ class NetUTask : public NetProc { const NetScope* task() const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -3873,7 +3873,7 @@ class NetWhile : public NetProc { void emit_proc_recurse(struct target_t*) const; - virtual NexusSet* nex_input(bool rem_out = true); + 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; @@ -4016,7 +4016,7 @@ class NetEBinary : public NetExpr { virtual NetExpr* eval_tree(); virtual NetExpr* evaluate_function(const LineInfo&loc, map&ctx) const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -4270,7 +4270,7 @@ class NetEConcat : public NetExpr { NetExpr* parm(unsigned idx) const { return parms_[idx]; } virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool has_width() const; virtual NetEConcat* dup_expr() const; virtual NetEConst* eval_tree(); @@ -4318,7 +4318,7 @@ class NetESelect : public NetExpr { // sub-expression. virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual bool has_width() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEConst* eval_tree(); @@ -4347,7 +4347,7 @@ class NetEEvent : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEEvent* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4370,7 +4370,7 @@ class NetENetenum : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENetenum* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4394,7 +4394,7 @@ class NetENew : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENew* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4416,7 +4416,7 @@ class NetENull : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetENull* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; }; @@ -4442,7 +4442,7 @@ class NetEProperty : public NetExpr { ivl_variable_type_t expr_type() const; virtual void expr_scan(struct expr_scan_t*) const; virtual NetEProperty* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4467,7 +4467,7 @@ class NetEScope : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEScope* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4501,7 +4501,7 @@ class NetESFunc : public NetExpr { map&ctx) const; virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual const netenum_t* enumeration() const; virtual void dump(ostream&) const; @@ -4636,7 +4636,7 @@ class NetEShallowCopy : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetEShallowCopy* dup_expr() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void dump(ostream&os) const; @@ -4668,7 +4668,7 @@ class NetETernary : public NetExpr { virtual NetExpr*evaluate_function(const LineInfo&loc, map&ctx) const; virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*root); @@ -4723,7 +4723,7 @@ class NetEUnary : public NetExpr { virtual NetNet* synthesize(Design*, NetScope*scope, NetExpr*root); virtual ivl_variable_type_t expr_type() const; - virtual NexusSet* nex_input(bool rem_out = true); + virtual NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -4799,7 +4799,7 @@ class NetESignal : public NetExpr { virtual NetESignal* dup_expr() const; NetNet* synthesize(Design*des, NetScope*scope, NetExpr*root); - NexusSet* nex_input(bool rem_out = true); + NexusSet* nex_input(bool rem_out = true, bool search_funcs = false) const; const netenum_t*enumeration() const; virtual NetExpr*evaluate_function(const LineInfo&loc, diff --git a/parse.y b/parse.y index 206b6fbb9..48dbe2d9a 100644 --- a/parse.y +++ b/parse.y @@ -4852,6 +4852,18 @@ module_item { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS, $3, $1); FILE_NAME(tmp, @2); } + | attribute_list_opt K_always_comb statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_COMB, $3, $1); + FILE_NAME(tmp, @2); + } + | attribute_list_opt K_always_ff statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_FF, $3, $1); + FILE_NAME(tmp, @2); + } + | attribute_list_opt K_always_latch statement_item + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS_LATCH, $3, $1); + FILE_NAME(tmp, @2); + } | attribute_list_opt K_initial statement_item { PProcess*tmp = pform_make_behavior(IVL_PR_INITIAL, $3, $1); FILE_NAME(tmp, @2); @@ -6401,7 +6413,7 @@ statement_item /* This is roughly statement_item in the LRM */ $$ = tmp; } | K_wait K_fork ';' - { PEventStatement*tmp = new PEventStatement(0); + { PEventStatement*tmp = new PEventStatement((PEEvent*)0); FILE_NAME(tmp,@1); $$ = tmp; } diff --git a/pform.cc b/pform.cc index c1a08a29a..189528985 100644 --- a/pform.cc +++ b/pform.cc @@ -3557,6 +3557,16 @@ vector* pform_make_udp_input_ports(list*names) PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, list*attr) { + // Add an implicit @* around the statement for the always_comb and + // always_latch statements. + if ((type == IVL_PR_ALWAYS_COMB) || (type == IVL_PR_ALWAYS_LATCH)) { + PEventStatement *tmp = new PEventStatement(true); + tmp->set_file(st->get_file()); + tmp->set_lineno(st->get_lineno()); + tmp->set_statement(st); + st = tmp; + } + PProcess*pp = new PProcess(type, st); // If we are in a part of the code where the meta-comment @@ -3576,8 +3586,10 @@ PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, pform_put_behavior_in_scope(pp); ivl_assert(*st, ! pform_cur_module.empty()); - if (pform_cur_module.front()->program_block && type == IVL_PR_ALWAYS) { - cerr << st->get_fileline() << ": error: Always statements not allowed" + if (pform_cur_module.front()->program_block && + ((type == IVL_PR_ALWAYS) || (type == IVL_PR_ALWAYS_COMB) || + (type == IVL_PR_ALWAYS_FF) || (type == IVL_PR_ALWAYS_LATCH))) { + cerr << st->get_fileline() << ": error: Always statements are not allowed" << " in program blocks." << endl; error_count += 1; } diff --git a/pform_dump.cc b/pform_dump.cc index 7d57b1704..b04f348a6 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -121,6 +121,15 @@ std::ostream& operator << (std::ostream&out, ivl_process_type_t pt) case IVL_PR_ALWAYS: out << "always"; break; + case IVL_PR_ALWAYS_COMB: + out << "always_comb"; + break; + case IVL_PR_ALWAYS_FF: + out << "always_ff"; + break; + case IVL_PR_ALWAYS_LATCH: + out << "always_latch"; + break; case IVL_PR_FINAL: out << "final"; break; @@ -1176,6 +1185,11 @@ void AProcess::dump(ostream&out, unsigned ind) const case IVL_PR_ALWAYS: out << setw(ind) << "" << "analog"; break; + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: + assert(0); + break; case IVL_PR_FINAL: out << setw(ind) << "" << "analog final"; break; diff --git a/synth.cc b/synth.cc index 3e4c85a1d..cd7516d3d 100644 --- a/synth.cc +++ b/synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2012 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 @@ -134,6 +134,9 @@ void synth_f::process(Design*des, NetProcTop*top) top_ = top; switch (top->type()) { case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: proc_always_(des); break; case IVL_PR_INITIAL: diff --git a/t-dll.h b/t-dll.h index b85bb2d43..31b2106a1 100644 --- a/t-dll.h +++ b/t-dll.h @@ -1,7 +1,7 @@ #ifndef IVL_t_dll_H #define IVL_t_dll_H /* - * Copyright (c) 2000-2016 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-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 @@ -645,7 +645,7 @@ struct ivl_parameter_s { * that generally only matters for VPI calls. */ struct ivl_process_s { - ivl_process_type_t type_ : 2; + ivl_process_type_t type_ : 3; unsigned int analog_flag : 1; ivl_scope_t scope_; ivl_statement_t stmt_; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 15767349a..800c87f82 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1166,6 +1166,24 @@ static int show_process(ivl_process_t net, void*x) else fprintf(out, "always\n"); break; + case IVL_PR_ALWAYS_COMB: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_comb\n"); + break; + case IVL_PR_ALWAYS_FF: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_ff\n"); + break; + case IVL_PR_ALWAYS_LATCH: + if (ivl_process_analog(net)) + assert(0); + else + fprintf(out, "always_latch\n"); + break; case IVL_PR_FINAL: if (ivl_process_analog(net)) fprintf(out, "analog final\n"); diff --git a/tgt-verilog/verilog.c b/tgt-verilog/verilog.c index 333277a59..62616dba0 100644 --- a/tgt-verilog/verilog.c +++ b/tgt-verilog/verilog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-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 @@ -393,6 +393,9 @@ static int show_process(ivl_process_t net, void*x) fprintf(out, " initial\n"); break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(out, " always\n"); break; case IVL_PR_FINAL: diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 4fc67135f..8d2a98d5b 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2017 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1606,6 +1606,9 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc) fprintf(vlog_out, "initial"); break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(vlog_out, "always"); break; case IVL_PR_FINAL: diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 4b41a4bdf..502c2a336 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -2358,6 +2358,9 @@ int draw_process(ivl_process_t net, void*x) break; case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: fprintf(vvp_out, " %%jmp T_%u;\n", thread_count); break; } @@ -2368,6 +2371,9 @@ int draw_process(ivl_process_t net, void*x) case IVL_PR_INITIAL: case IVL_PR_ALWAYS: + case IVL_PR_ALWAYS_COMB: + case IVL_PR_ALWAYS_FF: + case IVL_PR_ALWAYS_LATCH: if (init_flag) { fprintf(vvp_out, " .thread T_%u, $init;\n", thread_count); } else if (push_flag) {