Add %u support to the scanf routines.

This commit is contained in:
Cary R 2012-09-05 14:16:42 -07:00
parent 61cfb9e1fd
commit 1f6aec6e26
1 changed files with 150 additions and 4 deletions

View File

@ -716,6 +716,143 @@ static int scan_format_string(vpiHandle callh, vpiHandle argv,
return 1;
}
/*
* Routine to return a two state value (implements %u).
*
* Note: Since this is a binary routine it also does not check for leading
* space characters or use space as a boundary character.
*
* Return: 1 for a match, 0 for no match/variable and -1 for a
* suppressed match. No variable is fatal.
*/
static int scan_format_two_state(vpiHandle callh, vpiHandle argv,
struct byte_source *src, unsigned width,
unsigned suppress_flag, PLI_BYTE8 *name)
{
vpiHandle arg;
p_vpi_vecval val_ptr;
s_vpi_value val;
unsigned words, word;
PLI_INT32 varlen;
/* If we are being asked for no data then return a match fail. */
if (width == 0) return 0;
/* Since this is a binary format we do not have an ending sequence.
* Consequently we need to use the width to determine how many word
* pairs to remove from the input stream. */
if (suppress_flag) {
/* If no width was given then just remove one word pair. */
if (width == UINT_MAX) words = 1;
else words = (width+31)/32;
for (word = 0; word < words; word += 1) {
unsigned byte;
/* For a suppression we do not care about the endian order
* of the bytes. */
for (byte = 0; byte < 4; byte += 1) {
int ch = byte_getc(src);
/* See the EOF comments below for more details. */
if (ch == EOF) {
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s() only found %u of %u bytes "
"needed by %%u format code.\n", name,
word*4U + byte, words*4U);
return 0;
}
}
}
return -1;
}
/* We must have a variable to put the bits into. */
arg = vpi_scan(argv);
if (! arg) {
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s() ran out of variables for %%u format code.", name);
vpi_control(vpiFinish, 1);
return 0;
}
/* Extract either the given number of word pairs or enough to fill
* the variable. */
varlen = (vpi_get(vpiSize, arg)+31)/32;
assert(varlen > 0);
val_ptr = (p_vpi_vecval) malloc(varlen*sizeof(s_vpi_vecval));
if (width == UINT_MAX) words = (unsigned)varlen;
else words = (width+31)/32;
for (word = 0; word < words; word += 1) {
int byte;
PLI_INT32 bits = 0;
#ifdef WORDS_BIGENDIAN
for (byte = 3; byte >= 0; byte -= 1) {
#else
for (byte = 0; byte <= 3; byte += 1) {
#endif
int ch = byte_getc(src);
/* If there is an EOF while reading the bytes then treat
* that as a non-match. It could be argued that the bytes
* should be put back, but that is not practical and since
* a binary read should be treated as an atomic operation
* it's not helpful either. An EOF while reading is an
* error in the data stream so print a message to help the
* user debug what is going wrong. The calling routine has
* already verified that there is at least one byte
* available so this message is not printed when an EOF
* occurs at a format code boundary. Which may not be an
* error in the data stream. */
if (ch == EOF) {
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
(int)vpi_get(vpiLineNo, callh));
vpi_printf("%s() only found %d of %u bytes needed by "
"%%u format code.\n", name, word*4 +
#ifdef WORDS_BIGENDIAN
(3-byte),
#else
byte,
#endif
words*4U);
free(val_ptr);
return 0;
}
bits |= (ch & 0xff) << byte*8;
}
/* Only save the words that are in range. */
if (word < (unsigned)varlen) {
val_ptr[word].aval = bits;
val_ptr[word].bval = 0;
}
}
/* Mask the upper bits to match the specified width when required. */
if (width != UINT_MAX) {
PLI_INT32 mask = UINT32_MAX >> (32U - ((width - 1U) % 32U + 1U));
val_ptr[words-1].aval &= mask;
}
/* Not enough words were read to fill the variable so zero fill the
* upper words. */
if (words < (unsigned)varlen) {
for (word = words; word < varlen ; word += 1) {
val_ptr[word].aval = 0;
val_ptr[word].bval = 0;
}
}
/* Put the two-state value into the variable. */
val.format = vpiVectorVal;
val.value.vector = val_ptr;
vpi_put_value(arg, &val, 0, vpiNoDelay);
free(val_ptr);
/* One variable was consumed. */
return 1;
}
/*
* Routine to return a four state value (implements %z).
*
@ -804,8 +941,8 @@ static int scan_format_four_state(vpiHandle callh, vpiHandle argv,
* debug what is going wrong. The calling routine has
* already verified that there is at least one byte
* available so this message is not printed when an
* EOF occurs at an opcode boundary. Which may not be
* an error in the data stream. */
* EOF occurs at a format code boundary. Which may
* not be an error in the data stream. */
if (ch == EOF) {
vpi_printf("WARNING: %s:%d: ",
vpi_get_str(vpiFile, callh),
@ -883,8 +1020,6 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv,
* found just return EOF. */
len = vpi_get(vpiSize, item);
words = ((len + 31) / 32) - 1;
/* The mask is defined to be 32 bits. */
mask = 0xffffffff >> (32 - ((len - 1) % 32 + 1));
val.format = vpiVectorVal;
vpi_get_value(item, &val);
/* Check the full words for an undefined bit. */
@ -895,6 +1030,8 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv,
break;
}
}
/* The mask is defined to be 32 bits. */
mask = UINT32_MAX >> (32U - ((len - 1U) % 32U + 1U));
/* Check the top word for an undefined bit. */
if (match && (val.value.vector[words].bval & mask)) {
match = 0;
@ -1046,6 +1183,15 @@ static int scan_format(vpiHandle callh, struct byte_source*src, vpiHandle argv,
break;
case 'u':
match = scan_format_two_state(callh, argv, src,
max_width,
suppress_flag, name);
/* If a binary match fails and it is the first item
* matched then treat that as an EOF. */
if ((match == 0) && (rc == 0)) rc = EOF;
if (match == 1) rc += 1;
break;
case 'v':
vpi_printf("SORRY: %s:%d: ",
vpi_get_str(vpiFile, callh),