1 /*
2  * Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com)
3  *
4  *    This source code is free software; you can redistribute it
5  *    and/or modify it in source code form under the terms of the GNU
6  *    General Public License as published by the Free Software
7  *    Foundation; either version 2 of the License, or (at your option)
8  *    any later version.
9  *
10  *    This program is distributed in the hope that it will be useful,
11  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *    GNU General Public License for more details.
14  *
15  *    You should have received a copy of the GNU General Public License
16  *    along with this program; if not, write to the Free Software
17  *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 /*
21  * This file includes functions for evaluating REAL expressions.
22  */
23 # include  "vvp_priv.h"
24 # include  <string.h>
25 # include  <stdlib.h>
26 # include  <math.h>
27 # include  <assert.h>
28 # include  <stdbool.h>
29 
30 static unsigned long word_alloc_mask = 0x0f;
31 
allocate_word()32 int allocate_word()
33 {
34       int res = 4;
35 
36       while (res < WORD_COUNT && (1U << res) & word_alloc_mask)
37 	    res += 1;
38 
39       if (res >= WORD_COUNT) {
40 	    fprintf(stderr, "vvp.tgt error: Thread words (%d) exhausted "
41 	                    "during VVP code generation.\n", WORD_COUNT);
42 	    exit(1);
43       }
44       word_alloc_mask |= 1U << res;
45       return res;
46 }
47 
clr_word(int res)48 void clr_word(int res)
49 {
50       assert(res < WORD_COUNT);
51       word_alloc_mask &= ~ (1U << res);
52 }
53 
draw_binary_real(ivl_expr_t expr)54 static void draw_binary_real(ivl_expr_t expr)
55 {
56       switch (ivl_expr_opcode(expr)) {
57 	  case 'E':
58 	  case 'N':
59 	  case 'w':
60 	  case 'W':
61 	  case 'l':
62 	  case 'r':
63 	  case 'R':
64 	  case '&':
65 	  case '|':
66 	  case '^':
67 	  case 'A':
68 	  case 'O':
69 	  case 'X':
70 	    /* These should be caught in draw_eval_real(). */
71 	    assert(0);
72       }
73 
74       draw_eval_real(ivl_expr_oper1(expr));
75       draw_eval_real(ivl_expr_oper2(expr));
76 
77       switch (ivl_expr_opcode(expr)) {
78 
79 	  case '+':
80 	    fprintf(vvp_out, "    %%add/wr;\n");
81 	    break;
82 
83 	  case '-':
84 	    fprintf(vvp_out, "    %%sub/wr;\n");
85 	    break;
86 
87 	  case '*':
88 	    fprintf(vvp_out, "    %%mul/wr;\n");
89 	    break;
90 
91 	  case '/':
92 	    fprintf(vvp_out, "    %%div/wr;\n");
93 	    break;
94 
95 	  case '%':
96 	    fprintf(vvp_out, "    %%mod/wr;\n");
97 	    break;
98 	  case 'p':
99 	    fprintf(vvp_out, "    %%pow/wr;\n");
100 	    break;
101 
102 	  case 'm':
103 	    fprintf(vvp_out, "    %%min/wr;\n");
104 	    break;
105 
106 	  case 'M':
107 	    fprintf(vvp_out, "    %%max/wr;\n");
108 	    break;
109 
110 	  default:
111 	    fprintf(stderr, "vvp.tgt error: draw_binary_real(%c)\n",
112 		    ivl_expr_opcode(expr));
113 	    assert(0);
114       }
115 }
116 
draw_number_real(ivl_expr_t expr)117 static void draw_number_real(ivl_expr_t expr)
118 {
119       unsigned int idx;
120       const char*bits = ivl_expr_bits(expr);
121       unsigned wid = ivl_expr_width(expr);
122       unsigned long mant = 0;
123       int vexp = 0x1000;
124 
125 	/* If this is a negative number, then arrange for the 2's
126 	   complement to be calculated as we scan through the
127 	   value. Real values are sign-magnitude, and this negation
128 	   gets us a magnitude. */
129 
130       int negate = 0;
131       int carry = 0;
132       if (ivl_expr_signed(expr) && (bits[wid-1] == '1')) {
133 	    negate = 1;
134 	    carry = 1;
135       }
136 
137       for (idx = 0 ;  idx < wid && idx < IMM_WID ;  idx += 1) {
138 	    int cur_bit = bits[idx] == '1'? 1 : 0;
139 
140 	    if (negate) {
141 		  cur_bit ^= 1;
142 		  cur_bit += carry;
143 		  carry = (cur_bit >> 1) & 1;
144 		  cur_bit &= 1;
145 	    }
146 
147 	    if (cur_bit) mant |= 1 << idx;
148       }
149 
150       for ( ; idx < wid ; idx += 1) {
151 	    if (ivl_expr_signed(expr) && (bits[idx] == bits[IMM_WID-1]))
152 		  continue;
153 
154 	    if (bits[idx] == '0')
155 		  continue;
156 
157 	    fprintf(stderr, "vvp.tgt error: mantissa doesn't fit!\n");
158 	    assert(0);
159       }
160 
161 	/* If required, add in a sign bit. */
162       if (negate)
163 	    vexp |= 0x4000;
164 
165       fprintf(vvp_out, "    %%pushi/real %lu, %d; load(num)= %c%lu (wid=%u)\n",
166 	      mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
167 }
168 
draw_property_real(ivl_expr_t expr)169 static void draw_property_real(ivl_expr_t expr)
170 {
171       ivl_signal_t sig = ivl_expr_signal(expr);
172       unsigned pidx = ivl_expr_property_idx(expr);
173 
174       fprintf(vvp_out, "    %%load/obj v%p_0;\n", sig);
175       fprintf(vvp_out, "    %%prop/r %u;\n", pidx);
176       fprintf(vvp_out, "    %%pop/obj 1, 0;\n");
177 }
178 
draw_realnum_real(ivl_expr_t expr)179 static void draw_realnum_real(ivl_expr_t expr)
180 {
181       double value = ivl_expr_dvalue(expr);
182 
183       double fract;
184       int expo, vexp;
185       unsigned long mant;
186       int sign = 0;
187 
188 	/* Handle the special case that the value is +-inf. */
189       if (isinf(value)) {
190 	    if (value > 0)
191 		  fprintf(vvp_out, "    %%pushi/real 0, %d; load=+inf\n",
192 			  0x3fff);
193 	    else
194 		  fprintf(vvp_out, "    %%pushi/real 0, %d; load=-inf\n",
195 			  0x7fff);
196 	    return;
197       }
198 	/* Handle the special case that the value is NaN. */
199       if (value != value) {
200 	    fprintf(vvp_out, "    %%pushi/real 1, %d; load=NaN\n",
201 	            0x3fff);
202 	    return;
203       }
204 
205       if (value < 0) {
206 	    sign = 0x4000;
207 	    value *= -1;
208       }
209 
210       fract = frexp(value, &expo);
211       fract = ldexp(fract, 31);
212       mant = fract;
213       expo -= 31;
214 
215       vexp = expo + 0x1000;
216       assert(vexp >= 0);
217       assert(vexp < 0x2000);
218       vexp += sign;
219 
220       fprintf(vvp_out, "    %%pushi/real %lu, %d; load=%#g\n",
221 	      mant, vexp, ivl_expr_dvalue(expr));
222 
223 	/* Capture the residual bits, if there are any. Note that an
224 	   IEEE754 mantissa has 52 bits, 31 of which were accounted
225 	   for already. */
226       fract -= floor(fract);
227       fract = ldexp(fract, 22);
228       mant = fract;
229       expo -= 22;
230 
231       vexp = expo + 0x1000;
232       assert(vexp >= 0);
233       assert(vexp < 0x2000);
234       vexp += sign;
235 
236       if (mant != 0) {
237 	    fprintf(vvp_out, "    %%pushi/real %lu, %d; load=%#g\n",
238 		    mant, vexp, ivl_expr_dvalue(expr));
239 	    fprintf(vvp_out, "    %%add/wr;\n");
240       }
241 }
242 
243 /*
244  * The real value of a logic expression is the integer value of the
245  * expression converted to real.
246  */
draw_real_logic_expr(ivl_expr_t expr)247 static void draw_real_logic_expr(ivl_expr_t expr)
248 {
249       draw_eval_vec4(expr);
250       const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
251       fprintf(vvp_out, "    %%cvt/rv%s;\n", sign_flag);
252 }
253 
draw_select_real(ivl_expr_t expr)254 static void draw_select_real(ivl_expr_t expr)
255 {
256 	/* The sube references the expression to be selected from. */
257       ivl_expr_t sube = ivl_expr_oper1(expr);
258 	/* This is the select expression */
259       ivl_expr_t shift= ivl_expr_oper2(expr);
260 
261 	/* Assume the sub-expression is a signal */
262       ivl_signal_t sig = ivl_expr_signal(sube);
263       assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY || ivl_signal_data_type(sig) == IVL_VT_QUEUE);
264 
265       draw_eval_expr_into_integer(shift, 3);
266       fprintf(vvp_out, "    %%load/dar/r v%p_0;\n", sig);
267 }
268 
real_ex_pop(ivl_expr_t expr)269 static void real_ex_pop(ivl_expr_t expr)
270 {
271       const char*fb;
272       ivl_expr_t arg;
273 
274       if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0)
275             fb = "b";
276       else
277             fb = "f";
278 
279       arg = ivl_expr_parm(expr, 0);
280       assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
281 
282       fprintf(vvp_out, "    %%qpop/%s/real v%p_0;\n", fb, ivl_expr_signal(arg));
283 }
284 
draw_sfunc_real(ivl_expr_t expr)285 static void draw_sfunc_real(ivl_expr_t expr)
286 {
287       switch (ivl_expr_value(expr)) {
288 
289 	  case IVL_VT_REAL:
290 	    if (ivl_expr_parms(expr) == 0) {
291 		  fprintf(vvp_out, "    %%vpi_func/r %u %u \"%s\" {0 0 0};\n",
292 			  ivl_file_table_index(ivl_expr_file(expr)),
293 			  ivl_expr_lineno(expr), ivl_expr_name(expr));
294 
295 	    } else {
296 		  draw_vpi_rfunc_call(expr);
297 	    }
298 	    break;
299 
300 	  case IVL_VT_VECTOR:
301 	      /* If the value of the sfunc is a vector, then evaluate
302 		 it as a vector, then convert the result to a real
303 		 (via an index register) for the result. */
304 	    draw_real_logic_expr(expr);
305 	    break;
306 
307 	  default:
308 	    assert(0);
309       }
310 
311 }
312 
draw_signal_real_real(ivl_expr_t expr)313 static void draw_signal_real_real(ivl_expr_t expr)
314 {
315       ivl_signal_t sig = ivl_expr_signal(expr);
316 
317 	/* Special Case: If the signal is the return value of the function,
318 	   then use a different opcode to get the value. */
319       if (signal_is_return_value(sig)) {
320 	    assert(ivl_signal_dimensions(sig) == 0);
321 	    fprintf(vvp_out, "    %%retload/real 0; Load %s (draw_signal_real_real)\n",
322 		    ivl_signal_basename(sig));
323 	    return;
324       }
325 
326 
327       if (ivl_signal_dimensions(sig) == 0) {
328 	    fprintf(vvp_out, "    %%load/real v%p_0;\n", sig);
329 	    return;
330       }
331 
332       ivl_expr_t word_ex = ivl_expr_oper1(expr);
333       int word_ix = allocate_word();
334       draw_eval_expr_into_integer(word_ex, word_ix);
335       fprintf(vvp_out, "    %%load/ar v%p, %d;\n", sig, word_ix);
336       clr_word(word_ix);
337 }
338 
draw_signal_real(ivl_expr_t expr)339 static void draw_signal_real(ivl_expr_t expr)
340 {
341       ivl_signal_t sig = ivl_expr_signal(expr);
342       switch (ivl_signal_data_type(sig)) {
343 	  case IVL_VT_LOGIC:
344 	    draw_real_logic_expr(expr);
345 	    return;
346 	  case IVL_VT_REAL:
347 	    draw_signal_real_real(expr);
348 	    return;
349 	  default:
350 	    fprintf(stderr, "vvp.tgt error: signal_data_type=%d\n",
351 		    ivl_signal_data_type(sig));
352 	    assert(0);
353 	    return;
354       }
355 }
356 
357 /* If we have nested ternary operators they are likely tail recursive.
358  * This code is structured to allow this recursion without overflowing
359  * the available thread words. */
draw_ternary_real(ivl_expr_t expr)360 static void draw_ternary_real(ivl_expr_t expr)
361 {
362       ivl_expr_t cond = ivl_expr_oper1(expr);
363       ivl_expr_t true_ex = ivl_expr_oper2(expr);
364       ivl_expr_t false_ex = ivl_expr_oper3(expr);
365 
366       unsigned lab_true = local_count++;
367       unsigned lab_out = local_count++;
368 
369       int cond_flag = allocate_flag();
370 
371 	/* Evaluate the ternary condition. */
372       draw_eval_vec4(cond);
373       if (ivl_expr_width(cond) > 1)
374 	    fprintf(vvp_out, "    %%or/r;\n");
375 
376       fprintf(vvp_out, "    %%flag_set/vec4 %d;\n", cond_flag);
377 
378 
379 	/* Evaluate the true expression second. */
380       fprintf(vvp_out, "    %%jmp/1  T_%u.%u, %d;\n",
381 	      thread_count, lab_true, cond_flag);
382 
383 	/* Evaluate the false expression. */
384       draw_eval_real(false_ex);
385       fprintf(vvp_out, "    %%jmp/0  T_%u.%u, %d; End of false expr.\n",
386               thread_count, lab_out, cond_flag);
387 
388 	/* If the conditional is undefined then blend the real words. */
389       draw_eval_real(true_ex);
390       fprintf(vvp_out, "    %%blend/wr;\n");
391       fprintf(vvp_out, "    %%jmp  T_%u.%u; End of blend\n",
392               thread_count, lab_out);
393 
394 	/* Evaluate the true expression. */
395       fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_true);
396       draw_eval_real(true_ex);
397 
398 	/* This is the out label. */
399       fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
400 
401       clr_flag(cond_flag);
402 }
403 
increment(ivl_expr_t e,bool pre)404 static void increment(ivl_expr_t e, bool pre)
405 {
406       ivl_signal_t sig = ivl_expr_signal(e);
407       fprintf(vvp_out, "    %%load/real v%p_0;\n", sig);
408       if (!pre) fprintf(vvp_out, "    %%dup/real;\n");
409       fprintf(vvp_out, "    %%pushi/real 1, 0x1000;\n");
410       fprintf(vvp_out, "    %%add/wr;\n");
411       if ( pre) fprintf(vvp_out, "    %%dup/real;\n");
412       fprintf(vvp_out, "    %%store/real v%p_0;\n", sig);
413 }
414 
decrement(ivl_expr_t e,bool pre)415 static void decrement(ivl_expr_t e, bool pre)
416 {
417       ivl_signal_t sig = ivl_expr_signal(e);
418       fprintf(vvp_out, "    %%load/real v%p_0;\n", sig);
419       if (!pre) fprintf(vvp_out, "    %%dup/real;\n");
420       fprintf(vvp_out, "    %%pushi/real 1, 0x1000;\n");
421       fprintf(vvp_out, "    %%sub/wr;\n");
422       if ( pre) fprintf(vvp_out, "    %%dup/real;\n");
423       fprintf(vvp_out, "    %%store/real v%p_0;\n", sig);
424 }
425 
draw_unary_real(ivl_expr_t expr)426 static void draw_unary_real(ivl_expr_t expr)
427 {
428       ivl_expr_t sube;
429 
430 	/* If the opcode is a ~ or a ! then the sub expression must not be
431 	 * a real expression, so use vector evaluation and then convert
432 	 * that result to a real value. */
433       if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
434 	    draw_real_logic_expr(expr);
435 	    return;
436       }
437 
438       sube = ivl_expr_oper1(expr);
439 
440       if (ivl_expr_opcode(expr) == 'r') { /* Cast an integer value to a real. */
441 	    const char *suffix = "";
442 	    assert(ivl_expr_value(sube) != IVL_VT_REAL);
443 	    draw_eval_vec4(sube);
444 	    if (ivl_expr_signed(sube)) suffix = "/s";
445 	    fprintf(vvp_out, "    %%cvt/rv%s;\n", suffix);
446 	    return;
447       }
448 
449 
450       if (ivl_expr_opcode(expr) == '+') {
451 	    draw_eval_real(sube);
452 	    return;
453       }
454 
455       if (ivl_expr_opcode(expr) == '-') {
456 	    fprintf(vvp_out, "    %%pushi/real 0, 0; load 0.0\n");
457 	    draw_eval_real(sube);
458 	    fprintf(vvp_out, "    %%sub/wr;\n");
459 	    return;
460       }
461 
462       if (ivl_expr_opcode(expr) == 'm') { /* abs() */
463 	    draw_eval_real(sube);
464 	    fprintf(vvp_out, "    %%abs/wr;\n");
465 	    return;
466       }
467 
468       if (ivl_expr_opcode(expr) == 'v') { /* Handled in eval_expr.c. */
469             fprintf(stderr, "vvp.tgt error: real -> integer cast in real "
470                             "context.\n");
471 	    assert(0);
472       }
473 
474       switch (ivl_expr_opcode(expr)) {
475 	  case 'I':
476 	    increment(sube, true);
477 	    return;
478 	  case 'i':
479 	    increment(sube, false);
480 	    return;
481 
482 	  case 'D':
483 	    decrement(sube, true);
484 	    return;
485 	  case 'd':
486 	    decrement(sube, false);
487 	    return;
488 	}
489 
490       fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
491               ivl_expr_opcode(expr));
492       assert(0);
493 }
494 
draw_eval_real(ivl_expr_t expr)495 void draw_eval_real(ivl_expr_t expr)
496 {
497 
498 	/* If this expression/sub-expression is not real then we need
499 	 * to evaluate it as a bit value and then convert the bit based
500 	 * result to a real value. This is required to get integer
501 	 * division to work correctly. */
502       if (ivl_expr_value(expr) != IVL_VT_REAL) {
503 	    draw_real_logic_expr(expr);
504 	    return;
505       }
506 
507       switch (ivl_expr_type(expr)) {
508 
509 	  case IVL_EX_BINARY:
510 	    draw_binary_real(expr);
511 	    break;
512 
513 	  case IVL_EX_NUMBER:
514 	    draw_number_real(expr);
515 	    break;
516 
517 	  case IVL_EX_PROPERTY:
518 	    draw_property_real(expr);
519 	    break;
520 
521 	  case IVL_EX_REALNUM:
522 	    draw_realnum_real(expr);
523 	    break;
524 
525 	  case IVL_EX_SELECT:
526 	    draw_select_real(expr);
527 	    break;
528 
529 	  case IVL_EX_SFUNC:
530 	    if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0)
531 		  real_ex_pop(expr);
532 	    else if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_front")==0)
533 		  real_ex_pop(expr);
534 	    else
535 		  draw_sfunc_real(expr);
536 	    break;
537 
538 	  case IVL_EX_SIGNAL:
539 	    draw_signal_real(expr);
540 	    break;
541 
542 	  case IVL_EX_TERNARY:
543 	    draw_ternary_real(expr);
544 	    break;
545 
546 	  case IVL_EX_UFUNC:
547 	    draw_ufunc_real(expr);
548 	    break;
549 
550 	  case IVL_EX_UNARY:
551 	    draw_unary_real(expr);
552 	    break;
553 
554 	  default:
555 	    if (ivl_expr_value(expr) == IVL_VT_VECTOR) {
556 		  draw_eval_vec4(expr);
557 		  const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
558 		  fprintf(vvp_out, "    %%cvt/rv%s;\n", sign_flag);
559 
560 	    } else {
561 		  fprintf(stderr, "vvp.tgt error: XXXX Evaluate real expression (%d)\n",
562 			  ivl_expr_type(expr));
563 		  fprintf(vvp_out, " ; XXXX Evaluate real expression (%d)\n",
564 			  ivl_expr_type(expr));
565 		  return;
566 	    }
567 	    break;
568       }
569 
570 }
571