2001-03-22 06:06:21 +01:00
|
|
|
/*
|
2014-03-01 00:29:15 +01:00
|
|
|
* Copyright (c) 2001-2014 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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2001-03-22 06:06:21 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# include "vvp_priv.h"
|
2001-07-07 22:20:10 +02:00
|
|
|
# include <string.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
# include <stdlib.h>
|
2001-03-22 06:06:21 +01:00
|
|
|
# include <assert.h>
|
2011-08-06 23:54:38 +02:00
|
|
|
# include <stdbool.h>
|
2010-10-24 00:52:56 +02:00
|
|
|
# include "ivl_alloc.h"
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2001-03-23 02:10:24 +01:00
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
int number_is_unknown(ivl_expr_t expr)
|
2002-06-02 20:57:17 +02:00
|
|
|
{
|
|
|
|
|
const char*bits;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_type(expr) == IVL_EX_ULONG)
|
2007-10-04 05:58:40 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
assert(ivl_expr_type(expr) == IVL_EX_NUMBER);
|
2002-06-02 20:57:17 +02:00
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
bits = ivl_expr_bits(expr);
|
|
|
|
|
for (idx = 0 ; idx < ivl_expr_width(expr) ; idx += 1)
|
2002-06-02 20:57:17 +02:00
|
|
|
if ((bits[idx] != '0') && (bits[idx] != '1'))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2010-05-24 05:50:21 +02:00
|
|
|
* This function returns TRUE if the number can be represented as a
|
|
|
|
|
* lim_wid immediate value. This amounts to verifying that any upper
|
|
|
|
|
* bits are the same. For a negative value we do not support the most
|
|
|
|
|
* negative twos-complement value since it can not be negated. This
|
|
|
|
|
* code generator always emits positive values, hence the negation
|
|
|
|
|
* requirement.
|
2002-06-02 20:57:17 +02:00
|
|
|
*/
|
2010-05-28 05:09:32 +02:00
|
|
|
int number_is_immediate(ivl_expr_t expr, unsigned lim_wid, int negative_ok_flag)
|
2002-06-02 20:57:17 +02:00
|
|
|
{
|
2010-05-24 05:50:21 +02:00
|
|
|
const char *bits;
|
2010-05-28 05:09:32 +02:00
|
|
|
unsigned nbits = ivl_expr_width(expr);
|
2008-06-13 22:32:06 +02:00
|
|
|
char pad_bit = '0';
|
2002-06-02 20:57:17 +02:00
|
|
|
unsigned idx;
|
|
|
|
|
|
2010-05-24 05:50:21 +02:00
|
|
|
/* We can only convert numbers to an immediate value. */
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_type(expr) != IVL_EX_NUMBER
|
|
|
|
|
&& ivl_expr_type(expr) != IVL_EX_ULONG
|
|
|
|
|
&& ivl_expr_type(expr) != IVL_EX_DELAY)
|
2006-01-02 06:33:19 +01:00
|
|
|
return 0;
|
2002-06-02 20:57:17 +02:00
|
|
|
|
2010-05-24 05:50:21 +02:00
|
|
|
/* If a negative value is OK, then we really have one less
|
|
|
|
|
* significant bit because of the sign bit. */
|
|
|
|
|
if (negative_ok_flag) lim_wid -= 1;
|
|
|
|
|
|
|
|
|
|
/* This is an unsigned value so it can not have the -2**N problem. */
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_type(expr) == IVL_EX_ULONG) {
|
2010-05-24 05:50:21 +02:00
|
|
|
unsigned long imm;
|
|
|
|
|
if (lim_wid >= 8*sizeof(unsigned long)) return 1;
|
|
|
|
|
/* At this point we know that lim_wid is smaller than an
|
|
|
|
|
* unsigned long variable. */
|
2010-05-28 05:09:32 +02:00
|
|
|
imm = ivl_expr_uvalue(expr);
|
2010-05-24 05:50:21 +02:00
|
|
|
if (imm < (1UL << lim_wid)) return 1;
|
2008-10-07 01:22:34 +02:00
|
|
|
else return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-24 05:50:21 +02:00
|
|
|
/* This is an unsigned value so it can not have the -2**N problem. */
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_type(expr) == IVL_EX_DELAY) {
|
2010-05-24 05:50:21 +02:00
|
|
|
uint64_t imm;
|
2009-02-17 01:44:52 +01:00
|
|
|
if (lim_wid >= 8*sizeof(uint64_t)) return 1;
|
2010-05-24 05:50:21 +02:00
|
|
|
/* At this point we know that lim_wid is smaller than a
|
|
|
|
|
* uint64_t variable. */
|
2010-05-28 05:09:32 +02:00
|
|
|
imm = ivl_expr_delay_val(expr);
|
2010-05-24 05:50:21 +02:00
|
|
|
if (imm < ((uint64_t)1 << lim_wid)) return 1;
|
2009-02-17 01:44:52 +01:00
|
|
|
else return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
bits = ivl_expr_bits(expr);
|
2002-06-02 20:57:17 +02:00
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_signed(expr) && bits[nbits-1]=='1') pad_bit = '1';
|
2008-06-13 22:32:06 +02:00
|
|
|
|
2010-05-24 05:50:21 +02:00
|
|
|
if (pad_bit == '1' && !negative_ok_flag) return 0;
|
2007-10-04 05:58:40 +02:00
|
|
|
|
2008-06-13 22:32:06 +02:00
|
|
|
for (idx = lim_wid ; idx < nbits ; idx += 1)
|
2010-05-24 05:50:21 +02:00
|
|
|
if (bits[idx] != pad_bit) return 0;
|
|
|
|
|
|
|
|
|
|
/* If we have a negative number make sure it is not too big. */
|
|
|
|
|
if (pad_bit == '1') {
|
|
|
|
|
for (idx = 0; idx < lim_wid; idx += 1)
|
|
|
|
|
if (bits[idx] == '1') return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2008-06-13 22:32:06 +02:00
|
|
|
|
2002-06-02 20:57:17 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-24 05:50:21 +02:00
|
|
|
/*
|
|
|
|
|
* We can return positive or negative values. You must verify that the
|
|
|
|
|
* number is not unknown (number_is_unknown) and is small enough
|
|
|
|
|
* (number_is_immediate).
|
|
|
|
|
*/
|
2010-05-28 05:09:32 +02:00
|
|
|
long get_number_immediate(ivl_expr_t expr)
|
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
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
switch (ivl_expr_type(expr)) {
|
2002-06-02 20:57:17 +02:00
|
|
|
case IVL_EX_ULONG:
|
2010-05-28 05:09:32 +02:00
|
|
|
imm = ivl_expr_uvalue(expr);
|
2002-06-02 20:57:17 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_NUMBER: {
|
2010-05-28 05:09:32 +02:00
|
|
|
const char*bits = ivl_expr_bits(expr);
|
|
|
|
|
unsigned nbits = ivl_expr_width(expr);
|
2013-04-15 20:53:07 +02:00
|
|
|
unsigned idx;
|
2010-05-24 05:50:21 +02:00
|
|
|
/* We can not copy more bits than fit into a long. */
|
|
|
|
|
if (nbits > 8*sizeof(long)) nbits = 8*sizeof(long);
|
2002-06-02 20:57:17 +02:00
|
|
|
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]){
|
|
|
|
|
case '0':
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
2008-06-13 06:41:11 +02:00
|
|
|
imm |= 1L << idx;
|
2002-06-02 20:57:17 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_signed(expr) && bits[nbits-1]=='1' &&
|
2010-05-24 05:50:21 +02:00
|
|
|
nbits < 8*sizeof(long)) imm |= -1L << nbits;
|
2002-06-02 20:57:17 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return imm;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
uint64_t get_number_immediate64(ivl_expr_t expr)
|
2009-02-24 22:50:18 +01:00
|
|
|
{
|
|
|
|
|
uint64_t imm = 0;
|
|
|
|
|
|
2010-05-28 05:09:32 +02:00
|
|
|
switch (ivl_expr_type(expr)) {
|
2009-02-24 22:50:18 +01:00
|
|
|
case IVL_EX_ULONG:
|
2010-05-28 05:09:32 +02:00
|
|
|
imm = ivl_expr_uvalue(expr);
|
2009-02-24 22:50:18 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_NUMBER: {
|
2010-05-28 05:09:32 +02:00
|
|
|
const char*bits = ivl_expr_bits(expr);
|
|
|
|
|
unsigned nbits = ivl_expr_width(expr);
|
2013-04-15 20:53:07 +02:00
|
|
|
unsigned idx;
|
2009-02-24 22:50:18 +01:00
|
|
|
for (idx = 0 ; idx < nbits ; idx += 1) switch (bits[idx]){
|
|
|
|
|
case '0':
|
|
|
|
|
break;
|
|
|
|
|
case '1':
|
|
|
|
|
assert(idx < 64);
|
|
|
|
|
imm |= UINT64_C(1) << idx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2010-05-28 05:09:32 +02:00
|
|
|
if (ivl_expr_signed(expr) && bits[nbits-1]=='1' && nbits < 64)
|
2009-02-26 06:30:05 +01:00
|
|
|
imm |= (-UINT64_C(1)) << nbits;
|
2009-02-24 22:50:18 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return imm;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-27 16:04:42 +01:00
|
|
|
void eval_logic_into_integer(ivl_expr_t expr, unsigned ix)
|
2007-12-07 22:12:19 +01:00
|
|
|
{
|
|
|
|
|
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
|
|
|
{
|
2008-10-07 01:22:34 +02:00
|
|
|
assert(number_is_immediate(expr, IMM_WID, 1));
|
2009-08-29 01:50:59 +02:00
|
|
|
if (number_is_unknown(expr)) {
|
|
|
|
|
/* We are loading a 'bx so mimic %ix/get. */
|
|
|
|
|
fprintf(vvp_out, " %%ix/load %u, 0, 0;\n", ix);
|
2013-12-27 16:04:42 +01:00
|
|
|
fprintf(vvp_out, " %%flag_set/imm 4, 1;\n");
|
2009-08-29 01:50:59 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2008-06-13 06:41:11 +02:00
|
|
|
long imm = get_number_immediate(expr);
|
|
|
|
|
if (imm >= 0) {
|
2009-02-17 01:44:52 +01:00
|
|
|
fprintf(vvp_out, " %%ix/load %u, %ld, 0;\n", ix, imm);
|
2008-06-13 06:41:11 +02:00
|
|
|
} else {
|
2009-02-17 01:44:52 +01:00
|
|
|
fprintf(vvp_out, " %%ix/load %u, 0, 0; loading %ld\n", ix, imm);
|
|
|
|
|
fprintf(vvp_out, " %%ix/sub %u, %ld, 0;\n", ix, -imm);
|
2008-06-13 06:41:11 +02:00
|
|
|
}
|
2013-12-27 16:04:42 +01:00
|
|
|
/* This can not have have a X/Z value so clear flag 4. */
|
|
|
|
|
fprintf(vvp_out, " %%flag_set/imm 4, 0;\n");
|
2008-06-13 06:41:11 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2007-12-07 22:12:19 +01:00
|
|
|
|
2013-12-27 16:04:42 +01:00
|
|
|
/* Special case: There is an %ix instruction for
|
|
|
|
|
reading index values directly from variables. In
|
|
|
|
|
this case, try to use that special instruction. */
|
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-09-30 03:06:47 +02:00
|
|
|
ivl_expr_t ixe;
|
2010-09-27 20:03:43 +02:00
|
|
|
const char*type = ivl_expr_signed(expr) ? "/s" : "";
|
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) {
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(expr);
|
2013-12-27 16:04:42 +01:00
|
|
|
fprintf(vvp_out, " %%ix/vec4%s %u;\n", type, ix);
|
2008-05-16 19:38:32 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-09-30 03:06:47 +02:00
|
|
|
ixe = ivl_expr_oper1(expr);
|
2009-08-29 01:50:59 +02:00
|
|
|
if (number_is_immediate(ixe, IMM_WID, 0)) {
|
|
|
|
|
assert(! number_is_unknown(ixe));
|
2008-01-15 00:57:01 +01:00
|
|
|
word = get_number_immediate(ixe);
|
2009-08-29 01:50:59 +02:00
|
|
|
} else {
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(expr);
|
2013-12-27 16:04:42 +01:00
|
|
|
fprintf(vvp_out, " %%ix/vec4%s %u;\n", type, ix);
|
2008-01-15 00:57:01 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2007-12-07 22:12:19 +01:00
|
|
|
}
|
2010-09-27 20:03:43 +02:00
|
|
|
const char*type = ivl_signal_signed(sig) ? "/s" : "";
|
2008-09-11 04:37:11 +02:00
|
|
|
fprintf(vvp_out, " %%ix/getv%s %u, v%p_%u;\n", type, ix,
|
|
|
|
|
sig, word);
|
2007-12-07 22:12:19 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-27 16:04:42 +01:00
|
|
|
default:
|
2014-10-24 18:32:32 +02:00
|
|
|
draw_eval_vec4(expr);
|
2013-12-27 16:04:42 +01:00
|
|
|
/* Is this a signed expression? */
|
|
|
|
|
if (ivl_expr_signed(expr)) {
|
|
|
|
|
fprintf(vvp_out, " %%ix/vec4/s %u;\n", ix);
|
|
|
|
|
} else {
|
|
|
|
|
fprintf(vvp_out, " %%ix/vec4 %u;\n", ix);
|
2007-12-07 22:12:19 +01:00
|
|
|
}
|
2013-12-27 16:04:42 +01:00
|
|
|
break;
|
2007-12-07 22:12:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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:
|
2012-10-23 02:20:43 +02:00
|
|
|
draw_eval_real(expr);
|
|
|
|
|
fprintf(vvp_out, " %%cvt/sr %u;\n", ix);
|
2006-02-02 03:43:57 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "XXXX ivl_expr_value == %d\n",
|
|
|
|
|
ivl_expr_value(expr));
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-10-24 20:17:36 +02:00
|
|
|
char *process_octal_codes(const char *in, unsigned width)
|
2001-03-29 04:52:39 +02:00
|
|
|
{
|
2014-10-24 20:17:36 +02:00
|
|
|
unsigned idx = 0;
|
|
|
|
|
unsigned ridx = 0;
|
|
|
|
|
unsigned str_len = strlen(in);
|
|
|
|
|
char *out = (char *)malloc(str_len+1);
|
2001-06-18 03:09:32 +02:00
|
|
|
|
2014-10-24 20:17:36 +02:00
|
|
|
/* If we do not have any octal codes just return the input. */
|
|
|
|
|
if (width/8 == str_len) {
|
|
|
|
|
strcpy(out, in);
|
|
|
|
|
return out;
|
2001-06-18 03:09:32 +02:00
|
|
|
}
|
2001-03-29 04:52:39 +02:00
|
|
|
|
2014-10-24 20:17:36 +02:00
|
|
|
while (ridx < str_len) {
|
|
|
|
|
/* 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;
|
2008-11-18 00:59:40 +01:00
|
|
|
} else {
|
2014-10-24 20:17:36 +02:00
|
|
|
out[idx] = in[ridx];
|
|
|
|
|
idx += 1;
|
|
|
|
|
ridx += 1;
|
2011-07-21 03:45:13 +02:00
|
|
|
}
|
2001-03-22 06:06:21 +01:00
|
|
|
}
|
2014-10-24 20:17:36 +02:00
|
|
|
out[idx] = '\0';
|
2001-03-22 06:06:21 +01:00
|
|
|
|
2014-10-24 20:17:36 +02:00
|
|
|
return out;
|
2001-03-23 02:10:24 +01:00
|
|
|
}
|