2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2011-09-06 01:10:08 +02:00
|
|
|
* Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com)
|
2001-03-20 07:16:23 +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
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* vpiReg handles are handled here. These objects represent vectors of
|
|
|
|
|
* .var objects that can be manipulated by the VPI module.
|
|
|
|
|
*/
|
|
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
# include "compile.h"
|
2001-03-20 07:16:23 +01:00
|
|
|
# include "vpi_priv.h"
|
2009-04-16 04:08:37 +02:00
|
|
|
# include "vvp_net_sig.h"
|
2003-05-02 06:29:57 +02:00
|
|
|
# include "schedule.h"
|
2002-07-05 04:50:57 +02:00
|
|
|
# include "statistics.h"
|
2009-01-30 02:23:09 +01:00
|
|
|
# include "config.h"
|
|
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
# include "vvp_cleanup.h"
|
|
|
|
|
#endif
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cmath>
|
2005-04-13 08:34:20 +02:00
|
|
|
# include <iostream>
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cstdio>
|
|
|
|
|
# include <cstdlib>
|
|
|
|
|
# include <climits>
|
|
|
|
|
# include <cstring>
|
|
|
|
|
# include <cassert>
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
# include <valgrind/memcheck.h>
|
|
|
|
|
#endif
|
2010-10-24 00:52:56 +02:00
|
|
|
# include "ivl_alloc.h"
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2001-03-25 22:45:09 +02:00
|
|
|
/*
|
|
|
|
|
* Hex digits that represent 4-value bits of Verilog are not as
|
|
|
|
|
* trivially obvious to display as if the bits were the usual 2-value
|
|
|
|
|
* bits. So, although it is possible to write a function that
|
|
|
|
|
* generates a correct character for 4*4-value bits, it is easier to
|
|
|
|
|
* just perform the lookup in a table. This only takes 256 bytes,
|
|
|
|
|
* which is not many executable instructions:-)
|
|
|
|
|
*
|
2007-12-19 00:11:50 +01:00
|
|
|
* The table is calculated at compile time, therefore, by the
|
2001-03-25 22:45:09 +02:00
|
|
|
* draw_tt.c program.
|
|
|
|
|
*/
|
2001-03-25 21:38:05 +02:00
|
|
|
extern const char hex_digits[256];
|
2008-05-27 23:29:08 +02:00
|
|
|
extern const char oct_digits[64];
|
2001-03-25 22:45:09 +02:00
|
|
|
|
2001-12-18 06:31:54 +01:00
|
|
|
/*
|
|
|
|
|
* The string values need a result buf to hold the results. This
|
|
|
|
|
* buffer can be reused for that purpose. Whenever I have a need, the
|
|
|
|
|
* need_result_buf function makes sure that need can be met.
|
|
|
|
|
*/
|
2002-07-09 05:24:37 +02:00
|
|
|
char *need_result_buf(unsigned cnt, vpi_rbuf_t type)
|
2001-12-18 06:31:54 +01:00
|
|
|
{
|
2002-07-04 01:39:57 +02:00
|
|
|
static char*result_buf[2] = {0, 0};
|
|
|
|
|
static size_t result_buf_size[2] = {0, 0};
|
|
|
|
|
|
2009-01-24 01:04:44 +01:00
|
|
|
if (type == RBUF_DEL) {
|
|
|
|
|
free(result_buf[RBUF_VAL]);
|
|
|
|
|
result_buf[RBUF_VAL] = 0;
|
|
|
|
|
result_buf_size[RBUF_VAL] = 0;
|
|
|
|
|
|
|
|
|
|
free(result_buf[RBUF_STR]);
|
|
|
|
|
result_buf[RBUF_STR] = 0;
|
|
|
|
|
result_buf_size[RBUF_STR] = 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cnt = (cnt + 0x0fff) & ~0x0fff;
|
|
|
|
|
|
2002-07-09 05:24:37 +02:00
|
|
|
if (result_buf_size[type] == 0) {
|
|
|
|
|
result_buf[type] = (char*)malloc(cnt);
|
2002-09-10 04:27:11 +02:00
|
|
|
result_buf_size[type] = cnt;
|
2002-07-09 05:24:37 +02:00
|
|
|
} else if (result_buf_size[type] < cnt) {
|
|
|
|
|
result_buf[type] = (char*)realloc(result_buf[type], cnt);
|
2002-09-10 04:27:11 +02:00
|
|
|
result_buf_size[type] = cnt;
|
2001-12-18 06:31:54 +01:00
|
|
|
}
|
2002-07-03 04:09:38 +02:00
|
|
|
|
2002-07-09 05:24:37 +02:00
|
|
|
return result_buf[type];
|
2001-12-18 06:31:54 +01:00
|
|
|
}
|
|
|
|
|
|
2007-12-19 00:11:50 +01:00
|
|
|
char *simple_set_rbuf_str(const char *s1)
|
|
|
|
|
{
|
2010-01-23 04:44:56 +01:00
|
|
|
char *res = need_result_buf(strlen(s1)+1, RBUF_STR);
|
|
|
|
|
if (res) strcpy(res,s1);
|
|
|
|
|
return res;
|
2007-12-19 00:11:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *generic_get_str(int code, vpiHandle ref, const char *name, const char *index)
|
|
|
|
|
{
|
2010-01-23 04:44:56 +01:00
|
|
|
size_t len = strlen(name) + 1; /* include space for null termination */
|
|
|
|
|
char *bn = NULL;
|
|
|
|
|
if (code == vpiFullName) {
|
|
|
|
|
bn = strdup(vpi_get_str(code,ref));
|
|
|
|
|
len += strlen(bn) + 1; /* include space for "." separator */
|
|
|
|
|
}
|
|
|
|
|
if (index != NULL) len += strlen(index) + 2; /* include space for brackets */
|
|
|
|
|
|
|
|
|
|
char *res = need_result_buf(len, RBUF_STR);
|
|
|
|
|
if (!res) {
|
|
|
|
|
free(bn);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
*res=0; /* start with nothing */
|
2007-12-19 00:11:50 +01:00
|
|
|
|
|
|
|
|
/* if this works, I can make it more efficient later */
|
2010-01-23 04:44:56 +01:00
|
|
|
if (bn != NULL) {
|
|
|
|
|
strcat(res, bn);
|
|
|
|
|
strcat(res, ".");
|
|
|
|
|
free(bn);
|
|
|
|
|
}
|
|
|
|
|
strcat(res, name);
|
|
|
|
|
if (index != NULL) {
|
|
|
|
|
strcat(res, "[");
|
|
|
|
|
strcat(res, index);
|
|
|
|
|
strcat(res, "]");
|
|
|
|
|
}
|
|
|
|
|
return res;
|
2007-12-19 00:11:50 +01:00
|
|
|
}
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
/*
|
|
|
|
|
* The standard formating/conversion routines.
|
|
|
|
|
* They work with full or partial signals.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiBinStrVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
char *rbuf = need_result_buf(wid+1, RBUF_VAL);
|
|
|
|
|
long end = base + (signed)wid;
|
2009-09-11 00:32:09 +02:00
|
|
|
long offset = end - 1;
|
2009-07-28 06:42:04 +02:00
|
|
|
long ssize = (signed)sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
|
|
|
|
if (idx < 0 || idx >= ssize) {
|
|
|
|
|
rbuf[offset-idx] = 'x';
|
|
|
|
|
} else {
|
|
|
|
|
rbuf[offset-idx] = vvp_bit4_to_ascii(sig->value(idx));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rbuf[wid] = 0;
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiOctStrVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned dwid = (wid + 2) / 3;
|
|
|
|
|
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
|
|
|
|
|
long end = base + (signed)wid;
|
2009-07-28 06:42:04 +02:00
|
|
|
long ssize = (signed)sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
unsigned val = 0;
|
|
|
|
|
|
|
|
|
|
rbuf[dwid] = 0;
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
|
|
|
|
unsigned bit = 0;
|
|
|
|
|
if (idx < 0 || idx >= ssize) {
|
|
|
|
|
bit = 2; // BIT4_X
|
|
|
|
|
} else {
|
|
|
|
|
switch (sig->value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
bit = 0;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
bit = 1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
bit = 2;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
bit = 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
val |= bit << 2*((idx-base) % 3);
|
|
|
|
|
|
|
|
|
|
if ((idx-base) % 3 == 2) {
|
|
|
|
|
dwid -= 1;
|
|
|
|
|
rbuf[dwid] = oct_digits[val];
|
|
|
|
|
val = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fill in X or Z if they are the only thing in the value. */
|
|
|
|
|
switch (wid % 3) {
|
|
|
|
|
case 1:
|
|
|
|
|
if (val == 2) val = 42;
|
|
|
|
|
else if (val == 3) val = 63;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (val == 10) val = 42;
|
|
|
|
|
else if (val == 15) val = 63;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dwid > 0) rbuf[0] = oct_digits[val];
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiHexStrVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned dwid = (wid + 3) / 4;
|
|
|
|
|
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
|
|
|
|
|
long end = base + (signed)wid;
|
2009-07-28 06:42:04 +02:00
|
|
|
long ssize = (signed)sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
unsigned val = 0;
|
|
|
|
|
|
|
|
|
|
rbuf[dwid] = 0;
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
|
|
|
|
unsigned bit = 0;
|
|
|
|
|
if (idx < 0 || idx >= ssize) {
|
|
|
|
|
bit = 2; // BIT4_X
|
|
|
|
|
} else {
|
|
|
|
|
switch (sig->value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
bit = 0;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
bit = 1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
bit = 2;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
bit = 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
val |= bit << 2*((idx-base) % 4);
|
|
|
|
|
|
|
|
|
|
if ((idx-base) % 4 == 3) {
|
|
|
|
|
dwid -= 1;
|
|
|
|
|
rbuf[dwid] = hex_digits[val];
|
|
|
|
|
val = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fill in X or Z if they are the only thing in the value. */
|
|
|
|
|
switch (wid % 4) {
|
|
|
|
|
case 1:
|
|
|
|
|
if (val == 2) val = 170;
|
|
|
|
|
else if (val == 3) val = 255;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
if (val == 10) val = 170;
|
|
|
|
|
else if (val == 15) val = 255;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
if (val == 42) val = 170;
|
|
|
|
|
else if (val == 63) val = 255;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dwid > 0) rbuf[0] = hex_digits[val];
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiDecStrVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
int signed_flag, s_vpi_value*vp)
|
|
|
|
|
{
|
2009-07-28 06:42:04 +02:00
|
|
|
unsigned hwid = (sig->value_size()+2) / 3 + 1;
|
2008-05-27 23:29:08 +02:00
|
|
|
char *rbuf = need_result_buf(hwid, RBUF_VAL);
|
2009-07-28 06:42:04 +02:00
|
|
|
long ssize = (signed)sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
|
|
|
|
|
/* Do we have an end outside of the real signal vector. */
|
|
|
|
|
if (base < 0 || end > ssize) {
|
|
|
|
|
bool all_x = true;
|
|
|
|
|
if (end > ssize) end = ssize;
|
|
|
|
|
if (base < 0) base = 0;
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
|
|
|
|
if (sig->value(idx) != BIT4_X) {
|
|
|
|
|
all_x = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (all_x) {
|
|
|
|
|
rbuf[0] = 'x';
|
|
|
|
|
} else {
|
|
|
|
|
rbuf[0] = 'X';
|
|
|
|
|
}
|
|
|
|
|
rbuf[1] = 0;
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t vec4;
|
|
|
|
|
if (base == 0 && end == ssize) {
|
2009-11-21 02:54:48 +01:00
|
|
|
sig->vec4_value(vec4);
|
2008-05-27 23:29:08 +02:00
|
|
|
} else {
|
2009-11-21 02:54:48 +01:00
|
|
|
vvp_vector4_t tmp;
|
|
|
|
|
sig->vec4_value(tmp);
|
|
|
|
|
vec4 = tmp.subvalue(base, wid);
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpip_vec4_to_dec_str(vec4, rbuf, hwid, signed_flag);
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiIntVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-06-14 04:47:48 +02:00
|
|
|
int signed_flag, s_vpi_value*vp)
|
2008-05-27 23:29:08 +02:00
|
|
|
{
|
2009-11-21 02:54:48 +01:00
|
|
|
vvp_vector4_t tmp;
|
|
|
|
|
sig->vec4_value(tmp);
|
|
|
|
|
vvp_vector4_t sub = tmp.subvalue(base, wid);
|
2008-06-14 04:47:48 +02:00
|
|
|
long val = 0;
|
2008-06-26 00:42:57 +02:00
|
|
|
vector4_to_value(sub, val, signed_flag, false);
|
2008-06-14 04:47:48 +02:00
|
|
|
vp->value.integer = val;
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiRealVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
int signed_flag, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector4_t vec4(wid);
|
2009-07-28 06:42:04 +02:00
|
|
|
long ssize = (signed)sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
if (end > ssize) end = ssize;
|
|
|
|
|
|
|
|
|
|
for (long idx = (base < 0) ? 0 : base ; idx < end ; idx += 1) {
|
|
|
|
|
vec4.set_bit(idx-base, sig->value(idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vp->value.real = 0.0;
|
|
|
|
|
vector4_to_value(vec4, vp->value.real, signed_flag);
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiStringVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
/* The result will use a character for each 8 bits of the
|
|
|
|
|
vector. Add one extra character for the highest bits that
|
|
|
|
|
don't form an 8 bit group. */
|
|
|
|
|
char *rbuf = need_result_buf(wid/8 + ((wid&7)!=0) + 1, RBUF_VAL);
|
|
|
|
|
char *cp = rbuf;
|
|
|
|
|
|
|
|
|
|
char tmp = 0;
|
|
|
|
|
for (long idx = base+(signed)wid-1; idx >= base; idx -= 1) {
|
|
|
|
|
tmp <<= 1;
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
if (idx >=0 && idx < (signed)sig->value_size() &&
|
2008-05-27 23:29:08 +02:00
|
|
|
sig->value(idx) == BIT4_1) {
|
|
|
|
|
tmp |= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (((idx-base)&7)==0){
|
|
|
|
|
/* Skip leading nulls. */
|
|
|
|
|
if (tmp == 0 && cp == rbuf)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Nulls in the middle get turned into spaces. */
|
|
|
|
|
*cp++ = tmp ? tmp : ' ';
|
|
|
|
|
tmp = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*cp++ = 0;
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiScalarVal(vvp_signal_value*sig, int base,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
2009-07-28 06:42:04 +02:00
|
|
|
if (base >= 0 && base < (signed)sig->value_size()) {
|
2008-05-27 23:29:08 +02:00
|
|
|
switch (sig->value(base)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
vp->value.scalar = vpi0;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
vp->value.scalar = vpi1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X: {
|
|
|
|
|
vvp_scalar_t strn = sig->scalar_value(base);
|
|
|
|
|
if (strn.strength0() == 1) vp->value.scalar = vpiH;
|
|
|
|
|
else if (strn.strength1() == 1) vp->value.scalar = vpiL;
|
|
|
|
|
else vp->value.scalar = vpiX;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
vp->value.scalar = vpiZ;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
vp->value.scalar = vpiX;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiStrengthVal(vvp_signal_value*sig, int base,
|
2008-05-27 23:29:08 +02:00
|
|
|
unsigned wid, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
s_vpi_strengthval*op;
|
|
|
|
|
|
|
|
|
|
op = (s_vpi_strengthval*)
|
|
|
|
|
need_result_buf(wid * sizeof(s_vpi_strengthval), RBUF_VAL);
|
|
|
|
|
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
2009-07-28 06:42:04 +02:00
|
|
|
if (idx >=0 && idx < (signed)sig->value_size()) {
|
2008-05-27 23:29:08 +02:00
|
|
|
vvp_scalar_t val = sig->scalar_value(idx);
|
|
|
|
|
|
|
|
|
|
/* vvp_scalar_t strengths are 0-7, but the vpi strength
|
|
|
|
|
is bit0-bit7. This gets the vpi form of the strengths
|
|
|
|
|
from the vvp_scalar_t strengths. */
|
|
|
|
|
unsigned s0 = 1 << val.strength0();
|
|
|
|
|
unsigned s1 = 1 << val.strength1();
|
|
|
|
|
|
|
|
|
|
switch (val.value()) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
op[idx-base].logic = vpi0;
|
|
|
|
|
op[idx-base].s0 = s0|s1;
|
|
|
|
|
op[idx-base].s1 = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
op[idx-base].logic = vpi1;
|
|
|
|
|
op[idx-base].s0 = 0;
|
|
|
|
|
op[idx-base].s1 = s0|s1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
op[idx-base].logic = vpiX;
|
|
|
|
|
op[idx-base].s0 = s0;
|
|
|
|
|
op[idx-base].s1 = s1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
op[idx-base].logic = vpiZ;
|
|
|
|
|
op[idx-base].s0 = vpiHiZ;
|
|
|
|
|
op[idx-base].s1 = vpiHiZ;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
op[idx-base].logic = vpiX;
|
|
|
|
|
op[idx-base].s0 = vpiStrongDrive;
|
|
|
|
|
op[idx-base].s1 = vpiStrongDrive;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vp->value.strength = op;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid,
|
2008-05-27 23:29:08 +02:00
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
unsigned int obit = 0;
|
|
|
|
|
unsigned hwid = (wid - 1)/32 + 1;
|
|
|
|
|
|
|
|
|
|
s_vpi_vecval *op = (p_vpi_vecval)
|
|
|
|
|
need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL);
|
|
|
|
|
vp->value.vector = op;
|
|
|
|
|
|
|
|
|
|
op->aval = op->bval = 0;
|
|
|
|
|
for (long idx = base ; idx < end ; idx += 1) {
|
2009-07-28 06:42:04 +02:00
|
|
|
if (base >= 0 && base < (signed)sig->value_size()) {
|
2008-05-27 23:29:08 +02:00
|
|
|
switch (sig->value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
op->aval &= ~(1 << obit);
|
|
|
|
|
op->bval &= ~(1 << obit);
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
op->aval |= (1 << obit);
|
|
|
|
|
op->bval &= ~(1 << obit);
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
op->aval |= (1 << obit);
|
|
|
|
|
op->bval |= (1 << obit);
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
op->aval &= ~(1 << obit);
|
|
|
|
|
op->bval |= (1 << obit);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else { /* BIT4_X */
|
|
|
|
|
op->aval |= (1 << obit);
|
|
|
|
|
op->bval |= (1 << obit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obit++;
|
|
|
|
|
if (!(obit % 32)) {
|
|
|
|
|
op += 1;
|
|
|
|
|
if ((op - vp->value.vector) < (ptrdiff_t)hwid)
|
|
|
|
|
op->aval = op->bval = 0;
|
|
|
|
|
obit = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-01-16 06:44:14 +01:00
|
|
|
struct __vpiSignal* vpip_signal_from_handle(vpiHandle ref)
|
|
|
|
|
{
|
2010-10-08 03:01:11 +02:00
|
|
|
switch (ref->vpi_type->type_code) {
|
|
|
|
|
case vpiNet:
|
|
|
|
|
case vpiReg:
|
2011-06-28 15:59:02 +02:00
|
|
|
/* This handles both reg and logic */
|
2010-10-08 03:01:11 +02:00
|
|
|
case vpiIntegerVar:
|
|
|
|
|
case vpiByteVar:
|
|
|
|
|
case vpiShortIntVar:
|
|
|
|
|
case vpiIntVar:
|
|
|
|
|
case vpiLongIntVar:
|
2011-06-28 17:43:21 +02:00
|
|
|
case vpiBitVar:
|
2010-10-08 03:01:11 +02:00
|
|
|
return (struct __vpiSignal*)ref;
|
2007-01-16 06:44:14 +01:00
|
|
|
|
2010-10-08 03:01:11 +02:00
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2007-01-16 06:44:14 +01:00
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
/*
|
|
|
|
|
* implement vpi_get for vpiReg objects.
|
|
|
|
|
*/
|
|
|
|
|
static int signal_get(int code, vpiHandle ref)
|
|
|
|
|
{
|
2007-01-16 06:44:14 +01:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
|
|
|
|
assert(rfp);
|
2001-03-20 07:16:23 +01:00
|
|
|
|
|
|
|
|
switch (code) {
|
2008-01-01 18:45:02 +01:00
|
|
|
case vpiLineNo:
|
|
|
|
|
return 0; // Not implemented for now!
|
2001-03-20 07:16:23 +01:00
|
|
|
|
|
|
|
|
case vpiSigned:
|
2001-04-04 19:43:19 +02:00
|
|
|
return rfp->signed_flag != 0;
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2007-12-03 18:44:31 +01:00
|
|
|
case vpiArray:
|
2008-06-15 01:17:25 +02:00
|
|
|
return rfp->is_netarray != 0;
|
2007-12-03 18:44:31 +01:00
|
|
|
|
2008-05-01 00:39:50 +02:00
|
|
|
case vpiIndex: // This only works while we have a single index.
|
2008-06-15 01:17:25 +02:00
|
|
|
if (rfp->is_netarray) {
|
2008-05-01 00:39:50 +02:00
|
|
|
s_vpi_value vp;
|
|
|
|
|
vp.format = vpiIntVal;
|
|
|
|
|
vpi_get_value(rfp->id.index, &vp);
|
|
|
|
|
return vp.value.integer;
|
2008-06-15 01:17:25 +02:00
|
|
|
} else {
|
2011-12-06 04:52:49 +01:00
|
|
|
return vpiUndefined;
|
2008-06-15 01:17:25 +02:00
|
|
|
}
|
2008-05-01 00:39:50 +02:00
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
case vpiSize:
|
|
|
|
|
if (rfp->msb >= rfp->lsb)
|
|
|
|
|
return rfp->msb - rfp->lsb + 1;
|
|
|
|
|
else
|
|
|
|
|
return rfp->lsb - rfp->msb + 1;
|
|
|
|
|
|
2003-06-04 03:56:20 +02:00
|
|
|
case vpiNetType:
|
|
|
|
|
if (ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
return vpiWire;
|
|
|
|
|
else
|
2011-12-06 04:52:49 +01:00
|
|
|
return vpiUndefined;
|
2003-06-04 03:56:20 +02:00
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
case vpiLeftRange:
|
|
|
|
|
return rfp->msb;
|
2003-06-04 03:56:20 +02:00
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
case vpiRightRange:
|
|
|
|
|
return rfp->lsb;
|
|
|
|
|
|
|
|
|
|
case vpiAutomatic:
|
|
|
|
|
return (int) vpip_scope(rfp)->is_automatic;
|
2008-10-28 18:52:39 +01:00
|
|
|
|
2001-09-30 07:18:46 +02:00
|
|
|
case _vpiNexusId:
|
|
|
|
|
if (rfp->msb == rfp->lsb)
|
2005-07-15 01:34:18 +02:00
|
|
|
return (int) (unsigned long) rfp->node;
|
2001-09-30 07:18:46 +02:00
|
|
|
else
|
2011-12-06 04:52:49 +01:00
|
|
|
return vpiUndefined;
|
2001-09-30 07:18:46 +02:00
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
default:
|
2011-12-06 04:52:49 +01:00
|
|
|
fprintf(stderr, "VPI error: unknow signal_get property %d.\n",
|
|
|
|
|
code);
|
|
|
|
|
return vpiUndefined;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char* signal_get_str(int code, vpiHandle ref)
|
|
|
|
|
{
|
2010-10-07 00:02:45 +02:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
|
|
|
|
assert(rfp);
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
if (code == vpiFile) { // Not implemented for now!
|
|
|
|
|
return simple_set_rbuf_str(file_names[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-06 19:14:46 +01:00
|
|
|
if ((code != vpiName) && (code != vpiFullName)) return NULL;
|
2011-12-06 04:52:49 +01:00
|
|
|
|
2011-12-06 19:14:46 +01:00
|
|
|
// HERE: vpiFullName is just vpiName!
|
2007-12-19 00:11:50 +01:00
|
|
|
char *nm, *ixs;
|
2008-06-15 01:17:25 +02:00
|
|
|
if (rfp->is_netarray) {
|
|
|
|
|
nm = strdup(vpi_get_str(vpiName, rfp->within.parent));
|
2007-12-03 20:41:52 +01:00
|
|
|
s_vpi_value vp;
|
|
|
|
|
vp.format = vpiDecStrVal;
|
|
|
|
|
vpi_get_value(rfp->id.index, &vp);
|
2011-12-06 04:52:49 +01:00
|
|
|
ixs = vp.value.str; /* do I need to strdup() this? */
|
2007-12-03 20:41:52 +01:00
|
|
|
} else {
|
|
|
|
|
nm = strdup(rfp->id.name);
|
2007-12-19 00:11:50 +01:00
|
|
|
ixs = NULL;
|
2007-12-03 20:41:52 +01:00
|
|
|
}
|
2001-06-29 02:44:56 +02:00
|
|
|
|
2008-06-15 01:17:25 +02:00
|
|
|
char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs);
|
2007-12-03 20:41:52 +01:00
|
|
|
free(nm);
|
2007-12-19 00:11:50 +01:00
|
|
|
return rbuf;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
|
2001-10-15 03:49:50 +02:00
|
|
|
static vpiHandle signal_get_handle(int code, vpiHandle ref)
|
|
|
|
|
{
|
2008-06-15 01:17:25 +02:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
2010-10-07 00:02:45 +02:00
|
|
|
assert(rfp);
|
2001-10-15 03:49:50 +02:00
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
|
2007-12-03 18:44:31 +01:00
|
|
|
case vpiParent:
|
2008-06-15 01:17:25 +02:00
|
|
|
return rfp->is_netarray? rfp->within.parent : 0;
|
2007-12-03 18:44:31 +01:00
|
|
|
|
|
|
|
|
case vpiIndex:
|
2008-06-15 01:17:25 +02:00
|
|
|
return rfp->is_netarray? rfp->id.index : 0;
|
2007-12-03 18:44:31 +01:00
|
|
|
|
2001-10-15 03:49:50 +02:00
|
|
|
case vpiScope:
|
2008-06-15 01:17:25 +02:00
|
|
|
return &(vpip_scope(rfp)->base);
|
2004-03-09 04:11:02 +01:00
|
|
|
|
|
|
|
|
case vpiModule:
|
2009-01-16 20:09:48 +01:00
|
|
|
return vpip_module(vpip_scope(rfp));
|
2001-10-15 03:49:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-03 18:44:31 +01:00
|
|
|
static vpiHandle signal_iterate(int code, vpiHandle ref)
|
|
|
|
|
{
|
2010-10-07 00:02:45 +02:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
|
|
|
|
assert(rfp);
|
2007-12-03 18:44:31 +01:00
|
|
|
|
|
|
|
|
if (code == vpiIndex) {
|
2008-06-15 01:17:25 +02:00
|
|
|
return rfp->is_netarray? array_index_iterate(code, rfp->id.index) : 0;
|
2007-12-03 18:44:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
static unsigned signal_width(const struct __vpiSignal*rfp)
|
|
|
|
|
{
|
|
|
|
|
unsigned wid = (rfp->msb >= rfp->lsb)
|
|
|
|
|
? (rfp->msb - rfp->lsb + 1)
|
|
|
|
|
: (rfp->lsb - rfp->msb + 1);
|
|
|
|
|
|
|
|
|
|
return wid;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
/*
|
|
|
|
|
* The get_value method reads the values of the functors and returns
|
|
|
|
|
* the vector to the caller. This causes no side-effect, and reads the
|
|
|
|
|
* variables like a %load would.
|
|
|
|
|
*/
|
|
|
|
|
static void signal_get_value(vpiHandle ref, s_vpi_value*vp)
|
|
|
|
|
{
|
2010-10-07 00:02:45 +02:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
|
|
|
|
assert(rfp);
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
unsigned wid = signal_width(rfp);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2009-07-28 06:42:04 +02:00
|
|
|
vvp_signal_value*vsig = dynamic_cast<vvp_signal_value*>(rfp->node->fil);
|
2005-11-25 18:55:26 +01:00
|
|
|
assert(vsig);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
switch (vp->format) {
|
|
|
|
|
|
2001-05-15 17:09:08 +02:00
|
|
|
case vpiIntVal:
|
2008-06-14 04:47:48 +02:00
|
|
|
format_vpiIntVal(vsig, 0, wid, rfp->signed_flag, vp);
|
2001-05-15 17:09:08 +02:00
|
|
|
break;
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
case vpiScalarVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiScalarVal(vsig, 0, vp);
|
2005-03-12 05:27:42 +01:00
|
|
|
break;
|
2003-04-12 20:56:57 +02:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
case vpiStrengthVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiStrengthVal(vsig, 0, wid, vp);
|
2005-03-12 05:27:42 +01:00
|
|
|
break;
|
2003-04-12 20:56:57 +02:00
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
case vpiBinStrVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiBinStrVal(vsig, 0, wid, vp);
|
2001-03-21 06:13:03 +01:00
|
|
|
break;
|
|
|
|
|
|
2009-02-23 19:54:25 +01:00
|
|
|
case vpiHexStrVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiHexStrVal(vsig, 0, wid, vp);
|
|
|
|
|
break;
|
2001-03-25 21:38:05 +02:00
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
case vpiOctStrVal:
|
|
|
|
|
format_vpiOctStrVal(vsig, 0, wid, vp);
|
|
|
|
|
break;
|
2001-03-25 22:45:09 +02:00
|
|
|
|
2001-04-04 19:43:19 +02:00
|
|
|
case vpiDecStrVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiDecStrVal(vsig, 0, wid, rfp->signed_flag, vp);
|
2001-04-04 19:43:19 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-07-24 03:34:56 +02:00
|
|
|
case vpiStringVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiStringVal(vsig, 0, wid, vp);
|
2001-07-24 03:34:56 +02:00
|
|
|
break;
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
case vpiVectorVal:
|
|
|
|
|
format_vpiVectorVal(vsig, 0, wid, vp);
|
|
|
|
|
break;
|
2001-10-18 06:52:31 +02:00
|
|
|
|
2009-02-23 19:54:25 +01:00
|
|
|
case vpiRealVal:
|
2008-05-27 23:29:08 +02:00
|
|
|
format_vpiRealVal(vsig, 0, wid, rfp->signed_flag, vp);
|
|
|
|
|
break;
|
2006-12-09 20:06:53 +01:00
|
|
|
|
2009-10-29 19:53:31 +01:00
|
|
|
case vpiObjTypeVal:
|
|
|
|
|
if (wid == 1) {
|
|
|
|
|
vp->format = vpiScalarVal;
|
|
|
|
|
format_vpiScalarVal(vsig, 0, vp);
|
|
|
|
|
} else {
|
|
|
|
|
vp->format = vpiVectorVal;
|
|
|
|
|
format_vpiVectorVal(vsig, 0, wid, vp);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
default:
|
2002-11-26 00:33:45 +01:00
|
|
|
fprintf(stderr, "vvp internal error: get_value: "
|
2009-12-10 21:53:58 +01:00
|
|
|
"value type %d not implemented."
|
2002-11-26 00:33:45 +01:00
|
|
|
" Signal is %s in scope %s\n",
|
2009-12-10 21:53:58 +01:00
|
|
|
(int)vp->format, vpi_get_str(vpiName, ref),
|
|
|
|
|
vpip_scope(rfp)->name);
|
2001-03-21 06:13:03 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The put_value method writes the value into the vector, and returns
|
|
|
|
|
* the affected ref. This operation works much like the %set or
|
|
|
|
|
* %assign instructions and causes all the side-effects that the
|
2003-02-10 00:33:26 +01:00
|
|
|
* equivalent instruction would cause.
|
2001-03-20 07:16:23 +01:00
|
|
|
*/
|
2001-08-09 21:38:23 +02:00
|
|
|
|
2005-09-21 03:04:59 +02:00
|
|
|
static vvp_vector4_t from_stringval(const char*str, unsigned wid)
|
2002-11-26 00:33:45 +01:00
|
|
|
{
|
|
|
|
|
unsigned idx;
|
|
|
|
|
const char*cp;
|
|
|
|
|
|
|
|
|
|
cp = str + strlen(str);
|
|
|
|
|
idx = 0;
|
|
|
|
|
|
2005-09-21 03:04:59 +02:00
|
|
|
vvp_vector4_t val(wid, BIT4_0);
|
|
|
|
|
|
2002-11-26 00:33:45 +01:00
|
|
|
while ((idx < wid) && (cp > str)) {
|
|
|
|
|
unsigned byte = *--cp;
|
|
|
|
|
int bit;
|
|
|
|
|
|
|
|
|
|
for (bit = 0 ; bit < 8 ; bit += 1) {
|
|
|
|
|
if (byte & 1)
|
2005-09-21 03:04:59 +02:00
|
|
|
val.set_bit(idx, BIT4_1);
|
2002-11-26 00:33:45 +01:00
|
|
|
|
|
|
|
|
byte >>= 1;
|
|
|
|
|
idx += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-21 03:04:59 +02:00
|
|
|
return val;
|
2002-11-26 00:33:45 +01:00
|
|
|
}
|
|
|
|
|
|
2008-03-11 05:54:58 +01:00
|
|
|
static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags)
|
2001-03-20 07:16:23 +01:00
|
|
|
{
|
2001-05-14 02:42:32 +02:00
|
|
|
unsigned wid;
|
2008-03-11 05:54:58 +01:00
|
|
|
struct __vpiSignal*rfp = vpip_signal_from_handle(ref);
|
|
|
|
|
assert(rfp);
|
2005-09-21 03:04:59 +02:00
|
|
|
|
2008-03-11 06:18:41 +01:00
|
|
|
/* If this is a release, then we are not really putting a
|
|
|
|
|
value. Instead, issue a release "command" to the signal
|
|
|
|
|
node to cause it to release a forced value. */
|
|
|
|
|
if (flags == vpiReleaseFlag) {
|
2009-08-21 05:31:11 +02:00
|
|
|
vvp_net_fil_t*sig
|
|
|
|
|
= reinterpret_cast<vvp_net_fil_t*>(rfp->node->fil);
|
2009-05-16 05:49:07 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
vvp_net_ptr_t ptr(rfp->node, 0);
|
2009-09-05 06:37:31 +02:00
|
|
|
sig->release(ptr, false);
|
2008-03-11 06:18:41 +01:00
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
|
2005-09-21 03:04:59 +02:00
|
|
|
/* Make a vvp_vector4_t vector to receive the translated value
|
|
|
|
|
that we are going to poke. This will get populated
|
|
|
|
|
differently depending on the format. */
|
2001-05-14 02:42:32 +02:00
|
|
|
wid = (rfp->msb >= rfp->lsb)
|
2001-04-25 06:45:52 +02:00
|
|
|
? (rfp->msb - rfp->lsb + 1)
|
|
|
|
|
: (rfp->lsb - rfp->msb + 1);
|
|
|
|
|
|
2008-05-17 01:20:22 +02:00
|
|
|
|
|
|
|
|
vvp_vector4_t val = vec4_from_vpi_value(vp, wid);
|
|
|
|
|
|
|
|
|
|
/* If this is a vpiForce, then instead of writing to the
|
|
|
|
|
signal input port, we write to the special "force" port. */
|
|
|
|
|
int dest_port = 0;
|
|
|
|
|
if (flags == vpiForceFlag)
|
|
|
|
|
dest_port = 2;
|
|
|
|
|
|
|
|
|
|
/* This is the destination that I'm going to poke into. Make
|
|
|
|
|
it from the vvp_net_t pointer, and assume a write to
|
|
|
|
|
port-0. This is the port where signals receive input. */
|
|
|
|
|
vvp_net_ptr_t destination (rfp->node, dest_port);
|
|
|
|
|
|
2008-10-28 18:52:39 +01:00
|
|
|
vvp_send_vec4(destination, val, vthread_get_wt_context());
|
2008-05-17 01:20:22 +02:00
|
|
|
|
|
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid)
|
|
|
|
|
{
|
2005-09-21 03:04:59 +02:00
|
|
|
vvp_vector4_t val (wid, BIT4_0);
|
2005-03-03 05:33:10 +01:00
|
|
|
|
2001-04-25 06:45:52 +02:00
|
|
|
switch (vp->format) {
|
|
|
|
|
|
2001-04-26 02:01:33 +02:00
|
|
|
case vpiIntVal: {
|
2005-03-03 05:33:10 +01:00
|
|
|
long vpi_val = vp->value.integer;
|
2001-04-26 02:01:33 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2005-03-03 05:33:10 +01:00
|
|
|
vvp_bit4_t bit = vpi_val&1 ? BIT4_1 : BIT4_0;
|
|
|
|
|
val.set_bit(idx, bit);
|
|
|
|
|
vpi_val >>= 1;
|
2001-04-26 02:01:33 +02:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-19 02:36:36 +02:00
|
|
|
case vpiVectorVal:
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
unsigned long aval = vp->value.vector[idx/32].aval;
|
|
|
|
|
unsigned long bval = vp->value.vector[idx/32].bval;
|
|
|
|
|
aval >>= idx%32;
|
|
|
|
|
bval >>= idx%32;
|
2007-01-16 06:44:14 +01:00
|
|
|
int bitmask = (aval&1) | ((bval<<1)&2);
|
2008-04-23 05:18:14 +02:00
|
|
|
vvp_bit4_t bit = scalar_to_bit4(bitmask);
|
2007-01-16 06:44:14 +01:00
|
|
|
val.set_bit(idx, bit);
|
2002-07-19 02:36:36 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2006-02-21 06:31:54 +01:00
|
|
|
case vpiBinStrVal:
|
Rework $plusarg routines.
This patch addresses a number of issues:
Rewrote the $test$plusargs and $value$plusargs routines to have
better error/warning messages, to support runtime strings, to
correctly load bit based values (truncating, padding, negative
value), added support for the real formats using strtod() and
added "x/X" as an alias for "h/H" to match the other part of
Icarus.
Rewrite the vpip_{bin,oct,hex}_str_to_vec4 routines to ignore
embedded "_" characters. Add support for a negative value and
set the entire value to 'bx if an invalid digit is found. A
warning is printed for this case.
Rewrite vpip_dec_str_to_vec4 to ignore embedded "_" characters,
to support a single "x" or "z" constant and to return 'bx if an
invalid digit is found. A warning is printed for this case.
It simplifies the system task/functions error/warning messages.
It removes the signed flag for the bin and dec string conversions.
This was not being used (was always false) and the new negative
value support makes this obsolete.
Add support for a real variable to handle Bin, Oct, Dec and Hex
strings. They are converted into a vvp_vector4_t which is then
converted to a real value.
Add support for setting a bit based value using a real value.
Removed an unneeded rfp signal in vpip_make_reg()
2008-11-13 22:28:19 +01:00
|
|
|
vpip_bin_str_to_vec4(val, vp->value.str);
|
2006-02-21 06:31:54 +01:00
|
|
|
break;
|
|
|
|
|
case vpiOctStrVal:
|
|
|
|
|
vpip_oct_str_to_vec4(val, vp->value.str);
|
|
|
|
|
break;
|
|
|
|
|
case vpiDecStrVal:
|
Rework $plusarg routines.
This patch addresses a number of issues:
Rewrote the $test$plusargs and $value$plusargs routines to have
better error/warning messages, to support runtime strings, to
correctly load bit based values (truncating, padding, negative
value), added support for the real formats using strtod() and
added "x/X" as an alias for "h/H" to match the other part of
Icarus.
Rewrite the vpip_{bin,oct,hex}_str_to_vec4 routines to ignore
embedded "_" characters. Add support for a negative value and
set the entire value to 'bx if an invalid digit is found. A
warning is printed for this case.
Rewrite vpip_dec_str_to_vec4 to ignore embedded "_" characters,
to support a single "x" or "z" constant and to return 'bx if an
invalid digit is found. A warning is printed for this case.
It simplifies the system task/functions error/warning messages.
It removes the signed flag for the bin and dec string conversions.
This was not being used (was always false) and the new negative
value support makes this obsolete.
Add support for a real variable to handle Bin, Oct, Dec and Hex
strings. They are converted into a vvp_vector4_t which is then
converted to a real value.
Add support for setting a bit based value using a real value.
Removed an unneeded rfp signal in vpip_make_reg()
2008-11-13 22:28:19 +01:00
|
|
|
vpip_dec_str_to_vec4(val, vp->value.str);
|
2006-02-21 06:31:54 +01:00
|
|
|
break;
|
|
|
|
|
case vpiHexStrVal:
|
|
|
|
|
vpip_hex_str_to_vec4(val, vp->value.str);
|
|
|
|
|
break;
|
2008-04-23 05:18:14 +02:00
|
|
|
case vpiScalarVal:
|
|
|
|
|
val.set_bit(0, scalar_to_bit4(vp->value.scalar));
|
|
|
|
|
break;
|
2002-11-26 00:33:45 +01:00
|
|
|
case vpiStringVal:
|
2005-09-21 03:04:59 +02:00
|
|
|
val = from_stringval(vp->value.str, wid);
|
2002-11-26 00:33:45 +01:00
|
|
|
break;
|
Rework $plusarg routines.
This patch addresses a number of issues:
Rewrote the $test$plusargs and $value$plusargs routines to have
better error/warning messages, to support runtime strings, to
correctly load bit based values (truncating, padding, negative
value), added support for the real formats using strtod() and
added "x/X" as an alias for "h/H" to match the other part of
Icarus.
Rewrite the vpip_{bin,oct,hex}_str_to_vec4 routines to ignore
embedded "_" characters. Add support for a negative value and
set the entire value to 'bx if an invalid digit is found. A
warning is printed for this case.
Rewrite vpip_dec_str_to_vec4 to ignore embedded "_" characters,
to support a single "x" or "z" constant and to return 'bx if an
invalid digit is found. A warning is printed for this case.
It simplifies the system task/functions error/warning messages.
It removes the signed flag for the bin and dec string conversions.
This was not being used (was always false) and the new negative
value support makes this obsolete.
Add support for a real variable to handle Bin, Oct, Dec and Hex
strings. They are converted into a vvp_vector4_t which is then
converted to a real value.
Add support for setting a bit based value using a real value.
Removed an unneeded rfp signal in vpip_make_reg()
2008-11-13 22:28:19 +01:00
|
|
|
case vpiRealVal:
|
|
|
|
|
val = vvp_vector4_t(wid, vp->value.real);
|
|
|
|
|
break;
|
2002-11-26 00:33:45 +01:00
|
|
|
|
2001-04-25 06:45:52 +02:00
|
|
|
default:
|
2002-11-26 00:33:45 +01:00
|
|
|
fprintf(stderr, "vvp internal error: put_value: "
|
2009-12-10 21:53:58 +01:00
|
|
|
"value type %d not implemented here.\n",
|
|
|
|
|
(int)vp->format);
|
2001-04-25 06:45:52 +02:00
|
|
|
assert(0);
|
|
|
|
|
|
|
|
|
|
}
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2008-05-17 01:20:22 +02:00
|
|
|
return val;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct __vpirt vpip_reg_rt = {
|
|
|
|
|
vpiReg,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
2001-10-15 03:49:50 +02:00
|
|
|
signal_get_handle,
|
2007-12-03 18:44:31 +01:00
|
|
|
signal_iterate,
|
2010-10-11 06:52:26 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2001-03-20 07:16:23 +01:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2010-10-08 03:01:11 +02:00
|
|
|
static const struct __vpirt vpip_integer_rt = {
|
|
|
|
|
vpiIntegerVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
2010-10-22 22:39:46 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2010-10-08 03:01:11 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2001-03-25 01:35:35 +01:00
|
|
|
static const struct __vpirt vpip_net_rt = {
|
|
|
|
|
vpiNet,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
2001-10-15 03:49:50 +02:00
|
|
|
signal_get_handle,
|
2007-12-03 18:44:31 +01:00
|
|
|
signal_iterate,
|
2010-10-11 06:52:26 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2001-03-25 01:35:35 +01:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2010-10-08 03:01:11 +02:00
|
|
|
static const struct __vpirt vpip_byte_rt = {
|
|
|
|
|
vpiByteVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
2010-10-22 22:39:46 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2010-10-08 03:01:11 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2011-04-03 00:50:49 +02:00
|
|
|
static const struct __vpirt vpip_bitvar_rt = {
|
|
|
|
|
vpiBitVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2010-10-08 03:01:11 +02:00
|
|
|
static const struct __vpirt vpip_shortint_rt = {
|
|
|
|
|
vpiShortIntVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
2010-10-22 22:39:46 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2010-10-08 03:01:11 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct __vpirt vpip_int_rt = {
|
|
|
|
|
vpiIntVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
2010-10-22 22:39:46 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2010-10-08 03:01:11 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct __vpirt vpip_longint_rt = {
|
|
|
|
|
vpiLongIntVar,
|
|
|
|
|
signal_get,
|
|
|
|
|
signal_get_str,
|
|
|
|
|
signal_get_value,
|
|
|
|
|
signal_put_value,
|
|
|
|
|
signal_get_handle,
|
|
|
|
|
signal_iterate,
|
2010-10-22 22:39:46 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2010-10-08 03:01:11 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2007-09-11 00:30:00 +02:00
|
|
|
|
2002-06-21 06:58:55 +02:00
|
|
|
/*
|
2007-08-16 06:05:42 +02:00
|
|
|
* Construct a vpiIntegerVar object. Indicate the type using a flag
|
2002-06-21 06:58:55 +02:00
|
|
|
* to minimize the code modifications. Icarus implements integers
|
|
|
|
|
* as 'reg signed [31:0]'.
|
|
|
|
|
*/
|
2010-10-08 03:01:11 +02:00
|
|
|
vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec)
|
2002-06-21 06:58:55 +02:00
|
|
|
{
|
2010-10-08 03:01:11 +02:00
|
|
|
vpiHandle obj = vpip_make_net4(name, msb,lsb, true, vec);
|
|
|
|
|
obj->vpi_type = &vpip_integer_rt;
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-03 00:50:49 +02:00
|
|
|
/*
|
2011-09-06 01:10:08 +02:00
|
|
|
* Construct the two-state SystemVerilog variables.
|
2011-04-03 00:50:49 +02:00
|
|
|
*/
|
2011-09-06 01:10:08 +02:00
|
|
|
vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag,
|
|
|
|
|
vvp_net_t*vec)
|
2010-10-08 03:01:11 +02:00
|
|
|
{
|
2011-09-06 01:10:08 +02:00
|
|
|
vpiHandle obj = vpip_make_net4(name, msb, lsb, signed_flag, vec);
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2011-09-06 01:10:08 +02:00
|
|
|
// All unsigned 2-state variables are a vpiBitVar. All 2-state
|
|
|
|
|
// variables with a non-zero lsb are also a vpiBitVar.
|
|
|
|
|
if ((! signed_flag) || (lsb != 0) ) {
|
2011-04-03 00:50:49 +02:00
|
|
|
obj->vpi_type = &vpip_bitvar_rt;
|
2011-09-06 01:10:08 +02:00
|
|
|
} else {
|
|
|
|
|
// These could also be bit declarations with matching
|
|
|
|
|
// information, but for now they get the apparent type.
|
|
|
|
|
switch (msb) {
|
|
|
|
|
case 7:
|
|
|
|
|
obj->vpi_type = &vpip_byte_rt;
|
|
|
|
|
break;
|
|
|
|
|
case 15:
|
|
|
|
|
obj->vpi_type = &vpip_shortint_rt;
|
|
|
|
|
break;
|
|
|
|
|
case 31:
|
|
|
|
|
obj->vpi_type = &vpip_int_rt;
|
|
|
|
|
break;
|
|
|
|
|
case 63:
|
|
|
|
|
obj->vpi_type = &vpip_longint_rt;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Every other type of bit vector is a vpiBitVar with
|
|
|
|
|
// array dimensions.
|
|
|
|
|
obj->vpi_type = &vpip_bitvar_rt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-10-08 03:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
2002-06-21 06:58:55 +02:00
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2010-10-08 03:01:11 +02:00
|
|
|
* Construct a vpiReg/vpiLogicVar object. It's like a net, except for the type.
|
2001-03-20 07:16:23 +01:00
|
|
|
*/
|
2010-10-08 03:01:11 +02:00
|
|
|
vpiHandle vpip_make_var4(const char*name, int msb, int lsb,
|
2004-12-11 03:31:25 +01:00
|
|
|
bool signed_flag, vvp_net_t*vec)
|
2001-03-20 07:16:23 +01:00
|
|
|
{
|
2010-10-08 03:01:11 +02:00
|
|
|
vpiHandle obj = vpip_make_net4(name, msb,lsb, signed_flag, vec);
|
2001-07-13 05:02:34 +02:00
|
|
|
obj->vpi_type = &vpip_reg_rt;
|
|
|
|
|
return obj;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
static struct __vpiSignal **signal_pool = 0;
|
|
|
|
|
static unsigned signal_pool_count = 0;
|
2009-10-16 23:18:00 +02:00
|
|
|
static unsigned long signal_count = 0;
|
|
|
|
|
static unsigned long signal_dels = 0;
|
2009-01-30 02:23:09 +01:00
|
|
|
#endif
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2003-02-17 00:40:05 +01:00
|
|
|
static struct __vpiSignal* allocate_vpiSignal(void)
|
|
|
|
|
{
|
|
|
|
|
static struct __vpiSignal*alloc_array = 0;
|
|
|
|
|
static unsigned alloc_index = 0;
|
|
|
|
|
const unsigned alloc_count = 512;
|
|
|
|
|
|
|
|
|
|
if ((alloc_array == 0) || (alloc_index == alloc_count)) {
|
|
|
|
|
alloc_array = (struct __vpiSignal*)
|
|
|
|
|
calloc(alloc_count, sizeof(struct __vpiSignal));
|
|
|
|
|
alloc_index = 0;
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(alloc_array, alloc_count *
|
|
|
|
|
sizeof(struct __vpiSignal));
|
|
|
|
|
VALGRIND_CREATE_MEMPOOL(alloc_array, 0, 1);
|
|
|
|
|
signal_pool_count += 1;
|
|
|
|
|
signal_pool = (__vpiSignal **) realloc(signal_pool,
|
|
|
|
|
signal_pool_count*sizeof(__vpiSignal **));
|
|
|
|
|
signal_pool[signal_pool_count-1] = alloc_array;
|
|
|
|
|
#endif
|
2003-02-17 00:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*cur = alloc_array + alloc_index;
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct __vpiSignal));
|
|
|
|
|
cur->pool = alloc_array;
|
2009-10-16 23:18:00 +02:00
|
|
|
signal_count += 1;
|
2009-01-30 02:23:09 +01:00
|
|
|
#endif
|
2003-02-17 00:40:05 +01:00
|
|
|
alloc_index += 1;
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
void signal_delete(vpiHandle item)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiSignal *obj = (__vpiSignal *) item;
|
2009-09-25 00:11:56 +02:00
|
|
|
assert(obj->node->fil);
|
|
|
|
|
obj->node->fil->clear_all_callbacks();
|
2009-01-30 02:23:09 +01:00
|
|
|
vvp_net_delete(obj->node);
|
2009-10-16 23:18:00 +02:00
|
|
|
signal_dels += 1;
|
2009-01-30 02:23:09 +01:00
|
|
|
VALGRIND_MEMPOOL_FREE(obj->pool, obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void signal_pool_delete()
|
|
|
|
|
{
|
2009-10-16 23:18:00 +02:00
|
|
|
if (RUNNING_ON_VALGRIND && (signal_count != signal_dels)) {
|
|
|
|
|
fflush(NULL);
|
2009-10-20 04:53:46 +02:00
|
|
|
VALGRIND_PRINTF("Error: vvp missed deleting %ld of %lu signal(s).",
|
|
|
|
|
(long) signal_count - signal_dels, signal_count);
|
2009-10-16 23:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
for (unsigned idx = 0; idx < signal_pool_count; idx += 1) {
|
|
|
|
|
VALGRIND_DESTROY_MEMPOOL(signal_pool[idx]);
|
|
|
|
|
free(signal_pool[idx]);
|
|
|
|
|
}
|
2009-10-16 23:18:00 +02:00
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
free(signal_pool);
|
|
|
|
|
signal_pool = 0;
|
|
|
|
|
signal_pool_count = 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2001-03-25 01:35:35 +01:00
|
|
|
/*
|
2001-07-13 05:02:34 +02:00
|
|
|
* Construct a vpiNet object. Give the object specified dimensions,
|
2001-03-25 01:35:35 +01:00
|
|
|
* and point to the specified functor for the lsb.
|
2007-06-30 18:34:02 +02:00
|
|
|
*
|
2007-11-21 01:34:00 +01:00
|
|
|
* The name is the PLI name for the object. If it is an array it is
|
|
|
|
|
* <name>[<index>].
|
2001-03-25 01:35:35 +01:00
|
|
|
*/
|
2010-10-08 03:01:11 +02:00
|
|
|
vpiHandle vpip_make_net4(const char*name, int msb, int lsb,
|
2004-12-11 03:31:25 +01:00
|
|
|
bool signed_flag, vvp_net_t*node)
|
2001-03-25 01:35:35 +01:00
|
|
|
{
|
2003-02-17 00:40:05 +01:00
|
|
|
struct __vpiSignal*obj = allocate_vpiSignal();
|
2001-03-25 01:35:35 +01:00
|
|
|
obj->base.vpi_type = &vpip_net_rt;
|
2007-12-03 20:41:52 +01:00
|
|
|
obj->id.name = name? vpip_name_string(name) : 0;
|
2001-03-25 01:35:35 +01:00
|
|
|
obj->msb = msb;
|
|
|
|
|
obj->lsb = lsb;
|
2001-04-05 03:34:26 +02:00
|
|
|
obj->signed_flag = signed_flag? 1 : 0;
|
2008-06-15 01:17:25 +02:00
|
|
|
obj->is_netarray = 0;
|
2004-12-11 03:31:25 +01:00
|
|
|
obj->node = node;
|
2001-03-25 01:35:35 +01:00
|
|
|
|
2008-06-15 01:17:25 +02:00
|
|
|
// Place this object within a scope. If this object is
|
|
|
|
|
// attached to an array, then this value will be replaced with
|
|
|
|
|
// the handle to the parent.
|
|
|
|
|
obj->within.scope = vpip_peek_current_scope();
|
2001-03-25 01:35:35 +01:00
|
|
|
|
2002-07-05 04:50:57 +02:00
|
|
|
count_vpi_nets += 1;
|
|
|
|
|
|
2001-03-25 01:35:35 +01:00
|
|
|
return &obj->base;
|
|
|
|
|
}
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
static int PV_get_base(struct __vpiPV*rfp)
|
|
|
|
|
{
|
2008-06-14 01:22:18 +02:00
|
|
|
/* We return from the symbol base if it is defined. */
|
|
|
|
|
if (rfp->sbase != 0) {
|
|
|
|
|
s_vpi_value val;
|
2009-09-08 01:41:27 +02:00
|
|
|
/* Check to see if the value is defined. */
|
|
|
|
|
val.format = vpiVectorVal;
|
|
|
|
|
vpi_get_value(rfp->sbase, &val);
|
|
|
|
|
int words = (vpi_get(vpiSize, rfp->sbase)-1)/32 + 1;
|
|
|
|
|
for(int idx = 0; idx < words; idx += 1) {
|
|
|
|
|
/* Return INT_MIN to indicate an X base. */
|
|
|
|
|
if (val.value.vector[idx].bval != 0) return INT_MIN;
|
|
|
|
|
}
|
|
|
|
|
/* The value is defined so get and return it. */
|
2008-06-14 01:22:18 +02:00
|
|
|
val.format = vpiIntVal;
|
|
|
|
|
vpi_get_value(rfp->sbase, &val);
|
|
|
|
|
return val.value.integer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the width is zero then tbase is the constant. */
|
2008-05-27 23:29:08 +02:00
|
|
|
if (rfp->twid == 0) return rfp->tbase;
|
|
|
|
|
|
2009-08-25 18:40:30 +02:00
|
|
|
/* Get the value from thread space. */
|
2008-05-27 23:29:08 +02:00
|
|
|
int tval = 0;
|
2009-09-17 23:28:49 +02:00
|
|
|
for (unsigned idx = 0 ; (idx < rfp->twid) && (idx < 8*sizeof(tval));
|
|
|
|
|
idx += 1) {
|
2008-05-27 23:29:08 +02:00
|
|
|
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread,
|
2008-06-14 01:22:18 +02:00
|
|
|
rfp->tbase + idx);
|
2009-08-25 18:40:30 +02:00
|
|
|
switch (bit) {
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
/* We use INT_MIN to indicate an X base. */
|
|
|
|
|
return INT_MIN;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIT4_1:
|
2008-05-27 23:29:08 +02:00
|
|
|
tval |= 1<<idx;
|
2009-08-25 18:40:30 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break; // Do nothing!
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-17 18:47:57 +02:00
|
|
|
/* Check to see if we need to sign extend the result. */
|
|
|
|
|
if (rfp->is_signed && (rfp->twid < 8*sizeof(tval))) {
|
|
|
|
|
vvp_bit4_t msb = vthread_get_bit(vpip_current_vthread,
|
|
|
|
|
rfp->tbase + rfp->twid - 1);
|
|
|
|
|
if (msb == BIT4_1) {
|
|
|
|
|
tval |= ~((1 << rfp->twid) - 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
return tval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int PV_get(int code, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->type_code == vpiPartSelect);
|
|
|
|
|
struct __vpiPV*rfp = (struct __vpiPV*)ref;
|
|
|
|
|
|
|
|
|
|
int rval = 0;
|
|
|
|
|
switch (code) {
|
|
|
|
|
case vpiLineNo:
|
|
|
|
|
return 0; // Not implemented for now!
|
|
|
|
|
|
|
|
|
|
case vpiSigned:
|
|
|
|
|
return 0; // A part/bit select is always unsigned!
|
|
|
|
|
|
|
|
|
|
case vpiSize:
|
|
|
|
|
return rfp->width;
|
|
|
|
|
|
2009-01-15 19:43:46 +01:00
|
|
|
/* This is like the &A<> in array.cc. */
|
2008-05-27 23:29:08 +02:00
|
|
|
case vpiConstantSelect:
|
2009-01-15 19:43:46 +01:00
|
|
|
return rfp->sbase == 0 && rfp->twid == 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
case vpiLeftRange:
|
2009-01-16 20:09:48 +01:00
|
|
|
rval += rfp->width - 1;
|
2008-05-27 23:29:08 +02:00
|
|
|
case vpiRightRange:
|
|
|
|
|
rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp);
|
|
|
|
|
return rval;
|
|
|
|
|
|
2008-11-09 01:26:55 +01:00
|
|
|
case vpiAutomatic:
|
|
|
|
|
return vpi_get(vpiAutomatic, rfp->parent);
|
|
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
case _vpiFromThr:
|
|
|
|
|
return _vpi_at_PV;
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "PV_get: property %d is unknown\n", code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char* PV_get_str(int code, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->type_code == vpiPartSelect);
|
|
|
|
|
struct __vpiPV*rfp = (struct __vpiPV*)ref;
|
|
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
case vpiFile: // Not implemented for now!
|
|
|
|
|
return simple_set_rbuf_str(file_names[0]);
|
|
|
|
|
|
|
|
|
|
case vpiName:
|
|
|
|
|
case vpiFullName: {
|
|
|
|
|
const char*nm = vpi_get_str(code, rfp->parent);
|
2010-05-14 01:27:10 +02:00
|
|
|
size_t len = 256+strlen(nm);
|
|
|
|
|
char *full = (char *) malloc(len);
|
|
|
|
|
snprintf(full, len, "%s[%d:%d]", nm,
|
|
|
|
|
(int)vpi_get(vpiLeftRange, ref),
|
|
|
|
|
(int)vpi_get(vpiRightRange, ref));
|
|
|
|
|
full[len-1] = 0;
|
|
|
|
|
char *res = simple_set_rbuf_str(full);
|
|
|
|
|
free(full);
|
|
|
|
|
return res;
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
2010-05-14 01:27:10 +02:00
|
|
|
fprintf(stderr, "PV_get_str: property %d is unknown.\n", code);
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void PV_get_value(vpiHandle ref, p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->type_code == vpiPartSelect);
|
|
|
|
|
struct __vpiPV*rfp = (struct __vpiPV*)ref;
|
|
|
|
|
|
2009-08-29 07:08:40 +02:00
|
|
|
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(rfp->net->fil);
|
2008-05-27 23:29:08 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
|
|
|
|
switch (vp->format) {
|
|
|
|
|
|
|
|
|
|
case vpiIntVal:
|
2008-06-14 04:47:48 +02:00
|
|
|
format_vpiIntVal(sig, PV_get_base(rfp), rfp->width, 0, vp);
|
2008-05-27 23:29:08 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiBinStrVal:
|
|
|
|
|
format_vpiBinStrVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiOctStrVal:
|
|
|
|
|
format_vpiOctStrVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiHexStrVal:
|
|
|
|
|
format_vpiHexStrVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiDecStrVal:
|
|
|
|
|
format_vpiDecStrVal(sig, PV_get_base(rfp), rfp->width, 0, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiStringVal:
|
|
|
|
|
format_vpiStringVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiScalarVal:
|
|
|
|
|
format_vpiScalarVal(sig, PV_get_base(rfp), vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiStrengthVal:
|
|
|
|
|
format_vpiStrengthVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiVectorVal:
|
|
|
|
|
format_vpiVectorVal(sig, PV_get_base(rfp), rfp->width, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiRealVal:
|
|
|
|
|
format_vpiRealVal(sig, PV_get_base(rfp), rfp->width, 0, vp);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "vvp internal error: PV_get_value: "
|
2009-12-10 21:53:58 +01:00
|
|
|
"value type %d not implemented. Signal is %s.\n",
|
|
|
|
|
(int)vp->format, vpi_get_str(vpiFullName, rfp->parent));
|
2008-05-27 23:29:08 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->type_code == vpiPartSelect);
|
|
|
|
|
struct __vpiPV*rfp = (struct __vpiPV*)ref;
|
2009-09-14 03:30:13 +02:00
|
|
|
vvp_signal_value*sig = dynamic_cast<vvp_signal_value*>(rfp->net->fil);
|
2008-05-27 23:29:08 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
2009-09-14 03:30:13 +02:00
|
|
|
unsigned sig_size = sig->value_size();
|
2008-05-27 23:29:08 +02:00
|
|
|
unsigned width = rfp->width;
|
|
|
|
|
int base = PV_get_base(rfp);
|
2008-06-10 19:59:35 +02:00
|
|
|
if (base >= (signed) sig_size) return 0;
|
|
|
|
|
if (base + (signed) width < 0) return 0;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t val = vec4_from_vpi_value(vp, width);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the base is less than zero then trim off any unneeded
|
|
|
|
|
* lower bits.
|
|
|
|
|
*/
|
2008-05-27 23:29:08 +02:00
|
|
|
if (base < 0) {
|
|
|
|
|
width += base;
|
2008-06-10 19:59:35 +02:00
|
|
|
val = val.subvalue(-base, width);
|
2008-05-27 23:29:08 +02:00
|
|
|
base = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-10 19:59:35 +02:00
|
|
|
/*
|
|
|
|
|
* If the value is wider than the signal then trim off any
|
|
|
|
|
* unneeded upper bits.
|
|
|
|
|
*/
|
|
|
|
|
if (base+width > sig_size) {
|
|
|
|
|
width = sig_size - base;
|
|
|
|
|
val = val.subvalue(0, width);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool full_sig = base == 0 && width == sig_size;
|
2008-05-27 23:29:08 +02:00
|
|
|
|
2008-06-10 19:59:35 +02:00
|
|
|
vvp_net_ptr_t dest(rfp->net, 0);
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
if (full_sig) {
|
2008-10-28 18:52:39 +01:00
|
|
|
vvp_send_vec4(dest, val, vthread_get_wt_context());
|
2008-05-27 23:29:08 +02:00
|
|
|
} else {
|
2008-10-28 18:52:39 +01:00
|
|
|
vvp_send_vec4_pv(dest, val, base, width, sig_size,
|
|
|
|
|
vthread_get_wt_context());
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static vpiHandle PV_get_handle(int code, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->type_code==vpiPartSelect);
|
|
|
|
|
struct __vpiPV*rfp = (struct __vpiPV*)ref;
|
|
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
case vpiParent:
|
|
|
|
|
return rfp->parent;
|
2009-01-16 20:09:48 +01:00
|
|
|
|
|
|
|
|
case vpiModule:
|
|
|
|
|
return vpi_handle(vpiModule, rfp->parent);
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct __vpirt vpip_PV_rt = {
|
|
|
|
|
vpiPartSelect,
|
|
|
|
|
PV_get,
|
|
|
|
|
PV_get_str,
|
|
|
|
|
PV_get_value,
|
|
|
|
|
PV_put_value,
|
|
|
|
|
PV_get_handle,
|
2010-10-11 06:52:26 +02:00
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
2008-05-27 23:29:08 +02:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
2008-06-12 06:28:21 +02:00
|
|
|
struct __vpiPV* vpip_PV_from_handle(vpiHandle obj)
|
|
|
|
|
{
|
|
|
|
|
if (obj->vpi_type->type_code == vpiPartSelect)
|
|
|
|
|
return (__vpiPV*) obj;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, int base, int width)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));
|
|
|
|
|
obj->base.vpi_type = &vpip_PV_rt;
|
|
|
|
|
obj->parent = vvp_lookup_handle(var);
|
2008-06-14 01:22:18 +02:00
|
|
|
obj->sbase = 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
obj->tbase = base;
|
|
|
|
|
obj->twid = 0;
|
|
|
|
|
obj->width = (unsigned) width;
|
2008-06-15 00:31:48 +02:00
|
|
|
obj->net = 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
|
|
|
|
return &obj->base;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-14 01:22:18 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, char*symbol, int width)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));
|
|
|
|
|
obj->base.vpi_type = &vpip_PV_rt;
|
|
|
|
|
obj->parent = vvp_lookup_handle(var);
|
|
|
|
|
compile_vpi_lookup(&obj->sbase, symbol);
|
|
|
|
|
obj->tbase = 0;
|
|
|
|
|
obj->twid = 0;
|
|
|
|
|
obj->width = (unsigned) width;
|
2008-06-15 00:31:48 +02:00
|
|
|
obj->net = 0;
|
2008-06-14 01:22:18 +02:00
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
|
|
|
|
return &obj->base;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-28 01:26:18 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));
|
|
|
|
|
obj->base.vpi_type = &vpip_PV_rt;
|
|
|
|
|
obj->parent = vvp_lookup_handle(var);
|
|
|
|
|
obj->sbase = handle;
|
|
|
|
|
obj->tbase = 0;
|
|
|
|
|
obj->twid = 0;
|
|
|
|
|
obj->width = (unsigned) width;
|
|
|
|
|
obj->net = 0;
|
|
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
|
|
|
|
return &obj->base;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-17 18:47:57 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width)
|
2008-05-27 23:29:08 +02:00
|
|
|
{
|
|
|
|
|
struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV));
|
|
|
|
|
obj->base.vpi_type = &vpip_PV_rt;
|
|
|
|
|
obj->parent = vvp_lookup_handle(var);
|
2008-06-14 01:22:18 +02:00
|
|
|
obj->sbase = 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
obj->tbase = tbase;
|
|
|
|
|
obj->twid = (unsigned) twid;
|
2009-09-17 18:47:57 +02:00
|
|
|
obj->is_signed = strcmp(is_signed, "s") == 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
obj->width = (unsigned) width;
|
2008-06-15 00:31:48 +02:00
|
|
|
obj->net = 0;
|
2008-05-27 23:29:08 +02:00
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
2009-09-17 18:47:57 +02:00
|
|
|
delete [] is_signed;
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
return &obj->base;
|
|
|
|
|
}
|
2008-06-12 06:28:21 +02:00
|
|
|
|
|
|
|
|
void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiPV*obj = vpip_PV_from_handle(ref);
|
|
|
|
|
assert(obj);
|
|
|
|
|
|
2009-08-21 05:31:11 +02:00
|
|
|
vvp_vpi_callback*sig_fil;
|
2009-09-12 04:49:23 +02:00
|
|
|
sig_fil = dynamic_cast<vvp_vpi_callback*>(obj->net->fil);
|
2009-08-21 05:31:11 +02:00
|
|
|
assert(sig_fil);
|
2008-06-12 06:28:21 +02:00
|
|
|
|
|
|
|
|
/* Attach the __vpiCallback object to the signal. */
|
2009-08-21 05:31:11 +02:00
|
|
|
sig_fil->add_vpi_callback(cbh);
|
2008-06-12 06:28:21 +02:00
|
|
|
}
|
2009-01-30 02:23:09 +01:00
|
|
|
|
|
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
void PV_delete(vpiHandle item)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiPV *obj = (__vpiPV *) item;
|
2009-02-03 00:44:50 +01:00
|
|
|
if (obj->sbase) {
|
|
|
|
|
switch (obj->sbase->vpi_type->type_code) {
|
|
|
|
|
case vpiMemoryWord:
|
|
|
|
|
if (vpi_get(_vpiFromThr, obj->sbase) == _vpi_at_A) {
|
|
|
|
|
A_delete(obj->sbase);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case vpiPartSelect:
|
|
|
|
|
assert(vpi_get(_vpiFromThr, obj->sbase) == _vpi_at_PV);
|
|
|
|
|
PV_delete(obj->sbase);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-25 00:11:56 +02:00
|
|
|
assert(obj->net->fil);
|
|
|
|
|
obj->net->fil->clear_all_callbacks();
|
2009-01-30 02:23:09 +01:00
|
|
|
free(obj);
|
|
|
|
|
}
|
|
|
|
|
#endif
|