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

nickg / nvc / 19617311111

23 Nov 2025 09:08PM UTC coverage: 92.559%. Remained the same
19617311111

push

github

nickg
Structure sharing for component instances

139 of 147 new or added lines in 1 file covered. (94.56%)

52 existing lines in 4 files now uncovered.

75133 of 81173 relevant lines covered (92.56%)

432299.23 hits per line

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

94.42
/src/driver.c
1
//
2
//  Copyright (C) 2023-2024  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 "diag.h"
21
#include "driver.h"
22
#include "hash.h"
23
#include "ident.h"
24
#include "mask.h"
25
#include "option.h"
26
#include "phase.h"
27
#include "tree.h"
28
#include "type.h"
29

30
#include <assert.h>
31
#include <stdlib.h>
32

33
#define DRIVER_PAGE_SIZE 128
34

35
typedef struct _driver_page driver_page_t;
36

37
typedef struct _driver_page {
38
   driver_page_t *next;
39
   unsigned       count;
40
   driver_info_t  members[DRIVER_PAGE_SIZE];
41
} driver_page_t;
42

43
typedef struct _driver_set {
44
   hash_t        *map;
45
   driver_page_t *pages;
46
} driver_set_t;
47

48
typedef struct {
49
   driver_set_t *ds;
50
   tree_t        proc;
51
   bool          tentative;
52
} proc_params_t;
53

54
static driver_info_t *alloc_driver_info(driver_set_t *ds)
10,159✔
55
{
56
   if (ds->pages == NULL || ds->pages->count == DRIVER_PAGE_SIZE) {
10,159✔
57
      driver_page_t *p = xmalloc(sizeof(driver_page_t));
4,666✔
58
      p->next = ds->pages;
4,666✔
59
      p->count = 0;
4,666✔
60

61
      ds->pages = p;
4,666✔
62
   }
63

64
   return &(ds->pages->members[ds->pages->count++]);
10,159✔
65
}
66

67
static void drives_signal(driver_set_t *ds, tree_t where, tree_t expr,
13,021✔
68
                          tree_t view, bool tentative)
69
{
70
   if (tree_kind(expr) == T_AGGREGATE) {
13,021✔
71
      const int nassocs = tree_assocs(expr);
82✔
72
      for (int i = 0; i < nassocs; i++) {
285✔
73
         tree_t e = tree_value(tree_assoc(expr, i));
203✔
74
         drives_signal(ds, where, e, NULL, tentative);
203✔
75
      }
76

77
      return;
78
   }
79

80
   tree_t prefix = longest_static_prefix(expr);
12,939✔
81

82
   driver_info_t *last = NULL;
12,939✔
83
   tree_t ref = name_to_ref(prefix), decl = NULL;
12,939✔
84
   if (ref != NULL) {
12,939✔
85
      if (tree_kind((decl = tree_ref(ref))) == T_PARAM_DECL) {
12,866✔
86
         // Assignment to procedure parameter: this is handled at the
87
         // call site instead
88
         return;
89
      }
90

91
      driver_info_t *chain = hash_get(ds->map, where);
12,856✔
92
      for (; chain; last = chain, chain = chain->chain_proc) {
33,500✔
93
         if (chain->where != where || chain->decl != decl)
10,507✔
94
            continue;
7,003✔
95
         else if (tree_kind(chain->prefix) == T_REF)
3,504✔
96
            return;   // Already driving full signal
97
         else if (same_tree(prefix, chain->prefix))
978✔
98
            return;
99
      }
100
   }
101
   else if (tree_kind(prefix) != T_EXTERNAL_NAME)
73✔
102
      return;
103

104
   driver_info_t *di = alloc_driver_info(ds);
10,159✔
105
   di->chain_decl = NULL;
10,159✔
106
   di->chain_proc = NULL;
10,159✔
107
   di->decl       = decl;
10,159✔
108
   di->prefix     = prefix;
10,159✔
109
   di->where      = where;
10,159✔
110
   di->view       = view;
10,159✔
111
   di->tentative  = tentative;
10,159✔
112

113
   if (last == NULL)
10,159✔
114
      hash_put(ds->map, where, di);
7,855✔
115
   else
116
      last->chain_proc = di;
2,304✔
117

118
   if (decl != NULL) {
10,159✔
119
      driver_info_t *decl_head = hash_get(ds->map, decl);
10,137✔
120
      if (decl_head == NULL)
10,137✔
121
         hash_put(ds->map, decl, di);
9,204✔
122
      else {
123
         for (; decl_head->chain_decl; decl_head = decl_head->chain_decl);
1,644✔
124
         decl_head->chain_decl = di;
933✔
125
      }
126
   }
127
}
128

129
static void driver_proc_cb(tree_t t, void *ctx)
487,909✔
130
{
131
   proc_params_t *params = ctx;
487,909✔
132

133
   switch (tree_kind(t)) {
487,909✔
134
   case T_SIGNAL_ASSIGN:
9,319✔
135
   case T_DUMMY_DRIVER:
136
      drives_signal(params->ds, params->proc, tree_target(t),
18,638✔
137
                    NULL, params->tentative);
9,319✔
138
      break;
9,319✔
139

140
   case T_PCALL:
4,799✔
141
   case T_PROT_PCALL:
142
      // LRM 08 section 4.2.2.3: a process statement contains a driver
143
      // for each actual signal associated with a formal signal
144
      // parameter of mode out or inout in a subprogram call.
145
      {
146
         tree_t decl = tree_ref(t);
4,799✔
147
         const int nports = tree_ports(decl);
4,799✔
148
         for (int i = 0; i < nports; i++) {
16,601✔
149
            tree_t p = tree_port(decl, i);
11,802✔
150
            if (tree_class(p) != C_SIGNAL)
11,802✔
151
               continue;
11,453✔
152

153
            const port_mode_t mode = tree_subkind(p);
349✔
154
            if (mode == PORT_OUT || mode == PORT_INOUT) {
349✔
155
               tree_t arg = tree_param(t, i);
239✔
156
               assert(tree_subkind(arg) == P_POS);
239✔
157
               drives_signal(params->ds, params->proc, tree_value(arg),
239✔
158
                             NULL, params->tentative);
239✔
159
            }
160
            else if (mode == PORT_ARRAY_VIEW || mode == PORT_RECORD_VIEW) {
110✔
161
               tree_t arg = tree_param(t, i);
15✔
162
               assert(tree_subkind(arg) == P_POS);
15✔
163
               drives_signal(params->ds, params->proc, tree_value(arg),
15✔
164
                             tree_value(p), params->tentative);
15✔
165
            }
166
         }
167
      }
168
      break;
169

170
   default:
171
      break;
172
   }
173
}
487,909✔
174

175
static void visit_port_map(driver_set_t *ds, tree_t unit, tree_t inst,
4,044✔
176
                           bool tentative)
177
{
178
   const int nparams = tree_params(inst);
4,044✔
179
   for (int i = 0; i < nparams; i++) {
11,500✔
180
      tree_t map = tree_param(inst, i);
7,456✔
181

182
      tree_t port;
7,456✔
183
      if (tree_subkind(map) == P_POS)
7,456✔
184
         port = tree_port(unit, tree_pos(map));
4,440✔
185
      else {
186
         tree_t name = tree_name(map);
3,016✔
187
         switch (tree_kind(name)) {
3,016✔
188
         case T_CONV_FUNC:
87✔
189
         case T_TYPE_CONV:
190
            name = tree_value(name);
87✔
191
            break;
87✔
192
         default:
193
            break;
194
         }
195

196
         port = tree_ref(name_to_ref(name));
3,016✔
197
      }
198

199
      switch (tree_subkind(port)) {
7,456✔
200
      case PORT_OUT:
3,172✔
201
      case PORT_INOUT:
202
         drives_signal(ds, inst, tree_value(map), NULL, tentative);
3,172✔
203
         break;
3,172✔
204
      case PORT_ARRAY_VIEW:
73✔
205
      case PORT_RECORD_VIEW:
206
         drives_signal(ds, inst, tree_value(map), tree_value(port), tentative);
73✔
207
         break;
73✔
208
      }
209
   }
210
}
4,044✔
211

212
static void visit_instance(driver_set_t *ds, tree_t inst, bool tentative)
3,028✔
213
{
214
   tree_t unit = primary_unit_of(tree_ref(inst));
3,028✔
215
   visit_port_map(ds, unit, inst, tentative);
3,028✔
216
}
3,028✔
217

218
static void visit_block(driver_set_t *ds, tree_t b, bool tentative)
9,490✔
219
{
220
   const int nstmts = tree_stmts(b);
9,490✔
221
   for (int i = 0; i < nstmts; i++) {
22,956✔
222
      tree_t s = tree_stmt(b, i);
13,466✔
223
      switch (tree_kind(s)) {
13,466✔
224
      case T_PROCESS:
8,793✔
225
         {
226
            proc_params_t params = {
8,793✔
227
               .ds = ds,
228
               .proc = s,
229
               .tentative = tentative,
230
            };
231
            tree_visit(s, driver_proc_cb, &params);
8,793✔
232
         }
233
         break;
8,793✔
234
      case T_BLOCK:
1,016✔
235
         visit_port_map(ds, s, s, tentative);
1,016✔
236
         visit_block(ds, s, tentative);
1,016✔
237
         break;
1,016✔
238
      case T_FOR_GENERATE:
264✔
239
         visit_block(ds, s, true);
264✔
240
         break;
264✔
241
      case T_IF_GENERATE:
113✔
242
         {
243
            const int nconds = tree_conds(s);
113✔
244
            for (int i = 0; i < nconds; i++)
230✔
245
               visit_block(ds, tree_cond(s, i), true);
117✔
246
         }
247
         break;
248
      case T_CASE_GENERATE:
12✔
249
         {
250
            const int nalts = tree_stmts(s);
12✔
251
            for (int i = 0; i < nalts; i++) {
54✔
252
               tree_t a = tree_stmt(s, i);
42✔
253
               assert(tree_kind(a) == T_ALTERNATIVE);
42✔
254
               visit_block(ds, a, true);
42✔
255
            }
256
         }
257
         break;
258
      case T_INSTANCE:
3,028✔
259
         visit_instance(ds, s, tentative);
3,028✔
260
         break;
3,028✔
261
      default:
262
         break;
263
      }
264
   }
265

266
}
9,490✔
267

268
driver_set_t *find_drivers(tree_t where)
8,051✔
269
{
270
   driver_set_t *ds = xcalloc(sizeof(driver_set_t));
8,051✔
271
   ds->map = hash_new(128);
8,051✔
272

273
   switch (tree_kind(where)) {
8,051✔
274
   case T_ARCH:
8,051✔
275
   case T_BLOCK:
276
   case T_FOR_GENERATE:
277
   case T_COND_STMT:
278
   case T_ALTERNATIVE:
279
      visit_block(ds, where, false);
8,051✔
280
      break;
8,051✔
UNCOV
281
   case T_BINDING:
×
UNCOV
282
      visit_port_map(ds, primary_unit_of(tree_ref(where)), where, false);
×
UNCOV
283
      break;
×
284
   default:
×
285
      fatal_trace("cannot find drivers in %s", tree_kind_str(tree_kind(where)));
286
   }
287

288
   if (opt_get_int(OPT_DRIVER_VERBOSE))
8,051✔
289
      dump_drivers(ds);
×
290

291
   return ds;
8,051✔
292
}
293

294
void free_drivers(driver_set_t *ds)
8,051✔
295
{
296
   for (driver_page_t *p = ds->pages, *tmp; p; p = tmp) {
12,717✔
297
      tmp = p->next;
4,666✔
298
      free(p);
4,666✔
299
   }
300

301
   hash_free(ds->map);
8,051✔
302
   free(ds);
8,051✔
303
}
8,051✔
304

305
driver_info_t *get_drivers(driver_set_t *ds, tree_t what)
18,741✔
306
{
307
   return hash_get(ds->map, what);
18,741✔
308
}
309

310
bool has_unique_driver(driver_set_t *ds, tree_t what)
11✔
311
{
312
   // True if signal has exactly one driver for each sub-element
313

314
   driver_info_t *di = get_drivers(ds, what);
11✔
315

316
   if (di == NULL)
11✔
317
      return false;
318

319
   // First pass: look for assignments to the full signal
320

321
   bool saw_ref = false, saw_multiple = false;
11✔
322
   tree_t proc = di->where;
11✔
323
   for (driver_info_t *it = di; it; it = it->chain_decl) {
33✔
324
      if (it->tentative)
24✔
325
         return false;
326
      else if (it->where != proc)
22✔
327
         saw_multiple = true;
328
      else if (tree_kind(it->prefix) == T_REF)
10✔
329
         saw_ref = true;
3✔
330
   }
331

332
   if (saw_ref && !saw_multiple)
9✔
333
      return true;
334

335
   type_t type = tree_type(what);
8✔
336
   if (type_is_unconstrained(type))
8✔
337
      return false;
338

339
   int64_t length = 0, left = 0, right = 0;
7✔
340
   range_kind_t rkind = RANGE_ERROR;
7✔
341
   if (type_is_array(type) && dimension_of(type) == 1) {
7✔
342
      tree_t r = range_of(type, 0);
3✔
343
      if (folded_length(r, &length)) {
3✔
344
         left = assume_int(tree_left(r));
3✔
345
         right = assume_int(tree_right(r));
3✔
346
         rkind = tree_subkind(r);
3✔
347
      }
348
   }
349
   else if (type_is_record(type))
4✔
350
      length = type_fields(type);
3✔
351

352
   if (length == 0)
7✔
353
      return false;
354

355
   // Second pass: look for assignments to disjoint sub-elements
356

357
   bit_mask_t mask = {};
6✔
358
   mask_init(&mask, length);
6✔
359

360
   bool covered = false;
6✔
361
   for (driver_info_t *it = di; it; it = it->chain_decl) {
18✔
362
      const tree_kind_t kind = tree_kind(it->prefix);
14✔
363
      if (kind != T_ARRAY_REF && kind != T_ARRAY_SLICE && kind != T_RECORD_REF)
14✔
364
         goto out_free;
1✔
365

366
      tree_t value = tree_value(it->prefix);
13✔
367
      if (tree_kind(value) != T_REF)
13✔
368
         goto out_free;
1✔
369

370
      assert(tree_ref(value) == what);
12✔
371

372
      switch (kind) {
12✔
373
      case T_ARRAY_REF:
5✔
374
         {
375
            assert(tree_params(it->prefix) == 1);
5✔
376
            tree_t p0 = tree_value(tree_param(it->prefix, 0));
5✔
377

378
            int64_t ival;
5✔
379
            if (!folded_int(p0, &ival))
5✔
380
               goto out_free;
×
381

382
            const int zero = rkind == RANGE_TO ? ival - left : ival - right;
5✔
383
            if (mask_test(&mask, zero))
5✔
384
               goto out_free;
×
385

386
            mask_set(&mask, zero);
5✔
387
         }
388
         break;
5✔
389

390
      case T_ARRAY_SLICE:
2✔
391
         {
392
            tree_t r = tree_range(it->prefix, 0);
2✔
393

394
            int64_t low, high;
2✔
395
            if (!folded_bounds(r, &low, &high) || high < low)
2✔
396
               goto out_free;
×
397

398
            const int count = high - low + 1;
2✔
399
            const int zero = rkind == RANGE_TO ? low - left : low - right;
2✔
400

401
            if (mask_test_range(&mask, zero, count))
2✔
402
               goto out_free;
×
403

404
            mask_set_range(&mask, zero, count);
2✔
405
         }
406
         break;
2✔
407

408
      case T_RECORD_REF:
5✔
409
         {
410
            const int pos = tree_pos(tree_ref(it->prefix));
5✔
411

412
            if (mask_test(&mask, pos))
5✔
413
               goto out_free;
×
414

415
            mask_set(&mask, pos);
5✔
416
         }
417
         break;
418

419
      default:
×
420
         goto out_free;
×
421
      }
422
   }
423

424
   covered = (mask_popcount(&mask) == length);
4✔
425

426
 out_free:
6✔
427
   mask_free(&mask);
6✔
428
   return covered;
6✔
429
}
430

431
LCOV_EXCL_START
432
void dump_drivers(driver_set_t *ds)
433
{
434
   const void *key;
435
   void *value;
436
   for (hash_iter_t it = HASH_BEGIN; hash_iter(ds->map, &it, &key, &value); ) {
437
      tree_t tree = (tree_t)key;
438
      driver_info_t *di = value;
439

440
      const tree_kind_t kind = tree_kind(tree);
441
      if (kind != T_PROCESS && kind != T_INSTANCE)
442
         continue;
443

444
      printf("%s: { ", istr(tree_ident(tree)));
445
      for (; di; di = di->chain_proc) {
446
         vhdl_dump(di->prefix, 0);
447
         if (di->view)
448
            printf("<%s>", type_pp(tree_type(di->view)));
449
         if (di->tentative)
450
            printf("?");
451
         if (di->chain_proc)
452
            printf(", ");
453
      }
454
      printf(" }\n");
455
   }
456
}
457
LCOV_EXCL_STOP
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

© 2026 Coveralls, Inc