2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2008-03-11 05:54:58 +01:00
|
|
|
* Copyright (c) 2001-2008 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"
|
2003-05-02 06:29:57 +02:00
|
|
|
# include "schedule.h"
|
2002-07-05 04:50:57 +02:00
|
|
|
# include "statistics.h"
|
2003-05-02 06:29:57 +02:00
|
|
|
# include <math.h>
|
2005-04-13 08:34:20 +02:00
|
|
|
# include <iostream>
|
2001-05-09 06:23:18 +02:00
|
|
|
# include <stdio.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#ifdef HAVE_MALLOC_H
|
2001-03-20 07:16:23 +01:00
|
|
|
# include <malloc.h>
|
2001-09-15 20:27:04 +02:00
|
|
|
#endif
|
|
|
|
|
# include <stdlib.h>
|
2001-06-29 02:44:56 +02:00
|
|
|
# include <string.h>
|
2001-03-20 07:16:23 +01:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
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
|
|
|
{
|
2003-01-07 19:07:50 +01:00
|
|
|
cnt = (cnt + 0x0fff) & ~0x0fff;
|
|
|
|
|
|
2002-07-04 01:39:57 +02:00
|
|
|
static char*result_buf[2] = {0, 0};
|
|
|
|
|
static size_t result_buf_size[2] = {0, 0};
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
char *res = need_result_buf(strlen(s1)+1, RBUF_STR);
|
|
|
|
|
if (res) strcpy(res,s1);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *generic_get_str(int code, vpiHandle ref, const char *name, const char *index)
|
|
|
|
|
{
|
|
|
|
|
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) return NULL;
|
|
|
|
|
*res=0; /* start with nothing */
|
|
|
|
|
|
|
|
|
|
/* if this works, I can make it more efficient later */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
/*
|
|
|
|
|
* The standard formating/conversion routines.
|
|
|
|
|
* They work with full or partial signals.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static void format_vpiBinStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
char *rbuf = need_result_buf(wid+1, RBUF_VAL);
|
|
|
|
|
long offset = wid - 1 + base;
|
|
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
long ssize = (signed)sig->size();
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiOctStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned dwid = (wid + 2) / 3;
|
|
|
|
|
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
|
|
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
long ssize = (signed)sig->size();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiHexStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned dwid = (wid + 3) / 4;
|
|
|
|
|
char *rbuf = need_result_buf(dwid+1, RBUF_VAL);
|
|
|
|
|
long end = base + (signed)wid;
|
|
|
|
|
long ssize = (signed)sig->size();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiDecStrVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
int signed_flag, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned hwid = (sig->size()+2) / 3 + 1;
|
|
|
|
|
char *rbuf = need_result_buf(hwid, RBUF_VAL);
|
|
|
|
|
long ssize = (signed)sig->size();
|
|
|
|
|
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) {
|
|
|
|
|
vec4 = sig->vec4_value();
|
|
|
|
|
} else {
|
|
|
|
|
vec4 = sig->vec4_value().subvalue(base, wid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpip_vec4_to_dec_str(vec4, rbuf, hwid, signed_flag);
|
|
|
|
|
|
|
|
|
|
vp->value.str = rbuf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiIntVal(vvp_fun_signal_vec*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
|
|
|
{
|
2008-06-14 04:47:48 +02:00
|
|
|
vvp_vector4_t sub = sig->vec4_value().subvalue(base, wid);
|
|
|
|
|
long val = 0;
|
|
|
|
|
bool flag = vector4_to_value(sub, val, signed_flag);
|
|
|
|
|
if (! flag) val = 0;
|
|
|
|
|
vp->value.integer = val;
|
2008-05-27 23:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiRealVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
int signed_flag, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
vvp_vector4_t vec4(wid);
|
|
|
|
|
long ssize = (signed)sig->size();
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiStringVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (idx >=0 && idx < (signed)sig->size() &&
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiScalarVal(vvp_fun_signal_vec*sig, int base,
|
|
|
|
|
s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
if (base >= 0 && base < (signed)sig->size()) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiStrengthVal(vvp_fun_signal_vec*sig, int base,
|
|
|
|
|
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) {
|
|
|
|
|
if (idx >=0 && idx < (signed)sig->size()) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void format_vpiVectorVal(vvp_fun_signal_vec*sig, int base, unsigned wid,
|
|
|
|
|
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) {
|
|
|
|
|
if (base >= 0 && base < (signed)sig->size()) {
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
if ((ref->vpi_type->type_code != vpiNet)
|
|
|
|
|
&& (ref->vpi_type->type_code != vpiReg))
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return (struct __vpiSignal*)ref;
|
|
|
|
|
}
|
|
|
|
|
|
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:
|
|
|
|
|
return rfp->parent != 0;
|
|
|
|
|
|
2008-05-01 00:39:50 +02:00
|
|
|
case vpiIndex: // This only works while we have a single index.
|
|
|
|
|
if (rfp->parent) {
|
|
|
|
|
s_vpi_value vp;
|
|
|
|
|
vp.format = vpiIntVal;
|
|
|
|
|
vpi_get_value(rfp->id.index, &vp);
|
|
|
|
|
return vp.value.integer;
|
|
|
|
|
} else
|
|
|
|
|
return 0;
|
|
|
|
|
|
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
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
case vpiLeftRange: return rfp->msb;
|
|
|
|
|
case vpiRightRange: return rfp->lsb;
|
|
|
|
|
|
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
|
|
|
|
|
return 0;
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
default:
|
2007-08-23 00:15:32 +02:00
|
|
|
fprintf(stderr, "signal_get: property %d is unknown\n", code);
|
2001-03-20 07:16:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char* signal_get_str(int code, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert((ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
|| (ref->vpi_type->type_code==vpiReg));
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
|
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
if (code == vpiFile) { // Not implemented for now!
|
|
|
|
|
return simple_set_rbuf_str(file_names[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-19 00:11:50 +01:00
|
|
|
char *nm, *ixs;
|
2007-12-03 20:41:52 +01:00
|
|
|
if (rfp->parent) {
|
2007-12-19 02:33:21 +01:00
|
|
|
nm = strdup(vpi_get_str(vpiName, rfp->parent));
|
2007-12-03 20:41:52 +01:00
|
|
|
s_vpi_value vp;
|
|
|
|
|
vp.format = vpiDecStrVal;
|
|
|
|
|
vpi_get_value(rfp->id.index, &vp);
|
2007-12-19 00:11:50 +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
|
|
|
|
2007-12-19 00:11:50 +01:00
|
|
|
char *rbuf = generic_get_str(code, &rfp->scope->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)
|
|
|
|
|
{
|
|
|
|
|
assert((ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
|| (ref->vpi_type->type_code==vpiReg));
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
|
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
|
|
2007-12-03 18:44:31 +01:00
|
|
|
case vpiParent:
|
|
|
|
|
return rfp->parent;
|
|
|
|
|
|
|
|
|
|
case vpiIndex:
|
2007-12-03 20:41:52 +01:00
|
|
|
return rfp->parent ? rfp->id.index : 0;
|
2007-12-03 18:44:31 +01:00
|
|
|
|
2001-10-15 03:49:50 +02:00
|
|
|
case vpiScope:
|
|
|
|
|
return &rfp->scope->base;
|
2004-03-09 04:11:02 +01:00
|
|
|
|
|
|
|
|
case vpiModule:
|
|
|
|
|
{ struct __vpiScope*scope = rfp->scope;
|
|
|
|
|
while (scope && scope->base.vpi_type->type_code != vpiModule)
|
|
|
|
|
scope = scope->scope;
|
|
|
|
|
|
|
|
|
|
assert(scope);
|
|
|
|
|
return &scope->base;
|
|
|
|
|
}
|
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)
|
|
|
|
|
{
|
|
|
|
|
assert((ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
|| (ref->vpi_type->type_code==vpiReg));
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
|
|
|
|
|
|
|
|
|
if (code == vpiIndex) {
|
2007-12-03 20:41:52 +01:00
|
|
|
return rfp->parent ? 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)
|
|
|
|
|
{
|
|
|
|
|
assert((ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
|| (ref->vpi_type->type_code==vpiReg));
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*rfp = (struct __vpiSignal*)ref;
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
unsigned wid = signal_width(rfp);
|
2004-12-11 03:31:25 +01:00
|
|
|
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*vsig = dynamic_cast<vvp_fun_signal_vec*>(rfp->node->fun);
|
|
|
|
|
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;
|
|
|
|
|
|
2001-03-25 21:38:05 +02: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
|
|
|
|
2006-12-09 20:06:53 +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
|
|
|
}
|
|
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
default:
|
2002-11-26 00:33:45 +01:00
|
|
|
fprintf(stderr, "vvp internal error: get_value: "
|
|
|
|
|
"value type %u not implemented."
|
|
|
|
|
" Signal is %s in scope %s\n",
|
2007-12-03 20:41:52 +01:00
|
|
|
vp->format, vpi_get_str(vpiName, ref), rfp->scope->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-04-23 05:18:14 +02:00
|
|
|
static vvp_bit4_t scalar_to_bit4(PLI_INT32 scalar)
|
|
|
|
|
{
|
|
|
|
|
switch(scalar) {
|
|
|
|
|
case vpi0:
|
|
|
|
|
return BIT4_0;
|
|
|
|
|
case vpi1:
|
|
|
|
|
return BIT4_1;
|
|
|
|
|
case vpiX:
|
|
|
|
|
return BIT4_X;
|
|
|
|
|
case vpiZ:
|
|
|
|
|
return BIT4_Z;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Unsupported scalar value %d.\n", scalar);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
|
|
vvp_net_ptr_t dest_cmd(rfp->node, 3);
|
|
|
|
|
/* Assume this is a net. (XXXX Are we sure?) */
|
|
|
|
|
vvp_send_long(dest_cmd, 2 /* release/net */);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
vvp_send_vec4(destination, val);
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
vpip_bin_str_to_vec4(val, vp->value.str, false);
|
|
|
|
|
break;
|
|
|
|
|
case vpiOctStrVal:
|
|
|
|
|
vpip_oct_str_to_vec4(val, vp->value.str);
|
|
|
|
|
break;
|
|
|
|
|
case vpiDecStrVal:
|
|
|
|
|
vpip_dec_str_to_vec4(val, vp->value.str, false);
|
|
|
|
|
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;
|
|
|
|
|
|
2001-04-25 06:45:52 +02:00
|
|
|
default:
|
2002-11-26 00:33:45 +01:00
|
|
|
fprintf(stderr, "vvp internal error: put_value: "
|
2008-05-17 01:20:22 +02:00
|
|
|
"value type %u not implemented here.\n",
|
|
|
|
|
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,
|
2001-03-20 07:16:23 +01: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,
|
2001-03-25 01:35:35 +01: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]'.
|
|
|
|
|
*/
|
2004-12-11 03:31:25 +01:00
|
|
|
vpiHandle vpip_make_int(const char*name, int msb, int lsb, vvp_net_t*vec)
|
2002-06-21 06:58:55 +02:00
|
|
|
{
|
|
|
|
|
vpiHandle obj = vpip_make_net(name, msb,lsb, true, vec);
|
|
|
|
|
struct __vpiSignal*rfp = (struct __vpiSignal*)obj;
|
|
|
|
|
obj->vpi_type = &vpip_reg_rt;
|
|
|
|
|
rfp->isint_ = true;
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2001-07-13 05:02:34 +02:00
|
|
|
* Construct a vpiReg object. It's like a net, except for the type.
|
2001-03-20 07:16:23 +01:00
|
|
|
*/
|
2002-07-05 19:14:15 +02:00
|
|
|
vpiHandle vpip_make_reg(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
|
|
|
{
|
2001-08-08 03:05:06 +02:00
|
|
|
vpiHandle obj = vpip_make_net(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
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct __vpiSignal*cur = alloc_array + alloc_index;
|
|
|
|
|
alloc_index += 1;
|
|
|
|
|
return cur;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*/
|
2002-07-05 19:14:15 +02:00
|
|
|
vpiHandle vpip_make_net(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 18:44:31 +01:00
|
|
|
obj->parent = 0;
|
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;
|
2002-06-21 06:58:55 +02:00
|
|
|
obj->isint_ = false;
|
2004-12-11 03:31:25 +01:00
|
|
|
obj->node = node;
|
2001-03-25 01:35:35 +01:00
|
|
|
|
|
|
|
|
obj->scope = vpip_peek_current_scope();
|
|
|
|
|
|
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;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
int tval = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < rfp->twid ; idx += 1) {
|
|
|
|
|
vvp_bit4_t bit = vthread_get_bit(vpip_current_vthread,
|
2008-06-14 01:22:18 +02:00
|
|
|
rfp->tbase + idx);
|
2008-05-27 23:29:08 +02:00
|
|
|
if (bit == BIT4_1) {
|
|
|
|
|
tval |= 1<<idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
case vpiConstantSelect:
|
|
|
|
|
return rfp->twid == 0;
|
|
|
|
|
|
|
|
|
|
case vpiLeftRange: rval += rfp->width;
|
|
|
|
|
case vpiRightRange:
|
|
|
|
|
rval += vpi_get(vpiRightRange, rfp->parent) + PV_get_base(rfp);
|
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
char full[1024+strlen(nm)];
|
|
|
|
|
sprintf(full, "%s[%d:%d]", nm, vpi_get(vpiLeftRange, ref),
|
|
|
|
|
vpi_get(vpiRightRange, ref));
|
|
|
|
|
return simple_set_rbuf_str(full);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "PV_get_str: property %d is unknown\n", code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(rfp->net->fun);
|
|
|
|
|
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: "
|
|
|
|
|
"value type %u not implemented. Signal is %s.\n",
|
|
|
|
|
vp->format, vpi_get_str(vpiFullName, rfp->parent));
|
|
|
|
|
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;
|
2008-06-10 19:59:35 +02:00
|
|
|
vvp_fun_signal_vec*sig = dynamic_cast<vvp_fun_signal_vec*>(rfp->net->fun);
|
2008-05-27 23:29:08 +02:00
|
|
|
assert(sig);
|
|
|
|
|
|
2008-06-10 19:59:35 +02:00
|
|
|
unsigned sig_size = sig->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-06-10 19:59:35 +02:00
|
|
|
vvp_send_vec4(dest, val);
|
2008-05-27 23:29:08 +02:00
|
|
|
} else {
|
2008-06-10 19:59:35 +02:00
|
|
|
vvp_send_vec4_pv(dest, val, base, width, sig_size);
|
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;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct __vpirt vpip_PV_rt = {
|
|
|
|
|
vpiPartSelect,
|
|
|
|
|
PV_get,
|
|
|
|
|
PV_get_str,
|
|
|
|
|
PV_get_value,
|
|
|
|
|
PV_put_value,
|
|
|
|
|
PV_get_handle,
|
|
|
|
|
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;
|
|
|
|
|
obj->net = (vvp_net_t*) malloc(sizeof(vvp_net_t));
|
|
|
|
|
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;
|
|
|
|
|
obj->net = (vvp_net_t*) malloc(sizeof(vvp_net_t));
|
|
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
|
|
|
|
return &obj->base;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-27 23:29:08 +02:00
|
|
|
vpiHandle vpip_make_PV(char*var, int tbase, int twid, 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 = tbase;
|
|
|
|
|
obj->twid = (unsigned) twid;
|
|
|
|
|
obj->width = (unsigned) width;
|
|
|
|
|
obj->net = (vvp_net_t*) malloc(sizeof(vvp_net_t));
|
|
|
|
|
functor_ref_lookup(&obj->net, var);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
vvp_fun_signal_base*sig_fun;
|
|
|
|
|
sig_fun = dynamic_cast<vvp_fun_signal_base*>(obj->net->fun);
|
|
|
|
|
assert(sig_fun);
|
|
|
|
|
|
|
|
|
|
/* Attach the __vpiCallback object to the signal. */
|
|
|
|
|
sig_fun->add_vpi_callback(cbh);
|
|
|
|
|
}
|