• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 13741295555

08 Mar 2025 07:54PM UTC coverage: 92.319% (+0.08%) from 92.236%
13741295555

push

github

nickg
Pass mir_context_t around explicitly

33 of 38 new or added lines in 3 files covered. (86.84%)

542 existing lines in 5 files now uncovered.

68074 of 73738 relevant lines covered (92.32%)

433184.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.79
/src/nvc.c
1
//
2
//  Copyright (C) 2011-2025  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "common.h"
20
#include "cov/cov-api.h"
21
#include "diag.h"
22
#include "jit/jit-llvm.h"
23
#include "jit/jit.h"
24
#include "lib.h"
25
#include "lower.h"
26
#include "mir/mir-unit.h"
27
#include "option.h"
28
#include "phase.h"
29
#include "rt/assert.h"
30
#include "rt/model.h"
31
#include "rt/mspace.h"
32
#include "rt/rt.h"
33
#include "rt/shell.h"
34
#include "rt/wave.h"
35
#include "scan.h"
36
#include "server.h"
37
#include "thread.h"
38
#include "vhpi/vhpi-util.h"
39
#include "vlog/vlog-node.h"
40
#include "vlog/vlog-phase.h"
41
#include "vpi/vpi-model.h"
42

43
#include <getopt.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <ctype.h>
47
#include <assert.h>
48
#include <sys/types.h>
49
#include <limits.h>
50
#include <unistd.h>
51
#include <dirent.h>
52
#include <time.h>
53

54
#if HAVE_GIT_SHA
55
#include "gitsha.h"
56
#define GIT_SHA_ONLY(x) x
57
#else
58
#define GIT_SHA_ONLY(x)
59
#endif
60

61
#if !defined HAVE_LLVM || !defined SYSTEM_CC
62
#define DEFAULT_JIT true
63
#else
64
#define DEFAULT_JIT false
65
#endif
66

67
typedef struct {
68
   jit_t           *jit;
69
   unit_registry_t *registry;
70
   mir_context_t   *mir;
71
   bool             user_set_std;
72
   vhpi_context_t  *vhpi;
73
   vpi_context_t   *vpi;
74
   const char      *plugins;
75
   rt_model_t      *model;
76
   cover_data_t    *cover;
77
   ident_t          top_level;
78
   const char      *top_level_arg;
79
   lib_t            work;
80
} cmd_state_t;
81

82
const char copy_string[] =
83
   "Copyright (C) 2011-2025  Nick Gasson\n"
84
   "This program comes with ABSOLUTELY NO WARRANTY. This is free software, "
85
   "and\nyou are welcome to redistribute it under certain conditions. See "
86
   "the GNU\nGeneral Public Licence for details.";
87
const char version_string[] =
88
   PACKAGE_STRING GIT_SHA_ONLY(" (" GIT_SHA ")")
89
   LLVM_ONLY(" (Using LLVM " LLVM_VERSION ")") DEBUG_ONLY(" [debug]");
90

91
static int process_command(int argc, char **argv, cmd_state_t *state);
92
static int parse_int(const char *str);
93
static jit_t *get_jit(unit_registry_t *ur, mir_context_t *mc);
94

95
static ident_t to_unit_name(const char *str)
6,536✔
96
{
97
   char *name LOCAL = xstrdup(str);
13,069✔
98
   for (char *p = name; *p; p++) {
51,613✔
99
      if (!isalnum_iso88591(*p) && (p == name || (*p != '_' && *p != '-')))
45,080✔
100
         fatal("'%s' is not a valid design unit name", str);
3✔
101

102
      *p = toupper_iso88591(*p);
45,077✔
103
   }
104

105
   return ident_prefix(lib_name(lib_work()), ident_new(name), '.');
6,533✔
106
}
107

108
static int scan_cmd(int start, int argc, char **argv)
14,538✔
109
{
110
   const char *commands[] = {
14,538✔
111
      "-a", "-e", "-r", "-c", "--dump", "--make", "--syntax", "--list",
112
      "--init", "--install", "--print-deps", "--aotgen", "--do", "-i",
113
      "--cover-export", "--preprocess", "--gui", "--cover-merge",
114
      "--cover-report",
115
   };
116

117
   for (int i = start; i < argc; i++) {
38,304✔
118
      for (size_t j = 0; j < ARRAY_LEN(commands); j++) {
498,909✔
119
         if (commands[j][1] == '-') {
475,143✔
120
            if (strcmp(argv[i], commands[j]) == 0)
335,100✔
121
               return i;
195✔
122
         }
123
         else if (argv[i][0] == '-' && commands[j][1] == argv[i][1])
140,043✔
124
            return i;
10,218✔
125
      }
126
   }
127

128
   return argc;
129
}
130

131
static void bad_option(const char *what, char **argv)
6✔
132
{
133
   if (optopt == 0)
6✔
134
      fatal("unrecognised %s option $bold$%s$$", what, argv[optind - 1]);
3✔
135
   else
136
      fatal("unrecognised %s option $bold$-%c$$", what, optopt);
3✔
137
}
138

139
static void missing_argument(const char *what, char **argv)
3✔
140
{
141
   fatal("%s option $bold$%s$$ requires an argument", what, argv[optind - 1]);
3✔
142
}
143

144
static void parse_pp_define(char *optarg)
15✔
145
{
146
   char *eq = strchr(optarg, '=');
15✔
147
   if (eq == NULL)
15✔
148
      pp_defines_add(optarg, "");
6✔
149
   else {
150
      *eq = '\0';
9✔
151
      pp_defines_add(optarg, eq + 1);
9✔
152
   }
153
}
15✔
154

155
static void do_file_list(const char *file, jit_t *jit, unit_registry_t *ur)
9✔
156
{
157
   FILE *f;
9✔
158
   if (strcmp(file, "-") == 0)
9✔
159
      f = stdin;
3✔
160
   else if ((f = fopen(file, "r")) == NULL)
6✔
UNCOV
161
      fatal_errno("failed to open %s", file);
×
162

163
   char *line = NULL;
9✔
164
   size_t nchars, bufsz = 0;
9✔
165
   while ((nchars = getline(&line, &bufsz, f)) != -1) {
45✔
166
      char *stop = strpbrk(line, "\r\n#") ?: line + nchars;
36✔
167
      *stop = '\0';
36✔
168

169
      // Trim trailing whitespace
170
      while (stop > line && isspace_iso88591(*--stop))
63✔
171
         *stop = '\0';
27✔
172

173
      if (strlen(line) == 0)
36✔
174
         continue;
18✔
175

176
      analyse_file(line, jit, ur);
18✔
177
   }
178

179
   free(line);
9✔
180
   fclose(f);
9✔
181
}
9✔
182

183
static int analyse(int argc, char **argv, cmd_state_t *state)
3,526✔
184
{
185
   static struct option long_options[] = {
3,526✔
186
      { "bootstrap",       no_argument,       0, 'b' },
187
      { "error-limit",     required_argument, 0, 'l' },
188
      { "dump-vcode",      optional_argument, 0, 'v' },
189
      { "psl",             no_argument,       0, 'P' },
190
      { "relax",           required_argument, 0, 'X' },
191
      { "relaxed",         no_argument,       0, 'R' },
192
      { "define",          required_argument, 0, 'D' },
193
      { "files",           required_argument, 0, 'f' },
194
      { "check-synthesis", no_argument,       0, 's' },
195
      { "no-save",         no_argument,       0, 'N' },
196
      { "single-unit",     no_argument,       0, 'u' },
197
      { "preserve-case",   no_argument,       0, 'p' },
198
      { 0, 0, 0, 0 }
199
   };
200

201
   const int next_cmd = scan_cmd(2, argc, argv);
3,526✔
202
   int c, index = 0, error_limit = 20;
3,526✔
203
   const char *file_list = NULL;
3,526✔
204
   const char *spec = ":D:f:";
3,526✔
205
   bool no_save = false;
3,526✔
206

207
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
3,719✔
208
      switch (c) {
193✔
209
      case 0:
210
         // Set a flag
211
         break;
UNCOV
212
      case '?':
×
213
         bad_option("analysis", argv);
×
214
      case ':':
×
215
         missing_argument("analysis", argv);
×
216
      case 'b':
3✔
217
         opt_set_int(OPT_BOOTSTRAP, 1);
3✔
218
         break;
3✔
UNCOV
219
      case 'v':
×
220
         opt_set_str(OPT_DUMP_VCODE, optarg ?: "");
×
221
         break;
×
222
      case 'X':
6✔
223
         warnf("The $bold$--relax=$$ option is deprecated: use the combined "
6✔
224
               "$bold$--relaxed$$ option instead");
225
         opt_set_int(OPT_RELAXED, 1);
6✔
226
         break;
6✔
UNCOV
227
      case 'l':
×
228
         error_limit = parse_int(optarg);
×
229
         break;
×
230
      case 'P':
60✔
231
         opt_set_int(OPT_PSL_COMMENTS, 1);
60✔
232
         break;
60✔
233
      case 'R':
28✔
234
         opt_set_int(OPT_RELAXED, 1);
28✔
235
         break;
28✔
236
      case 'D':
9✔
237
         parse_pp_define(optarg);
9✔
238
         break;
9✔
239
      case 'f':
6✔
240
         file_list = optarg;
6✔
241
         break;
6✔
UNCOV
242
      case 's':
×
243
         opt_set_int(OPT_CHECK_SYNTHESIS, 1);
×
244
         break;
×
245
      case 'N':
3✔
246
         no_save = true;
3✔
247
         break;
3✔
248
      case 'u':
3✔
249
         opt_set_int(OPT_SINGLE_UNIT, 1);
3✔
250
         break;
3✔
251
      case 'p':
75✔
252
         opt_set_int(OPT_PRESERVE_CASE, 1);
75✔
253
         break;
75✔
UNCOV
254
      default:
×
255
         should_not_reach_here();
256
      }
257
   }
258

259
   set_error_limit(error_limit);
3,526✔
260

261
   if (state->mir == NULL)
3,526✔
262
      state->mir = mir_context_new();
3,526✔
263

264
   if (state->registry == NULL)
3,526✔
265
      state->registry = unit_registry_new();
3,526✔
266

267
   jit_t *jit = jit_new(state->registry, state->mir);
3,526✔
268

269
   if (file_list != NULL)
3,526✔
270
      do_file_list(file_list, jit, state->registry);
6✔
271

272
   for (int i = optind; i < next_cmd; i++) {
7,067✔
273
      if (argv[i][0] == '@')
3,544✔
274
         do_file_list(argv[i] + 1, jit, state->registry);
3✔
275
      else
276
         analyse_file(argv[i], jit, state->registry);
3,541✔
277
   }
278

279
   jit_free(jit);
3,523✔
280
   set_error_limit(0);
3,523✔
281

282
   if (error_count() > 0)
3,523✔
283
      return EXIT_FAILURE;
284

285
   if (!no_save)
3,523✔
286
      lib_save(state->work);
3,520✔
287

288
   if (error_count() > 0)
3,523✔
289
      return EXIT_FAILURE;   // May have errors saving library
290

291
   argc -= next_cmd - 1;
3,520✔
292
   argv += next_cmd - 1;
3,520✔
293

294
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3,520✔
295
}
296

297
static void parse_generic(const char *str)
51✔
298
{
299
   char *copy LOCAL = xstrdup(str);
102✔
300

301
   char *split = strchr(copy, '=');
51✔
302
   if (split == NULL || *(split + 1) == '\0' || *copy == '\0')
51✔
UNCOV
303
      fatal("invalid generic specification '%s' (use -gNAME=VALUE)", str);
×
304

305
   *split = '\0';
51✔
306

307
   for (char *p = copy; *p != '\0'; p++)
222✔
308
      *p = toupper_iso88591(*p);
171✔
309

310
   elab_set_generic(copy, split + 1);
51✔
311
}
51✔
312

313
static void set_top_level(char **argv, int next_cmd, cmd_state_t *state)
6,665✔
314
{
315
   if (optind == next_cmd) {
6,665✔
316
      if (state->top_level == NULL)
141✔
UNCOV
317
         fatal("missing top-level unit name");
×
318
   }
319
   else if (optind != next_cmd - 1)
6,524✔
UNCOV
320
      fatal("excess positional argument '%s' following top-level unit name",
×
UNCOV
321
            argv[optind + 1]);
×
322
   else {
323
      state->top_level_arg = argv[optind];
6,524✔
324
      state->top_level = to_unit_name(argv[optind]);
6,524✔
325
   }
326
}
6,662✔
327

328
static void parse_cover_options(const char *str, cover_mask_t *mask,
93✔
329
                                int *array_limit, int *threshold)
330
{
331
   static const struct {
93✔
332
      const char *name;
333
      cover_mask_t mask;
334
   } options[] = {
335
      { "statement",             COVER_MASK_STMT                        },
336
      { "toggle",                COVER_MASK_TOGGLE                      },
337
      { "branch",                COVER_MASK_BRANCH                      },
338
      { "expression",            COVER_MASK_EXPRESSION                  },
339
      { "fsm-state",             COVER_MASK_STATE                       },
340
      { "functional",            COVER_MASK_FUNCTIONAL                  },
341
      { "all",                   COVER_MASK_ALL                         },
342
      { "count-from-undefined",  COVER_MASK_TOGGLE_COUNT_FROM_UNDEFINED },
343
      { "count-from-to-z",       COVER_MASK_TOGGLE_COUNT_FROM_TO_Z      },
344
      { "include-mems",          COVER_MASK_TOGGLE_INCLUDE_MEMS         },
345
      { "exclude-unreachable",   COVER_MASK_EXCLUDE_UNREACHABLE         },
346
      { "fsm-no-default-enums",  COVER_MASK_FSM_NO_DEFAULT_ENUMS        }
347
   };
348

349
   for (const char *start = str; ; str++) {
1,203✔
350
      if (*str == ',' || *str == '\0') {
1,203✔
351
         if (strncmp(start, "ignore-arrays-from-", 19) == 0)
123✔
UNCOV
352
            *array_limit = parse_int(start + 19);
×
353
         else if (strncmp(start, "threshold-", 10) == 0)
123✔
UNCOV
354
            *threshold = parse_int(start + 10);
×
355
         else {
356
            int pos = 0;
357
            for (; pos < ARRAY_LEN(options); pos++) {
573✔
358
               if (!strncmp(options[pos].name, start, str - start))
573✔
359
                  break;
360
            }
361

362
            if (pos == ARRAY_LEN(options)) {
123✔
UNCOV
363
               diag_t *d = diag_new(DIAG_FATAL, NULL);
×
UNCOV
364
               diag_printf(d, "unknown coverage type '%.*s'",
×
UNCOV
365
                           (int)(str - start), start);
×
366
               diag_hint(d, NULL, "valid coverage types are: statement, "
×
367
                         "toggle, branch, and expression");
368
               diag_hint(d, NULL, "selected coverage types should be "
×
369
                         "comma separated e.g $bold$--cover=toggle,branch$$");
UNCOV
370
               diag_emit(d);
×
371
               fatal_exit(EXIT_FAILURE);
×
372
            }
373
            else
374
               *mask |= options[pos].mask;
123✔
375
         }
376

377
         if (*str == '\0')
123✔
378
            break;
379

380
         start = str + 1;
30✔
381
      }
382
   }
383
}
93✔
384

385
static int parse_optimise_level(const char *str)
3,164✔
386
{
387
   char *eptr;
3,164✔
388
   const int level = strtoul(optarg, &eptr, 10);
3,164✔
389
   if (level > 3 || *eptr != '\0')
3,164✔
UNCOV
390
      fatal("invalid optimisation level %s", optarg);
×
391
   return level;
3,164✔
392
}
393

394
static int elaborate(int argc, char **argv, cmd_state_t *state)
3,349✔
395
{
396
   static struct option long_options[] = {
3,349✔
397
      { "dump-llvm",       no_argument,       0, 'd' },
398
      { "dump-vcode",      optional_argument, 0, 'v' },
399
      { "cover",           optional_argument, 0, 'c' },
400
      { "cover-file",      required_argument, 0, 'F' },
401
      { "cover-spec",      required_argument, 0, 's' },
402
      { "sdf",             required_argument, 0, 'f' },
403
      { "verbose",         no_argument,       0, 'V' },
404
      { "no-save",         no_argument,       0, 'N' },
405
      { "jit",             no_argument,       0, 'j' },
406
      { "no-collapse",     no_argument,       0, 'C' },
407
      { "trace",           no_argument,       0, 't' },
408
      { 0, 0, 0, 0 }
409
   };
410

411
   bool use_jit = DEFAULT_JIT, no_save = false;
3,349✔
412
   unit_meta_t meta = {};
3,349✔
413
   cover_mask_t cover_mask = 0;
3,349✔
414
   const char *cover_spec_file = NULL, *sdf_args = NULL;
3,349✔
415
   int cover_array_limit = 0;
3,349✔
416
   int threshold = 1;
3,349✔
417
   const int next_cmd = scan_cmd(2, argc, argv);
3,349✔
418
   int c, index = 0;
3,349✔
419
   const char *spec = ":Vg:O:jt";
3,349✔
420
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
11,690✔
421
      switch (c) {
8,341✔
422
      case 'O':
3,161✔
423
         opt_set_int(OPT_OPTIMISE, parse_optimise_level(optarg));
3,161✔
424
         break;
3,161✔
UNCOV
425
      case 'd':
×
UNCOV
426
         opt_set_int(OPT_DUMP_LLVM, 1);
×
UNCOV
427
         break;
×
428
      case 'v':
×
429
         opt_set_str(OPT_DUMP_VCODE, optarg ?: "");
×
430
         break;
×
431
      case 'c':
120✔
432
         if (optarg)
120✔
433
            parse_cover_options(optarg, &(cover_mask), &(cover_array_limit),
93✔
434
                                &(threshold));
435
         else
436
            cover_mask = COVER_MASK_ALL;
27✔
437
         break;
UNCOV
438
      case 'V':
×
UNCOV
439
         opt_set_int(OPT_VERBOSE, 1);
×
UNCOV
440
         break;
×
441
      case 'N':
2,848✔
442
         opt_set_int(OPT_NO_SAVE, 1);
2,848✔
443
         no_save = true;
2,848✔
444
         break;
2,848✔
445
      case 'C':
3✔
446
         opt_set_int(OPT_NO_COLLAPSE, 1);
3✔
447
         break;
3✔
448
      case 'j':
2,122✔
449
         use_jit = true;
2,122✔
450
         break;
2,122✔
451
      case 'g':
51✔
452
         parse_generic(optarg);
51✔
453
         break;
51✔
454
      case 's':
6✔
455
         cover_spec_file = optarg;
6✔
456
         break;
6✔
457
      case 'F':
30✔
458
         meta.cover_file = optarg;
30✔
459
         break;
30✔
UNCOV
460
      case 'f':
×
UNCOV
461
         sdf_args = optarg;
×
UNCOV
462
         break;
×
463
      case 't':
×
464
         opt_set_int(OPT_RT_TRACE, 1);
×
465
         break;
×
466
      case 0:
467
         // Set a flag
468
         break;
UNCOV
469
      case '?':
×
UNCOV
470
         bad_option("elaboration", argv);
×
UNCOV
471
      case ':':
×
472
         missing_argument("elaboration", argv);
×
473
      default:
×
474
         should_not_reach_here();
475
      }
476
   }
477

478
   set_top_level(argv, next_cmd, state);
3,349✔
479

480
   progress("initialising");
3,346✔
481

482
   object_t *obj = lib_get_generic(state->work, state->top_level, NULL);
3,346✔
483
   if (obj == NULL)
3,340✔
UNCOV
484
      fatal("cannot find unit %s in library %s",
×
485
            istr(state->top_level), istr(lib_name(state->work)));
486

487
   progress("loading top-level unit");
3,340✔
488

489
   char *cover_default LOCAL = NULL;
6,674✔
490
   cover_data_t *cover = NULL;
3,340✔
491
   if (cover_mask != 0) {
3,340✔
492
      cover = cover_data_init(cover_mask, cover_array_limit, threshold);
120✔
493

494
      if (cover_spec_file != NULL)
120✔
495
         cover_load_spec_file(cover, cover_spec_file);
6✔
496

497
      if (meta.cover_file == NULL) {
120✔
498
         cover_default = xasprintf("%s.ncdb", state->top_level_arg);
90✔
499
         meta.cover_file = cover_default;
90✔
500
      }
501
   }
502

503
   if (sdf_args != NULL) {
3,340✔
504
      // TODO: Pass min-max spec to underlying sdf_parse somehow
UNCOV
505
      analyse_file(sdf_args, NULL, NULL);
×
506
   }
507

508
   if (state->model != NULL) {
3,340✔
UNCOV
509
      model_free(state->model);
×
UNCOV
510
      state->model = NULL;
×
511
   }
512

513
   if (state->jit != NULL) {
3,340✔
NEW
514
      jit_free(state->jit);
×
NEW
515
      state->jit = NULL;
×
516
   }
517

518
   if (state->registry != NULL) {
3,340✔
519
      unit_registry_free(state->registry);
3,269✔
520
      state->registry = NULL;
3,269✔
521
   }
522

523
   if (state->mir != NULL) {
3,340✔
524
      mir_context_free(state->mir);
3,269✔
525
      state->mir = NULL;
3,269✔
526
   }
527

528
   state->mir = mir_context_new();
3,340✔
529
   state->registry = unit_registry_new();
3,340✔
530
   state->jit = get_jit(state->registry, state->mir);
3,340✔
531
   state->model = model_new(state->jit, cover);
3,340✔
532

533
   if (state->vhpi == NULL)
3,340✔
534
      state->vhpi = vhpi_context_new();
3,265✔
535

536
   tree_t top = elab(obj, state->jit, state->registry, cover,
3,340✔
537
                     NULL, state->model);
538

539
   if (top == NULL)
3,337✔
540
      return EXIT_FAILURE;
541

542
   lib_put_meta(state->work, top, &meta);
3,337✔
543

544
   progress("elaborating design");
3,337✔
545

546
   if (cover != NULL) {
3,337✔
547
      fbuf_t *covdb = fbuf_open(meta.cover_file, FBUF_OUT, FBUF_CS_NONE);
120✔
548
      cover_dump_items(cover, covdb, COV_DUMP_ELAB, NULL);
120✔
549
      fbuf_close(covdb, NULL);
120✔
550

551
      progress("dumping coverage data");
120✔
552
   }
553

554
   if (error_count() > 0)
3,337✔
555
      return EXIT_FAILURE;
556

557
   char *pack_name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
6,671✔
558
   char *dll_name LOCAL = xasprintf("_%s." DLL_EXT, istr(tree_ident(top)));
6,671✔
559

560
   // Delete any existing generated code to avoid accidentally loading
561
   // the wrong version later
562
   lib_delete(state->work, pack_name);
3,337✔
563
   lib_delete(state->work, dll_name);
3,337✔
564

565
   if (!no_save) {
3,337✔
566
      lib_save(state->work);
489✔
567
      progress("saving library");
489✔
568
   }
569

570
   if (use_jit && !no_save) {
3,337✔
571
      FILE *f = lib_fopen(state->work, pack_name, "wb");
235✔
572
      if (f == NULL)
235✔
UNCOV
573
         fatal_errno("fopen: %s", pack_name);
×
574

575
      ident_t b0 = tree_ident(tree_stmt(top, 0));
235✔
576
      ident_t root = ident_prefix(lib_name(state->work), b0, '.');
235✔
577

578
      vcode_unit_t vu = unit_registry_get(state->registry, root);
235✔
579
      assert(vu != NULL);
235✔
580

581
      jit_write_pack(state->jit, vu, f);
235✔
582
      fclose(f);
235✔
583

584
      progress("writing JIT pack");
235✔
585
   }
586

587
   if (!use_jit)
3,337✔
588
      LLVM_ONLY(cgen(top, state->registry, state->jit));
1,215✔
589

590
   if (!use_jit || cover != NULL) {
3,337✔
591
      // Must discard current JIT state to load AOT library later
592
      model_free(state->model);
1,244✔
593
      jit_free(state->jit);
1,244✔
594
      mir_context_free(state->mir);
1,244✔
595
      state->jit = NULL;
1,244✔
596
      state->model = NULL;
1,244✔
597
      state->mir = NULL;
1,244✔
598
   }
599

600
   argc -= next_cmd - 1;
3,337✔
601
   argv += next_cmd - 1;
3,337✔
602

603
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3,337✔
604
}
605

606
static uint64_t parse_time(const char *str)
16✔
607
{
608
   char     unit[4];
16✔
609
   unsigned base;
16✔
610
   uint64_t mult = 1;
16✔
611

612
   if (sscanf(str, "%u%3s", &base, unit) != 2)
16✔
UNCOV
613
      fatal("invalid time format: %s", str);
×
614

615
   if      (strcmp(unit, "fs") == 0)  mult = 1;
16✔
616
   else if (strcmp(unit, "ps") == 0)  mult = 1000;
16✔
617
   else if (strcmp(unit, "ns") == 0)  mult = 1000000;
16✔
618
   else if (strcmp(unit, "us") == 0)  mult = 1000000000;
6✔
UNCOV
619
   else if (strcmp(unit, "ms") == 0)  mult = 1000000000000;
×
UNCOV
620
   else if (strcmp(unit, "sec") == 0) mult = 1000000000000000;
×
621
   else
622
      fatal("invalid unit: %s", unit);
×
623

624
   return base * mult;
16✔
625
}
626

627
static int parse_int(const char *str)
12✔
628
{
629
   char *eptr = NULL;
12✔
630
   int n = strtol(str, &eptr, 0);
12✔
631
   if ((eptr == NULL) || (*eptr != '\0'))
12✔
UNCOV
632
      fatal("invalid integer: %s", str);
×
633
   return n;
12✔
634
}
635

636
static bool parse_on_off(const char *str)
6✔
637
{
638
   if (strcasecmp(str, "on") == 0)
6✔
639
      return true;
640
   else if (strcasecmp(str, "off") == 0)
3✔
641
      return false;
642

UNCOV
643
   fatal("specifiy 'on' or 'off' instead of '%s'", str);
×
644
}
645

646
static vhdl_severity_t parse_severity(const char *str)
6✔
647
{
648
   if (strcasecmp(str, "note") == 0)
6✔
649
      return SEVERITY_NOTE;
650
   else if (strcasecmp(str, "warning") == 0)
6✔
651
      return SEVERITY_WARNING;
652
   else if (strcasecmp(str, "error") == 0)
6✔
653
      return SEVERITY_ERROR;
654
   else if (strcasecmp(str, "failure") == 0)
6✔
655
      return SEVERITY_FAILURE;
656
   else
UNCOV
657
      fatal("invalid severity level: %s", str);
×
658
}
659

660
static void parse_exit_severity(const char *str)
3✔
661
{
662
   const vhdl_severity_t s = parse_severity(optarg);
3✔
663
   set_exit_severity(s);
3✔
664
   set_status_severity(s);
3✔
665
}
3✔
666

667
static int parse_stop_delta(const char *str)
6✔
668
{
669
   const int ival = parse_int(str);
6✔
670
   if (ival < 1)
6✔
671
      fatal("$bold$--stop-delta$$ argument must be greater than zero");
3✔
672
   else if (ival > DELTA_CYCLE_MAX) {
3✔
673
      warnf("the maxmimum number of supported delta cycles is %d",
3✔
674
            DELTA_CYCLE_MAX);
675
      return DELTA_CYCLE_MAX;
3✔
676
   }
677
   else
678
      return ival;
679
}
680

UNCOV
681
static void ctrl_c_handler(void *arg)
×
682
{
UNCOV
683
   rt_model_t *model = arg;
×
684
   model_interrupt(model);
×
UNCOV
685
}
×
686

687
static jit_t *get_jit(unit_registry_t *ur, mir_context_t *mc)
4,813✔
688
{
689
   jit_t *jit = jit_new(ur, mc);
4,813✔
690

691
#ifdef HAVE_LLVM
692
   jit_preload(jit);
4,813✔
693
#endif
694

695
#if defined HAVE_LLVM && 1
696
   jit_register_llvm_plugin(jit);
4,813✔
697
#elif defined ARCH_X86_64 && 0
698
   jit_register_native_plugin(jit);
699
#endif
700

701
   _std_standard_init();
4,813✔
702
   _std_env_init();
4,813✔
703
   _std_reflection_init();
4,813✔
704
   _file_io_init();
4,813✔
705
   _nvc_sim_pkg_init();
4,813✔
706

707
   return jit;
4,813✔
708
}
709

710
static int plusarg_cmp(const void *lptr, const void *rptr)
6✔
711
{
712
   const char *lstr = *(const char **)lptr;
6✔
713
   const char *rstr = *(const char **)rptr;
6✔
714

715
   if (lstr[0] == '+' && rstr[0] != '+')
6✔
716
      return -1;
UNCOV
717
   else if (lstr[0] != '+' && rstr[0] == '+')
×
718
      return 1;
719
   else
720
      return lptr - rptr;
×
721
}
722

723
static cover_data_t *load_coverage(const unit_meta_t *meta, jit_t *j)
3,316✔
724
{
725
   if (meta->cover_file == NULL)
3,316✔
726
      return NULL;
727

728
   fbuf_t *f = fbuf_open(meta->cover_file, FBUF_IN, FBUF_CS_NONE);
120✔
729
   if (f == NULL)
120✔
UNCOV
730
      fatal_errno("failed to open coverage database: %s", meta->cover_file);
×
731

732
   cover_data_t *db = cover_read_items(f, 0);
120✔
733

734
   // Pre-allocate coverage counters
735
   const int n_tags = cover_count_items(db);
120✔
736
   jit_get_cover_mem(j, n_tags);
120✔
737

738
   fbuf_close(f, NULL);
120✔
739
   return db;
120✔
740
}
741

742
static void emit_coverage(const unit_meta_t *meta, jit_t *j, cover_data_t *db)
120✔
743
{
744
   assert(meta->cover_file != NULL);
120✔
745

746
   fbuf_t *f = fbuf_open(meta->cover_file, FBUF_OUT, FBUF_CS_NONE);
120✔
747
   if (f == NULL)
120✔
UNCOV
748
      fatal_errno("failed to open coverage database: %s", meta->cover_file);
×
749

750
   const int n_tags = cover_count_items(db);
120✔
751
   const int32_t *counts = jit_get_cover_mem(j, n_tags);
120✔
752
   cover_dump_items(db, f, COV_DUMP_RUNTIME, counts);
120✔
753

754
   fbuf_close(f, NULL);
120✔
755
}
120✔
756

757
static int run_cmd(int argc, char **argv, cmd_state_t *state)
3,325✔
758
{
759
   static struct option long_options[] = {
3,325✔
760
      { "trace",         no_argument,       0, 't' },
761
      { "profile",       no_argument,       0, 'p' },   // DEPRECATED 1.14
762
      { "stop-time",     required_argument, 0, 's' },
763
      { "stats",         no_argument,       0, 'S' },
764
      { "wave",          optional_argument, 0, 'w' },
765
      { "stop-delta",    required_argument, 0, 'd' },
766
      { "format",        required_argument, 0, 'f' },
767
      { "include",       required_argument, 0, 'i' },
768
      { "ieee-warnings", required_argument, 0, 'I' },   // DEPRECATED 1.16
769
      { "exclude",       required_argument, 0, 'e' },
770
      { "exit-severity", required_argument, 0, 'x' },
771
      { "dump-arrays",   optional_argument, 0, 'a' },
772
      { "load",          required_argument, 0, 'l' },
773
      { "vhpi-debug",    no_argument,       0, 'D' },
774
      { "vhpi-trace",    no_argument,       0, 'T' },
775
      { "gtkw",          optional_argument, 0, 'g' },
776
      { "shuffle",       no_argument,       0, 'H' },
777
      { 0, 0, 0, 0 }
778
   };
779

780
   wave_format_t wave_fmt = WAVE_FORMAT_FST;
3,325✔
781
   uint64_t      stop_time = TIME_HIGH;
3,325✔
782
   const char   *wave_fname = NULL;
3,325✔
783
   const char   *gtkw_fname = NULL;
3,325✔
784
   const char   *pli_plugins = NULL;
3,325✔
785

786
   static bool have_run = false;
3,325✔
787
   if (have_run)
3,325✔
UNCOV
788
      fatal("multiple run commands are not supported");
×
789

790
   have_run = true;
3,325✔
791

792
   const int next_cmd = scan_cmd(2, argc, argv);
3,325✔
793

794
   int c, index = 0;
3,325✔
795
   const char *spec = ":w::l:gi";
3,325✔
796
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
3,506✔
797
      switch (c) {
190✔
798
      case 0:
799
         // Set a flag
800
         break;
801
      case '?':
3✔
802
         bad_option("run", argv);
3✔
803
      case ':':
3✔
804
         missing_argument("run", argv);
3✔
UNCOV
805
      case 't':
×
UNCOV
806
         opt_set_int(OPT_RT_TRACE, 1);
×
UNCOV
807
         break;
×
808
      case 'p':
×
809
         warnf("the $bold$--profile$$ option is deprecated and has no effect");
×
810
         break;
×
811
      case 'T':
×
812
         opt_set_str(OPT_PLI_TRACE, "1");
×
813
         opt_set_int(OPT_PLI_DEBUG, 1);
×
814
         break;
×
815
      case 'D':
×
816
         opt_set_int(OPT_PLI_DEBUG, 1);
×
817
         break;
×
818
      case 's':
16✔
819
         stop_time = parse_time(optarg);
16✔
820
         break;
16✔
UNCOV
821
      case 'f':
×
UNCOV
822
         if (strcmp(optarg, "vcd") == 0)
×
823
            wave_fmt = WAVE_FORMAT_VCD;
824
         else if (strcmp(optarg, "fst") == 0)
×
825
            wave_fmt = WAVE_FORMAT_FST;
826
         else
827
            fatal("invalid waveform format: %s", optarg);
×
828
         break;
829
      case 'S':
3✔
830
         opt_set_int(OPT_RT_STATS, 1);
3✔
831
         break;
3✔
832
      case 'w':
99✔
833
         if (optarg == NULL)
99✔
834
            wave_fname = "";
835
         else
UNCOV
836
            wave_fname = optarg;
×
837
         break;
838
      case 'g':
9✔
839
         if (optarg == NULL)
9✔
840
            gtkw_fname = "";
841
         else
UNCOV
842
            gtkw_fname = optarg;
×
843
         break;
844
      case 'd':
6✔
845
         opt_set_int(OPT_STOP_DELTA, parse_stop_delta(optarg));
6✔
846
         break;
3✔
847
      case 'i':
3✔
848
         wave_include_glob(optarg);
3✔
849
         break;
3✔
850
      case 'e':
3✔
851
         wave_exclude_glob(optarg);
3✔
852
         break;
3✔
UNCOV
853
      case 'l':
×
UNCOV
854
         pli_plugins = optarg;
×
UNCOV
855
         break;
×
856
      case 'x':
3✔
857
         parse_exit_severity(optarg);
3✔
858
         break;
3✔
UNCOV
859
      case 'I':
×
860
         {
UNCOV
861
            const bool on = parse_on_off(optarg);
×
862

863
            // TODO: add an unconditional warning after 1.16
864
            if (state->jit != NULL && opt_get_int(OPT_IEEE_WARNINGS) != on)
×
UNCOV
865
               warnf("the $bold$--ieee-warnings$$ option may have no affect "
×
866
                     "as the IEEE packages have already been initialised, pass "
867
                     "$bold$--ieee-warnings$$ as a global option instead");
868

UNCOV
869
            opt_set_int(OPT_IEEE_WARNINGS, on);
×
870
         }
UNCOV
871
         break;
×
872
      case 'a':
39✔
873
         if (optarg == NULL)
39✔
874
            opt_set_int(OPT_DUMP_ARRAYS, INT_MAX);
36✔
875
         else
876
            opt_set_int(OPT_DUMP_ARRAYS, parse_int(optarg));
3✔
877
         break;
878
      case 'H':
3✔
879
         warnf("the $bold$--shuffle$$ option is intended for debug use only "
3✔
880
               "and may introduce significant performance overhead as well "
881
               "as non-deterministic behaviour");
882
         opt_set_int(OPT_SHUFFLE_PROCS, 1);
3✔
883
         break;
3✔
UNCOV
884
      default:
×
885
         should_not_reach_here();
886
      }
887
   }
888

889
   // Shuffle the arguments to put all the plusargs first
890
   qsort(argv + optind, next_cmd - optind, sizeof(char *), plusarg_cmp);
3,316✔
891

892
   int nplusargs = 0;
3,316✔
893
   char **plusargs = argv + optind;
3,316✔
894
   for (int i = optind; i < next_cmd; i++) {
6,494✔
895
      if (argv[i][0] == '+')
3,178✔
896
         nplusargs++, optind++;
3✔
897
   }
898

899
   set_top_level(argv, next_cmd, state);
3,316✔
900

901
   ident_t ename = ident_prefix(state->top_level, well_known(W_ELAB), '.');
3,316✔
902

903
   const unit_meta_t *meta = NULL;
3,316✔
904
   object_t *obj = lib_get_generic(state->work, ename, &meta);
3,316✔
905
   if (obj == NULL)
3,316✔
UNCOV
906
      fatal("%s not elaborated", istr(state->top_level));
×
907

908
   tree_t top = tree_from_object(obj);
3,316✔
909
   assert(top != NULL);
3,316✔
910

911
   wave_dumper_t *dumper = NULL;
3,316✔
912
   if (wave_fname != NULL) {
3,316✔
913
      const char *name_map[] = { "FST", "VCD" };
96✔
914
      const char *ext_map[]  = { "fst", "vcd" };
96✔
915
      char *tmp LOCAL = NULL, *tmp2 LOCAL = NULL;
192✔
916

917
      if (*wave_fname == '\0') {
96✔
918
         tmp = xasprintf("%s.%s", state->top_level_arg, ext_map[wave_fmt]);
96✔
919
         wave_fname = tmp;
96✔
920
         notef("writing %s waveform data to %s", name_map[wave_fmt], tmp);
96✔
921
      }
922

923
      if (gtkw_fname != NULL && *gtkw_fname == '\0') {
96✔
924
         tmp2 = xasprintf("%s.gtkw", state->top_level_arg);
9✔
925
         gtkw_fname = tmp2;
9✔
926
      }
927

928
      wave_include_file(argv[optind]);
96✔
929
      dumper = wave_dumper_new(wave_fname, gtkw_fname, top, wave_fmt);
96✔
930
   }
931
   else if (gtkw_fname != NULL)
3,220✔
UNCOV
932
      warnf("$bold$--gtkw$$ option has no effect without $bold$--wave$$");
×
933

934
   if (opt_get_size(OPT_HEAP_SIZE) < 0x100000)
3,316✔
935
      warnf("recommended heap size is at least 1M");
×
936

937
   if (state->mir == NULL)
3,316✔
938
      state->mir = mir_context_new();
1,458✔
939

940
   if (state->registry == NULL)
3,316✔
941
      state->registry = unit_registry_new();
360✔
942

943
   if (state->jit == NULL)
3,316✔
944
      state->jit = get_jit(state->registry, state->mir);
1,458✔
945

946
#ifdef ENABLE_LLVM
947
   jit_load_dll(state->jit, tree_ident(top));
3,316✔
948
#endif
949

950
   char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
6,632✔
951
   FILE *f = lib_fopen(state->work, name, "rb");
3,316✔
952
   if (f != NULL) {
3,316✔
953
      jit_load_pack(state->jit, f);
235✔
954
      fclose(f);
235✔
955
   }
956

957
   if (state->cover == NULL)
3,316✔
958
      state->cover = load_coverage(meta, state->jit);
3,316✔
959

960
   if (state->model == NULL) {
3,316✔
961
      state->model = model_new(state->jit, state->cover);
1,458✔
962
      create_scope(state->model, top, NULL);
1,458✔
963
   }
964

965
   if (state->vhpi == NULL)
3,316✔
966
      state->vhpi = vhpi_context_new();
357✔
967

968
   if (state->vpi == NULL)
3,316✔
969
      state->vpi = vpi_context_new();
3,316✔
970

971
   if (pli_plugins != NULL || state->plugins != NULL) {
3,316✔
972
      vhpi_context_initialise(state->vhpi, top, state->model, state->jit,
75✔
973
                              nplusargs, plusargs);
974
      vpi_context_initialise(state->vpi, top, state->model, state->jit,
75✔
975
                             nplusargs, plusargs);
976
   }
977
   else if (nplusargs > 0)
3,241✔
UNCOV
978
      warnf("found plusargs on command line but no VHPI plugin was loaded");
×
979

980
   if (pli_plugins != NULL)
3,316✔
981
      vhpi_load_plugins(pli_plugins);
×
982

983
   set_ctrl_c_handler(ctrl_c_handler, state->model);
3,316✔
984

985
   model_reset(state->model);
3,316✔
986

987
   if (dumper != NULL)
3,316✔
988
      wave_dumper_restart(dumper, state->model, state->jit);
96✔
989

990
   model_run(state->model, stop_time);
3,316✔
991

992
   set_ctrl_c_handler(NULL, NULL);
3,316✔
993

994
   const int rc = model_exit_status(state->model);
3,316✔
995

996
   if (dumper != NULL)
3,316✔
997
      wave_dumper_free(dumper);
96✔
998

999
   if (state->cover != NULL)
3,316✔
1000
      emit_coverage(meta, state->jit, state->cover);
120✔
1001

1002
   vhpi_context_free(state->vhpi);
3,316✔
1003
   state->vhpi = NULL;
3,316✔
1004

1005
   vpi_context_free(state->vpi);
3,316✔
1006
   state->vpi = NULL;
3,316✔
1007

1008
   model_free(state->model);
3,316✔
1009
   state->model = NULL;
3,316✔
1010

1011
   argc -= next_cmd - 1;
3,316✔
1012
   argv += next_cmd - 1;
3,316✔
1013

1014
   return rc == 0 && argc > 1 ? process_command(argc, argv, state) : rc;
3,316✔
1015
}
1016

1017
static int print_deps_cmd(int argc, char **argv, cmd_state_t *state)
3✔
1018
{
1019
   static struct option long_options[] = {
3✔
1020
      { 0, 0, 0, 0 }
1021
   };
1022

1023
   opt_set_int(OPT_MAKE_DEPS_ONLY, 1);
3✔
1024

1025
   const int next_cmd = scan_cmd(2, argc, argv);
3✔
1026
   int c, index = 0;
3✔
1027
   const char *spec = ":";
3✔
1028
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
3✔
UNCOV
1029
      switch (c) {
×
1030
      case 0: break;  // Set a flag
UNCOV
1031
      case '?': bad_option("make", argv);
×
1032
      case ':': missing_argument("make", argv);
×
UNCOV
1033
      default: abort();
×
1034
      }
1035
   }
1036

1037
   const int count = next_cmd - optind;
3✔
1038
   tree_t *targets = NULL;
3✔
1039
   if (count > 0)
3✔
1040
      targets = xmalloc_array(count, sizeof(tree_t));
3✔
1041

1042
   for (int i = optind; i < next_cmd; i++) {
9✔
1043
      ident_t name = to_unit_name(argv[i]);
6✔
1044
      ident_t elab = ident_prefix(name, well_known(W_ELAB), '.');
6✔
1045
      if ((targets[i - optind] = lib_get(state->work, elab)) == NULL) {
6✔
1046
         if ((targets[i - optind] = lib_get(state->work, name)) == NULL)
6✔
UNCOV
1047
            fatal("cannot find unit %s in library %s",
×
1048
                  istr(name), istr(lib_name(state->work)));
1049
      }
1050
   }
1051

1052
   make(targets, count, stdout);
3✔
1053

1054
   argc -= next_cmd - 1;
3✔
1055
   argv += next_cmd - 1;
3✔
1056

1057
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3✔
1058
}
1059

UNCOV
1060
static int make_cmd(int argc, char **argv, cmd_state_t *state)
×
1061
{
UNCOV
1062
   static struct option long_options[] = {
×
1063
      { "deps-only", no_argument, 0, 'd' },
1064
      { "posix",     no_argument, 0, 'p' },
1065
      { 0, 0, 0, 0 }
1066
   };
1067

UNCOV
1068
   warnf("the $bold$--make$$ command is deprecated and may be repurposed in a "
×
1069
         "future release");
UNCOV
1070
   notef("use $bold$--print-deps$$ to print Makefile dependencies instead");
×
1071

UNCOV
1072
   const int next_cmd = scan_cmd(2, argc, argv);
×
1073
   int c, index = 0;
×
UNCOV
1074
   const char *spec = ":";
×
1075
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
×
UNCOV
1076
      switch (c) {
×
1077
      case 0:
1078
         // Set a flag
1079
         break;
1080
      case 'd':
×
1081
         opt_set_int(OPT_MAKE_DEPS_ONLY, 1);
×
UNCOV
1082
         break;
×
1083
      case 'p':
1084
         // Does nothing
1085
         break;
1086
      case '?':
×
1087
         bad_option("make", argv);
×
UNCOV
1088
      case ':':
×
UNCOV
1089
         missing_argument("make", argv);
×
UNCOV
1090
      default:
×
1091
         abort();
×
1092
      }
1093
   }
1094

1095
   const int count = next_cmd - optind;
×
1096
   tree_t *targets = xmalloc_array(count, sizeof(tree_t));
×
1097

UNCOV
1098
   for (int i = optind; i < next_cmd; i++) {
×
UNCOV
1099
      ident_t name = to_unit_name(argv[i]);
×
1100
      ident_t elab = ident_prefix(name, well_known(W_ELAB), '.');
×
1101
      if ((targets[i - optind] = lib_get(state->work, elab)) == NULL) {
×
UNCOV
1102
         if ((targets[i - optind] = lib_get(state->work, name)) == NULL)
×
1103
            fatal("cannot find unit %s in library %s",
×
1104
                  istr(name), istr(lib_name(state->work)));
1105
      }
1106
   }
1107

1108
   make(targets, count, stdout);
×
1109

1110
   argc -= next_cmd - 1;
×
UNCOV
1111
   argv += next_cmd - 1;
×
1112

UNCOV
1113
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
×
1114
}
1115

1116
static void list_walk_fn(lib_t lib, ident_t ident, int kind, void *context)
12✔
1117
{
1118
   const char *pretty = "???";
12✔
1119
   switch (kind) {
12✔
1120
   case T_ELAB: pretty = "Elaborated"; break;
×
UNCOV
1121
   case T_ARCH: pretty = "Architecture"; break;
×
1122
   case T_ENTITY: pretty = "Entity"; break;
3✔
1123
   case T_PACKAGE: pretty = "Package"; break;
3✔
UNCOV
1124
   case T_PACK_BODY: pretty = "Package body"; break;
×
1125
   case T_PACK_INST: pretty = "Instantiated package"; break;
3✔
UNCOV
1126
   case T_CONFIGURATION: pretty = "Configuration"; break;
×
1127
   case T_CONTEXT: pretty = "Context"; break;
3✔
1128
   }
1129

1130
   printf("%-30s  : %s\n", istr(ident), pretty);
12✔
1131
}
12✔
1132

1133
static int list_cmd(int argc, char **argv, cmd_state_t *state)
3✔
1134
{
1135
   static struct option long_options[] = {
3✔
1136
      { 0, 0, 0, 0 }
1137
   };
1138

1139
   const int next_cmd = scan_cmd(2, argc, argv);
3✔
1140
   int c, index = 0;
3✔
1141
   const char *spec = ":";
3✔
1142
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
3✔
UNCOV
1143
      switch (c) {
×
1144
      case 0:
1145
         // Set a flag
1146
         break;
UNCOV
1147
      case '?':
×
UNCOV
1148
         bad_option("list", argv);
×
UNCOV
1149
      case ':':
×
1150
         missing_argument("list", argv);
×
UNCOV
1151
      default:
×
UNCOV
1152
         abort();
×
1153
      }
1154
   }
1155

1156
   lib_walk_index(state->work, list_walk_fn, NULL);
3✔
1157

1158
   argc -= next_cmd - 1;
3✔
1159
   argv += next_cmd - 1;
3✔
1160

1161
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3✔
1162
}
1163

1164
static int init_cmd(int argc, char **argv, cmd_state_t *state)
9✔
1165
{
1166
   static struct option long_options[] = {
9✔
1167
      { 0, 0, 0, 0 }
1168
   };
1169

1170
   const int next_cmd = scan_cmd(2, argc, argv);
9✔
1171
   int c, index = 0;
9✔
1172
   const char *spec = ":";
9✔
1173
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
9✔
UNCOV
1174
      switch (c) {
×
1175
      case 0:
1176
         // Set a flag
1177
         break;
UNCOV
1178
      case '?':
×
UNCOV
1179
         bad_option("init", argv);
×
UNCOV
1180
      case ':':
×
1181
         missing_argument("init", argv);
×
1182
      }
1183
   }
1184

1185
   if (argc != optind)
9✔
1186
      fatal("$bold$--init$$ command takes no positional arguments");
3✔
1187

1188
   lib_save(state->work);
6✔
1189

1190
   argc -= next_cmd - 1;
6✔
1191
   argv += next_cmd - 1;
6✔
1192

1193
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
6✔
1194
}
1195

UNCOV
1196
static void list_packages(void)
×
1197
{
UNCOV
1198
   LOCAL_TEXT_BUF tb = tb_new();
×
UNCOV
1199
   get_libexec_dir(tb);
×
1200

UNCOV
1201
   DIR *dir = opendir(tb_get(tb));
×
UNCOV
1202
   tb_rewind(tb);
×
1203

UNCOV
1204
   if (dir != NULL) {
×
1205
      struct dirent *d;
1206
      while ((d = readdir(dir))) {
×
UNCOV
1207
         if (strncmp(d->d_name, "install-", 8))
×
1208
            continue;
×
1209

UNCOV
1210
         const char *dot = strrchr(d->d_name, '.');
×
1211
         if (dot == NULL)
×
UNCOV
1212
            continue;
×
1213

1214
         const int nchar = dot - d->d_name - 8;
×
1215
         tb_printf(tb, " %.*s", nchar, d->d_name + 8);
×
1216
      }
1217

1218
      closedir(dir);
×
1219
   }
1220

1221
   notef("the following packages can be installed:%s", tb_get(tb));
×
1222
}
×
1223

UNCOV
1224
static int install_cmd(int argc, char **argv, cmd_state_t *state)
×
1225
{
UNCOV
1226
   static struct option long_options[] = {
×
1227
      { "dest", required_argument, 0, 'd' },
1228
      { 0, 0, 0, 0 }
1229
   };
1230

1231
   const int next_cmd = scan_cmd(2, argc, argv);
×
UNCOV
1232
   int c, index = 0;
×
1233
   const char *spec = ":";
×
UNCOV
1234
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
×
UNCOV
1235
      switch (c) {
×
1236
      case 0:
1237
         // Set a flag
1238
         break;
1239
      case '?':
×
1240
         bad_option("install", argv);
×
1241
      case ':':
×
1242
         missing_argument("install", argv);
×
UNCOV
1243
      case 'd':
×
UNCOV
1244
         setenv("NVC_INSTALL_DEST", optarg , 1);
×
UNCOV
1245
         break;
×
1246
      }
1247
   }
1248

1249
   if (argc == optind) {
×
1250
      errorf("missing argument to $bold$--install$$ command");
×
1251
      list_packages();
×
1252
      return EXIT_FAILURE;
×
1253
   }
1254

UNCOV
1255
   LOCAL_TEXT_BUF tb = tb_new();
×
1256
   if (get_exe_path(tb))
×
1257
      setenv("NVC", tb_get(tb), 1);
×
1258

1259
   if (state->user_set_std)
×
UNCOV
1260
      setenv("NVC_STD", standard_text(standard()), 1);
×
1261

1262
   for (int i = optind; i < next_cmd; i++) {
×
1263
      tb_rewind(tb);
×
1264
      get_libexec_dir(tb);
×
UNCOV
1265
      tb_printf(tb, DIR_SEP "install-%s.sh", argv[i]);
×
1266

1267
      file_info_t info;
×
UNCOV
1268
      if (!get_file_info(tb_get(tb), &info) || info.type != FILE_REGULAR) {
×
1269
         errorf("%s is not an executable script", tb_get(tb));
×
1270
         list_packages();
×
1271
         return EXIT_FAILURE;
×
1272
      }
1273

1274
      const char *args[] = {
×
1275
#ifdef __MINGW32__
1276
         "bash",
1277
#endif
1278
         tb_get(tb),
×
1279
         NULL
1280
      };
1281
      run_program(args);
×
1282
   }
1283

UNCOV
1284
   argc -= next_cmd - 1;
×
1285
   argv += next_cmd - 1;
×
1286

UNCOV
1287
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
×
1288
}
1289

UNCOV
1290
static int syntax_cmd(int argc, char **argv, cmd_state_t *state)
×
1291
{
1292
   static struct option long_options[] = {
×
1293
      { 0, 0, 0, 0 }
1294
   };
1295

UNCOV
1296
   warnf("the $bold$--syntax$$ command is deprecated, use "
×
1297
         "$bold$-a --no-save$$ instead");
1298

1299
   const int next_cmd = scan_cmd(2, argc, argv);
×
UNCOV
1300
   int c, index = 0;
×
UNCOV
1301
   const char *spec = ":";
×
UNCOV
1302
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
×
1303
      switch (c) {
×
1304
      case 0:
1305
         // Set a flag
1306
         break;
1307
      case '?':
×
1308
         bad_option("syntax", argv);
×
1309
      case ':':
×
1310
         missing_argument("syntax", argv);
×
1311
      }
1312
   }
1313

1314
   for (int i = optind; i < next_cmd; i++) {
×
1315
      input_from_file(argv[i]);
×
1316
      while (parse())
×
1317
         ;
1318
   }
1319

UNCOV
1320
   if (error_count() > 0)
×
1321
      return EXIT_FAILURE;
1322

1323
   argc -= next_cmd - 1;
×
UNCOV
1324
   argv += next_cmd - 1;
×
1325

UNCOV
1326
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
×
1327
}
1328

UNCOV
1329
static void dump_one_unit(ident_t name, bool add_elab, bool add_body)
×
1330
{
1331
   if (add_elab)
×
UNCOV
1332
      name = ident_prefix(name, well_known(W_ELAB), '.');
×
1333
   else if (add_body)
×
UNCOV
1334
      name = ident_prefix(name, well_known(W_BODY), '-');
×
1335

1336
   tree_t top = lib_get(lib_work(), name);
×
UNCOV
1337
   if (top == NULL)
×
1338
      fatal("%s not analysed", istr(name));
×
1339

1340
   dump(top);
×
1341
}
×
1342

1343
static int dump_cmd(int argc, char **argv, cmd_state_t *state)
×
1344
{
1345
   static struct option long_options[] = {
×
1346
      { "elab", no_argument, 0, 'E' },
1347
      { "body", no_argument, 0, 'b' },
1348
      { 0, 0, 0, 0 }
1349
   };
1350

UNCOV
1351
   const int next_cmd = scan_cmd(2, argc, argv);
×
1352
   bool add_elab = false, add_body = false;
×
UNCOV
1353
   int c, index = 0;
×
UNCOV
1354
   const char *spec = ":Eb";
×
UNCOV
1355
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
×
UNCOV
1356
      switch (c) {
×
1357
      case 0:
1358
         // Set a flag
1359
         break;
1360
      case '?':
×
1361
         bad_option("dump", argv);
×
1362
      case ':':
×
1363
         missing_argument("dump", argv);
×
1364
      case 'E':
1365
         add_elab = true;
1366
         break;
1367
      case 'b':
×
1368
         add_body = true;
×
1369
         break;
×
1370
      default:
×
UNCOV
1371
         abort();
×
1372
      }
1373
   }
1374

1375
   if (optind == next_cmd) {
×
1376
      if (state->top_level == NULL)
×
1377
         fatal("missing top-level unit name");
×
1378
      else
UNCOV
1379
         dump_one_unit(state->top_level, add_elab, add_body);
×
1380
   }
1381
   else {
1382
      for (int i = optind; i < next_cmd; i++)
×
1383
         dump_one_unit(to_unit_name(argv[i]), add_elab, add_body);
×
1384
   }
1385

1386
   argc -= next_cmd - 1;
×
UNCOV
1387
   argv += next_cmd - 1;
×
1388

1389
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
×
1390
}
1391

1392
#if ENABLE_LLVM
1393
static int aotgen_cmd(int argc, char **argv, cmd_state_t *state)
3✔
1394
{
1395
   static struct option long_options[] = {
3✔
1396
      { 0, 0, 0, 0 }
1397
   };
1398

1399
   const char *outfile = "preload." DLL_EXT;
3✔
1400

1401
   const int next_cmd = scan_cmd(2, argc, argv);
3✔
1402
   int c, index = 0;
3✔
1403
   const char *spec = ":o:VO:";
3✔
1404
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
9✔
1405
      switch (c) {
6✔
1406
      case 0: break;  // Set a flag
UNCOV
1407
      case 'V':
×
UNCOV
1408
         opt_set_int(OPT_VERBOSE, 1);
×
UNCOV
1409
         break;
×
1410
      case 'O':
3✔
1411
         opt_set_int(OPT_OPTIMISE, parse_optimise_level(optarg));
3✔
1412
         break;
3✔
1413
      case 'o': outfile = optarg; break;
3✔
1414
      case '?': bad_option("aotgen", argv);
×
1415
      case ':': missing_argument("aotgen", argv);
×
1416
      default: abort();
×
1417
      }
1418
   }
1419

1420
   const int count = next_cmd - optind;
3✔
1421
   aotgen(outfile, argv + optind, count);
3✔
1422

1423
   argc -= next_cmd - 1;
3✔
1424
   argv += next_cmd - 1;
3✔
1425

1426
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3✔
1427
}
1428
#else
1429
static int aotgen_cmd(int argc, char **argv, cmd_state_t *state)
1430
{
1431
   fatal("$bold$--aotgen$$ not supported without LLVM");
1432
}
1433
#endif
1434

1435
static int do_cmd(int argc, char **argv, cmd_state_t *state)
12✔
1436
{
1437
   static struct option long_options[] = {
12✔
1438
      { 0, 0, 0, 0 }
1439
   };
1440

1441
   const int next_cmd = scan_cmd(2, argc, argv);
12✔
1442
   int c, index = 0;
12✔
1443
   const char *spec = ":";
12✔
1444
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
12✔
UNCOV
1445
      switch (c) {
×
1446
      case 0: break;  // Set a flag
UNCOV
1447
      case '?': bad_option("do", argv);
×
UNCOV
1448
      case ':': missing_argument("do", argv);
×
UNCOV
1449
      default: abort();
×
1450
      }
1451
   }
1452

1453
   if (optind == next_cmd)
12✔
1454
      fatal("no script file specified");
×
1455

1456
   if (state->mir == NULL)
12✔
1457
      state->mir = mir_context_new();
12✔
1458

1459
   if (state->registry == NULL)
12✔
1460
      state->registry = unit_registry_new();
6✔
1461

1462
   if (state->jit == NULL)
12✔
1463
      state->jit = get_jit(state->registry, state->mir);
12✔
1464

1465
#ifdef ENABLE_TCL
1466
   tcl_shell_t *sh = shell_new(state->jit);
12✔
1467

1468
   if (strpbrk(argv[optind], "./\\") == NULL) {
12✔
1469
      ident_t unit_name = to_unit_name(argv[optind]);
3✔
1470
      if (lib_get(state->work, unit_name) != NULL) {
3✔
1471
         state->top_level_arg = xstrdup(argv[optind]);
3✔
1472
         state->top_level = unit_name;
3✔
1473
         optind++;
3✔
1474
      }
1475
   }
1476

1477
   if (state->top_level != NULL) {
12✔
1478
      ident_t ename = ident_prefix(state->top_level, well_known(W_ELAB), '.');
9✔
1479
      tree_t top = lib_get(state->work, ename);
9✔
1480
      if (top == NULL)
9✔
UNCOV
1481
         fatal("%s not elaborated", istr(state->top_level));
×
1482

1483
#ifdef ENABLE_LLVM
1484
      jit_load_dll(state->jit, tree_ident(top));
9✔
1485
#endif
1486

1487
      char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
18✔
1488
      FILE *f = lib_fopen(state->work, name, "rb");
9✔
1489
      if (f != NULL) {
9✔
UNCOV
1490
         jit_load_pack(state->jit, f);
×
UNCOV
1491
         fclose(f);
×
1492
      }
1493

1494
      shell_reset(sh, top);
9✔
1495
   }
1496

1497
   for (int i = optind; i < next_cmd; i++) {
21✔
1498
      if (!shell_do(sh, argv[i])) {
12✔
1499
         shell_free(sh);
3✔
1500
         return EXIT_FAILURE;
3✔
1501
      }
1502
   }
1503

1504
   shell_free(sh);
9✔
1505
#else
1506
   fatal("compiled without TCL support");
1507
#endif
1508

1509
   argc -= next_cmd - 1;
9✔
1510
   argv += next_cmd - 1;
9✔
1511

1512
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
9✔
1513
}
1514

1515
static int interact_cmd(int argc, char **argv, cmd_state_t *state)
3✔
1516
{
1517
   static struct option long_options[] = {
3✔
1518
      { 0, 0, 0, 0 }
1519
   };
1520

1521
   const int next_cmd = scan_cmd(2, argc, argv);
3✔
1522
   int c, index = 0;
3✔
1523
   const char *spec = ":";
3✔
1524
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
3✔
1525
      switch (c) {
×
1526
      case 0: break;  // Set a flag
UNCOV
1527
      case '?': bad_option("do", argv);
×
UNCOV
1528
      case ':': missing_argument("do", argv);
×
UNCOV
1529
      default: abort();
×
1530
      }
1531
   }
1532

1533
   if (state->mir == NULL)
3✔
1534
      state->mir = mir_context_new();
3✔
1535

1536
   if (state->registry == NULL)
3✔
1537
      state->registry = unit_registry_new();
3✔
1538

1539
   if (state->jit == NULL)
3✔
1540
      state->jit = get_jit(state->registry, state->mir);
3✔
1541

1542
#ifdef ENABLE_TCL
1543
   tcl_shell_t *sh = shell_new(state->jit);
3✔
1544

1545
   if (strpbrk(argv[optind], "./\\") == NULL) {
3✔
1546
      ident_t unit_name = to_unit_name(argv[optind]);
3✔
1547
      if (lib_get(state->work, unit_name) != NULL) {
3✔
1548
         state->top_level_arg = xstrdup(argv[optind]);
3✔
1549
         state->top_level = unit_name;
3✔
1550
         optind++;
3✔
1551
      }
1552
   }
1553

1554
   if (optind != next_cmd)
3✔
1555
      fatal("unexpected argument \"%s\"", argv[optind]);
×
1556

1557
   if (state->top_level != NULL) {
3✔
1558
      ident_t ename = ident_prefix(state->top_level, well_known(W_ELAB), '.');
3✔
1559
      tree_t top = lib_get(state->work, ename);
3✔
1560
      if (top == NULL)
3✔
UNCOV
1561
         fatal("%s not elaborated", istr(state->top_level));
×
1562

1563
#ifdef ENABLE_LLVM
1564
      jit_load_dll(state->jit, tree_ident(top));
3✔
1565
#endif
1566

1567
      char *name LOCAL = xasprintf("_%s.pack", istr(state->top_level));
6✔
1568
      FILE *f = lib_fopen(state->work, name, "rb");
3✔
1569
      if (f != NULL) {
3✔
UNCOV
1570
         jit_load_pack(state->jit, f);
×
UNCOV
1571
         fclose(f);
×
1572
      }
1573

1574
      shell_reset(sh, top);
3✔
1575
   }
1576

1577
   shell_interact(sh);
3✔
1578

1579
   shell_free(sh);
3✔
1580
#else
1581
   fatal("compiled without TCL support");
1582
#endif
1583

1584
   argc -= next_cmd - 1;
3✔
1585
   argv += next_cmd - 1;
3✔
1586

1587
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
3✔
1588
}
1589

1590
static uint32_t parse_cover_print_spec(char *str)
9✔
1591
{
1592
   uint32_t mask = 0;
9✔
1593
   const char *delim = ",";
9✔
1594
   for (char *tok = strtok(str, delim); tok; tok = strtok(NULL, delim)) {
27✔
1595
      if (!strcmp(tok, "covered"))
18✔
1596
         mask |= COVER_MASK_DONT_PRINT_COVERED;
6✔
1597
      else if (!strcmp(tok, "uncovered"))
12✔
1598
         mask |= COVER_MASK_DONT_PRINT_UNCOVERED;
6✔
1599
      else if (!strcmp(tok, "excluded"))
6✔
1600
         mask |= COVER_MASK_DONT_PRINT_EXCLUDED;
6✔
1601
      else {
UNCOV
1602
         diag_t *d = diag_new(DIAG_FATAL, NULL);
×
UNCOV
1603
         diag_printf(d, "invalid option: '%s' for $bold$--dont-print$$", tok);
×
UNCOV
1604
         diag_hint(d, NULL, "valid options are: 'covered', 'uncovered', "
×
1605
                   "'excluded'");
UNCOV
1606
         diag_emit(d);
×
UNCOV
1607
         fatal_exit(EXIT_FAILURE);
×
1608
      }
1609
   }
1610
   return mask;
9✔
1611
}
1612

1613
static int coverage_cmd(int argc, char **argv, cmd_state_t *state)
9✔
1614
{
1615
   warnf("the $bold$-c$$ sub-command is deprecated, use $bold$--cover-report$$ "
9✔
1616
         "or $bold$--cover-merge$$ instead");
1617

1618
   static struct option long_options[] = {
9✔
1619
      { "report",       required_argument, 0, 'r' },
1620
      { "exclude-file", required_argument, 0, 'e' },
1621
      { "export",       required_argument, 0, 'E' },
1622
      { "merge",        required_argument, 0, 'm' },
1623
      { "dont-print",   required_argument, 0, 'd' },
1624
      { "item-limit",   required_argument, 0, 'l' },
1625
      { "verbose",      no_argument,       0, 'V' },
1626
      { 0, 0, 0, 0 }
1627
   };
1628

1629
   const char *out_db = NULL, *rpt_file = NULL, *exclude_file = NULL;
9✔
1630
   const char *export_file = NULL;
9✔
1631
   int c, index;
9✔
1632
   const char *spec = ":V";
9✔
1633
   cover_mask_t rpt_mask = 0;
9✔
1634
   int item_limit = 5000;
9✔
1635

1636
   while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) {
24✔
1637
      switch (c) {
15✔
1638
      case 'r':
9✔
1639
         rpt_file = optarg;
9✔
1640
         break;
9✔
UNCOV
1641
      case 'm':
×
1642
         out_db = optarg;
×
UNCOV
1643
         break;
×
1644
      case 'e':
3✔
1645
         exclude_file = optarg;
3✔
1646
         break;
3✔
UNCOV
1647
      case 'E':
×
UNCOV
1648
         export_file = optarg;
×
UNCOV
1649
         break;
×
UNCOV
1650
      case 'd':
×
UNCOV
1651
         rpt_mask = parse_cover_print_spec(optarg);
×
UNCOV
1652
         break;
×
1653
      case 'l':
3✔
1654
         item_limit = parse_int(optarg);
3✔
1655
         break;
3✔
UNCOV
1656
      case 'V':
×
UNCOV
1657
         opt_set_int(OPT_VERBOSE, 1);
×
1658
         break;
×
UNCOV
1659
      case '?':
×
UNCOV
1660
         bad_option("coverage", argv);
×
UNCOV
1661
      case ':':
×
UNCOV
1662
         missing_argument("coverage", argv);
×
UNCOV
1663
      default:
×
1664
         abort();
×
1665
      }
1666
   }
1667

1668
   progress("initialising");
9✔
1669

1670
   if (optind == argc)
9✔
UNCOV
1671
      fatal("no input coverage database FILE specified");
×
1672

1673
   cover_data_t *cover = NULL;
1674

1675
   // Rest of inputs are coverage input files
1676
   for (int i = optind; i < argc; i++) {
21✔
1677
      fbuf_t *f = fbuf_open(argv[i], FBUF_IN, FBUF_CS_NONE);
12✔
1678

1679
      if (f != NULL) {
12✔
1680
         progress("Loading input coverage database: %s", argv[i]);
12✔
1681
         if (i == optind)
12✔
1682
            cover = cover_read_items(f, rpt_mask);
9✔
1683
         else
1684
            cover_merge_items(f, cover);
3✔
1685
      }
1686
      else
1687
         fatal("Could not open coverage database: %s", argv[i]);
×
1688

1689
      fbuf_close(f, NULL);
12✔
1690
   }
1691

1692
   if (out_db) {
9✔
UNCOV
1693
      progress("Saving merged coverage database to: %s", out_db);
×
UNCOV
1694
      fbuf_t *f = fbuf_open(out_db, FBUF_OUT, FBUF_CS_NONE);
×
1695
      cover_dump_items(cover, f, COV_DUMP_PROCESSING, NULL);
×
UNCOV
1696
      fbuf_close(f, NULL);
×
1697
   }
1698

1699
   if (exclude_file && cover) {
9✔
1700
      progress("Loading exclude file: %s", exclude_file);
3✔
1701
      cover_load_exclude_file(exclude_file, cover);
3✔
1702
   }
1703

1704
   if (rpt_file && cover) {
9✔
1705
      progress("Generating code coverage report.");
9✔
1706
      cover_report(rpt_file, cover, item_limit);
9✔
1707
   }
1708

1709
   if (export_file && cover) {
9✔
UNCOV
1710
      progress("Exporting XML coverage report");
×
1711

1712
      FILE *f = fopen(export_file, "w");
×
UNCOV
1713
      if (f == NULL)
×
1714
         fatal_errno("cannot open %s", export_file);
×
1715

1716
      cover_export_cobertura(cover, f, NULL);
×
UNCOV
1717
      fclose(f);
×
1718
   }
1719

1720
   return 0;
9✔
1721
}
1722

1723
#ifdef ENABLE_GUI
UNCOV
1724
static int gui_cmd(int argc, char **argv, cmd_state_t *state)
×
1725
{
UNCOV
1726
   static struct option long_options[] = {
×
1727
      { "init",     required_argument, 0, 'i' },
1728
      { "port",     required_argument, 0, 'p' },
1729
      { "protocol", required_argument, 0, 'o' },
1730
      { 0, 0, 0, 0 }
1731
   };
1732

1733
   const int next_cmd = scan_cmd(2, argc, argv);
×
1734
   server_kind_t kind = SERVER_HTTP;
×
UNCOV
1735
   int c, index = 0;
×
UNCOV
1736
   const char *spec = ":", *init_cmd = NULL;
×
UNCOV
1737
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
×
1738
      switch (c) {
×
1739
      case 0: break;  // Set a flag
UNCOV
1740
      case 'i': init_cmd = optarg; break;
×
1741
      case 'p':
×
1742
         {
1743
            const int port = parse_int(optarg);
×
1744
            if (port < 0 || port > UINT16_MAX)
×
1745
               fatal("invalid port number %d", port);
×
1746

UNCOV
1747
            opt_set_int(OPT_SERVER_PORT, port);
×
1748
         }
1749
         break;
×
UNCOV
1750
      case 'o':
×
1751
         {
1752
            if (strcmp(optarg, "http") == 0)
×
1753
               kind = SERVER_HTTP;
1754
            else if (strcmp(optarg, "cxxrtl") == 0)
×
1755
               kind = SERVER_CXXRTL;
1756
            else
UNCOV
1757
               fatal("invalid protocol '%s', valid choices are "
×
1758
                     "'http' and 'cxxrtl'", optarg);
1759
         }
1760
         break;
UNCOV
1761
      case '?': bad_option("gui", argv);
×
UNCOV
1762
      case ':': missing_argument("gui", argv);
×
UNCOV
1763
      default: abort();
×
1764
      }
1765
   }
1766

UNCOV
1767
   if (argc != optind)
×
UNCOV
1768
      fatal("$bold$--gui$$ command takes no positional arguments");
×
1769

UNCOV
1770
   tree_t top = NULL;
×
UNCOV
1771
   if (state->top_level != NULL) {
×
UNCOV
1772
      ident_t ename = ident_prefix(state->top_level, well_known(W_ELAB), '.');
×
UNCOV
1773
      if ((top = lib_get(state->work, ename)) == NULL)
×
UNCOV
1774
         fatal("%s not elaborated", istr(state->top_level));
×
1775
   }
1776

NEW
1777
   if (state->mir == NULL)
×
NEW
1778
      state->mir = mir_context_new();
×
1779

UNCOV
1780
   if (state->jit == NULL)
×
NEW
1781
      state->jit = get_jit(state->registry, state->mir);
×
1782

UNCOV
1783
   start_server(kind, state->jit, top, NULL, NULL, init_cmd);
×
1784

UNCOV
1785
   argc -= next_cmd - 1;
×
UNCOV
1786
   argv += next_cmd - 1;
×
1787

UNCOV
1788
   return argc > 1 ? process_command(argc, argv, state) : EXIT_SUCCESS;
×
1789
}
1790
#endif
1791

1792
static cover_data_t *merge_coverage_files(int argc, int next_cmd, char **argv,
162✔
1793
                                          cover_mask_t rpt_mask)
1794
{
1795
   // Merge all input coverage databases given on command line
1796

1797
   if (optind == next_cmd)
162✔
UNCOV
1798
      fatal("no input coverage database specified");
×
1799

1800
   cover_data_t *cover = NULL;
1801

1802
   for (int i = optind; i < next_cmd; i++) {
339✔
1803
      fbuf_t *f = fbuf_open(argv[i], FBUF_IN, FBUF_CS_NONE);
177✔
1804
      if (f == NULL) {
177✔
1805
         // Attempt to redirect the old file name to the new one
1806
         // TODO: this should be removed at some point
1807
         char *slash = strrchr(argv[i], *DIR_SEP) ?: strrchr(argv[i], '/');
12✔
1808
         if (slash != NULL && slash[1] == '_') {
12✔
1809
            char *tail = strstr(slash, ".covdb");
12✔
1810
            if (tail != NULL && tail[6] == '\0') {
12✔
1811
               ident_t unit_name = ident_new_n(slash + 2, tail - slash - 2);
12✔
1812
               lib_t lib = lib_find(ident_until(unit_name, '.'));
12✔
1813
               if (lib != NULL) {
12✔
1814
                  const unit_meta_t *meta;
12✔
1815
                  object_t *obj = lib_get_generic(lib, unit_name, &meta);
12✔
1816
                  if (obj != NULL && meta->cover_file != NULL) {
12✔
1817
                     warnf("redirecting %s to %s, please update your scripts",
12✔
1818
                           argv[i], meta->cover_file);
1819
                     f = fbuf_open(meta->cover_file, FBUF_IN, FBUF_CS_NONE);
12✔
1820
                  }
1821
               }
1822
            }
1823
         }
1824
      }
1825

1826
      if (f == NULL)
177✔
UNCOV
1827
         fatal_errno("could not open %s", argv[i]);
×
1828

1829
      progress("loading input coverage database %s", argv[i]);
177✔
1830

1831
      if (i == optind)
177✔
1832
         cover = cover_read_items(f, rpt_mask);
162✔
1833
      else
1834
         cover_merge_items(f, cover);
15✔
1835

1836
      fbuf_close(f, NULL);
177✔
1837
   }
1838

1839
   return cover;
162✔
1840
}
1841

1842
static int cover_export_cmd(int argc, char **argv, cmd_state_t *state)
39✔
1843
{
1844
   static struct option long_options[] = {
39✔
1845
      { "format",   required_argument, 0, 'f' },
1846
      { "output",   required_argument, 0, 'o' },
1847
      { "relative", optional_argument, 0, 'r' },
1848
      { 0, 0, 0, 0 }
1849
   };
1850

1851
   const int next_cmd = scan_cmd(2, argc, argv);
39✔
1852

1853
   enum { UNSET, COBERTURA, XML } format = UNSET;
39✔
1854
   const char *output = NULL, *relative = NULL;
39✔
1855
   int c, index;
39✔
1856
   const char *spec = ":o:";
39✔
1857
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
156✔
1858
      switch (c) {
117✔
1859
      case 'f':
39✔
1860
         if (strcasecmp(optarg, "cobertura") == 0)
39✔
1861
            format = COBERTURA;
1862
         else if (strcasecmp(optarg, "xml") == 0)
36✔
1863
            format = XML;
1864
         else
UNCOV
1865
            fatal("unknown format '%s', valid formats are: cobertura, xml",
×
1866
                  optarg);
1867
         break;
1868
      case 'o':
39✔
1869
         output = optarg;
39✔
1870
         break;
39✔
1871
      case 'r':
39✔
1872
         relative = optarg ?: ".";
39✔
1873
         break;
UNCOV
1874
      case '?':
×
1875
         bad_option("coverage export", argv);
×
UNCOV
1876
      case ':':
×
1877
         missing_argument("coverage export", argv);
×
1878
      default:
×
UNCOV
1879
         abort();
×
1880
      }
1881
   }
1882

1883
   if (format == UNSET) {
39✔
1884
      diag_t *d = diag_new(DIAG_FATAL, NULL);
×
UNCOV
1885
      diag_printf(d, "the $bold$--format$$ option is required");
×
1886
      diag_hint(d, NULL, "pass $bold$--format=cobertura$$ for Cobertura XML");
×
UNCOV
1887
      diag_emit(d);
×
UNCOV
1888
      return EXIT_FAILURE;
×
1889
   }
1890

1891
   // DEPRECATED 1.14
1892
   // Handle the old-style --cover-export which accepted a top-level unit name
1893
   bool looks_like_file = false;
39✔
1894
   if (argc != optind) {
39✔
1895
      file_info_t info;
39✔
1896
      if (get_file_info(argv[optind], &info))
39✔
1897
         looks_like_file = true;
UNCOV
1898
      else if (strstr(argv[optind], "/"))
×
UNCOV
1899
         looks_like_file = true;
×
1900
   }
1901

1902
   cover_data_t *cover;
39✔
1903
   if (looks_like_file)
39✔
1904
      cover = merge_coverage_files(argc, next_cmd, argv, 0);
39✔
1905
   else {
UNCOV
1906
      set_top_level(argv, next_cmd, state);
×
1907

UNCOV
1908
      char *fname LOCAL = xasprintf("_%s.elab.covdb", istr(state->top_level));
×
UNCOV
1909
      fbuf_t *f = lib_fbuf_open(state->work, fname, FBUF_IN, FBUF_CS_NONE);
×
1910

UNCOV
1911
      if (f == NULL)
×
UNCOV
1912
         fatal("no coverage database for %s", istr(state->top_level));
×
1913

UNCOV
1914
      cover = cover_read_items(f, 0);
×
UNCOV
1915
      fbuf_close(f, NULL);
×
1916

UNCOV
1917
      warnf("exporting the coverage database using the top-level unit name "
×
1918
            "is deprecated, pass the path to the coverage database instead");
1919
   }
1920

1921
   FILE *file = stdout;
39✔
1922
   if (output != NULL && (file = fopen(output, "w")) == NULL)
39✔
UNCOV
1923
      fatal_errno("cannot create %s", output);
×
1924

1925
   switch (format) {
39✔
1926
   case COBERTURA:
3✔
1927
      cover_export_cobertura(cover, file, relative);
3✔
1928
      break;
3✔
1929
   case XML:
36✔
1930
      cover_export_xml(cover, file, relative);
36✔
1931
      break;
36✔
1932
   case UNSET:
1933
      should_not_reach_here();
1934
   }
1935

1936
   if (file != stdout)
39✔
1937
      fclose(file);
39✔
1938

1939
   argc -= next_cmd - 1;
39✔
1940
   argv += next_cmd - 1;
39✔
1941

1942
   return argc > 1 ? process_command(argc, argv, state) : 0;
39✔
1943
}
1944

1945
static int cover_report_cmd(int argc, char **argv, cmd_state_t *state)
117✔
1946
{
1947
   static struct option long_options[] = {
117✔
1948
      { "report",       required_argument, 0, 'r' },   // DEPRECATED 1.14
1949
      { "output",       required_argument, 0, 'o' },
1950
      { "exclude-file", required_argument, 0, 'e' },
1951
      { "dont-print",   required_argument, 0, 'd' },
1952
      { "item-limit",   required_argument, 0, 'l' },
1953
      { "per-file",     no_argument,       0, 'f' },
1954
      { "verbose",      no_argument,       0, 'V' },
1955
      { 0, 0, 0, 0 }
1956
   };
1957

1958
   const int next_cmd = scan_cmd(2, argc, argv);
117✔
1959

1960
   const char *outdir = NULL, *exclude_file = NULL;
117✔
1961
   int c, index;
117✔
1962
   const char *spec = ":Vo:";
117✔
1963
   cover_mask_t rpt_mask = 0;
117✔
1964
   int item_limit = 5000;
117✔
1965

1966
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
279✔
1967
      switch (c) {
162✔
UNCOV
1968
      case 'r':
×
1969
         warnf("the $bold$--report$$ option is deprecated, use "
×
1970
               "$bold$--output$$ instead");
1971
         // Fall-through
1972
      case 'o':
117✔
1973
         outdir = optarg;
117✔
1974
         break;
117✔
1975
      case 'e':
30✔
1976
         exclude_file = optarg;
30✔
1977
         break;
30✔
1978
      case 'd':
9✔
1979
         rpt_mask |= parse_cover_print_spec(optarg);
9✔
1980
         break;
9✔
UNCOV
1981
      case 'l':
×
UNCOV
1982
         item_limit = parse_int(optarg);
×
UNCOV
1983
         break;
×
1984
      case 'f':
3✔
1985
         rpt_mask |= COVER_MASK_PER_FILE_REPORT;
3✔
1986
         break;
3✔
1987
      case 'V':
3✔
1988
         opt_set_int(OPT_VERBOSE, 1);
3✔
1989
         break;
3✔
UNCOV
1990
      case '?':
×
UNCOV
1991
         bad_option("coverage report", argv);
×
UNCOV
1992
      case ':':
×
UNCOV
1993
         missing_argument("coverage report", argv);
×
UNCOV
1994
      default:
×
1995
         should_not_reach_here();
1996
      }
1997
   }
1998

1999
   if (outdir == NULL)
117✔
UNCOV
2000
      fatal("the output directory must be specified with $bold$--output$$");
×
2001

2002
   progress("initialising");
117✔
2003

2004
   cover_data_t *cover = merge_coverage_files(argc, next_cmd, argv, rpt_mask);
117✔
2005

2006
   if (exclude_file && cover) {
117✔
2007
      progress("loading exclude file %s", exclude_file);
30✔
2008
      cover_load_exclude_file(exclude_file, cover);
30✔
2009
   }
2010

2011
   progress("generating code coverage report");
117✔
2012
   cover_report(outdir, cover, item_limit);
117✔
2013

2014
   argc -= next_cmd - 1;
117✔
2015
   argv += next_cmd - 1;
117✔
2016

2017
   return argc > 1 ? process_command(argc, argv, state) : 0;
117✔
2018
}
2019

2020
static int cover_merge_cmd(int argc, char **argv, cmd_state_t *state)
6✔
2021
{
2022
   static struct option long_options[] = {
6✔
2023
      { "output",       required_argument, 0, 'o' },
2024
      { "verbose",      no_argument,       0, 'V' },
2025
      { 0, 0, 0, 0 }
2026
   };
2027

2028
   const int next_cmd = scan_cmd(2, argc, argv);
6✔
2029

2030
   const char *out_db = NULL;
6✔
2031
   int c, index;
6✔
2032
   const char *spec = ":Vo:";
6✔
2033

2034
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
12✔
2035
      switch (c) {
6✔
2036
      case 'o':
6✔
2037
         out_db = optarg;
6✔
2038
         break;
6✔
UNCOV
2039
      case 'V':
×
UNCOV
2040
         opt_set_int(OPT_VERBOSE, 1);
×
UNCOV
2041
         break;
×
UNCOV
2042
      case '?':
×
UNCOV
2043
         bad_option("coverage merge", argv);
×
UNCOV
2044
      case ':':
×
UNCOV
2045
         missing_argument("coverage merge", argv);
×
UNCOV
2046
      default:
×
2047
         should_not_reach_here();
2048
      }
2049
   }
2050

2051
   if (out_db == NULL)
6✔
UNCOV
2052
      fatal("the output database must be specified with $bold$--output$$");
×
2053

2054
   progress("initialising");
6✔
2055

2056
   cover_data_t *cover = merge_coverage_files(argc, next_cmd, argv, 0);
6✔
2057

2058
   progress("saving merged coverage database to %s", out_db);
6✔
2059

2060
   fbuf_t *f = fbuf_open(out_db, FBUF_OUT, FBUF_CS_NONE);
6✔
2061
   cover_dump_items(cover, f, COV_DUMP_PROCESSING, NULL);
6✔
2062
   fbuf_close(f, NULL);
6✔
2063

2064
   argc -= next_cmd - 1;
6✔
2065
   argv += next_cmd - 1;
6✔
2066

2067
   return argc > 1 ? process_command(argc, argv, state) : 0;
6✔
2068
}
2069

2070
static int preprocess_cmd(int argc, char **argv, cmd_state_t *state)
3✔
2071
{
2072
   static struct option long_options[] = {
3✔
2073
      { "define",      required_argument, 0, 'D' },
2074
      { "single-unit", no_argument,       0, 'u' },
2075
      { 0, 0, 0, 0 }
2076
   };
2077

2078
   const int next_cmd = scan_cmd(2, argc, argv);
3✔
2079

2080
   int c, index;
3✔
2081
   const char *spec = ":D:";
3✔
2082
   while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) {
12✔
2083
      switch (c) {
9✔
2084
      case 'u':
3✔
2085
         opt_set_int(OPT_SINGLE_UNIT, 1);
3✔
2086
         break;
3✔
2087
      case 'D':
6✔
2088
         parse_pp_define(optarg);
6✔
2089
         break;
6✔
UNCOV
2090
      case ':':
×
2091
         missing_argument("preprocess", argv);
×
UNCOV
2092
      case '?':
×
2093
      default:
UNCOV
2094
         bad_option("preprocess", argv);
×
2095
      }
2096
   }
2097

2098
   if (optind == next_cmd)
3✔
UNCOV
2099
      fatal("no input files");
×
2100

2101
   LOCAL_TEXT_BUF tb = tb_new();
6✔
2102
   for (int i = optind; i < next_cmd; i++) {
9✔
2103
      input_from_file(argv[i]);
6✔
2104

2105
      tb_rewind(tb);
6✔
2106
      vlog_preprocess(tb, false);
6✔
2107

2108
      fputs(tb_get(tb), stdout);
6✔
2109
   }
2110

2111
   argc -= next_cmd - 1;
3✔
2112
   argv += next_cmd - 1;
3✔
2113

2114
   return argc > 1 ? process_command(argc, argv, state) : 0;
3✔
2115
}
2116

UNCOV
2117
static void usage(void)
×
2118
{
UNCOV
2119
   color_printf("$!cyan$Usage:$$ $bold$%s [OPTION]... "
×
2120
                "COMMAND [OPTION]...$$\n\n",  PACKAGE);
2121

UNCOV
2122
   wrapped_printf("Global options are placed before COMMAND, and "
×
2123
                  "command-specific options are placed afterwards. "
2124
                  "Multiple commands can be given and will be performed "
2125
                  "in order.\n\n");
2126

UNCOV
2127
   static const struct {
×
2128
      const char *group;
2129
      struct {
2130
         const char *args;
2131
         const char *usage;
2132
      } options[16];
2133
   } groups[] = {
2134
      { "Commands",
2135
        {
2136
           { "-a [OPTION]... FILE...", "Analyse FILEs into work library" },
2137
           { "-e [OPTION]... TOP", "Elaborate design unit TOP" },
2138
           { "-r [OPTION]... TOP", "Execute previously elaborated TOP" },
2139
#ifdef ENABLE_TCL
2140
           { "-i [TOP]", "Launch interactive TCL shell" },
2141
#endif
2142
           { "--cover-export FILE...",
2143
             "Export coverage database to external format" },
2144
           { "--cover-report FILE...",
2145
             "Generate HTML report from coverage database" },
2146
           { "--cover-merge FILE...", "Merge multiple coverage databases" },
2147
#ifdef ENABLE_TCL
2148
           { "--do [TOP] SCRIPT...", "Evaluate TCL script" },
2149
#endif
2150
#ifdef ENABLE_GUI
2151
           { "--gui", "Launch browser-based GUI" },
2152
#endif
2153
           { "--init", "Initialise work library directory" },
2154
           { "--install PKG", "Install third-party packages" },
2155
           { "--list", "Print all units in the library" },
2156
           { "--preprocess FILE...",
2157
             "Expand FILEs with Verilog preprocessor" },
2158
           { "--print-deps [UNIT]...",
2159
             "Print dependencies in Makefile format" },
2160
        }
2161
      },
2162
      { "Global options",
2163
        {
2164
           { "-h, --help", "Display this message and exit" },
2165
           { "-H SIZE", "Set the maximum heap size to SIZE bytes" },
2166
           { "--ieee-warnings={on,off}",
2167
             "Enable or disable warnings from IEEE packages" },
2168
           { "--ignore-time", "Skip source file timestamp check" },
2169
           { "--load=PLUGIN", "Load VHPI plugin at startup" },
2170
           { "-L PATH", "Add PATH to library search paths" },
2171
           { "-M SIZE", "Limit design unit heap space to SIZE bytes" },
2172
           { "--map=LIB:PATH", "Map library LIB to PATH" },
2173
           { "--messages={full,compact}",
2174
             "Diagnostic message style, compact is less verbose" },
2175
           { "--std={1993,..,2019}", "VHDL standard revision to use" },
2176
           { "--stderr={note,warning,error,failure}",
2177
             "Print messages of this severity level or higher to stderr" },
2178
           { "-v, --version", "Display version and copyright information" },
2179
           { "--vhpi-debug", "Report VHPI errors as diagnostic messages" },
2180
           { "--vhpi-trace", "Trace VHPI calls and events" },
2181
           { "--work=NAME", "Use NAME as the work library" },
2182
        }
2183
      },
2184
      { "Analysis options",
2185
        {
2186
           { "--bootstrap", "Allow compilation of STANDARD package" },
2187
           { "--check-synthesis", "Warn on common synthesis mistakes" },
2188
           { "-D, --define NAME=VALUE",
2189
             "Set preprocessor symbol NAME to VALUE" },
2190
           { "--error-limit=NUM", "Stop after NUM errors" },
2191
           { "-f, --files=LIST", "Read files to analyse from LIST" },
2192
           { "--no-save", "Do not save analysed design units" },
2193
           { "--preserve-case",
2194
             "Preserve the original case of VHDL identifiers" },
2195
           { "--psl", "Enable parsing of PSL directives in comments" },
2196
           { "--relaxed", "Disable certain pedantic rule checks" },
2197
           { "--single-unit",
2198
             "Treat all Verilog files as a single compilation unit" },
2199
        }
2200
      },
2201
      { "Elaboration options",
2202
        {
2203
           { "--cover[={statement,branch,expression,toggle,...}]",
2204
             "Enable code coverage collection" },
2205
           { "--cover-file=FILE",
2206
             "Set the file name of the coverage database" },
2207
           { "--cover-spec=FILE",
2208
             "Fine-grained coverage collection specification, see the manual "
2209
             "for details" },
2210
           { "-g NAME=VALUE", "Set top level generic NAME to VALUE" },
2211
           { "-j, --jit", "Enable just-in-time compilation during simulation" },
2212
           { "-O0, -O1, -O2, -O3", "Set optimisation level (default is -O2)" },
2213
           { "--no-collapse", "Do not collapse multiple signals into one" },
2214
           { "--no-save", "Do not save the elaborated design to disk" },
2215
           { "-V, --verbose", "Print resource usage at each step" },
2216
        }
2217
      },
2218
      { "Run options",
2219
        {
2220
           { "--dump-arrays[=N]",
2221
             "Include nested arrays with up to N elements in waveform dump" },
2222
           { "--exclude=GLOB",
2223
             "Exclude signals matching GLOB from waveform dump" },
2224
           { "--exit-severity={note,warning,error,failure}",
2225
             "Exit after an assertion failure of this severity" },
2226
           { "--format={fst,vcd}", "Waveform dump format" },
2227
           { "--include=GLOB",
2228
             "Include signals matching GLOB in waveform dump" },
2229
           { "--shuffle", "Run processes in random order" },
2230
           { "--stats", "Print time and memory usage at end of run" },
2231
           { "--stop-delta=N", "Stop after N delta cycles (default 10000)" },
2232
           { "--stop-after=T", "Stop after simulation time T (e.g. 5ns)" },
2233
           { "--trace", "Trace simulation events" },
2234
           { "-w, --wave[=FILE]", "Write waveform dump to FILE" },
2235
        }
2236
      },
2237
#ifdef ENABLE_GUI
2238
      { "GUI options",
2239
        {
2240
           { "--init=CMDS", "Evaluate TCL commands on startup" },
2241
           { "--port=PORT", "Specify port for HTTP server" },
2242
        }
2243
      },
2244
#endif
2245
      { "Coverage report options",
2246
        {
2247
           { "--exclude-file=FILE",
2248
             "Apply exclude file when generating report, see manual for syntax"
2249
           },
2250
           { "--dont-print={covered,uncovered,excluded}",
2251
             "Exclude specified items from coverage report" },
2252
        }
2253
      },
2254
      { "Coverage merge options",
2255
        {
2256
           { "-o, --output=FILE", "Output database file name" },
2257
        }
2258
      },
2259
      { "Coverage export options",
2260
        {
2261
           { "--format=FMT", "File format (must be 'cobertura')" },
2262
           { "-o, --output=FILE", "Output file name" },
2263
           { "--relative=PATH", "Strip PATH from prefix of absolute paths" },
2264
        }
2265
      },
2266
      { "Install options",
2267
        {
2268
           { "--dest=DIR", "Compile libraries into directory DIR" }
2269
        },
2270
      }
2271
   };
2272

UNCOV
2273
   const int right = MAX(60, terminal_width());
×
2274

2275
   for (int i = 0; i < ARRAY_LEN(groups); i++) {
×
2276
      color_printf("$bold$$cyan$%s:$$\n", groups[i].group);
×
2277

UNCOV
2278
      for (int j = 0; j < ARRAY_LEN(groups[i].options); j++) {
×
UNCOV
2279
         const char *args  = groups[i].options[j].args;
×
UNCOV
2280
         const char *usage = groups[i].options[j].usage;
×
2281

UNCOV
2282
         if (args == NULL || usage == NULL)
×
2283
            break;
2284

UNCOV
2285
         int col = 0;
×
2286
         if (args[0] == '-' && args[1] == '-' && i > 0)
×
UNCOV
2287
            col += color_printf("     $bold$%s$$ ", args);
×
2288
         else
2289
            col += color_printf(" $bold$%s$$ ", args);
×
2290

UNCOV
2291
         const int indent = i == 0 ? 30 : 20;
×
2292
         if (col > indent)
×
2293
            printf("\n%*.s", indent, "");
×
2294
         else
UNCOV
2295
            col += printf("%*.s", indent - col, "");
×
2296

2297
         col = indent;
2298

2299
         const char *p = usage, *begin = usage;
UNCOV
2300
         for (; *p != '\0'; p++) {
×
2301
            if (col + 1 >= right && p - begin + 1 < right - indent) {
×
UNCOV
2302
               printf("\n%*s", indent, "");
×
UNCOV
2303
               col = indent + p - begin;
×
2304
            }
UNCOV
2305
            else if (isspace_iso88591(*p)) {
×
UNCOV
2306
               fwrite(begin, 1, p - begin + 1, stdout);
×
UNCOV
2307
               col++;
×
UNCOV
2308
               begin = p + 1;
×
2309
            }
2310
            else
2311
               ++col;
2312
         }
2313

UNCOV
2314
         if (begin < p)
×
UNCOV
2315
            fwrite(begin, 1, p - begin, stdout);
×
2316

UNCOV
2317
         printf("\n");
×
2318
      }
2319

UNCOV
2320
      printf("\n");
×
2321
   }
2322

UNCOV
2323
   LOCAL_TEXT_BUF tb = tb_new();
×
UNCOV
2324
   lib_print_search_paths(tb);
×
UNCOV
2325
   color_printf("$!cyan$Library search paths:$$%s\n\n", tb_get(tb));
×
2326

UNCOV
2327
   wrapped_printf("The full manual can be read with $bold$man 1 %s$$ and "
×
2328
                  "contains detailed explanations of the commands and options "
2329
                  "above as well as examples.\n", PACKAGE_NAME);
2330
   color_printf("\nReport bugs at $link:%s\07%s$\n", PACKAGE_BUGREPORT,
×
2331
                PACKAGE_BUGREPORT);
UNCOV
2332
}
×
2333

2334
static vhdl_standard_t parse_standard(const char *str)
3,708✔
2335
{
2336
   char *eptr = NULL;
3,708✔
2337
   const int year = strtol(str, &eptr, 10);
3,708✔
2338
   if ((eptr != NULL) && (*eptr == '\0')) {
3,708✔
2339
      switch (year) {
3,708✔
UNCOV
2340
      case 1987:
×
2341
      case 87:
UNCOV
2342
         fatal("VHDL standard 1076-1987 is not supported");
×
2343
      case 1993:
2344
      case 93:
2345
         return STD_93;
2346
      case 2000:
58✔
2347
      case 0:
2348
         return STD_00;
58✔
2349
      case 2002:
27✔
2350
      case 2:
2351
         return STD_02;
27✔
2352
      case 2008:
954✔
2353
      case 8:
2354
         return STD_08;
954✔
2355
      case 2019:
244✔
2356
      case 19:
2357
         return STD_19;
244✔
2358
      }
2359
   }
2360

UNCOV
2361
   fatal("invalid standard revision: %s (allowed 1993, 2000, 2002, "
×
2362
         "2008, 2019)", str);
2363
}
2364

UNCOV
2365
static message_style_t parse_message_style(const char *str)
×
2366
{
UNCOV
2367
   if (strcmp(optarg, "full") == 0)
×
2368
      return MESSAGE_FULL;
UNCOV
2369
   else if (strcmp(optarg, "compact") == 0)
×
2370
      return MESSAGE_COMPACT;
2371

UNCOV
2372
   fatal("invalid message style '%s' (allowed are 'full' and 'compact')", str);
×
2373
}
2374

2375
static size_t parse_size(const char *str)
6✔
2376
{
2377
   char *eptr;
6✔
2378
   const ssize_t size = strtoll(str, &eptr, 0);
6✔
2379

2380
   if (size <= 0)
6✔
UNCOV
2381
      fatal("invalid size '%s' (must be positive)", str);
×
2382
   else if (*eptr == '\0')
6✔
UNCOV
2383
      return size;
×
2384
   else if (strcasecmp(eptr, "k") == 0)
6✔
UNCOV
2385
      return size * 1024;
×
2386
   else if (strcasecmp(eptr, "m") == 0)
6✔
2387
      return size * 1024 * 1024;
6✔
UNCOV
2388
   else if (strcasecmp(eptr, "g") == 0)
×
UNCOV
2389
      return size * 1024 * 1024 * 1024;
×
2390

UNCOV
2391
   fatal("invalid size '%s' (expected a number with optional k, m, "
×
2392
         "or g suffix)", str);
2393
}
2394

2395
static void parse_library_map(char *str)
9✔
2396
{
2397
#ifdef __MINGW32__
2398
   char *split = strpbrk(str, ";:");
2399
#else
2400
   char *split = strchr(str, ':');
9✔
2401
#endif
2402

2403
   if (split == NULL)
9✔
UNCOV
2404
      fatal("invalid library map syntax '%s': use NAME:PATH", str);
×
2405

2406
   *split = '\0';
9✔
2407

2408
   if (strcasecmp(str, "work") == 0)
9✔
UNCOV
2409
      fatal("use --work option to specify work library name and path");
×
2410

2411
   lib_add_map(str, split + 1);
9✔
2412
}
9✔
2413

2414
static int process_command(int argc, char **argv, cmd_state_t *state)
10,407✔
2415
{
2416
   static struct option long_options[] = {
10,407✔
2417
      { "dump",         no_argument, 0, 'd' },
2418
      { "make",         no_argument, 0, 'm' },   // DEPRECATED 1.8
2419
      { "syntax",       no_argument, 0, 's' },   // DEPRECATED 1.15
2420
      { "list",         no_argument, 0, 'l' },
2421
      { "init",         no_argument, 0, 'n' },
2422
      { "install",      no_argument, 0, 'I' },
2423
      { "print-deps",   no_argument, 0, 'P' },
2424
      { "aotgen",       no_argument, 0, 'A' },
2425
      { "do",           no_argument, 0, 'D' },
2426
      { "cover-export", no_argument, 0, 'E' },
2427
      { "cover-merge",  no_argument, 0, 'M' },
2428
      { "cover-report", no_argument, 0, 'p' },
2429
      { "preprocess",   no_argument, 0, 'R' },
2430
#ifdef ENABLE_GUI
2431
      { "gui",          no_argument, 0, 'g' },
2432
#endif
2433
      { 0, 0, 0, 0 }
2434
   };
2435

2436
   opterr = 0;
10,407✔
2437
   optind = 1;
10,407✔
2438

2439
   int index = 0;
10,407✔
2440
   const char *spec = "aerci";
10,407✔
2441
   switch (getopt_long(MIN(argc, 2), argv, spec, long_options, &index)) {
10,407✔
2442
   case 'a':
3,526✔
2443
      return analyse(argc, argv, state);
3,526✔
2444
   case 'e':
3,349✔
2445
      return elaborate(argc, argv, state);
3,349✔
2446
   case 'r':
3,325✔
2447
      return run_cmd(argc, argv, state);
3,325✔
2448
   case 'c':    // DEPRECATED 1.14
9✔
2449
      return coverage_cmd(argc, argv, state);
9✔
UNCOV
2450
   case 'd':
×
2451
      return dump_cmd(argc, argv, state);
×
2452
   case 'm':
×
UNCOV
2453
      return make_cmd(argc, argv, state);
×
UNCOV
2454
   case 's':
×
UNCOV
2455
      return syntax_cmd(argc, argv, state);
×
2456
   case 'l':
3✔
2457
      return list_cmd(argc, argv, state);
3✔
2458
   case 'n':
9✔
2459
      return init_cmd(argc, argv, state);
9✔
UNCOV
2460
   case 'I':
×
UNCOV
2461
      return install_cmd(argc, argv, state);
×
2462
   case 'P':
3✔
2463
      return print_deps_cmd(argc, argv, state);
3✔
2464
   case 'A':
3✔
2465
      return aotgen_cmd(argc, argv, state);
3✔
2466
   case 'D':
12✔
2467
      return do_cmd(argc, argv, state);
12✔
2468
   case 'i':
3✔
2469
      return interact_cmd(argc, argv, state);
3✔
2470
   case 'E':
39✔
2471
      return cover_export_cmd(argc, argv, state);
39✔
2472
   case 'M':
6✔
2473
      return cover_merge_cmd(argc, argv, state);
6✔
2474
   case 'p':
117✔
2475
      return cover_report_cmd(argc, argv, state);
117✔
2476
   case 'R':
3✔
2477
      return preprocess_cmd(argc, argv, state);
3✔
2478
#ifdef ENABLE_GUI
UNCOV
2479
   case 'g':
×
UNCOV
2480
      return gui_cmd(argc, argv, state);
×
2481
#endif
UNCOV
2482
   default:
×
UNCOV
2483
      fatal("missing command, try $bold$%s --help$$ for usage", PACKAGE);
×
2484
      return EXIT_FAILURE;
2485
   }
2486
}
2487

2488
int main(int argc, char **argv)
4,140✔
2489
{
2490
   term_init();
4,140✔
2491
   thread_init();
4,140✔
2492
   set_default_options();
4,140✔
2493
   intern_strings();
4,140✔
2494
   register_signal_handlers();
4,140✔
2495
   mspace_stack_limit(MSPACE_CURRENT_FRAME);
4,140✔
2496
   check_cpu_features();
4,140✔
2497

2498
   srand((unsigned)time(NULL));
4,140✔
2499
   atexit(fbuf_cleanup);
4,140✔
2500

2501
   static struct option long_options[] = {
4,140✔
2502
      { "help",          no_argument,       0, 'h' },
2503
      { "version",       no_argument,       0, 'v' },
2504
      { "work",          required_argument, 0, 'w' },
2505
      { "std",           required_argument, 0, 's' },
2506
      { "messages",      required_argument, 0, 'I' },
2507
      { "native",        no_argument,       0, 'n' }, // DEPRECATED 1.4
2508
      { "map",           required_argument, 0, 'p' },
2509
      { "ieee-warnings", required_argument, 0, 'W' },
2510
      { "ignore-time",   no_argument,       0, 'i' },
2511
      { "force-init",    no_argument,       0, 'f' }, // DEPRECATED 1.7
2512
      { "stderr",        required_argument, 0, 'E' },
2513
      { "load",          required_argument, 0, 'l' },
2514
      { "vhpi-debug",    no_argument,       0, 'D' },
2515
      { "vhpi-trace",    no_argument,       0, 'T' },
2516
      { 0, 0, 0, 0 }
2517
   };
2518

2519
   opterr = 0;
4,140✔
2520

2521
   const char *work_name = "work";
4,140✔
2522
   cmd_state_t state = {};
4,140✔
2523

2524
   const int next_cmd = scan_cmd(1, argc, argv);
4,140✔
2525
   int c, index = 0;
4,140✔
2526
   const char *spec = ":hivL:M:P:G:H:";
4,140✔
2527
   while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) {
8,301✔
2528
      switch (c) {
4,164✔
2529
      case 0:
2530
         // Set a flag
2531
         break;
2532
      case 'h':
×
2533
         usage();
×
2534
         exit(EXIT_SUCCESS);
×
2535
      case 'v':
UNCOV
2536
         printf("%s\n%s\n", version_string, copy_string);
×
2537
         exit(EXIT_SUCCESS);
×
2538
      case 'w':
204✔
2539
         work_name = optarg;
204✔
2540
         break;
204✔
2541
      case 'L':
147✔
2542
         lib_add_search_path(optarg);
147✔
2543
         break;
147✔
2544
      case 's':
3,708✔
2545
         set_standard(parse_standard(optarg));
3,708✔
2546
         state.user_set_std = true;
3,708✔
2547
         break;
3,708✔
UNCOV
2548
      case 'I':
×
2549
         set_message_style(parse_message_style(optarg));
×
2550
         break;
×
2551
      case 'p':
9✔
2552
         parse_library_map(optarg);
9✔
2553
         break;
9✔
2554
      case 'i':
×
2555
         opt_set_int(OPT_IGNORE_TIME, 1);
×
UNCOV
2556
         break;
×
UNCOV
2557
      case 'f':
×
UNCOV
2558
         warnf("the --force-init option is deprecated and has no effect");
×
UNCOV
2559
         break;
×
UNCOV
2560
      case 'n':
×
2561
         warnf("the --native option is deprecated and has no effect");
×
2562
         break;
×
2563
      case 'M':
×
UNCOV
2564
         opt_set_size(OPT_ARENA_SIZE, parse_size(optarg));
×
UNCOV
2565
         break;
×
UNCOV
2566
      case 'P':
×
2567
      case 'G':
UNCOV
2568
         warnf("the -%c option is deprecated and has no effect (the new "
×
2569
               "-H option sets a unified heap size)", c);
UNCOV
2570
         break;
×
2571
      case 'H':
6✔
2572
         opt_set_size(OPT_HEAP_SIZE, parse_size(optarg));
6✔
2573
         break;
6✔
2574
      case 'E':
3✔
2575
         set_stderr_severity(parse_severity(optarg));
3✔
2576
         break;
3✔
2577
      case 'l':
78✔
2578
         state.plugins = optarg;
78✔
2579
         break;
78✔
UNCOV
2580
      case 'T':
×
UNCOV
2581
         opt_set_str(OPT_PLI_TRACE, "1");
×
UNCOV
2582
         opt_set_int(OPT_PLI_DEBUG, 1);
×
UNCOV
2583
         break;
×
UNCOV
2584
      case 'D':
×
UNCOV
2585
         opt_set_int(OPT_PLI_DEBUG, 1);
×
UNCOV
2586
         break;
×
2587
      case 'W':
6✔
2588
         opt_set_int(OPT_IEEE_WARNINGS, parse_on_off(optarg));
6✔
2589
         break;
6✔
2590
      case '?':
3✔
2591
         bad_option("global", argv);
3✔
UNCOV
2592
      case ':':
×
UNCOV
2593
         missing_argument("global", argv);
×
UNCOV
2594
      default:
×
2595
         should_not_reach_here();
2596
      }
2597
   }
2598

2599
   state.work = lib_new(work_name);
4,137✔
2600
   lib_set_work(state.work);
4,131✔
2601

2602
   argc -= next_cmd - 1;
4,131✔
2603
   argv += next_cmd - 1;
4,131✔
2604

2605
   if (state.plugins != NULL) {
4,131✔
2606
      state.vhpi = vhpi_context_new();
78✔
2607
      vhpi_load_plugins(state.plugins);
78✔
2608
   }
2609

2610
   const int ret = process_command(argc, argv, &state);
4,131✔
2611

2612
   if (state.model != NULL)
4,104✔
2613
      model_free(state.model);
235✔
2614

2615
   if (state.jit != NULL)
4,104✔
2616
      jit_free(state.jit);   // JIT must be shut down before exiting
3,566✔
2617

2618
   if (state.registry != NULL)
4,104✔
2619
      unit_registry_free(state.registry);
3,954✔
2620

2621
   if (state.mir != NULL)
4,104✔
2622
      mir_context_free(state.mir);
3,817✔
2623

2624
   return ret;
4,104✔
2625
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc