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

nickg / nvc / 16099227452

06 Jul 2025 12:45PM UTC coverage: 92.335% (+0.05%) from 92.284%
16099227452

push

github

nickg
Handle underscores in Verilog decimal literals

Fixes #1230

18 of 20 new or added lines in 1 file covered. (90.0%)

598 existing lines in 16 files now uncovered.

71069 of 76969 relevant lines covered (92.33%)

564781.41 hits per line

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

85.48
/src/vlog/vlog-number.c
1
//
2
//  Copyright (C) 2023-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 "diag.h"
20
#include "fbuf.h"
21
#include "vlog/vlog-number.h"
22

23
#include <assert.h>
24
#include <inttypes.h>
25
#include <string.h>
26
#include <stdlib.h>
27

28
typedef enum {
29
   RADIX_STR = 0,
30
   RADIX_BIN = 2,
31
   RADIX_DEC = 10,
32
   RADIX_HEX = 16,
33
} vlog_radix_t;
34

35
typedef struct _bignum {
36
   unsigned width;
37
   bool     issigned;
38
   uint64_t words[];
39
} bignum_t;
40

41
#define BIGNUM_WORDS(w) (((w) + 63) / 64)
42

43
__attribute__((always_inline))
44
static inline int bignum_words(bignum_t *bn)
12,897✔
45
{
46
   return BIGNUM_WORDS(bn->width);
12,897✔
47
}
48

49
__attribute__((always_inline))
50
static inline uint64_t *bignum_abits(bignum_t *bn)
52,637✔
51
{
52
   return bn->words;
52,637✔
53
}
54

55
__attribute__((always_inline))
56
static inline uint64_t *bignum_bbits(bignum_t *bn)
8,385✔
57
{
58
   return bn->words + bignum_words(bn);
8,385✔
59
}
60

61
__attribute__((always_inline))
62
static inline int bignum_abit(bignum_t *bn, unsigned n)
439✔
63
{
64
   assert(n < bn->width);
×
65
   return (bignum_abits(bn)[n / 64] >> (n % 64)) & 1;
439✔
66
}
67

68
__attribute__((always_inline))
69
static inline int bignum_bbit(bignum_t *bn, unsigned n)
439✔
70
{
71
   assert(n < bn->width);
439✔
72
   return (bignum_bbits(bn)[n / 64] >> (n % 64)) & 1;
439✔
73
}
74

75
static inline void bignum_set_abit(bignum_t *bn, unsigned n, int b)
49,623✔
76
{
77
   if (n < bn->width)
49,623✔
78
      bignum_abits(bn)[n / 64] |= (uint64_t)(b & 1) << (n % 64);
49,615✔
79
}
49,623✔
80

81
static inline void bignum_set_bbit(bignum_t *bn, unsigned n, int b)
464✔
82
{
83
   if (n < bn->width)
464✔
84
      bignum_bbits(bn)[n / 64] |= (uint64_t)(b & 1) << (n % 64);
464✔
85
}
464✔
86

87
static inline void bignum_set_nibble(bignum_t *bn, unsigned n, int value)
12,275✔
88
{
89
   for (int i = 0; i < 4; i++)
61,375✔
90
      bignum_set_abit(bn, n + i, value >> i);
49,100✔
91
}
12,275✔
92

93
number_t number_new(const char *str, const loc_t *loc)
2,165✔
94
{
95
   int width = 32;
2,165✔
96
   const char *p = str;
2,165✔
97
   if (*p == '"')
2,165✔
98
      width = 8 * (strlen(str) - 2);
523✔
99
   else {
100
      const char *tick = strchr(str, '\'');
1,642✔
101
      if (tick == str)
1,642✔
102
         p++;
47✔
103
      else if (tick != NULL) {
1,595✔
104
         char *eptr;
131✔
105
         width = strtol(str, &eptr, 10);
131✔
106
         if (eptr != tick)
131✔
107
            should_not_reach_here();
108

109
         p = tick + 1;
131✔
110
      }
111
   }
112

113
   vlog_radix_t radix = RADIX_DEC;
2,165✔
114
   switch (*p) {
2,165✔
115
   case 'b': radix = RADIX_BIN; p++; break;
72✔
116
   case 'h': radix = RADIX_HEX; p++; break;
67✔
117
   case 'd': radix = RADIX_DEC; p++; break;
39✔
118
   case '"': radix = RADIX_STR; p++; break;
523✔
119
   default: break;
120
   }
121

122
   number_t result = { .bits = 0 };
2,165✔
123
   const int nwords = MAX(1, BIGNUM_WORDS(width));
2,165✔
124
   result.big = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
2,165✔
125
   result.big->width = width;
2,165✔
126
   result.big->issigned = false;
2,165✔
127

128
   for (int i = 0; i < nwords * 2; i++)
7,361✔
129
      result.big->words[i] = 0;
5,196✔
130

131
   if (radix == RADIX_STR) {
2,165✔
132
      for (int bit = width - 8; !(*p == '"' && *(p + 1) == '\0');
6,601✔
133
           p++, bit -= 8) {
6,078✔
134
         const uint8_t byte = *p;
6,078✔
135
         bignum_set_nibble(result.big, bit, byte);
6,078✔
136
         bignum_set_nibble(result.big, bit + 4, byte >> 4);
6,078✔
137
      }
138
   }
139
   else if (radix == RADIX_DEC) {
1,642✔
140
      for (; *p; p++) {
3,264✔
141
         switch (*p) {
1,761✔
142
         case '0'...'9':
1,759✔
143
            {
144
               const uint64_t ten[] = { 10 };
1,759✔
145
               const uint64_t digit[] = { *p - '0' };
1,759✔
146

147
               vec2_mul(result.big->words, width, ten, 64);
1,759✔
148
               vec2_add(result.big->words, width, digit, 64);
1,759✔
149
            }
150
            break;
1,759✔
151
         case '_':
2✔
152
            continue;
2✔
NEW
153
         default:
×
NEW
154
            error_at(loc, "invalid character '%c' in number %s", *p, str);
×
155
         }
156
      }
157
   }
158
   else {
159
      const char *start = p;
160
      for (; *(p + 1); p++);
253✔
161

162
      for (int bit = 0; p >= start; p--) {
389✔
163
         switch (radix) {
252✔
164
         case RADIX_BIN:
117✔
165
            {
166
               switch (*p) {
117✔
167
               case '0':
168
                  break;
169
               case '1':
59✔
170
                  bignum_set_abit(result.big, bit, 1);
59✔
171
                  break;
59✔
172
               case 'x':
24✔
173
                  bignum_set_abit(result.big, bit, 1);
24✔
174
                  bignum_set_bbit(result.big, bit, 1);
24✔
175
                  break;
24✔
176
               case 'z':
×
177
                  bignum_set_bbit(result.big, bit, 1);
×
178
                  break;
×
179
               case '_':
1✔
180
                  continue;
1✔
181
               default:
×
182
                  error_at(loc, "invalid character '%c' in number %s", *p, str);
×
183
               }
184

185
               if (bit >= width) {
116✔
186
                  warn_at(loc, "excess digits in binary constant %s", str);
1✔
187
                  return result;
1✔
188
               }
189

190
               bit++;
115✔
191
            }
192
            break;
115✔
193

194
         case RADIX_HEX:
135✔
195
            {
196
               switch (*p) {
135✔
197
               case 'x':
198
                  for (int i = 0; i < 4; i++) {
20✔
199
                     bignum_set_abit(result.big, bit + i, 1);
16✔
200
                     bignum_set_bbit(result.big, bit + i, 1);
16✔
201
                  }
202
                  break;
203
               case 'z':
204
                  for (int i = 0; i < 4; i++)
×
205
                     bignum_set_bbit(result.big, bit + i, 1);
×
206
                  break;
207
               case '0'...'9':
83✔
208
                  bignum_set_nibble(result.big, bit, *p - '0');
83✔
209
                  break;
83✔
210
               case 'a'...'f':
34✔
211
                  bignum_set_nibble(result.big, bit, 10 + *p - 'a');
34✔
212
                  break;
34✔
213
               case 'A'...'F':
2✔
214
                  bignum_set_nibble(result.big, bit, 10 + *p - 'A');
2✔
215
                  break;
2✔
216
               case '_':
12✔
217
                  continue;
12✔
218
               default:
×
219
                  error_at(loc, "invalid character '%c' in number %s", *p, str);
×
220
               }
221

222
               if (bit >= width) {
123✔
223
                  warn_at(loc, "excess digits in hex constant %s", str);
1✔
224
                  return result;
1✔
225
               }
226

227
               bit += 4;
122✔
228
            }
229
            break;
122✔
230

231
         default:
×
232
            should_not_reach_here();
233
         }
234
      }
235
   }
236

237
   return result;
2,163✔
238
}
239

240
void number_free(number_t *val)
218✔
241
{
242
   if (val->common.tag == TAG_BIGNUM)
218✔
243
      free(val->big);
218✔
244

245
   val->bits = 0;
218✔
246
}
218✔
247

248
void number_print(number_t val, text_buf_t *tb)
50✔
249
{
250
   if (number_is_defined(val)) {
50✔
251
      if (val.big->width == 32 && !val.big->issigned) {
49✔
252
         tb_printf(tb, "%"PRIi64, bignum_abits(val.big)[0]);
40✔
253
         return;
40✔
254
      }
255
      else if (val.big->width > 1 && val.big->width <= 32) {
9✔
256
         tb_printf(tb, "%u'%sd%"PRIu64, val.big->width,
8✔
257
                   val.big->issigned ? "s" : "", bignum_abits(val.big)[0]);
4✔
258
         return;
4✔
259
      }
260
   }
261

262
   tb_printf(tb, "%u'b", number_width(val));
6✔
263

264
   static const char map[] = "01zx";
6✔
265

266
   bool leading = true;
6✔
267
   for (int i = val.big->width - 1; i >= 0; i--) {
297✔
268
      const vlog_logic_t bit = number_bit(val, i);
291✔
269
      if (leading && bit != LOGIC_0)
291✔
270
         leading = false;
271
      else if (leading)
287✔
272
         continue;
253✔
273
      tb_append(tb, map[bit]);
38✔
274
   }
275

276
   if (leading)
6✔
277
      tb_append(tb, '0');
2✔
278
}
279

280
bool number_is_defined(number_t val)
7,454✔
281
{
282
   const int nwords = bignum_words(val.big);
7,454✔
283
   const uint64_t *bbits = bignum_bbits(val.big);
7,454✔
284

285
   for (int i = 0; i < nwords; i++) {
17,268✔
286
      if (bbits[i] != 0)
9,861✔
287
         return false;
288
   }
289

290
   return true;
291
}
292

293
int64_t number_integer(number_t val)
3,207✔
294
{
295
   assert(number_width(val) <= 64);
3,207✔
296
   assert(number_is_defined(val));
3,207✔
297

298
   return bignum_abits(val.big)[0];
3,207✔
299
}
300

301
unsigned number_width(number_t val)
4,758✔
302
{
303
   return val.big->width;
4,758✔
304
}
305

306
vlog_logic_t number_bit(number_t val, unsigned n)
439✔
307
{
308
   return bignum_abit(val.big, n) | (bignum_bbit(val.big, n) << 1);
439✔
309
}
310

311
uint8_t number_byte(number_t val, unsigned n)
2,583✔
312
{
313
   assert(number_is_defined(val));
2,583✔
314
   assert(n < bignum_words(val.big) * 8);
2,583✔
315

316
   const uint64_t *abits = bignum_abits(val.big);
2,583✔
317
   return (abits[n / 8] >> (n * 8) % 64) & 0xff;
2,583✔
318
}
319

320
number_t number_pack(const uint8_t *bits, unsigned width)
200✔
321
{
322
   const int nwords = BIGNUM_WORDS(width);
200✔
323
   bignum_t *bn = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
200✔
324
   bn->width = width;
200✔
325
   bn->issigned = 0;
200✔
326

327
   for (int i = 0; i < nwords * 2; i++)
600✔
328
      bn->words[i] = 0;
400✔
329

330
   for (int i = 0; i < width; i++) {
624✔
331
      bignum_set_abit(bn, i, bits[width - 1 - i]);
424✔
332
      bignum_set_bbit(bn, i, bits[width - 1 - i] >> 1);
424✔
333
   }
334

335
   return (number_t){ .big = bn };
200✔
336
}
337

338
bool number_equal(number_t a, number_t b)
9✔
339
{
340
   if (a.big->width != b.big->width)
9✔
341
      return false;
342
   else if (a.big->issigned != b.big->issigned)
9✔
343
      return false;
344

345
   const int nwords = bignum_words(a.big);
9✔
346
   for (int i = 0; i < nwords; i++) {
17✔
347
      if (a.big->words[i] != b.big->words[i])
9✔
348
         return false;
349
   }
350

351
   return true;
352
}
353

354
bool number_truthy(number_t a)
12✔
355
{
356
   const int nwords = bignum_words(a.big);
12✔
357
   for (int i = 0; i < nwords; i++) {
16✔
358
      if (bignum_bbits(a.big)[i] != 0)
12✔
359
         return false;
360
      else if (bignum_abits(a.big)[i] != 0)
8✔
361
         return true;
362
   }
363

364
   return false;
365
}
366

367
void number_write(number_t val, fbuf_t *f)
1,908✔
368
{
369
   fbuf_put_int(f, val.big->issigned ? -val.big->width : val.big->width);
1,908✔
370

371
   const int nwords = bignum_words(val.big);
1,908✔
372
   write_raw(val.big->words, nwords * 2  * sizeof(uint64_t), f);
1,908✔
373
}
1,908✔
374

375
number_t number_read(fbuf_t *f)
×
376
{
377
   const int64_t enc = fbuf_get_int(f);
×
378
   const unsigned width = llabs(enc);
×
379
   const int nwords = BIGNUM_WORDS(width);
×
380

381
   number_t result = { .bits = 0 };
×
382
   result.big = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
×
383
   result.big->width = width;
×
384
   result.big->issigned = enc < 0;
×
385

386
   read_raw(result.big->words, nwords * 2 * sizeof(uint64_t), f);
×
387

388
   return result;
×
389
}
390

391
number_t number_add(number_t a, number_t b)
×
392
{
393
   const int width = MAX(a.big->width, b.big->width) + 1;
×
394
   const int nwords = BIGNUM_WORDS(width);
×
395

396
   number_t result = { .bits = 0 };
×
397
   result.big = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
×
398
   result.big->width = width;
×
399
   result.big->issigned = a.big->issigned || b.big->issigned;
×
400

401
   assert(nwords == 1);  // TODO
×
402

403
   bignum_abits(result.big)[0] =
×
404
      bignum_abits(a.big)[0] + bignum_abits(b.big)[0];
×
405
   bignum_bbits(result.big)[0] =
×
406
      bignum_bbits(a.big)[0] | bignum_bbits(b.big)[0];
×
407

408
   return result;
×
409
}
410

411
number_t number_sub(number_t a, number_t b)
4✔
412
{
413
   const int width = MAX(a.big->width, b.big->width) + 1;
4✔
414
   const int nwords = BIGNUM_WORDS(width);
4✔
415

416
   number_t result = { .bits = 0 };
4✔
417
   result.big = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
4✔
418
   result.big->width = width;
4✔
419
   result.big->issigned = a.big->issigned || b.big->issigned;
4✔
420

421
   assert(nwords == 1);  // TODO
4✔
422

423
   bignum_abits(result.big)[0] =
4✔
424
      bignum_abits(a.big)[0] - bignum_abits(b.big)[0];
4✔
425
   bignum_bbits(result.big)[0] =
4✔
426
      bignum_bbits(a.big)[0] | bignum_bbits(b.big)[0];
4✔
427

428
   return result;
4✔
429
}
430

431
number_t number_logical_equal(number_t a, number_t b)
12✔
432
{
433
   const int width = 1;
12✔
434
   const int nwords = BIGNUM_WORDS(width);
12✔
435

436
   number_t result = { .bits = 0 };
12✔
437
   result.big = xmalloc_flex(sizeof(bignum_t), nwords * 2, sizeof(uint64_t));
12✔
438
   result.big->width = width;
12✔
439
   result.big->issigned = false;
12✔
440

441
   assert(bignum_words(a.big) == 1);  // TODO
12✔
442
   assert(bignum_words(b.big) == 1);  // TODO
12✔
443

444
   bignum_abits(result.big)[0] =
12✔
445
      bignum_abits(a.big)[0] == bignum_abits(b.big)[0];
12✔
446
   bignum_bbits(result.big)[0] =
12✔
447
      bignum_bbits(a.big)[0] | bignum_bbits(b.big)[0];
12✔
448

449
   return result;
12✔
450

451
}
452

453
void vec2_add(uint64_t *a, size_t asize, const uint64_t *b, size_t bsize)
1,759✔
454
{
455
   if (asize <= 64 && bsize <= 64)
1,759✔
456
      a[0] += b[0];
1,759✔
457
   else
458
      should_not_reach_here();   // TODO
459
}
1,759✔
460

461
void vec2_mul(uint64_t *a, size_t asize, const uint64_t *b, size_t bsize)
1,759✔
462
{
463
   if (asize <= 64 && bsize <= 64)
1,759✔
464
      a[0] *= b[0];
1,759✔
465
   else
466
      should_not_reach_here();   // TODO
467
}
1,759✔
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