/* * ============================================================================ * MK_TBL: Makes a lookup table from a description file * * Author: J. Zbiciak * Last Revision: 9/13/98 * ============================================================================ * * Makes a redundantly coded table in "N" bits. * * Takes a description of the form "0xxx1010xxx entry", and expands out all * the 'x's. Processes entries in order, so exceptions to a don't-care can * be handled: * * 00xx, "entry 1" * 0000, "entry 2" * * This causes 0000 to have "entry 2" and 0001, 0010, 0011 to have "entry 1". * * The table description file should contain a single integer on the first * non-comment line which corresponds to the number of bits that the table * encodes. The remaining lines should contain patterns as described above. * * Usage: make_tbl table.pat table.tbl * =========================================================================== */ #include "config.h" #include #include #include #include #include "macros.h" #define MAX_BITS (20) #define MAX_ENTRY (1000) #define MAX_LINE (1024) /* * =========================================================================== * RENDER_BITS -- converts value into a string of 1's and 0's * * Notes: This renders into a static buffer, and so it can't be used for * multiple %s fields in a printf(). Sorry. * =========================================================================== */ const char * render_bits(unsigned value, int bits) { int i; static char string[32]; char * s = string; for (i = bits-1; i >= 0; i--) *s++ = ( ((value >> i) & 1) + '0' ); return string; } /* * =========================================================================== * EXPAND_DC -- expands the don't-cares in a description line. * * This function isn't terribly efficient, but then it doesn't need to be. * =========================================================================== */ void expand_dc(char *tbl[], char *pattern, char *entry, int bits) { int len, num_dc; char *s; int dc_tmp[MAX_BITS], dc_pos[MAX_BITS]; int j; unsigned pat = 0, msk = 0, idx, i; /* --------------------------------------------------------------------- */ /* Scan the pattern buffer looking for "don't cares", and note their */ /* positions. Also, build a bit mask for the bits that aren't DC's. */ /* --------------------------------------------------------------------- */ for (len = num_dc = 0, s = pattern; *s=='1' || *s=='0' || *s=='x'; s++) { pat <<= 1; pat |= *s == '1'; msk <<= 1; if (*s == 'x') { dc_tmp[num_dc++] = len; } else { msk |= 1; } len++; if (len > bits || num_dc > bits) { fprintf(stderr,"Oversized pattern encountered in expand_dc()\n"); exit(1); } } /* --------------------------------------------------------------------- */ /* At this point, the dc_tmp array contains a list of all the don't- */ /* care positions. Re-order the array so that we can quickly fill in */ /* the don't-care positions in the next loop. This essentially does */ /* an endian swap bitwise on the recorded don't-care positions. */ /* --------------------------------------------------------------------- */ for (j = 0; j < num_dc; j++) { dc_pos[num_dc - j - 1] = len - dc_tmp[j] - 1; } /* --------------------------------------------------------------------- */ /* Now, fill in the table by expanding all of the don't-cares. */ /* --------------------------------------------------------------------- */ for (i = 0; i < (1U< 7 || o3 > 7 ) return NULL; p = (o1 << 6) | (o2 << 3) | o3; break; } default: /* just return whatever character that was escaped */ } } *es++ = p; if (es - out >= max_len) return NULL; /* entry too long */ } *es = 0; if (*s != '"') return NULL; return s; } /* * =========================================================================== * DECODE_BITS_LINE -- Decodes a line looking for # of bits designation * * Format: * * [space] [decimal number][, "default entry"] [space] [# comment] * * Return: * -- 0 if the line was complete * -- 1 if the line was empty/comments * -- -1 if the line was invalid * =========================================================================== */ int decode_bits_line ( char *input, int *bits, char *entry, int max_entry ) { char *s; int p,val; *bits = 0; /* --------------------------------------------------------------------- */ /* Skip leading whitespace and find first char of the bit pattern. */ /* --------------------------------------------------------------------- */ s = input; while (*s && isspace(*s)) s++; /* --------------------------------------------------------------------- */ /* If we stopped at a # or NUL, just return that this is a comment. */ /* --------------------------------------------------------------------- */ if (*s == '#' || !*s) return 1; /* --------------------------------------------------------------------- */ /* See if this is an integer, and if so decode it into our bit-length. */ /* If it isn't an integer, report an error. */ /* --------------------------------------------------------------------- */ if (!isdigit(*s)) { return -1; } val = 0; while (*s && isdigit(*s)) { p = *s++; val = val * 10 + p - '0'; } *bits = val; /* --------------------------------------------------------------------- */ /* Next, look for any whitespace, skipping it. If we run into end of */ /* string, stop here, returning what we have. Otherwise, look for the */ /* whitespace-comma-whitespace-quote sequence that preceeds a string. */ /* --------------------------------------------------------------------- */ while (*s && isspace(*s)) s++; if (!*s || *s == '\n' || *s == '#') { strncpy(entry,"NULL,",max_entry); return 0; } if (*s++ != ',') return -1; while (*s && isspace(*s)) s++; if (*s != '"') return -1; /* --------------------------------------------------------------------- */ /* Now, copy the quoted string. It should end with another quote. */ /* Handle C-style escapes for \b, \x##, \###, \n, \t, \", etc.. */ /* --------------------------------------------------------------------- */ s = grab_quoted_string(s, entry, max_entry); if (!s) return -1; /* --------------------------------------------------------------------- */ /* We should be ok -- we'll just silently ignore the rest of the line. */ /* Return SUCCESS! */ /* --------------------------------------------------------------------- */ return 0; } /* * =========================================================================== * DECODE_DC_LINE -- Decodes a line, returning the pattern and entry * * Format: * * [space] [10x]* [space],[space] "[C-style string]" [space] # [space] [cmt] * * Return: * -- 0 if the line was complete * -- 1 if the line was empty/comments * -- -1 if the line was invalid * =========================================================================== */ int decode_dc_line ( char *input, char *pattern, int max_bits, char *entry, int max_entry ) { char *s, *ps; int p; /* --------------------------------------------------------------------- */ /* Skip leading whitespace and find first char of the bit pattern. */ /* --------------------------------------------------------------------- */ s = input; while (*s && isspace(*s)) s++; /* --------------------------------------------------------------------- */ /* If we stopped at a # or NUL, just return that this is a comment. */ /* --------------------------------------------------------------------- */ if (*s == '#' || !*s) return 1; /* --------------------------------------------------------------------- */ /* Copy pattern into our pattern buffer. Do not allow the pattern */ /* length to exceed "bits." Allowed characters are [01A-Za-z._-]. */ /* Characters other than 0 and 1 are treated as "don't-cares" and are */ /* converted into 'x' in the pattern buffer. */ /* --------------------------------------------------------------------- */ ps = pattern; while (*s && (strchr("01._-",*s) || isalpha(*s))) { p = *s++; if (p != '0' && p != '1') p = 'x'; *ps++ = p; if (ps - pattern > max_bits) { return -1; /* pattern too long */ } } if (ps == pattern) return -1; /* we didn't find a pattern! */ *ps++ = 0; /* --------------------------------------------------------------------- */ /* Next, look for any whitespace, skipping it. The character after */ /* the (optional) whitespace must be a comma. After the comma is */ /* some more (optional) whitespace. It must be followed by a double */ /* quote (which starts the entry.) */ /* --------------------------------------------------------------------- */ while (*s && isspace(*s)) s++; if (*s++ != ',') return -1; while (*s && isspace(*s)) s++; if (*s != '"') return -1; /* --------------------------------------------------------------------- */ /* Now, copy the quoted string. It should end with another quote. */ /* Handle C-style escapes for \b, \x##, \###, \n, \t, \", etc.. */ /* --------------------------------------------------------------------- */ s = grab_quoted_string(s, entry, max_entry); if (!s) return -1; /* --------------------------------------------------------------------- */ /* We should be ok -- we'll just silently ignore the rest of the line. */ /* Return SUCCESS! */ /* --------------------------------------------------------------------- */ return 0; } /* * =========================================================================== * MAIN -- Uhm... uh... uhm... yeah! Huh-huh. * =========================================================================== */ int main(int argc, char *argv[]) { int bits, i; FILE *i_file, *o_file; char **tbl; char pattern[MAX_BITS + 2]; char entry [MAX_ENTRY + 1]; char d_entry[MAX_ENTRY + 1]; char buf [MAX_LINE + 1]; /* --------------------------------------------------------------------- */ /* Check to see that we've been given the appropriate number of args. */ /* --------------------------------------------------------------------- */ if (argc < 3) { fprintf(stderr,"Usage: make_tbl table.pat table.tbl\n"); exit(1); } /* --------------------------------------------------------------------- */ /* Next, try to open our input file for reading. */ /* --------------------------------------------------------------------- */ i_file = fopen(argv[1], "r"); if ( !i_file ) { perror(argv[1]); fprintf(stderr,"Unable to read input file '%s'\n", argv[1]); exit(1); } /* --------------------------------------------------------------------- */ /* Read the table size in bits from the file. Complain if we can't */ /* find it, or if its value is out of range. */ /* --------------------------------------------------------------------- */ while ( fgets(buf, sizeof(buf)-1, i_file) && (i = decode_bits_line(buf, &bits, d_entry, MAX_ENTRY)) ) { if (i < 0) { fprintf(stderr,"Syntax error in input. " "Table size in bits expected.\n"); fprintf(stderr,"--> %s\n",buf); exit(1); } } if (bits <= 0 || bits > MAX_BITS) { fprintf(stderr,"Bit size %d is out of range\n", bits); exit(1); } /* --------------------------------------------------------------------- */ /* Now that we have the table size, allocate the table and set all of */ /* the entries to the default value. */ /* --------------------------------------------------------------------- */ tbl = malloc(sizeof(char *) << bits); if (!tbl) { fprintf(stderr,"Out of memory allocating look-up table.\n" "Try a smaller table size.\n"); exit(1); } for (i = 0; i < (1 << bits); i++) tbl[i] = d_entry; while (fgets(buf, sizeof(buf)-1, i_file)) { if (! (i = decode_dc_line(buf, pattern, bits, entry, MAX_ENTRY)) ) { expand_dc(tbl, pattern, strdup(entry), bits); } if (i == -1) { fprintf(stderr,"Syntax error in pattern line.\n"); fprintf(stderr,"--> %s\n",buf); exit(1); } } /* --------------------------------------------------------------------- */ /* Close our input file, because we're done with it. */ /* --------------------------------------------------------------------- */ fclose(i_file); /* --------------------------------------------------------------------- */ /* Next try to open our output file, now that we've successfully read */ /* in all of the patterns from our input file. */ /* --------------------------------------------------------------------- */ o_file = fopen(argv[2], "w"); if ( !o_file ) { perror(argv[2]); fprintf(stderr,"Unable to write output file '%s'\n", argv[2]); exit(1); } /* --------------------------------------------------------------------- */ /* Write all of the entries in our table out to the output file. */ /* Note, we rely on the user to provide all the syntactic requirements */ /* such as commas. We do provide newlines, though. */ /* --------------------------------------------------------------------- */ for (i = 0; i < (1<