Handle delayed signals in timing checks as assignments

This commit is contained in:
mole99 2023-07-05 16:22:08 +02:00
parent 272771d183
commit 87885dbd9b
9 changed files with 719 additions and 114 deletions

View File

@ -119,7 +119,7 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \
pform_types.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 \
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)
all: dep config.h _pli_types.h version_tag.h ivl@EXEEXT@ version.exe iverilog-vpi.man

View File

@ -37,6 +37,7 @@ class PGate;
class PGenerate;
class PModport;
class PSpecPath;
class PTimingCheck;
class PTask;
class PFunction;
class PWire;
@ -136,7 +137,9 @@ class Module : public PScopeExtra, public PNamedItem {
program blocks. */
std::map<perm_string,PModport*> modports;
/* List for specify paths and timing checks */
std::list<PSpecPath*> specify_paths;
std::list<PTimingCheck*> timing_checks;
// The mod_name() is the name of the module type.
perm_string mod_name() const { return pscope_name(); }
@ -170,6 +173,7 @@ class Module : public PScopeExtra, public PNamedItem {
private:
void dump_specparams_(std::ostream&out, unsigned indent) const;
void dump_timingchecks_(std::ostream&out, unsigned indent) const;
std::list<PGate*> gates_;
private: // Not implemented

94
PTimingCheck.cc Normal file
View File

@ -0,0 +1,94 @@
/*
* 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,
pform_name_t* timestamp_cond,
pform_name_t* 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()
{
// Delete optional arguments
if (reference_event_.condition) delete reference_event_.condition;
if (data_event_.condition) delete data_event_.condition;
if(notifier_) delete notifier_;
if(timestamp_cond_) delete timestamp_cond_;
if(timecheck_cond_) delete timecheck_cond_;
if(delayed_reference_) delete delayed_reference_;
if(delayed_data_) delete delayed_data_;
}
PSetupHold::PSetupHold(event_t reference_event,
event_t data_event,
//PExpr setup_limit,
//PExpr hold_limit,
pform_name_t* notifier,
pform_name_t* timestamp_cond,
pform_name_t* 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()
{
// Delete optional arguments
if (reference_event_.condition) delete reference_event_.condition;
if (data_event_.condition) delete data_event_.condition;
if(notifier_) delete notifier_;
if(timestamp_cond_) delete timestamp_cond_;
if(timecheck_cond_) delete timecheck_cond_;
if(delayed_reference_) delete delayed_reference_;
if(delayed_data_) delete delayed_data_;
}

127
PTimingCheck.h Normal file
View File

@ -0,0 +1,127 @@
#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 "pform_types.h"
// TODO cleanup in destructor and cleanup in Module!
/*
* 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;
PExpr* condition;
};
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,
pform_name_t* timestamp_cond,
pform_name_t* 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;
public: // TODO
event_t reference_event_; // hierarchy_identifier
event_t data_event_;
//PExpr setup_limit;
//PExpr hold_limit;
pform_name_t* notifier_;
pform_name_t* timestamp_cond_;
pform_name_t* timecheck_cond_;
pform_name_t* delayed_reference_;
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,
pform_name_t* timestamp_cond,
pform_name_t* 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;
public: // TODO
event_t reference_event_; // hierarchy_identifier
event_t data_event_;
//PExpr setup_limit;
//PExpr hold_limit;
pform_name_t* notifier_;
pform_name_t* timestamp_cond_;
pform_name_t* timecheck_cond_;
pform_name_t* delayed_reference_;
pform_name_t* delayed_data_;
};
#endif /* IVL_PTimingCheck_H */

View File

@ -41,6 +41,7 @@
# include "PPackage.h"
# include "PScope.h"
# include "PSpec.h"
# include "PTimingCheck.h"
# include "netlist.h"
# include "netenum.h"
# include "netvector.h"
@ -6308,6 +6309,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"
<< reference_event_.name
<< " to " << *delayed_reference_ << 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"
<< reference_event_.name
<< " to " << *delayed_reference_ << 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,
const map<perm_string,PFunction*>&funcs)
{
@ -6421,13 +6556,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const
result_flag &= elaborate_behaviors_(des, scope);
// Elaborate the specify paths of the module.
for (list<PSpecPath*>::const_iterator sp = specify_paths.begin()
; sp != specify_paths.end() ; ++ sp ) {
(*sp)->elaborate(des, scope);
}
// Elaborate the timing checks of the module.
for (list<PTimingCheck*>::const_iterator tc = timing_checks.begin()
; tc != timing_checks.end() ; ++ tc ) {
(*tc)->elaborate(des, scope);
}
// Elaborate the elaboration tasks.
for (list<PCallTask*>::const_iterator et = elab_tasks.begin()
; et != elab_tasks.end() ; ++ et ) {

345
parse.y
View File

@ -28,6 +28,7 @@
# include "pform.h"
# include "Statement.h"
# include "PSpec.h"
# include "PTimingCheck.h"
# include "PPackage.h"
# include <stack>
# include <cstring>
@ -87,13 +88,6 @@ static pform_name_t* pform_create_super(void)
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
sub-rules may grab them. This makes parser rules a little easier to
write in some cases. */
@ -530,6 +524,8 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
PSpecPath* specpath;
std::list<index_component_t> *dimensions;
PTimingCheck::event_t* timing_check_event;
LexicalScope::lifetime_t lifetime;
enum typedef_t::basic_type typedef_basic_type;
@ -696,6 +692,9 @@ Module::port_t *module_declare_port(const YYLTYPE&loc, char *id,
%type <let_port_itm> let_port_item
%type <pform_name> hierarchy_identifier implicit_class_handle class_hierarchy_identifier
%type <pform_name> spec_notifier_opt spec_notifier spec_condition_opt
%type <pform_name> spec_condition spec_delayed_opt spec_delayed
%type <timing_check_event> spec_reference_event
%type <expr> assignment_pattern expression expr_mintypmax
%type <expr> expr_primary_or_typename expr_primary
%type <expr> class_new dynamic_array_new
@ -5900,72 +5899,167 @@ specify_item
yyerrok;
}
| K_Sfullskew '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
',' delay_value ',' delay_value spec_notifier_opt /* TODO event_based_flag remain_active_flag */ ')' ';'
{
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
if($10) delete $10; // spec_notifier_opt
}
| K_Shold '(' spec_reference_event ',' spec_reference_event
',' 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
if($8) delete $8; // spec_notifier_opt
}
| K_Snochange '(' spec_reference_event ',' spec_reference_event
',' 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
if($10) delete $10; // spec_notifier_opt
}
| K_Speriod '(' spec_reference_event ',' delay_value
spec_notifier_opt ')' ';'
{ delete $5;
{
cerr << @3 << ": warning: Timing checks are not supported." << endl;
delete $3; // spec_reference_event
delete $5; // delay_value
if($6) delete $6; // spec_notifier_opt
}
| K_Srecovery '(' spec_reference_event ',' spec_reference_event
',' 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
if($8) delete $8; // spec_notifier_opt
}
| K_Srecrem '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
',' expr_mintypmax ',' expr_mintypmax spec_notifier_opt spec_condition_opt
spec_condition_opt spec_delayed_opt spec_delayed_opt ')' ';'
{
cerr << @3 << ": warning: Timing checks are not supported. ";
if ($13 != nullptr || $14 != nullptr)
{
cerr << "Delayed reference and data signals become copies of the"
<< " original reference and data signals." << endl;
}
else
{
cerr << endl;
}
PRecRem*rec_rem = pform_make_rec_rem(@1, *$3, *$5, *$7, *$9, $10, $11, $12, $13, $14);
pform_module_timing_check((PTimingCheck*)rec_rem);
delete $3; // spec_reference_event
delete $5; // spec_reference_event
delete $7; // delay_value
delete $9; // delay_value
}
| K_Sremoval '(' spec_reference_event ',' spec_reference_event
',' 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
if($8) delete $8; // spec_notifier_opt
}
| K_Ssetup '(' spec_reference_event ',' spec_reference_event
',' 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
if($8) delete $8; // spec_notifier_opt
}
| K_Ssetuphold '(' spec_reference_event ',' spec_reference_event
',' delay_value ',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
delete $9;
',' expr_mintypmax ',' expr_mintypmax spec_notifier_opt spec_condition_opt
spec_condition_opt spec_delayed_opt spec_delayed_opt ')' ';'
{
cerr << @3 << ": warning: Timing checks are not supported. ";
if ($13 != nullptr || $14 != nullptr)
{
cerr << "Delayed reference and data signals become copies of the"
<< " original reference and data signals." << endl;
}
else
{
cerr << endl;
}
PSetupHold*setup_hold = pform_make_setup_hold(@1, *$3, *$5, *$7, *$9, $10, $11, $12, $13, $14);
pform_module_timing_check((PTimingCheck*)setup_hold);
delete $3; // spec_reference_event
delete $5; // spec_reference_event
delete $7; // delay_value
delete $9; // delay_value
}
| K_Sskew '(' spec_reference_event ',' spec_reference_event
',' 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
if($8) delete $8; // spec_notifier_opt
}
| K_Stimeskew '(' spec_reference_event ',' spec_reference_event
',' delay_value spec_notifier_opt ')' ';'
{ delete $7;
',' delay_value spec_notifier_opt /* TODO event_based_flag remain_active_flag */ ')' ';'
{
cerr << @3 << ": warning: Timing checks are not supported." << endl;
delete $3; // spec_reference_event
delete $5; // spec_reference_event
delete $7; // delay_value
if($8) delete $8; // spec_notifier_opt
}
| K_Swidth '(' spec_reference_event ',' delay_value ',' expression
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
if($8) delete $8;
}
| 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 ';'
{ delete $2;
{
cerr << @3 << ": warning: Timing checks are not supported." << endl;
delete $2; // 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 ';'
{ delete $2;
{
cerr << @3 << ": warning: Timing checks are not supported." << endl;
delete $2; // 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 +6204,8 @@ specify_path_identifiers
;
specparam
: IDENTIFIER '=' expression
{ PExpr*tmp = $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);
: IDENTIFIER '=' expr_mintypmax
{ pform_set_specparam(@1, lex_strings.make($1), specparam_active_range, $3);
delete[]$1;
}
| PATHPULSE_IDENTIFIER '=' expression
@ -6183,31 +6238,82 @@ spec_polarity
| { $$ = 0; }
;
// TODO spec_controlled_reference_event
spec_reference_event
: K_posedge expression
{ delete $2; }
| K_negedge expression
{ delete $2; }
| K_posedge expr_primary K_TAND expression
{ delete $2;
delete $4;
: hierarchy_identifier
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
event->name = *$1;
event->posedge = false;
event->negedge = false;
event->condition = nullptr;
delete $1;
$$ = event;
}
| K_negedge expr_primary K_TAND expression
{ delete $2;
delete $4;
| hierarchy_identifier K_TAND expression
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
event->name = *$1;
event->posedge = false;
event->negedge = false;
event->condition = $3;
delete $1;
$$ = event;
}
| K_edge '[' edge_descriptor_list ']' expr_primary
{ delete $5; }
| K_edge '[' edge_descriptor_list ']' expr_primary K_TAND expression
{ delete $5;
delete $7;
| K_posedge hierarchy_identifier
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
event->name = *$2;
event->posedge = true;
event->negedge = false;
event->condition = nullptr;
delete $2;
$$ = event;
}
| expr_primary K_TAND expression
{ delete $1;
delete $3;
| K_negedge hierarchy_identifier
{ PTimingCheck::event_t* event = new PTimingCheck::event_t;
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 = $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 = $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 = $7;
delete $5;
$$ = event;
}
| expr_primary
{ delete $1; }
;
/* The edge_descriptor is detected by the lexor as the various
@ -6221,29 +6327,44 @@ edge_descriptor_list
spec_notifier_opt
: /* empty */
{ }
{ $$ = 0; }
| spec_notifier
{ }
{ $$ = $1; }
;
spec_notifier
: ','
{ args_after_notifier = 0; }
{ $$ = 0; }
| ',' hierarchy_identifier
{ args_after_notifier = 0; delete $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; }
{ $$ = $2; }
;
spec_condition_opt
: /* empty */
{ $$ = 0; }
| spec_condition
{ $$ = $1; }
;
spec_condition
: ','
{ $$ = 0; }
| ',' hierarchy_identifier
{ $$ = $2; }
;
spec_delayed_opt
: /* empty */
{ $$ = 0; }
| spec_delayed
{ $$ = $1; }
;
spec_delayed
: ','
{ $$ = 0; }
| ',' hierarchy_identifier
{ $$ = $2; }
;
subroutine_call

View File

@ -32,6 +32,7 @@
# include "PGenerate.h"
# include "PModport.h"
# include "PSpec.h"
# include "PTimingCheck.h"
# include "discipline.h"
# include <list>
# include <map>
@ -3109,6 +3110,72 @@ extern void pform_module_specify_path(PSpecPath*obj)
pform_cur_module.front()->specify_paths.push_back(obj);
}
/*
* Timing checks.
*/
extern PRecRem* pform_make_rec_rem(const struct vlltype&li,
PTimingCheck::event_t&reference_event,
PTimingCheck::event_t&data_event,
PExpr&setup_limit,
PExpr&hold_limit,
pform_name_t* notifier,
pform_name_t* timestamp_cond,
pform_name_t* timecheck_cond,
pform_name_t* delayed_reference,
pform_name_t* delayed_data)
{
PRecRem*rec_rem = new PRecRem(
reference_event,
data_event,
//setup_limit,
//hold_limit,
notifier,
timestamp_cond,
timecheck_cond,
delayed_reference,
delayed_data
);
FILE_NAME(rec_rem, li);
return rec_rem;
}
extern PSetupHold* pform_make_setup_hold(const struct vlltype&li,
PTimingCheck::event_t&reference_event,
PTimingCheck::event_t&data_event,
PExpr&setup_limit,
PExpr&hold_limit,
pform_name_t* notifier,
pform_name_t* timestamp_cond,
pform_name_t* timecheck_cond,
pform_name_t* delayed_reference,
pform_name_t* delayed_data)
{
PSetupHold*setup_hold = new PSetupHold(
reference_event,
data_event,
//setup_limit,
//hold_limit,
notifier,
timestamp_cond,
timecheck_cond,
delayed_reference,
delayed_data
);
FILE_NAME(setup_hold, li);
return setup_hold;
}
extern void pform_module_timing_check(PTimingCheck*obj)
{
if (obj == 0)
return;
pform_cur_module.front()->timing_checks.push_back(obj);
}
void pform_set_port_type(const struct vlltype&li,
list<pform_port_t>*ports,

28
pform.h
View File

@ -30,6 +30,7 @@
# include "PTask.h"
# include "PUdp.h"
# include "PWire.h"
# include "PTimingCheck.h"
# include "verinum.h"
# include "discipline.h"
# include <iostream>
@ -429,6 +430,33 @@ extern PSpecPath*pform_assign_path_delay(PSpecPath*obj, std::list<PExpr*>*delays
extern void pform_module_specify_path(PSpecPath*obj);
/*
* Functions related to timing checks.
*/
extern PRecRem* pform_make_rec_rem(const struct vlltype&li,
PTimingCheck::event_t&reference_event,
PTimingCheck::event_t&data_event,
PExpr&setup_limit,
PExpr&hold_limit,
pform_name_t* notifier,
pform_name_t* timestamp_cond,
pform_name_t* timecheck_cond,
pform_name_t* delayed_reference,
pform_name_t* delayed_data
);
extern PSetupHold* pform_make_setup_hold(const struct vlltype&li,
PTimingCheck::event_t&reference_event,
PTimingCheck::event_t&data_event,
PExpr&setup_limit,
PExpr&hold_limit,
pform_name_t* notifier,
pform_name_t* timestamp_cond,
pform_name_t* timecheck_cond,
pform_name_t* delayed_reference,
pform_name_t* delayed_data
);
extern void pform_module_timing_check(PTimingCheck*obj);
/*
* pform_make_behavior creates processes that are declared with always
* or initial items.

View File

@ -1442,6 +1442,16 @@ void PSpecPath::dump(std::ostream&out, unsigned ind) const
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
{
out << setw(indent) << "" << "generate(" << id_number << ")";
@ -1704,6 +1714,17 @@ void Module::dump_specparams_(ostream&out, unsigned indent) const
}
}
void Module::dump_timingchecks_(ostream&out, unsigned indent) const
{
cout << "dump_timingchecks_" << endl;
typedef list<PTimingCheck*>::const_iterator tcheck_iter_t;
for (tcheck_iter_t cur = timing_checks.begin()
; cur != timing_checks.end() ; ++ cur ) {
(*cur)->dump(out, indent);
}
}
void Module::dump(ostream&out) const
{
if (attributes.begin() != attributes.end()) {
@ -1752,6 +1773,8 @@ void Module::dump(ostream&out) const
dump_specparams_(out, 4);
dump_timingchecks_(out, 4);
dump_enumerations_(out, 4);
dump_classes_(out, 4);