• 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

92.4
/src/vlog/vlog-trans.c
1
//
2
//  Copyright (C) 2024-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 "diag.h"
21
#include "hash.h"
22
#include "tree.h"
23
#include "type.h"
24
#include "vlog/vlog-defs.h"
25
#include "vlog/vlog-node.h"
26
#include "vlog/vlog-number.h"
27
#include "vlog/vlog-phase.h"
28
#include "vlog/vlog-util.h"
29

30
#include <assert.h>
31

32
#define CANNOT_HANDLE(v) do {                                           \
33
      fatal_at(vlog_loc(v), "cannot handle %s in %s" ,                  \
34
               vlog_kind_str(vlog_kind(v)), __FUNCTION__);              \
35
   } while (0)
36

37
typedef struct {
38
   tree_t  out;
39
   hash_t *map;
40
} trans_gen_t;
41

42
static tree_t trans_expr(trans_gen_t *g, vlog_node_t v)
316✔
43
{
44
   switch (vlog_kind(v)) {
316✔
45
   case V_NUMBER:
308✔
46
      {
47
         number_t n = vlog_number(v);
308✔
48
         type_t std_int = std_type(NULL, STD_INTEGER);
308✔
49

50
         tree_t lit = tree_new(T_LITERAL);
308✔
51
         tree_set_subkind(lit, L_INT);
308✔
52
         tree_set_type(lit, std_int);
308✔
53

54
         if (number_is_defined(n))
308✔
55
            tree_set_ival(lit, number_integer(n));
304✔
56
         else
57
            tree_set_ival(lit, 0);
4✔
58

59
         return lit;
60
      }
61
   case V_REF:
4✔
62
      {
63
         tree_t decl = hash_get(g->map, vlog_ref(v));
4✔
64
         if (decl == NULL)
4✔
65
            fatal_at(vlog_loc(v), "missing VHDL declaration for %s",
×
66
                     istr(vlog_ident(v)));
67

68
         if (tree_kind(decl) == T_CONST_DECL && tree_has_value(decl)) {
4✔
69
            tree_t value = tree_value(decl);
×
70
            if (is_literal(value))
×
71
               return value;
72
         }
73

74
         return make_ref(decl);
4✔
75
      }
76
   case V_BINARY:
4✔
77
      {
78
         tree_t left = trans_expr(g, vlog_left(v));
4✔
79
         tree_t right = trans_expr(g, vlog_right(v));
4✔
80
         assert(type_eq(tree_type(left), tree_type(right)));
4✔
81

82
         type_t std_int = std_type(NULL, STD_INTEGER);
4✔
83
         if (!type_eq(tree_type(left), std_int))
4✔
84
            fatal_at(vlog_loc(v), "only integer expressions are supported");
×
85

86
         tree_t t = tree_new(T_FCALL);
4✔
87
         tree_set_loc(t, vlog_loc(v));
4✔
88
         tree_set_type(t, std_int);
4✔
89

90
         switch (vlog_subkind(v)) {
4✔
91
         case V_BINARY_MINUS:
4✔
92
            tree_set_ident(t, well_known(W_OP_MINUS));
4✔
93
            tree_set_ref(t, std_func(ident_new("STD.STANDARD.\"-\"(I)I")));
4✔
94
            break;
4✔
95
         case V_BINARY_PLUS:
×
96
            tree_set_ident(t, well_known(W_OP_ADD));
×
97
            tree_set_ref(t, std_func(ident_new("STD.STANDARD.\"+\"(I)I")));
×
98
            break;
×
99
         default:
×
100
            CANNOT_HANDLE(v);
×
101
         }
102

103
         add_param(t, left, P_POS, NULL);
4✔
104
         add_param(t, right, P_POS, NULL);
4✔
105

106
         return t;
4✔
107
      }
108
   default:
×
109
      CANNOT_HANDLE(v);
×
110
   }
111
}
112

113
static type_t trans_type(trans_gen_t *g, vlog_node_t decl,
592✔
114
                         verilog_type_t scalar_type,
115
                         verilog_type_t packed_type)
116
{
117
   const int nranges = vlog_ranges(decl);
592✔
118
   if (nranges > 0) {
592✔
119
      type_t packed = verilog_type(packed_type);
140✔
120

121
      tree_t c = tree_new(T_CONSTRAINT);
140✔
122
      tree_set_subkind(c, C_INDEX);
140✔
123
      tree_set_loc(c, vlog_loc(decl));
140✔
124

125
      for (int i = 0; i < nranges; i++) {
280✔
126
         type_t index_type = index_type_of(packed, i);
140✔
127
         vlog_node_t vr = vlog_range(decl, i);
140✔
128

129
         tree_t left = trans_expr(g, vlog_left(vr));
140✔
130
         tree_t right = trans_expr(g, vlog_right(vr));
140✔
131

132
         int64_t ileft, iright;
140✔
133
         const bool left_is_const = folded_int(left, &ileft);
140✔
134
         const bool right_is_const = folded_int(right, &iright);
140✔
135

136
         range_kind_t dir;
140✔
137
         if (left_is_const && right_is_const)
140✔
138
            dir = ileft < iright ? RANGE_TO : RANGE_DOWNTO;
136✔
139
         else if (left_is_const)
4✔
140
            dir = RANGE_TO;   // Heuristic
141
         else
142
            dir = RANGE_DOWNTO;   // Heuristic
4✔
143

144
         tree_t r = tree_new(T_RANGE);
140✔
145
         tree_set_subkind(r, dir);
140✔
146
         tree_set_left(r, left);
140✔
147
         tree_set_right(r, right);
140✔
148
         tree_set_loc(r, vlog_loc(decl));
140✔
149
         tree_set_type(r, index_type);
140✔
150

151
         tree_add_range(c, r);
140✔
152
      }
153

154
      type_t sub = type_new(T_SUBTYPE);
140✔
155
      type_set_base(sub, packed);
140✔
156
      type_set_constraint(sub, c);
140✔
157

158
      return sub;
140✔
159
   }
160
   else
161
      return verilog_type(scalar_type);
452✔
162
}
163

164
static type_t trans_var_type(trans_gen_t *g, vlog_node_t v)
268✔
165
{
166
   vlog_node_t type = vlog_type(v);
268✔
167
   return trans_type(g, type, VERILOG_LOGIC, VERILOG_LOGIC_ARRAY);
268✔
168
}
169

170
static type_t trans_net_type(trans_gen_t *g, vlog_node_t v)
324✔
171
{
172
   vlog_node_t type = vlog_type(v);
324✔
173
   return trans_type(g, type, VERILOG_WIRE, VERILOG_WIRE_ARRAY);
324✔
174
}
175

176
static void trans_port_decl(trans_gen_t *g, vlog_node_t v)
246✔
177
{
178
   static const port_mode_t map[] = {
246✔
179
      [V_PORT_INPUT] = PORT_IN,
180
      [V_PORT_OUTPUT] = PORT_OUT,
181
      [V_PORT_INOUT] = PORT_INOUT,
182
   };
183

184
   const v_port_kind_t kind = vlog_subkind(v);
246✔
185

186
   tree_t t = tree_new(T_PORT_DECL);
246✔
187
   tree_set_ident(t, vlog_ident(v));
246✔
188
   tree_set_subkind(t, map[kind]);
246✔
189
   tree_set_class(t, C_SIGNAL);
246✔
190

191
   vlog_node_t net = vlog_ref(v);
246✔
192
   if (vlog_is_net(net)) {
246✔
193
      type_t type = trans_net_type(g, net);
222✔
194
      tree_set_type(t, type);
222✔
195
   }
196
   else {
197
      type_t type = trans_var_type(g, net);
24✔
198
      tree_set_type(t, type);
24✔
199
   }
200

201
   tree_add_port(g->out, t);
246✔
202
}
246✔
203

204
static void trans_param_decl(trans_gen_t *g, vlog_node_t v)
5✔
205
{
206
   tree_t t = tree_new(T_GENERIC_DECL);
5✔
207
   tree_set_ident(t, vlog_ident(v));
5✔
208
   tree_set_class(t, C_CONSTANT);
5✔
209
   tree_set_subkind(t, PORT_IN);
5✔
210

211
   // XXX: should be integer for untyped only
212
   /// tree_set_type(t, trans_var_type(g, v));
213
   tree_set_type(t, std_type(NULL, STD_INTEGER));
5✔
214

215
   tree_add_generic(g->out, t);
5✔
216

217
   hash_put(g->map, v, t);
5✔
218
}
5✔
219

220
static void trans_localparam(trans_gen_t *g, vlog_node_t v)
29✔
221
{
222
   tree_t t = tree_new(T_CONST_DECL);
29✔
223
   tree_set_ident(t, vlog_ident(v));
29✔
224
   tree_set_flag(t, TREE_F_GLOBALLY_STATIC);
29✔
225

226
   if (vlog_has_value(v)) {
29✔
227
      tree_t value = trans_expr(g, vlog_value(v));
28✔
228
      tree_set_value(t, value);
28✔
229
      tree_set_type(t, tree_type(value));
28✔
230
   }
231
   else
232
      assert(error_count() > 0);
1✔
233

234
   tree_add_decl(g->out, t);
29✔
235

236
   hash_put(g->map, v, t);
29✔
237
}
29✔
238

239
static void trans_var_decl(trans_gen_t *g, vlog_node_t v)
244✔
240
{
241
   type_t type = trans_var_type(g, v);
244✔
242

243
   tree_t t = tree_new(T_SIGNAL_DECL);
244✔
244
   tree_set_ident(t, vlog_ident(v));
244✔
245
   tree_set_type(t, type);
244✔
246

247
   tree_add_decl(g->out, t);
244✔
248
}
244✔
249

250
static void trans_net_decl(trans_gen_t *g, vlog_node_t decl)
102✔
251
{
252
   type_t type = trans_net_type(g, decl);
102✔
253

254
   tree_t t = tree_new(T_SIGNAL_DECL);
102✔
255
   tree_set_ident(t, vlog_ident(decl));
102✔
256
   tree_set_type(t, type);
102✔
257

258
   tree_add_decl(g->out, t);
102✔
259
}
102✔
260

261
void vlog_trans(vlog_node_t mod, tree_t out)
211✔
262
{
263
   assert(is_top_level(mod));
211✔
264

265
   trans_gen_t gen = {
211✔
266
      .map = hash_new(16),
211✔
267
      .out = out,
268
   };
269

270
   hset_t *ports = hset_new(16);
211✔
271
   const int nports = vlog_ports(mod);
211✔
272
   for (int i = 0; i < nports; i++) {
457✔
273
      vlog_node_t ref = vlog_port(mod, i);
246✔
274
      assert(vlog_kind(ref) == V_REF);
246✔
275

276
      // Do not translate the associated var/net declaration twice
277
      vlog_node_t port = vlog_ref(ref);
246✔
278
      hset_insert(ports, vlog_ref(port));
246✔
279
   }
280

281
   const int ndecls = vlog_decls(mod);
211✔
282
   for (int i = 0; i < ndecls; i++) {
1,083✔
283
      vlog_node_t d = vlog_decl(mod, i);
872✔
284
      switch (vlog_kind(d)) {
872✔
285
      case V_PORT_DECL:
286
         break;   // Translated below
287
      case V_VAR_DECL:
268✔
288
         if (!hset_contains(ports, d))
268✔
289
            trans_var_decl(&gen, d);
244✔
290
         break;
291
      case V_NET_DECL:
324✔
292
         if (!hset_contains(ports, d))
324✔
293
            trans_net_decl(&gen, d);
102✔
294
         break;
295
      case V_PARAM_DECL:
5✔
296
         trans_param_decl(&gen, d);
5✔
297
         break;
5✔
298
      case V_LOCALPARAM:
29✔
299
         trans_localparam(&gen, d);
29✔
300
         break;
29✔
UNCOV
301
      default:
×
302
         CANNOT_HANDLE(d);
872✔
303
      }
304
   }
305

306
   for (int i = 0; i < nports; i++) {
457✔
307
      vlog_node_t ref = vlog_port(mod, i);
246✔
308
      assert(vlog_kind(ref) == V_REF);
246✔
309

310
      vlog_node_t port = vlog_ref(ref);
246✔
311
      assert(vlog_kind(port) == V_PORT_DECL);
246✔
312
      trans_port_decl(&gen, port);
246✔
313
   }
314

315
   hash_free(gen.map);
211✔
316
   hset_free(ports);
211✔
317
}
211✔
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