diff --git a/lexor.lex b/lexor.lex index 4dc4c9c3f..6b5d3f875 100644 --- a/lexor.lex +++ b/lexor.lex @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: lexor.lex,v 1.77 2003/03/18 01:36:14 steve Exp $" +#ident "$Id: lexor.lex,v 1.78 2003/04/14 03:37:47 steve Exp $" #endif # include "config.h" @@ -80,10 +80,6 @@ void reset_lexor(); static void line_directive(); static void line_directive2(); -static verinum*make_sized_binary(const char*txt); -static verinum*make_sized_dec(const char*txt); -static verinum*make_sized_octal(const char*txt); -static verinum*make_sized_hex(const char*txt); static verinum*make_unsized_binary(const char*txt); static verinum*make_unsized_dec(const char*txt); static verinum*make_unsized_octal(const char*txt); @@ -228,67 +224,19 @@ W [ \t\b\f\r]+ yylval.text = strdup(yytext); return SYSTEM_IDENTIFIER; } -[0-9][0-9_]*[ \t]*\'[sS]?[dD][ \t]*[0-9][0-9_]* { - yylval.number = make_sized_dec(yytext); - return NUMBER; } -[0-9][0-9_]*[ \t]*\'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { - yylval.number = make_sized_binary(yytext); - return NUMBER; } -[0-9][0-9_]*[ \t]*\'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { - yylval.number = make_sized_octal(yytext); - return NUMBER; } -[0-9][0-9_]*[ \t]*\'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { - yylval.number = make_sized_hex(yytext); - return NUMBER; } \'[sS]?[dD][ \t]*[0-9][0-9_]* { yylval.number = make_unsized_dec(yytext); - return NUMBER; } + return BASED_NUMBER; } \'[sS]?[bB][ \t]*[0-1xzXZ_\?]+ { yylval.number = make_unsized_binary(yytext); - return NUMBER; } + return BASED_NUMBER; } \'[sS]?[oO][ \t]*[0-7xzXZ_\?]+ { yylval.number = make_unsized_octal(yytext); - return NUMBER; } + return BASED_NUMBER; } \'[sS]?[hH][ \t]*[0-9a-fA-FxzXZ_\?]+ { yylval.number = make_unsized_hex(yytext); - return NUMBER; } + return BASED_NUMBER; } -[0-9][0-9_]* { - char buf[4096]; - - if (strlen(yytext) >= sizeof(buf)-2){ - fprintf(stderr, "Ridicilously long decimal constant will be truncated!\n"); - } - - strncpy(buf, yytext, sizeof(buf)-2); - buf[sizeof(buf)-1] = 0; - - /* Convert the decimal number to a binary value, one digit at - a time. Watch out for overflow. */ - verinum::V*bits = new verinum::V[INTEGER_WIDTH]; - unsigned idx=0; - unsigned nbits=INTEGER_WIDTH; - - while(idxhas_sign(true); - delete[]bits; - return NUMBER; } +[0-9][0-9_]* { + yylval.number = make_unsized_dec(yytext); + return DEC_NUMBER; } [0-9][0-9_]*\.[0-9][0-9_]*([Ee][+-]?[0-9][0-9_]*)? { yylval.realtime = new verireal(yytext); @@ -397,96 +345,6 @@ void lex_end_table() BEGIN(INITIAL); } -static verinum*make_binary_with_size(unsigned size, bool fixed, const char*ptr) -{ - bool sign_flag = false; - verinum::V*bits = new verinum::V[size]; - - if (tolower(ptr[0]) == 's') { - ptr += 1; - sign_flag = true; - } - assert(tolower(*ptr) == 'b'); - ptr += 1; - - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - unsigned idx = 0; - const char*eptr = ptr + strlen(ptr) - 1; - - while ((eptr >= ptr) && (idx < size)) { - - switch (*eptr) { - case '_': - break; - case '0': - bits[idx++] = verinum::V0; - break; - case '1': - bits[idx++] = verinum::V1; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - break; - case 'x': case 'X': - bits[idx++] = verinum::Vx; - break; - default: - assert(0); - } - - eptr -= 1; - } - - - /* If we filled up the expected number of bits, but there are - still characters of the number part left, then report a - warning that we are truncating. */ - - if ((idx >= size) && (eptr >= ptr)) - cerr << yylloc.text << ":" << yylloc.first_line << - ": warning: Numeric binary constant ``" << ptr << - "'' truncated to " << size << " bits." << endl; - - - // Zero-extend binary number, except that z or x is extended - // if it is the highest supplied digit. - while (idx < size) { - switch (ptr[0]) { - case '0': - case '1': - bits[idx++] = verinum::V0; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - break; - case 'x': case 'X': - bits[idx++] = verinum::Vx; - break; - default: - assert(0); - } - } - - verinum*out = new verinum(bits, size, fixed); - delete[]bits; - out->has_sign(sign_flag); - return out; -} - -static verinum*make_sized_binary(const char*txt) -{ - char*ptr; - unsigned size = strtoul(txt,&ptr,10); - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - assert(*ptr == '\''); - ptr += 1; - - return make_binary_with_size(size, true, ptr); -} - static verinum*make_unsized_binary(const char*txt) { bool sign_flag = false; @@ -538,95 +396,6 @@ static verinum*make_unsized_binary(const char*txt) return out; } -static verinum*make_sized_octal(const char*txt) -{ - bool sign_flag = false; - char*ptr; - - unsigned size = strtoul(txt,&ptr,10); - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - assert(*ptr == '\''); - ptr += 1; - - if (tolower(*ptr) == 's') { - sign_flag = true; - ptr += 1; - } - assert(tolower(*ptr) == 'o'); - ptr += 1; - - /* We know from the size number how bit to make the verinum - array, so make it now. */ - verinum::V*bits = new verinum::V[(size+2)/3 * 3]; - - /* skip white space between size and the base token. */ - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - /* Get a pointer to the last character of the number string, - then work back from there (the least significant digit) - forward until I run out of digits or space to put them. */ - char*eptr = ptr + strlen(ptr) - 1; - unsigned idx = 0; - - while ((eptr >= ptr) && (idx < size)) { - switch (*eptr) { - case 'x': case 'X': - bits[idx++] = verinum::Vx; - bits[idx++] = verinum::Vx; - bits[idx++] = verinum::Vx; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - bits[idx++] = verinum::Vz; - bits[idx++] = verinum::Vz; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - { - unsigned val = *eptr - '0'; - bits[idx++] = (val&1)? verinum::V1 : verinum::V0; - bits[idx++] = (val&2)? verinum::V1 : verinum::V0; - bits[idx++] = (val&4)? verinum::V1 : verinum::V0; - break; - } - case '_': - break; - default: - assert(0); - } - - eptr -= 1; - } - - /* If we filled up all the bits and there are still characters - in the number string, then we overflowed. Report a warning - that we are truncating. */ - if ((idx >= size) && (eptr >= ptr)) - cerr << yylloc.text << ":" << yylloc.first_line << - ": warning: Numeric octal constant ``" << ptr << - "'' truncated to " << size << " bits." << endl; - - - /* If we did not fill up all the bits from the string, then - zero-extend the number. */ - while (idx < size) switch (ptr[1]) { - case 'x': case 'X': - bits[idx++] = verinum::Vx; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - break; - default: - bits[idx++] = verinum::V0; - } - - verinum*out = new verinum(bits, size, true); - delete[]bits; - out->has_sign(sign_flag); - return out; -} static verinum*make_unsized_octal(const char*txt) { @@ -687,102 +456,6 @@ static verinum*make_unsized_octal(const char*txt) return out; } -static verinum*make_sized_hex(const char*txt) -{ - bool sign_flag = false; - char*ptr; - unsigned size = strtoul(txt,&ptr,10); - - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - assert(*ptr == '\''); - ptr += 1; - - if (tolower(*ptr) == 's') { - sign_flag = true; - ptr += 1; - } - - assert(tolower(*ptr) == 'h'); - - ptr += 1; - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - verinum::V*bits = new verinum::V[(size+3)&~3]; - - unsigned idx = 0; - char*eptr = ptr + strlen(ptr) - 1; - - while ((eptr >= ptr) && (idx < size)) { - switch (*eptr) { - case 'x': case 'X': - bits[idx++] = verinum::Vx; - bits[idx++] = verinum::Vx; - bits[idx++] = verinum::Vx; - bits[idx++] = verinum::Vx; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - bits[idx++] = verinum::Vz; - bits[idx++] = verinum::Vz; - bits[idx++] = verinum::Vz; - 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': - { - unsigned val = tolower(*eptr) - 'a' + 10; - bits[idx++] = (val&1)? verinum::V1 : verinum::V0; - bits[idx++] = (val&2)? verinum::V1 : verinum::V0; - bits[idx++] = (val&4)? verinum::V1 : verinum::V0; - bits[idx++] = (val&8)? verinum::V1 : verinum::V0; - break; - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - unsigned val = *eptr - '0'; - bits[idx++] = (val&1)? verinum::V1 : verinum::V0; - bits[idx++] = (val&2)? verinum::V1 : verinum::V0; - bits[idx++] = (val&4)? verinum::V1 : verinum::V0; - bits[idx++] = (val&8)? verinum::V1 : verinum::V0; - break; - } - case '_': - break; - default: - assert(0); - } - - eptr -= 1; - } - - /* If we filled up the expected number of bits, but there are - still characters of the number part left, then report a - warning that we are truncating. */ - if ((idx >= size) && (eptr >= ptr)) - cerr << yylloc.text << ":" << yylloc.first_line << - ": warning: Numeric hex constant ``" << ptr << - "'' truncated to " << size << " bits." << endl; - - // zero extend hex numbers - while (idx < size) switch (ptr[0]) { - case 'x': case 'X': - bits[idx++] = verinum::Vx; - break; - case 'z': case 'Z': case '?': - bits[idx++] = verinum::Vz; - break; - default: - bits[idx++] = verinum::V0; - } - - verinum*out = new verinum(bits, size, true); - out->has_sign(sign_flag); - delete[]bits; - return out; -} static verinum*make_unsized_hex(const char*txt) { @@ -905,80 +578,93 @@ static int dec_buf_div2(char *buf) /* * Making a decimal number is much easier then the other base numbers - * because there are no z or x values to worry about. + * 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. */ -static verinum*make_dec_with_size(unsigned size, bool fixed, const char*ptr) + +static verinum*make_unsized_dec(const char*ptr) { char buf[4096]; bool signed_flag = false; + unsigned idx; - if (tolower(*ptr) == 's') { + if (ptr[0] == '\'') { + /* The number has decorations of the form 'sd, + possibly with space between the d and the . + Also, the 's' is optional, and markes 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; + + } else { + /* ... or an undecorated decimal number is passed + it. These numbers are treated as signed decimal. */ + assert(isdigit(*ptr)); signed_flag = true; - ptr += 1; - } - assert(tolower(*ptr) == 'd'); - - ptr += 1; - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - if (strlen(ptr) >= sizeof(buf)-2){ - fprintf(stderr, "Ridicilously long decimal constant will be truncated!\n"); } - strncpy(buf, ptr, sizeof(buf)-2); - buf[sizeof(buf)-1] = 0; - /* Convert the decimal number to a binary value, one digit at - a time. Watch out for overflow. */ - verinum::V*bits = new verinum::V[size]; - unsigned idx=0; + /* 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; + } - while(idxhas_sign(signed_flag); + 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; + } + + assert(strcmp(buf, "0") == 0); + + /* 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; + + /* 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); + } + + verinum*res = new verinum(bits, size, false); + res->has_sign(signed_flag); + delete[]bits; - return out; + return res; } -static verinum*make_sized_dec(const char*txt) -{ - char*ptr; - unsigned size = strtoul(txt,&ptr,10); - - while (*ptr && ((*ptr == ' ') || (*ptr == '\t'))) - ptr += 1; - - assert(*ptr == '\''); - ptr += 1; - - return make_dec_with_size(size, true, ptr); -} - -static verinum*make_unsized_dec(const char*txt) -{ - verinum*tmp = make_dec_with_size(INTEGER_WIDTH, false, txt+1); - tmp->has_sign(true); - return tmp; -} /* * The timescale parameter has the form: diff --git a/parse.y b/parse.y index e2355cf8d..a9f7ef38c 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.174 2003/03/18 01:36:14 steve Exp $" +#ident "$Id: parse.y,v 1.175 2003/04/14 03:37:47 steve Exp $" #endif # include "config.h" @@ -117,7 +117,7 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING %token PATHPULSE_IDENTIFIER -%token NUMBER +%token BASED_NUMBER DEC_NUMBER %token REALTIME %token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_SG %token K_PO_POS K_PO_NEG @@ -145,6 +145,7 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; %token KK_attribute +%type number %type signed_opt %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -232,6 +233,14 @@ source_file | source_file description ; +number : BASED_NUMBER + { $$ = $1; } + | DEC_NUMBER + { $$ = $1; } + | DEC_NUMBER BASED_NUMBER + { $$ = pform_verinum_with_size($1,$2, @2.text, @2.first_line); } + ; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -478,7 +487,7 @@ delay_value delay_value_simple - : NUMBER + : DEC_NUMBER { verinum*tmp = $1; if (tmp == 0) { yyerror(@1, "internal error: delay."); @@ -879,7 +888,7 @@ expression_list expr_primary - : NUMBER + : number { assert($1); PENumber*tmp = new PENumber($1); tmp->set_file(@1.text); @@ -1762,7 +1771,7 @@ parameter_value_opt tmp->by_name = $3; $$ = tmp; } - | '#' NUMBER + | '#' DEC_NUMBER { assert($2); PENumber*tmp = new PENumber($2); tmp->set_file(@1.text); @@ -2763,7 +2772,7 @@ udp_sequ_entry ; udp_initial - : K_initial IDENTIFIER '=' NUMBER ';' + : K_initial IDENTIFIER '=' number ';' { PExpr*etmp = new PENumber($4); PEIdent*itmp = new PEIdent(hname_t($2)); PAssign*atmp = new PAssign(itmp, etmp); diff --git a/pform.cc b/pform.cc index f6c583fd2..2dd7f95e0 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.cc,v 1.111 2003/03/06 04:37:12 steve Exp $" +#ident "$Id: pform.cc,v 1.112 2003/04/14 03:39:15 steve Exp $" #endif # include "config.h" @@ -133,6 +133,56 @@ void pform_set_timescale(int unit, int prec, } +verinum* pform_verinum_with_size(verinum*siz, verinum*val, + const char*file, unsigned lineno) +{ + assert(siz->is_defined()); + unsigned long size = siz->as_ulong(); + + verinum::V pad; + + switch (val->get(val->len()-1)) { + case verinum::Vz: + pad = verinum::Vz; + break; + case verinum::Vx: + pad = verinum::Vx; + break; + default: + pad = verinum::V0; + break; + } + + verinum*res = new verinum(pad, size); + + unsigned copy = val->len(); + if (res->len() < copy) + copy = res->len(); + + for (unsigned idx = 0 ; idx < copy ; idx += 1) { + res->set(idx, val->get(idx)); + } + + res->has_sign(val->has_sign()); + + bool trunc_flag = false; + for (unsigned idx = copy ; idx < val->len() ; idx += 1) { + if (val->get(idx) != pad) { + trunc_flag = true; + break; + } + } + + if (trunc_flag) { + cerr << file << ":" << lineno << ": warning: Numeric constant " + << "truncated to " << copy << " bits." << endl; + } + + delete siz; + delete val; + return res; +} + /* * This function evaluates delay expressions. The result should be a * simple constant that I can interpret as an unsigned number. @@ -1414,6 +1464,10 @@ int pform_parse(const char*path, FILE*file) /* * $Log: pform.cc,v $ + * Revision 1.112 2003/04/14 03:39:15 steve + * Break sized constants into a size token + * and a based numeric constant. + * * Revision 1.111 2003/03/06 04:37:12 steve * lex_strings.add module names earlier. * diff --git a/pform.h b/pform.h index 857be5dbb..2db261894 100644 --- a/pform.h +++ b/pform.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.h,v 1.68 2003/02/27 06:45:11 steve Exp $" +#ident "$Id: pform.h,v 1.69 2003/04/14 03:39:15 steve Exp $" #endif # include "netlist.h" @@ -148,6 +148,10 @@ extern void pform_make_udp(const char*name, list*parms, extern void pform_push_scope(char*name); extern void pform_pop_scope(); + +extern verinum* pform_verinum_with_size(verinum*s, verinum*val, + const char*file, unsigned loneno); + /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. @@ -275,6 +279,10 @@ extern void pform_dump(ostream&out, Module*mod); /* * $Log: pform.h,v $ + * Revision 1.69 2003/04/14 03:39:15 steve + * Break sized constants into a size token + * and a based numeric constant. + * * Revision 1.68 2003/02/27 06:45:11 steve * specparams as far as pform. *