2003-02-28 21:21:13 +01:00
|
|
|
/*
|
2008-01-02 19:42:23 +01:00
|
|
|
* Copyright (c) 2003-2008 Stephen Williams (steve@icarus.com)
|
2003-02-28 21:21:13 +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"
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#ifdef HAVE_MALLOC_H
|
|
|
|
|
# include <malloc.h>
|
|
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <assert.h>
|
|
|
|
|
|
2003-03-07 03:43:32 +01:00
|
|
|
static const char* magic_sfuncs[] = {
|
|
|
|
|
"$time",
|
|
|
|
|
"$stime",
|
|
|
|
|
"$realtime",
|
|
|
|
|
"$simtime",
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int is_magic_sfunc(const char*name)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
for (idx = 0 ; magic_sfuncs[idx] ; idx += 1)
|
|
|
|
|
if (strcmp(magic_sfuncs[idx],name) == 0)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-30 06:28:23 +01:00
|
|
|
static int is_fixed_memory_word(ivl_expr_t net)
|
|
|
|
|
{
|
|
|
|
|
ivl_signal_t sig;
|
|
|
|
|
|
|
|
|
|
if (ivl_expr_type(net) != IVL_EX_SIGNAL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
sig = ivl_expr_signal(net);
|
|
|
|
|
|
|
|
|
|
if (ivl_signal_array_count(sig) == 1)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (number_is_immediate(ivl_expr_oper1(net), 8*sizeof(unsigned)))
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-03-07 03:43:32 +01:00
|
|
|
|
2003-03-15 05:45:18 +01:00
|
|
|
static void draw_vpi_taskfunc_args(const char*call_string,
|
|
|
|
|
ivl_statement_t tnet,
|
|
|
|
|
ivl_expr_t fnet)
|
2003-02-28 21:21:13 +01:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
unsigned parm_count = tnet
|
|
|
|
|
? ivl_stmt_parm_count(tnet)
|
|
|
|
|
: ivl_expr_parms(fnet);
|
|
|
|
|
struct vector_info *vec = 0x0;
|
|
|
|
|
unsigned int vecs= 0;
|
|
|
|
|
unsigned int veci= 0;
|
2003-03-11 00:40:53 +01:00
|
|
|
|
|
|
|
|
ivl_parameter_t par;
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
/* Figure out how many expressions are going to be evaluated
|
|
|
|
|
for this task call. I won't need to evaluate expressions
|
|
|
|
|
for items that are VPI objects directly. */
|
|
|
|
|
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
ivl_expr_t expr = tnet
|
|
|
|
|
? ivl_stmt_parm(tnet, idx)
|
|
|
|
|
: ivl_expr_parm(fnet, idx);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
switch (ivl_expr_type(expr)) {
|
|
|
|
|
|
|
|
|
|
/* These expression types can be handled directly,
|
|
|
|
|
with VPI handles of their own. Therefore, skip
|
|
|
|
|
them in the process of evaluating expressions. */
|
|
|
|
|
case IVL_EX_NONE:
|
2007-01-16 06:44:14 +01:00
|
|
|
case IVL_EX_ARRAY:
|
2003-02-28 21:21:13 +01:00
|
|
|
case IVL_EX_NUMBER:
|
|
|
|
|
case IVL_EX_STRING:
|
2003-04-22 06:48:29 +02:00
|
|
|
case IVL_EX_EVENT:
|
2003-02-28 21:21:13 +01:00
|
|
|
case IVL_EX_SCOPE:
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-03-07 03:43:32 +01:00
|
|
|
case IVL_EX_SFUNC:
|
|
|
|
|
if (is_magic_sfunc(ivl_expr_name(expr)))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
case IVL_EX_SIGNAL:
|
|
|
|
|
/* If the signal node is narrower then the signal
|
|
|
|
|
itself, then this is a part select so I'm going
|
|
|
|
|
to need to evaluate the expression.
|
|
|
|
|
|
2003-04-13 01:25:20 +02:00
|
|
|
Also, if the signedness of the expression is
|
|
|
|
|
different from the signedness of the
|
|
|
|
|
signal. This could be caused by a $signed or
|
|
|
|
|
$unsigned system function.
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
If I don't need to do any evaluating, then skip
|
|
|
|
|
it as I'll be passing the handle to the signal
|
|
|
|
|
itself. */
|
|
|
|
|
if (ivl_expr_width(expr) !=
|
2005-06-18 17:55:21 +02:00
|
|
|
ivl_signal_width(ivl_expr_signal(expr))) {
|
2003-02-28 21:21:13 +01:00
|
|
|
break;
|
2003-04-13 01:25:20 +02:00
|
|
|
|
|
|
|
|
} else if (ivl_expr_signed(expr) !=
|
|
|
|
|
ivl_signal_signed(ivl_expr_signal(expr))) {
|
|
|
|
|
break;
|
2007-01-30 06:28:23 +01:00
|
|
|
} else if (! is_fixed_memory_word(expr)){
|
2007-01-16 06:44:14 +01:00
|
|
|
break;
|
2003-02-28 21:21:13 +01:00
|
|
|
} else {
|
2007-11-06 19:07:56 +01:00
|
|
|
/* Some array selects need to be evaluated. */
|
|
|
|
|
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
|
|
|
|
if (word_ex && !number_is_immediate(word_ex,
|
|
|
|
|
8*sizeof(unsigned))) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-02-28 21:21:13 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2005-06-18 17:55:21 +02:00
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
case IVL_EX_MEMORY:
|
|
|
|
|
if (!ivl_expr_oper1(expr)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Everything else will need to be evaluated and
|
|
|
|
|
passed as a constant to the vpi task. */
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vec = (struct vector_info *)
|
|
|
|
|
realloc(vec, (vecs+1)*sizeof(struct vector_info));
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_value(expr)) {
|
2007-02-14 06:59:24 +01:00
|
|
|
case IVL_VT_LOGIC:
|
|
|
|
|
case IVL_VT_BOOL:
|
2003-02-28 21:21:13 +01:00
|
|
|
vec[vecs] = draw_eval_expr(expr, 0);
|
|
|
|
|
break;
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
vec[vecs].base = draw_eval_real(expr);
|
|
|
|
|
vec[vecs].wid = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
vecs++;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-15 05:45:18 +01:00
|
|
|
fprintf(vvp_out, "%s", call_string);
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
for (idx = 0 ; idx < parm_count ; idx += 1) {
|
|
|
|
|
ivl_expr_t expr = tnet
|
|
|
|
|
? ivl_stmt_parm(tnet, idx)
|
|
|
|
|
: ivl_expr_parm(fnet, idx);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
switch (ivl_expr_type(expr)) {
|
|
|
|
|
case IVL_EX_NONE:
|
|
|
|
|
fprintf(vvp_out, ", \" \"");
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
case IVL_EX_ARRAY:
|
|
|
|
|
fprintf(vvp_out, ", v%p", ivl_expr_signal(expr));
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
case IVL_EX_NUMBER: {
|
|
|
|
|
unsigned bit, wid = ivl_expr_width(expr);
|
|
|
|
|
const char*bits = ivl_expr_bits(expr);
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, ", %u'%sb", wid,
|
|
|
|
|
ivl_expr_signed(expr)? "s" : "");
|
|
|
|
|
for (bit = wid ; bit > 0 ; bit -= 1)
|
|
|
|
|
fputc(bits[bit-1], vvp_out);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SIGNAL:
|
|
|
|
|
/* If this is a part select, then the value was
|
|
|
|
|
calculated above. Otherwise, just pass the
|
|
|
|
|
signal. */
|
|
|
|
|
if (ivl_expr_width(expr) !=
|
2005-06-18 17:55:21 +02:00
|
|
|
ivl_signal_width(ivl_expr_signal(expr))) {
|
2003-02-28 21:21:13 +01:00
|
|
|
break;
|
2003-04-13 01:25:20 +02:00
|
|
|
|
|
|
|
|
} else if (ivl_expr_signed(expr) !=
|
|
|
|
|
ivl_signal_signed(ivl_expr_signal(expr))) {
|
|
|
|
|
break;
|
|
|
|
|
|
2007-01-30 06:28:23 +01:00
|
|
|
} else if (! is_fixed_memory_word(expr)){
|
2007-01-16 06:44:14 +01:00
|
|
|
break;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
} else {
|
2007-01-16 06:44:14 +01:00
|
|
|
ivl_signal_t sig = ivl_expr_signal(expr);
|
2007-01-30 06:28:23 +01:00
|
|
|
unsigned use_word = 0;
|
|
|
|
|
ivl_expr_t word_ex = ivl_expr_oper1(expr);
|
|
|
|
|
if (word_ex) {
|
2007-11-06 19:07:56 +01:00
|
|
|
/* Some array select have been evaluated. */
|
|
|
|
|
if (!number_is_immediate(word_ex,
|
|
|
|
|
8*sizeof(unsigned))) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2007-01-30 06:28:23 +01:00
|
|
|
use_word = get_number_immediate(word_ex);
|
|
|
|
|
}
|
|
|
|
|
fprintf(vvp_out, ", v%p_%u", sig, use_word);
|
2003-02-28 21:21:13 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2007-01-16 06:44:14 +01:00
|
|
|
assert(0);
|
2004-12-11 03:31:25 +01:00
|
|
|
continue;
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
case IVL_EX_STRING:
|
2003-03-11 00:40:53 +01:00
|
|
|
if (( par = ivl_expr_parameter(expr) )) {
|
|
|
|
|
fprintf(vvp_out, ", P_%p", par);
|
|
|
|
|
|
|
|
|
|
} else {
|
2004-10-04 03:10:51 +02:00
|
|
|
fprintf(vvp_out, ", \"%s\"",
|
2003-03-11 00:40:53 +01:00
|
|
|
ivl_expr_string(expr));
|
|
|
|
|
}
|
2003-02-28 21:21:13 +01:00
|
|
|
continue;
|
|
|
|
|
|
2003-04-22 06:48:29 +02:00
|
|
|
case IVL_EX_EVENT:
|
|
|
|
|
fprintf(vvp_out, ", E_%p", ivl_expr_event(expr));
|
|
|
|
|
continue;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
case IVL_EX_SCOPE:
|
2003-03-25 03:15:48 +01:00
|
|
|
fprintf(vvp_out, ", S_%p", ivl_expr_scope(expr));
|
2003-02-28 21:21:13 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case IVL_EX_SFUNC:
|
2003-03-07 03:43:32 +01:00
|
|
|
if (is_magic_sfunc(ivl_expr_name(expr))) {
|
|
|
|
|
fprintf(vvp_out, ", %s", ivl_expr_name(expr));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
assert(veci < vecs);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_value(expr)) {
|
|
|
|
|
|
2007-02-14 06:59:24 +01:00
|
|
|
case IVL_VT_LOGIC:
|
|
|
|
|
case IVL_VT_BOOL:
|
2003-02-28 21:21:13 +01:00
|
|
|
fprintf(vvp_out, ", T<%u,%u,%s>", vec[veci].base,
|
|
|
|
|
vec[veci].wid, ivl_expr_signed(expr)? "s" : "u");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case IVL_VT_REAL:
|
|
|
|
|
fprintf(vvp_out, ", W<%u,r>", vec[veci].base);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
veci++;
|
|
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
assert(veci == vecs);
|
|
|
|
|
|
|
|
|
|
if (vecs) {
|
|
|
|
|
for (idx = 0; idx < vecs; idx++) {
|
|
|
|
|
if (vec[idx].wid > 0)
|
|
|
|
|
clr_vector(vec[idx]);
|
2003-04-23 04:22:47 +02:00
|
|
|
else if (vec[idx].wid == 0)
|
|
|
|
|
clr_word(vec[idx].base);
|
2003-02-28 21:21:13 +01:00
|
|
|
}
|
|
|
|
|
free(vec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(vvp_out, ";\n");
|
2003-03-15 05:45:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void draw_vpi_task_call(ivl_statement_t tnet)
|
|
|
|
|
{
|
|
|
|
|
char call_string[1024];
|
2008-01-01 18:45:02 +01:00
|
|
|
sprintf(call_string, " %%vpi_call %u %u \"%s\"",
|
2008-01-02 19:42:23 +01:00
|
|
|
ivl_file_table_index(ivl_stmt_file(tnet)),
|
2008-01-01 18:45:02 +01:00
|
|
|
ivl_stmt_lineno(tnet), ivl_stmt_name(tnet));
|
2003-03-15 05:45:18 +01:00
|
|
|
draw_vpi_taskfunc_args(call_string, tnet, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct vector_info draw_vpi_func_call(ivl_expr_t fnet, unsigned wid)
|
|
|
|
|
{
|
|
|
|
|
char call_string[1024];
|
|
|
|
|
struct vector_info res;
|
|
|
|
|
|
|
|
|
|
res.base = allocate_vector(wid);
|
|
|
|
|
res.wid = wid;
|
2008-01-01 18:45:02 +01:00
|
|
|
sprintf(call_string, " %%vpi_func %u %u \"%s\", %u, %u",
|
2008-01-02 19:42:23 +01:00
|
|
|
ivl_file_table_index(ivl_expr_file(fnet)),
|
2008-01-01 18:45:02 +01:00
|
|
|
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res.base, res.wid);
|
2003-03-15 05:45:18 +01:00
|
|
|
|
|
|
|
|
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int draw_vpi_rfunc_call(ivl_expr_t fnet)
|
|
|
|
|
{
|
|
|
|
|
char call_string[1024];
|
|
|
|
|
int res = allocate_word();
|
|
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
sprintf(call_string, " %%vpi_func/r %u %u \"%s\", %d",
|
2008-01-02 19:42:23 +01:00
|
|
|
ivl_file_table_index(ivl_expr_file(fnet)),
|
2008-01-01 18:45:02 +01:00
|
|
|
ivl_expr_lineno(fnet), ivl_expr_name(fnet), res);
|
2003-03-15 05:45:18 +01:00
|
|
|
|
|
|
|
|
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|