2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2012-01-20 00:04:51 +01:00
|
|
|
* Copyright (c) 2001-2012 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
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
static vpiHandle fill_in_net4(struct __vpiSignal*obj,
|
|
|
|
|
const char*name, int msb, int lsb,
|
|
|
|
|
bool signed_flag, vvp_net_t*node);
|
|
|
|
|
|
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;
|
2012-04-01 21:29:08 +02:00
|
|
|
unsigned hwid = (wid + 31)/32;
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
/*
|
|
|
|
|
* implement vpi_get for vpiReg objects.
|
|
|
|
|
*/
|
|
|
|
|
static int signal_get(int code, vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
2007-01-16 06:44:14 +01:00
|
|
|
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:
|
2012-01-19 19:16:39 +01:00
|
|
|
if (ref->get_type_code()==vpiNet)
|
2003-06-04 03:56:20 +02:00
|
|
|
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
|
|
|
|
2011-12-15 03:34:11 +01:00
|
|
|
// This private property must return zero when undefined.
|
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-15 03:34:11 +01:00
|
|
|
return 0;
|
2001-09-30 07:18:46 +02:00
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
default:
|
2011-12-15 03:34:11 +01:00
|
|
|
fprintf(stderr, "VPI error: unknown signal_get property %d.\n",
|
2011-12-06 04:52:49 +01:00
|
|
|
code);
|
|
|
|
|
return vpiUndefined;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char* signal_get_str(int code, vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
2010-10-07 00:02:45 +02:00
|
|
|
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
|
|
|
|
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
|
|
|
|
2011-12-06 20:34:11 +01:00
|
|
|
/* The scope information is added here for vpiFullName. */
|
2012-01-19 19:16:39 +01:00
|
|
|
char *rbuf = generic_get_str(code, vpip_scope(rfp), 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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(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:
|
2012-01-19 19:16:39 +01:00
|
|
|
return vpip_scope(rfp);
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
2010-10-07 00:02:45 +02:00
|
|
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
2010-10-07 00:02:45 +02:00
|
|
|
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;
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref);
|
2008-03-11 05:54:58 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2012-01-20 20:39:48 +01:00
|
|
|
int __vpiSignal::vpi_get(int code)
|
|
|
|
|
{ return signal_get(code, this); }
|
|
|
|
|
|
|
|
|
|
char* __vpiSignal::vpi_get_str(int code)
|
|
|
|
|
{ return signal_get_str(code, this); }
|
|
|
|
|
|
|
|
|
|
void __vpiSignal::vpi_get_value(p_vpi_value val)
|
|
|
|
|
{ signal_get_value(this, val); }
|
|
|
|
|
|
|
|
|
|
vpiHandle __vpiSignal::vpi_put_value(p_vpi_value val, int flags)
|
|
|
|
|
{ return signal_put_value(this, val, flags); }
|
|
|
|
|
|
|
|
|
|
vpiHandle __vpiSignal::vpi_handle(int code)
|
|
|
|
|
{ return signal_get_handle(code, this); }
|
|
|
|
|
|
|
|
|
|
vpiHandle __vpiSignal::vpi_iterate(int code)
|
|
|
|
|
{ return signal_iterate(code, this); }
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_reg : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_reg() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiReg; }
|
|
|
|
|
};
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_integer : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_integer() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiIntegerVar; }
|
|
|
|
|
};
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_net : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_net() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiNet; }
|
|
|
|
|
};
|
2001-03-25 01:35:35 +01:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_byte : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_byte() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiByteVar; }
|
|
|
|
|
};
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_bitvar : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_bitvar() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiBitVar; }
|
|
|
|
|
};
|
2011-04-03 00:50:49 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_shortint : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_shortint() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiShortIntVar; }
|
|
|
|
|
};
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_int : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_int() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiIntVar; }
|
|
|
|
|
};
|
2010-10-08 03:01:11 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct signal_longint : public __vpiSignal {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline signal_longint() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiLongIntVar; }
|
|
|
|
|
};
|
2010-10-08 03:01:11 +02:00
|
|
|
|
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
|
|
|
{
|
2012-01-20 00:04:51 +01:00
|
|
|
__vpiSignal*obj = new signal_integer;
|
|
|
|
|
return fill_in_net4(obj, name, msb, lsb, true, vec);
|
2010-10-08 03:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2012-01-20 00:04:51 +01:00
|
|
|
__vpiSignal*obj;
|
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) ) {
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_bitvar;
|
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:
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_byte;
|
2011-09-06 01:10:08 +02:00
|
|
|
break;
|
|
|
|
|
case 15:
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_shortint;
|
2011-09-06 01:10:08 +02:00
|
|
|
break;
|
|
|
|
|
case 31:
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_int;
|
2011-09-06 01:10:08 +02:00
|
|
|
break;
|
|
|
|
|
case 63:
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_longint;
|
2011-09-06 01:10:08 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// Every other type of bit vector is a vpiBitVar with
|
|
|
|
|
// array dimensions.
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new signal_bitvar;
|
2011-09-06 01:10:08 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-10-08 03:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
return fill_in_net4(obj, name, msb, lsb, signed_flag, vec);
|
2002-06-21 06:58:55 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2012-01-20 00:04:51 +01:00
|
|
|
__vpiSignal*obj = new signal_reg;
|
|
|
|
|
return fill_in_net4(obj, name, msb, lsb, signed_flag, vec);
|
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
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
struct vpiSignal_plug {
|
|
|
|
|
unsigned char space[sizeof (struct __vpiSignal)];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void* __vpiSignal::operator new(size_t siz)
|
2003-02-17 00:40:05 +01:00
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
assert(siz == sizeof(struct vpiSignal_plug));
|
|
|
|
|
static struct vpiSignal_plug*alloc_array = 0;
|
2003-02-17 00:40:05 +01:00
|
|
|
static unsigned alloc_index = 0;
|
|
|
|
|
const unsigned alloc_count = 512;
|
|
|
|
|
|
|
|
|
|
if ((alloc_array == 0) || (alloc_index == alloc_count)) {
|
2012-01-19 19:16:39 +01:00
|
|
|
alloc_array = (struct vpiSignal_plug*)
|
|
|
|
|
calloc(alloc_count, sizeof(struct vpiSignal_plug));
|
2003-02-17 00:40:05 +01:00
|
|
|
alloc_index = 0;
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(alloc_array, alloc_count *
|
2012-01-19 19:16:39 +01:00
|
|
|
sizeof(struct vpiSignal_plug));
|
2009-01-30 02:23:09 +01:00
|
|
|
VALGRIND_CREATE_MEMPOOL(alloc_array, 0, 1);
|
|
|
|
|
signal_pool_count += 1;
|
2012-01-19 19:16:39 +01:00
|
|
|
signal_pool = (vpiSignal_plug **) realloc(signal_pool,
|
|
|
|
|
signal_pool_count*sizeof(vpiSignal_plug **));
|
2009-01-30 02:23:09 +01:00
|
|
|
signal_pool[signal_pool_count-1] = alloc_array;
|
|
|
|
|
#endif
|
2003-02-17 00:40:05 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
struct vpiSignal_plug*cur = alloc_array + alloc_index;
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2012-01-19 19:16:39 +01:00
|
|
|
VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct vpiSignal_plug));
|
2009-01-30 02:23:09 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
void __vpiSignal::operator delete(void*)
|
2012-01-19 19:16:39 +01:00
|
|
|
{
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*/
|
2012-01-20 00:04:51 +01:00
|
|
|
static vpiHandle fill_in_net4(struct __vpiSignal*obj,
|
|
|
|
|
const char*name, int msb, int lsb,
|
|
|
|
|
bool signed_flag, vvp_net_t*node)
|
2001-03-25 01:35:35 +01:00
|
|
|
{
|
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;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2001-03-25 01:35:35 +01:00
|
|
|
}
|
2008-05-27 23:29:08 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
vpiHandle vpip_make_net4(const char*name, int msb, int lsb,
|
|
|
|
|
bool signed_flag, vvp_net_t*node)
|
|
|
|
|
{
|
|
|
|
|
struct __vpiSignal*obj = new signal_net;
|
|
|
|
|
return fill_in_net4(obj, name, msb, lsb, signed_flag, node);
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
|
|
|
|
assert(rfp);
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
|
|
|
|
assert(rfp);
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
|
|
|
|
assert(rfp);
|
2008-05-27 23:29:08 +02:00
|
|
|
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
|
|
|
|
assert(rfp);
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref);
|
|
|
|
|
assert(rfp);
|
2008-05-27 23:29:08 +02:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
inline __vpiPV::__vpiPV()
|
2012-01-20 23:15:26 +01:00
|
|
|
{ }
|
2008-06-12 06:28:21 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
int __vpiPV::get_type_code(void) const
|
|
|
|
|
{ return vpiPartSelect; }
|
|
|
|
|
|
2012-01-20 20:39:48 +01:00
|
|
|
int __vpiPV::vpi_get(int code)
|
|
|
|
|
{ return PV_get(code, this); }
|
|
|
|
|
|
|
|
|
|
char* __vpiPV::vpi_get_str(int code)
|
|
|
|
|
{ return PV_get_str(code, this); }
|
|
|
|
|
|
|
|
|
|
void __vpiPV::vpi_get_value(p_vpi_value val)
|
|
|
|
|
{ PV_get_value(this, val); }
|
|
|
|
|
|
|
|
|
|
vpiHandle __vpiPV::vpi_put_value(p_vpi_value val, int flags)
|
|
|
|
|
{ return PV_put_value(this, val, flags); }
|
|
|
|
|
|
|
|
|
|
vpiHandle __vpiPV::vpi_handle(int code)
|
|
|
|
|
{ return PV_get_handle(code, this); }
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, int base, int width)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*obj = new __vpiPV;
|
2008-05-27 23:29:08 +02:00
|
|
|
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);
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
2008-06-14 01:22:18 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, char*symbol, int width)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*obj = new __vpiPV;
|
2008-06-14 01:22:18 +02:00
|
|
|
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);
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2008-06-14 01:22:18 +02:00
|
|
|
}
|
|
|
|
|
|
2008-08-28 01:26:18 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*obj = new __vpiPV;
|
2008-08-28 01:26:18 +02:00
|
|
|
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);
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2008-08-28 01:26:18 +02:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV*obj = new __vpiPV;
|
2008-05-27 23:29:08 +02:00
|
|
|
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;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
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)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiPV *obj = dynamic_cast<__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();
|
2012-01-19 19:16:39 +01:00
|
|
|
delete obj;
|
2009-01-30 02:23:09 +01:00
|
|
|
}
|
|
|
|
|
#endif
|