Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement $width timing check (only vvp for now) #999

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions emit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,12 @@ void NetScope::emit_scope(struct target_t*tgt) const
tgt->signal(cur->second);
}

// TODO use for timing checks!
for (signals_map_iter_t cur = signals_map_.begin()
; cur != signals_map_.end() ; ++ cur ) {
tgt->tchk(cur->second);
}

// Run the signals again, but this time to connect the
// delay paths. This is done as a second pass because
// the paths reference other signals that may be later
Expand Down
3 changes: 3 additions & 0 deletions ivl_target.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t;
typedef struct ivl_process_s *ivl_process_t;
typedef struct ivl_scope_s *ivl_scope_t;
typedef struct ivl_signal_s *ivl_signal_t;
typedef struct ivl_tchk_s *ivl_tchk_t;
typedef struct ivl_port_info_s*ivl_port_info_t;
typedef struct ivl_switch_s *ivl_switch_t;
typedef struct ivl_memory_s *ivl_memory_t; //XXXX __attribute__((deprecated));
Expand Down Expand Up @@ -1905,6 +1906,8 @@ extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
extern ivl_nexus_t ivl_scope_mod_port(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_sigs(ivl_scope_t net);
extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_tchks(ivl_scope_t net);
extern ivl_tchk_t ivl_scope_tchk(ivl_scope_t net, unsigned idx);
extern unsigned ivl_scope_switches(ivl_scope_t net);
extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx);
extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net);
Expand Down
13 changes: 13 additions & 0 deletions t-dll-api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2366,6 +2366,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx)
return net->sigs_[idx];
}

extern "C" unsigned ivl_scope_tchks(ivl_scope_t net)
{
assert(net);
return net->tchks_.size();
}

extern "C" ivl_tchk_t ivl_scope_tchk(ivl_scope_t net, unsigned idx)
{
assert(net);
assert(idx < net->tchks_.size());
return net->tchks_[idx];
}

extern "C" unsigned ivl_scope_switches(ivl_scope_t net)
{
assert(net);
Expand Down
13 changes: 13 additions & 0 deletions t-dll.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2790,6 +2790,19 @@ void dll_target::signal(const NetNet*net)
if (debug_optimizer && obj->array_words > 1000) cerr << "debug: t-dll done with big nexus array" << endl;
}

void dll_target::tchk(const NetNet*net)
{
ivl_tchk_t obj = new struct ivl_tchk_s;

obj->name_ = net->name();

obj->scope_ = find_scope(des_, net->scope());
assert(obj->scope_);
//TODO FILE_NAME(obj, net);

obj->scope_->tchks_.push_back(obj);
}

bool dll_target::signal_paths(const NetNet*net)
{
/* Nothing to do if there are no paths for this signal. */
Expand Down
10 changes: 10 additions & 0 deletions t-dll.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct dll_target : public target_t, public expr_scan_t {
void scope(const NetScope*);
void convert_module_ports(const NetScope*);
void signal(const NetNet*);
void tchk(const NetNet*);
bool signal_paths(const NetNet*);
ivl_dll_t dll_;

Expand Down Expand Up @@ -693,6 +694,8 @@ struct ivl_scope_s {

std::vector<ivl_signal_t> sigs_;

std::vector<ivl_tchk_t> tchks_;

unsigned nlog_;
ivl_net_logic_t*log_;

Expand Down Expand Up @@ -778,6 +781,13 @@ struct ivl_signal_s {
unsigned nattr;
};

/*
* A timing check TODO
*/
struct ivl_tchk_s {
perm_string name_;
ivl_scope_t scope_;
};

/*
* The ivl_statement_t represents any statement. The type of statement
Expand Down
3 changes: 3 additions & 0 deletions target.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct target_t {
virtual void signal(const NetNet*) =0;
virtual bool signal_paths(const NetNet*);

/* Output a timing check (called for each timing check) */
virtual void tchk(const NetNet*) =0;

/* Analog branches */
virtual bool branch(const NetBranch*);

Expand Down
38 changes: 38 additions & 0 deletions tgt-vvp/draw_tchk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2023 Stephen Williams ([email protected])
* Copyright (c) 2023 Leo Moser ([email protected])
*
* 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 "vvp_priv.h"
# include <stdlib.h>
# include <math.h>
# include <string.h>
# include <inttypes.h>
# include <limits.h>
# include <assert.h>
# include "ivl_alloc.h"

/*
* This function draws a timing check
*/
void draw_tchk_in_scope(ivl_tchk_t tchk)
{
// TODO use nexus???

fprintf(vvp_out, " .tchk_width ;\n");
}
7 changes: 7 additions & 0 deletions tgt-vvp/vvp_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ extern char* process_octal_codes(const char*txt, unsigned wid);
extern void draw_modpath(ivl_signal_t path_sig, char*drive_label, unsigned drive_index);
extern void cleanup_modpath(void);

/*
* timing check symbols
* TODO
*/

extern void draw_tchk_in_scope(ivl_tchk_t tchk);

/*
* This function draws the execution of a vpi_call statement, along
* with the tricky handling of arguments. If this is called with a
Expand Down
9 changes: 9 additions & 0 deletions tgt-vvp/vvp_scope.c
Original file line number Diff line number Diff line change
Expand Up @@ -2515,6 +2515,15 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
}
}

/* Draw the timing checks. */

for (idx = 0 ; idx < ivl_scope_tchks(net) ; idx += 1) {
ivl_tchk_t tchk = ivl_scope_tchk(net, idx);

// TODO check for tchk type
draw_tchk_in_scope(tchk);
}

for (idx = 0 ; idx < ivl_scope_events(net) ; idx += 1) {
ivl_event_t event = ivl_scope_event(net, idx);
draw_event_in_scope(event);
Expand Down
32 changes: 9 additions & 23 deletions vpi/sdf_lexor.lex
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ static int yywrap(void)
%}

%x CCOMMENT
%x COND_EDGE_ID
%x EDGE_ID

%%

Expand All @@ -64,16 +62,15 @@ static int yywrap(void)
/* Count lines so that the parser can assign line numbers. */
\n { sdflloc.first_line += 1; }

/* The other edge identifiers. */
<COND_EDGE_ID,EDGE_ID>"01" {return K_01; }
<COND_EDGE_ID,EDGE_ID>"10" {return K_10; }
<COND_EDGE_ID,EDGE_ID>"0"[zZ] {return K_0Z; }
<COND_EDGE_ID,EDGE_ID>[zZ]"1" {return K_Z1; }
<COND_EDGE_ID,EDGE_ID>"1"[zZ] {return K_1Z; }
<COND_EDGE_ID,EDGE_ID>[zZ]"0" {return K_Z0; }
<COND_EDGE_ID,EDGE_ID>[pP][oO][sS][eE][dD][gG][eE] {return K_POSEDGE; }
<COND_EDGE_ID,EDGE_ID>[nN][eE][gG][eE][dD][gG][eE] {return K_NEGEDGE; }
<COND_EDGE_ID>[cC][oO][nN][dD] {return K_COND; }
/* The edge identifiers. */
"posedge" { return K_POSEDGE; }
"negedge" { return K_NEGEDGE; }
"01" {return K_01; }
"10" {return K_10; }
"0z" {return K_0Z; }
"z1" {return K_Z1; }
"1z" {return K_1Z; }
"z0" {return K_Z0; }

/* Integer values */
[0-9]+ {
Expand Down Expand Up @@ -165,17 +162,6 @@ static struct {
{ 0, IDENTIFIER }
};

void start_edge_id(unsigned cond)
{
if (cond) BEGIN(COND_EDGE_ID);
else BEGIN(EDGE_ID);
}

void stop_edge_id(void)
{
BEGIN(0);
}

static int lookup_keyword(const char*text)
{
unsigned idx, len, skip;
Expand Down
87 changes: 47 additions & 40 deletions vpi/sdf_parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ char sdf_use_hchar = '.';
struct port_with_edge_s port_with_edge;
struct sdf_delval_list_s delval_list;
struct interconnect_port_s interconnect_port;
struct port_tchk_s port_tchk;
};

%token K_ABSOLUTE K_CELL K_CELLTYPE K_COND K_CONDELSE K_DATE K_DELAYFILE
Expand All @@ -68,6 +69,8 @@ char sdf_use_hchar = '.';

%type <interconnect_port> port_interconnect

%type <port_tchk> port_tchk

%type <real_val> signed_real_number
%type <delay> delval rvalue_opt rvalue rtriple signed_real_number_opt

Expand Down Expand Up @@ -291,8 +294,6 @@ timing_spec
{ vpi_printf("SDF ERROR: %s:%d: Syntax error in CELL DELAY SPEC\n",
sdf_parse_path, @2.first_line); }
| '(' K_TIMINGCHECK tchk_def_list ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_TIMINGCHECK error ')'
{ vpi_printf("SDF ERROR: %s:%d: Syntax error in TIMINGCHECK SPEC\n",
sdf_parse_path, @2.first_line); }
Expand Down Expand Up @@ -382,55 +383,61 @@ tchk_def_list
/* Timing checks are ignored. */
tchk_def
: '(' K_SETUP port_tchk port_tchk rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $setup not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_HOLD port_tchk port_tchk rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $hold not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_SETUPHOLD port_tchk port_tchk rvalue rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $setuphold not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_RECOVERY port_tchk port_tchk rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $recovery not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_RECREM port_tchk port_tchk rvalue rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $recrem not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_REMOVAL port_tchk port_tchk rvalue ')'
| '(' K_WIDTH port_tchk rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $removal not supported.\n",
sdf_parse_path, @2.first_line); }
| '(' K_WIDTH port_tchk rvalue ')' // TODO
{ if (sdf_flag_inform) {
vpi_printf("SDF INFO: %s:%d: TIMINGCHECK $width with "
"ref_event = %d %s %s, value = %f\n",
sdf_parse_path, @2.first_line, $3.vpi_edge, $3.signal, $3.condition, $4.value);
}
sdf_tchk_width_limits($3, $4, @2.first_line);
free($3.signal);
free($3.condition);
}
| '(' K_PERIOD port_tchk rvalue ')'
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK $period not supported.\n",
sdf_parse_path, @2.first_line); }
;

port_tchk
: port_instance
{ free($1); }
/* This must only be an edge. For now we just accept everything. */
| cond_edge_start port_instance ')'
{ free($2); }
/* These must only be a cond. For now we just accept everything. */
| cond_edge_start timing_check_condition port_spec ')'
{ free($3.string_val); }
| cond_edge_start QSTRING timing_check_condition port_spec ')'
{ free($2);
free($4.string_val);
: port_spec
{ $$.signal = $1.string_val;
$$.vpi_edge = $1.vpi_edge;
$$.condition = NULL;
}
| '(' K_COND timing_check_condition port_spec ')'
{ vpi_printf("SDF WARNING: %s:%d: Conditions for timing checks not supported.\n",
sdf_parse_path, @2.first_line);$$.signal = $4.string_val;
$$.vpi_edge = $4.vpi_edge;
$$.condition = NULL; // TODO pass condition
}
;

cond_edge_start
: '(' { start_edge_id(1); } cond_edge_identifier { stop_edge_id(); }
;

cond_edge_identifier
: K_POSEDGE
| K_NEGEDGE
| K_01
| K_10
| K_0Z
| K_Z1
| K_1Z
| K_Z0
| K_COND
;

timing_check_condition
: port_interconnect
{ free($1.name); }
| '~' port_interconnect
{ free($2.name); }
| '!' port_interconnect
{ free($2.name); }
| port_interconnect equality_operator scalar_constant
{ free($1.name); }
: hierarchical_identifier
{ free($1); }
| '~' hierarchical_identifier
{ free($2); }
| '!' hierarchical_identifier
{ free($2); }
| hierarchical_identifier equality_operator scalar_constant
{ free($1); }
;

/* This is not complete! */
Expand Down Expand Up @@ -495,8 +502,8 @@ port_interconnect
;

port_edge
: '(' {start_edge_id(0);} edge_identifier {stop_edge_id();} port_instance ')'
{ $$.vpi_edge = $3; $$.string_val = $5; }
: '(' edge_identifier port_instance ')'
{ $$.vpi_edge = $2; $$.string_val = $3; }
;

edge_identifier
Expand Down
3 changes: 0 additions & 3 deletions vpi/sdf_parse_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,4 @@ extern const char*sdf_parse_path;
/* Hierarchy separator character to use. */
extern char sdf_use_hchar;

extern void start_edge_id(unsigned cond);
extern void stop_edge_id(void);

#endif /* IVL_sdf_parse_priv_h */
Loading