2003-01-26 22:15:58 +01:00
|
|
|
/*
|
2020-05-31 21:36:01 +02:00
|
|
|
* Copyright (c) 2003-2020 Stephen Williams (steve@icarus.com)
|
2003-01-26 22:15:58 +01:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form 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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2003-01-26 22:15:58 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file includes functions for evaluating REAL expressions.
|
|
|
|
|
*/
|
|
|
|
|
# include "vvp_priv.h"
|
|
|
|
|
# include <string.h>
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <math.h>
|
|
|
|
|
# include <assert.h>
|
2011-08-21 05:29:41 +02:00
|
|
|
# include <stdbool.h>
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
static unsigned long word_alloc_mask = 0x0f;
|
|
|
|
|
|
|
|
|
|
int allocate_word()
|
|
|
|
|
{
|
|
|
|
|
int res = 4;
|
|
|
|
|
|
2020-05-31 21:36:01 +02:00
|
|
|
while (res < WORD_COUNT && (1U << res) & word_alloc_mask)
|
2003-01-26 22:15:58 +01:00
|
|
|
res += 1;
|
|
|
|
|
|
2020-05-31 21:36:01 +02:00
|
|
|
if (res >= WORD_COUNT) {
|
|
|
|
|
fprintf(stderr, "vvp.tgt error: Thread words (%d) exhausted "
|
|
|
|
|
"during VVP code generation.\n", WORD_COUNT);
|
2010-07-07 23:33:10 +02:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2003-04-23 04:22:47 +02:00
|
|
|
word_alloc_mask |= 1U << res;
|
2003-01-26 22:15:58 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void clr_word(int res)
|
|
|
|
|
{
|
2020-05-31 21:36:01 +02:00
|
|
|
assert(res < WORD_COUNT);
|
2003-04-23 04:22:47 +02:00
|
|
|
word_alloc_mask &= ~ (1U << res);
|
2003-01-26 22:15:58 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_binary_real(ivl_expr_t expr)
|
2003-01-26 22:15:58 +01:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
switch (ivl_expr_opcode(expr)) {
|
2008-04-21 22:45:32 +02:00
|
|
|
case 'E':
|
|
|
|
|
case 'N':
|
2017-11-18 04:32:09 +01:00
|
|
|
case 'w':
|
|
|
|
|
case 'W':
|
2008-04-21 22:45:32 +02:00
|
|
|
case 'l':
|
|
|
|
|
case 'r':
|
|
|
|
|
case 'R':
|
|
|
|
|
case '&':
|
|
|
|
|
case '|':
|
|
|
|
|
case '^':
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'O':
|
|
|
|
|
case 'X':
|
2009-06-16 01:50:18 +02:00
|
|
|
/* These should be caught in draw_eval_real(). */
|
|
|
|
|
assert(0);
|
2008-04-21 22:45:32 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_eval_real(ivl_expr_oper1(expr));
|
|
|
|
|
draw_eval_real(ivl_expr_oper2(expr));
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2008-12-18 17:45:47 +01:00
|
|
|
switch (ivl_expr_opcode(expr)) {
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
case '+':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%add/wr;\n");
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-02-07 03:46:16 +01:00
|
|
|
case '-':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%sub/wr;\n");
|
2003-02-07 03:46:16 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
case '*':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%mul/wr;\n");
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-03-28 03:33:56 +01:00
|
|
|
case '/':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%div/wr;\n");
|
2003-03-28 03:33:56 +01:00
|
|
|
break;
|
|
|
|
|
|
2006-08-09 07:19:08 +02:00
|
|
|
case '%':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%mod/wr;\n");
|
2006-08-09 07:19:08 +02:00
|
|
|
break;
|
2008-02-01 02:15:03 +01:00
|
|
|
case 'p':
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pow/wr;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'm':
|
|
|
|
|
fprintf(vvp_out, " %%min/wr;\n");
|
2008-02-01 02:15:03 +01:00
|
|
|
break;
|
2008-05-04 06:54:42 +02:00
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
case 'M':
|
|
|
|
|
fprintf(vvp_out, " %%max/wr;\n");
|
|
|
|
|
break;
|
2010-06-19 01:03:17 +02:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
default:
|
2020-05-31 21:36:01 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: draw_binary_real(%c)\n",
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_expr_opcode(expr));
|
2003-01-26 22:15:58 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_number_real(ivl_expr_t expr)
|
2003-01-26 22:15:58 +01:00
|
|
|
{
|
2003-12-19 02:27:10 +01:00
|
|
|
unsigned int idx;
|
2008-12-18 17:45:47 +01:00
|
|
|
const char*bits = ivl_expr_bits(expr);
|
|
|
|
|
unsigned wid = ivl_expr_width(expr);
|
2010-11-01 22:21:48 +01:00
|
|
|
unsigned long mant = 0;
|
2006-10-11 01:54:28 +02:00
|
|
|
int vexp = 0x1000;
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2008-09-20 02:04:40 +02:00
|
|
|
/* If this is a negative number, then arrange for the 2's
|
|
|
|
|
complement to be calculated as we scan through the
|
|
|
|
|
value. Real values are sign-magnitude, and this negation
|
2010-10-02 20:02:27 +02:00
|
|
|
gets us a magnitude. */
|
2008-09-20 02:04:40 +02:00
|
|
|
|
|
|
|
|
int negate = 0;
|
|
|
|
|
int carry = 0;
|
2008-12-18 17:45:47 +01:00
|
|
|
if (ivl_expr_signed(expr) && (bits[wid-1] == '1')) {
|
2008-09-20 02:04:40 +02:00
|
|
|
negate = 1;
|
|
|
|
|
carry = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-07 01:22:34 +02:00
|
|
|
for (idx = 0 ; idx < wid && idx < IMM_WID ; idx += 1) {
|
2008-09-20 02:04:40 +02:00
|
|
|
int cur_bit = bits[idx] == '1'? 1 : 0;
|
|
|
|
|
|
|
|
|
|
if (negate) {
|
|
|
|
|
cur_bit ^= 1;
|
|
|
|
|
cur_bit += carry;
|
|
|
|
|
carry = (cur_bit >> 1) & 1;
|
|
|
|
|
cur_bit &= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur_bit) mant |= 1 << idx;
|
2003-01-26 22:15:58 +01:00
|
|
|
}
|
|
|
|
|
|
2008-08-17 03:30:07 +02:00
|
|
|
for ( ; idx < wid ; idx += 1) {
|
2008-12-18 17:45:47 +01:00
|
|
|
if (ivl_expr_signed(expr) && (bits[idx] == bits[IMM_WID-1]))
|
2008-08-17 03:30:07 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (bits[idx] == '0')
|
|
|
|
|
continue;
|
|
|
|
|
|
2010-07-07 23:33:10 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: mantissa doesn't fit!\n");
|
2008-08-17 03:30:07 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-20 02:04:40 +02:00
|
|
|
/* If required, add in a sign bit. */
|
|
|
|
|
if (negate)
|
2006-10-11 01:54:28 +02:00
|
|
|
vexp |= 0x4000;
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real %lu, %d; load(num)= %c%lu (wid=%u)\n",
|
|
|
|
|
mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
|
2003-01-26 22:15:58 +01:00
|
|
|
}
|
|
|
|
|
|
2013-01-11 03:48:15 +01:00
|
|
|
static void draw_property_real(ivl_expr_t expr)
|
|
|
|
|
{
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
|
|
|
|
unsigned pidx = ivl_expr_property_idx(expr);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
|
|
|
|
|
fprintf(vvp_out, " %%prop/r %u;\n", pidx);
|
2013-12-04 02:19:35 +01:00
|
|
|
fprintf(vvp_out, " %%pop/obj 1, 0;\n");
|
2013-01-11 03:48:15 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_realnum_real(ivl_expr_t expr)
|
2003-01-26 22:15:58 +01:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
double value = ivl_expr_dvalue(expr);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
double fract;
|
2003-01-28 05:15:50 +01:00
|
|
|
int expo, vexp;
|
2003-01-26 22:15:58 +01:00
|
|
|
unsigned long mant;
|
|
|
|
|
int sign = 0;
|
|
|
|
|
|
2007-06-12 04:36:58 +02:00
|
|
|
/* Handle the special case that the value is +-inf. */
|
|
|
|
|
if (isinf(value)) {
|
|
|
|
|
if (value > 0)
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real 0, %d; load=+inf\n",
|
|
|
|
|
0x3fff);
|
2007-06-12 04:36:58 +02:00
|
|
|
else
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real 0, %d; load=-inf\n",
|
|
|
|
|
0x7fff);
|
|
|
|
|
return;
|
2007-06-12 04:36:58 +02:00
|
|
|
}
|
2008-08-29 03:11:55 +02:00
|
|
|
/* Handle the special case that the value is NaN. */
|
|
|
|
|
if (value != value) {
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real 1, %d; load=NaN\n",
|
|
|
|
|
0x3fff);
|
|
|
|
|
return;
|
2008-08-29 03:11:55 +02:00
|
|
|
}
|
2007-06-12 04:36:58 +02:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
if (value < 0) {
|
2003-01-28 05:15:50 +01:00
|
|
|
sign = 0x4000;
|
2003-01-26 22:15:58 +01:00
|
|
|
value *= -1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-28 05:15:50 +01:00
|
|
|
fract = frexp(value, &expo);
|
|
|
|
|
fract = ldexp(fract, 31);
|
2003-01-26 22:15:58 +01:00
|
|
|
mant = fract;
|
2003-01-28 05:15:50 +01:00
|
|
|
expo -= 31;
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2003-01-28 05:15:50 +01:00
|
|
|
vexp = expo + 0x1000;
|
2003-01-26 22:15:58 +01:00
|
|
|
assert(vexp >= 0);
|
|
|
|
|
assert(vexp < 0x2000);
|
|
|
|
|
vexp += sign;
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n",
|
|
|
|
|
mant, vexp, ivl_expr_dvalue(expr));
|
2003-01-28 05:15:50 +01:00
|
|
|
|
2003-03-08 02:04:01 +01:00
|
|
|
/* Capture the residual bits, if there are any. Note that an
|
|
|
|
|
IEEE754 mantissa has 52 bits, 31 of which were accounted
|
|
|
|
|
for already. */
|
2003-01-28 05:15:50 +01:00
|
|
|
fract -= floor(fract);
|
2003-03-08 02:04:01 +01:00
|
|
|
fract = ldexp(fract, 22);
|
2003-01-28 05:15:50 +01:00
|
|
|
mant = fract;
|
2003-03-08 02:04:01 +01:00
|
|
|
expo -= 22;
|
2003-01-28 05:15:50 +01:00
|
|
|
|
|
|
|
|
vexp = expo + 0x1000;
|
|
|
|
|
assert(vexp >= 0);
|
|
|
|
|
assert(vexp < 0x2000);
|
|
|
|
|
vexp += sign;
|
|
|
|
|
|
|
|
|
|
if (mant != 0) {
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real %lu, %d; load=%#g\n",
|
|
|
|
|
mant, vexp, ivl_expr_dvalue(expr));
|
|
|
|
|
fprintf(vvp_out, " %%add/wr;\n");
|
2003-01-28 05:15:50 +01:00
|
|
|
}
|
2003-01-26 22:15:58 +01:00
|
|
|
}
|
|
|
|
|
|
2009-12-20 00:34:54 +01:00
|
|
|
/*
|
|
|
|
|
* The real value of a logic expression is the integer value of the
|
|
|
|
|
* expression converted to real.
|
|
|
|
|
*/
|
2014-10-24 18:32:32 +02:00
|
|
|
static void draw_real_logic_expr(ivl_expr_t expr)
|
2009-12-20 00:34:54 +01:00
|
|
|
{
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(expr);
|
2009-12-20 00:34:54 +01:00
|
|
|
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
2015-10-01 00:41:22 +02:00
|
|
|
fprintf(vvp_out, " %%cvt/rv%s;\n", sign_flag);
|
2009-12-20 00:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 23:48:25 +02:00
|
|
|
static void draw_select_real(ivl_expr_t expr)
|
2012-10-08 05:29:24 +02:00
|
|
|
{
|
|
|
|
|
/* The sube references the expression to be selected from. */
|
|
|
|
|
ivl_expr_t sube = ivl_expr_oper1(expr);
|
|
|
|
|
/* This is the select expression */
|
|
|
|
|
ivl_expr_t shift= ivl_expr_oper2(expr);
|
|
|
|
|
|
|
|
|
|
/* Assume the sub-expression is a signal */
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(sube);
|
2020-07-20 06:34:04 +02:00
|
|
|
assert(ivl_signal_data_type(sig) == IVL_VT_DARRAY || ivl_signal_data_type(sig) == IVL_VT_QUEUE);
|
2012-10-08 05:29:24 +02:00
|
|
|
|
|
|
|
|
draw_eval_expr_into_integer(shift, 3);
|
2012-10-23 23:48:25 +02:00
|
|
|
fprintf(vvp_out, " %%load/dar/r v%p_0;\n", sig);
|
2012-10-08 05:29:24 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-20 06:34:04 +02:00
|
|
|
static void real_ex_pop(ivl_expr_t expr)
|
|
|
|
|
{
|
|
|
|
|
const char*fb;
|
|
|
|
|
ivl_expr_t arg;
|
|
|
|
|
|
2020-07-26 07:15:48 +02:00
|
|
|
if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0)
|
2020-07-20 06:34:04 +02:00
|
|
|
fb = "b";
|
|
|
|
|
else
|
|
|
|
|
fb = "f";
|
|
|
|
|
|
|
|
|
|
arg = ivl_expr_parm(expr, 0);
|
|
|
|
|
assert(ivl_expr_type(arg) == IVL_EX_SIGNAL);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%qpop/%s/real v%p_0;\n", fb, ivl_expr_signal(arg));
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_sfunc_real(ivl_expr_t expr)
|
2003-01-27 01:14:37 +01:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
switch (ivl_expr_value(expr)) {
|
2003-03-15 05:45:18 +01:00
|
|
|
|
2003-02-07 03:46:16 +01:00
|
|
|
case IVL_VT_REAL:
|
2008-12-18 17:45:47 +01:00
|
|
|
if (ivl_expr_parms(expr) == 0) {
|
2014-01-14 02:46:39 +01:00
|
|
|
fprintf(vvp_out, " %%vpi_func/r %u %u \"%s\" {0 0 0};\n",
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_file_table_index(ivl_expr_file(expr)),
|
2012-10-23 02:20:43 +02:00
|
|
|
ivl_expr_lineno(expr), ivl_expr_name(expr));
|
2003-01-27 01:14:37 +01:00
|
|
|
|
2003-03-15 05:45:18 +01:00
|
|
|
} else {
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_vpi_rfunc_call(expr);
|
2003-03-15 05:45:18 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2003-02-07 03:46:16 +01:00
|
|
|
|
|
|
|
|
case IVL_VT_VECTOR:
|
|
|
|
|
/* If the value of the sfunc is a vector, then evaluate
|
|
|
|
|
it as a vector, then convert the result to a real
|
|
|
|
|
(via an index register) for the result. */
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_real_logic_expr(expr);
|
2003-03-15 05:45:18 +01:00
|
|
|
break;
|
2003-02-07 03:46:16 +01:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-27 01:14:37 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_signal_real_real(ivl_expr_t expr)
|
2005-07-07 18:22:49 +02:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2016-02-01 18:31:06 +01:00
|
|
|
/* Special Case: If the signal is the return value of the function,
|
|
|
|
|
then use a different opcode to get the value. */
|
|
|
|
|
if (signal_is_return_value(sig)) {
|
|
|
|
|
assert(ivl_signal_dimensions(sig) == 0);
|
|
|
|
|
fprintf(vvp_out, " %%retload/real 0; Load %s (draw_signal_real_real)\n",
|
|
|
|
|
ivl_signal_basename(sig));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-11-02 04:44:03 +01:00
|
|
|
if (ivl_signal_dimensions(sig) == 0) {
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
|
|
|
|
|
return;
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
2005-07-07 18:22:49 +02:00
|
|
|
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
2008-11-02 04:44:03 +01:00
|
|
|
int word_ix = allocate_word();
|
|
|
|
|
draw_eval_expr_into_integer(word_ex, word_ix);
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%load/ar v%p, %d;\n", sig, word_ix);
|
2008-11-02 04:44:03 +01:00
|
|
|
clr_word(word_ix);
|
2005-07-07 18:22:49 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_signal_real(ivl_expr_t expr)
|
2005-07-07 18:22:49 +02:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
2005-07-07 18:22:49 +02:00
|
|
|
switch (ivl_signal_data_type(sig)) {
|
|
|
|
|
case IVL_VT_LOGIC:
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_real_logic_expr(expr);
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2005-07-07 18:22:49 +02:00
|
|
|
case IVL_VT_REAL:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_signal_real_real(expr);
|
|
|
|
|
return;
|
2005-07-07 18:22:49 +02:00
|
|
|
default:
|
2010-07-07 23:33:10 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: signal_data_type=%d\n",
|
2005-07-07 18:22:49 +02:00
|
|
|
ivl_signal_data_type(sig));
|
|
|
|
|
assert(0);
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2005-07-07 18:22:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-07 23:33:10 +02:00
|
|
|
/* If we have nested ternary operators they are likely tail recursive.
|
|
|
|
|
* This code is structured to allow this recursion without overflowing
|
|
|
|
|
* the available thread words. */
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_ternary_real(ivl_expr_t expr)
|
2007-02-14 06:59:46 +01:00
|
|
|
{
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_expr_t cond = ivl_expr_oper1(expr);
|
|
|
|
|
ivl_expr_t true_ex = ivl_expr_oper2(expr);
|
|
|
|
|
ivl_expr_t false_ex = ivl_expr_oper3(expr);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
|
|
|
|
unsigned lab_true = local_count++;
|
2008-03-08 03:51:50 +01:00
|
|
|
unsigned lab_out = local_count++;
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2014-01-21 21:02:59 +01:00
|
|
|
int cond_flag = allocate_flag();
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2014-01-21 21:02:59 +01:00
|
|
|
/* Evaluate the ternary condition. */
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(cond);
|
2014-01-21 21:02:59 +01:00
|
|
|
if (ivl_expr_width(cond) > 1)
|
|
|
|
|
fprintf(vvp_out, " %%or/r;\n");
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2014-01-21 21:02:59 +01:00
|
|
|
fprintf(vvp_out, " %%flag_set/vec4 %d;\n", cond_flag);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
|
|
|
|
|
2010-07-07 23:33:10 +02:00
|
|
|
/* Evaluate the true expression second. */
|
2014-01-21 21:02:59 +01:00
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%u.%u, %d;\n",
|
|
|
|
|
thread_count, lab_true, cond_flag);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
/* Evaluate the false expression. */
|
|
|
|
|
draw_eval_real(false_ex);
|
2014-01-21 21:02:59 +01:00
|
|
|
fprintf(vvp_out, " %%jmp/0 T_%u.%u, %d; End of false expr.\n",
|
|
|
|
|
thread_count, lab_out, cond_flag);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2010-07-07 23:33:10 +02:00
|
|
|
/* If the conditional is undefined then blend the real words. */
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_eval_real(true_ex);
|
|
|
|
|
fprintf(vvp_out, " %%blend/wr;\n");
|
2012-08-31 21:35:26 +02:00
|
|
|
fprintf(vvp_out, " %%jmp T_%u.%u; End of blend\n",
|
2008-03-08 03:51:50 +01:00
|
|
|
thread_count, lab_out);
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
/* Evaluate the true expression. */
|
|
|
|
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_true);
|
|
|
|
|
draw_eval_real(true_ex);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2008-03-08 03:51:50 +01:00
|
|
|
/* This is the out label. */
|
2012-08-31 21:35:26 +02:00
|
|
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, lab_out);
|
2007-02-14 06:59:46 +01:00
|
|
|
|
2014-01-21 21:02:59 +01:00
|
|
|
clr_flag(cond_flag);
|
2007-02-14 06:59:46 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void increment(ivl_expr_t e, bool pre)
|
2011-08-21 05:29:41 +02:00
|
|
|
{
|
2012-10-23 02:20:43 +02:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(e);
|
|
|
|
|
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
|
|
|
|
|
if (!pre) fprintf(vvp_out, " %%dup/real;\n");
|
|
|
|
|
fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n");
|
|
|
|
|
fprintf(vvp_out, " %%add/wr;\n");
|
|
|
|
|
if ( pre) fprintf(vvp_out, " %%dup/real;\n");
|
|
|
|
|
fprintf(vvp_out, " %%store/real v%p_0;\n", sig);
|
2011-08-21 05:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void decrement(ivl_expr_t e, bool pre)
|
2011-08-21 05:29:41 +02:00
|
|
|
{
|
2012-10-23 02:20:43 +02:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(e);
|
|
|
|
|
fprintf(vvp_out, " %%load/real v%p_0;\n", sig);
|
|
|
|
|
if (!pre) fprintf(vvp_out, " %%dup/real;\n");
|
|
|
|
|
fprintf(vvp_out, " %%pushi/real 1, 0x1000;\n");
|
|
|
|
|
fprintf(vvp_out, " %%sub/wr;\n");
|
|
|
|
|
if ( pre) fprintf(vvp_out, " %%dup/real;\n");
|
|
|
|
|
fprintf(vvp_out, " %%store/real v%p_0;\n", sig);
|
2011-08-21 05:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
static void draw_unary_real(ivl_expr_t expr)
|
2007-02-20 06:58:36 +01:00
|
|
|
{
|
2008-09-30 03:06:47 +02:00
|
|
|
ivl_expr_t sube;
|
|
|
|
|
|
2009-12-20 00:34:54 +01:00
|
|
|
/* If the opcode is a ~ or a ! then the sub expression must not be
|
|
|
|
|
* a real expression, so use vector evaluation and then convert
|
2008-04-21 22:45:32 +02:00
|
|
|
* that result to a real value. */
|
2009-12-20 00:34:54 +01:00
|
|
|
if ((ivl_expr_opcode(expr) == '~') || (ivl_expr_opcode(expr) == '!')) {
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_real_logic_expr(expr);
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2008-06-20 04:14:19 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-18 17:45:47 +01:00
|
|
|
sube = ivl_expr_oper1(expr);
|
2010-06-19 01:03:17 +02:00
|
|
|
|
|
|
|
|
if (ivl_expr_opcode(expr) == 'r') { /* Cast an integer value to a real. */
|
2010-09-27 20:03:43 +02:00
|
|
|
const char *suffix = "";
|
2010-06-19 01:03:17 +02:00
|
|
|
assert(ivl_expr_value(sube) != IVL_VT_REAL);
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(sube);
|
2010-06-19 01:03:17 +02:00
|
|
|
if (ivl_expr_signed(sube)) suffix = "/s";
|
2014-01-21 21:02:59 +01:00
|
|
|
fprintf(vvp_out, " %%cvt/rv%s;\n", suffix);
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2010-06-19 01:03:17 +02:00
|
|
|
}
|
|
|
|
|
|
2007-02-20 06:58:36 +01:00
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
if (ivl_expr_opcode(expr) == '+') {
|
|
|
|
|
draw_eval_real(sube);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-02-20 06:58:36 +01:00
|
|
|
|
2008-12-18 17:45:47 +01:00
|
|
|
if (ivl_expr_opcode(expr) == '-') {
|
2012-10-23 02:20:43 +02:00
|
|
|
fprintf(vvp_out, " %%pushi/real 0, 0; load 0.0\n");
|
|
|
|
|
draw_eval_real(sube);
|
|
|
|
|
fprintf(vvp_out, " %%sub/wr;\n");
|
|
|
|
|
return;
|
2007-02-20 06:58:36 +01:00
|
|
|
}
|
|
|
|
|
|
2010-06-19 01:03:17 +02:00
|
|
|
if (ivl_expr_opcode(expr) == 'm') { /* abs() */
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_eval_real(sube);
|
|
|
|
|
fprintf(vvp_out, " %%abs/wr;\n");
|
|
|
|
|
return;
|
2008-05-04 06:54:42 +02:00
|
|
|
}
|
|
|
|
|
|
2011-08-07 00:27:39 +02:00
|
|
|
if (ivl_expr_opcode(expr) == 'v') { /* Handled in eval_expr.c. */
|
2010-07-07 23:33:10 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: real -> integer cast in real "
|
2010-06-19 01:03:17 +02:00
|
|
|
"context.\n");
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
switch (ivl_expr_opcode(expr)) {
|
|
|
|
|
case 'I':
|
|
|
|
|
increment(sube, true);
|
|
|
|
|
return;
|
|
|
|
|
case 'i':
|
|
|
|
|
increment(sube, false);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case 'D':
|
|
|
|
|
decrement(sube, true);
|
|
|
|
|
return;
|
|
|
|
|
case 'd':
|
|
|
|
|
decrement(sube, false);
|
|
|
|
|
return;
|
2011-08-21 05:29:41 +02:00
|
|
|
}
|
|
|
|
|
|
2010-07-07 23:33:10 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n",
|
2010-06-19 01:03:17 +02:00
|
|
|
ivl_expr_opcode(expr));
|
|
|
|
|
assert(0);
|
2007-02-20 06:58:36 +01:00
|
|
|
}
|
|
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
void draw_eval_real(ivl_expr_t expr)
|
2003-01-26 22:15:58 +01:00
|
|
|
{
|
|
|
|
|
|
2009-06-16 01:50:18 +02:00
|
|
|
/* If this expression/sub-expression is not real then we need
|
|
|
|
|
* to evaluate it as a bit value and then convert the bit based
|
|
|
|
|
* result to a real value. This is required to get integer
|
|
|
|
|
* division to work correctly. */
|
|
|
|
|
if (ivl_expr_value(expr) != IVL_VT_REAL) {
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_real_logic_expr(expr);
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2009-06-16 01:50:18 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-18 17:45:47 +01:00
|
|
|
switch (ivl_expr_type(expr)) {
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
case IVL_EX_BINARY:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_binary_real(expr);
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_NUMBER:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_number_real(expr);
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
2013-01-11 03:48:15 +01:00
|
|
|
case IVL_EX_PROPERTY:
|
|
|
|
|
draw_property_real(expr);
|
|
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
case IVL_EX_REALNUM:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_realnum_real(expr);
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
2012-10-08 05:29:24 +02:00
|
|
|
case IVL_EX_SELECT:
|
2012-10-23 23:48:25 +02:00
|
|
|
draw_select_real(expr);
|
2012-10-08 05:29:24 +02:00
|
|
|
break;
|
|
|
|
|
|
2003-01-27 01:14:37 +01:00
|
|
|
case IVL_EX_SFUNC:
|
2020-07-26 07:15:48 +02:00
|
|
|
if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_back")==0)
|
2020-07-20 06:34:04 +02:00
|
|
|
real_ex_pop(expr);
|
2020-07-26 07:15:48 +02:00
|
|
|
else if (strcmp(ivl_expr_name(expr), "$ivl_queue_method$pop_front")==0)
|
2020-07-20 06:34:04 +02:00
|
|
|
real_ex_pop(expr);
|
|
|
|
|
else
|
|
|
|
|
draw_sfunc_real(expr);
|
2003-01-27 01:14:37 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
case IVL_EX_SIGNAL:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_signal_real(expr);
|
2003-01-26 22:15:58 +01:00
|
|
|
break;
|
|
|
|
|
|
2007-02-14 06:59:46 +01:00
|
|
|
case IVL_EX_TERNARY:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_ternary_real(expr);
|
2007-02-14 06:59:46 +01:00
|
|
|
break;
|
|
|
|
|
|
2005-07-13 06:52:31 +02:00
|
|
|
case IVL_EX_UFUNC:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_ufunc_real(expr);
|
2005-07-13 06:52:31 +02:00
|
|
|
break;
|
|
|
|
|
|
2007-02-20 06:58:36 +01:00
|
|
|
case IVL_EX_UNARY:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_unary_real(expr);
|
2007-02-20 06:58:36 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
default:
|
2008-12-18 17:45:47 +01:00
|
|
|
if (ivl_expr_value(expr) == IVL_VT_VECTOR) {
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(expr);
|
2008-12-18 17:45:47 +01:00
|
|
|
const char*sign_flag = ivl_expr_signed(expr)? "/s" : "";
|
2015-10-01 00:41:22 +02:00
|
|
|
fprintf(vvp_out, " %%cvt/rv%s;\n", sign_flag);
|
2003-02-07 03:46:16 +01:00
|
|
|
|
|
|
|
|
} else {
|
2020-05-31 21:36:01 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: XXXX Evaluate real expression (%d)\n",
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_expr_type(expr));
|
2003-02-07 03:46:16 +01:00
|
|
|
fprintf(vvp_out, " ; XXXX Evaluate real expression (%d)\n",
|
2008-12-18 17:45:47 +01:00
|
|
|
ivl_expr_type(expr));
|
2012-10-23 02:20:43 +02:00
|
|
|
return;
|
2003-02-07 03:46:16 +01:00
|
|
|
}
|
|
|
|
|
break;
|
2003-01-26 22:15:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|