-
Notifications
You must be signed in to change notification settings - Fork 521
/
expr.cc
726 lines (636 loc) · 21.9 KB
/
expr.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
/*
* VHDL code generation for expressions.
*
* Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "vhdl_target.h"
#include "support.hh"
#include "state.hh"
#include <iostream>
#include <cassert>
#include <cstring>
/*
* Change the signedness of a vector.
*/
static vhdl_expr *change_signedness(vhdl_expr *e, bool issigned)
{
int msb = e->get_type()->get_msb();
int lsb = e->get_type()->get_lsb();
vhdl_type u(issigned ? VHDL_TYPE_SIGNED : VHDL_TYPE_UNSIGNED, msb, lsb);
return e->cast(&u);
}
/*
* Generate code to ensure that the VHDL expression vhd_e has the
* same signedness as the Verilog expression vl_e.
*/
static vhdl_expr *correct_signedness(vhdl_expr *vhd_e, ivl_expr_t vl_e)
{
bool should_be_signed = ivl_expr_signed(vl_e) != 0;
if (vhd_e->get_type()->get_name() == VHDL_TYPE_UNSIGNED
&& should_be_signed) {
//operand->print();
//std::cout << "^ should be signed but is not" << std::endl;
return change_signedness(vhd_e, true);
}
else if (vhd_e->get_type()->get_name() == VHDL_TYPE_SIGNED
&& !should_be_signed) {
//operand->print();
//std::cout << "^ should be unsigned but is not" << std::endl;
return change_signedness(vhd_e, false);
}
else
return vhd_e;
}
/*
* Convert a constant Verilog string to a constant VHDL string.
*/
static vhdl_expr *translate_string(ivl_expr_t e)
{
// TODO: May need to inspect or escape parts of this
const char *str = ivl_expr_string(e);
return new vhdl_const_string(str);
}
/*
* A reference to a signal in an expression. It's assumed that the
* signal has already been defined elsewhere.
*/
static vhdl_var_ref *translate_signal(ivl_expr_t e)
{
ivl_signal_t sig = ivl_expr_signal(e);
const vhdl_scope *scope = find_scope_for_signal(sig);
assert(scope);
const char *renamed = get_renamed_signal(sig).c_str();
vhdl_decl *decl = scope->get_decl(renamed);
assert(decl);
// Make sure we can read from this declaration
// E.g. if this is an `out' port then we need to make it a buffer
decl->ensure_readable();
// Can't generate a constant initialiser for this signal
// later as it has already been read
if (scope->initializing())
decl->set_initial(NULL);
vhdl_var_ref *ref =
new vhdl_var_ref(renamed, new vhdl_type(*decl->get_type()));
ivl_expr_t off;
if (ivl_signal_array_count(sig) > 0 && (off = ivl_expr_oper1(e))) {
// Select from an array
vhdl_expr *vhd_off = translate_expr(off);
if (NULL == vhd_off) {
delete ref;
return NULL;
}
vhdl_type integer(VHDL_TYPE_INTEGER);
ref->set_slice(vhd_off->cast(&integer));
}
return ref;
}
/*
* A numeric literal ends up as std_logic bit string.
*/
static vhdl_expr *translate_number(ivl_expr_t e)
{
if (ivl_expr_width(e) == 1)
return new vhdl_const_bit(ivl_expr_bits(e)[0]);
else
return new vhdl_const_bits(ivl_expr_bits(e), ivl_expr_width(e),
ivl_expr_signed(e) != 0);
}
static vhdl_expr *translate_ulong(ivl_expr_t e)
{
return new vhdl_const_int(ivl_expr_uvalue(e));
}
static vhdl_expr *translate_delay(ivl_expr_t e)
{
return scale_time(get_active_entity(), ivl_expr_delay_val(e));
}
static vhdl_expr *translate_reduction(support_function_t f, bool neg,
vhdl_expr *operand)
{
vhdl_expr *result;
if (operand->get_type()->get_name() == VHDL_TYPE_STD_LOGIC)
result = operand;
else {
require_support_function(f);
vhdl_fcall *fcall =
new vhdl_fcall(support_function::function_name(f),
vhdl_type::std_logic());
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR);
fcall->add_expr(operand->cast(&std_logic_vector));
result = fcall;
}
if (neg)
return new vhdl_unaryop_expr(VHDL_UNARYOP_NOT, result,
vhdl_type::std_logic());
else
return result;
}
static vhdl_expr *translate_unary(ivl_expr_t e)
{
vhdl_expr *operand = translate_expr(ivl_expr_oper1(e));
if (NULL == operand)
return NULL;
operand = correct_signedness(operand, e);
char opcode = ivl_expr_opcode(e);
switch (opcode) {
case '!':
case '~':
return new vhdl_unaryop_expr
(VHDL_UNARYOP_NOT, operand, new vhdl_type(*operand->get_type()));
case '-':
operand = change_signedness(operand, true);
return new vhdl_unaryop_expr
(VHDL_UNARYOP_NEG, operand, new vhdl_type(*operand->get_type()));
case 'N': // NOR
return translate_reduction(SF_REDUCE_OR, true, operand);
case '|':
return translate_reduction(SF_REDUCE_OR, false, operand);
case 'A': // NAND
return translate_reduction(SF_REDUCE_AND, true, operand);
case '&':
return translate_reduction(SF_REDUCE_AND, false, operand);
case '^': // XOR
return translate_reduction(SF_REDUCE_XOR, false, operand);
case 'X': // XNOR
return translate_reduction(SF_REDUCE_XNOR, false, operand);
default:
error("No translation for unary opcode '%c'\n",
ivl_expr_opcode(e));
delete operand;
return NULL;
}
}
/*
* Translate a numeric binary operator (+, -, etc.) to
* a VHDL equivalent using the numeric_std package.
*/
static vhdl_expr *translate_numeric(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// May need to make either side Boolean for operators
// to work
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
if (lhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
rhs = rhs->cast(&boolean);
else if (rhs->get_type()->get_name() == VHDL_TYPE_BOOLEAN)
lhs = lhs->cast(&boolean);
vhdl_type *rtype;
if (op == VHDL_BINOP_MULT)
rtype = new vhdl_type(lhs->get_type()->get_name(),
(lhs->get_type()->get_width()*2) - 1, 0);
else
rtype = new vhdl_type(*lhs->get_type());
return new vhdl_binop_expr(lhs, op, rhs, rtype);
}
static vhdl_expr *translate_relation(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// Generate any necessary casts
// Arbitrarily, the RHS is casted to the type of the LHS
vhdl_expr *r_cast = rhs->cast(lhs->get_type());
return new vhdl_binop_expr(lhs, op, r_cast, vhdl_type::boolean());
}
/*
* Like translate_relation but both operands must be Boolean.
*/
static vhdl_expr *translate_logical(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
return translate_relation(lhs->cast(&boolean), rhs->cast(&boolean), op);
}
static vhdl_expr *translate_shift(vhdl_expr *lhs, vhdl_expr *rhs,
vhdl_binop_t op)
{
// The RHS must be an integer
vhdl_type integer(VHDL_TYPE_INTEGER);
vhdl_expr *r_cast = rhs->cast(&integer);
vhdl_type *rtype = new vhdl_type(*lhs->get_type());
// The sra operator is not defined on numeric_std types until
// VHDL-2006 which is not well supported. Instead we can use
// the shift_right function which does the same thing and
// exists in earlier versions of numeric_std.
if (op == VHDL_BINOP_SRA) {
vhdl_fcall *sra = new vhdl_fcall("shift_right", rtype);
sra->add_expr(lhs);
sra->add_expr(r_cast);
return sra;
}
else
return new vhdl_binop_expr(lhs, op, r_cast, rtype);
}
/*
* The exponentiation operator in VHDL is not defined for numeric_std
* types. We can get around this by converting the operands to integers,
* performing the operation, then converting the result back to the
* original type. This will work OK in simulation but certainly will not
* synthesise unless the operands are constant.
*
* However, even this does not work quite correctly. The Integer type in
* VHDL is signed and usually only 32 bits, therefore any result larger
* than this will overflow and raise an exception. I can't see a way
* around this at the moment.
*/
static vhdl_expr *translate_power(ivl_expr_t e, vhdl_expr *lhs, vhdl_expr *rhs)
{
vhdl_type integer(VHDL_TYPE_INTEGER);
vhdl_expr *lhs_int = lhs->cast(&integer);
vhdl_expr *rhs_int = rhs->cast(&integer);
vhdl_expr *result = new vhdl_binop_expr(lhs_int, VHDL_BINOP_POWER, rhs_int,
vhdl_type::integer());
int width = ivl_expr_width(e);
const char *func = ivl_expr_signed(e) ? "To_Signed" : "To_Unsigned";
vhdl_type *type = ivl_expr_signed(e)
? vhdl_type::nsigned(width) : vhdl_type::nunsigned(width);
vhdl_fcall *conv = new vhdl_fcall(func, type);
conv->add_expr(result);
conv->add_expr(new vhdl_const_int(width));
return conv;
}
static vhdl_expr *translate_binary(ivl_expr_t e)
{
vhdl_expr *lhs = translate_expr(ivl_expr_oper1(e));
if (NULL == lhs)
return NULL;
vhdl_expr *rhs = translate_expr(ivl_expr_oper2(e));
if (NULL == rhs)
return NULL;
int lwidth = lhs->get_type()->get_width();
int rwidth = rhs->get_type()->get_width();
int result_width = ivl_expr_width(e);
// For === and !== we need to compare std_logic_vectors
// rather than signeds
vhdl_type std_logic_vector(VHDL_TYPE_STD_LOGIC_VECTOR, result_width-1, 0);
vhdl_type_name_t ltype = lhs->get_type()->get_name();
vhdl_type_name_t rtype = rhs->get_type()->get_name();
bool vectorop =
(ltype == VHDL_TYPE_SIGNED || ltype == VHDL_TYPE_UNSIGNED) &&
(rtype == VHDL_TYPE_SIGNED || rtype == VHDL_TYPE_UNSIGNED);
// May need to resize the left or right hand side or change the
// signedness
if (vectorop) {
if (lwidth < rwidth)
lhs = lhs->resize(rwidth);
else if (rwidth < lwidth)
rhs = rhs->resize(lwidth);
lhs = correct_signedness(lhs, ivl_expr_oper1(e));
rhs = correct_signedness(rhs, ivl_expr_oper2(e));
}
vhdl_expr *result;
switch (ivl_expr_opcode(e)) {
case '+':
result = translate_numeric(lhs, rhs, VHDL_BINOP_ADD);
break;
case '-':
result = translate_numeric(lhs, rhs, VHDL_BINOP_SUB);
break;
case '*':
result = translate_numeric(lhs, rhs, VHDL_BINOP_MULT);
break;
case '/':
result = translate_numeric(lhs, rhs, VHDL_BINOP_DIV);
break;
case '%':
result = translate_numeric(lhs, rhs, VHDL_BINOP_MOD);
break;
case 'e':
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
break;
case 'E':
if (vectorop)
result = translate_relation(lhs->cast(&std_logic_vector),
rhs->cast(&std_logic_vector), VHDL_BINOP_EQ);
else
result = translate_relation(lhs, rhs, VHDL_BINOP_EQ);
break;
case 'n':
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
break;
case 'N':
if (vectorop)
result = translate_relation(lhs->cast(&std_logic_vector),
rhs->cast(&std_logic_vector), VHDL_BINOP_NEQ);
else
result = translate_relation(lhs, rhs, VHDL_BINOP_NEQ);
break;
case '&': // Bitwise AND
result = translate_numeric(lhs, rhs, VHDL_BINOP_AND);
break;
case 'a': // Logical AND
result = translate_logical(lhs, rhs, VHDL_BINOP_AND);
break;
case 'A': // Bitwise NAND
result = translate_numeric(lhs, rhs, VHDL_BINOP_NAND);
break;
case 'O': // Bitwise NOR
result = translate_numeric(lhs, rhs, VHDL_BINOP_NOR);
break;
case 'X': // Bitwise XNOR
result = translate_numeric(lhs, rhs, VHDL_BINOP_XNOR);
break;
case '|': // Bitwise OR
result = translate_numeric(lhs, rhs, VHDL_BINOP_OR);
break;
case 'o': // Logical OR
result = translate_logical(lhs, rhs, VHDL_BINOP_OR);
break;
case '<':
result = translate_relation(lhs, rhs, VHDL_BINOP_LT);
break;
case 'L':
result = translate_relation(lhs, rhs, VHDL_BINOP_LEQ);
break;
case '>':
result = translate_relation(lhs, rhs, VHDL_BINOP_GT);
break;
case 'G':
result = translate_relation(lhs, rhs, VHDL_BINOP_GEQ);
break;
case 'l':
result = translate_shift(lhs, rhs, VHDL_BINOP_SL);
break;
case 'r':
result = translate_shift(lhs, rhs, VHDL_BINOP_SR);
break;
case 'R': // Arithmetic right shift
// Verilog only actually performs a signed shift if the
// argument being shifted is signed, otherwise it defaults
// to a normal shift
if (ivl_expr_signed(ivl_expr_oper1(e)))
result = translate_shift(lhs, rhs, VHDL_BINOP_SRA);
else
result = translate_shift(lhs, rhs, VHDL_BINOP_SR);
break;
case '^':
result = translate_numeric(lhs, rhs, VHDL_BINOP_XOR);
break;
case 'p': // Power
result = translate_power(e, lhs, rhs);
break;
default:
error("No translation for binary opcode '%c'\n",
ivl_expr_opcode(e));
delete lhs;
delete rhs;
return NULL;
}
if (NULL == result)
return NULL;
if (vectorop) {
result = correct_signedness(result, e);
int actual_width = result->get_type()->get_width();
if (actual_width != result_width) {
//result->print();
//std::cout << "^ should be " << result_width << " but is " << actual_width << std::endl;
}
}
return result;
}
static vhdl_expr *translate_select(ivl_expr_t e)
{
vhdl_expr *from = translate_expr(ivl_expr_oper1(e));
if (NULL == from)
return NULL;
ivl_expr_t o2 = ivl_expr_oper2(e);
if (o2) {
vhdl_expr *base = translate_expr(ivl_expr_oper2(e));
if (NULL == base)
return NULL;
vhdl_var_ref *from_var_ref = dynamic_cast<vhdl_var_ref*>(from);
if (NULL == from_var_ref) {
// We can't directly select bits from something that's not
// a variable reference in VHDL, but we can emulate the
// effect with a shift and a resize
return new vhdl_binop_expr(from, VHDL_BINOP_SR, base->to_integer(),
new vhdl_type(*from->get_type()));
}
else if (from_var_ref->get_type()->get_name() != VHDL_TYPE_STD_LOGIC) {
// We can use the more idiomatic VHDL slice notation on a
// single variable reference
vhdl_type integer(VHDL_TYPE_INTEGER);
from_var_ref->set_slice(base->cast(&integer), ivl_expr_width(e) - 1);
return from_var_ref;
}
else {
// Make sure we're not trying to select more than one bit
// from a std_logic (this shouldn't actually happen)
if (ivl_expr_width(e) > 1) {
error("%s:%d: trying to select more than one bit from a std_logic",
ivl_expr_file(e), ivl_expr_lineno(e));
return NULL;
}
else
return from_var_ref;
}
}
else
return correct_signedness(from, e)->resize(ivl_expr_width(e));
}
template <class T>
static T *translate_parms(T *t, ivl_expr_t e)
{
int nparams = ivl_expr_parms(e);
for (int i = 0; i < nparams; i++) {
vhdl_expr *param = translate_expr(ivl_expr_parm(e, i));
if (NULL == param)
return NULL;
t->add_expr(param);
}
return t;
}
static vhdl_expr *translate_ufunc(ivl_expr_t e)
{
ivl_scope_t defscope = ivl_expr_def(e);
ivl_scope_t parentscope = ivl_scope_parent(defscope);
assert(ivl_scope_type(parentscope) == IVL_SCT_MODULE);
// A function is always declared in a module, which should have
// a corresponding entity by this point: so we can get type
// information, etc. from the declaration
vhdl_entity *parent_ent = find_entity(parentscope);
assert(parent_ent);
const char *funcname = ivl_scope_tname(defscope);
vhdl_type *rettype =
vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0);
vhdl_fcall *fcall = new vhdl_fcall(funcname, rettype);
int nparams = ivl_expr_parms(e);
for (int i = 0; i < nparams; i++) {
vhdl_expr *param = translate_expr(ivl_expr_parm(e, i));
if (NULL == param) {
delete fcall;
return NULL;
}
// Ensure the parameter has the correct VHDL type
// Parameter number is i + 1 since 0th parameter is return value
ivl_signal_t param_sig = ivl_scope_port(defscope, i + 1);
vhdl_type *param_type =
vhdl_type::type_for(ivl_signal_width(param_sig),
ivl_signal_signed(param_sig) != 0);
fcall->add_expr(param->cast(param_type));
delete param_type;
}
return fcall;
}
static vhdl_expr *translate_ternary(ivl_expr_t e)
{
support_function_t sf;
int width = ivl_expr_width(e);
bool issigned = ivl_expr_signed(e) != 0;
if (width == 1)
sf = SF_TERNARY_LOGIC;
else if (issigned)
sf = SF_TERNARY_SIGNED;
else
sf = SF_TERNARY_UNSIGNED;
require_support_function(sf);
vhdl_expr *test = translate_expr(ivl_expr_oper1(e));
vhdl_expr *true_part = translate_expr(ivl_expr_oper2(e));
vhdl_expr *false_part = translate_expr(ivl_expr_oper3(e));
if (!test || !true_part || !false_part)
return NULL;
vhdl_type boolean(VHDL_TYPE_BOOLEAN);
test = test->cast(&boolean);
vhdl_fcall *fcall =
new vhdl_fcall(support_function::function_name(sf),
vhdl_type::type_for(width, issigned));
fcall->add_expr(test);
fcall->add_expr(true_part);
fcall->add_expr(false_part);
return fcall;
}
static vhdl_expr *translate_concat(ivl_expr_t e)
{
vhdl_type *rtype =
vhdl_type::type_for(ivl_expr_width(e), ivl_expr_signed(e) != 0);
vhdl_binop_expr *concat = new vhdl_binop_expr(VHDL_BINOP_CONCAT, rtype);
int nrepeat = ivl_expr_repeat(e);
while (nrepeat--)
translate_parms<vhdl_binop_expr>(concat, e);
return concat;
}
vhdl_expr *translate_sfunc_time(ivl_expr_t e)
{
cerr << "warning: no translation for $time (returning 0)" << endl;
vhdl_expr *result = new vhdl_const_int(0);
result->set_comment("$time not supported, returned 0 instead!");
return result;
}
vhdl_expr *translate_sfunc_stime(ivl_expr_t e)
{
cerr << "warning: no translation for $stime (returning 0)" << endl;
vhdl_expr *result = new vhdl_const_int(0);
result->set_comment("$stime not supported, returned 0 instead!");
return result;
}
vhdl_expr *translate_sfunc_simtime(ivl_expr_t e)
{
cerr << "warning: no translation for $simtime (returning 0)" << endl;
vhdl_expr *result = new vhdl_const_int(0);
result->set_comment("$simtime not supported, returned 0 instead!");
return result;
}
vhdl_expr *translate_sfunc_random(ivl_expr_t e)
{
cerr << "warning: no translation for $random (returning 0)" << endl;
vhdl_expr *result = new vhdl_const_int(0);
result->set_comment("$random not supported, returned 0 instead!");
return result;
}
vhdl_expr *translate_sfunc_fopen(ivl_expr_t e)
{
cerr << "warning: no translation for $fopen (returning 0)" << endl;
vhdl_expr *result = new vhdl_const_int(0);
result->set_comment("$fopen not supported, returned 0 instead!");
return result;
}
vhdl_expr *translate_sfunc(ivl_expr_t e)
{
const char *name = ivl_expr_name(e);
if (strcmp(name, "$time") == 0)
return translate_sfunc_time(e);
else if (strcmp(name, "$stime") == 0)
return translate_sfunc_stime(e);
else if (strcmp(name, "$simtime") == 0)
return translate_sfunc_simtime(e);
else if (strcmp(name, "$random") == 0)
return translate_sfunc_random(e);
else if (strcmp(name, "$fopen") == 0)
return translate_sfunc_random(e);
else {
error("No translation for system function %s", name);
return NULL;
}
}
/*
* Generate a VHDL expression from a Verilog expression.
*/
vhdl_expr *translate_expr(ivl_expr_t e)
{
assert(e);
ivl_expr_type_t type = ivl_expr_type(e);
switch (type) {
case IVL_EX_STRING:
return translate_string(e);
case IVL_EX_SIGNAL:
return translate_signal(e);
case IVL_EX_NUMBER:
return translate_number(e);
case IVL_EX_ULONG:
return translate_ulong(e);
case IVL_EX_UNARY:
return translate_unary(e);
case IVL_EX_BINARY:
return translate_binary(e);
case IVL_EX_SELECT:
return translate_select(e);
case IVL_EX_UFUNC:
return translate_ufunc(e);
case IVL_EX_TERNARY:
return translate_ternary(e);
case IVL_EX_CONCAT:
return translate_concat(e);
case IVL_EX_SFUNC:
return translate_sfunc(e);
case IVL_EX_DELAY:
return translate_delay(e);
case IVL_EX_REALNUM:
error("No VHDL translation for real expression at %s:%d",
ivl_expr_file(e), ivl_expr_lineno(e));
return NULL;
default:
error("No VHDL translation for expression at %s:%d (type = %d)",
ivl_expr_file(e), ivl_expr_lineno(e), type);
return NULL;
}
}
/*
* Translate an expression into a time. This is achieved simply
* by multiplying the expression by 1ns.
*/
vhdl_expr *translate_time_expr(ivl_expr_t e)
{
vhdl_expr *time = translate_expr(e);
if (NULL == time)
return NULL;
if (time->get_type()->get_name() != VHDL_TYPE_TIME) {
vhdl_type integer(VHDL_TYPE_INTEGER);
time = time->cast(&integer);
vhdl_expr *ns1 = scale_time(get_active_entity(), 1);
return new vhdl_binop_expr(time, VHDL_BINOP_MULT, ns1,
vhdl_type::time());
}
else // Translating IVL_EX_DELAY will always return a time type
return time;
}