diff --git a/ext/ghw/ghwdump.c b/ext/ghw/ghwdump.c new file mode 100644 index 0000000..e6f24ca --- /dev/null +++ b/ext/ghw/ghwdump.c @@ -0,0 +1,325 @@ +/* Display a GHDL Wavefile for debugging. + Copyright (C) 2005 Tristan Gingold + + This program is free software: you can redistribute it and/or modify + it 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, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "libghw.h" + +static const char *progname; +void +usage (void) +{ + printf ("usage: %s [OPTIONS] FILEs...\n", progname); + printf ("Options are:\n" + " -t display types\n" + " -h display hierarchy\n" + " -H display hierarchy with full pathnames\n" + " -T display time\n" + " -s display signals (and time)\n" + " -S display strings\n" + " -f list of signals to display (default: all, example: -f " + "1,3,5-7,21-33)\n" + " -l display list of sections\n" " -v verbose\n"); +} + +static void +add_single_signal (int **signalSet, int *nbSignals, int signal) +{ + assert (NULL != signalSet); + assert (NULL != nbSignals); + assert (0 <= nbSignals[0]); + assert (0 <= signal); + + int newSize = (1 + nbSignals[0]); + /*printf("adding signal %6d set of signals to display\n", signal); */ + signalSet[0] = (int *) realloc (signalSet[0], newSize * sizeof (int)); + signalSet[0][nbSignals[0]] = signal; + nbSignals[0] = newSize; +} + +static void +add_signal_range (int **signalSet, int *nbSignals, const char *s, + const char *e) +{ + + int i; + int rangeSize; + int rangeEnd = -1; + int rangeStart = -1; + int bytesMatched = -1; + int expected = ((e - s) - 1); + int itemsMatched = + sscanf (s, "%d-%d%n", &rangeStart, &rangeEnd, &bytesMatched); + if (2 == itemsMatched && expected == bytesMatched) + { + if (rangeEnd < rangeStart) + { + int t = rangeEnd; + rangeEnd = rangeStart; + rangeStart = t; + } + } + else + { + itemsMatched = sscanf (s, "%d%n", &rangeStart, &bytesMatched); + if (1 == itemsMatched && expected == bytesMatched) + { + if (0 <= rangeStart) + { + rangeEnd = rangeStart; + } + } + } + + rangeSize = (rangeEnd - rangeStart); + if (rangeEnd < 0 || rangeStart < 0 || rangeSize < 0) + { + fprintf (stderr, + "incorrect signal range specification\"%s\" found in " + "command line, aborting\n", s); + exit (1); + } + + for (i = rangeStart; i <= rangeEnd; ++i) + { + add_single_signal (signalSet, nbSignals, i); + } +} + +static void +add_signals (int **signalSet, int *nbSignals, const char *arg) +{ + int c = -1; + const char *e; + const char *s = e = arg; + while (0 != c) + { + c = *(e++); + if (',' == c || 0 == c) + { + add_signal_range (signalSet, nbSignals, s, e); + s = e; + } + } +} + +static void +disp_string_table (struct ghw_handler *hp) +{ + int i; + printf ("String table:\n"); + + for (i = 1; i < hp->nbr_str; i++) + printf (" %s\n", hp->str_table[i]); +} + +int +main (int argc, char **argv) +{ + int i; + int flag_disp_types; + int flag_disp_hierarchy; + int flag_disp_time; + int flag_disp_signals; + int flag_disp_strings; + int flag_full_names; + int flag_list; + int flag_verbose; + int nb_signals; + int *signal_set; + int filter_done; + int eof; + enum ghw_sm_type sm; + + progname = argv[0]; + flag_disp_types = 0; + flag_disp_hierarchy = 0; + flag_full_names = 0; + flag_disp_time = 0; + flag_disp_signals = 0; + flag_disp_strings = 0; + flag_list = 0; + flag_verbose = 0; + nb_signals = 0; + signal_set = NULL; + filter_done = 0; + + /* Disp help if there is only an help option. */ + if (argc == 2 + && (strcmp (argv[1], "--help") == 0 || strcmp (argv[1], "-h") == 0)) + { + usage (); + exit (0); + } + + while (1) + { + int c; + + c = getopt (argc, argv, "thHTsSlvf:"); + if (c == -1) + break; + switch (c) + { + case 't': + flag_disp_types = 1; + break; + case 'h': + flag_disp_hierarchy = 1; + break; + case 'H': + flag_disp_hierarchy = 1; + flag_full_names = 1; + break; + case 'T': + flag_disp_time = 1; + break; + case 's': + flag_disp_signals = 1; + flag_disp_time = 1; + break; + case 'S': + flag_disp_strings = 1; + break; + case 'f': + add_signals (&signal_set, &nb_signals, optarg); + break; + case 'l': + flag_list = 1; + break; + case 'v': + flag_verbose++; + break; + default: + usage (); + exit (2); + } + } + + if (optind >= argc) + { + usage (); + return 1; + } + + for (i = optind; i < argc; i++) + { + struct ghw_handler h; + struct ghw_handler *hp = &h; + + hp->flag_verbose = flag_verbose; + + if (ghw_open (hp, argv[i]) != 0) + { + fprintf (stderr, "cannot open ghw file %s\n", argv[i]); + return 1; + } + if (flag_list) + { + while (1) + { + const char *section_name; + int section; + + section = ghw_read_section (hp); + if (section == -2) + { + printf ("eof of file\n"); + break; + } + else if (section < 0) + { + printf ("Error in file\n"); + break; + } + else if (section == 0) + { + printf ("Unknown section\n"); + break; + } + section_name = ghw_sections[section].name; + printf ("Section %s\n", section_name); + if ((*ghw_sections[section].handler) (hp) < 0) + break; + + if (flag_disp_strings && strcmp (section_name, "STR") == 0) + disp_string_table (hp); + else if (flag_disp_types && strcmp (section_name, "TYP") == 0) + ghw_disp_types (hp); + } + } + else + { + if (ghw_read_base (hp) < 0) + { + fprintf (stderr, "cannot read ghw file\n"); + return 2; + } + if (flag_disp_types) + ghw_disp_types (hp); + if (flag_disp_hierarchy) + { + hp->flag_full_names = flag_full_names; + ghw_disp_hie (hp, hp->hie); + } + +#if 1 + sm = ghw_sm_init; + eof = 0; + while (!eof) + { + switch (ghw_read_sm (hp, &sm)) + { + case ghw_res_snapshot: + case ghw_res_cycle: + if (flag_disp_time) + printf ("Time is " GHWPRI64 " fs\n", hp->snap_time); + if (flag_disp_signals) + { + if (!filter_done) + { + ghw_filter_signals (hp, signal_set, nb_signals); + filter_done = 1; + } + ghw_disp_values (hp); + } + break; + case ghw_res_eof: + eof = 1; + break; + default: + abort (); + } + } + +#else + if (ghw_read_dump (hp) < 0) + { + fprintf (stderr, "error in ghw dump\n"); + return 3; + } +#endif + } + ghw_close (&h); + } + return 0; +} diff --git a/ext/ghw/libghw.c b/ext/ghw/libghw.c new file mode 100644 index 0000000..84ff648 --- /dev/null +++ b/ext/ghw/libghw.c @@ -0,0 +1,2387 @@ +/* GHDL Wavefile reader library. + Copyright (C) 2005 Tristan Gingold + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#include "libghw.h" + +// Exit the program with return value 1 and print calling line +__attribute__((noreturn)) static void +ghw_error_exit_line (char const *file, int line) +{ + fprintf(stderr, "Failed to load ghw file due to invalid data. Terminating.\n"); + fprintf(stderr, "Error raised at %s:%d.\n", file, line); + exit(1); +} + +#define ghw_error_exit() ghw_error_exit_line(__FILE__, __LINE__) + +// Call malloc (size), fail exit when malloc fails (returns NULL) +void * +malloc_unwrap (size_t size) +{ + void *ret = malloc (size); + if (ret == NULL) + { + fprintf(stderr, "libghw could not allocate %zu bytes. Terminating.\n", size); + exit(12); + } + return ret; +} + +// Call calloc () +void * +calloc_unwrap (size_t nmemb, size_t size) +{ + void *ret = calloc(nmemb, size); + if (ret == NULL) + { + fprintf(stderr, "libghw could not allocate %zu elements of size %zu bytes. Terminating.\n", nmemb, size); + exit(12); + } + return ret; +} + +/* Reopen H through decompressor DECOMP. */ + +static int +ghw_openz (struct ghw_handler *h, const char *decomp, const char *filename) +{ + int plen = strlen (decomp) + 1 + strlen (filename) + 1; + char *p = malloc_unwrap (plen); + + snprintf (p, plen, "%s %s", decomp, filename); + fclose (h->stream); + h->stream = popen (p, "r"); + free (p); + + if (h->stream == NULL) + return -1; + + h->stream_ispipe = 1; + + return 0; +} + +int +ghw_open (struct ghw_handler *h, const char *filename) +{ + char hdr[16]; + + h->stream = fopen (filename, "rb"); + if (h->stream == NULL) + return -1; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + /* Check compression layer. */ + if (!memcmp (hdr, "\x1f\x8b", 2)) + { + if (ghw_openz (h, "gzip -cd", filename) < 0) + return -1; + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + } + else if (!memcmp (hdr, "BZ", 2)) + { + if (ghw_openz (h, "bzip2 -cd", filename) < 0) + return -1; + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + } + else + { + h->stream_ispipe = 0; + } + + /* Check magic. */ + if (memcmp (hdr, "GHDLwave\n", 9) != 0) + return -2; + /* Check version. */ + if (hdr[9] != 16 || hdr[10] != 0) + return -2; + h->version = hdr[11]; + if (h->version > 1) + return -3; + if (hdr[12] == 1) + h->word_be = 0; + else if (hdr[12] == 2) + h->word_be = 1; + else + return -4; +#if 0 + /* Endianness. */ + { + int endian; + union + { + unsigned char b[4]; + uint32_t i; + } v; + v.i = 0x11223344; + if (v.b[0] == 0x11) + endian = 2; + else if (v.b[0] == 0x44) + endian = 1; + else + return -3; + + if (hdr[12] != 1 && hdr[12] != 2) + return -3; + if (hdr[12] != endian) + h->swap_word = 1; + else + h->swap_word = 0; + } +#endif + h->word_len = hdr[13]; + h->off_len = hdr[14]; + + if (hdr[15] != 0) + return -5; + + h->hie = NULL; + return 0; +} + +int32_t +ghw_get_i32 (struct ghw_handler *h, unsigned char *b) +{ + if (h->word_be) + return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0); + else + return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0); +} + +// Read an i32, make sure it's positive, cast to u32 +uint32_t +ghw_get_i32_positive (struct ghw_handler *h, unsigned char *b) +{ + int32_t val_i = ghw_get_i32 (h, b); + if (val_i < 0) ghw_error_exit (); + return (uint32_t) val_i; +} + +int64_t +ghw_get_i64 (struct ghw_handler *ghw_h, unsigned char *b) +{ + int l, h; + + if (ghw_h->word_be) + { + h = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0); + l = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | (b[7] << 0); + } + else + { + l = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0); + h = (b[7] << 24) | (b[6] << 16) | (b[5] << 8) | (b[4] << 0); + } + return (((int64_t) h) << 32) | l; +} + +int +ghw_read_byte (struct ghw_handler *h, unsigned char *res) +{ + int v; + + v = fgetc (h->stream); + if (v == EOF) + return -1; + *res = v; + return 0; +} + +int +ghw_read_uleb128 (struct ghw_handler *h, uint32_t * res) +{ + uint32_t r = 0; + unsigned int off = 0; + + while (1) + { + int v = fgetc (h->stream); + if (v == EOF) + return -1; + r |= (v & 0x7f) << off; + if ((v & 0x80) == 0) + break; + off += 7; + } + *res = r; + return 0; +} + +int +ghw_read_sleb128 (struct ghw_handler *h, int32_t * res) +{ + int32_t r = 0; + unsigned int off = 0; + + while (1) + { + int v = fgetc (h->stream); + if (v == EOF) + return -1; + r |= ((int32_t) (v & 0x7f)) << off; + off += 7; + if ((v & 0x80) == 0) + { + if ((v & 0x40) && off < 32) + r |= ~0U << off; + break; + } + } + *res = r; + return 0; +} + +int +ghw_read_lsleb128 (struct ghw_handler *h, int64_t * res) +{ + static const int64_t r_mask = -1; + int64_t r = 0; + unsigned int off = 0; + + while (1) + { + int v = fgetc (h->stream); + if (v == EOF) + return -1; + r |= ((int64_t) (v & 0x7f)) << off; + off += 7; + if ((v & 0x80) == 0) + { + if ((v & 0x40) && off < 64) + r |= r_mask << off; + break; + } + } + *res = r; + return 0; +} + +int +ghw_read_f64 (struct ghw_handler *h, double *res) +{ + /* FIXME: handle byte order. */ + if (fread (res, sizeof (*res), 1, h->stream) != 1) + return -1; + return 0; +} + +// Get the string with id str_id from h->str_table if the ID is valid. +static const char * +ghw_get_str(struct ghw_handler *h, uint32_t str_id) +{ + if (str_id >= h->nbr_str) + { + fprintf(stderr, "Invalid string ID %u in ghw file\n", str_id); + ghw_error_exit(); + } + return h->str_table[str_id]; +} + +// Read a string ID from the input file and return the correpsonding string. +const char * +ghw_read_strid (struct ghw_handler *h) +{ + uint32_t id; + + if (ghw_read_uleb128 (h, &id) != 0) + ghw_error_exit(); + return ghw_get_str(h, id); +} + +// Get the type with ID type_id from h->types if the ID is valid and +// the type has been initialized. +union ghw_type * +ghw_get_typeid (struct ghw_handler *h, uint32_t type_id) +{ + if ((type_id < 1) || type_id - 1 >= h->nbr_types || + h->types[type_id - 1] == NULL) + { + fprintf(stderr, "Invalid typeid ID %u in ghw file\n", type_id); + ghw_error_exit(); + } + return h->types[type_id - 1]; +} + +// Read a typeid ID from the input file and return the correpsonding string. +union ghw_type * +ghw_read_typeid (struct ghw_handler *h) +{ + uint32_t id; + + if (ghw_read_uleb128 (h, &id) != 0) + ghw_error_exit(); + return ghw_get_typeid(h, id); +} + +union ghw_range * +ghw_read_range (struct ghw_handler *h) +{ + int t = fgetc (h->stream); + if (t == EOF) + ghw_error_exit(); + switch (t & 0x7f) + { + case ghdl_rtik_type_b2: + { + struct ghw_range_b2 *r; + r = malloc_unwrap (sizeof (struct ghw_range_b2)); + r->kind = t & 0x7f; + r->dir = (t & 0x80) != 0; + if (ghw_read_byte (h, &r->left) != 0) + goto err_rr_b2; + if (ghw_read_byte (h, &r->right) != 0) + goto err_rr_b2; + return (union ghw_range *) r; + err_rr_b2: + free (r); + ghw_error_exit(); + } + case ghdl_rtik_type_e8: + { + struct ghw_range_e8 *r; + r = malloc_unwrap (sizeof (struct ghw_range_e8)); + r->kind = t & 0x7f; + r->dir = (t & 0x80) != 0; + if (ghw_read_byte (h, &r->left) != 0) + goto err_e8; + if (ghw_read_byte (h, &r->right) != 0) + goto err_e8; + return (union ghw_range *) r; + err_e8: + free (r); + ghw_error_exit(); + } + case ghdl_rtik_type_i32: + case ghdl_rtik_type_p32: + { + struct ghw_range_i32 *r; + r = malloc_unwrap (sizeof (struct ghw_range_i32)); + r->kind = t & 0x7f; + r->dir = (t & 0x80) != 0; + if (ghw_read_sleb128 (h, &r->left) != 0) + goto err_i32; + if (ghw_read_sleb128 (h, &r->right) != 0) + goto err_i32; + return (union ghw_range *) r; + err_i32: + free (r); + ghw_error_exit(); + } + case ghdl_rtik_type_i64: + case ghdl_rtik_type_p64: + { + struct ghw_range_i64 *r; + r = malloc_unwrap (sizeof (struct ghw_range_i64)); + r->kind = t & 0x7f; + r->dir = (t & 0x80) != 0; + if (ghw_read_lsleb128 (h, &r->left) != 0) + goto err_i64; + if (ghw_read_lsleb128 (h, &r->right) != 0) + goto err_i64; + return (union ghw_range *) r; + err_i64: + free (r); + ghw_error_exit(); + } + case ghdl_rtik_type_f64: + { + struct ghw_range_f64 *r; + r = malloc_unwrap (sizeof (struct ghw_range_f64)); + r->kind = t & 0x7f; + r->dir = (t & 0x80) != 0; + if (ghw_read_f64 (h, &r->left) != 0) + goto err_f64; + if (ghw_read_f64 (h, &r->right) != 0) + goto err_f64; + return (union ghw_range *) r; + err_f64: + free (r); + ghw_error_exit(); + } + default: + fprintf (stderr, "ghw_read_range: type %d unhandled\n", t & 0x7f); + ghw_error_exit(); + } +} + +int +ghw_read_str (struct ghw_handler *h) +{ + unsigned char hdr[12]; + unsigned i; + char *p; + int prev_len; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 0 || hdr[3] != 0) + return -1; + + // Read number of strings and total string size. Make sure that nbr_string + // is not too large, as it's incremented afterwards. + h->nbr_str = ghw_get_i32_positive (h, &hdr[4]); + h->nbr_str++; + h->str_size = (uint32_t) ghw_get_i32 (h, &hdr[8]); + + // Allocate str_table, str_content. Avoid exceeding size_t limits. + h->str_table = (char **) calloc_unwrap(h->nbr_str, sizeof (char *)); + + uint64_t alloc_size = h->str_size + h->nbr_str + 1; + if (alloc_size > SIZE_MAX) ghw_error_exit(); + h->str_content = (char *) malloc_unwrap (alloc_size); + char *p_end = h->str_content + alloc_size; + + if (h->flag_verbose) + { + printf ("Number of strings: %u\n", h->nbr_str - 1); + printf ("String table size: %u\n", h->str_size); + } + + h->str_table[0] = ""; + p = h->str_content; + prev_len = 0; + for (i = 1; i < h->nbr_str; i++) + { + int j; + int c; + char *prev; + int sh; + + h->str_table[i] = p; + prev = h->str_table[i - 1]; + for (j = 0; j < prev_len; j++) + { + if (p >= p_end) goto err_ghw_read_str; + *p++ = prev[j]; + } + + while (1) + { + c = fgetc (h->stream); + if (c == EOF) + return -1; + if ((c >= 0 && c <= 31) || (c >= 128 && c <= 159)) + break; + if (p >= p_end) goto err_ghw_read_str; + *p++ = c; + } + + if (p >= p_end) goto err_ghw_read_str; + *p++ = 0; + + if (h->flag_verbose > 1) + printf (" string %u (pl=%d): %s\n", i, prev_len, ghw_get_str(h, i)); + + prev_len = c & 0x1f; + sh = 5; + while (c >= 128) + { + c = fgetc (h->stream); + if (c == EOF) + return -1; + prev_len |= (c & 0x1f) << sh; + sh += 5; + } + } + if (fread (hdr, 4, 1, h->stream) != 1) + return -1; + if (memcmp (hdr, "EOS", 4) != 0) + return -1; + return 0; + +err_ghw_read_str: + fprintf(stderr, "Invalid string entry in GHW file.\n"); + ghw_error_exit(); + + +} + +union ghw_type * +ghw_get_base_type (union ghw_type *t) +{ + switch (t->kind) + { + case ghdl_rtik_type_b2: + case ghdl_rtik_type_e8: + case ghdl_rtik_type_e32: + case ghdl_rtik_type_i32: + case ghdl_rtik_type_i64: + case ghdl_rtik_type_f64: + case ghdl_rtik_type_p32: + case ghdl_rtik_type_p64: + case ghdl_rtik_type_array: + return t; + case ghdl_rtik_subtype_scalar: + return t->ss.base; + case ghdl_rtik_subtype_array: + return t->sa.base; + case ghdl_rtik_subtype_unbounded_array: + return t->sua.base; + default: + fprintf (stderr, "ghw_get_base_type: cannot handle type %d\n", t->kind); + ghw_error_exit(); + } +} + +/* Return -1 for unbounded types. */ +static int +get_nbr_elements (union ghw_type *t) +{ + switch (t->kind) + { + case ghdl_rtik_type_b2: + case ghdl_rtik_type_e8: + case ghdl_rtik_type_e32: + case ghdl_rtik_type_i32: + case ghdl_rtik_type_i64: + case ghdl_rtik_type_f64: + case ghdl_rtik_type_p32: + case ghdl_rtik_type_p64: + case ghdl_rtik_subtype_scalar: + return 1; + case ghdl_rtik_type_array: + return -1; + case ghdl_rtik_subtype_array: + return t->sa.nbr_scalars; + case ghdl_rtik_type_record: + return t->rec.nbr_scalars; + case ghdl_rtik_subtype_record: + return t->sr.nbr_scalars; + case ghdl_rtik_subtype_unbounded_record: + case ghdl_rtik_subtype_unbounded_array: + return -1; + default: + fprintf (stderr, "get_nbr_elements: unhandled type %d\n", t->kind); + ghw_error_exit(); + } +} + +int +ghw_get_range_length (union ghw_range *rng) +{ + int res; + + if (rng == NULL) ghw_error_exit(); + + assert (rng != NULL); + + switch (rng->kind) + { + case ghdl_rtik_type_i32: + if (rng->i32.dir) + res = rng->i32.left - rng->i32.right + 1; + else + res = rng->i32.right - rng->i32.left + 1; + break; + case ghdl_rtik_type_b2: + if (rng->b2.dir) + res = rng->b2.left - rng->b2.right + 1; + else + res = rng->b2.right - rng->b2.left + 1; + break; + case ghdl_rtik_type_e8: + if (rng->e8.dir) + res = rng->e8.left - rng->e8.right + 1; + else + res = rng->e8.right - rng->e8.left + 1; + break; + default: + fprintf (stderr, "get_range_length: unhandled kind %d\n", rng->kind); + ghw_error_exit(); + } + /* The length of a null range is 0. */ + return (res <= 0) ? 0 : res; +} + +static union ghw_type *ghw_read_type_bounds (struct ghw_handler *h, + union ghw_type *base); + +/* Create an array subtype using BASE and ranges read from H. */ + +struct ghw_subtype_array * +ghw_read_array_subtype (struct ghw_handler *h, union ghw_type *base) +{ + struct ghw_type_array *arr = + (struct ghw_type_array *) ghw_get_base_type (base); + if (arr->kind != ghdl_rtik_type_array) ghw_error_exit(); + + struct ghw_subtype_array *sa; + unsigned j; + int nbr_scalars; + int nbr_els; + + sa = malloc_unwrap (sizeof (struct ghw_subtype_array)); + sa->kind = ghdl_rtik_subtype_array; + sa->name = NULL; + sa->base = base; + nbr_els = get_nbr_elements (arr->el); + nbr_scalars = 1; + sa->rngs = calloc_unwrap (arr->nbr_dim, sizeof (union ghw_range *)); + for (j = 0; j < arr->nbr_dim; j++) + { + sa->rngs[j] = ghw_read_range (h); + nbr_scalars *= ghw_get_range_length (sa->rngs[j]); + } + if (nbr_els >= 0) + { + /* Element type is bounded. */ + sa->el = arr->el; + } + else + { + /* Read bounds for the elements. */ + sa->el = ghw_read_type_bounds (h, arr->el); + nbr_els = get_nbr_elements (sa->el); + } + sa->nbr_scalars = nbr_scalars * nbr_els; + return sa; +} + +struct ghw_subtype_record * +ghw_read_record_subtype (struct ghw_handler *h, struct ghw_type_record *base) +{ + struct ghw_subtype_record *sr; + + sr = malloc_unwrap (sizeof (struct ghw_subtype_record)); + sr->kind = ghdl_rtik_subtype_record; + sr->name = NULL; + sr->base = base; + if (base->nbr_scalars >= 0) + { + /* Record base type is bounded. */ + sr->nbr_scalars = base->nbr_scalars; + sr->els = base->els; + } + else + { + /* Read subtypes. */ + unsigned j; + int nbr_scalars; + + sr->els = + calloc_unwrap (base->nbr_fields, sizeof (struct ghw_record_element)); + nbr_scalars = 0; + for (j = 0; j < base->nbr_fields; j++) + { + union ghw_type *btype = base->els[j].type; + int el_nbr_scalars = get_nbr_elements (btype); + + sr->els[j].name = base->els[j].name; + if (el_nbr_scalars >= 0) + { + /* Element is constrained. */ + sr->els[j].type = btype; + } + else + { + sr->els[j].type = ghw_read_type_bounds (h, btype); + el_nbr_scalars = get_nbr_elements (sr->els[j].type); + } + nbr_scalars += el_nbr_scalars; + } + sr->nbr_scalars = nbr_scalars; + } + return sr; +} + +/* Read bounds for BASE and create a subtype. */ + +static union ghw_type * +ghw_read_type_bounds (struct ghw_handler *h, union ghw_type *base) +{ + switch (base->kind) + { + case ghdl_rtik_type_array: + case ghdl_rtik_subtype_unbounded_array: + return (union ghw_type *) ghw_read_array_subtype (h, base); + break; + case ghdl_rtik_type_record: + case ghdl_rtik_subtype_unbounded_record: + return (union ghw_type *) ghw_read_record_subtype (h, &base->rec); + break; + default: + fprintf (stderr, "ghw_read_type_bounds: unhandled kind %d\n", + base->kind); + ghw_error_exit(); + } +} + +int +ghw_read_type (struct ghw_handler *h) +{ + unsigned char hdr[8]; + uint32_t i; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 0 || hdr[3] != 0) + return -1; + + h->nbr_types = ghw_get_i32_positive (h, &hdr[4]); + + // Allocate type storage, initialize it to 0 to catch invalid accesses. + h->types = (union ghw_type **) calloc_unwrap (h->nbr_types, sizeof (union ghw_type *)); + + for (i = 0; i < h->nbr_types; i++) + { + int t; + + t = fgetc (h->stream); + if (t == EOF) + return -1; + if (h->flag_verbose > 1) + printf ("type[%u]= %d\n", i, t); + switch (t) + { + case ghdl_rtik_type_b2: + case ghdl_rtik_type_e8: + { + struct ghw_type_enum *e; + uint32_t j; + + e = malloc_unwrap (sizeof (struct ghw_type_enum)); + e->lits = NULL; + e->kind = t; + e->wkt = ghw_wkt_unknown; + e->name = ghw_read_strid (h); + if (ghw_read_uleb128 (h, &e->nbr) != 0) + goto err_rt_b2; + uint64_t lit_size = e->nbr * sizeof (char *); + if (lit_size > SIZE_MAX) ghw_error_exit(); + e->lits = (const char **) malloc_unwrap (lit_size); + if (h->flag_verbose > 1) + printf ("enum %s:", e->name); + for (j = 0; j < e->nbr; j++) + { + e->lits[j] = ghw_read_strid (h); + if (h->flag_verbose > 1) + printf (" %s", e->lits[j]); + } + if (h->flag_verbose > 1) + printf ("\n"); + h->types[i] = (union ghw_type *) e; + break; + err_rt_b2: + free (e->lits); + free (e); + return -1; + } + break; + case ghdl_rtik_type_i32: + case ghdl_rtik_type_i64: + case ghdl_rtik_type_f64: + { + struct ghw_type_scalar *sc; + + sc = malloc_unwrap (sizeof (struct ghw_type_scalar)); + sc->kind = t; + sc->name = ghw_read_strid (h); + if (h->flag_verbose > 1) + printf ("scalar: %s\n", sc->name); + h->types[i] = (union ghw_type *) sc; + } break; + case ghdl_rtik_type_p32: + case ghdl_rtik_type_p64: + { + struct ghw_type_physical *ph; + + ph = malloc_unwrap (sizeof (struct ghw_type_physical)); + ph->kind = t; + ph->name = ghw_read_strid (h); + ph->units = NULL; + if (h->version == 0) + ph->nbr_units = 0; + else + { + unsigned j; + + if (ghw_read_uleb128 (h, &ph->nbr_units) != 0) + goto err_p32; + ph->units = calloc_unwrap (ph->nbr_units, sizeof (struct ghw_unit)); + for (j = 0; j < ph->nbr_units; j++) + { + ph->units[j].name = ghw_read_strid (h); + if (ghw_read_lsleb128 (h, &ph->units[j].val) < 0) + goto err_p32; + } + } + if (h->flag_verbose > 1) + printf ("physical: %s\n", ph->name); + h->types[i] = (union ghw_type *) ph; + break; + err_p32: + free (ph->units); + free (ph); + return -1; + } + break; + case ghdl_rtik_subtype_scalar: + { + struct ghw_subtype_scalar *ss; + + ss = malloc_unwrap (sizeof (struct ghw_subtype_scalar)); + ss->kind = t; + ss->name = ghw_read_strid (h); + ss->base = ghw_read_typeid (h); + ss->rng = ghw_read_range (h); + if (h->flag_verbose > 1) + printf ("subtype scalar: %s\n", ss->name); + h->types[i] = (union ghw_type *) ss; + } break; + case ghdl_rtik_type_array: + { + struct ghw_type_array *arr; + unsigned j; + + arr = malloc_unwrap (sizeof (struct ghw_type_array)); + arr->dims = NULL; + arr->kind = t; + arr->name = ghw_read_strid (h); + arr->el = ghw_read_typeid (h); + if (ghw_read_uleb128 (h, &arr->nbr_dim) != 0) + goto err_array; + arr->dims = + (union ghw_type **) calloc_unwrap (arr->nbr_dim, + sizeof (union ghw_type *)); + for (j = 0; j < arr->nbr_dim; j++) + arr->dims[j] = ghw_read_typeid (h); + if (h->flag_verbose > 1) + printf ("array: %s (ndim=%u) of %s\n", arr->name, arr->nbr_dim, + arr->el->common.name); + h->types[i] = (union ghw_type *) arr; + break; + err_array: + if (arr->dims != NULL) free (arr->dims); + free (arr); + return -1; + } + break; + case ghdl_rtik_subtype_array: + { + struct ghw_subtype_array *sa; + const char *name; + union ghw_type *base; + + name = ghw_read_strid (h); + base = ghw_read_typeid (h); + + sa = ghw_read_array_subtype (h, base); + sa->name = name; + h->types[i] = (union ghw_type *) sa; + if (h->flag_verbose > 1) + printf ("subtype array: %s (nbr_scalars=%d)\n", sa->name, + sa->nbr_scalars); + } + break; + case ghdl_rtik_subtype_unbounded_array: + { + struct ghw_subtype_unbounded_array *sua; + + sua = malloc_unwrap (sizeof (struct ghw_subtype_unbounded_array)); + sua->kind = t; + sua->name = ghw_read_strid (h); + sua->base = ghw_read_typeid (h); + h->types[i] = (union ghw_type *) sua; + if (h->flag_verbose > 1) + printf ("subtype unbounded array: %s\n", sua->name); + } + break; + case ghdl_rtik_type_record: + { + struct ghw_type_record *rec; + unsigned j; + int nbr_scalars; + + rec = malloc_unwrap (sizeof (struct ghw_type_record)); + rec->kind = t; + rec->name = ghw_read_strid (h); + rec->els = NULL; + if (ghw_read_uleb128 (h, &rec->nbr_fields) != 0) + goto err_record; + rec->els = + calloc_unwrap (rec->nbr_fields, sizeof (struct ghw_record_element)); + nbr_scalars = 0; + for (j = 0; j < rec->nbr_fields; j++) + { + rec->els[j].name = ghw_read_strid (h); + rec->els[j].type = ghw_read_typeid (h); + if (nbr_scalars != -1) + { + int field_nbr_scalars = + get_nbr_elements (rec->els[j].type); + if (field_nbr_scalars == -1) + nbr_scalars = -1; + else + nbr_scalars += field_nbr_scalars; + } + } + rec->nbr_scalars = nbr_scalars; + if (h->flag_verbose > 1) + printf ("record type: %s (nbr_scalars=%d)\n", rec->name, + rec->nbr_scalars); + h->types[i] = (union ghw_type *) rec; + break; + err_record: + free (rec->els); + free (rec); + return -1; + } + break; + case ghdl_rtik_subtype_record: + { + struct ghw_subtype_record *sr; + const char *name; + struct ghw_type_record *base; + + name = ghw_read_strid (h); + union ghw_type * base_u = ghw_read_typeid (h); + if (base_u->kind != ghdl_rtik_type_record) ghw_error_exit(); + base = (struct ghw_type_record *) base_u; + + sr = ghw_read_record_subtype (h, base); + sr->name = name; + h->types[i] = (union ghw_type *) sr; + if (h->flag_verbose > 1) + printf ("subtype record: %s (nbr_scalars=%d)\n", sr->name, + sr->nbr_scalars); + } + break; + case ghdl_rtik_subtype_unbounded_record: + { + struct ghw_subtype_unbounded_record *sur; + + sur = malloc_unwrap (sizeof (struct ghw_subtype_unbounded_record)); + sur->kind = t; + sur->name = ghw_read_strid (h); + union ghw_type * base_u = ghw_read_typeid (h); + if (base_u->kind != ghdl_rtik_type_record) ghw_error_exit(); + sur->base = (struct ghw_type_record *) base_u; + h->types[i] = (union ghw_type *) sur; + if (h->flag_verbose > 1) + printf ("subtype unbounded record: %s\n", sur->name); + } + break; + default: + fprintf (stderr, "ghw_read_type: unknown type %d\n", t); + return -1; + } + } + if (fgetc (h->stream) != 0) + return -1; + return 0; +} + +int +ghw_read_wk_types (struct ghw_handler *h) +{ + char hdr[4]; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 0 || hdr[3] != 0) + return -1; + + while (1) + { + int t; + union ghw_type *tid; + + t = fgetc (h->stream); + if (t == EOF) + return -1; + else if (t == 0) + break; + + tid = ghw_read_typeid (h); + if (tid->kind == ghdl_rtik_type_b2 || tid->kind == ghdl_rtik_type_e8) + { + if (h->flag_verbose > 0) + printf ("%s: wkt=%d\n", tid->en.name, t); + tid->en.wkt = t; + } + } + return 0; +} + +void +ghw_disp_typename (struct ghw_handler *h, union ghw_type *t) +{ + (void) h; + printf ("%s", t->common.name); +} + +/* Read a signal composed of severals elements. + Return 0 for success. */ +int +ghw_read_signal (struct ghw_handler *h, unsigned int *sigs, union ghw_type *t) +{ + switch (t->kind) + { + case ghdl_rtik_type_b2: + case ghdl_rtik_type_e8: + case ghdl_rtik_type_e32: + case ghdl_rtik_subtype_scalar: + { + unsigned int sig_el; + + if (ghw_read_uleb128 (h, &sig_el) < 0) + return -1; + *sigs = sig_el; + if (sig_el == 0 || sig_el >= h->nbr_sigs) + return -1; + if (h->sigs[sig_el].type == NULL) + h->sigs[sig_el].type = ghw_get_base_type (t); + } + return 0; + case ghdl_rtik_subtype_array: + { + int i; + int stride; + int len; + + len = t->sa.nbr_scalars; + stride = get_nbr_elements (t->sa.el); + + for (i = 0; i < len; i += stride) + if (ghw_read_signal (h, &sigs[i], t->sa.el) < 0) + return -1; + } + return 0; + case ghdl_rtik_type_record: + { + struct ghw_type_record *r = &t->rec; + int nbr_fields = r->nbr_fields; + int i; + int off; + + off = 0; + for (i = 0; i < nbr_fields; i++) + { + if (ghw_read_signal (h, &sigs[off], r->els[i].type) < 0) + return -1; + off += get_nbr_elements (r->els[i].type); + } + } + return 0; + case ghdl_rtik_subtype_record: + { + struct ghw_subtype_record *sr = &t->sr; + int nbr_fields = sr->base->nbr_fields; + int i; + int off; + + off = 0; + for (i = 0; i < nbr_fields; i++) + { + if (ghw_read_signal (h, &sigs[off], sr->els[i].type) < 0) + return -1; + off += get_nbr_elements (sr->els[i].type); + } + } + return 0; + default: + fprintf (stderr, "ghw_read_signal: type kind %d unhandled\n", t->kind); + ghw_error_exit(); + } +} + +int +ghw_read_value (struct ghw_handler *h, + union ghw_val *val, union ghw_type *type) +{ + switch (ghw_get_base_type (type)->kind) + { + case ghdl_rtik_type_b2: + { + int v; + v = fgetc (h->stream); + if (v == EOF) + return -1; + val->b2 = v; + } + break; + case ghdl_rtik_type_e8: + { + int v; + v = fgetc (h->stream); + if (v == EOF) + return -1; + val->e8 = v; + } + break; + case ghdl_rtik_type_i32: + case ghdl_rtik_type_p32: + { + int32_t v; + if (ghw_read_sleb128 (h, &v) < 0) + return -1; + val->i32 = v; + } + break; + case ghdl_rtik_type_f64: + { + double v; + if (ghw_read_f64 (h, &v) < 0) + return -1; + val->f64 = v; + } + break; + case ghdl_rtik_type_p64: + { + int64_t v; + if (ghw_read_lsleb128 (h, &v) < 0) + return -1; + val->i64 = v; + } + break; + default: + fprintf (stderr, "read_value: cannot handle format %d\n", type->kind); + ghw_error_exit(); + } + return 0; +} + +int +ghw_read_hie (struct ghw_handler *h) +{ + unsigned char hdr[16]; + int nbr_scopes; + int nbr_sigs; + unsigned i; + struct ghw_hie *blk; + struct ghw_hie **last; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 0 || hdr[3] != 0) + return -1; + nbr_scopes = ghw_get_i32 (h, &hdr[4]); + /* Number of declared signals (which may be composite). */ + nbr_sigs = ghw_get_i32 (h, &hdr[8]); + /* Number of basic signals. */ + h->nbr_sigs = ghw_get_i32_positive (h, &hdr[12]); + + if (h->flag_verbose) + printf ("%d scopes, %d signals, %u signal elements\n", nbr_scopes, + nbr_sigs, h->nbr_sigs); + + blk = (struct ghw_hie *) malloc_unwrap (sizeof (struct ghw_hie)); + blk->kind = ghw_hie_design; + blk->name = NULL; + blk->parent = NULL; + blk->brother = NULL; + blk->u.blk.child = NULL; + + last = &blk->u.blk.child; + h->hie = blk; + + h->nbr_sigs++; + h->skip_sigs = NULL; + h->flag_full_names = 0; + h->sigs_no_null = 0; + h->sigs = (struct ghw_sig *) calloc_unwrap (h->nbr_sigs, sizeof (struct ghw_sig)); + + while (1) + { + int t; + struct ghw_hie *el; + unsigned int str; + + t = fgetc (h->stream); + if (t == EOF) + return -1; + if (t == 0) + break; + + if (t == ghw_hie_eos) + { + if (blk->parent == NULL) ghw_error_exit(); + blk = blk->parent; + if (blk->u.blk.child == NULL) + last = &blk->u.blk.child; + else + { + struct ghw_hie *l = blk->u.blk.child; + while (l->brother != NULL) + l = l->brother; + last = &l->brother; + } + + continue; + } + + el = (struct ghw_hie *) malloc_unwrap (sizeof (struct ghw_hie)); + el->kind = t; + el->parent = blk; + el->brother = NULL; + + /* Link. */ + *last = el; + last = &el->brother; + + /* Read name. */ + if (ghw_read_uleb128 (h, &str) != 0) + return -1; + el->name = ghw_get_str(h, str); + el->name = h->str_table[str]; + + switch (t) + { + case ghw_hie_eoh: + case ghw_hie_design: + case ghw_hie_eos: + /* Should not be here. */ + abort(); + case ghw_hie_process: + el->u.blk.child = NULL; + break; + case ghw_hie_block: + case ghw_hie_generate_if: + case ghw_hie_generate_for: + case ghw_hie_instance: + case ghw_hie_generic: + case ghw_hie_package: + /* Create a block. */ + el->u.blk.child = NULL; + + if (t == ghw_hie_generate_for) + { + el->u.blk.iter_type = ghw_read_typeid (h); + el->u.blk.iter_value = malloc_unwrap (sizeof (union ghw_val)); + if (ghw_read_value + (h, el->u.blk.iter_value, el->u.blk.iter_type) < 0) + return -1; + } + blk = el; + last = &el->u.blk.child; + break; + case ghw_hie_signal: + case ghw_hie_port_in: + case ghw_hie_port_out: + case ghw_hie_port_inout: + case ghw_hie_port_buffer: + case ghw_hie_port_linkage: + /* For a signal, read type. */ + { + int nbr_el; + unsigned int *sigs; + + el->u.sig.type = ghw_read_typeid (h); + nbr_el = get_nbr_elements (el->u.sig.type); + if (nbr_el < 0) + return -1; + sigs = + (unsigned int *) calloc_unwrap (nbr_el + 1, sizeof (unsigned int)); + el->u.sig.sigs = sigs; + /* Last element is NULL. */ + sigs[nbr_el] = 0; + + if (h->flag_verbose > 1) + printf ("signal %s: %d el [", el->name, nbr_el); + if (ghw_read_signal (h, sigs, el->u.sig.type) < 0) + return -1; + if (h->flag_verbose > 1) + { + int j; + for (j = 0; j < nbr_el; j++) + printf (" #%u", sigs[j]); + printf ("]\n"); + } + } + break; + default: + fprintf (stderr, "ghw_read_hie: unhandled kind %d\n", t); + ghw_error_exit(); + } + } + + /* Allocate values. Store indication if we have NULL-type signals with index + i > 0. Index i=0 */ + int sigs_no_null = 1; + for (i = 0; i < h->nbr_sigs; i++) + if (h->sigs[i].type != NULL) + h->sigs[i].val = (union ghw_val *) malloc_unwrap (sizeof (union ghw_val)); + else if (i > 0 && sigs_no_null != 0) + { + printf ("Warning: ghw_read_hie: NULL type signal %ud.\n", i); + printf ("Loading this file may take a long time.\n"); + sigs_no_null = 0; + } + + h->sigs_no_null = sigs_no_null; + return 0; +} + +const char * +ghw_get_hie_name (struct ghw_hie *h) +{ + switch (h->kind) + { + case ghw_hie_eoh: + return "eoh"; + case ghw_hie_design: + return "design"; + case ghw_hie_block: + return "block"; + case ghw_hie_generate_if: + return "generate-if"; + case ghw_hie_generate_for: + return "generate-for"; + case ghw_hie_instance: + return "instance"; + case ghw_hie_package: + return "package"; + case ghw_hie_process: + return "process"; + case ghw_hie_generic: + return "generic"; + case ghw_hie_eos: + return "eos"; + case ghw_hie_signal: + return "signal"; + case ghw_hie_port_in: + return "port-in"; + case ghw_hie_port_out: + return "port-out"; + case ghw_hie_port_inout: + return "port-inout"; + case ghw_hie_port_buffer: + return "port-buffer"; + case ghw_hie_port_linkage: + return "port-linkage"; + default: + return "??"; + } +} + +void ghw_disp_value (union ghw_val *val, union ghw_type *type); + +static void +print_name (struct ghw_hie *hie, int full_names) +{ + int i; + int depth; + struct ghw_hie *p; + struct ghw_hie **buf; + struct ghw_hie **end; + + /* HIE must be valid. */ + assert (hie->name != NULL); + + if (0 == full_names) + { + printf (" %s: ", hie->name); + return; + } + + p = hie; + depth = 0; + while (p && p->name) + { + p = p->parent; + ++depth; + } + buf = (struct ghw_hie **) calloc_unwrap (depth, sizeof (struct ghw_hie *)); + + p = hie; + end = depth + buf; + while (p && p->name) + { + *(--end) = p; + p = p->parent; + } + + putchar (' '); + putchar ('/'); + for (i = 0; i < depth; ++i) + { + printf ("%s%s", i ? "/" : "", buf[i]->name); + if (ghw_hie_generate_for == buf[i]->kind) + { + putchar ('('); + ghw_disp_value (buf[i]->u.blk.iter_value, buf[i]->u.blk.iter_type); + putchar (')'); + } + } + putchar (':'); + putchar (' '); + free (buf); +} + +void +ghw_disp_hie (struct ghw_handler *h, struct ghw_hie *top) +{ + int i; + int indent; + struct ghw_hie *hie; + struct ghw_hie *n; + + hie = top; + indent = 0; + + while (1) + { + if (0 == h->flag_full_names) + for (i = 0; i < indent; i++) + fputc (' ', stdout); + printf ("%s", ghw_get_hie_name (hie)); + + switch (hie->kind) + { + case ghw_hie_design: + case ghw_hie_block: + case ghw_hie_generate_if: + case ghw_hie_generate_for: + case ghw_hie_instance: + case ghw_hie_process: + case ghw_hie_package: + if (hie->name) + print_name (hie, h->flag_full_names); + if (hie->kind == ghw_hie_generate_for) + { + printf ("("); + ghw_disp_value (hie->u.blk.iter_value, hie->u.blk.iter_type); + printf (")"); + } + n = hie->u.blk.child; + if (n == NULL) + n = hie->brother; + else + indent++; + break; + case ghw_hie_generic: + case ghw_hie_eos: + abort(); + case ghw_hie_signal: + case ghw_hie_port_in: + case ghw_hie_port_out: + case ghw_hie_port_inout: + case ghw_hie_port_buffer: + case ghw_hie_port_linkage: + { + unsigned int *sigs = hie->u.sig.sigs; + unsigned int k, num; + + print_name (hie, h->flag_full_names); + ghw_disp_subtype_indication (h, hie->u.sig.type); + printf (":"); + k = 0; + /* There can be 0-length signals. */ + while (sigs[k] != GHW_NO_SIG) + { + /* First signal of the range. */ + printf (" #%u", sigs[k]); + for (num = 1; sigs[k + num] != GHW_NO_SIG; num++) + if (sigs[k + num] != sigs[k + num - 1] + 1) + break; + if (num > 1) + printf ("-#%u", sigs[k + num - 1]); + k += num; + } + n = hie->brother; + } + break; + default: + abort(); + } + printf ("\n"); + + while (n == NULL) + { + if (hie->parent == NULL) + return; + hie = hie->parent; + indent--; + n = hie->brother; + } + hie = n; + } +} + +int +ghw_read_eoh (struct ghw_handler *h) +{ + (void) h; + return 0; +} + +int +ghw_read_base (struct ghw_handler *h) +{ + unsigned char hdr[4]; + int res; + + while (1) + { + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + if (memcmp (hdr, "STR", 4) == 0) + res = ghw_read_str (h); + else if (memcmp (hdr, "HIE", 4) == 0) + res = ghw_read_hie (h); + else if (memcmp (hdr, "TYP", 4) == 0) + res = ghw_read_type (h); + else if (memcmp (hdr, "WKT", 4) == 0) + res = ghw_read_wk_types (h); + else if (memcmp (hdr, "EOH", 4) == 0) + return 0; + else + { + fprintf (stderr, "ghw_read_base: unknown GHW section %c%c%c%c\n", + hdr[0], hdr[1], hdr[2], hdr[3]); + return -1; + } + if (res != 0) + { + fprintf (stderr, "ghw_read_base: error in section %s\n", hdr); + return res; + } + } +} + +int +ghw_read_signal_value (struct ghw_handler *h, struct ghw_sig *s) +{ + if (s->type == NULL) ghw_error_exit(); + return ghw_read_value (h, s->val, s->type); +} + +int +ghw_read_snapshot (struct ghw_handler *h) +{ + unsigned char hdr[12]; + unsigned i; + struct ghw_sig *s; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + if (hdr[0] != 0 || hdr[1] != 0 || hdr[2] != 0 || hdr[3] != 0) + return -1; + h->snap_time = ghw_get_i64 (h, &hdr[4]); + if (h->flag_verbose > 1) + printf ("Time is " GHWPRI64 " fs\n", h->snap_time); + + for (i = 0; i < h->nbr_sigs; i++) + { + s = &h->sigs[i]; + if (s->type != NULL) + { + if (h->flag_verbose > 1) + printf ("read type %d for sig %u\n", s->type->kind, i); + if (ghw_read_signal_value (h, s) < 0) + return -1; + } + } + if (fread (hdr, 4, 1, h->stream) != 1) + return -1; + + if (memcmp (hdr, "ESN", 4)) + return -1; + + return 0; +} + +void ghw_disp_values (struct ghw_handler *h); + +int +ghw_read_cycle_start (struct ghw_handler *h) +{ + unsigned char hdr[8]; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + h->snap_time = ghw_get_i64 (h, hdr); + return 0; +} + +int +ghw_read_cycle_cont (struct ghw_handler *h, int *list) +{ + uint32_t i; + int *list_p; + + i = 0; + list_p = list; + while (1) + { + uint32_t d; + + /* Read delta to next signal. */ + if (ghw_read_uleb128 (h, &d) < 0) + return -1; + if (d == 0) + { + /* Last signal reached. */ + break; + } + + /* Find next signal. */ + if (h->sigs_no_null) + { + /* Fast version. */ + i = i + d; + if (i >= h->nbr_sigs) + goto err; + } + else + { + /* Slow version: Linear search through all signals. Find d-th + element with non-NULL type. Note: Type of sigs[0] is ignored. */ + while (d > 0) + { + i++; + if (i >= h->nbr_sigs) + goto err; + if (h->sigs[i].type != NULL) + d--; + } + } + + // i=0 is not a valid signal + if (i == 0) goto err; + + if (ghw_read_signal_value (h, &h->sigs[i]) < 0) + return -1; + if (list_p) + *list_p++ = i; + } + + if (list_p) + *list_p = 0; + return 0; + +err: + fprintf(stderr, "Error: ghw_read_cycle_cont: Invalid entry in GHW file.\n"); + return -1; +} + +int +ghw_read_cycle_next (struct ghw_handler *h) +{ + int64_t d_time; + + if (ghw_read_lsleb128 (h, &d_time) < 0) + return -1; + if (d_time == -1) + return 0; + h->snap_time += d_time; + return 1; +} + +int +ghw_read_cycle_end (struct ghw_handler *h) +{ + char hdr[4]; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + if (memcmp (hdr, "ECY", 4)) + return -1; + + return 0; +} + +static const char * +ghw_get_lit (union ghw_type *type, uint32_t e) +{ + if (e >= type->en.nbr) + return "??"; + else + return type->en.lits[e]; +} + +static void +ghw_disp_lit (union ghw_type *type, uint32_t e) +{ + printf ("%s (%u)", ghw_get_lit (type, e), e); +} + +void +ghw_disp_value (union ghw_val *val, union ghw_type *type) +{ + switch (ghw_get_base_type (type)->kind) + { + case ghdl_rtik_type_b2: + ghw_disp_lit (type, val->b2); + break; + case ghdl_rtik_type_e8: + ghw_disp_lit (type, val->e8); + break; + case ghdl_rtik_type_i32: + printf (GHWPRI32, val->i32); + break; + case ghdl_rtik_type_p64: + printf (GHWPRI64, val->i64); + break; + case ghdl_rtik_type_f64: + printf ("%g", val->f64); + break; + default: + fprintf (stderr, "ghw_disp_value: cannot handle type %d\n", type->kind); + ghw_error_exit(); + } +} + +/* Put the ASCII representation of VAL into BUF, whose size if LEN. + A NUL is always written to BUF. +*/ +void +ghw_get_value (char *buf, int len, union ghw_val *val, union ghw_type *type) +{ + union ghw_type *base = ghw_get_base_type (type); + + switch (base->kind) + { + case ghdl_rtik_type_b2: + if (val->b2 <= 1) + { + strncpy (buf, ghw_get_lit(base, val->b2), len - 1); + buf[len - 1] = 0; + } + else + { + snprintf (buf, len, "?%d", val->b2); + } + break; + case ghdl_rtik_type_e8: + if (val->b2 <= base->en.nbr) + { + strncpy (buf, ghw_get_lit(base, val->e8), len - 1); + buf[len - 1] = 0; + } + else + { + snprintf (buf, len, "?%d", val->e8); + } + break; + case ghdl_rtik_type_i32: + snprintf (buf, len, GHWPRI32, val->i32); + break; + case ghdl_rtik_type_p64: + snprintf (buf, len, GHWPRI64, val->i64); + break; + case ghdl_rtik_type_f64: + snprintf (buf, len, "%g", val->f64); + break; + default: + snprintf (buf, len, "?bad type %d?", type->kind); + } +} + +static char +is_skip_signal (int *signals_to_keep, int nb_signals_to_keep, int signal) +{ + int i; + for (i = 0; i < nb_signals_to_keep; ++i) + { + if (signal == signals_to_keep[i]) + { + return 0; + } + } + return 1; +} + +void +ghw_filter_signals (struct ghw_handler *h, int *signals_to_keep, + int nb_signals_to_keep) +{ + unsigned i; + + if (0 < nb_signals_to_keep && 0 != signals_to_keep) + { + if (0 == h->skip_sigs) + { + h->skip_sigs = (char *) calloc_unwrap (h->nbr_sigs, sizeof (char)); + } + for (i = 0; i < h->nbr_sigs; ++i) + { + h->skip_sigs[i] = + is_skip_signal (signals_to_keep, nb_signals_to_keep, i); + } + } + else + { + if (0 != h->skip_sigs) + { + free (h->skip_sigs); + h->skip_sigs = 0; + } + } +} + +void +ghw_disp_values (struct ghw_handler *h) +{ + unsigned i; + for (i = 0; i < h->nbr_sigs; i++) + { + struct ghw_sig *s = &h->sigs[i]; + int skip = (0 != h->skip_sigs && (0 != h->skip_sigs[i])); + if (s->type != NULL && !skip) + { + printf ("#%u: ", i); + ghw_disp_value (s->val, s->type); + printf ("\n"); + } + } +} + +int +ghw_read_directory (struct ghw_handler *h) +{ + unsigned char hdr[8]; + int nbr_entries; + int i; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + nbr_entries = ghw_get_i32 (h, &hdr[4]); + + if (h->flag_verbose) + printf ("Directory (%d entries):\n", nbr_entries); + + for (i = 0; i < nbr_entries; i++) + { + unsigned char ent[8]; + int pos; + + if (fread (ent, sizeof (ent), 1, h->stream) != 1) + return -1; + + pos = ghw_get_i32 (h, &ent[4]); + if (h->flag_verbose) + printf (" %s at %d\n", ent, pos); + } + + if (fread (hdr, 4, 1, h->stream) != 1) + return -1; + if (memcmp (hdr, "EOD", 4)) + return -1; + return 0; +} + +int +ghw_read_tailer (struct ghw_handler *h) +{ + unsigned char hdr[8]; + int pos; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + return -1; + + pos = ghw_get_i32 (h, &hdr[4]); + + if (h->flag_verbose) + printf ("Tailer: directory at %d\n", pos); + return 0; +} + +enum ghw_res +ghw_read_sm_hdr (struct ghw_handler *h, int *list) +{ + unsigned char hdr[4]; + int res; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + { + if (feof (h->stream)) + return ghw_res_eof; + else + return ghw_res_error; + } + if (memcmp (hdr, "SNP", 4) == 0) + { + res = ghw_read_snapshot (h); + if (res < 0) + return res; + return ghw_res_snapshot; + } + else if (memcmp (hdr, "CYC", 4) == 0) + { + res = ghw_read_cycle_start (h); + if (res < 0) + return res; + res = ghw_read_cycle_cont (h, list); + if (res < 0) + return res; + + return ghw_res_cycle; + } + else if (memcmp (hdr, "DIR", 4) == 0) + { + res = ghw_read_directory (h); + } + else if (memcmp (hdr, "TAI", 4) == 0) + { + res = ghw_read_tailer (h); + } + else + { + fprintf (stderr, "unknown GHW section %c%c%c%c\n", hdr[0], hdr[1], + hdr[2], hdr[3]); + return -1; + } + if (res != 0) + return res; + return ghw_res_other; +} + +int +ghw_read_sm (struct ghw_handler *h, enum ghw_sm_type *sm) +{ + int res; + + while (1) + { + /* printf ("sm: state = %d\n", *sm); */ + switch (*sm) + { + case ghw_sm_init: + case ghw_sm_sect: + res = ghw_read_sm_hdr (h, NULL); + switch (res) + { + case ghw_res_other: + break; + case ghw_res_snapshot: + *sm = ghw_sm_sect; + return res; + case ghw_res_cycle: + *sm = ghw_sm_cycle; + return res; + default: + return res; + } + break; + case ghw_sm_cycle: + if (0) + printf ("Time is " GHWPRI64 " fs\n", h->snap_time); + if (0) + ghw_disp_values (h); + + res = ghw_read_cycle_next (h); + if (res < 0) + return res; + if (res == 1) + { + res = ghw_read_cycle_cont (h, NULL); + if (res < 0) + return res; + return ghw_res_cycle; + } + res = ghw_read_cycle_end (h); + if (res < 0) + return res; + *sm = ghw_sm_sect; + break; + } + } +} + +int +ghw_read_cycle (struct ghw_handler *h) +{ + int res; + + res = ghw_read_cycle_start (h); + if (res < 0) + return res; + while (1) + { + res = ghw_read_cycle_cont (h, NULL); + if (res < 0) + return res; + + if (0) + printf ("Time is " GHWPRI64 " fs\n", h->snap_time); + if (0) + ghw_disp_values (h); + + res = ghw_read_cycle_next (h); + if (res < 0) + return res; + if (res == 0) + break; + } + res = ghw_read_cycle_end (h); + return res; +} + +int +ghw_read_dump (struct ghw_handler *h) +{ + unsigned char hdr[4]; + int res; + + while (1) + { + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + { + if (feof (h->stream)) + return 0; + else + return -1; + } + if (memcmp (hdr, "SNP", 4) == 0) + { + res = ghw_read_snapshot (h); + if (0 && res >= 0) + ghw_disp_values (h); + } + else if (memcmp (hdr, "CYC", 4) == 0) + { + res = ghw_read_cycle (h); + } + else if (memcmp (hdr, "DIR", 4) == 0) + { + res = ghw_read_directory (h); + } + else if (memcmp (hdr, "TAI", 4) == 0) + { + res = ghw_read_tailer (h); + } + else + { + fprintf (stderr, "unknown GHW section %c%c%c%c\n", hdr[0], hdr[1], + hdr[2], hdr[3]); + return -1; + } + if (res != 0) + return res; + } +} + +struct ghw_section ghw_sections[] = { {"\0\0\0", NULL}, +{"STR", ghw_read_str}, +{"HIE", ghw_read_hie}, +{"TYP", ghw_read_type}, +{"WKT", ghw_read_wk_types}, +{"EOH", ghw_read_eoh}, +{"SNP", ghw_read_snapshot}, +{"CYC", ghw_read_cycle}, +{"DIR", ghw_read_directory}, +{"TAI", ghw_read_tailer} +}; + +int +ghw_read_section (struct ghw_handler *h) +{ + unsigned char hdr[4]; + unsigned i; + + if (fread (hdr, sizeof (hdr), 1, h->stream) != 1) + { + if (feof (h->stream)) + return -2; + else + return -1; + } + + for (i = 1; i < sizeof (ghw_sections) / sizeof (*ghw_sections); i++) + if (memcmp (hdr, ghw_sections[i].name, 4) == 0) + return i; + + fprintf (stderr, "ghw_read_section: unknown GHW section %c%c%c%c\n", hdr[0], + hdr[1], hdr[2], hdr[3]); + return 0; +} + +void +ghw_close (struct ghw_handler *h) +{ + if (h->stream) + { + if (h->stream_ispipe) + pclose (h->stream); + else + fclose (h->stream); + + h->stream = NULL; + } +} + +const char * +ghw_get_dir (int is_downto) +{ + return is_downto ? "downto" : "to"; +} + +void +ghw_disp_range (union ghw_type *type, union ghw_range *rng) +{ + switch (rng->kind) + { + case ghdl_rtik_type_b2: + printf ("%s %s %s", ghw_get_lit (type, rng->b2.left), + ghw_get_dir (rng->b2.dir), ghw_get_lit (type, rng->b2.right)); + break; + case ghdl_rtik_type_e8: + printf ("%s %s %s", ghw_get_lit (type, rng->e8.left), + ghw_get_dir (rng->e8.dir), ghw_get_lit (type, rng->e8.right)); + break; + case ghdl_rtik_type_i32: + case ghdl_rtik_type_p32: + printf (GHWPRI32 " %s " GHWPRI32, rng->i32.left, + ghw_get_dir (rng->i32.dir), rng->i32.right); + break; + case ghdl_rtik_type_i64: + case ghdl_rtik_type_p64: + printf (GHWPRI64 " %s " GHWPRI64, rng->i64.left, + ghw_get_dir (rng->i64.dir), rng->i64.right); + break; + case ghdl_rtik_type_f64: + printf ("%g %s %g", rng->f64.left, ghw_get_dir (rng->f64.dir), + rng->f64.right); + break; + default: + printf ("?(%d)", rng->kind); + } +} + +static void +ghw_disp_array_subtype_bounds (struct ghw_subtype_array *a) +{ + unsigned i; + struct ghw_type_array *base = + (struct ghw_type_array *) ghw_get_base_type (a->base); + + printf (" ("); + for (i = 0; i < base->nbr_dim; i++) + { + if (i != 0) + printf (", "); + ghw_disp_range (base->dims[i], a->rngs[i]); + } + printf (")"); +} + +static void +ghw_disp_record_subtype_bounds (struct ghw_subtype_record *sr) +{ + struct ghw_type_record *base = sr->base; + int is_first = 1; + unsigned i; + + for (i = 0; i < base->nbr_fields; i++) + { + if (sr->els[i].type != base->els[i].type) + { + if (is_first) + { + printf ("("); + is_first = 0; + } + else + printf (", "); + printf ("%s", base->els[i].name); + switch (sr->els[i].type->kind) + { + case ghdl_rtik_subtype_array: + ghw_disp_array_subtype_bounds (&sr->els[i].type->sa); + break; + case ghdl_rtik_subtype_record: + ghw_disp_record_subtype_bounds (&sr->els[i].type->sr); + break; + default: + printf ("??? (%d)", sr->els[i].type->kind); + } + } + } + if (!is_first) + printf (")"); +} + +static void +ghw_disp_subtype_definition (struct ghw_handler *h, union ghw_type *t) +{ + switch (t->kind) + { + case ghdl_rtik_subtype_scalar: + { + struct ghw_subtype_scalar *s = &t->ss; + ghw_disp_typename (h, s->base); + printf (" range "); + ghw_disp_range (s->base, s->rng); + } break; + case ghdl_rtik_subtype_array: + { + struct ghw_subtype_array *a = &t->sa; + + ghw_disp_typename (h, (union ghw_type *) a->base); + ghw_disp_array_subtype_bounds (a); + } break; + case ghdl_rtik_subtype_record: + { + struct ghw_subtype_record *sr = &t->sr; + + ghw_disp_typename (h, (union ghw_type *) sr->base); + ghw_disp_record_subtype_bounds (sr); + } break; + case ghdl_rtik_subtype_unbounded_array: + case ghdl_rtik_subtype_unbounded_record: + { + struct ghw_subtype_unbounded_record *sur = &t->sur; + + ghw_disp_typename (h, (union ghw_type *) sur->base); + } break; + default: + printf ("ghw_disp_subtype_definition: unhandled type kind %d\n", + t->kind); + } +} + +static int +ghw_is_anonymous_type (struct ghw_handler *h, union ghw_type *t) +{ + return t->common.name == h->str_table[0]; +} + +void +ghw_disp_subtype_indication (struct ghw_handler *h, union ghw_type *t) +{ + if (ghw_is_anonymous_type (h, t)) + { + /* Anonymous subtype. */ + ghw_disp_subtype_definition (h, t); + } + else + ghw_disp_typename (h, t); +} + +void +ghw_disp_type (struct ghw_handler *h, union ghw_type *t) +{ + switch (t->kind) + { + case ghdl_rtik_type_b2: + case ghdl_rtik_type_e8: + { + struct ghw_type_enum *e = &t->en; + uint32_t i; + + printf ("type %s is (", e->name); + for (i = 0; i < e->nbr; i++) + { + if (i != 0) + printf (", "); + printf ("%s", ghw_get_lit(t, i)); + } + printf (");"); + if (e->wkt != ghw_wkt_unknown) + printf (" -- WKT:%d", e->wkt); + printf ("\n"); + } + break; + case ghdl_rtik_type_i32: + case ghdl_rtik_type_f64: + { + struct ghw_type_scalar *s = &t->sc; + printf ("type %s is range <>;\n", s->name); + } break; + case ghdl_rtik_type_p32: + case ghdl_rtik_type_p64: + { + unsigned i; + + struct ghw_type_physical *p = &t->ph; + printf ("type %s is range <> units\n", p->name); + for (i = 0; i < p->nbr_units; i++) + { + struct ghw_unit *u = &p->units[i]; + printf (" %s = " GHWPRI64 " %s;\n", u->name, u->val, + p->units[0].name); + } + printf ("end units;\n"); + } break; + case ghdl_rtik_type_array: + { + struct ghw_type_array *a = &t->ar; + unsigned i; + + printf ("type %s is array (", a->name); + for (i = 0; i < a->nbr_dim; i++) + { + if (i != 0) + printf (", "); + ghw_disp_typename (h, a->dims[i]); + printf (" range <>"); + } + printf (") of "); + ghw_disp_subtype_indication (h, a->el); + printf (";\n"); + } + break; + case ghdl_rtik_type_record: + { + struct ghw_type_record *r = &t->rec; + unsigned i; + + printf ("type %s is record\n", r->name); + for (i = 0; i < r->nbr_fields; i++) + { + printf (" %s: ", r->els[i].name); + ghw_disp_subtype_indication (h, r->els[i].type); + printf (";\n"); + } + printf ("end record;\n"); + } + break; + case ghdl_rtik_subtype_array: + case ghdl_rtik_subtype_scalar: + case ghdl_rtik_subtype_record: + case ghdl_rtik_subtype_unbounded_array: + case ghdl_rtik_subtype_unbounded_record: + { + struct ghw_type_common *c = &t->common; + printf ("subtype %s is ", c->name); + ghw_disp_subtype_definition (h, t); + printf (";\n"); + } break; + default: + printf ("ghw_disp_type: unhandled type kind %d\n", t->kind); + } +} + +void +ghw_disp_types (struct ghw_handler *h) +{ + uint32_t i; + + for (i = 0; i < h->nbr_types; i++) + if (h->types[i] != NULL && + (h->flag_verbose || !ghw_is_anonymous_type (h, h->types[i]))) + ghw_disp_type (h, ghw_get_typeid(h, i+1)); // pass i+1 to access index i +} diff --git a/ext/ghw/libghw.h b/ext/ghw/libghw.h new file mode 100644 index 0000000..ed0f407 --- /dev/null +++ b/ext/ghw/libghw.h @@ -0,0 +1,483 @@ +/* GHDL Wavefile reader library. + Copyright (C) 2005-2017 Tristan Gingold + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; If not, see . +*/ + +#ifndef _LIBGHW_H_ +#define _LIBGHW_H_ + +#include +#include + +/* To be libraries friendly. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The libghw uses the standard c99 int32_t and int64_t. They are declared + in stdint.h. Header inttypes.h includes stdint.h and provides macro for + printf and co specifiers. Use it if known to be available. */ + +#if defined(__cplusplus) || \ + defined(__linux__) || \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(HAVE_INTTYPES_H) +/* Use C99 standard header. */ +#include +#define GHWPRI64 "%" PRId64 +#define GHWPRI32 "%" PRId32 +#else +#include +#define GHWPRI64 "%lld" +#define GHWPRI32 "%d" +#endif + +enum ghdl_rtik +{ + ghdl_rtik_top, /* 0 */ + ghdl_rtik_library, + ghdl_rtik_package, + ghdl_rtik_package_body, + ghdl_rtik_entity, + ghdl_rtik_architecture, /* 5 */ + ghdl_rtik_process, + ghdl_rtik_block, + ghdl_rtik_if_generate, + ghdl_rtik_for_generate, + ghdl_rtik_instance, + ghdl_rtik_constant, + ghdl_rtik_iterator, + ghdl_rtik_variable, + ghdl_rtik_signal, + ghdl_rtik_file, + ghdl_rtik_port, + ghdl_rtik_generic, + ghdl_rtik_alias, + ghdl_rtik_guard, + ghdl_rtik_component, + ghdl_rtik_attribute, + ghdl_rtik_type_b2, /* 22 */ + ghdl_rtik_type_e8, + ghdl_rtik_type_e32, + ghdl_rtik_type_i32, /* 25 */ + ghdl_rtik_type_i64, + ghdl_rtik_type_f64, + ghdl_rtik_type_p32, + ghdl_rtik_type_p64, + ghdl_rtik_type_access, /* 30 */ + ghdl_rtik_type_array, + ghdl_rtik_type_record, + ghdl_rtik_type_file, + ghdl_rtik_subtype_scalar, + ghdl_rtik_subtype_array, /* 35 */ + ghdl_rtik_subtype_array_ptr, /* Obsolete. */ + ghdl_rtik_subtype_unbounded_array, + ghdl_rtik_subtype_record, + ghdl_rtik_subtype_unbounded_record, +#if 0 + ghdl_rtik_subtype_access, /* 40 */ + ghdl_rtik_type_protected, + ghdl_rtik_element, + ghdl_rtik_unit, + ghdl_rtik_attribute_transaction, + ghdl_rtik_attribute_quiet, + ghdl_rtik_attribute_stable, +#endif + ghdl_rtik_error +}; + +/* Well-known types. */ +enum ghw_wkt_type +{ + ghw_wkt_unknown, + ghw_wkt_boolean, + ghw_wkt_bit, + ghw_wkt_std_ulogic +}; + +struct ghw_range_b2 +{ + enum ghdl_rtik kind:8; + int dir:8; /* 0: to, !0: downto. */ + unsigned char left; + unsigned char right; +}; + +struct ghw_range_e8 +{ + enum ghdl_rtik kind:8; + int dir:8; /* 0: to, !0: downto. */ + unsigned char left; + unsigned char right; +}; + +struct ghw_range_i32 +{ + enum ghdl_rtik kind:8; + int dir:8; /* 0: to, !0: downto. */ + int32_t left; + int32_t right; +}; + +struct ghw_range_i64 +{ + enum ghdl_rtik kind:8; + int dir:8; + int64_t left; + int64_t right; +}; + +struct ghw_range_f64 +{ + enum ghdl_rtik kind:8; + int dir:8; + double left; + double right; +}; + +union ghw_range +{ + enum ghdl_rtik kind:8; + struct ghw_range_b2 b2; + struct ghw_range_e8 e8; + struct ghw_range_i32 i32; + struct ghw_range_i64 i64; + struct ghw_range_f64 f64; +}; + +/* Note: the first two fields must be kind and name. */ +union ghw_type; + +struct ghw_type_common +{ + enum ghdl_rtik kind; + const char *name; +}; + +struct ghw_type_enum +{ + enum ghdl_rtik kind; + const char *name; + + enum ghw_wkt_type wkt; + uint32_t nbr; + const char **lits; +}; + +struct ghw_type_scalar +{ + enum ghdl_rtik kind; + const char *name; +}; + +struct ghw_unit +{ + const char *name; + int64_t val; +}; + +struct ghw_type_physical +{ + enum ghdl_rtik kind; + const char *name; + uint32_t nbr_units; + struct ghw_unit *units; +}; + +struct ghw_type_array +{ + enum ghdl_rtik kind; + const char *name; + + unsigned int nbr_dim; + union ghw_type *el; + union ghw_type **dims; +}; + +struct ghw_subtype_unbounded_array +{ + enum ghdl_rtik kind; + const char *name; + + union ghw_type *base; +}; + +struct ghw_subtype_array +{ + enum ghdl_rtik kind; + const char *name; + + union ghw_type *base; + int nbr_scalars; + union ghw_range **rngs; + union ghw_type *el; +}; + +struct ghw_subtype_scalar +{ + enum ghdl_rtik kind; + const char *name; + + union ghw_type *base; + union ghw_range *rng; +}; + +struct ghw_record_element +{ + const char *name; + union ghw_type *type; +}; + +struct ghw_type_record +{ + enum ghdl_rtik kind; + const char *name; + + unsigned int nbr_fields; + int nbr_scalars; /* Number of scalar elements (ie nbr of signals). */ + struct ghw_record_element *els; +}; + +struct ghw_subtype_record +{ + enum ghdl_rtik kind; + const char *name; + + struct ghw_type_record *base; + int nbr_scalars; /* Number of scalar elements (ie nbr of signals). */ + struct ghw_record_element *els; +}; + +struct ghw_subtype_unbounded_record +{ + enum ghdl_rtik kind; + const char *name; + + struct ghw_type_record *base; +}; + +union ghw_type +{ + enum ghdl_rtik kind; + struct ghw_type_common common; + struct ghw_type_enum en; + struct ghw_type_scalar sc; + struct ghw_type_physical ph; + struct ghw_subtype_scalar ss; + struct ghw_type_array ar; + struct ghw_type_record rec; + struct ghw_subtype_array sa; + struct ghw_subtype_unbounded_array sua; + struct ghw_subtype_record sr; + struct ghw_subtype_unbounded_record sur; +}; + +union ghw_val +{ + unsigned char b2; + unsigned char e8; + int32_t i32; + int64_t i64; + double f64; +}; + +/* A non-composite signal. */ +struct ghw_sig +{ + union ghw_type *type; + union ghw_val *val; +}; + +enum ghw_hie_kind +{ + ghw_hie_eoh = 0, + ghw_hie_design = 1, + ghw_hie_block = 3, + ghw_hie_generate_if = 4, + ghw_hie_generate_for = 5, + ghw_hie_instance = 6, + ghw_hie_package = 7, + ghw_hie_process = 13, + ghw_hie_generic = 14, + ghw_hie_eos = 15, + ghw_hie_signal = 16, + ghw_hie_port_in = 17, + ghw_hie_port_out = 18, + ghw_hie_port_inout = 19, + ghw_hie_port_buffer = 20, + ghw_hie_port_linkage = 21 +}; + +#define GHW_NO_SIG 0 + +struct ghw_hie +{ + enum ghw_hie_kind kind; + struct ghw_hie *parent; + const char *name; + struct ghw_hie *brother; + union + { + struct + { + struct ghw_hie *child; + union ghw_type *iter_type; + union ghw_val *iter_value; + } blk; + struct + { + union ghw_type *type; + /* Array of signal elements. + Last element is GHW_NO_SIG (0). */ + unsigned int *sigs; + } sig; + } u; +}; + +struct ghw_handler +{ + FILE *stream; + /* True if STREAM was popen, else was fopen. */ + unsigned char stream_ispipe; + /* True if words are big-endian. */ + unsigned char word_be; + unsigned char word_len; + unsigned char off_len; + /* Minor version. */ + int version; + + /* Set by user. */ + int flag_verbose; + + /* String table. */ + /* Number of strings. */ + uint32_t nbr_str; + /* Size of the strings (without nul). */ + uint32_t str_size; + /* String table. */ + char **str_table; + /* Array containing strings. */ + char *str_content; + + /* Type table. */ + uint32_t nbr_types; + union ghw_type **types; + + /* Non-composite (or basic) signals. */ + uint32_t nbr_sigs; + char *skip_sigs; + int flag_full_names; + struct ghw_sig *sigs; + /* 1: sigs does not contain any signals with type = NULL and index > 0 */ + int sigs_no_null; + + /* Hierarchy. */ + struct ghw_hie *hie; + + /* Time of the next cycle. */ + int64_t snap_time; +}; + +/* Open a GHW file with H. + Return < 0 in case of error. */ +int ghw_open (struct ghw_handler *h, const char *filename); + +/* Return base type of T. */ +union ghw_type *ghw_get_base_type (union ghw_type *t); + +/* Return length of RNG. */ +int ghw_get_range_length (union ghw_range *rng); + +/* Put the ASCII representation of VAL into BUF, whose size if LEN. + A NUL is always written to BUF. */ +void ghw_get_value (char *buf, int len, union ghw_val *val, + union ghw_type *type); + +const char *ghw_get_hie_name (struct ghw_hie *h); + +void ghw_disp_hie (struct ghw_handler *h, struct ghw_hie *top); + +int ghw_read_base (struct ghw_handler *h); + +void ghw_filter_signals (struct ghw_handler *h, int *signals_to_keep, + int nb_signals_to_keep); + +void ghw_disp_values (struct ghw_handler *h); + +int ghw_read_cycle_start (struct ghw_handler *h); + +int ghw_read_cycle_cont (struct ghw_handler *h, int *list); + +int ghw_read_cycle_next (struct ghw_handler *h); + +int ghw_read_cycle_end (struct ghw_handler *h); + +enum ghw_sm_type +{ + /* At init; + Read section name. */ + ghw_sm_init = 0, + ghw_sm_sect = 1, + ghw_sm_cycle = 2 +}; + +enum ghw_res +{ + ghw_res_error = -1, + ghw_res_eof = -2, + ghw_res_ok = 0, + ghw_res_snapshot = 1, + ghw_res_cycle = 2, + ghw_res_other = 3 +}; + +enum ghw_res ghw_read_sm_hdr (struct ghw_handler *h, int *list); + +int ghw_read_sm (struct ghw_handler *h, enum ghw_sm_type *sm); + +int ghw_read_dump (struct ghw_handler *h); + +struct ghw_section +{ + const char name[4]; + int (*handler) (struct ghw_handler * h); +}; + +extern struct ghw_section ghw_sections[]; + +int ghw_read_section (struct ghw_handler *h); + +void ghw_close (struct ghw_handler *h); + +const char *ghw_get_dir (int is_downto); + +void ghw_disp_subtype_indication (struct ghw_handler *h, union ghw_type *t); + +/* Note: TYPE must be a base type (used only to display literals). */ +void ghw_disp_range (union ghw_type *type, union ghw_range *rng); + +void ghw_disp_type (struct ghw_handler *h, union ghw_type *t); + +void ghw_disp_types (struct ghw_handler *h); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBGHW_H_ */