Merge pull request #966 from mole99/delayed-signals
Handle delayed signals in timing checks as assignments
This commit is contained in:
commit
ceb07dc9db
|
|
@ -119,7 +119,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
|
||||||
pform_types.o \
|
pform_types.o \
|
||||||
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \
|
symbol_search.o sync.o sys_funcs.o verinum.o verireal.o vpi_modules.o target.o \
|
||||||
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \
|
Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PFunction.o \
|
||||||
PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o \
|
PGate.o PGenerate.o PModport.o PNamedItem.o PPackage.o PScope.o PSpec.o PTimingCheck.o \
|
||||||
PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT)
|
PTask.o PUdp.o PWire.o Statement.o AStatement.o $M $(FF) $(TT)
|
||||||
|
|
||||||
all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man
|
all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man
|
||||||
|
|
|
||||||
4
Module.h
4
Module.h
|
|
@ -37,6 +37,7 @@ class PGate;
|
||||||
class PGenerate;
|
class PGenerate;
|
||||||
class PModport;
|
class PModport;
|
||||||
class PSpecPath;
|
class PSpecPath;
|
||||||
|
class PTimingCheck;
|
||||||
class PTask;
|
class PTask;
|
||||||
class PFunction;
|
class PFunction;
|
||||||
class PWire;
|
class PWire;
|
||||||
|
|
@ -136,7 +137,9 @@ class Module : public PScopeExtra, public PNamedItem {
|
||||||
program blocks. */
|
program blocks. */
|
||||||
std::map<perm_string,PModport*> modports;
|
std::map<perm_string,PModport*> modports;
|
||||||
|
|
||||||
|
/* List for specify paths and timing checks */
|
||||||
std::list<PSpecPath*> specify_paths;
|
std::list<PSpecPath*> specify_paths;
|
||||||
|
std::list<PTimingCheck*> timing_checks;
|
||||||
|
|
||||||
// The mod_name() is the name of the module type.
|
// The mod_name() is the name of the module type.
|
||||||
perm_string mod_name() const { return pscope_name(); }
|
perm_string mod_name() const { return pscope_name(); }
|
||||||
|
|
@ -170,6 +173,7 @@ class Module : public PScopeExtra, public PNamedItem {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void dump_specparams_(std::ostream&out, unsigned indent) const;
|
void dump_specparams_(std::ostream&out, unsigned indent) const;
|
||||||
|
void dump_timingchecks_(std::ostream&out, unsigned indent) const;
|
||||||
std::list<PGate*> gates_;
|
std::list<PGate*> gates_;
|
||||||
|
|
||||||
private: // Not implemented
|
private: // Not implemented
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023 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
|
||||||
|
* General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "PTimingCheck.h"
|
||||||
|
|
||||||
|
PRecRem::PRecRem(event_t* reference_event,
|
||||||
|
event_t* data_event,
|
||||||
|
PExpr* setup_limit,
|
||||||
|
PExpr* hold_limit,
|
||||||
|
pform_name_t* notifier,
|
||||||
|
PExpr* timestamp_cond,
|
||||||
|
PExpr* timecheck_cond,
|
||||||
|
pform_name_t* delayed_reference,
|
||||||
|
pform_name_t* delayed_data)
|
||||||
|
:
|
||||||
|
reference_event_ (reference_event),
|
||||||
|
data_event_ (data_event),
|
||||||
|
setup_limit_ (setup_limit),
|
||||||
|
hold_limit_ (hold_limit),
|
||||||
|
notifier_ (notifier),
|
||||||
|
timestamp_cond_ (timestamp_cond),
|
||||||
|
timecheck_cond_ (timecheck_cond),
|
||||||
|
delayed_reference_ (delayed_reference),
|
||||||
|
delayed_data_ (delayed_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PRecRem::~PRecRem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PSetupHold::PSetupHold(event_t* reference_event,
|
||||||
|
event_t* data_event,
|
||||||
|
PExpr* setup_limit,
|
||||||
|
PExpr* hold_limit,
|
||||||
|
pform_name_t* notifier,
|
||||||
|
PExpr* timestamp_cond,
|
||||||
|
PExpr* timecheck_cond,
|
||||||
|
pform_name_t* delayed_reference,
|
||||||
|
pform_name_t* delayed_data)
|
||||||
|
:
|
||||||
|
reference_event_ (reference_event),
|
||||||
|
data_event_ (data_event),
|
||||||
|
setup_limit_ (setup_limit),
|
||||||
|
hold_limit_ (hold_limit),
|
||||||
|
notifier_ (notifier),
|
||||||
|
timestamp_cond_ (timestamp_cond),
|
||||||
|
timecheck_cond_ (timecheck_cond),
|
||||||
|
delayed_reference_ (delayed_reference),
|
||||||
|
delayed_data_ (delayed_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PSetupHold::~PSetupHold()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
#ifndef IVL_PTimingCheck_H
|
||||||
|
#define IVL_PTimingCheck_H
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023 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
|
||||||
|
* General Public License as published by the Free Software
|
||||||
|
* Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
# include "LineInfo.h"
|
||||||
|
# include "PExpr.h"
|
||||||
|
# include "pform_types.h"
|
||||||
|
# include <memory>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The PTimingCheck is the base class for all timing checks
|
||||||
|
*/
|
||||||
|
class PTimingCheck : public LineInfo {
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum EdgeType {EDGE_01, EDGE_0X, EDGE_10, EDGE_1X, EDGE_X0, EDGE_X1};
|
||||||
|
|
||||||
|
struct event_t {
|
||||||
|
pform_name_t name;
|
||||||
|
bool posedge;
|
||||||
|
bool negedge;
|
||||||
|
std::vector<EdgeType> edges;
|
||||||
|
std::unique_ptr<PExpr> condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This struct is used to parse the optional arguments
|
||||||
|
struct optional_args_t {
|
||||||
|
pform_name_t* notifier = nullptr;
|
||||||
|
PExpr* timestamp_cond = nullptr;
|
||||||
|
PExpr* timecheck_cond = nullptr;
|
||||||
|
pform_name_t* delayed_reference = nullptr;
|
||||||
|
pform_name_t* delayed_data = nullptr;
|
||||||
|
PExpr* event_based_flag = nullptr;
|
||||||
|
PExpr* remain_active_flag = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
PTimingCheck() { }
|
||||||
|
virtual ~PTimingCheck() { }
|
||||||
|
|
||||||
|
virtual void elaborate(class Design*des, class NetScope*scope) const = 0;
|
||||||
|
|
||||||
|
virtual void dump(std::ostream&out, unsigned ind) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The PRecRem is the parse of a $recrem timing check
|
||||||
|
*/
|
||||||
|
class PRecRem : public PTimingCheck {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
PRecRem(event_t* reference_event,
|
||||||
|
event_t* data_event,
|
||||||
|
PExpr* setup_limit,
|
||||||
|
PExpr* hold_limit,
|
||||||
|
pform_name_t* notifier,
|
||||||
|
PExpr* timestamp_cond,
|
||||||
|
PExpr* timecheck_cond,
|
||||||
|
pform_name_t* delayed_reference,
|
||||||
|
pform_name_t* delayed_data);
|
||||||
|
|
||||||
|
~PRecRem();
|
||||||
|
|
||||||
|
void elaborate(class Design*des, class NetScope*scope) const override;
|
||||||
|
|
||||||
|
void dump(std::ostream&out, unsigned ind) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<event_t> reference_event_;
|
||||||
|
std::unique_ptr<event_t> data_event_;
|
||||||
|
|
||||||
|
std::unique_ptr<PExpr> setup_limit_;
|
||||||
|
std::unique_ptr<PExpr> hold_limit_;
|
||||||
|
|
||||||
|
std::unique_ptr<pform_name_t> notifier_;
|
||||||
|
|
||||||
|
std::unique_ptr<PExpr> timestamp_cond_;
|
||||||
|
std::unique_ptr<PExpr> timecheck_cond_;
|
||||||
|
|
||||||
|
std::unique_ptr<pform_name_t> delayed_reference_;
|
||||||
|
std::unique_ptr<pform_name_t> delayed_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The PSetupHold is the parse of a $setuphold timing check
|
||||||
|
*/
|
||||||
|
class PSetupHold : public PTimingCheck {
|
||||||
|
|
||||||
|
public:
|
||||||
|
PSetupHold(event_t* reference_event,
|
||||||
|
event_t* data_event,
|
||||||
|
PExpr* setup_limit,
|
||||||
|
PExpr* hold_limit,
|
||||||
|
pform_name_t* notifier,
|
||||||
|
PExpr* timestamp_cond,
|
||||||
|
PExpr* timecheck_cond,
|
||||||
|
pform_name_t* delayed_reference,
|
||||||
|
pform_name_t* delayed_data);
|
||||||
|
|
||||||
|
~PSetupHold();
|
||||||
|
|
||||||
|
void elaborate(class Design*des, class NetScope*scope) const override;
|
||||||
|
|
||||||
|
void dump(std::ostream&out, unsigned ind) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<event_t> reference_event_;
|
||||||
|
std::unique_ptr<event_t> data_event_;
|
||||||
|
|
||||||
|
std::unique_ptr<PExpr> setup_limit_;
|
||||||
|
std::unique_ptr<PExpr> hold_limit_;
|
||||||
|
|
||||||
|
std::unique_ptr<pform_name_t> notifier_;
|
||||||
|
|
||||||
|
std::unique_ptr<PExpr> timestamp_cond_;
|
||||||
|
std::unique_ptr<PExpr> timecheck_cond_;
|
||||||
|
|
||||||
|
std::unique_ptr<pform_name_t> delayed_reference_;
|
||||||
|
std::unique_ptr<pform_name_t> delayed_data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* IVL_PTimingCheck_H */
|
||||||
162
elaborate.cc
162
elaborate.cc
|
|
@ -41,6 +41,7 @@
|
||||||
# include "PPackage.h"
|
# include "PPackage.h"
|
||||||
# include "PScope.h"
|
# include "PScope.h"
|
||||||
# include "PSpec.h"
|
# include "PSpec.h"
|
||||||
|
# include "PTimingCheck.h"
|
||||||
# include "netlist.h"
|
# include "netlist.h"
|
||||||
# include "netenum.h"
|
# include "netenum.h"
|
||||||
# include "netvector.h"
|
# include "netvector.h"
|
||||||
|
|
@ -6331,6 +6332,140 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PRecRem::elaborate(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
// At present, no timing checks are supported.
|
||||||
|
// Still, in order to get some models working
|
||||||
|
// assign the original reference and data signals to
|
||||||
|
// the delayed reference and data signals as per
|
||||||
|
// 15.5.4 Option behavior
|
||||||
|
|
||||||
|
if (delayed_reference_ != nullptr)
|
||||||
|
{
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PRecRem::elaborate: Assigning "
|
||||||
|
<< reference_event_->name
|
||||||
|
<< " to " << *delayed_reference_ << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig = des->find_signal(scope, reference_event_->name);
|
||||||
|
|
||||||
|
if (sig == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< reference_event_->name << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig_delayed = des->find_signal(scope, *delayed_reference_);
|
||||||
|
|
||||||
|
if (sig_delayed == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< *delayed_reference_ << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sig->pin(0), sig_delayed->pin(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delayed_data_ != nullptr)
|
||||||
|
{
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PRecRem::elaborate: Assigning "
|
||||||
|
<< data_event_->name
|
||||||
|
<< " to " << *delayed_data_ << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig = des->find_signal(scope, data_event_->name);
|
||||||
|
|
||||||
|
if (sig == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< data_event_->name << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig_delayed = des->find_signal(scope, *delayed_data_);
|
||||||
|
|
||||||
|
if (sig_delayed == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< *delayed_data_ << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sig->pin(0), sig_delayed->pin(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSetupHold::elaborate(Design*des, NetScope*scope) const
|
||||||
|
{
|
||||||
|
// At present, no timing checks are supported.
|
||||||
|
// Still, in order to get some models working
|
||||||
|
// assign the original reference and data signals to
|
||||||
|
// the delayed reference and data signals as per
|
||||||
|
// 15.5.4 Option behavior
|
||||||
|
|
||||||
|
if (delayed_reference_ != nullptr)
|
||||||
|
{
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PSetupHold::elaborate: Assigning"
|
||||||
|
<< reference_event_->name
|
||||||
|
<< " to " << *delayed_reference_ << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig = des->find_signal(scope, reference_event_->name);
|
||||||
|
|
||||||
|
if (sig == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< reference_event_->name << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig_delayed = des->find_signal(scope, *delayed_reference_);
|
||||||
|
|
||||||
|
if (sig_delayed == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< *delayed_reference_ << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sig->pin(0), sig_delayed->pin(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delayed_data_ != nullptr)
|
||||||
|
{
|
||||||
|
if (debug_elaborate) {
|
||||||
|
cerr << get_fileline() << ": PSetupHold::elaborate: Assigning"
|
||||||
|
<< data_event_->name
|
||||||
|
<< " to " << *delayed_data_ << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig = des->find_signal(scope, data_event_->name);
|
||||||
|
|
||||||
|
if (sig == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< data_event_->name << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetNet*sig_delayed = des->find_signal(scope, *delayed_data_);
|
||||||
|
|
||||||
|
if (sig_delayed == nullptr) {
|
||||||
|
cerr << get_fileline() << ": error: Cannot find: "
|
||||||
|
<< *delayed_data_ << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(sig->pin(0), sig_delayed->pin(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void elaborate_functions(Design*des, NetScope*scope,
|
static void elaborate_functions(Design*des, NetScope*scope,
|
||||||
const map<perm_string,PFunction*>&funcs)
|
const map<perm_string,PFunction*>&funcs)
|
||||||
{
|
{
|
||||||
|
|
@ -6406,10 +6541,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
||||||
bool result_flag = true;
|
bool result_flag = true;
|
||||||
|
|
||||||
// Elaborate within the generate blocks.
|
// Elaborate within the generate blocks.
|
||||||
typedef list<PGenerate*>::const_iterator generate_it_t;
|
for (const auto cur : generate_schemes) {
|
||||||
for (generate_it_t cur = generate_schemes.begin()
|
cur->elaborate(des, scope);
|
||||||
; cur != generate_schemes.end() ; ++ cur ) {
|
|
||||||
(*cur)->elaborate(des, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elaborate functions.
|
// Elaborate functions.
|
||||||
|
|
@ -6428,10 +6561,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
||||||
// complex.
|
// complex.
|
||||||
const list<PGate*>&gl = get_gates();
|
const list<PGate*>&gl = get_gates();
|
||||||
|
|
||||||
for (list<PGate*>::const_iterator gt = gl.begin()
|
for (const auto gt : gl) {
|
||||||
; gt != gl.end() ; ++ gt ) {
|
gt->elaborate(des, scope);
|
||||||
|
|
||||||
(*gt)->elaborate(des, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elaborate the variable initialization statements, making a
|
// Elaborate the variable initialization statements, making a
|
||||||
|
|
@ -6444,17 +6575,18 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
||||||
result_flag &= elaborate_behaviors_(des, scope);
|
result_flag &= elaborate_behaviors_(des, scope);
|
||||||
|
|
||||||
// Elaborate the specify paths of the module.
|
// Elaborate the specify paths of the module.
|
||||||
|
for (const auto sp : specify_paths) {
|
||||||
|
sp->elaborate(des, scope);
|
||||||
|
}
|
||||||
|
|
||||||
for (list<PSpecPath*>::const_iterator sp = specify_paths.begin()
|
// Elaborate the timing checks of the module.
|
||||||
; sp != specify_paths.end() ; ++ sp ) {
|
for (const auto tc : timing_checks) {
|
||||||
|
tc->elaborate(des, scope);
|
||||||
(*sp)->elaborate(des, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elaborate the elaboration tasks.
|
// Elaborate the elaboration tasks.
|
||||||
for (list<PCallTask*>::const_iterator et = elab_tasks.begin()
|
for (const auto et : elab_tasks) {
|
||||||
; et != elab_tasks.end() ; ++ et ) {
|
result_flag &= et->elaborate_elab(des, scope);
|
||||||
result_flag &= (*et)->elaborate_elab(des, scope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result_flag;
|
return result_flag;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Check that when timing checks are disabled (or in the case of Icarus Verilog not supported)
|
||||||
|
// that the delayed reference and data signals become copies of the original reference and data signals
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
wire sig1, sig2, del_sig1, del_sig2, del_sig3, del_sig4, notifier, cond1, cond2;
|
||||||
|
|
||||||
|
assign sig1 = 1'b0;
|
||||||
|
assign sig2 = 1'b1;
|
||||||
|
|
||||||
|
specify
|
||||||
|
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier , cond1 , cond2 , del_sig1 , del_sig2 ) ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Internally the simulator does the following:
|
||||||
|
assign del_sig1 = sig1;
|
||||||
|
assign del_sig2 = sig2;
|
||||||
|
*/
|
||||||
|
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier, cond1 , cond2 , del_sig3 , del_sig4 );
|
||||||
|
|
||||||
|
/*
|
||||||
|
Internally the simulator does the following:
|
||||||
|
assign del_sig3 = sig1;
|
||||||
|
assign del_sig4 = sig2;
|
||||||
|
*/
|
||||||
|
|
||||||
|
endspecify
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
|
||||||
|
if (del_sig1 == 1'b0 && del_sig2 == 1'b1 && del_sig3 == 1'b0 && del_sig4 == 1'b1)
|
||||||
|
$display("PASSED");
|
||||||
|
else
|
||||||
|
$display("FAILED");
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
// Check that various timing checks can be parsed
|
||||||
|
|
||||||
|
module test;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$display("PASSED");
|
||||||
|
end
|
||||||
|
|
||||||
|
wire sig1, sig2, del_sig1, del_sig2, notifier, cond1, cond2;
|
||||||
|
|
||||||
|
specify
|
||||||
|
$setup(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$setup(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$setup(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$setup(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$setup(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$setup(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$setup(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$hold(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$hold(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$hold(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$hold(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$hold(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$hold(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$hold(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$setuphold(posedge sig1 , negedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(negedge sig1 , posedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier, cond1 , cond2) ;
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier, cond1 , cond2 , del_sig1 , del_sig2 ) ;
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 , del_sig2 ) ;
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 , del_sig2 ) ;
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,,, del_sig2 ) ;
|
||||||
|
$setuphold(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 ,) ;
|
||||||
|
$setuphold(edge [10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$setuphold(posedge sig1 , edge [10, x0, 1x] sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$removal(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$removal(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$removal(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$removal(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$removal(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$removal(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$removal(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$recovery(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$recovery(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$recovery(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$recovery(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$recovery(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$recovery(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$recovery(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$recrem(posedge sig1 , negedge sig2 , 0:0:0 , 0:0:0);
|
||||||
|
$recrem(negedge sig1 , posedge sig2 , 0:0:0 , 0:0:0);
|
||||||
|
$recrem(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$recrem(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier, cond1 , cond2);
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier, cond1 , cond2 , del_sig1 , del_sig2 );
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 , del_sig2 );
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 , del_sig2 );
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,,, del_sig2 );
|
||||||
|
$recrem(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier,,, del_sig1 ,);
|
||||||
|
$recrem(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$recrem(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$skew(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$skew(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$skew(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$skew(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$skew(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$skew(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$skew(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
|
||||||
|
$timeskew(posedge sig1 , negedge sig2 , 0:0:0);
|
||||||
|
$timeskew(negedge sig1 , posedge sig2 , 0:0:0);
|
||||||
|
$timeskew(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$timeskew(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , notifier);
|
||||||
|
$timeskew(posedge sig1, negedge sig2 , 0:0:0 , notifier);
|
||||||
|
$timeskew(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , notifier);
|
||||||
|
$timeskew(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , notifier);
|
||||||
|
$timeskew(posedge sig1 , negedge sig2 , 0:0:0 , notifier , 1'b0);
|
||||||
|
$timeskew(negedge sig1 , posedge sig2 , 0:0:0 , notifier , 1'b1 , 1'b0);
|
||||||
|
$timeskew(negedge sig1 , posedge sig2 , 0:0:0 , , , 1'b1);
|
||||||
|
|
||||||
|
$fullskew(posedge sig1 , negedge sig2 , 0:0:0 , 0:0:0);
|
||||||
|
$fullskew(negedge sig1 , posedge sig2 , 0:0:0 , 0:0:0);
|
||||||
|
$fullskew(posedge sig1 &&& cond1 == cond2 , posedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$fullskew(negedge sig1 &&& cond1 == cond2 , negedge sig2 &&& cond1 == cond2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$fullskew(posedge sig1, negedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$fullskew(edge[10, x0, 1x] sig1 , posedge sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$fullskew(posedge sig1 , edge[10, x0, 1x] sig2 , 0:0:0 , 0:0:0 , notifier);
|
||||||
|
$fullskew(posedge sig1 , negedge sig2 , 0:0:0 , 0:0:0 , notifier , 1'b0);
|
||||||
|
$fullskew(negedge sig1 , posedge sig2 , 0:0:0 , 0:0:0 , notifier , 1'b1 , 1'b0);
|
||||||
|
$fullskew(negedge sig1 , posedge sig2 , 0:0:0 , 0:0:0 , , , 1'b1);
|
||||||
|
|
||||||
|
$width(posedge sig1 , 0:0:0 );
|
||||||
|
$width(posedge sig1 &&& cond1 , 0:0:0 , 0 );
|
||||||
|
$width(posedge sig1 &&& cond1 , 0:0:0 , 0 , notifier );
|
||||||
|
$width(edge[10, x0, 1x] sig1 &&& cond1 , 0:0:0 );
|
||||||
|
|
||||||
|
$period(posedge sig1 , 0:0:0 );
|
||||||
|
$period(negedge sig1 &&& cond1 , 0:0:0 , notifier );
|
||||||
|
$period(edge[10, x0, 1x] sig1 &&& cond1 , 0:0:0 );
|
||||||
|
|
||||||
|
$nochange(posedge sig1 , posedge sig2 , 10 , 20 );
|
||||||
|
$nochange(negedge sig1 &&& cond1 , posedge sig2 , 10 , 20 );
|
||||||
|
$nochange(negedge sig1 , posedge sig2 &&& cond1 , 10 , 20 , notifier );
|
||||||
|
$nochange(edge[10, x0, 1x] sig1 &&& cond1 , posedge sig2 , 10 , 20 );
|
||||||
|
$nochange(posedge sig1 &&& cond1 , edge[10, x0, 1x] sig2 , 10 , 20 );
|
||||||
|
|
||||||
|
endspecify
|
||||||
|
endmodule
|
||||||
|
|
@ -72,3 +72,5 @@ task_return1 vvp_tests/task_return1.json
|
||||||
task_return2 vvp_tests/task_return2.json
|
task_return2 vvp_tests/task_return2.json
|
||||||
task_return_fail1 vvp_tests/task_return_fail1.json
|
task_return_fail1 vvp_tests/task_return_fail1.json
|
||||||
task_return_fail2 vvp_tests/task_return_fail2.json
|
task_return_fail2 vvp_tests/task_return_fail2.json
|
||||||
|
timing_check_syntax vvp_tests/timing_check_syntax.json
|
||||||
|
timing_check_delayed_signals vvp_tests/timing_check_delayed_signals.json
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "timing_check_delayed_signals.v"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"type" : "normal",
|
||||||
|
"source" : "timing_check_syntax.v"
|
||||||
|
}
|
||||||
513
parse.y
513
parse.y
|
|
@ -28,10 +28,12 @@
|
||||||
# include "pform.h"
|
# include "pform.h"
|
||||||
# include "Statement.h"
|
# include "Statement.h"
|
||||||
# include "PSpec.h"
|
# include "PSpec.h"
|
||||||
|
# include "PTimingCheck.h"
|
||||||
# include "PPackage.h"
|
# include "PPackage.h"
|
||||||
# include <stack>
|
# include <stack>
|
||||||
# include <cstring>
|
# include <cstring>
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
|
# include <memory>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
@ -87,13 +89,6 @@ static pform_name_t* pform_create_super(void)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is used to keep track of the extra arguments after the notifier
|
|
||||||
* in the $setuphold and $recrem timing checks. This allows us to print
|
|
||||||
* a warning message that the delayed signals will not be created. We
|
|
||||||
* need to do this since not driving these signals creates real
|
|
||||||
* simulation issues. */
|
|
||||||
static unsigned args_after_notifier;
|
|
||||||
|
|
||||||
/* The rules sometimes push attributes into a global context where
|
/* The rules sometimes push attributes into a global context where
|
||||||
sub-rules may grab them. This makes parser rules a little easier to
|
sub-rules may grab them. This makes parser rules a little easier to
|
||||||
write in some cases. */
|
write in some cases. */
|
||||||
|
|
@ -530,6 +525,9 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
|
||||||
PSpecPath* specpath;
|
PSpecPath* specpath;
|
||||||
std::list<index_component_t> *dimensions;
|
std::list<index_component_t> *dimensions;
|
||||||
|
|
||||||
|
PTimingCheck::event_t* timing_check_event;
|
||||||
|
PTimingCheck::optional_args_t* spec_optional_args;
|
||||||
|
|
||||||
LexicalScope::lifetime_t lifetime;
|
LexicalScope::lifetime_t lifetime;
|
||||||
|
|
||||||
enum typedef_t::basic_type typedef_basic_type;
|
enum typedef_t::basic_type typedef_basic_type;
|
||||||
|
|
@ -696,6 +694,15 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
|
||||||
%type <let_port_itm> let_port_item
|
%type <let_port_itm> let_port_item
|
||||||
|
|
||||||
%type <pform_name> hierarchy_identifier implicit_class_handle class_hierarchy_identifier
|
%type <pform_name> hierarchy_identifier implicit_class_handle class_hierarchy_identifier
|
||||||
|
%type <pform_name> spec_notifier_opt spec_notifier
|
||||||
|
%type <timing_check_event> spec_reference_event
|
||||||
|
%type <spec_optional_args> setuphold_opt_args recrem_opt_args setuphold_recrem_opt_notifier
|
||||||
|
%type <spec_optional_args> setuphold_recrem_opt_timestamp_cond setuphold_recrem_opt_timecheck_cond
|
||||||
|
%type <spec_optional_args> setuphold_recrem_opt_delayed_reference setuphold_recrem_opt_delayed_data
|
||||||
|
%type <spec_optional_args> timeskew_opt_args fullskew_opt_args
|
||||||
|
%type <spec_optional_args> timeskew_fullskew_opt_notifier timeskew_fullskew_opt_event_based_flag
|
||||||
|
%type <spec_optional_args> timeskew_fullskew_opt_remain_active_flag
|
||||||
|
|
||||||
%type <expr> assignment_pattern expression expr_mintypmax
|
%type <expr> assignment_pattern expression expr_mintypmax
|
||||||
%type <expr> expr_primary_or_typename expr_primary
|
%type <expr> expr_primary_or_typename expr_primary
|
||||||
%type <expr> class_new dynamic_array_new
|
%type <expr> class_new dynamic_array_new
|
||||||
|
|
@ -5900,72 +5907,169 @@ specify_item
|
||||||
yyerrok;
|
yyerrok;
|
||||||
}
|
}
|
||||||
| K_Sfullskew '(' spec_reference_event ',' spec_reference_event
|
| K_Sfullskew '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value ',' delay_value fullskew_opt_args ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
delete $9;
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $9; // delay_value
|
||||||
|
|
||||||
|
delete $10->notifier;
|
||||||
|
delete $10->event_based_flag;
|
||||||
|
delete $10->remain_active_flag;
|
||||||
|
|
||||||
|
delete $10; // fullskew_opt_args
|
||||||
}
|
}
|
||||||
| K_Shold '(' spec_reference_event ',' spec_reference_event
|
| K_Shold '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $8; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Snochange '(' spec_reference_event ',' spec_reference_event
|
| K_Snochange '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
delete $9;
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $9; // delay_value
|
||||||
|
delete $10; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Speriod '(' spec_reference_event ',' delay_value
|
| K_Speriod '(' spec_reference_event ',' delay_value
|
||||||
spec_notifier_opt ')' ';'
|
spec_notifier_opt ')' ';'
|
||||||
{ delete $5;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // delay_value
|
||||||
|
delete $6; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Srecovery '(' spec_reference_event ',' spec_reference_event
|
| K_Srecovery '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $8; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Srecrem '(' spec_reference_event ',' spec_reference_event
|
| K_Srecrem '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
|
',' expr_mintypmax ',' expr_mintypmax recrem_opt_args ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
delete $9;
|
cerr << @3 << ": warning: Timing checks are not supported. ";
|
||||||
|
if ($10->delayed_reference != nullptr || $10->delayed_data != nullptr)
|
||||||
|
{
|
||||||
|
cerr << "Delayed reference and data signals become copies of the"
|
||||||
|
<< " original reference and data signals." << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRecRem*recrem = pform_make_recrem(@1, $3, $5, $7, $9, $10);
|
||||||
|
pform_module_timing_check(recrem);
|
||||||
|
|
||||||
|
delete $10; // setuphold_recrem_opt_notifier
|
||||||
}
|
}
|
||||||
| K_Sremoval '(' spec_reference_event ',' spec_reference_event
|
| K_Sremoval '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $8; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Ssetup '(' spec_reference_event ',' spec_reference_event
|
| K_Ssetup '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $8; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Ssetuphold '(' spec_reference_event ',' spec_reference_event
|
| K_Ssetuphold '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
|
',' expr_mintypmax ',' expr_mintypmax setuphold_opt_args ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
delete $9;
|
cerr << @3 << ": warning: Timing checks are not supported. ";
|
||||||
|
if ($10->delayed_reference != nullptr || $10->delayed_data != nullptr)
|
||||||
|
{
|
||||||
|
cerr << "Delayed reference and data signals become copies of the"
|
||||||
|
<< " original reference and data signals." << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
PSetupHold*setuphold = pform_make_setuphold(@1, $3, $5, $7, $9, $10);
|
||||||
|
pform_module_timing_check(setuphold);
|
||||||
|
|
||||||
|
delete $10; // setuphold_recrem_opt_notifier
|
||||||
}
|
}
|
||||||
| K_Sskew '(' spec_reference_event ',' spec_reference_event
|
| K_Sskew '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value spec_notifier_opt ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
delete $8; // spec_notifier_opt
|
||||||
}
|
}
|
||||||
| K_Stimeskew '(' spec_reference_event ',' spec_reference_event
|
| K_Stimeskew '(' spec_reference_event ',' spec_reference_event
|
||||||
',' delay_value spec_notifier_opt ')' ';'
|
',' delay_value timeskew_opt_args ')' ';'
|
||||||
{ delete $7;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // spec_reference_event
|
||||||
|
delete $7; // delay_value
|
||||||
|
|
||||||
|
delete $8->notifier;
|
||||||
|
delete $8->event_based_flag;
|
||||||
|
delete $8->remain_active_flag;
|
||||||
|
|
||||||
|
delete $8; // timeskew_opt_args
|
||||||
}
|
}
|
||||||
| K_Swidth '(' spec_reference_event ',' delay_value ',' expression
|
| K_Swidth '(' spec_reference_event ',' delay_value ',' expression
|
||||||
spec_notifier_opt ')' ';'
|
spec_notifier_opt ')' ';'
|
||||||
{ delete $5;
|
{
|
||||||
delete $7;
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // delay_value
|
||||||
|
delete $7; // expression
|
||||||
|
delete $8;
|
||||||
}
|
}
|
||||||
| K_Swidth '(' spec_reference_event ',' delay_value ')' ';'
|
| K_Swidth '(' spec_reference_event ',' delay_value ')' ';'
|
||||||
{ delete $5;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $3; // spec_reference_event
|
||||||
|
delete $5; // delay_value
|
||||||
}
|
}
|
||||||
| K_pulsestyle_onevent specify_path_identifiers ';'
|
| K_pulsestyle_onevent specify_path_identifiers ';'
|
||||||
{ delete $2;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $2; // specify_path_identifiers
|
||||||
}
|
}
|
||||||
| K_pulsestyle_ondetect specify_path_identifiers ';'
|
| K_pulsestyle_ondetect specify_path_identifiers ';'
|
||||||
{ delete $2;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $2; // specify_path_identifiers
|
||||||
}
|
}
|
||||||
| K_showcancelled specify_path_identifiers ';'
|
| K_showcancelled specify_path_identifiers ';'
|
||||||
{ delete $2;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $2; // specify_path_identifiers
|
||||||
}
|
}
|
||||||
| K_noshowcancelled specify_path_identifiers ';'
|
| K_noshowcancelled specify_path_identifiers ';'
|
||||||
{ delete $2;
|
{
|
||||||
|
cerr << @3 << ": warning: Timing checks are not supported." << endl;
|
||||||
|
delete $2; // specify_path_identifiers
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -6110,47 +6214,8 @@ specify_path_identifiers
|
||||||
;
|
;
|
||||||
|
|
||||||
specparam
|
specparam
|
||||||
: IDENTIFIER '=' expression
|
: IDENTIFIER '=' expr_mintypmax
|
||||||
{ PExpr*tmp = $3;
|
{ pform_set_specparam(@1, lex_strings.make($1), specparam_active_range, $3);
|
||||||
pform_set_specparam(@1, lex_strings.make($1), specparam_active_range, tmp);
|
|
||||||
delete[]$1;
|
|
||||||
}
|
|
||||||
| IDENTIFIER '=' expression ':' expression ':' expression
|
|
||||||
{ PExpr*tmp = 0;
|
|
||||||
switch (min_typ_max_flag) {
|
|
||||||
case MIN:
|
|
||||||
tmp = $3;
|
|
||||||
delete $5;
|
|
||||||
delete $7;
|
|
||||||
break;
|
|
||||||
case TYP:
|
|
||||||
delete $3;
|
|
||||||
tmp = $5;
|
|
||||||
delete $7;
|
|
||||||
break;
|
|
||||||
case MAX:
|
|
||||||
delete $3;
|
|
||||||
delete $5;
|
|
||||||
tmp = $7;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (min_typ_max_warn > 0) {
|
|
||||||
cerr << tmp->get_fileline() << ": warning: Choosing ";
|
|
||||||
switch (min_typ_max_flag) {
|
|
||||||
case MIN:
|
|
||||||
cerr << "min";
|
|
||||||
break;
|
|
||||||
case TYP:
|
|
||||||
cerr << "typ";
|
|
||||||
break;
|
|
||||||
case MAX:
|
|
||||||
cerr << "max";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cerr << " expression." << endl;
|
|
||||||
min_typ_max_warn -= 1;
|
|
||||||
}
|
|
||||||
pform_set_specparam(@1, lex_strings.make($1), specparam_active_range, tmp);
|
|
||||||
delete[]$1;
|
delete[]$1;
|
||||||
}
|
}
|
||||||
| PATHPULSE_IDENTIFIER '=' expression
|
| PATHPULSE_IDENTIFIER '=' expression
|
||||||
|
|
@ -6183,31 +6248,82 @@ spec_polarity
|
||||||
| { $$ = 0; }
|
| { $$ = 0; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
// TODO spec_controlled_reference_event
|
||||||
spec_reference_event
|
spec_reference_event
|
||||||
: K_posedge expression
|
: hierarchy_identifier
|
||||||
{ delete $2; }
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
| K_negedge expression
|
event->name = *$1;
|
||||||
{ delete $2; }
|
event->posedge = false;
|
||||||
| K_posedge expr_primary K_TAND expression
|
event->negedge = false;
|
||||||
{ delete $2;
|
event->condition = nullptr;
|
||||||
delete $4;
|
delete $1;
|
||||||
|
$$ = event;
|
||||||
}
|
}
|
||||||
| K_negedge expr_primary K_TAND expression
|
| hierarchy_identifier K_TAND expression
|
||||||
{ delete $2;
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
delete $4;
|
event->name = *$1;
|
||||||
|
event->posedge = false;
|
||||||
|
event->negedge = false;
|
||||||
|
event->condition = std::unique_ptr<PExpr>($3);
|
||||||
|
delete $1;
|
||||||
|
$$ = event;
|
||||||
}
|
}
|
||||||
| K_edge '[' edge_descriptor_list ']' expr_primary
|
| K_posedge hierarchy_identifier
|
||||||
{ delete $5; }
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
| K_edge '[' edge_descriptor_list ']' expr_primary K_TAND expression
|
event->name = *$2;
|
||||||
{ delete $5;
|
event->posedge = true;
|
||||||
delete $7;
|
event->negedge = false;
|
||||||
|
event->condition = nullptr;
|
||||||
|
delete $2;
|
||||||
|
$$ = event;
|
||||||
}
|
}
|
||||||
| expr_primary K_TAND expression
|
| K_negedge hierarchy_identifier
|
||||||
{ delete $1;
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
delete $3;
|
event->name = *$2;
|
||||||
|
event->posedge = false;
|
||||||
|
event->negedge = true;
|
||||||
|
event->condition = nullptr;
|
||||||
|
delete $2;
|
||||||
|
$$ = event;
|
||||||
|
}
|
||||||
|
| K_posedge hierarchy_identifier K_TAND expression
|
||||||
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
|
event->name = *$2;
|
||||||
|
event->posedge = true;
|
||||||
|
event->negedge = false;
|
||||||
|
event->condition = std::unique_ptr<PExpr>($4);
|
||||||
|
delete $2;
|
||||||
|
$$ = event;
|
||||||
|
}
|
||||||
|
| K_negedge hierarchy_identifier K_TAND expression
|
||||||
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
|
event->name = *$2;
|
||||||
|
event->posedge = false;
|
||||||
|
event->negedge = true;
|
||||||
|
event->condition = std::unique_ptr<PExpr>($4);
|
||||||
|
delete $2;
|
||||||
|
$$ = event;
|
||||||
|
}
|
||||||
|
| K_edge '[' edge_descriptor_list ']' hierarchy_identifier
|
||||||
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
|
event->name = *$5;
|
||||||
|
event->posedge = false;
|
||||||
|
event->negedge = false;
|
||||||
|
// TODO add edge descriptors
|
||||||
|
event->condition = nullptr;
|
||||||
|
delete $5;
|
||||||
|
$$ = event;
|
||||||
|
}
|
||||||
|
| K_edge '[' edge_descriptor_list ']' hierarchy_identifier K_TAND expression
|
||||||
|
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
|
||||||
|
event->name = *$5;
|
||||||
|
event->posedge = false;
|
||||||
|
event->negedge = false;
|
||||||
|
// TODO add edge descriptors
|
||||||
|
event->condition = std::unique_ptr<PExpr>($7);
|
||||||
|
delete $5;
|
||||||
|
$$ = event;
|
||||||
}
|
}
|
||||||
| expr_primary
|
|
||||||
{ delete $1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
/* The edge_descriptor is detected by the lexor as the various
|
/* The edge_descriptor is detected by the lexor as the various
|
||||||
|
|
@ -6219,31 +6335,204 @@ edge_descriptor_list
|
||||||
| K_edge_descriptor
|
| K_edge_descriptor
|
||||||
;
|
;
|
||||||
|
|
||||||
|
setuphold_opt_args
|
||||||
|
: setuphold_recrem_opt_notifier
|
||||||
|
{ $$ = $1; }
|
||||||
|
|
|
||||||
|
{ $$ = new PTimingCheck::optional_args_t; }
|
||||||
|
;
|
||||||
|
|
||||||
|
recrem_opt_args
|
||||||
|
: setuphold_recrem_opt_notifier
|
||||||
|
{ $$ = $1; }
|
||||||
|
|
|
||||||
|
{ $$ = new PTimingCheck::optional_args_t; }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* The following rules are used for the optional arguments
|
||||||
|
in $recrem and $setuphold */
|
||||||
|
setuphold_recrem_opt_notifier
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' hierarchy_identifier // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->notifier = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' setuphold_recrem_opt_timestamp_cond // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' hierarchy_identifier setuphold_recrem_opt_timestamp_cond
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->notifier = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
setuphold_recrem_opt_timestamp_cond
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' expression // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->timestamp_cond = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' setuphold_recrem_opt_timecheck_cond // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' expression setuphold_recrem_opt_timecheck_cond
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->timestamp_cond = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
setuphold_recrem_opt_timecheck_cond
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' expression // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->timecheck_cond = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' setuphold_recrem_opt_delayed_reference // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' expression setuphold_recrem_opt_delayed_reference
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->timecheck_cond = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
setuphold_recrem_opt_delayed_reference
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' hierarchy_identifier // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->delayed_reference = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' setuphold_recrem_opt_delayed_data // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' hierarchy_identifier setuphold_recrem_opt_delayed_data
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->delayed_reference = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
setuphold_recrem_opt_delayed_data
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' hierarchy_identifier // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->delayed_data = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
timeskew_opt_args
|
||||||
|
: timeskew_fullskew_opt_notifier
|
||||||
|
{ $$ = $1; }
|
||||||
|
|
|
||||||
|
{ $$ = new PTimingCheck::optional_args_t; }
|
||||||
|
;
|
||||||
|
|
||||||
|
fullskew_opt_args
|
||||||
|
: timeskew_fullskew_opt_notifier
|
||||||
|
{ $$ = $1; }
|
||||||
|
|
|
||||||
|
{ $$ = new PTimingCheck::optional_args_t; }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* The following rules are used for the optional arguments
|
||||||
|
in $timeskew and $fullskew */
|
||||||
|
timeskew_fullskew_opt_notifier
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' hierarchy_identifier // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->notifier = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' timeskew_fullskew_opt_event_based_flag // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' hierarchy_identifier timeskew_fullskew_opt_event_based_flag
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->notifier = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
timeskew_fullskew_opt_event_based_flag
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' expression // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->event_based_flag = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' timeskew_fullskew_opt_remain_active_flag // Empty
|
||||||
|
{ $$ = $2; }
|
||||||
|
| ',' expression timeskew_fullskew_opt_remain_active_flag
|
||||||
|
{
|
||||||
|
$$ = $3;
|
||||||
|
$$->event_based_flag = $2;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
timeskew_fullskew_opt_remain_active_flag
|
||||||
|
: ',' // Empty and end of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
| ',' expression // End of list
|
||||||
|
{
|
||||||
|
PTimingCheck::optional_args_t* args = new PTimingCheck::optional_args_t;
|
||||||
|
args->remain_active_flag = $2;
|
||||||
|
$$ = args;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
spec_notifier_opt
|
spec_notifier_opt
|
||||||
: /* empty */
|
: /* empty */
|
||||||
{ }
|
{ $$ = nullptr; }
|
||||||
| spec_notifier
|
| spec_notifier
|
||||||
{ }
|
{ $$ = $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
spec_notifier
|
spec_notifier
|
||||||
: ','
|
: ','
|
||||||
{ args_after_notifier = 0; }
|
{ $$ = nullptr; }
|
||||||
| ',' hierarchy_identifier
|
| ',' hierarchy_identifier
|
||||||
{ args_after_notifier = 0; delete $2; }
|
{ $$ = $2; }
|
||||||
| spec_notifier ','
|
|
||||||
{ args_after_notifier += 1; }
|
|
||||||
| spec_notifier ',' hierarchy_identifier
|
|
||||||
{ args_after_notifier += 1;
|
|
||||||
if (args_after_notifier >= 3) {
|
|
||||||
cerr << @3 << ": warning: Timing checks are not supported "
|
|
||||||
"and delayed signal \"" << *$3
|
|
||||||
<< "\" will not be driven." << endl;
|
|
||||||
}
|
|
||||||
delete $3;
|
|
||||||
}
|
|
||||||
/* How do we match this path? */
|
|
||||||
| IDENTIFIER
|
|
||||||
{ args_after_notifier = 0; delete[]$1; }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
subroutine_call
|
subroutine_call
|
||||||
|
|
|
||||||
63
pform.cc
63
pform.cc
|
|
@ -32,6 +32,7 @@
|
||||||
# include "PGenerate.h"
|
# include "PGenerate.h"
|
||||||
# include "PModport.h"
|
# include "PModport.h"
|
||||||
# include "PSpec.h"
|
# include "PSpec.h"
|
||||||
|
# include "PTimingCheck.h"
|
||||||
# include "discipline.h"
|
# include "discipline.h"
|
||||||
# include <list>
|
# include <list>
|
||||||
# include <map>
|
# include <map>
|
||||||
|
|
@ -3109,6 +3110,68 @@ extern void pform_module_specify_path(PSpecPath*obj)
|
||||||
pform_cur_module.front()->specify_paths.push_back(obj);
|
pform_cur_module.front()->specify_paths.push_back(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timing checks.
|
||||||
|
*/
|
||||||
|
extern PRecRem* pform_make_recrem(const struct vlltype&li,
|
||||||
|
PTimingCheck::event_t*reference_event,
|
||||||
|
PTimingCheck::event_t*data_event,
|
||||||
|
PExpr*setup_limit,
|
||||||
|
PExpr*hold_limit,
|
||||||
|
PTimingCheck::optional_args_t* args)
|
||||||
|
{
|
||||||
|
ivl_assert(li, args);
|
||||||
|
|
||||||
|
PRecRem*recrem = new PRecRem(
|
||||||
|
reference_event,
|
||||||
|
data_event,
|
||||||
|
setup_limit,
|
||||||
|
hold_limit,
|
||||||
|
args->notifier,
|
||||||
|
args->timestamp_cond,
|
||||||
|
args->timecheck_cond,
|
||||||
|
args->delayed_reference,
|
||||||
|
args->delayed_data
|
||||||
|
);
|
||||||
|
|
||||||
|
FILE_NAME(recrem, li);
|
||||||
|
|
||||||
|
return recrem;
|
||||||
|
}
|
||||||
|
extern PSetupHold* pform_make_setuphold(const struct vlltype&li,
|
||||||
|
PTimingCheck::event_t*reference_event,
|
||||||
|
PTimingCheck::event_t*data_event,
|
||||||
|
PExpr*setup_limit,
|
||||||
|
PExpr*hold_limit,
|
||||||
|
PTimingCheck::optional_args_t* args)
|
||||||
|
{
|
||||||
|
ivl_assert(li, args);
|
||||||
|
|
||||||
|
PSetupHold*setuphold = new PSetupHold(
|
||||||
|
reference_event,
|
||||||
|
data_event,
|
||||||
|
setup_limit,
|
||||||
|
hold_limit,
|
||||||
|
args->notifier,
|
||||||
|
args->timestamp_cond,
|
||||||
|
args->timecheck_cond,
|
||||||
|
args->delayed_reference,
|
||||||
|
args->delayed_data
|
||||||
|
);
|
||||||
|
|
||||||
|
FILE_NAME(setuphold, li);
|
||||||
|
|
||||||
|
return setuphold;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void pform_module_timing_check(PTimingCheck*obj)
|
||||||
|
{
|
||||||
|
if (!obj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pform_cur_module.front()->timing_checks.push_back(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void pform_set_port_type(const struct vlltype&li,
|
void pform_set_port_type(const struct vlltype&li,
|
||||||
list<pform_port_t>*ports,
|
list<pform_port_t>*ports,
|
||||||
|
|
|
||||||
20
pform.h
20
pform.h
|
|
@ -30,6 +30,7 @@
|
||||||
# include "PTask.h"
|
# include "PTask.h"
|
||||||
# include "PUdp.h"
|
# include "PUdp.h"
|
||||||
# include "PWire.h"
|
# include "PWire.h"
|
||||||
|
# include "PTimingCheck.h"
|
||||||
# include "verinum.h"
|
# include "verinum.h"
|
||||||
# include "discipline.h"
|
# include "discipline.h"
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
|
@ -429,6 +430,25 @@ extern PSpecPath*pform_assign_path_delay(PSpecPath*obj, std::list<PExpr*>*delays
|
||||||
|
|
||||||
extern void pform_module_specify_path(PSpecPath*obj);
|
extern void pform_module_specify_path(PSpecPath*obj);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions related to timing checks.
|
||||||
|
*/
|
||||||
|
extern PRecRem* pform_make_recrem(const struct vlltype&li,
|
||||||
|
PTimingCheck::event_t*reference_event,
|
||||||
|
PTimingCheck::event_t*data_event,
|
||||||
|
PExpr*setup_limit,
|
||||||
|
PExpr*hold_limit,
|
||||||
|
PTimingCheck::optional_args_t* args
|
||||||
|
);
|
||||||
|
extern PSetupHold* pform_make_setuphold(const struct vlltype&li,
|
||||||
|
PTimingCheck::event_t*reference_event,
|
||||||
|
PTimingCheck::event_t*data_event,
|
||||||
|
PExpr*setup_limit,
|
||||||
|
PExpr*hold_limit,
|
||||||
|
PTimingCheck::optional_args_t* args
|
||||||
|
);
|
||||||
|
extern void pform_module_timing_check(PTimingCheck*obj);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pform_make_behavior creates processes that are declared with always
|
* pform_make_behavior creates processes that are declared with always
|
||||||
* or initial items.
|
* or initial items.
|
||||||
|
|
|
||||||
|
|
@ -1442,6 +1442,16 @@ void PSpecPath::dump(std::ostream&out, unsigned ind) const
|
||||||
out << ");" << endl;
|
out << ");" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PRecRem::dump(std::ostream&out, unsigned ind) const
|
||||||
|
{
|
||||||
|
out << setw(ind) << "" << "recrem ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PSetupHold::dump(std::ostream&out, unsigned ind) const
|
||||||
|
{
|
||||||
|
out << setw(ind) << "" << "setuphold ";
|
||||||
|
}
|
||||||
|
|
||||||
void PGenerate::dump(ostream&out, unsigned indent) const
|
void PGenerate::dump(ostream&out, unsigned indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "generate(" << id_number << ")";
|
out << setw(indent) << "" << "generate(" << id_number << ")";
|
||||||
|
|
@ -1704,6 +1714,15 @@ void Module::dump_specparams_(ostream&out, unsigned indent) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Module::dump_timingchecks_(ostream&out, unsigned indent) const
|
||||||
|
{
|
||||||
|
cout << "dump_timingchecks_" << endl;
|
||||||
|
|
||||||
|
for (const auto cur : timing_checks) {
|
||||||
|
cur->dump(out, indent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Module::dump(ostream&out) const
|
void Module::dump(ostream&out) const
|
||||||
{
|
{
|
||||||
if (attributes.begin() != attributes.end()) {
|
if (attributes.begin() != attributes.end()) {
|
||||||
|
|
@ -1752,6 +1771,8 @@ void Module::dump(ostream&out) const
|
||||||
|
|
||||||
dump_specparams_(out, 4);
|
dump_specparams_(out, 4);
|
||||||
|
|
||||||
|
dump_timingchecks_(out, 4);
|
||||||
|
|
||||||
dump_enumerations_(out, 4);
|
dump_enumerations_(out, 4);
|
||||||
|
|
||||||
dump_classes_(out, 4);
|
dump_classes_(out, 4);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue