2001-03-20 07:16:23 +01:00
|
|
|
/*
|
2006-02-21 06:31:54 +01:00
|
|
|
* Copyright (c) 2001-2006 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
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2007-01-16 06:44:14 +01:00
|
|
|
#ident "$Id: vpi_signal.cc,v 1.76 2007/01/16 05:44:16 steve Exp $"
|
2001-03-20 07:16:23 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* vpiReg handles are handled here. These objects represent vectors of
|
|
|
|
|
* .var objects that can be manipulated by the VPI module.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
# 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:-)
|
|
|
|
|
*
|
|
|
|
|
* The table is calculated as compile time, therefore, by the
|
|
|
|
|
* draw_tt.c program.
|
|
|
|
|
*/
|
2001-03-25 21:38:05 +02:00
|
|
|
extern const char hex_digits[256];
|
2001-03-25 22:45:09 +02:00
|
|
|
extern const char oct_digits[256];
|
|
|
|
|
|
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-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) {
|
|
|
|
|
|
|
|
|
|
case vpiSigned:
|
2001-04-04 19:43:19 +02:00
|
|
|
return rfp->signed_flag != 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;
|
|
|
|
|
|
2002-09-11 18:06:57 +02:00
|
|
|
char *bn = strdup(vpi_get_str(vpiFullName, &rfp->scope->base));
|
2002-07-03 04:09:38 +02:00
|
|
|
char *nm = (char*)rfp->name;
|
|
|
|
|
|
2002-09-11 18:06:57 +02:00
|
|
|
char *rbuf = need_result_buf(strlen(bn) + strlen(nm) + 2, RBUF_STR);
|
2001-06-29 02:44:56 +02:00
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
switch (code) {
|
|
|
|
|
|
|
|
|
|
case vpiFullName:
|
2002-07-04 01:39:57 +02:00
|
|
|
sprintf(rbuf, "%s.%s", bn, nm);
|
2002-09-11 18:06:57 +02:00
|
|
|
free(bn);
|
2002-07-04 01:39:57 +02:00
|
|
|
return rbuf;
|
2001-06-29 02:44:56 +02:00
|
|
|
|
|
|
|
|
case vpiName:
|
2002-07-04 01:39:57 +02:00
|
|
|
strcpy(rbuf, nm);
|
2002-09-11 18:06:57 +02:00
|
|
|
free(bn);
|
2002-07-04 01:39:57 +02:00
|
|
|
return rbuf;
|
2001-03-20 07:16:23 +01:00
|
|
|
}
|
|
|
|
|
|
2002-09-11 18:06:57 +02:00
|
|
|
free(bn);
|
2001-03-20 07:16:23 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
|
2002-07-04 01:16:27 +02:00
|
|
|
static char *signal_vpiDecStrVal(struct __vpiSignal*rfp, s_vpi_value*vp)
|
2001-04-04 19:43:19 +02:00
|
|
|
{
|
|
|
|
|
unsigned wid = (rfp->msb >= rfp->lsb)
|
|
|
|
|
? (rfp->msb - rfp->lsb + 1)
|
|
|
|
|
: (rfp->lsb - rfp->msb + 1);
|
|
|
|
|
|
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
|
|
|
/* FIXME: bits should be an array of vvp_bit4_t. */
|
|
|
|
|
unsigned char* bits = new unsigned char[wid];
|
|
|
|
|
|
2001-04-04 19:43:19 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2004-12-11 03:31:25 +01:00
|
|
|
bits[idx] = vsig->value(idx);
|
2001-04-04 19:43:19 +02:00
|
|
|
}
|
|
|
|
|
|
2002-07-03 04:09:38 +02:00
|
|
|
unsigned hwid = (wid+2) / 3 + 1;
|
2002-07-09 05:24:37 +02:00
|
|
|
char *rbuf = need_result_buf(hwid, RBUF_VAL);
|
2001-12-18 06:31:54 +01:00
|
|
|
|
2002-07-03 04:09:38 +02:00
|
|
|
vpip_bits_to_dec_str(bits, wid, rbuf, hwid, rfp->signed_flag);
|
2001-05-22 06:08:49 +02:00
|
|
|
|
2002-02-03 02:01:51 +01:00
|
|
|
delete[]bits;
|
2002-07-03 04:09:38 +02:00
|
|
|
|
|
|
|
|
return rbuf;
|
2001-04-04 19:43:19 +02:00
|
|
|
}
|
|
|
|
|
|
2002-02-03 02:01:51 +01:00
|
|
|
|
2002-07-04 01:16:27 +02:00
|
|
|
static char *signal_vpiStringVal(struct __vpiSignal*rfp, s_vpi_value*vp)
|
2001-07-24 03:34:56 +02:00
|
|
|
{
|
|
|
|
|
unsigned wid = (rfp->msb >= rfp->lsb)
|
|
|
|
|
? (rfp->msb - rfp->lsb + 1)
|
|
|
|
|
: (rfp->lsb - rfp->msb + 1);
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
vvp_fun_signal*vsig = dynamic_cast<vvp_fun_signal*>(rfp->node->fun);
|
2001-07-24 03:34:56 +02:00
|
|
|
|
2002-01-09 04:29:12 +01:00
|
|
|
/* The result will use a character for each 8 bits of the
|
|
|
|
|
vector. Add one extra character for the highest bits that
|
2002-07-03 04:09:38 +02:00
|
|
|
don't form an 8 bit group. */
|
2002-07-09 05:24:37 +02:00
|
|
|
char *rbuf = need_result_buf(wid/8 + ((wid&7)!=0) + 1, RBUF_VAL);
|
2002-07-03 04:09:38 +02:00
|
|
|
char *cp = rbuf;
|
2001-12-18 06:31:54 +01:00
|
|
|
|
2002-01-09 04:29:12 +01:00
|
|
|
char tmp = 0;
|
|
|
|
|
int bitnr;
|
|
|
|
|
for(bitnr=wid-1; bitnr>=0; bitnr--){
|
|
|
|
|
tmp <<= 1;
|
|
|
|
|
|
2004-12-11 03:31:25 +01:00
|
|
|
switch (vsig->value(bitnr)) {
|
|
|
|
|
case BIT4_0:
|
2002-01-09 04:29:12 +01:00
|
|
|
break;
|
2004-12-11 03:31:25 +01:00
|
|
|
case BIT4_1:
|
2002-01-09 04:29:12 +01:00
|
|
|
tmp |= 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2001-07-24 03:34:56 +02:00
|
|
|
|
2002-01-09 04:29:12 +01:00
|
|
|
if ((bitnr&7)==0){
|
2004-02-20 02:52:25 +01:00
|
|
|
/* Skip leading nulls. */
|
|
|
|
|
if (tmp == 0 && cp == rbuf)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Nulls in the middle get turned into spaces. */
|
|
|
|
|
*cp++ = tmp? tmp : ' ';
|
|
|
|
|
tmp = 0;
|
2002-01-09 04:29:12 +01:00
|
|
|
}
|
2001-07-24 03:34:56 +02:00
|
|
|
}
|
|
|
|
|
*cp++ = 0;
|
2002-07-03 04:09:38 +02:00
|
|
|
|
|
|
|
|
return rbuf;
|
2001-07-24 03:34:56 +02:00
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void signal_get_IntVal(struct __vpiSignal*rfp, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned wid = signal_width(rfp);
|
2007-07-24 18:01:56 +02:00
|
|
|
unsigned iwid = 8 * sizeof vp->value.integer;
|
2005-11-30 01:42:14 +01:00
|
|
|
vvp_fun_signal_vec*vsig = dynamic_cast<vvp_fun_signal_vec*>(rfp->node->fun);
|
2005-03-12 05:27:42 +01:00
|
|
|
|
2007-07-24 18:01:56 +02:00
|
|
|
if (wid > iwid) {
|
|
|
|
|
wid = iwid;
|
|
|
|
|
}
|
2005-03-12 05:27:42 +01:00
|
|
|
vp->value.integer = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
switch (vsig->value(idx)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
vp->value.integer |= 1<<idx;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* vpi_get_value of vpiIntVal treats x and z
|
|
|
|
|
values as 0. */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void signal_get_ScalarVal(struct __vpiSignal*rfp, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
vvp_fun_signal*vsig = dynamic_cast<vvp_fun_signal*>(rfp->node->fun);
|
|
|
|
|
|
|
|
|
|
switch (vsig->value(0)) {
|
|
|
|
|
case BIT4_0:
|
|
|
|
|
vp->value.scalar = vpi0;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
vp->value.scalar = vpi1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
vp->value.scalar = vpiX;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
vp->value.scalar = vpiZ;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void signal_get_StrengthVal(struct __vpiSignal*rfp, s_vpi_value*vp)
|
|
|
|
|
{
|
2005-11-25 18:55:26 +01:00
|
|
|
vvp_fun_signal_vec*vsig = dynamic_cast<vvp_fun_signal_vec*>(rfp->node->fun);
|
2005-03-12 05:27:42 +01:00
|
|
|
unsigned wid = signal_width(rfp);
|
|
|
|
|
s_vpi_strengthval*op;
|
|
|
|
|
|
|
|
|
|
op = (s_vpi_strengthval*)
|
|
|
|
|
need_result_buf(wid * sizeof(s_vpi_strengthval), RBUF_VAL);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
vvp_scalar_t val = vsig->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].logic = vpi0;
|
|
|
|
|
op[idx].s0 = s0|s1;
|
|
|
|
|
op[idx].s1 = 0;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_1:
|
|
|
|
|
op[idx].logic = vpi1;
|
|
|
|
|
op[idx].s0 = 0;
|
|
|
|
|
op[idx].s1 = s0|s1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_X:
|
|
|
|
|
op[idx].logic = vpiX;
|
|
|
|
|
op[idx].s0 = s0;
|
|
|
|
|
op[idx].s1 = s1;
|
|
|
|
|
break;
|
|
|
|
|
case BIT4_Z:
|
|
|
|
|
op[idx].logic = vpiZ;
|
|
|
|
|
op[idx].s0 = vpiHiZ;
|
|
|
|
|
op[idx].s1 = vpiHiZ;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-08-11 06:51:13 +02:00
|
|
|
vp->value.strength = op;
|
2005-03-12 05:27:42 +01:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2002-07-03 04:09:38 +02:00
|
|
|
char *rbuf = 0;
|
2001-03-21 06:13:03 +01:00
|
|
|
|
|
|
|
|
switch (vp->format) {
|
|
|
|
|
|
2001-05-15 17:09:08 +02:00
|
|
|
case vpiIntVal:
|
2005-03-12 05:27:42 +01:00
|
|
|
signal_get_IntVal(rfp, vp);
|
2001-05-15 17:09:08 +02:00
|
|
|
break;
|
|
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
case vpiScalarVal:
|
|
|
|
|
signal_get_ScalarVal(rfp, vp);
|
|
|
|
|
break;
|
2003-04-12 20:56:57 +02:00
|
|
|
|
2005-03-12 05:27:42 +01:00
|
|
|
case vpiStrengthVal:
|
|
|
|
|
signal_get_StrengthVal(rfp, vp);
|
|
|
|
|
break;
|
2003-04-12 20:56:57 +02:00
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
case vpiBinStrVal:
|
2002-07-09 05:24:37 +02:00
|
|
|
rbuf = need_result_buf(wid+1, RBUF_VAL);
|
2001-12-18 06:31:54 +01:00
|
|
|
|
2001-03-21 06:13:03 +01:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2004-12-11 03:31:25 +01:00
|
|
|
rbuf[wid-idx-1] = "01xz"[vsig->value(idx)];
|
2001-03-21 06:13:03 +01:00
|
|
|
}
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[wid] = 0;
|
|
|
|
|
vp->value.str = rbuf;
|
2001-03-21 06:13:03 +01:00
|
|
|
break;
|
|
|
|
|
|
2001-03-25 21:38:05 +02:00
|
|
|
case vpiHexStrVal: {
|
2005-06-13 02:54:04 +02:00
|
|
|
unsigned hwid = (wid + 3) / 4;
|
2001-12-18 06:31:54 +01:00
|
|
|
|
2002-07-09 05:24:37 +02:00
|
|
|
rbuf = need_result_buf(hwid+1, RBUF_VAL);
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[hwid] = 0;
|
2001-03-25 21:38:05 +02:00
|
|
|
|
2005-06-13 02:54:04 +02:00
|
|
|
vpip_vec4_to_hex_str(vsig->vec4_value(), rbuf, hwid+1, false);
|
2002-07-03 04:09:38 +02:00
|
|
|
vp->value.str = rbuf;
|
2001-03-25 21:38:05 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-25 22:45:09 +02:00
|
|
|
case vpiOctStrVal: {
|
|
|
|
|
unsigned hval, hwid;
|
|
|
|
|
hwid = (wid + 2) / 3;
|
2001-12-18 06:31:54 +01:00
|
|
|
|
2002-07-09 05:24:37 +02:00
|
|
|
rbuf = need_result_buf(hwid+1, RBUF_VAL);
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[hwid] = 0;
|
2001-03-25 22:45:09 +02:00
|
|
|
hval = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2004-12-11 03:31:25 +01:00
|
|
|
hval = hval | (vsig->value(idx) << 2*(idx % 3));
|
2001-03-25 22:45:09 +02:00
|
|
|
|
|
|
|
|
if (idx%3 == 2) {
|
|
|
|
|
hwid -= 1;
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[hwid] = oct_digits[hval];
|
2001-03-25 22:45:09 +02:00
|
|
|
hval = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hwid > 0) {
|
|
|
|
|
hwid -= 1;
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[hwid] = oct_digits[hval];
|
2001-07-16 20:48:07 +02:00
|
|
|
unsigned padd = 0;
|
2002-07-03 04:09:38 +02:00
|
|
|
switch(rbuf[hwid]) {
|
2001-07-16 20:48:07 +02:00
|
|
|
case 'X': padd = 2; break;
|
|
|
|
|
case 'Z': padd = 3; break;
|
|
|
|
|
}
|
|
|
|
|
if (padd) {
|
|
|
|
|
for (unsigned idx = wid % 3; idx < 3; idx += 1) {
|
|
|
|
|
hval = hval | padd << 2*idx;
|
|
|
|
|
}
|
2002-07-03 04:09:38 +02:00
|
|
|
rbuf[hwid] = oct_digits[hval];
|
2001-07-16 20:48:07 +02:00
|
|
|
}
|
2001-03-25 22:45:09 +02:00
|
|
|
}
|
2002-07-03 04:09:38 +02:00
|
|
|
vp->value.str = rbuf;
|
2001-03-25 22:45:09 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2001-04-04 19:43:19 +02:00
|
|
|
case vpiDecStrVal:
|
2002-07-03 04:09:38 +02:00
|
|
|
vp->value.str = signal_vpiDecStrVal(rfp, vp);
|
2001-04-04 19:43:19 +02:00
|
|
|
break;
|
|
|
|
|
|
2001-07-24 03:34:56 +02:00
|
|
|
case vpiStringVal:
|
2002-07-03 04:09:38 +02:00
|
|
|
vp->value.str = signal_vpiStringVal(rfp, vp);
|
2001-07-24 03:34:56 +02:00
|
|
|
break;
|
|
|
|
|
|
2002-07-03 04:09:38 +02:00
|
|
|
case vpiVectorVal: {
|
2001-10-18 06:52:31 +02:00
|
|
|
unsigned int obit = 0;
|
2002-06-30 04:52:36 +02:00
|
|
|
unsigned hwid = (wid - 1)/32 + 1;
|
|
|
|
|
|
2002-07-09 05:24:37 +02:00
|
|
|
rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL);
|
2002-07-03 04:09:38 +02:00
|
|
|
s_vpi_vecval *op = (p_vpi_vecval)rbuf;
|
2002-06-30 04:52:36 +02:00
|
|
|
vp->value.vector = op;
|
|
|
|
|
|
|
|
|
|
op->aval = op->bval = 0;
|
2001-10-18 06:52:31 +02:00
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
2004-12-11 03:31:25 +01:00
|
|
|
switch (vsig->value(idx)) {
|
|
|
|
|
case BIT4_0:
|
2001-10-18 06:52:31 +02:00
|
|
|
op->aval &= ~(1 << obit);
|
|
|
|
|
op->bval &= ~(1 << obit);
|
|
|
|
|
break;
|
2004-12-11 03:31:25 +01:00
|
|
|
case BIT4_1:
|
2001-10-18 06:52:31 +02:00
|
|
|
op->aval |= (1 << obit);
|
|
|
|
|
op->bval &= ~(1 << obit);
|
|
|
|
|
break;
|
2004-12-11 03:31:25 +01:00
|
|
|
case BIT4_X:
|
2002-07-04 01:16:27 +02:00
|
|
|
op->aval |= (1 << obit);
|
2001-10-18 06:52:31 +02:00
|
|
|
op->bval |= (1 << obit);
|
|
|
|
|
break;
|
2004-12-11 03:31:25 +01:00
|
|
|
case BIT4_Z:
|
2002-07-04 01:16:27 +02:00
|
|
|
op->aval &= ~(1 << obit);
|
2001-10-18 06:52:31 +02:00
|
|
|
op->bval |= (1 << obit);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
obit++;
|
2002-06-30 04:52:36 +02:00
|
|
|
if (!(obit % 32)) {
|
2002-07-23 04:36:34 +02:00
|
|
|
op += 1;
|
2002-07-23 17:11:41 +02:00
|
|
|
if ((op - vp->value.vector) < (ptrdiff_t)hwid)
|
2002-07-23 04:36:34 +02:00
|
|
|
op->aval = op->bval = 0;
|
|
|
|
|
obit = 0;
|
2001-10-18 06:52:31 +02:00
|
|
|
}
|
|
|
|
|
}
|
2002-06-30 04:52:36 +02:00
|
|
|
break;
|
2001-10-18 06:52:31 +02:00
|
|
|
}
|
|
|
|
|
|
2006-12-09 20:06:53 +01:00
|
|
|
case vpiRealVal: {
|
|
|
|
|
bool flag = rfp->signed_flag;
|
|
|
|
|
vp->value.real = 0.0;
|
|
|
|
|
vector4_to_value(vsig->vec4_value(), vp->value.real, flag);
|
|
|
|
|
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: "
|
|
|
|
|
"value type %u not implemented."
|
|
|
|
|
" Signal is %s in scope %s\n",
|
|
|
|
|
vp->format, rfp->name, 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
|
|
|
}
|
|
|
|
|
|
2004-05-19 05:26:24 +02:00
|
|
|
static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp)
|
2001-03-20 07:16:23 +01:00
|
|
|
{
|
2001-05-14 02:42:32 +02:00
|
|
|
unsigned wid;
|
|
|
|
|
struct __vpiSignal*rfp;
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
assert((ref->vpi_type->type_code==vpiNet)
|
|
|
|
|
|| (ref->vpi_type->type_code==vpiReg));
|
|
|
|
|
|
2001-05-14 02:42:32 +02:00
|
|
|
rfp = (struct __vpiSignal*)ref;
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2005-09-21 03:04:59 +02:00
|
|
|
/* 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. */
|
2005-03-03 05:33:10 +01:00
|
|
|
vvp_net_ptr_t destination (rfp->node, 0);
|
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);
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
#if 0
|
2001-04-25 06:45:52 +02:00
|
|
|
case vpiScalarVal:
|
|
|
|
|
switch (vp->value.scalar) {
|
|
|
|
|
case vpi0:
|
2004-05-19 05:26:24 +02:00
|
|
|
functor_poke(rfp, 0, 0, St0, 0);
|
2001-04-25 06:45:52 +02:00
|
|
|
break;
|
|
|
|
|
case vpi1:
|
2004-05-19 05:26:24 +02:00
|
|
|
functor_poke(rfp, 0, 1, St1, 0);
|
2001-04-25 06:45:52 +02:00
|
|
|
break;
|
|
|
|
|
case vpiX:
|
2004-05-19 05:26:24 +02:00
|
|
|
functor_poke(rfp, 0, 2, StX, 0);
|
2001-04-25 06:45:52 +02:00
|
|
|
break;
|
|
|
|
|
case vpiZ:
|
2004-05-19 05:26:24 +02:00
|
|
|
functor_poke(rfp, 0, 3, HiZ, 0);
|
2001-04-25 06:45:52 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2005-03-03 05:33:10 +01:00
|
|
|
#endif
|
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);
|
|
|
|
|
static const vvp_bit4_t bit_table[4] = {
|
|
|
|
|
BIT4_0, BIT4_1, BIT4_X, BIT4_Z };
|
|
|
|
|
vvp_bit4_t bit = bit_table[bitmask];
|
|
|
|
|
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;
|
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: "
|
|
|
|
|
"value type %u not implemented."
|
|
|
|
|
" Signal is %s in scope %s\n",
|
|
|
|
|
vp->format, rfp->name, rfp->scope->name);
|
2001-04-25 06:45:52 +02:00
|
|
|
assert(0);
|
|
|
|
|
|
|
|
|
|
}
|
2001-03-20 07:16:23 +01:00
|
|
|
|
2005-03-03 05:33:10 +01:00
|
|
|
vvp_send_vec4(destination, val);
|
|
|
|
|
|
2001-03-20 07:16:23 +01:00
|
|
|
return ref;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
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,
|
2001-03-25 01:35:35 +01:00
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
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
|
|
|
*
|
|
|
|
|
* The name is the PLI name for the object. If it is nil, then this is
|
|
|
|
|
* actually the word of an array and has no name of its own.
|
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-01-16 06:44:14 +01:00
|
|
|
obj->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;
|
|
|
|
|
}
|