Add support for text macros with arguments.
[iverilog.git] / tgt-vvp / eval_real.c
blobfccabfb9066259dfaf686cfd93633b235ab95911
1 /*
2 * Copyright (c) 2003-2005 Stephen Williams (steve@icarus.com)
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: eval_real.c,v 1.22 2007/06/12 02:36:58 steve Exp $"
21 #endif
24 * This file includes functions for evaluating REAL expressions.
26 # include "vvp_priv.h"
27 # include <string.h>
28 #ifdef HAVE_MALLOC_H
29 # include <malloc.h>
30 #endif
31 # include <stdlib.h>
32 # include <math.h>
33 # include <assert.h>
35 static unsigned long word_alloc_mask = 0x0f;
37 int allocate_word()
39 int res = 4;
40 int max = 8*sizeof(word_alloc_mask);
42 while (res < max && (1U << res) & word_alloc_mask)
43 res += 1;
45 assert(res < max);
46 word_alloc_mask |= 1U << res;
47 return res;
50 void clr_word(int res)
52 int max = 8*sizeof(word_alloc_mask);
53 assert(res < max);
54 word_alloc_mask &= ~ (1U << res);
58 static int draw_binary_real(ivl_expr_t exp)
60 int l, r = -1;
62 l = draw_eval_real(ivl_expr_oper1(exp));
63 r = draw_eval_real(ivl_expr_oper2(exp));
65 switch (ivl_expr_opcode(exp)) {
67 case '+':
68 fprintf(vvp_out, " %%add/wr %d, %d;\n", l, r);
69 break;
71 case '-':
72 fprintf(vvp_out, " %%sub/wr %d, %d;\n", l, r);
73 break;
75 case '*':
76 fprintf(vvp_out, " %%mul/wr %d, %d;\n", l, r);
77 break;
79 case '/':
80 fprintf(vvp_out, " %%div/wr %d, %d;\n", l, r);
81 break;
83 case '%':
84 fprintf(vvp_out, " %%mod/wr %d, %d;\n", l, r);
85 break;
86 #if 0
87 case '%':
88 { struct vector_info res = draw_eval_expr(exp, STUFF_OK_XZ);
89 l = allocate_word();
90 fprintf(vvp_out, " %%ix/get %d, %u, %u;\n",
91 l, res.base, res.wid);
92 fprintf(vvp_out, " %%cvt/ri %d, %d;\n", l, l);
93 clr_vector(res);
95 break;
96 #endif
97 default:
98 fprintf(stderr, "XXXX draw_binary_real(%c)\n",
99 ivl_expr_opcode(exp));
100 assert(0);
103 if (r >= 0) clr_word(r);
105 return l;
108 static int draw_number_real(ivl_expr_t exp)
110 unsigned int idx;
111 int res = allocate_word();
112 const char*bits = ivl_expr_bits(exp);
113 unsigned wid = ivl_expr_width(exp);
114 unsigned long mant = 0, mask = -1UL;
115 int vexp = 0x1000;
117 for (idx = 0 ; idx < wid ; idx += 1) {
118 mask <<= 1;
119 if (bits[idx] == '1')
120 mant |= 1 << idx;
123 /* If this is actually a negative number, then get the
124 positive equivalent, and set the sign bit in the exponent
125 field.
127 To get the positive equivilent of mant we need to take the
128 negative of the mantissa (0-mant) but also be aware that
129 the bits may not have been as many bits as the width of the
130 mant variable. This would lead to spurious '1' bits in the
131 high bits of mant that are masked by ~((-1UL)<<wid). */
132 if (ivl_expr_signed(exp) && (bits[wid-1] == '1')) {
133 mant = (0-mant) & ~(mask);
134 vexp |= 0x4000;
137 fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu\n",
138 res, mant, vexp, (vexp&0x4000)? '-' : '+', mant);
139 return res;
142 static int draw_realnum_real(ivl_expr_t exp)
144 int res = allocate_word();
145 double value = ivl_expr_dvalue(exp);
147 double fract;
148 int expo, vexp;
149 unsigned long mant;
150 int sign = 0;
152 /* Handle the special case that the value is +-inf. */
153 if (isinf(value)) {
154 if (value > 0)
155 fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=+inf\n",
156 res, 0x3fff);
157 else
158 fprintf(vvp_out, " %%loadi/wr %d, 0, %d; load=-inf\n",
159 res, 0x7fff);
160 return res;
163 if (value < 0) {
164 sign = 0x4000;
165 value *= -1;
168 fract = frexp(value, &expo);
169 fract = ldexp(fract, 31);
170 mant = fract;
171 expo -= 31;
173 vexp = expo + 0x1000;
174 assert(vexp >= 0);
175 assert(vexp < 0x2000);
176 vexp += sign;
178 fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%f\n",
179 res, mant, vexp, ivl_expr_dvalue(exp));
181 /* Capture the residual bits, if there are any. Note that an
182 IEEE754 mantissa has 52 bits, 31 of which were accounted
183 for already. */
184 fract -= floor(fract);
185 fract = ldexp(fract, 22);
186 mant = fract;
187 expo -= 22;
189 vexp = expo + 0x1000;
190 assert(vexp >= 0);
191 assert(vexp < 0x2000);
192 vexp += sign;
194 if (mant != 0) {
195 int tmp_word = allocate_word();
196 fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load=%f\n",
197 tmp_word, mant, vexp, ivl_expr_dvalue(exp));
198 fprintf(vvp_out, " %%add/wr %d, %d;\n", res, tmp_word);
199 clr_word(tmp_word);
202 return res;
205 static int draw_sfunc_real(ivl_expr_t exp)
207 struct vector_info sv;
208 int res;
209 const char*sign_flag = "";
211 switch (ivl_expr_value(exp)) {
213 case IVL_VT_REAL:
214 if (ivl_expr_parms(exp) == 0) {
215 res = allocate_word();
216 fprintf(vvp_out, " %%vpi_func/r \"%s\", %d;\n",
217 ivl_expr_name(exp), res);
219 } else {
220 res = draw_vpi_rfunc_call(exp);
222 break;
224 case IVL_VT_VECTOR:
225 /* If the value of the sfunc is a vector, then evaluate
226 it as a vector, then convert the result to a real
227 (via an index register) for the result. */
228 sv = draw_eval_expr(exp, 0);
229 clr_vector(sv);
231 if (ivl_expr_signed(exp))
232 sign_flag = "/s";
234 res = allocate_word();
235 fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
236 sign_flag, res, sv.base, sv.wid);
238 fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
239 break;
241 default:
242 assert(0);
243 res = -1;
246 return res;
250 * The real value of a signal is the integer value of a signal
251 * converted to real.
253 static int draw_signal_real_logic(ivl_expr_t exp)
255 int res = allocate_word();
256 struct vector_info sv = draw_eval_expr(exp, 0);
257 const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
259 fprintf(vvp_out, " %%ix/get%s %d, %u, %u; logic signal as real\n",
260 sign_flag, res, sv.base, sv.wid);
261 clr_vector(sv);
263 fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
265 return res;
268 static int draw_signal_real_real(ivl_expr_t exp)
270 ivl_signal_t sig = ivl_expr_signal(exp);
271 int res = allocate_word();
272 unsigned long word = 0;
274 if (ivl_signal_array_count(sig) > 1) {
275 ivl_expr_t ix = ivl_expr_oper1(exp);
276 if (!number_is_immediate(ix, 8*sizeof(word))) {
277 /* XXXX Need to generate a %load/ar instruction. */
278 assert(0);
279 return res;
282 /* The index is constant, so we can return to direct
283 readout with the specific word selected. */
284 word = get_number_immediate(ix);
287 fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word);
289 return res;
292 static int draw_signal_real(ivl_expr_t exp)
294 ivl_signal_t sig = ivl_expr_signal(exp);
295 switch (ivl_signal_data_type(sig)) {
296 case IVL_VT_LOGIC:
297 return draw_signal_real_logic(exp);
298 case IVL_VT_REAL:
299 return draw_signal_real_real(exp);
300 default:
301 fprintf(stderr, "internal error: signal_data_type=%d\n",
302 ivl_signal_data_type(sig));
303 assert(0);
304 return -1;
308 static int draw_ternary_real(ivl_expr_t exp)
310 ivl_expr_t cond = ivl_expr_oper1(exp);
311 ivl_expr_t true_ex = ivl_expr_oper2(exp);
312 ivl_expr_t false_ex = ivl_expr_oper3(exp);
314 struct vector_info tst;
316 unsigned lab_true = local_count++;
317 unsigned lab_false = local_count++;
319 int tru, fal;
320 int res = allocate_word();
322 tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
323 if ((tst.base >= 4) && (tst.wid > 1)) {
324 struct vector_info tmp;
326 fprintf(vvp_out, " %%or/r %u, %u, %u;\n",
327 tst.base, tst.base, tst.wid);
329 tmp = tst;
330 tmp.base += 1;
331 tmp.wid -= 1;
332 clr_vector(tmp);
334 tst.wid = 1;
337 fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
338 thread_count, lab_true, tst.base);
340 tru = draw_eval_real(true_ex);
341 fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, tru);
342 fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_false);
343 clr_word(tru);
345 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_true);
347 fal = draw_eval_real(false_ex);
348 fprintf(vvp_out, " %%mov/wr %d, %d;\n", res, fal);
349 clr_word(fal);
351 fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_false);
353 clr_vector(tst);
355 return res;
358 static int draw_unary_real(ivl_expr_t exp)
360 ivl_expr_t sube = ivl_expr_oper1(exp);
361 int sub = draw_eval_real(sube);
363 if (ivl_expr_opcode(exp) == '+')
364 return sub;
366 if (ivl_expr_opcode(exp) == '-') {
367 int res = allocate_word();
368 fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0\n", res);
369 fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub);
371 clr_word(sub);
372 return res;
375 fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp));
376 fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp));
377 return 0;
380 int draw_eval_real(ivl_expr_t exp)
382 int res = 0;
384 switch (ivl_expr_type(exp)) {
386 case IVL_EX_BINARY:
387 res = draw_binary_real(exp);
388 break;
390 case IVL_EX_NUMBER:
391 res = draw_number_real(exp);
392 break;
394 case IVL_EX_REALNUM:
395 res = draw_realnum_real(exp);
396 break;
398 case IVL_EX_SFUNC:
399 res = draw_sfunc_real(exp);
400 break;
402 case IVL_EX_SIGNAL:
403 res = draw_signal_real(exp);
404 break;
406 case IVL_EX_TERNARY:
407 res = draw_ternary_real(exp);
408 break;
410 case IVL_EX_UFUNC:
411 res = draw_ufunc_real(exp);
412 break;
414 case IVL_EX_UNARY:
415 res = draw_unary_real(exp);
416 break;
418 default:
419 if (ivl_expr_value(exp) == IVL_VT_VECTOR) {
420 struct vector_info sv = draw_eval_expr(exp, 0);
421 const char*sign_flag = ivl_expr_signed(exp)? "/s" : "";
423 clr_vector(sv);
424 res = allocate_word();
426 fprintf(vvp_out, " %%ix/get%s %d, %u, %u;\n",
427 sign_flag, res, sv.base, sv.wid);
429 fprintf(vvp_out, " %%cvt/ri %d, %d;\n", res, res);
431 } else {
432 fprintf(stderr, "XXXX Evaluate real expression (%d)\n",
433 ivl_expr_type(exp));
434 fprintf(vvp_out, " ; XXXX Evaluate real expression (%d)\n",
435 ivl_expr_type(exp));
436 return 0;
438 break;
441 return res;
446 * $Log: eval_real.c,v $
447 * Revision 1.22 2007/06/12 02:36:58 steve
448 * handle constant inf values.
450 * Revision 1.21 2007/06/07 03:20:15 steve
451 * Properly handle signed conversion to real
453 * Revision 1.20 2007/02/26 19:49:50 steve
454 * Spelling fixes (larry doolittle)
456 * Revision 1.19 2007/02/20 05:58:36 steve
457 * Handle unary minus of real valued expressions.
459 * Revision 1.18 2007/02/14 05:59:46 steve
460 * Handle type of ternary expressions properly.
462 * Revision 1.17 2007/01/16 05:44:16 steve
463 * Major rework of array handling. Memories are replaced with the
464 * more general concept of arrays. The NetMemory and NetEMemory
465 * classes are removed from the ivl core program, and the IVL_LPM_RAM
466 * lpm type is removed from the ivl_target API.
468 * Revision 1.16 2006/10/10 23:54:28 steve
469 * Fix rendering of signed numbers in real expressions.
471 * Revision 1.15 2006/08/09 05:19:08 steve
472 * Add support for real valued modulus.
474 * Revision 1.14 2005/07/13 04:52:31 steve
475 * Handle functions with real values.
477 * Revision 1.13 2005/07/11 16:56:51 steve
478 * Remove NetVariable and ivl_variable_t structures.
480 * Revision 1.12 2005/07/07 16:22:50 steve
481 * Generalize signals to carry types.
483 * Revision 1.11 2004/10/04 01:10:57 steve
484 * Clean up spurious trailing white space.
486 * Revision 1.10 2003/12/19 01:27:10 steve
487 * Fix various unsigned compare warnings.
489 * Revision 1.9 2003/05/25 02:50:08 steve
490 * Add % in real expressions.
492 * Revision 1.8 2003/04/23 02:22:47 steve
493 * Fix word register leak.
495 * Revision 1.7 2003/03/28 02:33:56 steve
496 * Add support for division of real operands.
498 * Revision 1.6 2003/03/15 04:45:18 steve
499 * Allow real-valued vpi functions to have arguments.
501 * Revision 1.5 2003/03/08 01:04:01 steve
502 * Excess precision breaks some targets.
504 * Revision 1.4 2003/02/07 02:46:16 steve
505 * Handle real value subtract and comparisons.
507 * Revision 1.3 2003/01/28 04:15:50 steve
508 * Deliver residual bits of real value.
510 * Revision 1.2 2003/01/27 00:14:37 steve
511 * Support in various contexts the $realtime
512 * system task.
514 * Revision 1.1 2003/01/26 21:16:00 steve
515 * Rework expression parsing and elaboration to
516 * accommodate real/realtime values and expressions.