diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 7f8c2c696..730b64fe4 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -39,6 +39,8 @@ CC = @CC@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ +LEX = @LEX@ +YACC = @YACC@ CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -I$(srcdir) -I.. @file64_support@ @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ @@ -62,8 +64,9 @@ dep: O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \ sys_finish.o sys_plusargs.o sys_random.o sys_random_mti.o \ -sys_readmem.o sys_readmem_lex.o sys_scanf.o \ -sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o priv.o stringheap.o +sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \ +sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \ +mt19937int.o priv.o sdf_lexor.o sdf_parse.o stringheap.o ifeq (@HAVE_LIBZ@,yes) ifeq (@HAVE_LIBBZ2@,yes) @@ -84,6 +87,12 @@ system.vpi: $O ../vvp/libvpi.a sys_readmem_lex.c: sys_readmem_lex.lex flex -t -Preadmem $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c +sdf_lexor.c: sdf_lexor.lex + flex -t -Psdf $(srcdir)/sdf_lexor.lex > sdf_lexor.c + +sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y + $(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y + ifeq (@enable_vvp32@,yes) all32: bin32 bin32/system.vpi diff --git a/vpi/configure.in b/vpi/configure.in index 172378351..e4e98738c 100644 --- a/vpi/configure.in +++ b/vpi/configure.in @@ -15,6 +15,14 @@ then exit 1 fi +AC_CHECK_PROGS(YACC,bison,none) +if test "$YACC" = "none" +then + echo "*** Error: No suitable bison found. ***" + echo " Please install the 'bison' package." + exit 1 +fi + AC_EXEEXT AC_SUBST(EXEEXT) diff --git a/vpi/sdf_lexor.lex b/vpi/sdf_lexor.lex new file mode 100644 index 000000000..44d0aa94b --- /dev/null +++ b/vpi/sdf_lexor.lex @@ -0,0 +1,127 @@ + +%option never-interactive + +%{ +/* + * Copyright (c) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "sdf_priv.h" +# include "sdf_parse_priv.h" +# include "sdf_parse.h" +# include +# include +# include + +static void process_quoted_string(void); +static int lookup_keyword(const char*text); +const char*sdf_parse_path = 0; + +static int yywrap(void) +{ + return 1; +} + + +# define yylval sdflval +%} + +%% + +[ \m\t] { /* Skip white space. */; } + + /* Count lines so that the parser can assign line numbers. */ +\n { sdflloc.first_line += 1; } + + /* Real values */ +[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)? { + yylval.real_val = strtod(yytext, 0); + return REAL_NUMBER; +} + +[a-zA-Z]+ { + return lookup_keyword(yytext); +} + +\"[^\"]*\" { + process_quoted_string(); + return QSTRING; +} + +. { return yytext[0]; } + +%% + +static struct { + const char*name; + int code; +} keywords[] = { + { "ABSOLUTE", K_ABSOLUTE }, + { "CELL", K_CELL }, + { "CELLTYPE", K_CELLTYPE }, + { "DATE", K_DATE }, + { "DELAY", K_DELAY }, + { "DELAYFILE", K_DELAYFILE }, + { "DESIGN", K_DESIGN }, + { "DIVIDER", K_DIVIDER }, + { "INCREMENT", K_INCREMENT }, + { "INSTANCE", K_INSTANCE }, + { "IOPATH", K_IOPATH }, + { "PROCESS", K_PROCESS }, + { "PROGRAM", K_PROGRAM }, + { "SDFVERSION", K_SDFVERSION }, + { "TEMPERATURE",K_TEMPERATURE }, + { "TIMESCALE", K_TIMESCALE }, + { "VENDOR", K_VENDOR }, + { "VERSION", K_VERSION }, + { "VOLTAGE", K_VOLTAGE }, + { 0, IDENTIFIER } +}; + +static int lookup_keyword(const char*text) +{ + int idx; + for (idx = 0 ; keywords[idx].name ; idx += 1) { + if (strcasecmp(text, keywords[idx].name) == 0) + return keywords[idx].code; + } + + yylval.string_val = strdup(yytext); + return IDENTIFIER; +} + +/* + * Create a string witout the leading and trailing quotes. + */ +static void process_quoted_string(void) +{ + yylval.string_val = strdup(yytext+1); + char*endp = yylval.string_val+strlen(yylval.string_val); + assert(endp[-1] == '"'); + endp[-1] = 0; +} + +extern int sdfparse(void); +void sdf_process_file(FILE*fd, const char*path) +{ + yyrestart(fd); + + sdf_parse_path = path; + sdfparse(); + sdf_parse_path = 0; +} diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y new file mode 100644 index 000000000..8ac41013c --- /dev/null +++ b/vpi/sdf_parse.y @@ -0,0 +1,308 @@ + +%{ +/* + * Copyright (c) 1998-2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +extern int sdflex(void); +static void yyerror(const char*msg); +# include "vpi_user.h" +# include "sdf_parse_priv.h" +# include "sdf_priv.h" +# include + +/* This is the hierarchy separator to use. */ +static char use_hchar = '.'; + +%} + +%union { + unsigned long int_val; + double real_val; + char* string_val; + + struct sdf_delval_list_s delval_list; +}; + +%token K_ABSOLUTE K_CELL K_CELLTYPE K_DATE K_DELAYFILE K_DELAY K_DESIGN +%token K_DIVIDER K_INCREMENT K_INSTANCE K_IOPATH +%token K_PROCESS K_PROGRAM K_SDFVERSION K_TEMPERATURE K_TIMESCALE +%token K_VENDOR K_VERSION K_VOLTAGE + +%token QSTRING IDENTIFIER +%token REAL_NUMBER +%token INTEGER + +%type celltype +%type cell_instance +%type hierarchical_identifier +%type port port_instance port_spec + +%type rvalue rtriple signed_real_number +%type delval + +%type delval_list + +%% + +source_file + : '(' K_DELAYFILE sdf_header_list cell_list ')' + ; + +sdf_header_list + : sdf_header_list sdf_header_item + | sdf_header_item + ; + +sdf_header_item + : sdfversion + | design_name + | date + | vendor + | program_name + | program_version + | hierarchy_divider + | voltage + | process + | temperature + | time_scale + ; + +sdfversion + : '(' K_SDFVERSION QSTRING ')' + { free($3); + } + ; + +design_name + : '(' K_DESIGN QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Design: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } + ; + +date + : '(' K_DATE QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Date: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } + ; + +vendor + : '(' K_VENDOR QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Vendor: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } +; + +program_name + : '(' K_PROGRAM QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Program: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } + ; + +program_version + : '(' K_VERSION QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Program Version: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } + ; + +hierarchy_divider + : '(' K_DIVIDER '.' ')' { use_hchar = '.'; } + | '(' K_DIVIDER '/' ')' { use_hchar = '/'; } + ; + +voltage + : '(' K_VOLTAGE rtriple ')' + | '(' K_VOLTAGE signed_real_number ')' + ; + +process + : '(' K_PROCESS QSTRING ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: Process: %s\n", + sdf_parse_path, @2.first_line, $3); + free($3); + } + ; + +temperature + : '(' K_TEMPERATURE rtriple ')' + | '(' K_TEMPERATURE signed_real_number ')' + ; + +time_scale + : '(' K_TIMESCALE REAL_NUMBER IDENTIFIER ')' + { if (sdf_flag_inform) vpi_printf("%s:%d:SDF INFO: TIMESCALE : %f%s\n", + sdf_parse_path, @2.first_line, $3, $4); + free($4); + } + ; + +cell_list + : cell_list cell + | cell + ; + +cell + : '(' K_CELL celltype cell_instance + { sdf_select_instance($3, $4); /* find the instance in the design */} + timing_spec_list + ')' + { free($3); + free($4); } + | '(' K_CELL error ')' + { vpi_printf("%s:%d: Syntax error in CELL\n", + sdf_parse_path, @2.first_line); } + ; + +celltype + : '(' K_CELLTYPE QSTRING ')' + { $$ = $3; } + ; + +cell_instance + : '(' K_INSTANCE hierarchical_identifier ')' + { $$ = $3; } + | '(' K_INSTANCE '*' ')' + { $$ = 0; } + ; + +timing_spec_list + : timing_spec_list timing_spec + | timing_spec + ; + +timing_spec + : '(' K_DELAY deltype_list ')' + | '(' K_DELAY error ')' + { vpi_printf("%s:%d: Syntax error in CELL DELAY SPEC\n", + sdf_parse_path, @2.first_line); } + ; + +deltype_list + : deltype_list deltype + | deltype + ; + +deltype + : '(' K_ABSOLUTE del_def_list ')' + | '(' K_INCREMENT del_def_list ')' + | '(' error ')' + { vpi_printf("%s:%d: Invalid/malformed delay type\n", + sdf_parse_path, @1.first_line); } + ; + +del_def_list + : del_def_list del_def + | del_def + ; + +del_def + : '(' K_IOPATH port_spec port_instance delval_list ')' + { sdf_iopath_delays($3, $4, &$5); + free($3); + free($4); + } + | '(' K_IOPATH error ')' + { vpi_printf("%s:%d: Invalid/malformed IOPATH\n", + sdf_parse_path, @2.first_line); } + ; + +port_spec + : port_instance + /* | port_edge */ + ; + +port_instance + : port { $$ = $1; } + ; + +port + : hierarchical_identifier + { $$ = $1; } + /* | hierarchical_identifier '[' INTEGER ']' */ + ; + +delval_list + : delval_list delval + { int idx; + $$.count = $1.count; + for (idx = 0 ; idx < $$.count ; idx += 1) + $$.val[idx] = $1.val[idx]; + if ($$.count < 12) { + $$.val[$$.count] = $2; + $$.count += 1; + } + } + | delval + { $$.count = 1; + $$.val[0] = $1; + } + ; + +delval + : rvalue + { $$ = $1; } + | '(' rvalue rvalue ')' + { $$ = $2; + vpi_printf("%s:%d: SDF WARNING: Pulse rejection limits ignored\n", + sdf_parse_path, @3.first_line); + } + | '(' rvalue rvalue rvalue ')' + { $$ = $2; + vpi_printf("%s:%d: SDF WARNING: Pulse rejection limits ignored\n", + sdf_parse_path, @3.first_line); + } + ; + +rvalue + : '(' signed_real_number ')' + { $$ = $2; } + | '(' rtriple ')' + { $$ = $2; } + ; + +hierarchical_identifier + : IDENTIFIER + { $$ = $1; } + ; + +rtriple + : signed_real_number ':' signed_real_number ':' signed_real_number + { $$ = $3; /* XXXX Assume typical value. */ } + ; + +signed_real_number + : REAL_NUMBER { $$ = $1; } + | '+' REAL_NUMBER { $$ = $2; } + | '-' REAL_NUMBER { $$ = -$2; } + ; + +%% + +void yyerror(const char*msg) +{ + fprintf(stderr, "SDF ERROR: %s\n", msg); +} diff --git a/vpi/sdf_parse_priv.h b/vpi/sdf_parse_priv.h new file mode 100644 index 000000000..9ecce9dad --- /dev/null +++ b/vpi/sdf_parse_priv.h @@ -0,0 +1,30 @@ +#ifndef _sdf_parse_priv_h +#define _sdf_parse_priv_h +/* + * Copyright (c) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * This file is only included by sdf_parse.y and sdf_lexor.lex. It is + * used to share declarations between the parse and the lexor. + */ + + /* Path to source for error messages. */ +extern const char*sdf_parse_path; + +#endif diff --git a/vpi/sdf_priv.h b/vpi/sdf_priv.h new file mode 100644 index 000000000..d76e5626b --- /dev/null +++ b/vpi/sdf_priv.h @@ -0,0 +1,48 @@ +#ifndef _sdf_priv_h +#define _sdf_priv_h +/* + * Copyright (c) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include + +/* + * Invoke the parser to parse the opened SDF file. The fd is the SDF + * file already opened and ready for reading. The path is the path to + * the file and is only used for error messages. + */ +extern void sdf_process_file(FILE*fd, const char*path); + +extern int sdf_flag_warning; +extern int sdf_flag_inform; + +/* **** + * These functions are called by the parser to process the SDF file as + * it is parsed. + */ + +struct sdf_delval_list_s { + int count; + double val[12]; +}; + +extern void sdf_select_instance(const char*celltype, const char*inst); +extern void sdf_iopath_delays(const char*src, const char*dst, + const struct sdf_delval_list_s*delval); + +#endif diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c new file mode 100644 index 000000000..681fafde9 --- /dev/null +++ b/vpi/sys_sdf.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2007 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "vpi_config.h" + +# include "vpi_user.h" +# include "sdf_priv.h" +# include +# include +# include + +/* + * These are static context + */ + +int sdf_flag_warnings = 0; +int sdf_flag_inform = 0; + + /* Scope of the $sdf_annotate call. Annotation starts here. */ +static vpiHandle sdf_scope; + /* The cell in process. */ +static vpiHandle sdf_cur_cell; + +/* + * These functions are called by the SDF parser during parsing to + * handling items discovered in the parse. + */ +void sdf_select_instance(const char*celltype, const char*cellinst) +{ + vpiHandle idx = vpi_iterate(vpiModule, sdf_scope); + assert(idx); + + vpiHandle cur; + while ( (cur = vpi_scan(idx)) ) { + + /* If we find the cell in this scope, then save it for + future processing. */ + if ( strcmp(cellinst, vpi_get_str(vpiName,cur)) == 0) { + sdf_cur_cell = cur; + vpi_free_object(idx); + + /* The scope that matches should be a module. */ + if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) { + vpi_printf("SDF ERROR: Scope %s in %s is not a module.\n", + cellinst, vpi_get_str(vpiName,sdf_scope)); + } + /* The matching scope (a module) should have the + expected type. */ + if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) { + vpi_printf("SDF ERROR: Module %s in %s is not a %s; " + "it is an %s\n", cellinst, + vpi_get_str(vpiName,sdf_scope), celltype, + vpi_get_str(vpiDefName,sdf_cur_cell)); + } + + return; + } + } + + sdf_cur_cell = 0; + vpi_printf("SDF WARNING: Unable to find %s in current scope\n", cellinst); +} + +void sdf_iopath_delays(const char*src, const char*dst, + const struct sdf_delval_list_s*delval_list) +{ + assert(sdf_cur_cell); + + vpiHandle iter = vpi_iterate(vpiModPath, sdf_cur_cell); + assert(iter); + + /* Search for the modpath that matches the IOPATH by looking + for the modpath that uses the same ports as the ports that + the parser has found. */ + vpiHandle path; + while ( (path = vpi_scan(iter)) ) { + vpiHandle path_in = vpi_handle(vpiModPathIn,path); + vpiHandle path_out = vpi_handle(vpiModPathOut,path); + + path_in = vpi_handle(vpiExpr,path_in); + path_out = vpi_handle(vpiExpr,path_out); + assert(vpi_get(vpiType,path_in) == vpiNet); + assert(vpi_get(vpiType,path_out) == vpiNet); + + /* If the src name doesn't match, go on. */ + if (strcmp(src,vpi_get_str(vpiName,path_in)) != 0) + continue; + + /* If the dst name doesn't match, go on. */ + if (strcmp(dst,vpi_get_str(vpiName,path_out)) != 0) + continue; + + /* Ah, this must be a match! */ + break; + } + + if (path == 0) { + vpi_printf("SDF ERROR: Unable to find ModPath %s -> %s in %s\n", + src, dst, vpi_get_str(vpiName,sdf_cur_cell)); + return; + } + + /* No longer need the iterator. */ + vpi_free_object(iter); + + struct t_vpi_time delay_vals[12]; + int idx; + for (idx = 0 ; idx < delval_list->count ; idx += 1) { + delay_vals[idx].type = vpiScaledRealTime; + delay_vals[idx].real = delval_list->val[idx]; + } + + s_vpi_delay delays; + delays.da = delay_vals; + delays.no_of_delays = delval_list->count; + delays.time_type = vpiScaledRealTime; + delays.mtm_flag = 0; + delays.append_flag = 0; + delays.plusere_flag = 0; + + vpi_put_delays(path, &delays); +} + +static void check_command_line_args(void) +{ + struct t_vpi_vlog_info vlog_info; + int idx; + + static int sdf_command_line_done = 0; + if (sdf_command_line_done) + return; + + vpi_get_vlog_info(&vlog_info); + + for (idx = 0 ; idx < vlog_info.argc ; idx += 1) { + if (strcmp(vlog_info.argv[idx],"-sdf-warn") == 0) { + sdf_flag_warnings = 1; + + } else if (strcmp(vlog_info.argv[idx],"-sdf-info") == 0) { + sdf_flag_inform = 1; + + } else if (strcmp(vlog_info.argv[idx],"-sdf-verbose") == 0) { + sdf_flag_warnings = 1; + sdf_flag_inform = 1; + } + } + + sdf_command_line_done = 1; +} + +static PLI_INT32 sys_sdf_annotate_compiletf(PLI_BYTE8*name) +{ + check_command_line_args(); + return 0; +} + +static PLI_INT32 sys_sdf_annotate_calltf(PLI_BYTE8*name) +{ + s_vpi_value value; + vpiHandle sys = vpi_handle(vpiSysTfCall,0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + + vpiHandle path = vpi_scan(argv); + assert(path); + + vpi_free_object(argv); + + value.format = vpiStringVal; + vpi_get_value(path, &value); + + if ((value.format != vpiStringVal) || !value.value.str) { + vpi_printf("ERROR: %s: File name argument (type=%d)" + " does not have a string value\n", + name, vpi_get(vpiType, path)); + return 0; + } + + char*path_str = strdup(value.value.str); + FILE*sdf_fd = fopen(path_str, "r"); + assert(sdf_fd); + + sdf_scope = vpi_handle(vpiScope,sys); + sdf_cur_cell = 0; + + sdf_process_file(sdf_fd, path_str); + + fclose(sdf_fd); + free(path_str); + return 0; +} + +void sys_sdf_register() +{ + s_vpi_systf_data tf_data; + + tf_data.type = vpiSysTask; + tf_data.tfname = "$sdf_annotate"; + tf_data.calltf = sys_sdf_annotate_calltf; + tf_data.compiletf = sys_sdf_annotate_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$sdf_annotate"; + vpi_register_systf(&tf_data); +} diff --git a/vpi/sys_table.c b/vpi/sys_table.c index ceb7e0033..be260e8bc 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -36,6 +36,7 @@ extern void sys_random_register(); extern void sys_random_mti_register(); extern void sys_readmem_register(); extern void sys_scanf_register(); +extern void sys_sdf_register(); extern void sys_time_register(); extern void sys_vcd_register(); extern void sys_vcdoff_register(); @@ -176,6 +177,7 @@ void (*vlog_startup_routines[])() = { sys_scanf_register, sys_time_register, sys_lxt_or_vcd_register, + sys_sdf_register, 0 }; diff --git a/vvp/delay.cc b/vvp/delay.cc index 446795e37..4497f8901 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -576,19 +576,53 @@ static void modpath_src_put_delays ( vpiHandle ref, p_vpi_delay delays ) vvp_fun_modpath_src *fun = dynamic_cast(src->net->fun); assert( fun ); - assert(delays->no_of_delays == 12); + + typedef unsigned char map_array_t[12]; + static const map_array_t map_2 = {0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0}; + static const map_array_t map12 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + + const map_array_t*use_map = 0; + switch (delays->no_of_delays) { + case 2: + use_map = &map_2; + break; + case 12: + use_map = &map12; + break; + default: + assert(0); + break; + } if (delays->time_type == vpiSimTime) { - for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) { - tmp[idx] = vpip_timestruct_to_time(delays->da+idx); + for (idx = 0 ; idx < 12 ; idx += 1) { + tmp[idx] = vpip_timestruct_to_time(delays->da+use_map[0][idx]); } } else { - for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) { - tmp[idx] = vpip_scaled_real_to_time64(delays->da[idx].real, + for (idx = 0 ; idx < 12 ; idx += 1) { + tmp[idx] = vpip_scaled_real_to_time64(delays->da[use_map[0][idx]].real, src->dest->scope); } } + /* Now clean up any to-from-x delays to me the min/max based on + the rules for selecting X delays. This only needs to happen + if the X delays are not already explicitly given. */ + if (delays->no_of_delays <= 6) { + vvp_time64_t t_max = tmp[0]; + vvp_time64_t t_min = tmp[1]; + for (idx = 1 ; idx < delays->no_of_delays ; idx += 1) { + if (tmp[idx] > t_max) t_max = tmp[idx]; + if (tmp[idx] < t_min) t_min = tmp[idx]; + } + tmp[DELAY_EDGE_0x] = t_min; + tmp[DELAY_EDGE_x1] = t_max; + tmp[DELAY_EDGE_1x] = t_min; + tmp[DELAY_EDGE_x0] = t_max; + tmp[DELAY_EDGE_xz] = t_max; + tmp[DELAY_EDGE_zx] = t_min; + } + fun->put_delay12(tmp); } diff --git a/vvp/vvp.man b/vvp/vvp.man index 3ad520cd5..a3afa4e5b 100644 --- a/vvp/vvp.man +++ b/vvp/vvp.man @@ -96,6 +96,20 @@ space, and is written out incrementally. Thus, you can view lxt2 files while a simulation is still running (or paused) or if your simulation crashes or is killed, you still have a useful dump. +.TP 8 +.B -sdf-warn +When loading an SDF annnotation file, this option causes the annotator +to print warnings for questionable but non-fatal issues. + +.TP 8 +.B -sdf-info +When loading an SDF annnotation file, this option causes the annotator +to print information about the annotation. + +.TP 8 +.B -sdf-verbose +This is shorthand for -sdf-info -sdf-warn. + .SH ENVIRONMENT .PP The vvp command also accepts some environment variables that control