2001-03-22 06:06:21 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
#if !defined(WINNT)
|
2001-08-31 03:37:56 +02:00
|
|
|
#ident "$Id: eval_expr.c,v 1.43 2001/08/31 01:37:56 steve Exp $"
|
2001-03-22 06:06:21 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "vvp_priv.h"
|
2001-07-07 22:20:10 +02:00
|
|
|
# include <string.h>
|
|
|
|
|
# include <malloc.h>
|
2001-03-22 06:06:21 +01:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid);
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
static unsigned char allocation_map[0x10000/8];
|
|
|
|
|
|
|
|
|
|
static inline int peek_bit(unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
unsigned bit = addr % 8;
|
|
|
|
|
addr /= 8;
|
|
|
|
|
return 1 & (allocation_map[addr] >> bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void set_bit(unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
unsigned bit = addr % 8;
|
|
|
|
|
addr /= 8;
|
|
|
|
|
allocation_map[addr] |= (1 << bit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void clr_bit(unsigned addr)
|
|
|
|
|
{
|
|
|
|
|
unsigned bit = addr % 8;
|
|
|
|
|
addr /= 8;
|
|
|
|
|
allocation_map[addr] &= ~(1 << bit);
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-01 04:07:34 +02:00
|
|
|
/*
|
|
|
|
|
* This clears a vector that was previously allocated by
|
|
|
|
|
* allocate_vector. That is, it unmarks all the bits of the map that
|
|
|
|
|
* represent this vector.
|
|
|
|
|
*
|
|
|
|
|
* If the vector is based in one of 4 constant bit values, then there
|
|
|
|
|
* are no bits to clear. If the vector is based in the 4-8 result
|
|
|
|
|
* area, then someone is broken.
|
|
|
|
|
*/
|
2001-03-31 19:36:38 +02:00
|
|
|
void clr_vector(struct vector_info vec)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
2001-05-01 04:07:34 +02:00
|
|
|
if (vec.base < 4)
|
|
|
|
|
return;
|
|
|
|
|
assert(vec.base >= 8);
|
2001-03-22 06:06:21 +01:00
|
|
|
for (idx = 0 ; idx < vec.wid ; idx += 1)
|
|
|
|
|
clr_bit(vec.base + idx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned short allocate_vector(unsigned short wid)
|
|
|
|
|
{
|
|
|
|
|
unsigned short base = 8;
|
|
|
|
|
|
|
|
|
|
unsigned short idx = 0;
|
|
|
|
|
while (idx < wid) {
|
|
|
|
|
assert((base + idx) < 0x10000);
|
|
|
|
|
if (peek_bit(base+idx)) {
|
|
|
|
|
base = base + idx + 1;
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < wid ; idx += 1)
|
|
|
|
|
set_bit(base+idx);
|
|
|
|
|
|
|
|
|
|
return base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
static struct vector_info draw_binary_expr_eq(ivl_expr_t exp)
|
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);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
|
|
|
|
unsigned wid = ivl_expr_width(le);
|
|
|
|
|
if (ivl_expr_width(re) > wid)
|
|
|
|
|
wid = ivl_expr_width(re);
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid);
|
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);
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
lv.base = 6;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case 'e': /* == */
|
|
|
|
|
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': /* !== */
|
|
|
|
|
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': /* != */
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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. */
|
|
|
|
|
{ unsigned short base = allocate_vector(1);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, 1;\n", base, lv.base);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* XXXX For now, assume the operands are a single bit. */
|
|
|
|
|
assert(ivl_expr_width(le) == 1);
|
|
|
|
|
assert(ivl_expr_width(re) == 1);
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid);
|
|
|
|
|
|
|
|
|
|
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, " %%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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(wid == 1);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/* XXXX For now, assume the operands are a single bit. */
|
|
|
|
|
assert(ivl_expr_width(le) == 1);
|
|
|
|
|
assert(ivl_expr_width(re) == 1);
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(wid == 1);
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
static struct vector_info draw_binary_expr_le(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;
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, owid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, owid);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
2001-04-05 03:12:27 +02:00
|
|
|
case 'G':
|
|
|
|
|
assert(lv.wid == rv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
rv.base, lv.base, lv.wid);
|
|
|
|
|
fprintf(vvp_out, " %%or 5, 4, 1;\n");
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
case 'L':
|
|
|
|
|
assert(lv.wid == rv.wid);
|
2001-04-05 03:12:27 +02:00
|
|
|
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 '<':
|
|
|
|
|
assert(lv.wid == rv.wid);
|
2001-04-05 03:12:27 +02:00
|
|
|
fprintf(vvp_out, " %%cmp/%c %u, %u, %u;\n", s_flag,
|
|
|
|
|
lv.base, rv.base, lv.wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clr_vector(lv);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
|
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. */
|
|
|
|
|
{ unsigned short base = allocate_vector(1);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 5, 1;\n", base);
|
|
|
|
|
lv.base = base;
|
|
|
|
|
lv.wid = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-01 09:22:42 +02:00
|
|
|
assert(wid == 1);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid);
|
|
|
|
|
|
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;
|
|
|
|
|
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 '&':
|
|
|
|
|
fprintf(vvp_out, " %%and %u, %u, %u;\n",
|
|
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '|':
|
|
|
|
|
fprintf(vvp_out, " %%or %u, %u, %u;\n",
|
|
|
|
|
lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-04-15 18:37:48 +02:00
|
|
|
case '^':
|
|
|
|
|
fprintf(vvp_out, " %%xor %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);
|
|
|
|
|
|
|
|
|
|
struct vector_info lv;
|
|
|
|
|
|
2001-06-23 20:40:34 +02: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. */
|
2001-04-21 03:49:17 +02:00
|
|
|
switch (ivl_expr_type(re)) {
|
2001-06-23 20:40:34 +02:00
|
|
|
|
2001-04-21 03:49:17 +02:00
|
|
|
case IVL_EX_NUMBER: {
|
2001-06-23 20:40:34 +02:00
|
|
|
unsigned shift = 0;
|
2001-04-21 03:49:17 +02:00
|
|
|
unsigned idx, nbits = ivl_expr_width(re);
|
|
|
|
|
const char*bits = ivl_expr_bits(re);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]) {
|
|
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
assert(idx < (8*sizeof shift));
|
|
|
|
|
shift |= 1 << idx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2001-06-23 20:40:34 +02:00
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 0, %u;\n", shift);
|
2001-04-21 03:49:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IVL_EX_ULONG:
|
2001-06-23 20:40:34 +02:00
|
|
|
fprintf(vvp_out, " %%ix/load 0, %lu;\n", ivl_expr_uvalue(re));
|
2001-04-21 03:49:17 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-06-23 20:40:34 +02:00
|
|
|
default: {
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
rv = draw_eval_expr(re);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get 0, %u, %u;\n",
|
|
|
|
|
rv.base, rv.wid);
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-04-21 03:49:17 +02:00
|
|
|
}
|
|
|
|
|
|
2001-04-21 05:26:23 +02:00
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
|
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) */
|
|
|
|
|
fprintf(vvp_out, " %%shiftl/i0 %u, %u;\n", lv.base, lv.wid);
|
|
|
|
|
break;
|
2001-04-21 05:26:23 +02:00
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
case 'r': /* >> (unsigned right shift) */
|
|
|
|
|
fprintf(vvp_out, " %%shiftr/i0 %u, %u;\n", lv.base, lv.wid);
|
2001-04-21 05:26:23 +02:00
|
|
|
break;
|
2001-06-30 23:07:26 +02:00
|
|
|
|
2001-04-21 05:26:23 +02:00
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
return lv;
|
2001-04-21 05:26:23 +02:00
|
|
|
}
|
|
|
|
|
|
2001-06-30 23:07:26 +02:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
lv = draw_eval_expr_wid(le, wid);
|
|
|
|
|
rv = draw_eval_expr_wid(re, wid);
|
|
|
|
|
|
2001-06-17 01:45:05 +02:00
|
|
|
assert(lv.wid == wid);
|
|
|
|
|
assert(rv.wid == wid);
|
|
|
|
|
|
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-05-24 06:20:10 +02:00
|
|
|
case '%':
|
|
|
|
|
fprintf(vvp_out, " %%mod %u, %u, %u;\n", lv.base, rv.base, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2001-03-31 04:00:44 +02:00
|
|
|
|
|
|
|
|
clr_vector(rv);
|
|
|
|
|
|
|
|
|
|
return lv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
static struct vector_info draw_binary_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info rv;
|
|
|
|
|
|
|
|
|
|
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': /* != */
|
|
|
|
|
assert(wid == 1);
|
|
|
|
|
rv = draw_binary_expr_eq(exp);
|
|
|
|
|
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': /* >= */
|
2001-04-01 09:22:42 +02:00
|
|
|
rv = draw_binary_expr_le(exp, wid);
|
|
|
|
|
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-05-24 06:20:10 +02:00
|
|
|
case '%':
|
|
|
|
|
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': /* >> */
|
|
|
|
|
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 '^':
|
2001-04-15 06:07:56 +02:00
|
|
|
case 'X':
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-22 02:17:49 +02:00
|
|
|
static struct vector_info draw_bitsel_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
ivl_signal_t sig = ivl_expr_signal(exp);
|
|
|
|
|
ivl_expr_t sel = ivl_expr_oper1(exp);
|
|
|
|
|
|
|
|
|
|
/* Evaluate the bit select expression and save the result into
|
|
|
|
|
index register 0. */
|
|
|
|
|
res = draw_eval_expr(sel);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get 0, %u,%u;\n", res.base, res.wid);
|
|
|
|
|
clr_vector(res);
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%load/x %u, V_%s, 0;\n", res.base,
|
|
|
|
|
vvp_mangle_id(ivl_signal_name(sig)));
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
static struct vector_info draw_concat_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
2001-07-22 21:33:51 +02:00
|
|
|
unsigned off, rep;
|
2001-03-31 04:00:44 +02:00
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
assert(wid >= ivl_expr_width(exp));
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
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) {
|
|
|
|
|
unsigned idx = ivl_expr_parms(exp);
|
|
|
|
|
while (idx > 0) {
|
|
|
|
|
ivl_expr_t arg = ivl_expr_parm(exp, idx-1);
|
|
|
|
|
unsigned awid = ivl_expr_width(arg);
|
2001-03-31 04:00:44 +02:00
|
|
|
|
2001-07-22 21:33:51 +02:00
|
|
|
struct vector_info avec = draw_eval_expr_wid(arg, awid);
|
2001-03-31 04:00:44 +02:00
|
|
|
|
2001-07-22 21:33:51 +02:00
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base+off,
|
|
|
|
|
avec.base, avec.wid);
|
|
|
|
|
clr_vector(avec);
|
|
|
|
|
|
|
|
|
|
idx -= 1;
|
|
|
|
|
off += awid;
|
|
|
|
|
assert(off <= wid);
|
|
|
|
|
}
|
|
|
|
|
rep -= 1;
|
2001-03-31 04:00:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (off < wid) {
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+off, wid-off);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
2001-03-29 07:16:25 +02:00
|
|
|
while (idx < nwid) {
|
2001-03-23 02:10:24 +01:00
|
|
|
unsigned cnt;
|
2001-03-22 06:06:21 +01:00
|
|
|
char src = '?';
|
|
|
|
|
switch (bits[idx]) {
|
|
|
|
|
case '0':
|
|
|
|
|
src = '0';
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
src = '1';
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
src = '2';
|
|
|
|
|
break;
|
|
|
|
|
case 'z':
|
|
|
|
|
src = '3';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
for (cnt = 1 ; idx+cnt < wid ; cnt += 1)
|
|
|
|
|
if (bits[idx+cnt] != bits[idx])
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %c, %u;\n",
|
|
|
|
|
res.base+idx, src, cnt);
|
|
|
|
|
|
|
|
|
|
idx += cnt;
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-29 07:16:25 +02:00
|
|
|
/* Pad the number up to the expression width. */
|
|
|
|
|
if (idx < wid)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n", res.base+idx, wid-idx);
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2001-03-23 02:10:24 +01:00
|
|
|
static struct vector_info draw_signal_expr(ivl_expr_t exp, unsigned wid)
|
2001-03-22 06:06:21 +01:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
2001-07-27 06:51:44 +02:00
|
|
|
unsigned lsi = ivl_expr_lsi(exp);
|
2001-03-23 02:10:24 +01:00
|
|
|
unsigned swid = ivl_expr_width(exp);
|
2001-03-22 06:06:21 +01:00
|
|
|
const char*name = ivl_expr_name(exp);
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
if (swid > wid)
|
|
|
|
|
swid = wid;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
for (idx = 0 ; idx < swid ; idx += 1)
|
2001-03-22 06:06:21 +01:00
|
|
|
fprintf(vvp_out, " %%load %u, V_%s[%u];\n",
|
2001-07-27 06:51:44 +02:00
|
|
|
res.base+idx, vvp_mangle_id(name), idx+lsi);
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
/* Pad the signal value with zeros. */
|
|
|
|
|
if (swid < wid)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+swid, wid-swid);
|
2001-03-22 06:06:21 +01:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-06 19:54:33 +02:00
|
|
|
void draw_memory_index_expr(ivl_memory_t mem, ivl_expr_t ae)
|
|
|
|
|
{
|
|
|
|
|
int root = ivl_memory_root(mem);
|
|
|
|
|
unsigned width = ivl_memory_width(mem);
|
2001-05-10 02:26:53 +02:00
|
|
|
width = (width+3) & ~3;
|
2001-05-06 19:54:33 +02:00
|
|
|
|
|
|
|
|
switch (ivl_expr_type(ae)) {
|
|
|
|
|
case IVL_EX_NUMBER: {
|
|
|
|
|
unsigned nbits = ivl_expr_width(ae);
|
|
|
|
|
const char*bits = ivl_expr_bits(ae);
|
|
|
|
|
unsigned long v = 0;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0 ; idx < nbits ; idx += 1)
|
|
|
|
|
switch (bits[idx]) {
|
|
|
|
|
case '0':
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
assert(idx < (8*sizeof v));
|
|
|
|
|
v |= 1 << idx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
v = ~0UL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 3, %lu;\n", (v-root)*width);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IVL_EX_ULONG: {
|
|
|
|
|
unsigned v = ivl_expr_uvalue(ae);
|
|
|
|
|
fprintf(vvp_out, " %%ix/load 3, %u;\n", (v-root)*width);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
struct vector_info addr = draw_eval_expr(ae);
|
|
|
|
|
fprintf(vvp_out, " %%ix/get 3, %u, %u;\n",
|
|
|
|
|
addr.base, addr.wid);
|
|
|
|
|
clr_vector(addr);
|
|
|
|
|
if (root>0)
|
2001-05-10 02:26:53 +02:00
|
|
|
fprintf(vvp_out, " %%ix/sub 3, %u;\n", root);
|
2001-05-06 19:54:33 +02:00
|
|
|
if (width>1)
|
2001-05-10 02:26:53 +02:00
|
|
|
fprintf(vvp_out, " %%ix/mul 3, %u;\n", width);
|
2001-05-06 19:54:33 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct vector_info draw_memory_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
unsigned swid = ivl_expr_width(exp);
|
|
|
|
|
const char*name = ivl_expr_name(exp);
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
|
|
|
|
draw_memory_index_expr(ivl_expr_memory(exp), ivl_expr_oper1(exp));
|
|
|
|
|
|
|
|
|
|
if (swid > wid)
|
|
|
|
|
swid = wid;
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < swid ; idx += 1) {
|
|
|
|
|
if (idx)
|
|
|
|
|
fprintf(vvp_out, " %%ix/add 3, 1;\n");
|
|
|
|
|
fprintf(vvp_out, " %%load/m %u, M_%s;\n",
|
2001-06-21 06:53:59 +02:00
|
|
|
res.base+idx, vvp_mangle_id(name));
|
2001-05-06 19:54:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pad the signal value with zeros. */
|
|
|
|
|
if (swid < wid)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+swid, wid-swid);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-17 06:37:02 +02:00
|
|
|
static struct vector_info draw_ternary_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
struct vector_info res, tmp;
|
|
|
|
|
|
|
|
|
|
unsigned lab_false, lab_out;
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
lab_false = local_count++;
|
|
|
|
|
lab_out = local_count++;
|
|
|
|
|
|
|
|
|
|
tmp = draw_eval_expr(cond);
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, " %%jmp/0xz T_%d.%d, %u;\n",
|
|
|
|
|
thread_count, lab_false, tmp.base);
|
|
|
|
|
|
|
|
|
|
tmp = draw_eval_expr_wid(true_ex, wid);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, tmp.base, wid);
|
|
|
|
|
fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out);
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_false);
|
|
|
|
|
|
|
|
|
|
tmp = draw_eval_expr_wid(false_ex, wid);
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, %u, %u;\n", res.base, tmp.base, wid);
|
|
|
|
|
clr_vector(tmp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out);
|
|
|
|
|
|
|
|
|
|
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 idx;
|
|
|
|
|
struct vector_info *vec = 0x0;
|
|
|
|
|
unsigned int vecs= 0;
|
|
|
|
|
unsigned int veci= 0;
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
fprintf(vvp_out, " %%vpi_func \"%s\", %u, %u;\n",
|
|
|
|
|
ivl_expr_name(exp), res.base, res.wid);
|
|
|
|
|
return res;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Evaluate any expressions that need to be evaluated by the
|
|
|
|
|
run-time before passed to the system task. The results are
|
|
|
|
|
stored in the vec array. */
|
|
|
|
|
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
ivl_expr_t expr = ivl_expr_parm(exp, idx);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_type(expr)) {
|
|
|
|
|
case IVL_EX_NONE:
|
|
|
|
|
case IVL_EX_NUMBER:
|
|
|
|
|
case IVL_EX_SIGNAL:
|
|
|
|
|
case IVL_EX_STRING:
|
|
|
|
|
case IVL_EX_SCOPE:
|
|
|
|
|
case IVL_EX_SFUNC:
|
|
|
|
|
continue;
|
|
|
|
|
case IVL_EX_MEMORY:
|
|
|
|
|
if (!ivl_expr_oper1(expr)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec = (struct vector_info *)
|
|
|
|
|
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
|
|
|
|
vec[vecs] = draw_eval_expr(expr);
|
|
|
|
|
vecs++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Start the complicated expression. */
|
2001-05-20 03:02:55 +02:00
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2001-07-07 22:20:10 +02:00
|
|
|
fprintf(vvp_out, " %%vpi_func \"%s\", %u, %u",
|
2001-05-20 03:02:55 +02:00
|
|
|
ivl_expr_name(exp), res.base, res.wid);
|
|
|
|
|
|
2001-07-07 22:20:10 +02:00
|
|
|
/* Now draw all the parameters to the function. */
|
|
|
|
|
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
ivl_expr_t expr = ivl_expr_parm(exp, idx);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_type(expr)) {
|
|
|
|
|
case IVL_EX_NONE:
|
|
|
|
|
fprintf(vvp_out, ", \" \"");
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_NUMBER: {
|
|
|
|
|
unsigned bit, wid = ivl_expr_width(expr);
|
|
|
|
|
const char*bits = ivl_expr_bits(expr);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, ", %u'b", wid);
|
|
|
|
|
for (bit = wid ; bit > 0 ; bit -= 1)
|
|
|
|
|
fputc(bits[bit-1], vvp_out);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SIGNAL:
|
|
|
|
|
fprintf(vvp_out, ", V_%s",
|
|
|
|
|
vvp_mangle_id(ivl_expr_name(expr)));
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_STRING:
|
|
|
|
|
fprintf(vvp_out, ", \"%s\"",
|
|
|
|
|
ivl_expr_string(expr));
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SCOPE:
|
|
|
|
|
fprintf(vvp_out, ", S_%s",
|
|
|
|
|
vvp_mangle_id(ivl_scope_name(ivl_expr_scope(expr))));
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SFUNC:
|
|
|
|
|
if (strcmp("$time", ivl_expr_name(expr)) == 0)
|
|
|
|
|
fprintf(vvp_out, ", $time");
|
|
|
|
|
else
|
|
|
|
|
fprintf(vvp_out, ", ?");
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_MEMORY:
|
|
|
|
|
if (!ivl_expr_oper1(expr)) {
|
|
|
|
|
fprintf(vvp_out, ", M_%s",
|
|
|
|
|
vvp_mangle_id(ivl_expr_name(expr)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, ", T<%u,%u>",
|
|
|
|
|
vec[veci].base,
|
|
|
|
|
vec[veci].wid);
|
|
|
|
|
veci++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(veci == vecs);
|
|
|
|
|
|
|
|
|
|
if (vecs) {
|
|
|
|
|
for (idx = 0; idx < vecs; idx++)
|
|
|
|
|
clr_vector(vec[idx]);
|
|
|
|
|
free(vec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, ";\n");
|
|
|
|
|
|
|
|
|
|
|
2001-05-20 03:02:55 +02:00
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-06 04:28:02 +02:00
|
|
|
/*
|
|
|
|
|
* A call to a user defined function generates a result that is the
|
|
|
|
|
* result of this expression.
|
|
|
|
|
*
|
|
|
|
|
* The result of the function is placed by the function execution into
|
|
|
|
|
* a signal within the scope of the function that also has a basename
|
|
|
|
|
* the same as the function. The ivl_target API handled the result
|
|
|
|
|
* mapping already, and we get the name of the result signal as
|
|
|
|
|
* parameter 0 of the function definition.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
unsigned swid = ivl_expr_width(exp);
|
|
|
|
|
ivl_scope_t def = ivl_expr_def(exp);
|
2001-07-27 04:41:55 +02:00
|
|
|
ivl_signal_t retval = ivl_scope_port(def, 0);
|
2001-04-06 04:28:02 +02:00
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
/* evaluate the expressions and send the results to the
|
|
|
|
|
function ports. */
|
|
|
|
|
|
|
|
|
|
assert(ivl_expr_parms(exp) == (ivl_scope_ports(def)-1));
|
|
|
|
|
for (idx = 0 ; idx < ivl_expr_parms(exp) ; idx += 1) {
|
2001-07-27 04:41:55 +02:00
|
|
|
ivl_signal_t port = ivl_scope_port(def, idx+1);
|
2001-04-06 04:28:02 +02:00
|
|
|
unsigned pin, bit;
|
|
|
|
|
|
2001-07-27 04:41:55 +02:00
|
|
|
res = draw_eval_expr_wid(ivl_expr_parm(exp, idx),
|
|
|
|
|
ivl_signal_pins(port));
|
2001-04-06 04:28:02 +02:00
|
|
|
bit = res.base;
|
2001-07-27 04:41:55 +02:00
|
|
|
assert(res.wid <= ivl_signal_pins(port));
|
2001-04-06 04:28:02 +02:00
|
|
|
for (pin = 0 ; pin < res.wid ; pin += 1) {
|
|
|
|
|
fprintf(vvp_out, " %%set V_%s[%u], %u;\n",
|
2001-07-27 04:41:55 +02:00
|
|
|
vvp_mangle_id(ivl_signal_name(port)),
|
|
|
|
|
pin, bit);
|
2001-04-06 04:28:02 +02:00
|
|
|
if (bit >= 4)
|
|
|
|
|
bit += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clr_vector(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Call the function */
|
2001-06-21 06:53:59 +02:00
|
|
|
fprintf(vvp_out, " %%fork TD_%s", vvp_mangle_id(ivl_scope_name(def)));
|
|
|
|
|
fprintf(vvp_out, ", S_%s;\n", vvp_mangle_id(ivl_scope_name(def)));
|
2001-04-06 04:28:02 +02:00
|
|
|
fprintf(vvp_out, " %%join;\n");
|
|
|
|
|
|
|
|
|
|
/* The return value is in a signal that has the name of the
|
|
|
|
|
expression. Load that into the thread and return the
|
|
|
|
|
vector result. */
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
|
|
|
|
|
2001-08-23 04:54:15 +02:00
|
|
|
{ unsigned load_wid = swid;
|
|
|
|
|
if (load_wid > ivl_signal_pins(retval))
|
|
|
|
|
load_wid = ivl_signal_pins(retval);
|
|
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < load_wid ; idx += 1)
|
|
|
|
|
fprintf(vvp_out, " %%load %u, V_%s[%u];\n",
|
|
|
|
|
res.base+idx,
|
|
|
|
|
vvp_mangle_id(ivl_signal_name(retval)), idx);
|
|
|
|
|
|
|
|
|
|
if (load_wid < swid)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+load_wid, swid-load_wid);
|
|
|
|
|
}
|
2001-04-06 04:28:02 +02:00
|
|
|
|
|
|
|
|
/* Pad the signal value with zeros. */
|
|
|
|
|
if (swid < wid)
|
|
|
|
|
fprintf(vvp_out, " %%mov %u, 0, %u;\n",
|
|
|
|
|
res.base+swid, wid-swid);
|
|
|
|
|
|
|
|
|
|
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-06-18 03:09:32 +02:00
|
|
|
const char *rop;
|
|
|
|
|
int inv = 0;
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_opcode(exp)) {
|
|
|
|
|
case '!': rop = "nor"; break;
|
|
|
|
|
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 '~':
|
2001-04-02 00:26:21 +02:00
|
|
|
res = draw_eval_expr_wid(sub, wid);
|
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-04-01 23:47:29 +02:00
|
|
|
case '!':
|
2001-06-18 03:09:32 +02:00
|
|
|
case 'N':
|
|
|
|
|
case 'A':
|
|
|
|
|
case 'X':
|
|
|
|
|
inv = 1;
|
|
|
|
|
case '&':
|
|
|
|
|
case '|':
|
|
|
|
|
case '^':
|
2001-04-02 00:26:21 +02:00
|
|
|
res = draw_eval_expr(sub);
|
2001-04-01 23:47:29 +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;
|
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-04-01 23:47:29 +02:00
|
|
|
fprintf(vvp_out, " %%inv %u, 1;\n", res.base);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-29 04:52:39 +02:00
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vvp error: unhandled unary: %c\n",
|
|
|
|
|
ivl_expr_opcode(exp));
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid)
|
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
|
|
|
fprintf(stderr, "vvp error: unhandled expr type: %u\n",
|
2001-08-03 19:06:10 +02:00
|
|
|
ivl_expr_type(exp));
|
2001-03-31 04:00:44 +02:00
|
|
|
case IVL_EX_NONE:
|
2001-03-22 06:06:21 +01:00
|
|
|
assert(0);
|
|
|
|
|
res.base = 0;
|
|
|
|
|
res.wid = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-08-03 19:06:10 +02:00
|
|
|
case IVL_EX_STRING:
|
|
|
|
|
fprintf(stderr, "vvp error: unhandled expr type STRING\n");
|
|
|
|
|
assert(0);
|
|
|
|
|
res.base = 0;
|
|
|
|
|
res.wid = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
case IVL_EX_BINARY:
|
2001-03-23 02:10:24 +01:00
|
|
|
res = draw_binary_expr(exp, wid);
|
2001-03-22 06:06:21 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-07-22 02:17:49 +02:00
|
|
|
case IVL_EX_BITSEL:
|
|
|
|
|
res = draw_bitsel_expr(exp, wid);
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-31 04:00:44 +02:00
|
|
|
case IVL_EX_CONCAT:
|
|
|
|
|
res = draw_concat_expr(exp, wid);
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SIGNAL:
|
2001-03-23 02:10:24 +01:00
|
|
|
res = draw_signal_expr(exp, wid);
|
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-06 19:54:33 +02:00
|
|
|
case IVL_EX_MEMORY:
|
|
|
|
|
res = draw_memory_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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
struct vector_info draw_eval_expr(ivl_expr_t exp)
|
|
|
|
|
{
|
|
|
|
|
return draw_eval_expr_wid(exp, ivl_expr_width(exp));
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-22 06:06:21 +01:00
|
|
|
/*
|
|
|
|
|
* $Log: eval_expr.c,v $
|
2001-08-31 03:37:56 +02:00
|
|
|
* Revision 1.43 2001/08/31 01:37:56 steve
|
|
|
|
|
* Handle update in place of repeat constants.
|
|
|
|
|
*
|
2001-08-23 04:54:15 +02:00
|
|
|
* Revision 1.42 2001/08/23 02:54:15 steve
|
|
|
|
|
* Handle wide assignment to narrow return value.
|
|
|
|
|
*
|
2001-08-03 19:06:10 +02:00
|
|
|
* Revision 1.41 2001/08/03 17:06:10 steve
|
|
|
|
|
* More detailed messages about unsupported things.
|
|
|
|
|
*
|
2001-07-27 06:51:44 +02:00
|
|
|
* Revision 1.40 2001/07/27 04:51:45 steve
|
|
|
|
|
* Handle part select expressions as variants of
|
|
|
|
|
* NetESignal/IVL_EX_SIGNAL objects, instead of
|
|
|
|
|
* creating new and useless temporary signals.
|
|
|
|
|
*
|
2001-07-27 04:41:55 +02:00
|
|
|
* Revision 1.39 2001/07/27 02:41:56 steve
|
|
|
|
|
* Fix binding of dangling function ports. do not elide them.
|
|
|
|
|
*
|
2001-07-22 21:33:51 +02:00
|
|
|
* Revision 1.38 2001/07/22 19:33:51 steve
|
|
|
|
|
* Handle repeat for concatenation expressions.
|
|
|
|
|
*
|
2001-07-22 02:17:49 +02:00
|
|
|
* Revision 1.37 2001/07/22 00:17:50 steve
|
|
|
|
|
* Support the NetESubSignal expressions in vvp.tgt.
|
|
|
|
|
*
|
2001-07-09 17:38:35 +02:00
|
|
|
* Revision 1.36 2001/07/09 15:38:35 steve
|
|
|
|
|
* Properly step through wide inputs. (Stephan Boettcher)
|
|
|
|
|
*
|
2001-07-07 22:20:10 +02:00
|
|
|
* Revision 1.35 2001/07/07 20:20:10 steve
|
|
|
|
|
* Pass parameters to system functions.
|
|
|
|
|
*
|
2001-06-30 23:07:26 +02:00
|
|
|
* Revision 1.34 2001/06/30 21:07:26 steve
|
|
|
|
|
* Support non-const right shift (unsigned).
|
|
|
|
|
*
|
2001-06-23 20:40:34 +02:00
|
|
|
* Revision 1.33 2001/06/23 18:40:34 steve
|
|
|
|
|
* Generate %shiftl instructions for shift.
|
|
|
|
|
*
|
2001-06-21 06:53:59 +02:00
|
|
|
* Revision 1.32 2001/06/21 04:53:59 steve
|
|
|
|
|
* Escaped identifiers in behavioral expressions. (Stephan Boettcher)
|
|
|
|
|
*
|
2001-06-18 03:09:32 +02:00
|
|
|
* Revision 1.31 2001/06/18 01:09:32 steve
|
|
|
|
|
* More behavioral unary reduction operators.
|
|
|
|
|
* (Stephan Boettcher)
|
|
|
|
|
*
|
2001-06-17 01:45:05 +02:00
|
|
|
* Revision 1.30 2001/06/16 23:45:05 steve
|
|
|
|
|
* Add support for structural multiply in t-dll.
|
|
|
|
|
* Add code generators and vvp support for both
|
|
|
|
|
* structural and behavioral multiply.
|
|
|
|
|
*
|
2001-05-24 06:20:10 +02:00
|
|
|
* Revision 1.29 2001/05/24 04:20:10 steve
|
|
|
|
|
* Add behavioral modulus.
|
|
|
|
|
*
|
2001-05-20 03:18:38 +02:00
|
|
|
* Revision 1.28 2001/05/20 01:18:38 steve
|
|
|
|
|
* Implement reduction nor.
|
|
|
|
|
*
|
2001-05-20 03:02:55 +02:00
|
|
|
* Revision 1.27 2001/05/20 01:02:55 steve
|
|
|
|
|
* Initial support for system functions.
|
|
|
|
|
*
|
2001-05-17 06:37:02 +02:00
|
|
|
* Revision 1.26 2001/05/17 04:37:02 steve
|
|
|
|
|
* Behavioral ternary operators for vvp.
|
|
|
|
|
*
|
2001-05-10 02:26:53 +02:00
|
|
|
* Revision 1.25 2001/05/10 00:26:53 steve
|
|
|
|
|
* VVP support for memories in expressions,
|
|
|
|
|
* including general support for thread bit
|
|
|
|
|
* vectors as system task parameters.
|
|
|
|
|
* (Stephan Boettcher)
|
|
|
|
|
*
|
2001-05-06 19:54:33 +02:00
|
|
|
* Revision 1.24 2001/05/06 17:54:33 steve
|
|
|
|
|
* Behavioral code to read memories. (Stephan Boettcher)
|
|
|
|
|
*
|
2001-05-02 03:57:25 +02:00
|
|
|
* Revision 1.23 2001/05/02 01:57:25 steve
|
|
|
|
|
* Support behavioral subtraction.
|
|
|
|
|
*
|
2001-05-01 04:07:34 +02:00
|
|
|
* Revision 1.22 2001/05/01 02:07:34 steve
|
|
|
|
|
* Comparisons cant leave their results in the opcode
|
|
|
|
|
* result area or their values will be clobbered by other
|
|
|
|
|
* parts of a complex expression.
|
|
|
|
|
*
|
2001-04-30 07:11:18 +02:00
|
|
|
* Revision 1.21 2001/04/30 05:11:18 steve
|
|
|
|
|
* OR is %or. Get this right.
|
|
|
|
|
*
|
2001-04-29 22:47:39 +02:00
|
|
|
* Revision 1.20 2001/04/29 20:47:39 steve
|
|
|
|
|
* Evalulate logical or (||)
|
2001-03-22 06:06:21 +01:00
|
|
|
*/
|
|
|
|
|
|