• 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

87.71
/src/vlog/vlog-udp.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 "ident.h"
20
#include "mir/mir-node.h"
21
#include "mir/mir-unit.h"
22
#include "vlog/vlog-node.h"
23
#include "vlog/vlog-number.h"
24

25
#include <assert.h>
26
#include <stdlib.h>
27

28
#define CANNOT_HANDLE(v) do {                                           \
29
      fatal_at(vlog_loc(v), "cannot handle %s in %s" ,                  \
30
               vlog_kind_str(vlog_kind(v)), __FUNCTION__);              \
31
   } while (0)
32

33
static mir_value_t vlog_lower_rvalue(mir_unit_t *mu, vlog_node_t v)
4✔
34
{
35
   switch (vlog_kind(v)) {
4✔
36
   case V_NUMBER:
4✔
37
      {
38
         number_t num = vlog_number(v);
4✔
39
         assert(number_width(num) == 1);
4✔
40

41
         mir_type_t t_logic = mir_vec4_type(mu, 1, false);
4✔
42
         return mir_const_vec(mu, t_logic, number_bit(num, 0), 1);
4✔
43
      }
UNCOV
44
   default:
×
45
      CANNOT_HANDLE(v);
4✔
46
   }
47
}
48

49
void vlog_lower_udp(mir_unit_t *mu, object_t *obj)
12✔
50
{
51
   vlog_node_t udp = vlog_from_object(obj);
12✔
52
   assert(vlog_kind(udp) == V_INST_BODY);
12✔
53

54
   vlog_node_t table = vlog_stmt(udp, 0);
12✔
55
   assert(vlog_kind(table) == V_UDP_TABLE);
12✔
56

57
   const vlog_udp_kind_t kind = vlog_subkind(table);
12✔
58

59
   mir_block_t start_bb = mir_add_block(mu);
12✔
60
   assert(start_bb.id == 1);
12✔
61

62
   vlog_node_t out_decl = vlog_ref(vlog_port(udp, 0));
12✔
63
   assert(vlog_kind(out_decl) == V_PORT_DECL);
12✔
64
   assert(vlog_subkind(out_decl) == V_PORT_OUTPUT);
12✔
65

66
   int hops;
12✔
67
   mir_value_t out_var = mir_search_object(mu, out_decl, &hops);
12✔
68
   assert(!mir_is_null(out_var));
12✔
69

70
   const int nports = vlog_ports(udp);
12✔
71
   mir_value_t *in_vars LOCAL = xmalloc_array(nports - 1, sizeof(mir_value_t));
24✔
72
   for (int i = 1; i < nports; i++) {
40✔
73
      vlog_node_t decl = vlog_ref(vlog_port(udp, i));
28✔
74
      assert(vlog_kind(decl) == V_PORT_DECL);
28✔
75
      assert(vlog_subkind(decl) == V_PORT_INPUT);
28✔
76

77
      int hops;
28✔
78
      in_vars[i - 1] = mir_search_object(mu, decl, &hops);
28✔
79
      assert(!mir_is_null(in_vars[i - 1]));
28✔
80
   }
81

82
   mir_type_t t_offset = mir_offset_type(mu);
12✔
83
   mir_type_t t_logic = mir_vec4_type(mu, 1, false);
12✔
84
   mir_type_t t_time = mir_time_type(mu);
12✔
85

86
   mir_value_t result_var = mir_add_var(mu, t_logic, MIR_NULL_STAMP,
12✔
87
                                        ident_new("result"), MIR_VAR_TEMP);
88

89
   {
90
      mir_value_t upref = mir_build_var_upref(mu, hops, out_var.id);
12✔
91
      mir_value_t out = mir_build_load(mu, upref);
12✔
92
      mir_value_t one = mir_const(mu, t_offset, 1);
12✔
93
      mir_build_drive_signal(mu, out, one);
12✔
94

95
      for (int i = 1; i < nports; i++) {
40✔
96
         mir_value_t upref = mir_build_var_upref(mu, hops, in_vars[i - 1].id);
28✔
97
         mir_value_t nets = mir_build_load(mu, upref);
28✔
98
         mir_build_sched_event(mu, nets, one);
28✔
99
      }
100

101
      if (vlog_stmts(table) > 0) {
12✔
102
         vlog_node_t init = vlog_value(vlog_stmt(table, 0));
4✔
103
         mir_build_map_const(mu, vlog_lower_rvalue(mu, init), out, one);
4✔
104
      }
105

106
      mir_build_return(mu, MIR_NULL_VALUE);
12✔
107
   }
108

109
   mir_block_t wait_bb = mir_add_block(mu);
12✔
110

111
   mir_set_cursor(mu, start_bb, MIR_APPEND);
12✔
112

113
   {
114
      mir_value_t one = mir_const(mu, t_offset, 1);
12✔
115
      mir_value_t zero = mir_const(mu, t_time, 1);
12✔
116
      mir_value_t logic0 = mir_const_vec(mu, t_logic, 0, 0);
12✔
117
      mir_value_t logic1 = mir_const_vec(mu, t_logic, 1, 0);
12✔
118
      mir_value_t logicX = mir_const_vec(mu, t_logic, 1, 1);
12✔
119

120
      mir_value_t level_map[127];
12✔
121
      level_map['0'] = logic0;
12✔
122
      level_map['1'] = logic1;
12✔
123
      level_map['x'] = level_map['X'] = logicX;
12✔
124

125
      mir_value_t *mem LOCAL = xmalloc_array(nports * 2, sizeof(mir_value_t));
24✔
126
      mir_value_t *in_regs = mem, *in_nets = mem + nports;
12✔
127

128
      for (int i = 1; i < nports; i++) {
40✔
129
         mir_value_t upref = mir_build_var_upref(mu, hops, in_vars[i - 1].id);
28✔
130
         mir_value_t nets = mir_build_load(mu, upref);
28✔
131
         mir_value_t value = mir_build_load(mu, mir_build_resolved(mu, nets));
28✔
132
         in_regs[i - 1] = mir_build_pack(mu, t_logic, value);
28✔
133
         in_nets[i - 1] = nets;
28✔
134
      }
135

136
      mir_block_t test_bb = start_bb;
12✔
137

138
      const int nentries = vlog_params(table);
12✔
139
      for (int i = 0; i < nentries; i++) {
100✔
140
         vlog_node_t entry = vlog_param(table, i);
88✔
141
         assert(vlog_kind(entry) == V_UDP_ENTRY);
88✔
142

143
         mir_block_t hit_bb = mir_add_block(mu);
88✔
144
         mir_value_t and = MIR_NULL_VALUE;
88✔
145

146
         int pos = 0;
88✔
147
         for (int j = 0; j < nports - 1; j++) {
280✔
148
            mir_value_t cmp = MIR_NULL_VALUE;
192✔
149
            vlog_node_t sym = vlog_param(entry, pos++);
192✔
150
            switch (vlog_kind(sym)) {
192✔
151
            case V_UDP_LEVEL:
120✔
152
               switch (vlog_ival(sym)) {
120✔
153
               case '0':
80✔
154
               case '1':
155
               case 'x':
156
               case 'X':
157
                  cmp = mir_build_cmp(mu, MIR_CMP_EQ, in_regs[j],
160✔
158
                                      level_map[vlog_ival(sym)]);
80✔
159
                  break;
80✔
UNCOV
160
               case '*':
×
UNCOV
161
                  cmp = mir_build_event_flag(mu, in_nets[j], one);
×
UNCOV
162
                  break;
×
UNCOV
163
               case 'b':
×
164
                  {
165
                     mir_value_t is0 =
×
166
                        mir_build_cmp(mu, MIR_CMP_EQ, in_regs[j], logic0);
×
167
                     mir_value_t is1 =
×
168
                        mir_build_cmp(mu, MIR_CMP_EQ, in_regs[j], logic1);
×
UNCOV
169
                     cmp = mir_build_and(mu, is0, is1);
×
170
                  }
171
                  break;
×
172
               case '?':
173
                  break;
174
               default:
×
UNCOV
175
                  CANNOT_HANDLE(sym);
×
176
               }
177
               break;
178

179
            case V_UDP_EDGE:
72✔
180
               {
181
                  const char left = vlog_ival(vlog_left(sym));
72✔
182
                  const char right = vlog_ival(vlog_right(sym));
72✔
183

184
                  cmp = mir_build_event_flag(mu, in_nets[j], one);
72✔
185

186
                  if (left != '?') {
72✔
187
                     mir_value_t last_ptr =
56✔
188
                        mir_build_last_value(mu, in_nets[j]);
56✔
189
                     mir_value_t last = mir_build_load(mu, last_ptr);
56✔
190
                     mir_value_t packed = mir_build_pack(mu, t_logic, last);
56✔
191
                     mir_value_t eq = mir_build_cmp(mu, MIR_CMP_EQ, packed,
56✔
192
                                                    level_map[(unsigned)left]);
56✔
193
                     cmp = mir_build_and(mu, cmp, eq);
56✔
194
                  }
195

196
                  if (right != '?') {
72✔
197
                     mir_value_t eq = mir_build_cmp(mu, MIR_CMP_EQ, in_regs[j],
64✔
198
                                                    level_map[(unsigned)right]);
64✔
199
                     cmp = mir_build_and(mu, cmp, eq);
64✔
200
                  }
201
               }
202
               break;
203

UNCOV
204
            default:
×
UNCOV
205
               CANNOT_HANDLE(entry);
×
206
            }
207

208
            if (mir_is_null(and))
192✔
209
               and = cmp;
96✔
210
            else if (!mir_is_null(cmp))
96✔
211
               and = mir_build_and(mu, and, cmp);
64✔
212
         }
213

214
         if (kind == V_UDP_SEQ) {
88✔
215
            mir_value_t upref = mir_build_var_upref(mu, hops, out_var.id);
72✔
216
            mir_value_t out = mir_build_load(mu, upref);
72✔
217
            mir_value_t resolved = mir_build_resolved(mu, out);
72✔
218
            mir_value_t cur = mir_build_load(mu, resolved);
72✔
219
            mir_value_t packed = mir_build_pack(mu, t_logic, cur);
72✔
220

221
            vlog_node_t sym = vlog_param(entry, pos++);
72✔
222
            assert(vlog_kind(sym) == V_UDP_LEVEL);
72✔
223

224
            mir_value_t cmp = MIR_NULL_VALUE;
72✔
225
            switch (vlog_ival(sym)) {
72✔
226
            case '0':
32✔
227
            case '1':
228
            case 'x':
229
            case 'X':
230
               cmp = mir_build_cmp(mu, MIR_CMP_EQ, packed,
64✔
231
                                   level_map[vlog_ival(sym)]);
32✔
232
               break;
32✔
233
            case '?':
234
               break;
UNCOV
235
            default:
×
UNCOV
236
               CANNOT_HANDLE(sym);
×
237
            }
238

239
            if (mir_is_null(and))
72✔
240
               and = cmp;
×
241
            else if (!mir_is_null(cmp))
72✔
242
               and = mir_build_and(mu, and, cmp);
32✔
243
         }
244

245
         if (mir_is_null(and)) {
88✔
UNCOV
246
            mir_build_jump(mu, hit_bb);
×
UNCOV
247
            break;
×
248
         }
249
         else {
250
            test_bb = mir_add_block(mu);
88✔
251
            mir_build_cond(mu, and, hit_bb, test_bb);
88✔
252
         }
253

254
         mir_set_cursor(mu, hit_bb, MIR_APPEND);
88✔
255

256
         vlog_node_t sym = vlog_param(entry, pos++);
88✔
257
         assert(vlog_kind(sym) == V_UDP_LEVEL);
88✔
258
         assert(pos == vlog_params(entry));
88✔
259

260
         mir_value_t drive;
88✔
261
         switch (vlog_ival(sym)) {
88✔
262
         case '0':
64✔
263
         case '1':
264
         case 'x':
265
         case 'X':
266
            drive = level_map[vlog_ival(sym)];
64✔
267
            break;
64✔
268
         case '-':
24✔
269
            // No change, skip assignment to output
270
            drive = MIR_NULL_VALUE;
24✔
271
            mir_build_wait(mu, start_bb, MIR_NULL_VALUE);
24✔
272
            mir_set_cursor(mu, test_bb, MIR_APPEND);
24✔
273
            continue;
24✔
UNCOV
274
         default:
×
UNCOV
275
            CANNOT_HANDLE(entry);
×
276
         }
277

278
         mir_build_store(mu, result_var, drive);
64✔
279
         mir_build_jump(mu, wait_bb);
64✔
280

281
         mir_set_cursor(mu, test_bb, MIR_APPEND);
64✔
282
      }
283

284
      mir_set_cursor(mu, test_bb, MIR_APPEND);
12✔
285

286
      if (!mir_block_finished(mu, test_bb)) {
12✔
287
         if (kind == V_UDP_SEQ)
12✔
288
            mir_build_wait(mu, start_bb, MIR_NULL_VALUE);   // Skip assignment
8✔
289
         else {
290
            mir_build_store(mu, result_var, logicX);
4✔
291
            mir_build_jump(mu, wait_bb);
4✔
292
         }
293
      }
294

295
      mir_set_cursor(mu, wait_bb, MIR_APPEND);
12✔
296

297
      mir_value_t result = mir_build_load(mu, result_var);
12✔
298
      const uint8_t strength = kind == V_UDP_COMB ? ST_STRONG : 0;
12✔
299
      mir_value_t drive =
12✔
300
         mir_build_unpack(mu, result, strength, MIR_NULL_VALUE);
12✔
301

302
      mir_value_t upref = mir_build_var_upref(mu, hops, out_var.id);
12✔
303
      mir_value_t out = mir_build_load(mu, upref);
12✔
304
      mir_build_sched_waveform(mu, out, one, drive, zero, zero);
12✔
305

306
      mir_build_wait(mu, start_bb, MIR_NULL_VALUE);
12✔
307
   }
308
}
12✔
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