2003-02-28 21:21:13 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2003 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
|
|
|
|
|
*/
|
|
|
|
|
#ifdef HAVE_CVS_IDENT
|
2005-07-11 18:56:50 +02:00
|
|
|
#ident "$Id: draw_vpi.c,v 1.12 2005/07/11 16:56:51 steve Exp $"
|
2003-02-28 21:21:13 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
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;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
} else {
|
|
|
|
|
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)) {
|
|
|
|
|
case IVL_VT_VECTOR:
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2003-02-28 21:21:13 +01:00
|
|
|
} else {
|
2004-10-04 03:10:51 +02:00
|
|
|
fprintf(vvp_out, ", V_%s",
|
2003-02-28 21:21:13 +01:00
|
|
|
vvp_signal_label(ivl_expr_signal(expr)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2004-12-11 03:31:25 +01:00
|
|
|
fprintf(vvp_out, ", V_%s",
|
|
|
|
|
vvp_signal_label(ivl_expr_signal(expr)));
|
|
|
|
|
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
|
|
|
case IVL_EX_MEMORY:
|
|
|
|
|
if (!ivl_expr_oper1(expr)) {
|
2004-10-04 03:10:51 +02:00
|
|
|
fprintf(vvp_out, ", M_%s",
|
2003-02-28 21:21:13 +01:00
|
|
|
vvp_memory_label(ivl_expr_memory(expr)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
assert(veci < vecs);
|
|
|
|
|
|
|
|
|
|
switch (ivl_expr_value(expr)) {
|
|
|
|
|
|
|
|
|
|
case IVL_VT_VECTOR:
|
|
|
|
|
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];
|
|
|
|
|
sprintf(call_string, " %%vpi_call \"%s\"", ivl_stmt_name(tnet));
|
|
|
|
|
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;
|
|
|
|
|
sprintf(call_string, " %%vpi_func \"%s\", %u, %u",
|
|
|
|
|
ivl_expr_name(fnet), res.base, res.wid);
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
sprintf(call_string, " %%vpi_func/r \"%s\", %d",
|
|
|
|
|
ivl_expr_name(fnet), res);
|
|
|
|
|
|
|
|
|
|
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
2003-02-28 21:21:13 +01:00
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: draw_vpi.c,v $
|
2005-07-11 18:56:50 +02:00
|
|
|
* Revision 1.12 2005/07/11 16:56:51 steve
|
|
|
|
|
* Remove NetVariable and ivl_variable_t structures.
|
|
|
|
|
*
|
2005-06-18 17:55:21 +02:00
|
|
|
* Revision 1.11 2005/06/18 15:55:21 steve
|
|
|
|
|
* Handle signed display of unsigned signals.
|
|
|
|
|
*
|
2004-12-11 03:31:25 +01:00
|
|
|
* Revision 1.10 2004/12/11 02:31:28 steve
|
|
|
|
|
* Rework of internals to carry vectors through nexus instead
|
|
|
|
|
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
|
|
|
|
* down this path.
|
|
|
|
|
*
|
2004-10-04 03:10:51 +02:00
|
|
|
* Revision 1.9 2004/10/04 01:10:57 steve
|
|
|
|
|
* Clean up spurious trailing white space.
|
|
|
|
|
*
|
2003-04-23 04:22:47 +02:00
|
|
|
* Revision 1.8 2003/04/23 02:22:47 steve
|
|
|
|
|
* Fix word register leak.
|
|
|
|
|
*
|
2003-04-22 06:48:29 +02:00
|
|
|
* Revision 1.7 2003/04/22 04:48:30 steve
|
|
|
|
|
* Support event names as expressions elements.
|
|
|
|
|
*
|
2003-04-13 01:25:20 +02:00
|
|
|
* Revision 1.6 2003/04/12 23:25:20 steve
|
|
|
|
|
* Properly pass $signed(signal) to tasks.
|
|
|
|
|
*
|
2003-03-25 03:15:48 +01:00
|
|
|
* Revision 1.5 2003/03/25 02:15:48 steve
|
|
|
|
|
* Use hash code for scope labels.
|
|
|
|
|
*
|
2003-03-15 05:45:18 +01:00
|
|
|
* Revision 1.4 2003/03/15 04:45:18 steve
|
|
|
|
|
* Allow real-valued vpi functions to have arguments.
|
|
|
|
|
*
|
2003-03-11 00:40:53 +01:00
|
|
|
* Revision 1.3 2003/03/10 23:40:54 steve
|
|
|
|
|
* Keep parameter constants for the ivl_target API.
|
|
|
|
|
*
|
2003-03-07 03:43:32 +01:00
|
|
|
* Revision 1.2 2003/03/07 02:43:32 steve
|
|
|
|
|
* Handle general $function arguments as expresions.
|
|
|
|
|
*
|
2003-02-28 21:21:13 +01:00
|
|
|
* Revision 1.1 2003/02/28 20:21:13 steve
|
|
|
|
|
* Merge vpi_call and vpi_func draw functions.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|