2001-03-22 06:06:21 +01:00
|
|
|
/*
|
2008-01-02 19:42:23 +01:00
|
|
|
* Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com)
|
2001-03-22 06:06:21 +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
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "vvp_priv.h"
|
2001-07-07 22:20:10 +02:00
|
|
|
# include <string.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2001-07-07 22:20:10 +02:00
|
|
|
# include <malloc.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
2001-03-22 06:06:21 +01:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
|
|
|
|
|
int ok_flags);
|
2007-12-05 04:15:15 +01:00
|
|
|
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
|
2008-06-14 05:23:40 +02:00
|
|
|
int add_index, long immediate);
|
2001-03-23 02:10:24 +01:00
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
int number_is_unknown(ivl_expr_t ex)
|
|
|
|
|
{
|
|
|
|
|
const char*bits;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
2007-10-04 05:58:40 +02:00
|
|
|
if (ivl_expr_type(ex) == IVL_EX_ULONG)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
assert(ivl_expr_type(ex) == IVL_EX_NUMBER);
|
|
|
|
|
|
|
|
|
|
bits = ivl_expr_bits(ex);
|
|
|
|
|
for (idx = 0 ; idx < ivl_expr_width(ex) ; idx += 1)
|
|
|
|
|
if ((bits[idx] != '0') && (bits[idx] != '1'))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function returns TRUE if the number can be represented in a
|
|
|
|
|
* 16bit immediate value. This amounts to looking for non-zero bits
|
|
|
|
|
* above bitX. The maximum size of the immediate may vary, so use
|
|
|
|
|
* lim_wid at the width limit to use.
|
|
|
|
|
*/
|
2008-06-13 22:32:06 +02:00
|
|
|
int number_is_immediate(ivl_expr_t ex, unsigned lim_wid, int negative_ok_flag)
|
2002-06-02 20:57:17 +02:00
|
|
|
{
|
|
|
|
|
const char*bits;
|
2008-06-13 22:32:06 +02:00
|
|
|
unsigned nbits = ivl_expr_width(ex);
|
|
|
|
|
char pad_bit = '0';
|
2002-06-02 20:57:17 +02:00
|
|
|
unsigned idx;
|
|
|
|
|
|
2006-01-02 06:33:19 +01:00
|
|
|
if (ivl_expr_type(ex) != IVL_EX_NUMBER
|
|
|
|
|
&& ivl_expr_type(ex) != IVL_EX_ULONG)
|
|
|
|
|
return 0;
|
2002-06-02 20:57:17 +02:00
|
|
|
|
|
|
|
|
bits = ivl_expr_bits(ex);
|
|
|
|
|
|
2008-06-13 22:32:06 +02:00
|
|
|
if (ivl_expr_signed(ex) && bits[nbits-1]=='1')
|
|
|
|
|
pad_bit = '1';
|
|
|
|
|
|
|
|
|
|
if (pad_bit == '1' && !negative_ok_flag)
|
2007-10-04 05:58:40 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2008-06-13 22:32:06 +02:00
|
|
|
for (idx = lim_wid ; idx < nbits ; idx += 1)
|
|
|
|
|
if (bits[idx] != pad_bit)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-13 06:41:11 +02:00
|
|
|
long get_number_immediate(ivl_expr_t ex)
|
2002-06-02 20:57:17 +02:00
|
|
|
{
|
2008-06-13 06:41:11 +02:00
|
|
|
long imm = 0;
|
2002-06-02 20:57:17 +02:00
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_type(ex)) {
|
|
|
|
|
case IVL_EX_ULONG:
|
|
|
|
|
imm = ivl_expr_uvalue(ex);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_NUMBER: {
|
|
|
|
|
const char*bits = ivl_expr_bits(ex);
|
|
|
|
|
unsigned nbits = ivl_expr_width(ex);
|
|
|
|
|
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]){
|
|
|
|
|
case '0':
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
2008-05-29 23:00:32 +02:00
|
|
|
assert(idx < 8*sizeof(imm));
|
2008-06-13 06:41:11 +02:00
|
|
|
imm |= 1L << idx;
|
2002-06-02 20:57:17 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2008-06-13 06:41:11 +02:00
|
|
|
if (ivl_expr_signed(ex) && bits[nbits-1]=='1' && nbits < 8*sizeof(imm))
|
|
|
|
|
imm |= -1L << nbits;
|
2002-06-02 20:57:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return imm;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-07 22:12:19 +01:00
|
|
|
static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
|
|
|
|
{
|
|
|
|
|
switch (ivl_expr_type(expr)) {
|
|
|
|
|
|
2008-06-13 06:41:11 +02:00
|
|
|
case IVL_EX_NUMBER:
|
2007-12-07 22:12:19 +01:00
|
|
|
case IVL_EX_ULONG:
|
2008-06-13 06:41:11 +02:00
|
|
|
{
|
|
|
|
|
long imm = get_number_immediate(expr);
|
|
|
|
|
if (imm >= 0) {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load %u, %ld;\n", ix, imm);
|
2008-06-13 06:41:11 +02:00
|
|
|
} else {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load %u, 0; loading %ld\n", ix, imm);
|
|
|
|
|
fprintf(vvp_out, " %%ix/sub %u, %ld;\n", ix, -imm);
|
2008-06-13 06:41:11 +02:00
|
|
|
}
|
2008-09-18 01:18:17 +02:00
|
|
|
/* This can not have have a X/Z value so clear bit 4. */
|
|
|
|
|
fprintf(vvp_out, " %%mov 4, 0, 1;\n");
|
2008-06-13 06:41:11 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2007-12-07 22:12:19 +01:00
|
|
|
|
|
|
|
|
case IVL_EX_SIGNAL: {
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
2008-05-16 19:38:32 +02:00
|
|
|
|
2007-12-07 22:12:19 +01:00
|
|
|
unsigned word = 0;
|
2008-05-19 20:31:40 +02:00
|
|
|
if (ivl_signal_dimensions(sig) > 0) {
|
2008-05-16 19:38:32 +02:00
|
|
|
|
|
|
|
|
/* Detect the special case that this is a
|
|
|
|
|
variable array. In this case, the ix/getv
|
|
|
|
|
will not work, so do it the hard way. */
|
|
|
|
|
if (ivl_signal_type(sig) == IVL_SIT_REG) {
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
rv = draw_eval_expr(expr, 0);
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
2008-05-16 19:38:32 +02:00
|
|
|
ix, rv.base, rv.wid);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-07 22:12:19 +01:00
|
|
|
ivl_expr_t ixe = ivl_expr_oper1(expr);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(ixe, 8*sizeof(unsigned long), 0))
|
2008-01-15 00:57:01 +01:00
|
|
|
word = get_number_immediate(ixe);
|
|
|
|
|
else {
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
rv = draw_eval_expr(expr, 0);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
|
|
|
|
ix, rv.base, rv.wid);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2007-12-07 22:12:19 +01:00
|
|
|
}
|
2008-09-11 04:37:11 +02:00
|
|
|
char*type = ivl_signal_signed(sig) ? "/s" : "";
|
|
|
|
|
fprintf(vvp_out, " %%ix/getv%s %u, v%p_%u;\n", type, ix,
|
|
|
|
|
sig, word);
|
2007-12-07 22:12:19 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
rv = draw_eval_expr(expr, 0);
|
2008-01-15 00:57:01 +01:00
|
|
|
fprintf(vvp_out, " %%ix/get %u, %u, %u;\n",
|
2007-12-07 22:12:19 +01:00
|
|
|
ix, rv.base, rv.wid);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-02 03:43:57 +01:00
|
|
|
/*
|
|
|
|
|
* This function, in addition to setting the value into index 0, sets
|
|
|
|
|
* bit 4 to 1 if the value is unknown.
|
|
|
|
|
*/
|
|
|
|
|
void draw_eval_expr_into_integer(ivl_expr_t expr, unsigned ix)
|
|
|
|
|
{
|
|
|
|
|
int word;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_value(expr)) {
|
|
|
|
|
|
|
|
|
|
case IVL_VT_BOOL:
|
|
|
|
|
case IVL_VT_LOGIC:
|
2007-12-07 22:12:19 +01:00
|
|
|
eval_logic_into_integer(expr, ix);
|
2006-02-02 03:43:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
word = draw_eval_real(expr);
|
|
|
|
|
clr_word(word);
|
|
|
|
|
fprintf(vvp_out, " %%cvt/ir %u, %u;\n", ix, word);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "XXXX ivl_expr_value == %d\n",
|
|
|
|
|
ivl_expr_value(expr));
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
/*
|
2002-09-24 06:20:32 +02:00
|
|
|
* The STUFF_OK_XZ bit is true if the output is going to be further
|
2007-02-26 20:49:48 +01:00
|
|
|
* processed so that x and z values are equivalent. This may allow for
|
2002-09-13 05:12:50 +02:00
|
|
|
* new optimizations.
|
|
|
|
|
*/
|
2002-06-02 20:57:17 +02:00
|
|
|
static struct vector_info draw_eq_immediate(ivl_expr_t exp, unsigned ewid,
|
|
|
|
|
ivl_expr_t le,
|
2002-09-13 05:12:50 +02:00
|
|
|
ivl_expr_t re,
|
2002-09-24 06:20:32 +02:00
|
|
|
int stuff_ok_flag)
|
2002-06-02 20:57:17 +02:00
|
|
|
{
|
|
|
|
|
unsigned wid;
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
unsigned long imm = get_number_immediate(re);
|
|
|
|
|
|
|
|
|
|
wid = ivl_expr_width(le);
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag);
|
2002-06-02 20:57:17 +02:00
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case 'E': /* === */
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
|
|
|
|
|
lv.base, imm, wid);
|
2002-09-24 06:20:32 +02:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
2002-06-02 20:57:17 +02:00
|
|
|
lv.base = 6;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'e': /* == */
|
2002-09-13 05:12:50 +02:00
|
|
|
/* If this is a single bit being compared to 1, and the
|
|
|
|
|
output doesn't care about x vs z, then just return
|
|
|
|
|
the value itself. */
|
2002-09-24 06:20:32 +02:00
|
|
|
if ((stuff_ok_flag&STUFF_OK_XZ) && (lv.wid == 1) && (imm == 1))
|
2002-09-13 05:12:50 +02:00
|
|
|
break;
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
|
|
|
|
|
lv.base, imm, wid);
|
2002-09-24 06:20:32 +02:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
2002-06-02 20:57:17 +02:00
|
|
|
lv.base = 4;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'N': /* !== */
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
|
|
|
|
|
lv.base, imm, wid);
|
2002-09-24 06:20:32 +02:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
2002-06-02 20:57:17 +02:00
|
|
|
lv.base = 6;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
fprintf(vvp_out, " %%inv 6, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'n': /* != */
|
2002-09-13 06:09:51 +02:00
|
|
|
/* If this is a single bit being compared to 0, and the
|
|
|
|
|
output doesn't care about x vs z, then just return
|
|
|
|
|
the value itself. */
|
2002-09-24 06:20:32 +02:00
|
|
|
if ((stuff_ok_flag&STUFF_OK_XZ) && (lv.wid == 1) && (imm == 0))
|
2002-09-13 06:09:51 +02:00
|
|
|
break;
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
fprintf(vvp_out, " %%cmpi/u %u, %lu, %u;\n",
|
|
|
|
|
lv.base, imm, wid);
|
2002-09-24 06:20:32 +02:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
2002-06-02 20:57:17 +02:00
|
|
|
lv.base = 4;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
fprintf(vvp_out, " %%inv 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
/* In the special case that 47 bits are ok, and this really is
|
|
|
|
|
a single bit value, then we are done. */
|
|
|
|
|
if ((lv.wid == 1) && (ewid == 1) && (stuff_ok_flag&STUFF_OK_47))
|
|
|
|
|
return lv;
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
/* Move the result out out the 4-7 bit that the compare
|
|
|
|
|
uses. This is because that bit may be clobbered by other
|
|
|
|
|
expressions. */
|
2002-09-13 05:12:50 +02:00
|
|
|
if (lv.base < 8) {
|
2003-06-17 21:17:42 +02:00
|
|
|
unsigned base = allocate_vector(ewid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of equality compare.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = ewid;
|
|
|
|
|
if (ewid > 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, ewid-1);
|
2002-09-13 06:09:51 +02:00
|
|
|
|
|
|
|
|
} else if (lv.wid < ewid) {
|
2003-06-17 21:17:42 +02:00
|
|
|
unsigned base = allocate_vector(ewid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of equality compare.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
2002-09-13 06:09:51 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", base,
|
|
|
|
|
lv.base, lv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
base+lv.wid, ewid-lv.wid);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = ewid;
|
2002-06-02 20:57:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
/*
|
|
|
|
|
* This handles the special case that the operands of the comparison
|
|
|
|
|
* are real valued expressions.
|
|
|
|
|
*/
|
|
|
|
|
static struct vector_info draw_binary_expr_eq_real(ivl_expr_t exp)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
int lword, rword;
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(1);
|
|
|
|
|
res.wid = 1;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
lword = draw_eval_real(ivl_expr_oper1(exp));
|
|
|
|
|
rword = draw_eval_real(ivl_expr_oper2(exp));
|
|
|
|
|
|
|
|
|
|
clr_word(lword);
|
|
|
|
|
clr_word(rword);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
|
|
|
|
|
case 'e':
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'n': /* != */
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 4, 1;\n", res.base);
|
|
|
|
|
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
static struct vector_info draw_binary_expr_eq(ivl_expr_t exp,
|
|
|
|
|
unsigned ewid,
|
2002-09-24 06:20:32 +02:00
|
|
|
int stuff_ok_flag)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
2001-03-23 02:10:24 +01:00
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
unsigned wid;
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
2004-06-30 05:07:32 +02:00
|
|
|
if ((ivl_expr_value(le) == IVL_VT_REAL)
|
|
|
|
|
||(ivl_expr_value(re) == IVL_VT_REAL)) {
|
|
|
|
|
return draw_binary_expr_eq_real(exp);
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(re,16,0) && !number_is_unknown(re))
|
2002-09-24 06:20:32 +02:00
|
|
|
return draw_eq_immediate(exp, ewid, le, re, stuff_ok_flag);
|
2002-06-02 20:57:17 +02:00
|
|
|
|
2005-09-14 04:53:13 +02:00
|
|
|
assert(ivl_expr_value(le) == IVL_VT_LOGIC
|
|
|
|
|
|| ivl_expr_value(le) == IVL_VT_BOOL);
|
|
|
|
|
assert(ivl_expr_value(re) == IVL_VT_LOGIC
|
|
|
|
|
|| ivl_expr_value(re) == IVL_VT_BOOL);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
wid = ivl_expr_width(le);
|
2001-03-23 02:10:24 +01:00
|
|
|
if (ivl_expr_width(re) > wid)
|
|
|
|
|
wid = ivl_expr_width(re);
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, stuff_ok_flag&~STUFF_OK_47);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid, stuff_ok_flag&~STUFF_OK_47);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
2001-03-27 08:43:27 +02:00
|
|
|
case 'E': /* === */
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n", lv.base,
|
|
|
|
|
rv.base, lv.wid);
|
2003-01-26 22:15:58 +01:00
|
|
|
if (lv.base >= 8)
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
if (rv.base >= 8)
|
|
|
|
|
clr_vector(rv);
|
2001-03-27 08:43:27 +02:00
|
|
|
lv.base = 6;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case 'e': /* == */
|
2001-09-29 03:53:22 +02:00
|
|
|
if (lv.wid != rv.wid) {
|
|
|
|
|
fprintf(stderr,"internal error: operands of == "
|
|
|
|
|
" have different widths: %u vs %u\n",
|
|
|
|
|
lv.wid, rv.wid);
|
|
|
|
|
}
|
2001-03-22 06:06:21 +01:00
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n", lv.base,
|
|
|
|
|
rv.base, lv.wid);
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
lv.base = 4;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-27 08:43:27 +02:00
|
|
|
case 'N': /* !== */
|
2001-11-19 05:25:46 +01:00
|
|
|
if (lv.wid != rv.wid) {
|
|
|
|
|
fprintf(stderr,"internal error: operands of !== "
|
|
|
|
|
" have different widths: %u vs %u\n",
|
|
|
|
|
lv.wid, rv.wid);
|
|
|
|
|
}
|
2001-03-27 08:43:27 +02:00
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n", lv.base,
|
|
|
|
|
rv.base, lv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%inv 6, 1;\n");
|
|
|
|
|
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
lv.base = 6;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case 'n': /* != */
|
2001-11-19 05:25:46 +01:00
|
|
|
if (lv.wid != rv.wid) {
|
|
|
|
|
fprintf(stderr,"internal error: operands of != "
|
|
|
|
|
" have different widths: %u vs %u\n",
|
|
|
|
|
lv.wid, rv.wid);
|
|
|
|
|
}
|
2001-03-22 06:06:21 +01:00
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/u %u, %u, %u;\n", lv.base,
|
|
|
|
|
rv.base, lv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%inv 4, 1;\n");
|
|
|
|
|
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
lv.base = 4;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
if ((stuff_ok_flag&STUFF_OK_47) && (wid == 1)) {
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 04:07:34 +02:00
|
|
|
/* Move the result out out the 4-7 bit that the compare
|
|
|
|
|
uses. This is because that bit may be clobbered by other
|
|
|
|
|
expressions. */
|
2003-06-17 21:17:42 +02:00
|
|
|
{ unsigned base = allocate_vector(ewid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of equality compare.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 04:07:34 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
|
|
|
|
lv.base = base;
|
2001-11-19 05:25:46 +01:00
|
|
|
lv.wid = ewid;
|
|
|
|
|
if (ewid > 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, ewid-1);
|
2001-05-01 04:07:34 +02:00
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 08:49:32 +02:00
|
|
|
static struct vector_info draw_binary_expr_land(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr(le, STUFF_OK_XZ);
|
2001-10-10 06:47:43 +02:00
|
|
|
|
|
|
|
|
if ((lv.base >= 4) && (lv.wid > 1)) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
tmp.base = allocate_vector(1);
|
|
|
|
|
tmp.wid = 1;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(tmp.base);
|
2001-10-10 06:47:43 +02:00
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
|
|
|
|
lv.base, lv.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
rv = draw_eval_expr(re, STUFF_OK_XZ);
|
2001-10-10 06:47:43 +02:00
|
|
|
if ((rv.base >= 4) && (rv.wid > 1)) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
tmp.base = allocate_vector(1);
|
|
|
|
|
tmp.wid = 1;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(tmp.base);
|
2001-10-10 06:47:43 +02:00
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
|
|
|
|
rv.base, rv.wid);
|
|
|
|
|
rv = tmp;
|
|
|
|
|
}
|
2001-04-01 08:49:32 +02:00
|
|
|
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
if (rv.base < 4) {
|
|
|
|
|
unsigned lb = lv.base;
|
|
|
|
|
unsigned rb = rv.base;
|
|
|
|
|
|
|
|
|
|
if ((lb == 0) || (rb == 0)) {
|
|
|
|
|
lv.base = 0;
|
|
|
|
|
|
|
|
|
|
} else if ((lb == 1) && (rb == 1)) {
|
|
|
|
|
lv.base = 1;
|
|
|
|
|
} else {
|
|
|
|
|
lv.base = 2;
|
|
|
|
|
}
|
2001-10-10 06:47:43 +02:00
|
|
|
lv.wid = 1;
|
2001-04-01 08:49:32 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%and %u, %u, 1;\n", rv.base, lv.base);
|
|
|
|
|
lv = rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%and %u, %u, 1;\n", lv.base, rv.base);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
/* If we only want the single bit result, then we are done. */
|
|
|
|
|
if (wid == 1)
|
|
|
|
|
return lv;
|
|
|
|
|
|
|
|
|
|
/* Write the result into a zero-padded result. */
|
2003-06-17 21:17:42 +02:00
|
|
|
{ unsigned base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of padded logical AND.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = wid;
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, wid-1);
|
|
|
|
|
}
|
2001-04-01 08:49:32 +02:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-29 22:47:39 +02:00
|
|
|
static struct vector_info draw_binary_expr_lor(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
2003-05-10 04:38:49 +02:00
|
|
|
lv = draw_eval_expr(le, STUFF_OK_XZ);
|
2001-11-19 05:25:46 +01:00
|
|
|
|
|
|
|
|
/* if the left operand has width, then evaluate the single-bit
|
2007-02-26 20:49:48 +01:00
|
|
|
logical equivalent. */
|
2001-11-19 05:25:46 +01:00
|
|
|
if ((lv.base >= 4) && (lv.wid > 1)) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
tmp.base = allocate_vector(1);
|
|
|
|
|
tmp.wid = 1;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(tmp.base);
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
|
|
|
|
lv.base, lv.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-10 04:38:49 +02:00
|
|
|
rv = draw_eval_expr(re, STUFF_OK_XZ);
|
2001-04-29 22:47:39 +02:00
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
/* if the right operand has width, then evaluate the single-bit
|
2007-02-26 20:49:48 +01:00
|
|
|
logical equivalent. */
|
2001-11-19 05:25:46 +01:00
|
|
|
if ((rv.base >= 4) && (rv.wid > 1)) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
tmp.base = allocate_vector(1);
|
|
|
|
|
tmp.wid = 1;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(tmp.base);
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n", tmp.base,
|
|
|
|
|
rv.base, rv.wid);
|
|
|
|
|
rv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-04-29 22:47:39 +02:00
|
|
|
if (lv.base < 4) {
|
|
|
|
|
if (rv.base < 4) {
|
|
|
|
|
unsigned lb = lv.base;
|
|
|
|
|
unsigned rb = rv.base;
|
|
|
|
|
|
|
|
|
|
if ((lb == 0) && (rb == 0)) {
|
|
|
|
|
lv.base = 0;
|
|
|
|
|
|
|
|
|
|
} else if ((lb == 1) || (rb == 1)) {
|
|
|
|
|
lv.base = 1;
|
|
|
|
|
} else {
|
|
|
|
|
lv.base = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%or %u, %u, 1;\n", rv.base, lv.base);
|
|
|
|
|
lv = rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
2001-04-30 07:11:18 +02:00
|
|
|
fprintf(vvp_out, " %%or %u, %u, 1;\n", lv.base, rv.base);
|
2001-04-29 22:47:39 +02:00
|
|
|
clr_vector(rv);
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
|
|
|
|
|
/* If we only want the single bit result, then we are done. */
|
|
|
|
|
if (wid == 1)
|
|
|
|
|
return lv;
|
|
|
|
|
|
|
|
|
|
/* Write the result into a zero-padded result. */
|
2003-06-17 21:17:42 +02:00
|
|
|
{ unsigned base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of padded logical OR.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = wid;
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, wid-1);
|
|
|
|
|
}
|
2001-04-29 22:47:39 +02:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
static struct vector_info draw_binary_expr_le_real(ivl_expr_t exp)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
int lword = draw_eval_real(le);
|
|
|
|
|
int rword = draw_eval_real(re);
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(1);
|
|
|
|
|
res.wid = 1;
|
|
|
|
|
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
clr_word(lword);
|
|
|
|
|
clr_word(rword);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case '<':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-07 03:46:16 +01:00
|
|
|
case 'L': /* <= */
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", lword, rword);
|
|
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
case '>':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-07 03:46:16 +01:00
|
|
|
case 'G': /* >= */
|
|
|
|
|
fprintf(vvp_out, " %%cmp/wr %d, %d;\n", rword, lword);
|
|
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", res.base);
|
|
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-14 04:53:13 +02:00
|
|
|
static struct vector_info draw_binary_expr_le_bool(ivl_expr_t exp,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
int lw, rw;
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
|
|
|
|
|
char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u';
|
|
|
|
|
|
|
|
|
|
assert(ivl_expr_value(le) == IVL_VT_BOOL);
|
|
|
|
|
assert(ivl_expr_value(re) == IVL_VT_BOOL);
|
|
|
|
|
|
|
|
|
|
lw = draw_eval_bool64(le);
|
|
|
|
|
rw = draw_eval_bool64(re);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case 'G':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, rw, lw);
|
|
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'L':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, lw, rw);
|
|
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '<':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, lw, rw);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
|
fprintf(vvp_out, " %%cmp/w%c %u, %u;\n", s_flag, rw, lw);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clr_word(lw);
|
|
|
|
|
clr_word(rw);
|
|
|
|
|
|
|
|
|
|
/* Move the result out out the 4-7 bit that the compare
|
|
|
|
|
uses. This is because that bit may be clobbered by other
|
|
|
|
|
expressions. */
|
|
|
|
|
{ unsigned base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of padded inequality compare.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-14 04:53:13 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
|
|
|
|
|
tmp.base = base;
|
|
|
|
|
tmp.wid = wid;
|
|
|
|
|
if (wid > 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, wid-1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
static struct vector_info draw_binary_expr_le(ivl_expr_t exp,
|
|
|
|
|
unsigned wid,
|
|
|
|
|
int stuff_ok_flag)
|
2001-04-01 09:22:42 +02:00
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
2001-04-05 03:12:27 +02:00
|
|
|
char s_flag = (ivl_expr_signed(le) && ivl_expr_signed(re)) ? 's' : 'u';
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
unsigned owid = ivl_expr_width(le);
|
|
|
|
|
if (ivl_expr_width(re) > owid)
|
|
|
|
|
owid = ivl_expr_width(re);
|
|
|
|
|
|
2003-02-07 03:46:16 +01:00
|
|
|
if (ivl_expr_value(le) == IVL_VT_REAL)
|
|
|
|
|
return draw_binary_expr_le_real(exp);
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_value(re) == IVL_VT_REAL)
|
2003-01-26 22:15:58 +01:00
|
|
|
return draw_binary_expr_le_real(exp);
|
|
|
|
|
|
2005-09-14 04:53:13 +02:00
|
|
|
/* Detect the special case that we can do this with integers. */
|
|
|
|
|
if (ivl_expr_value(le) == IVL_VT_BOOL
|
|
|
|
|
&& ivl_expr_value(re) == IVL_VT_BOOL
|
|
|
|
|
&& owid < 64) {
|
|
|
|
|
return draw_binary_expr_le_bool(exp, wid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(ivl_expr_value(le) == IVL_VT_LOGIC
|
|
|
|
|
|| ivl_expr_value(le) == IVL_VT_BOOL);
|
|
|
|
|
assert(ivl_expr_value(re) == IVL_VT_LOGIC
|
|
|
|
|
|| ivl_expr_value(re) == IVL_VT_BOOL);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2008-01-04 21:25:16 +01:00
|
|
|
lv.wid = 0; lv.base=0;
|
|
|
|
|
rv.wid = 0; rv.base=0;
|
2001-04-01 09:22:42 +02:00
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
2001-04-05 03:12:27 +02:00
|
|
|
case 'G':
|
2007-10-04 05:58:40 +02:00
|
|
|
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
|
2007-10-04 05:58:40 +02:00
|
|
|
unsigned imm = get_number_immediate(le);
|
|
|
|
|
assert(imm >= 0);
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
rv.base, imm, rv.wid);
|
|
|
|
|
} else {
|
|
|
|
|
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
rv.base, lv.base, lv.wid);
|
|
|
|
|
}
|
2001-04-05 03:12:27 +02:00
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
case 'L':
|
2007-10-04 05:58:40 +02:00
|
|
|
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
|
2007-10-04 05:58:40 +02:00
|
|
|
unsigned imm = get_number_immediate(re);
|
|
|
|
|
assert(imm >= 0);
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
lv.base, imm, lv.wid);
|
|
|
|
|
} else {
|
|
|
|
|
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
lv.base, rv.base, lv.wid);
|
|
|
|
|
}
|
2001-04-01 09:22:42 +02:00
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '<':
|
2007-10-04 05:58:40 +02:00
|
|
|
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(re,16,0) && !number_is_unknown(re)) {
|
2007-10-04 05:58:40 +02:00
|
|
|
unsigned imm = get_number_immediate(re);
|
|
|
|
|
assert(imm >= 0);
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
lv.base, imm, lv.wid);
|
|
|
|
|
} else {
|
|
|
|
|
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
lv.base, rv.base, lv.wid);
|
|
|
|
|
}
|
2001-04-05 03:12:27 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '>':
|
2007-10-04 05:58:40 +02:00
|
|
|
rv = draw_eval_expr_wid(re, owid, STUFF_OK_XZ);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(le,16,0) && !number_is_unknown(le)) {
|
2007-10-04 05:58:40 +02:00
|
|
|
unsigned imm = get_number_immediate(le);
|
|
|
|
|
assert(imm >= 0);
|
|
|
|
|
fprintf(vvp_out, " %%cmpi/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
rv.base, imm, rv.wid);
|
|
|
|
|
} else {
|
|
|
|
|
lv = draw_eval_expr_wid(le, owid, STUFF_OK_XZ);
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
rv.base, lv.base, lv.wid);
|
|
|
|
|
}
|
2001-04-01 09:22:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-04 05:58:40 +02:00
|
|
|
if (lv.wid > 0) clr_vector(lv);
|
|
|
|
|
if (rv.wid > 0) clr_vector(rv);
|
2001-04-01 09:22:42 +02:00
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
if ((stuff_ok_flag&STUFF_OK_47) && (wid == 1)) {
|
|
|
|
|
lv.base = 5;
|
|
|
|
|
lv.wid = wid;
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 04:07:34 +02:00
|
|
|
/* Move the result out out the 4-7 bit that the compare
|
|
|
|
|
uses. This is because that bit may be clobbered by other
|
|
|
|
|
expressions. */
|
2003-06-17 21:17:42 +02:00
|
|
|
{ unsigned base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of padded inequality compare.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 04:07:34 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
|
|
|
|
|
lv.base = base;
|
2001-11-19 05:25:46 +01:00
|
|
|
lv.wid = wid;
|
|
|
|
|
if (wid > 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base+1, wid-1);
|
2001-05-01 04:07:34 +02:00
|
|
|
}
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-28 02:51:28 +02:00
|
|
|
static struct vector_info draw_logic_immediate(ivl_expr_t exp,
|
|
|
|
|
ivl_expr_t le,
|
|
|
|
|
ivl_expr_t re,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
|
|
|
|
unsigned long imm = get_number_immediate(re);
|
|
|
|
|
|
|
|
|
|
assert(lv.base >= 4);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
|
|
|
|
|
case '&':
|
|
|
|
|
fprintf(vvp_out, " %%andi %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-02 05:47:49 +02:00
|
|
|
static struct vector_info draw_binary_expr_logic(ivl_expr_t exp,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
2008-05-28 02:51:28 +02:00
|
|
|
if (ivl_expr_opcode(exp) == '&') {
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(re, IMM_WID, 0) && !number_is_unknown(re))
|
2008-05-28 02:51:28 +02:00
|
|
|
return draw_logic_immediate(exp, le, re, wid);
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(le, IMM_WID, 0) && !number_is_unknown(le))
|
2008-05-28 02:51:28 +02:00
|
|
|
return draw_logic_immediate(exp, re, le, wid);
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-02 05:47:49 +02:00
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid, STUFF_OK_XZ);
|
2001-04-02 05:47:49 +02:00
|
|
|
|
2001-04-15 06:07:56 +02:00
|
|
|
/* The result goes into the left operand, and that is returned
|
|
|
|
|
as the result. The instructions do not allow the lv value
|
|
|
|
|
to be a constant bit, so we either switch the operands, or
|
|
|
|
|
copy the vector into a new area. */
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
if (rv.base > 4) {
|
|
|
|
|
struct vector_info tmp = lv;
|
|
|
|
|
lv = rv;
|
|
|
|
|
rv = tmp;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(lv.wid);
|
|
|
|
|
tmp.wid = lv.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of binary logic.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-15 06:07:56 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, lv.base, tmp.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-02 05:47:49 +02:00
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
|
|
|
|
|
case '&':
|
2008-04-21 22:45:32 +02:00
|
|
|
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
2001-04-02 05:47:49 +02:00
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '|':
|
2008-04-21 22:45:32 +02:00
|
|
|
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
2001-04-02 05:47:49 +02:00
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-15 18:37:48 +02:00
|
|
|
case '^':
|
2008-04-21 22:45:32 +02:00
|
|
|
fprintf(vvp_out, " %%xor %u, %u, %u;\n",
|
2001-04-15 18:37:48 +02:00
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-09-12 17:49:43 +02:00
|
|
|
case 'A': /* NAND (~&) */
|
|
|
|
|
fprintf(vvp_out, " %%nand %u, %u, %u;\n",
|
|
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-09-18 06:29:55 +02:00
|
|
|
case 'O': /* NOR (~|) */
|
|
|
|
|
fprintf(vvp_out, " %%nor %u, %u, %u;\n",
|
|
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-15 06:07:56 +02:00
|
|
|
case 'X': /* exclusive nor (~^) */
|
|
|
|
|
fprintf(vvp_out, " %%xnor %u, %u, %u;\n",
|
|
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-02 05:47:49 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-23 20:40:34 +02:00
|
|
|
/*
|
|
|
|
|
* Draw code to evaluate the << expression. Use the %shiftl/i0
|
2001-06-30 23:07:26 +02:00
|
|
|
* or %shiftr/i0 instruction to do the real work of shifting. This
|
|
|
|
|
* means that I can handle both left and right shifts in this
|
|
|
|
|
* function, with the only difference the opcode I generate at the
|
|
|
|
|
* end.
|
2001-06-23 20:40:34 +02:00
|
|
|
*/
|
2001-06-30 23:07:26 +02:00
|
|
|
static struct vector_info draw_binary_expr_lrs(ivl_expr_t exp, unsigned wid)
|
2001-04-21 03:49:17 +02:00
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
2002-12-20 02:11:14 +01:00
|
|
|
const char*opcode = "?";
|
2001-04-21 03:49:17 +02:00
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
|
2002-12-20 02:11:14 +01:00
|
|
|
/* Evaluate the expression that is to be shifted. */
|
2001-06-30 23:07:26 +02:00
|
|
|
switch (ivl_expr_opcode(exp)) {
|
2001-04-21 05:26:23 +02:00
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
case 'l': /* << (left shift) */
|
2002-11-21 23:42:48 +01:00
|
|
|
lv = draw_eval_expr_wid(le, wid, 0);
|
2002-11-22 01:01:50 +01:00
|
|
|
|
|
|
|
|
/* shifting 0 gets 0. */
|
|
|
|
|
if (lv.base == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(lv.wid);
|
|
|
|
|
tmp.wid = lv.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of left shift (<<).\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-22 01:01:50 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, lv.base, lv.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
2002-12-20 02:11:14 +01:00
|
|
|
opcode = "%shiftl";
|
2001-06-30 23:07:26 +02:00
|
|
|
break;
|
2001-04-21 05:26:23 +02:00
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
case 'r': /* >> (unsigned right shift) */
|
2002-11-21 23:42:48 +01:00
|
|
|
|
|
|
|
|
/* with the right shift, there may be high bits that are
|
|
|
|
|
shifted into the desired width of the expression, so
|
|
|
|
|
we let the expression size itself, if it is bigger
|
|
|
|
|
then what is requested of us. */
|
|
|
|
|
if (wid > ivl_expr_width(le)) {
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid, 0);
|
|
|
|
|
} else {
|
|
|
|
|
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
|
|
|
|
}
|
2002-11-22 01:01:50 +01:00
|
|
|
|
|
|
|
|
/* shifting 0 gets 0. */
|
|
|
|
|
if (lv.base == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(lv.wid);
|
|
|
|
|
tmp.wid = lv.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of right shift (>>).\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-22 01:01:50 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, lv.base, lv.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
2002-12-20 02:11:14 +01:00
|
|
|
opcode = "%shiftr";
|
2001-04-21 05:26:23 +02:00
|
|
|
break;
|
2001-06-30 23:07:26 +02:00
|
|
|
|
2003-06-18 05:55:18 +02:00
|
|
|
case 'R': /* >>> (signed right shift) */
|
|
|
|
|
|
|
|
|
|
/* with the right shift, there may be high bits that are
|
|
|
|
|
shifted into the desired width of the expression, so
|
|
|
|
|
we let the expression size itself, if it is bigger
|
|
|
|
|
then what is requested of us. */
|
|
|
|
|
if (wid > ivl_expr_width(le)) {
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid, 0);
|
|
|
|
|
} else {
|
|
|
|
|
lv = draw_eval_expr_wid(le, ivl_expr_width(le), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* shifting 0 gets 0. */
|
|
|
|
|
if (lv.base == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Sign extend any constant begets itself, if this
|
|
|
|
|
expression is signed. */
|
|
|
|
|
if ((lv.base < 4) && (ivl_expr_signed(exp)))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(lv.wid);
|
|
|
|
|
tmp.wid = lv.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of right shift (>>>).\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), lv.wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2003-06-18 05:55:18 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, lv.base, lv.wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_signed(exp))
|
|
|
|
|
opcode = "%shiftr/s";
|
|
|
|
|
else
|
|
|
|
|
opcode = "%shiftr";
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-21 05:26:23 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-12-20 02:11:14 +01:00
|
|
|
/* Figure out the shift amount and load that into the index
|
|
|
|
|
register. The value may be a constant, or may need to be
|
|
|
|
|
evaluated at run time. */
|
2007-12-07 22:12:19 +01:00
|
|
|
eval_logic_into_integer(re,0);
|
2002-12-20 02:11:14 +01:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %s/i0 %u, %u;\n", opcode, lv.base, lv.wid);
|
|
|
|
|
|
|
|
|
|
if (lv.base >= 8)
|
|
|
|
|
save_expression_lookaside(lv.base, exp, lv.wid);
|
|
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
return lv;
|
2001-04-21 05:26:23 +02:00
|
|
|
}
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
static struct vector_info draw_load_add_immediate(ivl_expr_t le,
|
|
|
|
|
ivl_expr_t re,
|
2008-06-14 05:23:40 +02:00
|
|
|
unsigned wid,
|
|
|
|
|
int signed_flag)
|
2007-12-05 04:15:15 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info lv;
|
2008-06-14 05:23:40 +02:00
|
|
|
long imm = get_number_immediate(re);
|
2007-12-05 04:15:15 +01:00
|
|
|
lv.base = allocate_vector(wid);
|
|
|
|
|
lv.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (lv.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of addition.\n",
|
|
|
|
|
ivl_expr_file(le), ivl_expr_lineno(le), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
2007-12-05 04:15:15 +01:00
|
|
|
|
2008-01-13 03:22:46 +01:00
|
|
|
/* Load the signal value with a %load that adds the index
|
2007-12-05 04:15:15 +01:00
|
|
|
register to the value being loaded. */
|
2008-06-14 05:23:40 +02:00
|
|
|
draw_signal_dest(le, lv, signed_flag, imm);
|
2007-12-05 04:15:15 +01:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-31 22:04:57 +02:00
|
|
|
static struct vector_info draw_add_immediate(ivl_expr_t le,
|
|
|
|
|
ivl_expr_t re,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
unsigned long imm;
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
2002-05-31 22:04:57 +02:00
|
|
|
assert(lv.wid == wid);
|
|
|
|
|
|
|
|
|
|
imm = get_number_immediate(re);
|
|
|
|
|
|
2008-05-28 17:47:28 +02:00
|
|
|
/* This shouldn't generally happen, because the elaborator
|
|
|
|
|
should take care of simple constant propagation like this,
|
|
|
|
|
but it doesn't have to and it is easy to catch here. */
|
|
|
|
|
if (imm == 0)
|
|
|
|
|
return lv;
|
|
|
|
|
|
|
|
|
|
switch (lv.base) {
|
|
|
|
|
case 0: /* Left expression is 0. */
|
|
|
|
|
lv.base = allocate_vector(wid);
|
|
|
|
|
if (lv.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of addition.\n",
|
|
|
|
|
ivl_expr_file(re), ivl_expr_lineno(re), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: /* Left expression is 1...1 (i.e. -1) */
|
|
|
|
|
imm -= 1;
|
|
|
|
|
if (imm == 0) {
|
|
|
|
|
lv.base = 0;
|
|
|
|
|
} else {
|
|
|
|
|
lv.base = allocate_vector(wid);
|
|
|
|
|
if (lv.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of addition.\n",
|
|
|
|
|
ivl_expr_file(re), ivl_expr_lineno(re), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, " %%movi %u, %lu %u;\n", lv.base, imm, wid);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: /* Left expression is X or Z */
|
|
|
|
|
case 3:
|
|
|
|
|
lv.base = 2;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* The regular case. */
|
|
|
|
|
fprintf(vvp_out, " %%addi %u, %lu, %u;\n", lv.base, imm, wid);
|
|
|
|
|
break;
|
2002-05-30 03:57:23 +02:00
|
|
|
}
|
|
|
|
|
|
2002-05-29 18:29:34 +02:00
|
|
|
return lv;
|
|
|
|
|
}
|
2001-06-30 23:07:26 +02:00
|
|
|
|
2002-08-28 20:38:07 +02:00
|
|
|
/*
|
|
|
|
|
* The subi is restricted to imm operands that are <= 16 bits wide.
|
|
|
|
|
*/
|
|
|
|
|
static struct vector_info draw_sub_immediate(ivl_expr_t le,
|
|
|
|
|
ivl_expr_t re,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
unsigned long imm;
|
2003-08-03 05:53:38 +02:00
|
|
|
unsigned tmp;
|
2002-08-28 20:38:07 +02:00
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
2002-08-28 20:38:07 +02:00
|
|
|
assert(lv.wid == wid);
|
|
|
|
|
|
|
|
|
|
imm = get_number_immediate(re);
|
2008-05-28 17:47:28 +02:00
|
|
|
if (imm == 0)
|
|
|
|
|
return lv;
|
2002-08-28 20:38:07 +02:00
|
|
|
|
2003-08-03 05:53:38 +02:00
|
|
|
switch (lv.base) {
|
|
|
|
|
case 0:
|
|
|
|
|
case 1:
|
|
|
|
|
tmp = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of subtraction.\n",
|
|
|
|
|
ivl_expr_file(le), ivl_expr_lineno(le), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp, lv.base, wid);
|
2003-08-03 05:53:38 +02:00
|
|
|
lv.base = tmp;
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
2008-05-28 17:47:28 +02:00
|
|
|
break;
|
2003-08-03 05:53:38 +02:00
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
lv.base = 2;
|
2008-05-28 17:47:28 +02:00
|
|
|
break;
|
2003-08-03 05:53:38 +02:00
|
|
|
|
|
|
|
|
default:
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%subi %u, %lu, %u;\n", lv.base, imm, wid);
|
2008-05-28 17:47:28 +02:00
|
|
|
break;
|
2003-08-03 05:53:38 +02:00
|
|
|
}
|
|
|
|
|
|
2002-08-28 20:38:07 +02:00
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2002-05-31 22:04:57 +02:00
|
|
|
static struct vector_info draw_mul_immediate(ivl_expr_t le,
|
|
|
|
|
ivl_expr_t re,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
unsigned long imm;
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
2002-05-31 22:04:57 +02:00
|
|
|
assert(lv.wid == wid);
|
|
|
|
|
|
|
|
|
|
imm = get_number_immediate(re);
|
2008-05-28 17:47:28 +02:00
|
|
|
if (imm == 0)
|
|
|
|
|
return lv;
|
2002-05-31 22:04:57 +02:00
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%muli %u, %lu, %u;\n", lv.base, imm, lv.wid);
|
2002-05-31 22:04:57 +02:00
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-24 06:20:10 +02:00
|
|
|
static struct vector_info draw_binary_expr_arith(ivl_expr_t exp, unsigned wid)
|
2001-03-31 04:00:44 +02:00
|
|
|
{
|
|
|
|
|
ivl_expr_t le = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t re = ivl_expr_oper2(exp);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
2008-05-14 20:51:53 +02:00
|
|
|
const char*sign_string = ivl_expr_signed(le) && ivl_expr_signed(re)? "/s" : "";
|
2002-04-14 20:41:34 +02:00
|
|
|
|
2008-06-14 05:23:40 +02:00
|
|
|
int signed_flag = ivl_expr_signed(exp)? 1 : 0;
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
|
|
|
|
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_ULONG))
|
2008-06-14 05:23:40 +02:00
|
|
|
return draw_load_add_immediate(le, re, wid, signed_flag);
|
2007-12-05 04:15:15 +01:00
|
|
|
|
|
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
|
|
|
|
&& (ivl_expr_type(le) == IVL_EX_SIGNAL)
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_NUMBER))
|
2008-06-14 05:23:40 +02:00
|
|
|
return draw_load_add_immediate(le, re, wid, signed_flag);
|
2007-12-05 04:15:15 +01:00
|
|
|
|
|
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
|
|
|
|
|
&& (ivl_expr_type(le) == IVL_EX_ULONG))
|
2008-06-14 05:23:40 +02:00
|
|
|
return draw_load_add_immediate(re, le, wid, signed_flag);
|
2007-12-05 04:15:15 +01:00
|
|
|
|
|
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_SIGNAL)
|
|
|
|
|
&& (ivl_expr_type(le) == IVL_EX_NUMBER))
|
2008-06-14 05:23:40 +02:00
|
|
|
return draw_load_add_immediate(re, le, wid, signed_flag);
|
2007-12-05 04:15:15 +01:00
|
|
|
|
2002-05-29 18:29:34 +02:00
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_ULONG))
|
|
|
|
|
return draw_add_immediate(le, re, wid);
|
|
|
|
|
|
|
|
|
|
if ((ivl_expr_opcode(exp) == '+')
|
2002-05-30 03:57:23 +02:00
|
|
|
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
2002-05-31 22:04:57 +02:00
|
|
|
&& (! number_is_unknown(re))
|
2008-06-13 22:32:06 +02:00
|
|
|
&& number_is_immediate(re, 8*sizeof(unsigned long), 0))
|
2002-05-29 18:29:34 +02:00
|
|
|
return draw_add_immediate(le, re, wid);
|
|
|
|
|
|
2002-08-28 20:38:07 +02:00
|
|
|
if ((ivl_expr_opcode(exp) == '-')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_ULONG))
|
|
|
|
|
return draw_sub_immediate(le, re, wid);
|
|
|
|
|
|
|
|
|
|
if ((ivl_expr_opcode(exp) == '-')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
|
|
|
|
&& (! number_is_unknown(re))
|
2008-06-13 22:32:06 +02:00
|
|
|
&& number_is_immediate(re, IMM_WID, 0))
|
2002-08-28 20:38:07 +02:00
|
|
|
return draw_sub_immediate(le, re, wid);
|
|
|
|
|
|
2002-05-31 22:04:57 +02:00
|
|
|
if ((ivl_expr_opcode(exp) == '*')
|
|
|
|
|
&& (ivl_expr_type(re) == IVL_EX_NUMBER)
|
|
|
|
|
&& (! number_is_unknown(re))
|
2008-06-13 22:32:06 +02:00
|
|
|
&& number_is_immediate(re, IMM_WID, 0))
|
2002-05-31 22:04:57 +02:00
|
|
|
return draw_mul_immediate(le, re, wid);
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid, STUFF_OK_XZ);
|
2005-09-17 03:01:00 +02:00
|
|
|
rv = draw_eval_expr_wid(re, wid, STUFF_OK_XZ|STUFF_OK_RO);
|
2001-03-31 04:00:44 +02:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
if (lv.wid != wid) {
|
|
|
|
|
fprintf(stderr, "XXXX ivl_expr_opcode(exp) = %c,"
|
|
|
|
|
" lv.wid=%u, wid=%u\n", ivl_expr_opcode(exp),
|
|
|
|
|
lv.wid, wid);
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-17 01:45:05 +02:00
|
|
|
assert(lv.wid == wid);
|
|
|
|
|
assert(rv.wid == wid);
|
|
|
|
|
|
2001-10-14 05:24:35 +02:00
|
|
|
/* The arithmetic instructions replace the left operand with
|
|
|
|
|
the result. If the left operand is a replicated constant,
|
2007-02-26 20:49:48 +01:00
|
|
|
then I need to make a writable copy so that the
|
2001-10-14 05:24:35 +02:00
|
|
|
instruction can operate. */
|
|
|
|
|
if (lv.base < 4) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
|
|
|
|
|
tmp.base = allocate_vector(wid);
|
|
|
|
|
tmp.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of arithmetic expression.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-14 05:24:35 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", tmp.base,
|
|
|
|
|
lv.base, wid);
|
|
|
|
|
lv = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-24 06:20:10 +02:00
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case '+':
|
2001-05-02 03:57:25 +02:00
|
|
|
fprintf(vvp_out, " %%add %u, %u, %u;\n", lv.base, rv.base, wid);
|
2001-05-24 06:20:10 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
|
fprintf(vvp_out, " %%sub %u, %u, %u;\n", lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-06-17 01:45:05 +02:00
|
|
|
case '*':
|
|
|
|
|
fprintf(vvp_out, " %%mul %u, %u, %u;\n", lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-10-16 03:27:17 +02:00
|
|
|
case '/':
|
2002-04-14 20:41:34 +02:00
|
|
|
fprintf(vvp_out, " %%div%s %u, %u, %u;\n", sign_string,
|
|
|
|
|
lv.base, rv.base, wid);
|
2001-10-16 03:27:17 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-05-24 06:20:10 +02:00
|
|
|
case '%':
|
2004-06-19 18:17:37 +02:00
|
|
|
fprintf(vvp_out, " %%mod%s %u, %u, %u;\n", sign_string,
|
|
|
|
|
lv.base, rv.base, wid);
|
2001-05-24 06:20:10 +02:00
|
|
|
break;
|
|
|
|
|
|
2008-02-04 22:04:20 +01:00
|
|
|
case 'p':
|
2008-02-05 04:43:50 +01:00
|
|
|
fprintf(vvp_out, " %%pow%s %u, %u, %u;\n", sign_string,
|
|
|
|
|
lv.base, rv.base, wid);
|
2008-02-04 22:04:20 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-05-24 06:20:10 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2001-03-31 04:00:44 +02:00
|
|
|
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
static struct vector_info draw_binary_expr(ivl_expr_t exp,
|
|
|
|
|
unsigned wid,
|
2002-09-24 06:20:32 +02:00
|
|
|
int stuff_ok_flag)
|
2001-03-23 02:10:24 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info rv;
|
2002-10-20 04:55:37 +02:00
|
|
|
int stuff_ok_used_flag = 0;
|
2001-03-23 02:10:24 +01:00
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
2001-04-01 08:49:32 +02:00
|
|
|
case 'a': /* && (logical and) */
|
|
|
|
|
rv = draw_binary_expr_land(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-27 08:43:27 +02:00
|
|
|
case 'E': /* === */
|
2001-03-23 02:10:24 +01:00
|
|
|
case 'e': /* == */
|
2001-03-27 08:43:27 +02:00
|
|
|
case 'N': /* !== */
|
2001-03-23 02:10:24 +01:00
|
|
|
case 'n': /* != */
|
2002-09-24 06:20:32 +02:00
|
|
|
rv = draw_binary_expr_eq(exp, wid, stuff_ok_flag);
|
2002-10-20 04:55:37 +02:00
|
|
|
stuff_ok_used_flag = 1;
|
2001-03-23 02:10:24 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
case '<':
|
2001-04-05 03:12:27 +02:00
|
|
|
case '>':
|
2001-04-01 09:22:42 +02:00
|
|
|
case 'L': /* <= */
|
2001-04-05 03:12:27 +02:00
|
|
|
case 'G': /* >= */
|
2002-09-24 06:20:32 +02:00
|
|
|
rv = draw_binary_expr_le(exp, wid, stuff_ok_flag);
|
2002-10-20 04:55:37 +02:00
|
|
|
stuff_ok_used_flag = 1;
|
2001-04-01 09:22:42 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
case '+':
|
2001-05-02 03:57:25 +02:00
|
|
|
case '-':
|
2001-06-17 01:45:05 +02:00
|
|
|
case '*':
|
2001-10-16 03:27:17 +02:00
|
|
|
case '/':
|
2001-05-24 06:20:10 +02:00
|
|
|
case '%':
|
2008-02-04 22:04:20 +01:00
|
|
|
case 'p':
|
2001-05-24 06:20:10 +02:00
|
|
|
rv = draw_binary_expr_arith(exp, wid);
|
2001-03-31 04:00:44 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-04-21 05:26:23 +02:00
|
|
|
case 'l': /* << */
|
2001-06-30 23:07:26 +02:00
|
|
|
case 'r': /* >> */
|
2003-06-18 05:55:18 +02:00
|
|
|
case 'R': /* >>> */
|
2001-06-30 23:07:26 +02:00
|
|
|
rv = draw_binary_expr_lrs(exp, wid);
|
2001-04-21 03:49:17 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-04-29 22:47:39 +02:00
|
|
|
case 'o': /* || (logical or) */
|
|
|
|
|
rv = draw_binary_expr_lor(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-02 05:47:49 +02:00
|
|
|
case '&':
|
|
|
|
|
case '|':
|
2001-04-15 18:37:48 +02:00
|
|
|
case '^':
|
2002-09-12 17:49:43 +02:00
|
|
|
case 'A': /* NAND (~&) */
|
2002-09-18 06:29:55 +02:00
|
|
|
case 'O': /* NOR (~|) */
|
2002-09-12 17:49:43 +02:00
|
|
|
case 'X': /* XNOR (~^) */
|
2001-04-02 05:47:49 +02:00
|
|
|
rv = draw_binary_expr_logic(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
default:
|
2001-03-31 04:00:44 +02:00
|
|
|
fprintf(stderr, "vvp.tgt error: unsupported binary (%c)\n",
|
|
|
|
|
ivl_expr_opcode(exp));
|
2001-03-23 02:10:24 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-20 04:55:37 +02:00
|
|
|
/* Mark in the lookaside that this value is done. If any OK
|
|
|
|
|
flags besides the STUFF_OK_47 flag are set, then the result
|
|
|
|
|
may not be a pure one, so clear the lookaside for the range
|
|
|
|
|
instead of setting in to the new expression result.
|
|
|
|
|
|
|
|
|
|
The stuff_ok_used_flag tells me if the stuff_ok_flag was
|
|
|
|
|
even used by anything. If not, then I can ignore it in the
|
|
|
|
|
following logic. */
|
|
|
|
|
if (rv.base >= 8) {
|
|
|
|
|
if (stuff_ok_used_flag && (stuff_ok_flag & ~STUFF_OK_47))
|
|
|
|
|
save_expression_lookaside(rv.base, 0, wid);
|
|
|
|
|
else
|
|
|
|
|
save_expression_lookaside(rv.base, exp, wid);
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-09-20 05:46:38 +02:00
|
|
|
/*
|
|
|
|
|
* The concatenation operator is evaluated by evaluating each sub-
|
2007-02-26 20:49:48 +01:00
|
|
|
* expression, then copying it into the contiguous vector of the
|
2001-09-20 05:46:38 +02:00
|
|
|
* result. Do this until the result vector is filled.
|
|
|
|
|
*/
|
2005-09-17 03:01:00 +02:00
|
|
|
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid,
|
|
|
|
|
int stuff_ok_flag)
|
2001-03-31 04:00:44 +02:00
|
|
|
{
|
2001-07-22 21:33:51 +02:00
|
|
|
unsigned off, rep;
|
2001-03-31 04:00:44 +02:00
|
|
|
struct vector_info res;
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
|
|
|
|
|
|
2001-09-20 05:46:38 +02:00
|
|
|
/* Allocate a vector to hold the result. */
|
2001-03-31 04:00:44 +02:00
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for result of concatenation.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
|
2001-09-20 05:46:38 +02:00
|
|
|
/* Get the repeat count. This must be a constant that has been
|
|
|
|
|
evaluated at compile time. The operands will be repeated to
|
|
|
|
|
form the result. */
|
2001-07-22 21:33:51 +02:00
|
|
|
rep = ivl_expr_repeat(exp);
|
2001-03-31 04:00:44 +02:00
|
|
|
off = 0;
|
|
|
|
|
|
2001-07-22 21:33:51 +02:00
|
|
|
while (rep > 0) {
|
2001-09-20 05:46:38 +02:00
|
|
|
|
|
|
|
|
/* Each repeat, evaluate the sub-expressions, from lsb
|
|
|
|
|
to msb, and copy each into the result vector. The
|
|
|
|
|
expressions are arranged in the concatenation from
|
|
|
|
|
MSB to LSB, to go through them backwards.
|
|
|
|
|
|
|
|
|
|
Abort the loop if the result vector gets filled up. */
|
|
|
|
|
|
2001-07-22 21:33:51 +02:00
|
|
|
unsigned idx = ivl_expr_parms(exp);
|
2001-09-20 05:46:38 +02:00
|
|
|
while ((idx > 0) && (off < wid)) {
|
2001-07-22 21:33:51 +02:00
|
|
|
ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
|
|
|
|
|
unsigned awid = ivl_expr_width(arg);
|
2001-03-31 04:00:44 +02:00
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
unsigned trans;
|
|
|
|
|
struct vector_info avec;
|
|
|
|
|
|
|
|
|
|
/* Try to locate the subexpression in the
|
|
|
|
|
lookaside map. */
|
2005-09-17 03:01:00 +02:00
|
|
|
avec.base = allocate_vector_exp(arg, awid, alloc_exclusive);
|
2002-09-27 18:33:34 +02:00
|
|
|
avec.wid = awid;
|
|
|
|
|
|
|
|
|
|
trans = awid;
|
2001-09-20 05:46:38 +02:00
|
|
|
if ((off + awid) > wid)
|
|
|
|
|
trans = wid - off;
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
if (avec.base != 0) {
|
|
|
|
|
assert(awid == avec.wid);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
res.base+off,
|
|
|
|
|
avec.base, trans);
|
|
|
|
|
clr_vector(avec);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
struct vector_info dest;
|
|
|
|
|
|
|
|
|
|
dest.base = res.base+off;
|
|
|
|
|
dest.wid = trans;
|
|
|
|
|
draw_eval_expr_dest(arg, dest, 0);
|
|
|
|
|
}
|
2001-09-20 05:46:38 +02:00
|
|
|
|
2001-07-22 21:33:51 +02:00
|
|
|
|
|
|
|
|
idx -= 1;
|
2001-09-20 05:46:38 +02:00
|
|
|
off += trans;
|
2001-07-22 21:33:51 +02:00
|
|
|
assert(off <= wid);
|
|
|
|
|
}
|
|
|
|
|
rep -= 1;
|
2001-03-31 04:00:44 +02:00
|
|
|
}
|
|
|
|
|
|
2001-09-20 05:46:38 +02:00
|
|
|
/* Pad the result with 0, if necessary. */
|
2001-03-31 04:00:44 +02:00
|
|
|
if (off < wid) {
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+off, wid-off);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
/* Save the accumulated result in the lookaside map. */
|
|
|
|
|
if (res.base >= 8)
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
/*
|
|
|
|
|
* A number in an expression is made up by copying constant bits into
|
|
|
|
|
* the allocated vector.
|
|
|
|
|
*/
|
|
|
|
|
static struct vector_info draw_number_expr(ivl_expr_t exp, unsigned wid)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
2001-03-29 07:16:25 +02:00
|
|
|
unsigned nwid;
|
2001-03-23 02:10:24 +01:00
|
|
|
struct vector_info res;
|
2001-03-22 06:06:21 +01:00
|
|
|
const char*bits = ivl_expr_bits(exp);
|
|
|
|
|
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
2001-03-29 07:16:25 +02:00
|
|
|
nwid = wid;
|
|
|
|
|
if (ivl_expr_width(exp) < nwid)
|
|
|
|
|
nwid = ivl_expr_width(exp);
|
2001-03-23 02:10:24 +01:00
|
|
|
|
|
|
|
|
/* If all the bits of the number have the same value, then we
|
|
|
|
|
can use a constant bit. There is no need to allocate wr
|
|
|
|
|
bits, and there is no need to generate any code. */
|
|
|
|
|
|
2001-03-29 07:16:25 +02:00
|
|
|
for (idx = 1 ; idx < nwid ; idx += 1) {
|
2001-03-23 02:10:24 +01:00
|
|
|
if (bits[idx] != bits[0])
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-29 07:16:25 +02:00
|
|
|
if (idx >= res.wid) {
|
2001-03-23 02:10:24 +01:00
|
|
|
switch (bits[0]) {
|
|
|
|
|
case '0':
|
|
|
|
|
res.base = 0;
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
res.base = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
res.base = 2;
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
res.base = 3;
|
|
|
|
|
break;
|
2005-09-19 22:18:20 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
res.base = 0;
|
2001-03-23 02:10:24 +01:00
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The number value needs to be represented as an allocated
|
|
|
|
|
vector. Allocate the vector and use %mov instructions to
|
|
|
|
|
load the constant bit values. */
|
|
|
|
|
res.base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for number value.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
2001-03-23 02:10:24 +01:00
|
|
|
|
2008-08-28 03:22:23 +02:00
|
|
|
/* Detect the special case that the entire number fits in an
|
|
|
|
|
immediate. In this case we generate a single %movi
|
|
|
|
|
instruction. */
|
2008-06-13 22:32:06 +02:00
|
|
|
if ((!number_is_unknown(exp)) && number_is_immediate(exp, IMM_WID,0)) {
|
2008-05-28 02:51:28 +02:00
|
|
|
unsigned long val = get_number_immediate(exp);
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, %lu, %u;\n", res.base, val, wid);
|
2007-10-04 05:58:40 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-28 03:22:23 +02:00
|
|
|
/* Use %movi as much as possible to build the value into the
|
|
|
|
|
destination. Use the %mov to handle the remaining general
|
|
|
|
|
bits. */
|
2001-03-23 02:10:24 +01:00
|
|
|
idx = 0;
|
2008-08-28 03:22:23 +02:00
|
|
|
unsigned long val = 0;
|
|
|
|
|
unsigned val_bits = 0;
|
|
|
|
|
unsigned val_addr = res.base;
|
2001-03-29 07:16:25 +02:00
|
|
|
while (idx < nwid) {
|
2008-08-28 03:22:23 +02:00
|
|
|
char src = 0;
|
2001-03-22 06:06:21 +01:00
|
|
|
switch (bits[idx]) {
|
|
|
|
|
case '0':
|
2008-08-28 03:22:23 +02:00
|
|
|
val_bits += 1;
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
case '1':
|
2008-08-28 03:22:23 +02:00
|
|
|
val |= 1UL << val_bits;
|
|
|
|
|
val_bits += 1;
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
src = '2';
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
src = '3';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-28 03:22:23 +02:00
|
|
|
if (val_bits >= IMM_WID
|
|
|
|
|
|| (val_bits>0 && src != 0)
|
|
|
|
|
|| (val_bits>0 && idx+1==nwid)) {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, %lu, %u;\n",
|
2008-08-28 03:22:23 +02:00
|
|
|
val_addr, val, val_bits);
|
|
|
|
|
val_addr += val_bits;
|
|
|
|
|
val_bits = 0;
|
|
|
|
|
val = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (src != 0) {
|
|
|
|
|
assert(val_bits == 0);
|
|
|
|
|
unsigned cnt;
|
|
|
|
|
for (cnt = 1 ; idx+cnt < nwid ; cnt += 1)
|
|
|
|
|
if (bits[idx+cnt] != bits[idx])
|
|
|
|
|
break;
|
2001-03-23 02:10:24 +01:00
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %c, %u;\n", val_addr, src, cnt);
|
2008-08-28 03:22:23 +02:00
|
|
|
val_addr += cnt;
|
|
|
|
|
idx += cnt-1;
|
|
|
|
|
}
|
2001-03-23 02:10:24 +01:00
|
|
|
|
2008-08-28 03:22:23 +02:00
|
|
|
idx += 1;
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-29 07:16:25 +02:00
|
|
|
/* Pad the number up to the expression width. */
|
2003-06-11 04:23:45 +02:00
|
|
|
if (idx < wid) {
|
|
|
|
|
if (ivl_expr_signed(exp) && bits[nwid-1] == '1')
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 1, %u;\n",
|
|
|
|
|
res.base+idx, wid-idx);
|
|
|
|
|
|
|
|
|
|
else if (bits[nwid-1] == 'x')
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 2, %u;\n",
|
|
|
|
|
res.base+idx, wid-idx);
|
|
|
|
|
|
|
|
|
|
else if (bits[nwid-1] == 'z')
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 3, %u;\n",
|
|
|
|
|
res.base+idx, wid-idx);
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+idx, wid-idx);
|
|
|
|
|
}
|
2001-03-29 07:16:25 +02:00
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
if (res.base >= 8)
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2003-07-26 05:34:42 +02:00
|
|
|
/*
|
|
|
|
|
* The PAD expression takes a smaller node and pads it out to a larger
|
|
|
|
|
* value. It will zero extend or sign extend depending on the
|
|
|
|
|
* signedness of the expression.
|
|
|
|
|
*/
|
|
|
|
|
static struct vector_info draw_pad_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info subv;
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
subv = draw_eval_expr(ivl_expr_oper1(exp), 0);
|
2004-09-10 02:14:31 +02:00
|
|
|
if (wid <= subv.wid) {
|
2003-07-26 05:34:42 +02:00
|
|
|
if (subv.base >= 8)
|
2004-09-10 02:14:31 +02:00
|
|
|
save_expression_lookaside(subv.base, exp, subv.wid);
|
|
|
|
|
res.base = subv.base;
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
return res;
|
2003-07-26 05:34:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"to pad expression.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
2003-07-26 05:34:42 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
res.base, subv.base, subv.wid);
|
|
|
|
|
|
|
|
|
|
assert(wid > subv.wid);
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_signed(exp)) {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = subv.wid ; idx < res.wid ; idx += 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
|
|
|
|
|
res.base+idx, subv.base+subv.wid-1);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+subv.wid, res.wid - subv.wid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
static struct vector_info draw_realnum_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
double val = ivl_expr_dvalue(exp);
|
2007-01-19 06:24:53 +01:00
|
|
|
long ival = val;
|
|
|
|
|
|
|
|
|
|
unsigned addr, run, idx;
|
|
|
|
|
int bit;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "; draw_realnum_expr(%f, %u) as %ld\n",
|
|
|
|
|
val, wid, ival);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2003-01-26 22:15:58 +01:00
|
|
|
|
2007-01-19 06:24:53 +01:00
|
|
|
addr = res.base;
|
|
|
|
|
run = 1;
|
|
|
|
|
bit = ival & 1;
|
|
|
|
|
ival >>= 1LL;
|
|
|
|
|
|
|
|
|
|
for (idx = 1 ; idx < wid ; idx += 1) {
|
|
|
|
|
int next_bit = ival & 1;
|
|
|
|
|
ival >>= 1LL;
|
|
|
|
|
|
|
|
|
|
if (next_bit == bit) {
|
|
|
|
|
run += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run);
|
2007-01-19 06:24:53 +01:00
|
|
|
addr += run;
|
|
|
|
|
run = 1;
|
|
|
|
|
bit = next_bit;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %d, %u;\n", addr, bit, run);
|
2007-01-19 06:24:53 +01:00
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-14 04:51:20 +01:00
|
|
|
static char *process_octal_codes(const char *in, unsigned width)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx = 0;
|
|
|
|
|
unsigned ridx = 0;
|
|
|
|
|
unsigned str_len = strlen(in);
|
|
|
|
|
char *out = (char *)malloc(str_len+1);
|
|
|
|
|
|
|
|
|
|
/* If we do not have any octal codes just return the input. */
|
|
|
|
|
if (width/8 == str_len) {
|
|
|
|
|
strcpy(out, in);
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-02 05:23:08 +02:00
|
|
|
while (ridx < str_len) {
|
2007-11-14 04:51:20 +01:00
|
|
|
/* An octal constant always has three digits. */
|
|
|
|
|
if (in[ridx] == '\\') {
|
|
|
|
|
out[idx] = (in[ridx+1]-'0')*64 + (in[ridx+2]-'0')*8 +
|
|
|
|
|
(in[ridx+3]-'0');
|
|
|
|
|
idx += 1;
|
|
|
|
|
ridx += 4;
|
|
|
|
|
} else {
|
|
|
|
|
out[idx] = in[ridx];
|
|
|
|
|
idx += 1;
|
|
|
|
|
ridx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
out[idx] = '\0';
|
|
|
|
|
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-18 18:41:49 +02:00
|
|
|
/*
|
|
|
|
|
* A string in an expression is made up by copying constant bits into
|
|
|
|
|
* the allocated vector.
|
|
|
|
|
*/
|
|
|
|
|
static struct vector_info draw_string_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
2007-11-14 04:51:20 +01:00
|
|
|
char *p, *fp;
|
2001-10-18 18:41:49 +02:00
|
|
|
unsigned ewid, nwid;
|
2007-11-14 06:14:07 +01:00
|
|
|
unsigned idx;
|
2001-10-18 18:41:49 +02:00
|
|
|
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
nwid = wid;
|
|
|
|
|
ewid = ivl_expr_width(exp);
|
|
|
|
|
if (ewid < nwid)
|
|
|
|
|
nwid = ewid;
|
|
|
|
|
|
2007-11-14 04:51:20 +01:00
|
|
|
/* Our string may have embedded \xxx sequences so they need
|
|
|
|
|
to be removed before we proceed. Returns a new string. */
|
|
|
|
|
fp = process_octal_codes(ivl_expr_string(exp), ewid);
|
|
|
|
|
p = fp;
|
|
|
|
|
|
2001-10-18 18:41:49 +02:00
|
|
|
p += (ewid / 8) - 1;
|
|
|
|
|
|
|
|
|
|
/* The string needs to be represented as an allocated
|
|
|
|
|
vector. Allocate the vector and use %mov instructions to
|
|
|
|
|
load the constant bit values. */
|
|
|
|
|
res.base = allocate_vector(wid);
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"for string value.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
2001-10-18 18:41:49 +02:00
|
|
|
|
2007-11-14 06:14:07 +01:00
|
|
|
/* Since this is a string, we know that all the bits are
|
|
|
|
|
defined and each character represents exactly 8 bits. Use
|
|
|
|
|
the %movi instruction to more efficiently move the string
|
|
|
|
|
around. */
|
2001-10-18 18:41:49 +02:00
|
|
|
idx = 0;
|
|
|
|
|
while (idx < nwid) {
|
2007-11-14 06:14:07 +01:00
|
|
|
unsigned bits;
|
2008-05-28 02:51:28 +02:00
|
|
|
unsigned trans = IMM_WID;
|
|
|
|
|
if (nwid-idx < trans)
|
2007-11-14 06:14:07 +01:00
|
|
|
trans = nwid-idx;
|
|
|
|
|
|
|
|
|
|
bits = *p;
|
|
|
|
|
p -= 1;
|
|
|
|
|
if (trans > 8) {
|
|
|
|
|
bits |= *p << 8;
|
|
|
|
|
p -= 1;
|
2008-05-28 02:51:28 +02:00
|
|
|
if (trans > 16) {
|
|
|
|
|
bits |= *p << 16;
|
|
|
|
|
p -= 1;
|
|
|
|
|
if (trans > 24) {
|
|
|
|
|
bits |= *p << 24;
|
|
|
|
|
p -= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-10-18 18:41:49 +02:00
|
|
|
}
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, %u, %u;\n", res.base+idx,bits,trans);
|
2001-10-18 18:41:49 +02:00
|
|
|
|
2007-11-14 06:14:07 +01:00
|
|
|
idx += trans;
|
2001-10-18 18:41:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pad the number up to the expression width. */
|
|
|
|
|
if (idx < wid)
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", res.base+idx, wid-idx);
|
2001-10-18 18:41:49 +02:00
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
if (res.base >= 8)
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2007-11-14 04:51:20 +01:00
|
|
|
free(fp);
|
2001-10-18 18:41:49 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2007-02-12 05:37:58 +01:00
|
|
|
/*
|
|
|
|
|
* This function is given an expression, the preallocated vector
|
|
|
|
|
* result, and the swid that is filled in so far. The caller has
|
|
|
|
|
* already calculated the load swid bits of exp into the beginning of
|
|
|
|
|
* the res vector. This function just calculates the pad to fill out
|
|
|
|
|
* the res area.
|
|
|
|
|
*/
|
2007-12-16 07:05:56 +01:00
|
|
|
void pad_expr_in_place(ivl_expr_t exp, struct vector_info res, unsigned swid)
|
2007-02-12 05:37:58 +01:00
|
|
|
{
|
|
|
|
|
if (res.wid <= swid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_signed(exp)) {
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = swid ; idx < res.wid ; idx += 1)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n",
|
|
|
|
|
res.base+idx, res.base+swid-1);
|
|
|
|
|
|
|
|
|
|
} else {
|
2008-05-28 02:51:28 +02:00
|
|
|
unsigned base = res.base+swid;
|
|
|
|
|
unsigned count = res.wid-swid;
|
|
|
|
|
/* The %movi is faster for larger widths, but for very
|
|
|
|
|
small counts, the %mov is faster. */
|
|
|
|
|
if (count > 4)
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, 0, %u;\n", base, count);
|
2008-05-28 02:51:28 +02:00
|
|
|
else
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", base, count);
|
2007-02-12 05:37:58 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-27 06:51:44 +02:00
|
|
|
/*
|
|
|
|
|
* Evaluating a signal expression means loading the bits of the signal
|
|
|
|
|
* into the thread bits. Remember to account for the part select by
|
|
|
|
|
* offsetting the read from the lsi (least significant index) of the
|
|
|
|
|
* signal.
|
2007-12-05 04:15:15 +01:00
|
|
|
*
|
2008-06-14 05:23:40 +02:00
|
|
|
* If the add_index is 0, then generate a %load/vp0 to add the
|
|
|
|
|
* word0 value to the loaded value before storing it into the
|
|
|
|
|
* destination. If the add_index is 1, then generate a %load/vp0/s to
|
|
|
|
|
* do a signed load.
|
2001-07-27 06:51:44 +02:00
|
|
|
*/
|
2007-12-05 04:15:15 +01:00
|
|
|
static void draw_signal_dest(ivl_expr_t exp, struct vector_info res,
|
2008-06-14 05:23:40 +02:00
|
|
|
int add_index, long immediate)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
2001-03-23 02:10:24 +01:00
|
|
|
unsigned swid = ivl_expr_width(exp);
|
2002-08-04 00:30:48 +02:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(exp);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
unsigned word = 0;
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
if (swid > res.wid)
|
|
|
|
|
swid = res.wid;
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
/* If this is an access to an array, handle that by emitting a
|
2007-01-16 06:44:14 +01:00
|
|
|
load/av instruction. */
|
2008-05-19 20:31:40 +02:00
|
|
|
if (ivl_signal_dimensions(sig) > 0) {
|
2007-01-16 06:44:14 +01:00
|
|
|
ivl_expr_t ix = ivl_expr_oper1(exp);
|
2008-01-13 03:22:46 +01:00
|
|
|
|
2008-05-16 19:38:32 +02:00
|
|
|
draw_eval_expr_into_integer(ix, 3);
|
|
|
|
|
if (add_index < 0) {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%load/av %u, v%p, %u;\n",
|
2008-05-16 19:38:32 +02:00
|
|
|
res.base, sig, swid);
|
2008-06-15 04:59:57 +02:00
|
|
|
pad_expr_in_place(exp, res, swid);
|
2008-05-16 19:38:32 +02:00
|
|
|
} else {
|
2008-06-15 04:59:57 +02:00
|
|
|
const char*sign_flag = (add_index>0)? "/s" : "";
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2008-05-16 19:38:32 +02:00
|
|
|
/* Add an immediate value to an array value. */
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
|
|
|
|
fprintf(vvp_out, " %%load/avp0%s %u, v%p, %u;\n",
|
2008-06-15 04:59:57 +02:00
|
|
|
sign_flag, res.base, sig, res.wid);
|
2008-05-16 19:38:32 +02:00
|
|
|
}
|
|
|
|
|
return;
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
|
|
|
|
|
2007-06-30 06:10:37 +02:00
|
|
|
|
|
|
|
|
if (ivl_signal_data_type(sig) == IVL_VT_REAL) {
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
assert(add_index < 0);
|
2007-06-30 06:10:37 +02:00
|
|
|
int tmp = allocate_word();
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%load/wr %d, v%p_%u;\n", tmp, sig, word);
|
|
|
|
|
fprintf(vvp_out, " %%cvt/vr %u, %d, %u;\n", res.base, tmp, res.wid);
|
2007-06-30 06:10:37 +02:00
|
|
|
clr_word(tmp);
|
|
|
|
|
|
2007-12-05 04:15:15 +01:00
|
|
|
} else if (add_index >= 0) {
|
|
|
|
|
|
2008-06-14 05:23:40 +02:00
|
|
|
const char*sign_flag = add_index==1? "/s" : "";
|
2007-12-05 04:15:15 +01:00
|
|
|
|
|
|
|
|
/* If this is a REG (a variable) then I can do a vector read. */
|
2008-06-14 05:23:40 +02:00
|
|
|
if (immediate >= 0) {
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %lu;\n", immediate);
|
|
|
|
|
} else {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load 0, 0; immediate=%ld\n", immediate);
|
|
|
|
|
fprintf(vvp_out, " %%ix/sub 0, %ld;\n", -immediate);
|
2008-06-14 05:23:40 +02:00
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, " %%load/vp0%s %u, v%p_%u, %u;\n", sign_flag,
|
|
|
|
|
res.base, sig,word, res.wid);
|
2008-01-13 03:22:46 +01:00
|
|
|
swid = res.wid;
|
2007-12-05 04:15:15 +01:00
|
|
|
|
2007-06-30 06:10:37 +02:00
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
/* If this is a REG (a variable) then I can do a vector read. */
|
|
|
|
|
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u;\n",
|
|
|
|
|
res.base, sig, word, swid);
|
|
|
|
|
|
|
|
|
|
}
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2007-02-12 05:37:58 +01:00
|
|
|
pad_expr_in_place(exp, res, swid);
|
2002-11-06 06:41:37 +01:00
|
|
|
}
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid,
|
|
|
|
|
int stuff_ok_flag)
|
2002-11-06 06:41:37 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO) ? 0 : 1;
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
/* Already in the vector lookaside? */
|
2005-09-17 03:01:00 +02:00
|
|
|
res.base = allocate_vector_exp(exp, wid, alloc_exclusive);
|
2002-11-06 06:41:37 +01:00
|
|
|
res.wid = wid;
|
2005-09-17 03:01:00 +02:00
|
|
|
if (res.base != 0) {
|
|
|
|
|
fprintf(vvp_out, "; Reuse signal base=%u wid=%u from lookaside.\n",
|
|
|
|
|
res.base, res.wid);
|
2002-11-06 06:41:37 +01:00
|
|
|
return res;
|
2005-09-17 03:01:00 +02:00
|
|
|
}
|
2002-11-06 06:41:37 +01:00
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"to load variable/wire.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2008-01-13 03:22:46 +01:00
|
|
|
draw_signal_dest(exp, res, -1, 0L);
|
2001-03-22 06:06:21 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-14 06:43:01 +02:00
|
|
|
static struct vector_info draw_select_array(ivl_expr_t sube,
|
|
|
|
|
ivl_expr_t bit_idx,
|
|
|
|
|
unsigned bit_width,
|
|
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(sube);
|
2007-12-10 02:00:32 +01:00
|
|
|
/* unsigned sig_wid = ivl_expr_width(sube); */
|
2007-04-14 06:43:01 +02:00
|
|
|
ivl_expr_t ix = ivl_expr_oper1(sube);
|
|
|
|
|
|
|
|
|
|
struct vector_info shiv;
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
shiv = draw_eval_expr(bit_idx, STUFF_OK_XZ|STUFF_OK_RO);
|
|
|
|
|
draw_eval_expr_into_integer(ix, 3);
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
|
2007-04-14 06:43:01 +02:00
|
|
|
if (shiv.base >= 8)
|
|
|
|
|
clr_vector(shiv);
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (res.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"to hold selected value.\n",
|
|
|
|
|
ivl_expr_file(sube), ivl_expr_lineno(sube), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
2007-04-14 06:43:01 +02:00
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < wid ; idx += 1) {
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%load/avx.p %u, v%p, 0;\n", res.base+idx, sig);
|
2007-04-14 06:43:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2005-02-15 08:12:55 +01:00
|
|
|
static struct vector_info draw_select_signal(ivl_expr_t sube,
|
|
|
|
|
ivl_expr_t bit_idx,
|
2005-12-22 16:42:22 +01:00
|
|
|
unsigned bit_wid,
|
2005-02-15 08:12:55 +01:00
|
|
|
unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(sube);
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
/* Use this word of the signal. */
|
|
|
|
|
unsigned use_word = 0;
|
2007-04-14 06:43:01 +02:00
|
|
|
|
|
|
|
|
/* If this is an access to an array, try to get the index as a
|
2008-05-19 20:44:03 +02:00
|
|
|
constant. If it is (and the array is not a reg array then
|
|
|
|
|
this reduces to a signal access and we stay here. If it is
|
|
|
|
|
not constant, then give up and do an array index in front
|
|
|
|
|
of this part select. */
|
2007-04-14 06:43:01 +02:00
|
|
|
|
2008-05-19 20:31:40 +02:00
|
|
|
if (ivl_signal_dimensions(sig) > 0) {
|
2007-01-16 06:44:14 +01:00
|
|
|
ivl_expr_t ix = ivl_expr_oper1(sube);
|
2007-04-14 06:43:01 +02:00
|
|
|
|
2008-05-19 20:44:03 +02:00
|
|
|
if (ivl_signal_type(sig)==IVL_SIT_REG
|
2008-06-13 22:32:06 +02:00
|
|
|
|| !number_is_immediate(ix, 8*sizeof(unsigned long),0))
|
2007-04-14 06:43:01 +02:00
|
|
|
return draw_select_array(sube, bit_idx, bit_wid, wid);
|
2007-01-16 06:44:14 +01:00
|
|
|
|
|
|
|
|
/* The index is constant, so we can return to direct
|
|
|
|
|
readout with the specific word selected. */
|
|
|
|
|
use_word = get_number_immediate(ix);
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-10 02:28:49 +01:00
|
|
|
/* Try the special case that the part is at the beginning of
|
|
|
|
|
the signal (or the entire width). Just load the early bits
|
|
|
|
|
in one go. */
|
2008-06-13 22:32:06 +02:00
|
|
|
if (number_is_immediate(bit_idx, 32, 0)
|
2007-12-10 02:00:32 +01:00
|
|
|
&& get_number_immediate(bit_idx) == 0
|
2007-12-26 17:22:33 +01:00
|
|
|
&& (ivl_expr_width(sube) >= bit_wid)) {
|
2007-12-10 02:28:49 +01:00
|
|
|
|
2005-09-17 06:01:32 +02:00
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%load/v %u, v%p_%u, %u; Only need %u of %u bits\n",
|
2007-12-26 17:22:33 +01:00
|
|
|
res.base, sig, use_word, bit_wid, bit_wid, ivl_expr_width(sube));
|
2008-09-04 18:41:51 +02:00
|
|
|
|
2007-12-26 17:22:33 +01:00
|
|
|
save_signal_lookaside(res.base, sig, use_word, bit_wid);
|
|
|
|
|
/* Pad the part select to the desired width. Note that
|
|
|
|
|
this *should* always turn into an unsigned pad
|
|
|
|
|
because part selects are always unsigned. */
|
|
|
|
|
pad_expr_in_place(sube, res, bit_wid);
|
2005-09-17 06:01:32 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Alas, do it the hard way. */
|
2008-06-11 02:29:47 +02:00
|
|
|
|
|
|
|
|
draw_eval_expr_into_integer(bit_idx, 1);
|
|
|
|
|
|
2005-02-15 08:12:55 +01:00
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2005-02-15 08:12:55 +01:00
|
|
|
|
2008-06-11 02:29:47 +02:00
|
|
|
unsigned use_wid = res.wid;
|
|
|
|
|
if (use_wid > bit_wid)
|
|
|
|
|
use_wid = bit_wid;
|
|
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%load/x1p %u, v%p_%u, %u;\n",
|
2008-06-11 02:29:47 +02:00
|
|
|
res.base, sig, use_word, use_wid);
|
|
|
|
|
if (use_wid < res.wid)
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
2008-06-11 02:29:47 +02:00
|
|
|
res.base + use_wid, res.wid - use_wid);
|
2005-02-15 08:12:55 +01:00
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
static struct vector_info draw_select_expr(ivl_expr_t exp, unsigned wid,
|
|
|
|
|
int stuff_ok_flag)
|
2002-01-28 01:52:41 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info subv, shiv, res;
|
|
|
|
|
ivl_expr_t sube = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t shift = ivl_expr_oper2(exp);
|
|
|
|
|
|
2005-09-17 03:01:00 +02:00
|
|
|
int alloc_exclusive = (stuff_ok_flag&STUFF_OK_RO)? 0 : 1;
|
|
|
|
|
|
2005-09-19 22:18:20 +02:00
|
|
|
res.wid = wid;
|
|
|
|
|
|
2005-09-15 04:49:47 +02:00
|
|
|
/* First look for the self expression in the lookaside, and
|
2008-01-01 18:45:02 +01:00
|
|
|
allocate that if possible. If I find it, then immediately
|
2005-09-15 04:49:47 +02:00
|
|
|
return that. */
|
2005-09-17 03:01:00 +02:00
|
|
|
if ( (res.base = allocate_vector_exp(exp, wid, alloc_exclusive)) != 0) {
|
2005-09-15 04:49:47 +02:00
|
|
|
fprintf(vvp_out, "; Reuse base=%u wid=%u from lookaside.\n",
|
|
|
|
|
res.base, wid);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_type(sube) == IVL_EX_SIGNAL) {
|
2005-12-22 16:42:22 +01:00
|
|
|
res = draw_select_signal(sube, shift, ivl_expr_width(exp), wid);
|
2005-09-15 04:49:47 +02:00
|
|
|
fprintf(vvp_out, "; Save base=%u wid=%u in lookaside.\n",
|
|
|
|
|
res.base, wid);
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2005-02-15 08:12:55 +01:00
|
|
|
|
2002-01-28 01:52:41 +01:00
|
|
|
/* Evaluate the sub-expression. */
|
2002-09-13 05:12:50 +02:00
|
|
|
subv = draw_eval_expr(sube, 0);
|
2002-01-28 01:52:41 +01:00
|
|
|
|
|
|
|
|
/* Any bit select of a constant zero is another constant zero,
|
|
|
|
|
so short circuit and return the value we know. */
|
|
|
|
|
if (subv.base == 0) {
|
|
|
|
|
subv.wid = wid;
|
|
|
|
|
return subv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Evaluate the bit select base expression and store the
|
|
|
|
|
result into index register 0. */
|
2002-09-24 06:20:32 +02:00
|
|
|
shiv = draw_eval_expr(shift, STUFF_OK_XZ);
|
2005-01-28 06:37:48 +01:00
|
|
|
|
|
|
|
|
/* Detect and handle the special case that the shift is a
|
|
|
|
|
constant 0. Skip the shift, and return the subexpression
|
|
|
|
|
with the width trimmed down to the desired width. */
|
|
|
|
|
if (shiv.base == 0) {
|
|
|
|
|
assert(subv.wid >= wid);
|
|
|
|
|
res.base = subv.base;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-28 01:52:41 +01:00
|
|
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n", shiv.base, shiv.wid);
|
|
|
|
|
clr_vector(shiv);
|
|
|
|
|
|
|
|
|
|
/* If the subv result is a magic constant, then make a copy in
|
2007-02-26 20:49:48 +01:00
|
|
|
writable vector space and work from there instead. */
|
2002-02-03 06:53:00 +01:00
|
|
|
if (subv.base < 4) {
|
2002-01-28 01:52:41 +01:00
|
|
|
res.base = allocate_vector(subv.wid);
|
2002-12-20 00:11:29 +01:00
|
|
|
res.wid = subv.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2002-01-28 01:52:41 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base,
|
|
|
|
|
subv.base, res.wid);
|
|
|
|
|
subv = res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", subv.base, subv.wid);
|
|
|
|
|
|
|
|
|
|
if (subv.wid > wid) {
|
|
|
|
|
res.base = subv.base;
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
|
|
|
|
subv.base += wid;
|
2005-09-17 03:01:00 +02:00
|
|
|
subv.wid -= wid;
|
2002-01-28 01:52:41 +01:00
|
|
|
clr_vector(subv);
|
|
|
|
|
|
2005-09-19 22:18:20 +02:00
|
|
|
} else {
|
|
|
|
|
assert(subv.wid == wid);
|
2002-01-28 01:52:41 +01:00
|
|
|
res = subv;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-15 04:49:47 +02:00
|
|
|
if (res.base >= 8) {
|
|
|
|
|
fprintf(vvp_out, "; Save expression base=%u wid=%u in lookaside\n",
|
|
|
|
|
res.base, wid);
|
2002-09-27 18:33:34 +02:00
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
2005-09-15 04:49:47 +02:00
|
|
|
}
|
2002-09-27 18:33:34 +02:00
|
|
|
|
2002-01-28 01:52:41 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
static struct vector_info draw_ternary_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
2003-06-16 00:49:32 +02:00
|
|
|
struct vector_info res, tru, fal, tst;
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2002-08-22 05:38:40 +02:00
|
|
|
unsigned lab_true, lab_false, lab_out;
|
2001-05-17 06:37:02 +02:00
|
|
|
ivl_expr_t cond = ivl_expr_oper1(exp);
|
|
|
|
|
ivl_expr_t true_ex = ivl_expr_oper2(exp);
|
|
|
|
|
ivl_expr_t false_ex = ivl_expr_oper3(exp);
|
|
|
|
|
|
2002-08-22 05:38:40 +02:00
|
|
|
lab_true = local_count++;
|
2001-05-17 06:37:02 +02:00
|
|
|
lab_false = local_count++;
|
|
|
|
|
lab_out = local_count++;
|
|
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
/* Evaluate the condition expression, and if necessary reduce
|
|
|
|
|
it to a single bit. */
|
2005-09-17 03:01:00 +02:00
|
|
|
tst = draw_eval_expr(cond, STUFF_OK_XZ|STUFF_OK_RO);
|
2003-06-16 00:49:32 +02:00
|
|
|
if ((tst.base >= 4) && (tst.wid > 1)) {
|
|
|
|
|
struct vector_info tmp;
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2002-07-12 20:10:45 +02:00
|
|
|
fprintf(vvp_out, " %%or/r %u, %u, %u;\n",
|
2003-06-16 00:49:32 +02:00
|
|
|
tst.base, tst.base, tst.wid);
|
|
|
|
|
|
|
|
|
|
tmp = tst;
|
|
|
|
|
tmp.base += 1;
|
|
|
|
|
tmp.wid -= 1;
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
|
|
|
|
|
tst.wid = 1;
|
2002-07-12 20:10:45 +02:00
|
|
|
}
|
|
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
|
|
|
|
|
thread_count, lab_true, tst.base);
|
|
|
|
|
|
|
|
|
|
tru = draw_eval_expr_wid(true_ex, wid, 0);
|
|
|
|
|
|
|
|
|
|
/* The true result must be in a writable register, because the
|
|
|
|
|
blend might want to manipulate it. */
|
|
|
|
|
if (tru.base < 4) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(wid);
|
|
|
|
|
tmp.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(tmp.base);
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, tru.base, wid);
|
|
|
|
|
tru = tmp;
|
|
|
|
|
}
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2002-08-22 05:38:40 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/1 T_%d.%d, %u;\n",
|
2003-06-16 00:49:32 +02:00
|
|
|
thread_count, lab_out, tst.base);
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2003-09-24 22:46:20 +02:00
|
|
|
clear_expression_lookaside();
|
|
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ; End of true expr.\n",
|
|
|
|
|
thread_count, lab_true);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fal = draw_eval_expr_wid(false_ex, wid, 0);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " %%jmp/0 T_%d.%d, %u;\n",
|
|
|
|
|
thread_count, lab_false, tst.base);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " ; End of false expr.\n");
|
2002-08-22 05:38:40 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
clr_vector(tst);
|
|
|
|
|
clr_vector(fal);
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " %%blend %u, %u, %u; Condition unknown.\n",
|
|
|
|
|
tru.base, fal.base, wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n",
|
2003-06-17 00:14:15 +02:00
|
|
|
thread_count, lab_out);
|
2002-08-22 05:38:40 +02:00
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_false);
|
2003-06-16 00:49:32 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u; Return false value\n",
|
|
|
|
|
tru.base, fal.base, wid);
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2002-08-22 05:38:40 +02:00
|
|
|
/* This is the out label. */
|
2001-05-17 06:37:02 +02:00
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
2002-09-27 22:24:42 +02:00
|
|
|
clear_expression_lookaside();
|
2001-05-17 06:37:02 +02:00
|
|
|
|
2003-06-16 00:49:32 +02:00
|
|
|
res = tru;
|
|
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
if (res.base >= 8)
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-20 03:02:55 +02:00
|
|
|
static struct vector_info draw_sfunc_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
2001-07-07 22:20:10 +02:00
|
|
|
unsigned parm_count = ivl_expr_parms(exp);
|
2001-05-20 03:02:55 +02:00
|
|
|
struct vector_info res;
|
|
|
|
|
|
2001-07-07 22:20:10 +02:00
|
|
|
|
|
|
|
|
/* If the function has no parameters, then use this short-form
|
|
|
|
|
to draw the statement. */
|
|
|
|
|
if (parm_count == 0) {
|
2005-09-14 04:53:13 +02:00
|
|
|
assert(ivl_expr_value(exp) == IVL_VT_LOGIC
|
|
|
|
|
|| ivl_expr_value(exp) == IVL_VT_BOOL);
|
2001-07-07 22:20:10 +02:00
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2008-01-01 18:45:02 +01:00
|
|
|
fprintf(vvp_out, " %%vpi_func %u %u \"%s\", %u, %u;\n",
|
2008-01-02 19:42:23 +01:00
|
|
|
ivl_file_table_index(ivl_expr_file(exp)),
|
2008-01-01 18:45:02 +01:00
|
|
|
ivl_expr_lineno(exp), ivl_expr_name(exp),
|
|
|
|
|
res.base, res.wid);
|
2001-07-07 22:20:10 +02:00
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 05:45:18 +01:00
|
|
|
res = draw_vpi_func_call(exp, wid);
|
2001-07-07 22:20:10 +02:00
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
/* New basic block starts after VPI calls. */
|
|
|
|
|
clear_expression_lookaside();
|
|
|
|
|
|
2001-05-20 03:02:55 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-29 04:52:39 +02:00
|
|
|
static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
ivl_expr_t sub = ivl_expr_oper1(exp);
|
2001-10-10 06:47:43 +02:00
|
|
|
const char *rop = 0;
|
2001-06-18 03:09:32 +02:00
|
|
|
int inv = 0;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case '&': rop = "and"; break;
|
|
|
|
|
case '|': rop = "or"; break;
|
|
|
|
|
case '^': rop = "xor"; break;
|
|
|
|
|
case 'A': rop = "nand"; break;
|
|
|
|
|
case 'N': rop = "nor"; break;
|
|
|
|
|
case 'X': rop = "xnor"; break;
|
|
|
|
|
}
|
2001-03-29 04:52:39 +02:00
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case '~':
|
2002-09-24 06:20:32 +02:00
|
|
|
res = draw_eval_expr_wid(sub, wid, STUFF_OK_XZ);
|
2001-08-31 03:37:56 +02:00
|
|
|
switch (res.base) {
|
|
|
|
|
case 0:
|
|
|
|
|
res.base = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
res.base = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
res.base = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(vvp_out, " %%inv %u, %u;\n", res.base, res.wid);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-03-29 04:52:39 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-09-29 06:37:44 +02:00
|
|
|
case '-':
|
|
|
|
|
/* Unary minus is implemented by generating the 2's
|
|
|
|
|
complement of the number. That is the 1's complement
|
|
|
|
|
(bitwise invert) with a 1 added in. Note that the
|
|
|
|
|
%sub subtracts -1 (1111...) to get %add of +1. */
|
2002-09-24 06:20:32 +02:00
|
|
|
res = draw_eval_expr_wid(sub, wid, STUFF_OK_XZ);
|
2001-09-29 06:37:44 +02:00
|
|
|
switch (res.base) {
|
|
|
|
|
case 0:
|
|
|
|
|
res.base = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
res.base = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
res.base = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(vvp_out, " %%inv %u, %u;\n", res.base, res.wid);
|
2003-10-01 19:44:20 +02:00
|
|
|
fprintf(vvp_out, " %%addi %u, 1, %u;\n",res.base,res.wid);
|
2001-09-29 06:37:44 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-01 23:47:29 +02:00
|
|
|
case '!':
|
2002-09-24 06:20:32 +02:00
|
|
|
res = draw_eval_expr(sub, STUFF_OK_XZ);
|
2001-10-24 07:06:54 +02:00
|
|
|
if (res.wid > 1) {
|
|
|
|
|
/* a ! on a vector is implemented with a reduction
|
|
|
|
|
nor. Generate the result into the first bit of
|
|
|
|
|
the input vector and free the rest of the
|
|
|
|
|
vector. */
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
assert(res.base >= 4);
|
|
|
|
|
tmp.base = res.base+1;
|
|
|
|
|
tmp.wid = res.wid - 1;
|
|
|
|
|
fprintf(vvp_out, " %%nor/r %u, %u, %u;\n",
|
|
|
|
|
res.base, res.base, res.wid);
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
res.wid = 1;
|
2002-05-07 05:49:58 +02:00
|
|
|
} else switch (res.base) {
|
|
|
|
|
case 0:
|
|
|
|
|
res.base = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
res.base = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
case 3:
|
|
|
|
|
res.base = 2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
|
|
|
|
break;
|
2001-10-24 07:06:54 +02:00
|
|
|
}
|
2001-11-19 05:25:46 +01:00
|
|
|
|
|
|
|
|
/* If the result needs to be bigger then the calculated
|
|
|
|
|
value, then write it into a padded vector. */
|
|
|
|
|
if (res.wid < wid) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(wid);
|
|
|
|
|
tmp.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
if (tmp.base == 0) {
|
|
|
|
|
fprintf(stderr, "%s:%u: vvp.tgt error: "
|
|
|
|
|
"Unable to allocate %u thread bits "
|
|
|
|
|
"to pad unary expression result.\n",
|
|
|
|
|
ivl_expr_file(exp), ivl_expr_lineno(exp), wid);
|
|
|
|
|
vvp_errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, res.base, res.wid);
|
2008-05-28 02:51:28 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
2001-11-19 05:25:46 +01:00
|
|
|
tmp.base+res.wid, tmp.wid-res.wid);
|
|
|
|
|
clr_vector(res);
|
|
|
|
|
res = tmp;
|
|
|
|
|
}
|
2001-10-24 07:06:54 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-06-18 03:09:32 +02:00
|
|
|
case 'N':
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'X':
|
|
|
|
|
inv = 1;
|
|
|
|
|
case '&':
|
|
|
|
|
case '|':
|
|
|
|
|
case '^':
|
2002-09-13 05:12:50 +02:00
|
|
|
res = draw_eval_expr(sub, 0);
|
2001-04-01 23:47:29 +02:00
|
|
|
if (res.wid > 1) {
|
|
|
|
|
struct vector_info tmp;
|
2001-11-19 05:25:46 +01:00
|
|
|
/* If the previous result is in the constant area
|
|
|
|
|
(and is a vector) then copy it out into some
|
|
|
|
|
temporary space. */
|
|
|
|
|
if (res.base < 4) {
|
|
|
|
|
tmp.base = allocate_vector(res.wid);
|
|
|
|
|
tmp.wid = res.wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, res.base, res.wid);
|
|
|
|
|
res = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 23:47:29 +02:00
|
|
|
tmp.base = res.base+1;
|
|
|
|
|
tmp.wid = res.wid - 1;
|
2001-06-18 03:09:32 +02:00
|
|
|
fprintf(vvp_out, " %%%s/r %u, %u, %u;\n",
|
|
|
|
|
rop,
|
2001-04-01 23:47:29 +02:00
|
|
|
res.base, res.base, res.wid);
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
res.wid = 1;
|
2001-06-18 03:09:32 +02:00
|
|
|
} else if (inv) {
|
2001-11-19 05:25:46 +01:00
|
|
|
assert(res.base >= 4);
|
2001-04-01 23:47:29 +02:00
|
|
|
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
|
|
|
|
}
|
2001-11-19 05:25:46 +01:00
|
|
|
|
|
|
|
|
/* If the result needs to be bigger then the calculated
|
|
|
|
|
value, then write it into a passed vector. */
|
|
|
|
|
if (res.wid < wid) {
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
tmp.base = allocate_vector(wid);
|
|
|
|
|
tmp.wid = wid;
|
2008-04-16 06:51:03 +02:00
|
|
|
assert(res.base);
|
2001-11-19 05:25:46 +01:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
tmp.base, res.base, res.wid);
|
2008-05-28 02:51:28 +02:00
|
|
|
fprintf(vvp_out, " %%movi %u, 0, %u;\n",
|
2001-11-19 05:25:46 +01:00
|
|
|
tmp.base+res.wid, tmp.wid-res.wid);
|
|
|
|
|
clr_vector(res);
|
|
|
|
|
res = tmp;
|
|
|
|
|
}
|
2001-04-01 23:47:29 +02:00
|
|
|
break;
|
|
|
|
|
|
2008-05-05 07:00:01 +02:00
|
|
|
case 'm': /* abs() */
|
|
|
|
|
res = draw_eval_expr_wid(sub, wid, 0);
|
|
|
|
|
|
|
|
|
|
if (!ivl_expr_signed(sub))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (res.base == 0 || res.base == 2 || res.base == 3)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Handle the special case of a -1 constant. Make the
|
|
|
|
|
result a 1. */
|
|
|
|
|
if (res.base == 1) {
|
|
|
|
|
res.base = allocate_vector(wid);
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%movi %d, 1, %u;\n",
|
2008-05-05 07:00:01 +02:00
|
|
|
res.base, res.wid);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-18 01:18:17 +02:00
|
|
|
fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count);
|
|
|
|
|
fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid);
|
|
|
|
|
fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid);
|
2008-05-05 07:00:01 +02:00
|
|
|
fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count);
|
|
|
|
|
local_count += 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-29 04:52:39 +02:00
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vvp error: unhandled unary: %c\n",
|
|
|
|
|
ivl_expr_opcode(exp));
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-27 18:33:34 +02:00
|
|
|
if (res.base >= 8)
|
|
|
|
|
save_expression_lookaside(res.base, exp, wid);
|
|
|
|
|
|
2001-03-29 04:52:39 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-06 06:41:37 +01:00
|
|
|
/*
|
|
|
|
|
* Sometimes we know ahead of time where we want the expression value
|
|
|
|
|
* to go. In that case, call this function. It will check to see if
|
|
|
|
|
* the expression can be preplaced, and if so it will evaluate it in
|
|
|
|
|
* place.
|
|
|
|
|
*/
|
|
|
|
|
static void draw_eval_expr_dest(ivl_expr_t exp, struct vector_info dest,
|
|
|
|
|
int stuff_ok_flag)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info tmp;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_type(exp)) {
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SIGNAL:
|
2008-01-13 03:22:46 +01:00
|
|
|
draw_signal_dest(exp, dest, -1, 0L);
|
2002-11-06 06:41:37 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fallback, is to draw the expression by width, and mov it to
|
|
|
|
|
the required dest. */
|
|
|
|
|
tmp = draw_eval_expr_wid(exp, dest.wid, stuff_ok_flag);
|
|
|
|
|
assert(tmp.wid == dest.wid);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n",
|
|
|
|
|
dest.base, tmp.base, dest.wid);
|
|
|
|
|
|
|
|
|
|
if (tmp.base >= 8)
|
|
|
|
|
save_expression_lookaside(tmp.base, exp, tmp.wid);
|
|
|
|
|
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-13 05:12:50 +02:00
|
|
|
struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid,
|
2002-09-24 06:20:32 +02:00
|
|
|
int stuff_ok_flag)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_type(exp)) {
|
|
|
|
|
default:
|
2001-03-31 04:00:44 +02:00
|
|
|
case IVL_EX_NONE:
|
2008-03-10 17:30:46 +01:00
|
|
|
fprintf(stderr, "%s:%u: vvp-tgt error: unhandled expr. type: "
|
|
|
|
|
"%u at %s:%d\n", ivl_expr_file(exp), ivl_expr_lineno(exp),
|
|
|
|
|
ivl_expr_type(exp), __FILE__, __LINE__);
|
2008-03-12 22:58:45 +01:00
|
|
|
exit(1);
|
2001-03-22 06:06:21 +01:00
|
|
|
res.base = 0;
|
|
|
|
|
res.wid = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-08-03 19:06:10 +02:00
|
|
|
case IVL_EX_STRING:
|
2001-10-18 18:41:49 +02:00
|
|
|
res = draw_string_expr(exp, wid);
|
2001-08-03 19:06:10 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case IVL_EX_BINARY:
|
2002-09-24 06:20:32 +02:00
|
|
|
res = draw_binary_expr(exp, wid, stuff_ok_flag);
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
case IVL_EX_CONCAT:
|
2005-09-17 03:01:00 +02:00
|
|
|
res = draw_concat_expr(exp, wid, stuff_ok_flag);
|
2001-03-31 04:00:44 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case IVL_EX_NUMBER:
|
2001-03-23 02:10:24 +01:00
|
|
|
res = draw_number_expr(exp, wid);
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-01-26 22:15:58 +01:00
|
|
|
case IVL_EX_REALNUM:
|
|
|
|
|
res = draw_realnum_expr(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2002-01-28 01:52:41 +01:00
|
|
|
case IVL_EX_SELECT:
|
2003-07-26 05:34:42 +02:00
|
|
|
if (ivl_expr_oper2(exp) == 0)
|
|
|
|
|
res = draw_pad_expr(exp, wid);
|
|
|
|
|
else
|
2005-09-17 03:01:00 +02:00
|
|
|
res = draw_select_expr(exp, wid, stuff_ok_flag);
|
2002-01-28 01:52:41 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case IVL_EX_SIGNAL:
|
2005-09-17 03:01:00 +02:00
|
|
|
res = draw_signal_expr(exp, wid, stuff_ok_flag);
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
2001-03-29 04:52:39 +02:00
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
case IVL_EX_TERNARY:
|
|
|
|
|
res = draw_ternary_expr(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-05-20 03:02:55 +02:00
|
|
|
case IVL_EX_SFUNC:
|
|
|
|
|
res = draw_sfunc_expr(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-06 04:28:02 +02:00
|
|
|
case IVL_EX_UFUNC:
|
|
|
|
|
res = draw_ufunc_expr(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-29 04:52:39 +02:00
|
|
|
case IVL_EX_UNARY:
|
|
|
|
|
res = draw_unary_expr(exp, wid);
|
|
|
|
|
break;
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-24 06:20:32 +02:00
|
|
|
struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag)
|
2001-03-23 02:10:24 +01:00
|
|
|
{
|
2002-09-24 06:20:32 +02:00
|
|
|
return draw_eval_expr_wid(exp, ivl_expr_width(exp), stuff_ok_flag);
|
2001-03-23 02:10:24 +01:00
|
|
|
}
|