Break sized constants into a size token

and a based numeric constant.
This commit is contained in:
steve 2003-04-14 03:37:47 +00:00
parent 3b17456254
commit 561a268c9c
4 changed files with 157 additions and 400 deletions

448
lexor.lex
View File

@ -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(idx<nbits){
int rem = dec_buf_div2(buf);
bits[idx] = (rem==1) ? verinum::V1 : verinum::V0;
++idx;
}
for(; idx<nbits; ++idx){
bits[idx] = verinum::V0;
}
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
if (strcmp(buf, "0") != 0){
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << yytext <<
"'' truncated to " << nbits << " bits." << endl;
}
yylval.number = new verinum(bits, nbits, false);
yylval.number->has_sign(true);
delete[]bits;
return NUMBER; }
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 (ptr[0] == '\'') {
/* The number has decorations of the form 'sd<digits>,
possibly with space between the d and the <digits>.
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;
if (strlen(ptr) >= sizeof(buf)-2){
fprintf(stderr, "Ridicilously long decimal constant will be truncated!\n");
} else {
/* ... or an undecorated decimal number is passed
it. These numbers are treated as signed decimal. */
assert(isdigit(*ptr));
signed_flag = true;
}
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(idx<size){
buf[idx++] = *ptr++;
}
if (idx == sizeof buf) {
fprintf(stderr, "Ridiculously long"
" decimal constant will be truncated!\n");
idx -= 1;
}
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;
++idx;
bits[idx++] = (rem == 1) ? verinum::V1 : verinum::V0;
}
for(; idx<size; ++idx){
bits[idx] = 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);
}
/* If we run out of bits to hold the value, but there are
still valueable bits in the number, print a warning. */
if (strcmp(buf, "0") != 0){
cerr << yylloc.text << ":" << yylloc.first_line <<
": warning: Numeric decimal constant ``" << ptr <<
"'' truncated to " << size << " bits." << endl;
}
verinum*res = new verinum(bits, size, false);
res->has_sign(signed_flag);
verinum*out = new verinum(bits, size, fixed);
out->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:

21
parse.y
View File

@ -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 <text> IDENTIFIER SYSTEM_IDENTIFIER STRING
%token <text> PATHPULSE_IDENTIFIER
%token <number> NUMBER
%token <number> BASED_NUMBER DEC_NUMBER
%token <realtime> 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> number
%type <flag> signed_opt
%type <drive> drive_strength drive_strength_opt dr_strength0 dr_strength1
%type <letter> 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);

View File

@ -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.
*

10
pform.h
View File

@ -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<string>*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.
*