1998-11-04 00:28:49 +01:00
|
|
|
|
2006-05-17 06:15:12 +02:00
|
|
|
%option never-interactive
|
2008-01-04 20:33:03 +01:00
|
|
|
%option nounput
|
2006-05-17 06:15:12 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
%{
|
|
|
|
|
/*
|
2009-01-09 02:59:39 +01:00
|
|
|
* Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com)
|
1998-11-04 00:28:49 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2001-07-25 05:10:48 +02:00
|
|
|
# include "config.h"
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
//# define YYSTYPE lexval
|
|
|
|
|
|
2002-06-06 20:57:18 +02:00
|
|
|
# include <iostream>
|
1999-06-06 22:42:48 +02:00
|
|
|
# include "compiler.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "parse_misc.h"
|
2001-10-21 01:02:39 +02:00
|
|
|
# include "parse_api.h"
|
1998-11-04 00:28:49 +01:00
|
|
|
# include "parse.h"
|
|
|
|
|
# include <ctype.h>
|
1999-07-10 03:03:18 +02:00
|
|
|
# include <string.h>
|
2000-03-12 18:09:40 +01:00
|
|
|
# include "lexor_keyword.h"
|
2008-05-11 21:00:11 +02:00
|
|
|
# include "discipline.h"
|
2008-05-01 07:07:09 +02:00
|
|
|
# include <list>
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
# define YY_USER_INIT reset_lexor();
|
|
|
|
|
# define yylval VLlval
|
2000-11-30 18:31:42 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Lexical location information is passed in the yylloc variable to th
|
|
|
|
|
* parser. The file names, strings, are kept in a list so that I can
|
|
|
|
|
* re-use them. The set_file_name function will return a pointer to
|
|
|
|
|
* the name as it exists in the list (and delete the passed string.)
|
|
|
|
|
* If the name is new, it will be added to the list.
|
|
|
|
|
*/
|
1998-11-04 00:28:49 +01:00
|
|
|
extern YYLTYPE yylloc;
|
|
|
|
|
|
2008-03-28 04:30:53 +01:00
|
|
|
static char* strdupnew(char const *str)
|
|
|
|
|
{
|
|
|
|
|
return str ? strcpy(new char [strlen(str)+1], str) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-11-30 18:31:42 +01:00
|
|
|
static const char* set_file_name(char*text)
|
|
|
|
|
{
|
2007-12-20 18:31:01 +01:00
|
|
|
perm_string path = filename_strings.make(text);
|
|
|
|
|
delete[]text;
|
2007-04-19 04:52:53 +02:00
|
|
|
|
|
|
|
|
/* Check this file name with the list of library file
|
|
|
|
|
names. If there is a match, then turn on the
|
|
|
|
|
pform_library_flag. This is how the parser knows that
|
|
|
|
|
modules declared in this file are library modules. */
|
2007-12-20 18:31:01 +01:00
|
|
|
pform_library_flag = library_file_map[path];
|
|
|
|
|
return path;
|
2000-11-30 18:31:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
extern void pform_set_timescale(int, int, const char*file, unsigned line);
|
2000-07-23 00:09:03 +02:00
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
void reset_lexor();
|
1999-07-03 23:27:22 +02:00
|
|
|
static void line_directive();
|
1999-11-23 03:49:04 +01:00
|
|
|
static void line_directive2();
|
1999-07-03 23:27:22 +02:00
|
|
|
|
1999-05-06 06:09:28 +02:00
|
|
|
static verinum*make_unsized_binary(const char*txt);
|
2007-09-17 19:08:07 +02:00
|
|
|
static verinum*make_undef_highz_dec(const char*txt);
|
1999-05-06 06:09:28 +02:00
|
|
|
static verinum*make_unsized_dec(const char*txt);
|
|
|
|
|
static verinum*make_unsized_octal(const char*txt);
|
|
|
|
|
static verinum*make_unsized_hex(const char*txt);
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-04-14 23:42:01 +02:00
|
|
|
static int dec_buf_div2(char *buf);
|
|
|
|
|
|
2000-07-23 00:09:03 +02:00
|
|
|
static void process_timescale(const char*txt);
|
|
|
|
|
|
2008-05-01 07:07:09 +02:00
|
|
|
static list<int> keyword_mask_stack;
|
|
|
|
|
|
1999-06-22 05:59:37 +02:00
|
|
|
static int comment_enter;
|
2008-09-16 02:58:45 +02:00
|
|
|
static bool in_module = false;
|
1998-11-04 00:28:49 +01:00
|
|
|
%}
|
|
|
|
|
|
|
|
|
|
%x CCOMMENT
|
2002-02-15 06:20:58 +01:00
|
|
|
%x PCOMMENT
|
1999-06-22 05:59:37 +02:00
|
|
|
%x LCOMMENT
|
1998-11-04 00:28:49 +01:00
|
|
|
%x CSTRING
|
1998-11-23 01:20:22 +01:00
|
|
|
%s UDPTABLE
|
1999-06-12 22:35:27 +02:00
|
|
|
%x PPTIMESCALE
|
2004-06-13 06:56:53 +02:00
|
|
|
%x PPDEFAULT_NETTYPE
|
2008-05-01 07:07:09 +02:00
|
|
|
%x PPBEGIN_KEYWORDS
|
2007-06-14 05:50:00 +02:00
|
|
|
%s EDGES
|
2008-05-08 07:11:19 +02:00
|
|
|
%x REAL_SCALE
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-07-11 19:15:16 +02:00
|
|
|
W [ \t\b\f\r]+
|
|
|
|
|
|
2008-05-08 07:11:19 +02:00
|
|
|
S [afpnumkKMGT]
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
%%
|
|
|
|
|
|
1999-07-03 23:27:22 +02:00
|
|
|
^"#line"[ ]+\"[^\"]*\"[ ]+[0-9]+.* { line_directive(); }
|
1999-11-23 03:49:04 +01:00
|
|
|
^"`line"[ ]+[0-9]+[ ]+\"[^\"]*\".* { line_directive2(); }
|
1999-07-03 23:27:22 +02:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
[ \t\b\f\r] { ; }
|
|
|
|
|
\n { yylloc.first_line += 1; }
|
|
|
|
|
|
2003-08-28 06:11:17 +02:00
|
|
|
/* C++ style comments start with / / and run to the end of the
|
2002-02-15 06:20:58 +01:00
|
|
|
current line. These are very easy to handle. */
|
|
|
|
|
|
1999-06-22 05:59:37 +02:00
|
|
|
"//".* { comment_enter = YY_START; BEGIN(LCOMMENT); }
|
|
|
|
|
<LCOMMENT>. { yymore(); }
|
|
|
|
|
<LCOMMENT>\n { yylloc.first_line += 1; BEGIN(comment_enter); }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-02-15 06:20:58 +01:00
|
|
|
|
|
|
|
|
/* The contents of C-style comments are ignored, like white space. */
|
|
|
|
|
|
1999-06-22 05:59:37 +02:00
|
|
|
"/*" { comment_enter = YY_START; BEGIN(CCOMMENT); }
|
2008-10-05 05:35:22 +02:00
|
|
|
<CCOMMENT>. { ; }
|
|
|
|
|
<CCOMMENT>\n { yylloc.first_line += 1; }
|
1999-06-22 05:59:37 +02:00
|
|
|
<CCOMMENT>"*/" { BEGIN(comment_enter); }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2002-02-15 06:20:58 +01:00
|
|
|
|
2002-05-23 05:08:50 +02:00
|
|
|
"(*" { return K_PSTAR; }
|
|
|
|
|
"*)" { return K_STARP; }
|
1999-05-16 07:08:42 +02:00
|
|
|
"<<" { return K_LS; }
|
2003-06-18 05:55:18 +02:00
|
|
|
"<<<" { return K_LS; /* Note: Functionally, <<< is the same as <<. */}
|
|
|
|
|
">>" { return K_RS; }
|
|
|
|
|
">>>" { return K_RSS; }
|
2006-07-31 05:50:17 +02:00
|
|
|
"**" { return K_POW; }
|
1998-11-04 00:28:49 +01:00
|
|
|
"<=" { return K_LE; }
|
|
|
|
|
">=" { return K_GE; }
|
1999-06-19 05:21:21 +02:00
|
|
|
"=>" { return K_EG; }
|
|
|
|
|
"*>" { return K_SG; }
|
1998-11-07 18:05:05 +01:00
|
|
|
"==" { return K_EQ; }
|
|
|
|
|
"!=" { return K_NE; }
|
|
|
|
|
"===" { return K_CEQ; }
|
|
|
|
|
"!==" { return K_CNE; }
|
1999-03-15 03:43:32 +01:00
|
|
|
"||" { return K_LOR; }
|
|
|
|
|
"&&" { return K_LAND; }
|
2001-07-02 01:44:43 +02:00
|
|
|
"&&&" { return K_TAND; }
|
1999-06-13 19:30:23 +02:00
|
|
|
"~|" { return K_NOR; }
|
|
|
|
|
"~^" { return K_NXOR; }
|
|
|
|
|
"^~" { return K_NXOR; }
|
|
|
|
|
"~&" { return K_NAND; }
|
1999-12-31 04:24:30 +01:00
|
|
|
"->" { return K_TRIGGER; }
|
2001-07-02 01:44:43 +02:00
|
|
|
"+:" { return K_PO_POS; }
|
|
|
|
|
"-:" { return K_PO_NEG; }
|
2008-05-11 21:00:11 +02:00
|
|
|
"<+" { return K_CONTRIBUTE; }
|
1999-06-13 19:30:23 +02:00
|
|
|
|
2003-06-17 06:23:25 +02:00
|
|
|
/* Watch out for the tricky case of (*). Cannot parse this as "(*"
|
|
|
|
|
and ")", but since I know that this is really ( * ), replace it
|
|
|
|
|
with "*" and return that. */
|
2006-02-02 06:21:45 +01:00
|
|
|
"("{W}*"*"{W}*")" { return '*'; }
|
2003-06-17 06:23:25 +02:00
|
|
|
|
2007-06-14 05:50:00 +02:00
|
|
|
<EDGES>"]" { BEGIN(0); return yytext[0]; }
|
1999-05-16 07:08:42 +02:00
|
|
|
[}{;:\[\],()#=.@&!?<>%|^~+*/-] { return yytext[0]; }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
\" { BEGIN(CSTRING); }
|
2007-02-09 06:19:04 +01:00
|
|
|
<CSTRING>\\\\ { yymore(); /* Catch \\, which is a \ escaping itself */ }
|
|
|
|
|
<CSTRING>\\\" { yymore(); /* Catch \", which is an escaped quote */ }
|
1998-11-04 00:28:49 +01:00
|
|
|
<CSTRING>\n { BEGIN(0);
|
2009-01-09 02:03:33 +01:00
|
|
|
yylval.text = strdupnew(yytext);
|
1998-11-04 00:28:49 +01:00
|
|
|
VLerror(yylloc, "Missing close quote of string.");
|
2000-06-27 06:36:29 +02:00
|
|
|
yylloc.first_line += 1;
|
1998-11-04 00:28:49 +01:00
|
|
|
return STRING; }
|
|
|
|
|
<CSTRING>\" { BEGIN(0);
|
2009-01-09 02:03:33 +01:00
|
|
|
yylval.text = strdupnew(yytext);
|
1999-07-10 03:03:18 +02:00
|
|
|
yylval.text[strlen(yytext)-1] = 0;
|
1998-11-04 00:28:49 +01:00
|
|
|
return STRING; }
|
|
|
|
|
<CSTRING>. { yymore(); }
|
|
|
|
|
|
2000-03-05 07:14:10 +01:00
|
|
|
<UDPTABLE>\(\?0\) { return '_'; }
|
|
|
|
|
<UDPTABLE>\(\?1\) { return '+'; }
|
|
|
|
|
<UDPTABLE>\(\?[xX]\) { return '%'; }
|
|
|
|
|
<UDPTABLE>\(\?\?\) { return '*'; }
|
|
|
|
|
<UDPTABLE>\(01\) { return 'r'; }
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>\(0[xX]\) { return 'Q'; }
|
2003-03-18 02:36:14 +01:00
|
|
|
<UDPTABLE>\(b[xX]\) { return 'q'; }
|
2005-09-14 17:01:07 +02:00
|
|
|
<UDPTABLE>\(b0\) { return 'f'; /* b0 is 10|00, but only 10 is meaningful */}
|
|
|
|
|
<UDPTABLE>\(b1\) { return 'r'; /* b1 is 11|01, but only 01 is meaningful */}
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>\(0\?\) { return 'P'; }
|
2000-03-05 07:14:10 +01:00
|
|
|
<UDPTABLE>\(10\) { return 'f'; }
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>\(1[xX]\) { return 'M'; }
|
|
|
|
|
<UDPTABLE>\(1\?\) { return 'N'; }
|
2000-03-05 07:14:10 +01:00
|
|
|
<UDPTABLE>\([xX]0\) { return 'F'; }
|
|
|
|
|
<UDPTABLE>\([xX]1\) { return 'R'; }
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>\([xX]\?\) { return 'B'; }
|
1998-11-25 03:35:53 +01:00
|
|
|
<UDPTABLE>[bB] { return 'b'; }
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>[lL] { return 'l'; /* IVL extension */ }
|
|
|
|
|
<UDPTABLE>[hH] { return 'h'; /* IVL extension */ }
|
1998-11-25 03:35:53 +01:00
|
|
|
<UDPTABLE>[fF] { return 'f'; }
|
|
|
|
|
<UDPTABLE>[rR] { return 'r'; }
|
|
|
|
|
<UDPTABLE>[xX] { return 'x'; }
|
2001-06-18 02:51:23 +02:00
|
|
|
<UDPTABLE>[nN] { return 'n'; }
|
|
|
|
|
<UDPTABLE>[pP] { return 'p'; }
|
|
|
|
|
<UDPTABLE>[01\?\*\-] { return yytext[0]; }
|
1998-11-23 01:20:22 +01:00
|
|
|
|
2007-06-14 05:50:00 +02:00
|
|
|
<EDGES>"01" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"0x" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"0z" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"10" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"1x" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"1z" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"x0" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"x1" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"z0" { return K_edge_descriptor; }
|
|
|
|
|
<EDGES>"z1" { return K_edge_descriptor; }
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
[a-zA-Z_][a-zA-Z0-9$_]* {
|
2000-03-12 18:09:40 +01:00
|
|
|
int rc = lexor_keyword_code(yytext, yyleng);
|
2005-07-07 18:22:49 +02:00
|
|
|
switch (rc) {
|
|
|
|
|
case IDENTIFIER:
|
2008-03-28 04:30:53 +01:00
|
|
|
yylval.text = strdupnew(yytext);
|
2001-11-06 03:52:19 +01:00
|
|
|
if (strncmp(yylval.text,"PATHPULSE$", 10) == 0)
|
|
|
|
|
rc = PATHPULSE_IDENTIFIER;
|
2005-07-07 18:22:49 +02:00
|
|
|
break;
|
|
|
|
|
|
2007-06-14 05:50:00 +02:00
|
|
|
case K_edge:
|
|
|
|
|
BEGIN(EDGES);
|
|
|
|
|
break;
|
|
|
|
|
|
2008-09-16 02:58:45 +02:00
|
|
|
case K_module:
|
|
|
|
|
case K_macromodule:
|
|
|
|
|
in_module = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case K_endmodule:
|
|
|
|
|
in_module = false;
|
|
|
|
|
break;
|
|
|
|
|
|
2005-07-07 18:22:49 +02:00
|
|
|
default:
|
1998-11-04 00:28:49 +01:00
|
|
|
yylval.text = 0;
|
2005-07-07 18:22:49 +02:00
|
|
|
break;
|
2001-11-06 03:52:19 +01:00
|
|
|
}
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2008-05-11 21:00:11 +02:00
|
|
|
/* If this identifier names a discipline, then return this as
|
|
|
|
|
a DISCIPLINE_IDENTIFIER and return the discipline as the
|
|
|
|
|
value instead. */
|
|
|
|
|
if (rc == IDENTIFIER && gn_verilog_ams_flag) {
|
|
|
|
|
perm_string tmp = lex_strings.make(yylval.text);
|
2008-11-02 17:10:41 +01:00
|
|
|
map<perm_string,ivl_discipline_t>::iterator cur = disciplines.find(tmp);
|
2008-05-11 21:00:11 +02:00
|
|
|
if (cur != disciplines.end()) {
|
|
|
|
|
yylval.discipline = (*cur).second;
|
|
|
|
|
rc = DISCIPLINE_IDENTIFIER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2000-03-12 18:09:40 +01:00
|
|
|
return rc;
|
2008-02-16 00:05:39 +01:00
|
|
|
}
|
2000-03-12 18:09:40 +01:00
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2001-12-29 20:00:13 +01:00
|
|
|
\\[^ \t\b\f\r\n]+ {
|
2008-03-28 04:30:53 +01:00
|
|
|
yylval.text = strdupnew(yytext+1);
|
1998-11-04 00:28:49 +01:00
|
|
|
return IDENTIFIER; }
|
|
|
|
|
|
|
|
|
|
\$([a-zA-Z0-9$_]+) {
|
2001-08-31 19:38:41 +02:00
|
|
|
if (strcmp(yytext,"$setuphold") == 0)
|
|
|
|
|
return K_Ssetuphold;
|
1998-11-23 01:20:22 +01:00
|
|
|
if (strcmp(yytext,"$attribute") == 0)
|
|
|
|
|
return KK_attribute;
|
2001-07-02 01:44:43 +02:00
|
|
|
if (strcmp(yytext,"$hold") == 0)
|
|
|
|
|
return K_Shold;
|
|
|
|
|
if (strcmp(yytext,"$period") == 0)
|
|
|
|
|
return K_Speriod;
|
|
|
|
|
if (strcmp(yytext,"$recovery") == 0)
|
|
|
|
|
return K_Srecovery;
|
2003-08-31 23:14:28 +02:00
|
|
|
if (strcmp(yytext,"$recrem") == 0)
|
|
|
|
|
return K_Srecrem;
|
2001-07-02 01:44:43 +02:00
|
|
|
if (strcmp(yytext,"$setup") == 0)
|
|
|
|
|
return K_Ssetup;
|
|
|
|
|
if (strcmp(yytext,"$width") == 0)
|
|
|
|
|
return K_Swidth;
|
2008-03-28 04:30:53 +01:00
|
|
|
yylval.text = strdupnew(yytext);
|
1998-11-04 00:28:49 +01:00
|
|
|
return SYSTEM_IDENTIFIER; }
|
|
|
|
|
|
1999-06-14 05:15:14 +02:00
|
|
|
|
2000-01-07 04:45:49 +01:00
|
|
|
\'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext);
|
2003-04-14 05:37:47 +02:00
|
|
|
return BASED_NUMBER; }
|
2007-09-17 19:08:07 +02:00
|
|
|
\'[sS]?[dD][ \t]*[xzXZ?]_* { yylval.number = make_undef_highz_dec(yytext);
|
|
|
|
|
return BASED_NUMBER; }
|
2000-01-07 04:45:49 +01:00
|
|
|
\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext);
|
2003-04-14 05:37:47 +02:00
|
|
|
return BASED_NUMBER; }
|
2000-01-07 04:45:49 +01:00
|
|
|
\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext);
|
2003-04-14 05:37:47 +02:00
|
|
|
return BASED_NUMBER; }
|
2000-01-07 04:45:49 +01:00
|
|
|
\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext);
|
2003-04-14 05:37:47 +02:00
|
|
|
return BASED_NUMBER; }
|
1999-05-06 06:09:28 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
[0-9][0-9_]* {
|
|
|
|
|
yylval.number = make_unsized_dec(yytext);
|
2007-10-12 01:37:57 +02:00
|
|
|
based_size = yylval.number->as_ulong();
|
2003-04-14 05:37:47 +02:00
|
|
|
return DEC_NUMBER; }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2008-05-08 07:11:19 +02:00
|
|
|
/* These rules handle the scaled real literals from Verilog-AMS. The
|
|
|
|
|
value is a number with a single letter scale factor. If
|
|
|
|
|
verilog-ams is not enabled, then reject this rule. If it is
|
|
|
|
|
enabled, then collect the scale and use it to scale the value. */
|
|
|
|
|
[0-9][0-9_]*\.[0-9][0-9_]*/{S} {
|
|
|
|
|
if (!gn_verilog_ams_flag) REJECT;
|
|
|
|
|
BEGIN(REAL_SCALE);
|
|
|
|
|
yymore(); }
|
|
|
|
|
|
|
|
|
|
[0-9][0-9_]*/{S} {
|
|
|
|
|
if (!gn_verilog_ams_flag) REJECT;
|
|
|
|
|
BEGIN(REAL_SCALE);
|
|
|
|
|
yymore(); }
|
|
|
|
|
|
|
|
|
|
<REAL_SCALE>{S} {
|
|
|
|
|
size_t token_len = strlen(yytext);
|
|
|
|
|
char*tmp = new char[token_len + 5];
|
|
|
|
|
int scale = 0;
|
|
|
|
|
strcpy(tmp, yytext);
|
|
|
|
|
switch (tmp[token_len-1]) {
|
|
|
|
|
case 'a': scale = -18; break; /* atto- */
|
|
|
|
|
case 'f': scale = -15; break; /* femto- */
|
|
|
|
|
case 'p': scale = -12; break; /* pico- */
|
|
|
|
|
case 'n': scale = -9; break; /* nano- */
|
|
|
|
|
case 'u': scale = -6; break; /* micro- */
|
|
|
|
|
case 'm': scale = -3; break; /* milli- */
|
|
|
|
|
case 'k': scale = 3; break; /* kilo- */
|
|
|
|
|
case 'K': scale = 3; break; /* kilo- */
|
|
|
|
|
case 'M': scale = 6; break; /* mega- */
|
|
|
|
|
case 'G': scale = 9; break; /* giga- */
|
|
|
|
|
case 'T': scale = 12; break; /* tera- */
|
|
|
|
|
default: assert(0); break;
|
|
|
|
|
}
|
|
|
|
|
snprintf(tmp+token_len-1, 5, "e%d", scale);
|
|
|
|
|
yylval.realtime = new verireal(tmp);
|
|
|
|
|
delete[]tmp;
|
|
|
|
|
|
|
|
|
|
BEGIN(0);
|
|
|
|
|
return REALTIME; }
|
|
|
|
|
|
1999-06-15 04:50:02 +02:00
|
|
|
[0-9][0-9_]*\.[0-9][0-9_]*([Ee][+-]?[0-9][0-9_]*)? {
|
|
|
|
|
yylval.realtime = new verireal(yytext);
|
|
|
|
|
return REALTIME; }
|
|
|
|
|
|
|
|
|
|
[0-9][0-9_]*[Ee][+-]?[0-9][0-9_]* {
|
|
|
|
|
yylval.realtime = new verireal(yytext);
|
|
|
|
|
return REALTIME; }
|
|
|
|
|
|
1999-07-11 19:15:16 +02:00
|
|
|
|
|
|
|
|
/* Notice and handle the timescale directive. */
|
1999-06-15 04:50:02 +02:00
|
|
|
|
2001-04-28 20:43:18 +02:00
|
|
|
^{W}?`timescale { BEGIN(PPTIMESCALE); }
|
2000-07-23 00:09:03 +02:00
|
|
|
<PPTIMESCALE>.* { process_timescale(yytext); }
|
1999-06-12 22:35:27 +02:00
|
|
|
<PPTIMESCALE>\n {
|
2008-09-16 02:58:45 +02:00
|
|
|
if (in_module) {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
|
|
|
|
|
"`timescale directive can not be inside a module "
|
|
|
|
|
"definition." << endl;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
1999-06-12 22:35:27 +02:00
|
|
|
yylloc.first_line += 1;
|
|
|
|
|
BEGIN(0); }
|
|
|
|
|
|
1998-12-09 05:02:47 +01:00
|
|
|
|
1999-07-11 19:15:16 +02:00
|
|
|
/* These are directives that I do not yet support. I think that IVL
|
|
|
|
|
should handle these, not an external preprocessor. */
|
|
|
|
|
|
2008-04-23 22:55:04 +02:00
|
|
|
^{W}?`celldefine{W}?.* { }
|
|
|
|
|
^{W}?`default_decay_time{W}?.* { }
|
|
|
|
|
^{W}?`default_trireg_strength{W}?.* { }
|
2001-04-28 20:43:18 +02:00
|
|
|
^{W}?`delay_mode_distributed{W}?.* { }
|
2008-04-23 22:55:04 +02:00
|
|
|
^{W}?`delay_mode_unit{W}?.* { }
|
|
|
|
|
^{W}?`delay_mode_path{W}?.* { }
|
|
|
|
|
^{W}?`delay_mode_zero{W}?.* { }
|
|
|
|
|
^{W}?`disable_portfaults{W}?.* { }
|
|
|
|
|
^{W}?`enable_portfaults{W}?.* { }
|
|
|
|
|
^{W}?`endcelldefine{W}?.* { }
|
|
|
|
|
`endprotect { }
|
|
|
|
|
^{W}?`line{W}?.* { }
|
|
|
|
|
^{W}?`nosuppress_faults{W}?.* { }
|
|
|
|
|
^{W}?`nounconnected_drive{W}?.* { }
|
|
|
|
|
`protect { }
|
|
|
|
|
^{W}?`resetall{W}?.* { }
|
|
|
|
|
^{W}?`suppress_faults{W}?.* { }
|
|
|
|
|
^{W}?`unconnected_drive{W}?.* { }
|
|
|
|
|
^{W}?`uselib{W}?.* { }
|
1999-07-11 19:15:16 +02:00
|
|
|
|
2008-05-01 07:07:09 +02:00
|
|
|
^{W}?`begin_keywords{W}? { BEGIN(PPBEGIN_KEYWORDS); }
|
|
|
|
|
|
|
|
|
|
<PPBEGIN_KEYWORDS>\"[a-zA-Z0-9 -]*\".* {
|
|
|
|
|
keyword_mask_stack.push_front(lexor_keyword_mask);
|
|
|
|
|
|
|
|
|
|
char*word = yytext+1;
|
|
|
|
|
char*tail = strchr(word, '"');
|
|
|
|
|
tail[0] = 0;
|
|
|
|
|
if (strcmp(word,"1364-1995") == 0) {
|
|
|
|
|
lexor_keyword_mask = GN_KEYWORDS_1364_1995;
|
|
|
|
|
} else if (strcmp(word,"1364-2001") == 0) {
|
|
|
|
|
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
|
|
|
|
|GN_KEYWORDS_1364_2001
|
|
|
|
|
|GN_KEYWORDS_1364_2001_CONFIG;
|
|
|
|
|
} else if (strcmp(word,"1364-2001-noconfig") == 0) {
|
|
|
|
|
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
|
|
|
|
|GN_KEYWORDS_1364_2001;
|
|
|
|
|
} else if (strcmp(word,"1364-2005") == 0) {
|
|
|
|
|
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
|
|
|
|
|GN_KEYWORDS_1364_2001
|
|
|
|
|
|GN_KEYWORDS_1364_2001_CONFIG
|
|
|
|
|
|GN_KEYWORDS_1364_2005;
|
2008-05-03 01:28:48 +02:00
|
|
|
} else if (strcmp(word,"VAMS-2.3") == 0) {
|
|
|
|
|
lexor_keyword_mask = GN_KEYWORDS_1364_1995
|
|
|
|
|
|GN_KEYWORDS_1364_2001
|
|
|
|
|
|GN_KEYWORDS_1364_2001_CONFIG
|
|
|
|
|
|GN_KEYWORDS_1364_2005
|
|
|
|
|
|GN_KEYWORDS_VAMS_2_3;
|
2008-05-01 07:07:09 +02:00
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "%s:%d: Ignoring unknown keywords string: %s\n",
|
|
|
|
|
yylloc.text, yylloc.first_line, word);
|
|
|
|
|
}
|
|
|
|
|
BEGIN(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<PPBEGIN_KEYWORDS>.* {
|
|
|
|
|
fprintf(stderr, "%s:%d: Malformed keywords specification: %s\n",
|
|
|
|
|
yylloc.text, yylloc.first_line, yytext);
|
|
|
|
|
BEGIN(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^{W}?`end_keywords{W}?.* {
|
|
|
|
|
if (!keyword_mask_stack.empty()) {
|
|
|
|
|
lexor_keyword_mask = keyword_mask_stack.front();
|
|
|
|
|
keyword_mask_stack.pop_front();
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(stderr, "%s:%d: Mismatched end_keywords directive\n",
|
|
|
|
|
yylloc.text, yylloc.first_line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-13 06:56:53 +02:00
|
|
|
/* Notice and handle the default_nettype directive. The lexor
|
|
|
|
|
detects the default_nettype keyword, and the second part of the
|
|
|
|
|
rule collects the rest of the line and processes it. We only need
|
|
|
|
|
to look for the first work, and interpret it. */
|
|
|
|
|
|
|
|
|
|
`default_nettype{W}? { BEGIN(PPDEFAULT_NETTYPE); }
|
|
|
|
|
<PPDEFAULT_NETTYPE>.* {
|
|
|
|
|
NetNet::Type net_type;
|
|
|
|
|
size_t wordlen = strcspn(yytext, " \t\f\r\n");
|
|
|
|
|
yytext[wordlen] = 0;
|
|
|
|
|
if (strcmp(yytext,"wire") == 0) {
|
|
|
|
|
net_type = NetNet::WIRE;
|
|
|
|
|
|
|
|
|
|
} else if (strcmp(yytext,"none") == 0) {
|
|
|
|
|
net_type = NetNet::NONE;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line
|
2008-09-16 02:58:45 +02:00
|
|
|
<< ": error: Net type " << yytext
|
2004-06-13 06:56:53 +02:00
|
|
|
<< " is not a valid (and supported)"
|
|
|
|
|
<< " default net type." << endl;
|
|
|
|
|
net_type = NetNet::WIRE;
|
|
|
|
|
error_count += 1;
|
|
|
|
|
}
|
|
|
|
|
pform_set_default_nettype(net_type, yylloc.text, yylloc.first_line);
|
2008-02-16 00:05:39 +01:00
|
|
|
}
|
2004-06-13 06:56:53 +02:00
|
|
|
<PPDEFAULT_NETTYPE>\n {
|
|
|
|
|
yylloc.first_line += 1;
|
|
|
|
|
BEGIN(0); }
|
|
|
|
|
|
1999-07-11 19:15:16 +02:00
|
|
|
|
|
|
|
|
/* These are directives that are not supported by me and should have
|
|
|
|
|
been handled by an external preprocessor such as ivlpp. */
|
|
|
|
|
|
2001-04-28 20:43:18 +02:00
|
|
|
^{W}?`define{W}?.* {
|
1999-07-11 19:15:16 +02:00
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `define not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^{W}?`else{W}?.* {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `else not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^{W}?`endif{W}?.* {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `endif not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^{W}?`ifdef{W}?.* {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `ifdef not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^`include{W}?.* {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `include not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
^`undef{W}?.* {
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line <<
|
2008-09-16 02:58:45 +02:00
|
|
|
": warning: `undef not supported. Use an external preprocessor."
|
1999-07-11 19:15:16 +02:00
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-05-28 06:21:12 +02:00
|
|
|
`{W} { cerr << yylloc.text << ":" << yylloc.first_line << ": error: "
|
|
|
|
|
<< "Stray tic (`) here. Perhaps you put white space" << endl;
|
|
|
|
|
cerr << yylloc.text << ":" << yylloc.first_line << ": : "
|
|
|
|
|
<< "between the tic and preprocessor directive?"
|
|
|
|
|
<< endl;
|
|
|
|
|
error_count += 1; }
|
1999-07-11 19:15:16 +02:00
|
|
|
|
|
|
|
|
/* Final catchall. something got lost or mishandled. */
|
2008-01-04 20:33:03 +01:00
|
|
|
/* XXX Should we tell the luser something about the lexical state? */
|
1999-07-11 19:15:16 +02:00
|
|
|
|
2008-01-04 20:33:03 +01:00
|
|
|
<*>.|\n { cerr << yylloc.text << ":" << yylloc.first_line
|
2003-05-28 06:21:12 +02:00
|
|
|
<< ": error: unmatched character (";
|
1998-11-04 00:28:49 +01:00
|
|
|
if (isgraph(yytext[0]))
|
|
|
|
|
cerr << yytext[0];
|
|
|
|
|
else
|
2002-12-04 03:07:00 +01:00
|
|
|
cerr << "hex " << hex << (0xffU & ((unsigned) (yytext[0])));
|
1998-11-04 00:28:49 +01:00
|
|
|
|
2003-05-28 06:21:12 +02:00
|
|
|
cerr << ")" << endl;
|
|
|
|
|
error_count += 1; }
|
1998-11-04 00:28:49 +01:00
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
1998-11-23 01:20:22 +01:00
|
|
|
/*
|
|
|
|
|
* The UDP state table needs some slightly different treatment by the
|
|
|
|
|
* lexor. The level characters are normally accepted as other things,
|
|
|
|
|
* so the parser needs to switch my mode when it believes in needs to.
|
|
|
|
|
*/
|
|
|
|
|
void lex_start_table()
|
|
|
|
|
{
|
|
|
|
|
BEGIN(UDPTABLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void lex_end_table()
|
|
|
|
|
{
|
|
|
|
|
BEGIN(INITIAL);
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-06 06:09:28 +02:00
|
|
|
static verinum*make_unsized_binary(const char*txt)
|
|
|
|
|
{
|
2000-01-07 04:45:49 +01:00
|
|
|
bool sign_flag = false;
|
1999-06-14 05:15:14 +02:00
|
|
|
const char*ptr = txt;
|
|
|
|
|
assert(*ptr == '\'');
|
|
|
|
|
ptr += 1;
|
2000-01-07 04:45:49 +01:00
|
|
|
|
|
|
|
|
if (tolower(*ptr) == 's') {
|
|
|
|
|
sign_flag = true;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
2003-06-11 03:58:21 +02:00
|
|
|
|
1999-06-14 05:15:14 +02:00
|
|
|
assert(tolower(*ptr) == 'b');
|
2003-06-11 03:58:21 +02:00
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
1999-06-14 05:15:14 +02:00
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
unsigned size = 0;
|
|
|
|
|
for (const char*idx = ptr ; *idx ; idx += 1)
|
|
|
|
|
if (*idx != '_') size += 1;
|
|
|
|
|
|
2007-10-12 01:37:57 +02:00
|
|
|
if ((based_size > 0) && (size > based_size)) yywarn(yylloc,
|
|
|
|
|
"extra digits given for sized binary constant.");
|
|
|
|
|
|
1999-06-14 05:15:14 +02:00
|
|
|
verinum::V*bits = new verinum::V[size];
|
|
|
|
|
|
|
|
|
|
unsigned idx = size;
|
|
|
|
|
while (*ptr) {
|
|
|
|
|
switch (ptr[0]) {
|
|
|
|
|
case '0':
|
|
|
|
|
bits[--idx] = verinum::V0;
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
bits[--idx] = verinum::V1;
|
|
|
|
|
break;
|
1999-07-08 04:06:39 +02:00
|
|
|
case 'z': case 'Z': case '?':
|
1999-06-14 05:15:14 +02:00
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
break;
|
|
|
|
|
case 'x': case 'X':
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
break;
|
|
|
|
|
case '_':
|
|
|
|
|
break;
|
|
|
|
|
default:
|
1999-07-07 02:24:42 +02:00
|
|
|
fprintf(stderr, "%c\n", ptr[0]);
|
1999-06-14 05:15:14 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-27 06:36:11 +01:00
|
|
|
verinum*out = new verinum(bits, size, false);
|
2000-01-07 04:45:49 +01:00
|
|
|
out->has_sign(sign_flag);
|
|
|
|
|
delete[]bits;
|
|
|
|
|
return out;
|
1999-05-06 06:09:28 +02:00
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-05-06 06:09:28 +02:00
|
|
|
static verinum*make_unsized_octal(const char*txt)
|
|
|
|
|
{
|
2000-01-07 04:45:49 +01:00
|
|
|
bool sign_flag = false;
|
1999-06-13 19:30:23 +02:00
|
|
|
const char*ptr = txt;
|
|
|
|
|
assert(*ptr == '\'');
|
|
|
|
|
ptr += 1;
|
2000-01-07 04:45:49 +01:00
|
|
|
|
|
|
|
|
if (tolower(*ptr) == 's') {
|
|
|
|
|
sign_flag = true;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-13 19:30:23 +02:00
|
|
|
assert(tolower(*ptr) == 'o');
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
1999-06-14 05:15:14 +02:00
|
|
|
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
unsigned size = 0;
|
|
|
|
|
for (const char*idx = ptr ; *idx ; idx += 1)
|
|
|
|
|
if (*idx != '_') size += 3;
|
|
|
|
|
|
2007-10-12 01:37:57 +02:00
|
|
|
if (based_size > 0) {
|
|
|
|
|
int rem = based_size % 3;
|
|
|
|
|
if (rem != 0) based_size += 3 - rem;
|
|
|
|
|
if (size > based_size) yywarn(yylloc,
|
|
|
|
|
"extra digits given for sized octal constant.");
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-13 19:30:23 +02:00
|
|
|
verinum::V*bits = new verinum::V[size];
|
|
|
|
|
|
|
|
|
|
unsigned idx = size;
|
|
|
|
|
while (*ptr) {
|
|
|
|
|
unsigned val;
|
|
|
|
|
switch (ptr[0]) {
|
|
|
|
|
case '0': case '1': case '2': case '3':
|
|
|
|
|
case '4': case '5': case '6': case '7':
|
|
|
|
|
val = *ptr - '0';
|
|
|
|
|
bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
|
|
|
|
|
break;
|
1999-07-07 02:24:42 +02:00
|
|
|
case 'x': case 'X':
|
1999-06-13 19:30:23 +02:00
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
break;
|
1999-07-08 04:06:39 +02:00
|
|
|
case 'z': case 'Z': case '?':
|
1999-06-13 19:30:23 +02:00
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
break;
|
1999-06-14 05:15:14 +02:00
|
|
|
case '_':
|
|
|
|
|
break;
|
1999-06-13 19:30:23 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-27 06:36:11 +01:00
|
|
|
verinum*out = new verinum(bits, size, false);
|
2000-01-07 04:45:49 +01:00
|
|
|
out->has_sign(sign_flag);
|
|
|
|
|
delete[]bits;
|
|
|
|
|
return out;
|
1999-05-06 06:09:28 +02:00
|
|
|
}
|
|
|
|
|
|
1998-11-04 00:28:49 +01:00
|
|
|
|
1999-05-06 06:09:28 +02:00
|
|
|
static verinum*make_unsized_hex(const char*txt)
|
|
|
|
|
{
|
2000-01-07 04:45:49 +01:00
|
|
|
bool sign_flag = false;
|
1999-06-13 19:30:23 +02:00
|
|
|
const char*ptr = txt;
|
|
|
|
|
assert(*ptr == '\'');
|
|
|
|
|
ptr += 1;
|
2000-01-07 04:45:49 +01:00
|
|
|
|
|
|
|
|
if (tolower(*ptr) == 's') {
|
|
|
|
|
sign_flag = true;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
1999-06-13 19:30:23 +02:00
|
|
|
assert(tolower(*ptr) == 'h');
|
1999-06-14 05:15:14 +02:00
|
|
|
|
1999-06-13 19:30:23 +02:00
|
|
|
ptr += 1;
|
1999-06-14 05:15:14 +02:00
|
|
|
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
unsigned size = 0;
|
|
|
|
|
for (const char*idx = ptr ; *idx ; idx += 1)
|
|
|
|
|
if (*idx != '_') size += 4;
|
1999-06-13 19:30:23 +02:00
|
|
|
|
2007-10-12 01:37:57 +02:00
|
|
|
if (based_size > 0) {
|
|
|
|
|
int rem = based_size % 4;
|
|
|
|
|
if (rem != 0) based_size += 4 - rem;
|
|
|
|
|
if (size > based_size) yywarn(yylloc,
|
|
|
|
|
"extra digits given for sized hex constant.");
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-13 19:30:23 +02:00
|
|
|
verinum::V*bits = new verinum::V[size];
|
|
|
|
|
|
|
|
|
|
unsigned idx = size;
|
|
|
|
|
while (*ptr) {
|
|
|
|
|
unsigned val;
|
|
|
|
|
switch (ptr[0]) {
|
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
|
val = *ptr - '0';
|
|
|
|
|
bits[--idx] = (val&8) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
|
|
|
|
|
break;
|
|
|
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
|
|
|
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
|
|
|
|
val = tolower(*ptr) - 'a' + 10;
|
|
|
|
|
bits[--idx] = (val&8) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&4) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&2) ? verinum::V1 : verinum::V0;
|
|
|
|
|
bits[--idx] = (val&1) ? verinum::V1 : verinum::V0;
|
|
|
|
|
break;
|
1999-07-07 02:24:42 +02:00
|
|
|
case 'x': case 'X':
|
1999-06-13 19:30:23 +02:00
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
bits[--idx] = verinum::Vx;
|
|
|
|
|
break;
|
1999-07-08 04:06:39 +02:00
|
|
|
case 'z': case 'Z': case '?':
|
1999-06-13 19:30:23 +02:00
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
bits[--idx] = verinum::Vz;
|
|
|
|
|
break;
|
1999-06-14 05:15:14 +02:00
|
|
|
case '_':
|
|
|
|
|
break;
|
1999-06-13 19:30:23 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-27 06:36:11 +01:00
|
|
|
verinum*out = new verinum(bits, size, false);
|
2000-01-07 04:45:49 +01:00
|
|
|
out->has_sign(sign_flag);
|
|
|
|
|
delete[]bits;
|
|
|
|
|
return out;
|
1999-05-06 06:09:28 +02:00
|
|
|
}
|
|
|
|
|
|
2002-04-14 23:42:01 +02:00
|
|
|
|
|
|
|
|
/* Divide the integer given by the string by 2. Return the remainder bit. */
|
|
|
|
|
static int dec_buf_div2(char *buf)
|
|
|
|
|
{
|
|
|
|
|
int partial;
|
|
|
|
|
int len = strlen(buf);
|
|
|
|
|
char *dst_ptr;
|
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
|
|
partial = 0;
|
|
|
|
|
pos = 0;
|
|
|
|
|
|
|
|
|
|
/* dst_ptr overwrites buf, but all characters that are overwritten
|
|
|
|
|
were already used by the reader. */
|
|
|
|
|
dst_ptr = buf;
|
|
|
|
|
|
|
|
|
|
while(buf[pos] == '0')
|
|
|
|
|
++pos;
|
|
|
|
|
|
|
|
|
|
for(; pos<len; ++pos){
|
|
|
|
|
if (buf[pos]=='_')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
assert(isdigit(buf[pos]));
|
|
|
|
|
|
|
|
|
|
partial= partial*10 + (buf[pos]-'0');
|
|
|
|
|
|
|
|
|
|
if (partial >= 2){
|
|
|
|
|
*dst_ptr = partial/2 + '0';
|
|
|
|
|
partial = partial & 1;
|
|
|
|
|
|
|
|
|
|
++dst_ptr;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
*dst_ptr = '0';
|
|
|
|
|
++dst_ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If result of division was zero string, it should remain that way.
|
|
|
|
|
// Don't eat the last zero...
|
|
|
|
|
if (dst_ptr == buf){
|
|
|
|
|
*dst_ptr = '0';
|
|
|
|
|
++dst_ptr;
|
|
|
|
|
}
|
|
|
|
|
*dst_ptr = 0;
|
|
|
|
|
|
|
|
|
|
return partial;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-17 19:08:07 +02:00
|
|
|
/* Support a single x, z or ? as a decimal constant (from 1364-2005). */
|
|
|
|
|
static verinum* make_undef_highz_dec(const char* ptr)
|
|
|
|
|
{
|
|
|
|
|
bool signed_flag = false;
|
|
|
|
|
|
|
|
|
|
assert(*ptr == '\'');
|
|
|
|
|
/* The number may have decorations of the form 'sd<code>,
|
|
|
|
|
possibly with space between the d and the <code>.
|
|
|
|
|
Also, the 's' is optional, and marks the number as signed. */
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
if (tolower(*ptr) == 's') {
|
|
|
|
|
signed_flag = true;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(tolower(*ptr) == 'd');
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
/* Process the code. */
|
|
|
|
|
verinum::V* bits = new verinum::V[1];
|
|
|
|
|
switch (*ptr) {
|
|
|
|
|
case 'x':
|
|
|
|
|
case 'X':
|
|
|
|
|
bits[0] = verinum::Vx;
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
case 'Z':
|
|
|
|
|
case '?':
|
|
|
|
|
bits[0] = verinum::Vz;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
ptr += 1;
|
|
|
|
|
while (*ptr == '_') ptr += 1;
|
|
|
|
|
assert(*ptr == 0);
|
|
|
|
|
|
|
|
|
|
verinum*out = new verinum(bits, 1, false);
|
|
|
|
|
out->has_sign(signed_flag);
|
|
|
|
|
delete[]bits;
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
1999-03-16 05:44:45 +01:00
|
|
|
/*
|
1999-06-12 05:41:30 +02:00
|
|
|
* Making a decimal number is much easier then the other base numbers
|
2003-04-14 05:37:47 +02:00
|
|
|
* because there are no z or x values to worry about. It is much
|
|
|
|
|
* harder then other base numbers because the width needed in bits is
|
|
|
|
|
* hard to calculate.
|
1999-03-16 05:44:45 +01:00
|
|
|
*/
|
2003-04-14 05:37:47 +02:00
|
|
|
|
|
|
|
|
static verinum*make_unsized_dec(const char*ptr)
|
1999-03-16 05:44:45 +01:00
|
|
|
{
|
2002-04-14 23:42:01 +02:00
|
|
|
char buf[4096];
|
2000-01-07 04:45:49 +01:00
|
|
|
bool signed_flag = false;
|
2003-04-14 05:37:47 +02:00
|
|
|
unsigned idx;
|
2002-04-14 23:42:01 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
if (ptr[0] == '\'') {
|
|
|
|
|
/* The number has decorations of the form 'sd<digits>,
|
|
|
|
|
possibly with space between the d and the <digits>.
|
2008-06-12 19:04:29 +02:00
|
|
|
Also, the 's' is optional, and marks the number as
|
2003-04-14 05:37:47 +02:00
|
|
|
signed. */
|
2000-01-07 04:45:49 +01:00
|
|
|
ptr += 1;
|
1999-03-16 05:44:45 +01:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
if (tolower(*ptr) == 's') {
|
|
|
|
|
signed_flag = true;
|
|
|
|
|
ptr += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(tolower(*ptr) == 'd');
|
1999-06-14 05:15:14 +02:00
|
|
|
ptr += 1;
|
2000-10-23 00:27:59 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
|
|
|
|
|
ptr += 1;
|
1999-03-16 05:44:45 +01:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
} else {
|
|
|
|
|
/* ... or an undecorated decimal number is passed
|
|
|
|
|
it. These numbers are treated as signed decimal. */
|
|
|
|
|
assert(isdigit(*ptr));
|
|
|
|
|
signed_flag = true;
|
|
|
|
|
}
|
1999-03-16 05:44:45 +01:00
|
|
|
|
|
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
/* Copy the digits into a buffer that I can use to do in-place
|
|
|
|
|
decimal divides. */
|
|
|
|
|
idx = 0;
|
|
|
|
|
while ((idx < sizeof buf) && (*ptr != 0)) {
|
|
|
|
|
if (*ptr == '_') {
|
|
|
|
|
ptr += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
1999-03-16 05:44:45 +01:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
buf[idx++] = *ptr++;
|
2002-04-14 23:42:01 +02:00
|
|
|
}
|
2000-10-23 00:27:59 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
if (idx == sizeof buf) {
|
|
|
|
|
fprintf(stderr, "Ridiculously long"
|
|
|
|
|
" decimal constant will be truncated!\n");
|
|
|
|
|
idx -= 1;
|
2002-04-14 23:42:01 +02:00
|
|
|
}
|
2003-04-14 05:37:47 +02:00
|
|
|
|
|
|
|
|
buf[idx] = 0;
|
|
|
|
|
unsigned tmp_size = idx * 4 + 1;
|
|
|
|
|
verinum::V *bits = new verinum::V[tmp_size];
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
while (idx < tmp_size) {
|
|
|
|
|
int rem = dec_buf_div2(buf);
|
|
|
|
|
bits[idx++] = (rem == 1) ? verinum::V1 : verinum::V0;
|
2002-04-14 23:42:01 +02:00
|
|
|
}
|
2000-10-23 00:27:59 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
assert(strcmp(buf, "0") == 0);
|
1999-06-12 05:41:30 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
/* Now calculate the minimum number of bits needed to
|
|
|
|
|
represent this unsigned number. */
|
|
|
|
|
unsigned size = tmp_size;
|
|
|
|
|
while ((size > 1) && (bits[size-1] == verinum::V0))
|
|
|
|
|
size -= 1;
|
1999-06-14 05:15:14 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
/* Now account for the signedness. Don't leave a 1 in the high
|
|
|
|
|
bit if this is a signed number. */
|
|
|
|
|
if (signed_flag && (bits[size-1] == verinum::V1)) {
|
|
|
|
|
size += 1;
|
|
|
|
|
assert(size <= tmp_size);
|
|
|
|
|
}
|
1999-06-14 05:15:14 +02:00
|
|
|
|
2007-10-12 01:37:57 +02:00
|
|
|
/* Since we never have the real number of bits that a decimal
|
|
|
|
|
number represents we do not check for extra bits. */
|
|
|
|
|
// if (based_size > 0) { }
|
|
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
verinum*res = new verinum(bits, size, false);
|
|
|
|
|
res->has_sign(signed_flag);
|
1999-06-12 05:41:30 +02:00
|
|
|
|
2003-04-14 05:37:47 +02:00
|
|
|
delete[]bits;
|
|
|
|
|
return res;
|
1999-06-12 05:41:30 +02:00
|
|
|
}
|
|
|
|
|
|
1999-03-16 05:44:45 +01:00
|
|
|
|
2000-07-23 00:09:03 +02:00
|
|
|
/*
|
|
|
|
|
* The timescale parameter has the form:
|
|
|
|
|
* " <num> xs / <num> xs"
|
|
|
|
|
*/
|
|
|
|
|
static void process_timescale(const char*txt)
|
|
|
|
|
{
|
|
|
|
|
unsigned num;
|
|
|
|
|
const char*cp = txt + strspn(txt, " \t");
|
|
|
|
|
char*tmp;
|
|
|
|
|
const char*ctmp;
|
|
|
|
|
|
|
|
|
|
int unit = 0;
|
|
|
|
|
int prec = 0;
|
|
|
|
|
|
|
|
|
|
num = strtoul(cp, &tmp, 10);
|
|
|
|
|
if (num == 0) {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale string.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (num >= 10) {
|
|
|
|
|
unit += 1;
|
|
|
|
|
num /= 10;
|
|
|
|
|
}
|
|
|
|
|
if (num != 1) {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale unit number.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cp = tmp;
|
|
|
|
|
cp += strspn(cp, " \t");
|
|
|
|
|
ctmp = cp + strcspn(cp, " \t/");
|
|
|
|
|
|
|
|
|
|
if (strncmp("s", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 0;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 3;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("us", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 6;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 9;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 12;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
|
|
|
|
|
unit -= 15;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale unit of measurement");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cp = ctmp;
|
|
|
|
|
cp += strspn(cp, " \t/");
|
|
|
|
|
|
|
|
|
|
num = strtoul(cp, &tmp, 10);
|
|
|
|
|
if (num == 0) {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale string.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
assert(num);
|
|
|
|
|
while (num >= 10) {
|
|
|
|
|
prec += 1;
|
|
|
|
|
num /= 10;
|
|
|
|
|
}
|
|
|
|
|
if (num != 1) {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale precision number.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cp = tmp;
|
|
|
|
|
cp += strspn(cp, " \t");
|
2000-08-01 04:14:34 +02:00
|
|
|
ctmp = cp + strcspn(cp, " \t\r");
|
2000-07-23 00:09:03 +02:00
|
|
|
|
|
|
|
|
if (strncmp("s", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 0;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ms", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 3;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("us", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 6;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ns", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 9;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("ps", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 12;
|
|
|
|
|
|
|
|
|
|
} else if (strncmp("fs", cp, ctmp-cp) == 0) {
|
|
|
|
|
prec -= 15;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
VLerror(yylloc, "Invalid timescale precision units of measurement");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2002-04-15 02:04:22 +02:00
|
|
|
pform_set_timescale(unit, prec, yylloc.text, yylloc.first_line);
|
2000-07-23 00:09:03 +02:00
|
|
|
}
|
1998-12-09 05:02:47 +01:00
|
|
|
|
2000-11-04 02:54:01 +01:00
|
|
|
int yywrap()
|
1998-12-09 05:02:47 +01:00
|
|
|
{
|
1999-07-03 23:27:22 +02:00
|
|
|
return 1;
|
1998-12-09 05:02:47 +01:00
|
|
|
}
|
|
|
|
|
|
1999-07-03 23:27:22 +02:00
|
|
|
/*
|
|
|
|
|
* The line directive matches lines of the form #line "foo" N and
|
|
|
|
|
* calls this function. Here I parse out the file name and line
|
|
|
|
|
* number, and change the yylloc to suite.
|
|
|
|
|
*/
|
|
|
|
|
static void line_directive()
|
1998-12-09 05:02:47 +01:00
|
|
|
{
|
1999-07-03 23:27:22 +02:00
|
|
|
char*qt1 = strchr(yytext, '"');
|
|
|
|
|
assert(qt1);
|
|
|
|
|
qt1 += 1;
|
1998-12-09 05:02:47 +01:00
|
|
|
|
1999-07-03 23:27:22 +02:00
|
|
|
char*qt2 = strchr(qt1, '"');
|
|
|
|
|
assert(qt2);
|
1998-12-09 05:02:47 +01:00
|
|
|
|
1999-07-03 23:27:22 +02:00
|
|
|
char*buf = new char[qt2-qt1+1];
|
|
|
|
|
strncpy(buf, qt1, qt2-qt1);
|
|
|
|
|
buf[qt2-qt1] = 0;
|
1998-12-09 05:02:47 +01:00
|
|
|
|
2000-11-30 18:31:42 +01:00
|
|
|
yylloc.text = set_file_name(buf);
|
1999-07-03 23:27:22 +02:00
|
|
|
|
|
|
|
|
qt2 += 1;
|
|
|
|
|
yylloc.first_line = strtoul(qt2,0,0);
|
1998-12-09 05:02:47 +01:00
|
|
|
}
|
|
|
|
|
|
1999-11-23 03:49:04 +01:00
|
|
|
static void line_directive2()
|
|
|
|
|
{
|
|
|
|
|
assert(strncmp(yytext,"`line",5) == 0);
|
|
|
|
|
char*cp = yytext + strlen("`line");
|
|
|
|
|
cp += strspn(cp, " ");
|
|
|
|
|
yylloc.first_line = strtoul(cp,&cp,10);
|
|
|
|
|
|
2001-10-30 22:46:56 +01:00
|
|
|
yylloc.first_line -= 1;
|
|
|
|
|
|
1999-11-23 03:49:04 +01:00
|
|
|
cp += strspn(cp, " ");
|
|
|
|
|
if (*cp == 0) return;
|
|
|
|
|
|
|
|
|
|
char*qt1 = strchr(yytext, '"');
|
|
|
|
|
assert(qt1);
|
|
|
|
|
qt1 += 1;
|
|
|
|
|
|
|
|
|
|
char*qt2 = strchr(qt1, '"');
|
|
|
|
|
assert(qt2);
|
|
|
|
|
|
|
|
|
|
char*buf = new char[qt2-qt1+1];
|
|
|
|
|
strncpy(buf, qt1, qt2-qt1);
|
|
|
|
|
buf[qt2-qt1] = 0;
|
|
|
|
|
|
2000-11-30 18:31:42 +01:00
|
|
|
yylloc.text = set_file_name(buf);
|
1999-11-23 03:49:04 +01:00
|
|
|
}
|
|
|
|
|
|
2001-10-21 01:02:39 +02:00
|
|
|
extern FILE*vl_input;
|
|
|
|
|
void reset_lexor()
|
1998-11-04 00:28:49 +01:00
|
|
|
{
|
|
|
|
|
yyrestart(vl_input);
|
|
|
|
|
yylloc.first_line = 1;
|
2000-11-30 18:31:42 +01:00
|
|
|
|
2007-12-20 18:31:01 +01:00
|
|
|
/* Announce the first file name. */
|
2008-03-28 04:30:53 +01:00
|
|
|
yylloc.text = set_file_name(strdupnew(vl_file.c_str()));
|
1998-11-04 00:28:49 +01:00
|
|
|
}
|