iverilog/vvp/vpi_const.cc

704 lines
16 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_const.cc,v 1.32 2004/10/04 01:10:59 steve Exp $"
#endif
# include "vpi_priv.h"
# include <stdio.h>
2001-09-15 20:27:04 +02:00
#ifdef HAVE_MALLOC_H
# include <malloc.h>
2001-09-15 20:27:04 +02:00
#endif
# include <stdlib.h>
# include <string.h>
# include <assert.h>
static int string_get(int code, vpiHandle ref)
{
struct __vpiStringConst*rfp;
switch (code) {
case vpiSize:
rfp = (struct __vpiStringConst*)ref;
2004-05-18 20:43:38 +02:00
assert((ref->vpi_type->type_code == vpiConstant)
|| ((ref->vpi_type->type_code == vpiParameter)));
//fprintf(stderr, "String:|%s|, Length: %d\n", rfp->value, strlen(rfp->value));
return strlen(rfp->value)*8;
case vpiSigned:
return 0;
case vpiConstType:
return vpiStringConst;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiStringConst\n", code);
assert(0);
return 0;
}
}
static void string_value(vpiHandle ref, p_vpi_value vp)
{
unsigned uint_value;
struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref;
2003-03-13 05:59:21 +01:00
int size = strlen(rfp->value);
char*rbuf = 0;
char*cp;
2003-03-11 00:37:07 +01:00
assert((ref->vpi_type->type_code == vpiConstant)
|| ((ref->vpi_type->type_code == vpiParameter)));
switch (vp->format) {
case vpiObjTypeVal:
/* String parameters by default have vpiStringVal values. */
vp->format = vpiStringVal;
case vpiStringVal:
rbuf = need_result_buf(size + 1, RBUF_VAL);
strcpy(rbuf, (char*)rfp->value);
vp->value.str = rbuf;
break;
case vpiDecStrVal:
if (size > 4){
// We only support standard integers. Ignore other bytes...
size = 4;
fprintf(stderr, "Warning (vpi_const.cc): %%d on constant strings only looks "
"at first 4 bytes!\n");
}
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(size + 1, RBUF_VAL);
uint_value = 0;
for(int i=0; i<size;i ++){
uint_value <<=8;
uint_value += (unsigned char)(rfp->value[i]);
}
2003-03-13 05:59:21 +01:00
sprintf(rbuf, "%u", uint_value);
vp->value.str = rbuf;
break;
case vpiBinStrVal:
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(8 * size + 1, RBUF_VAL);
cp = rbuf;
for(int i=0; i<size;i ++){
for(int bit=7;bit>=0; bit--){
*cp++ = "01"[ (rfp->value[i]>>bit)&1 ];
}
}
*cp = 0;
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiHexStrVal:
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(2 * size + 1, RBUF_VAL);
cp = rbuf;
for(int i=0; i<size;i++){
for(int nibble=1;nibble>=0; nibble--){
*cp++ = "0123456789abcdef"[ (rfp->value[i]>>(nibble*4))&15 ];
}
}
*cp = 0;
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiOctStrVal:
fprintf(stderr, "ERROR (vpi_const.cc): %%o display of constant strings not yet implemented\n");
assert(0);
break;
default:
fprintf(stderr, "ERROR (vpi_const.cc): vp->format: %d\n", vp->format);
assert(0);
vp->format = vpiSuppressVal;
break;
}
}
static const struct __vpirt vpip_string_rt = {
vpiConstant,
string_get,
0,
string_value,
0,
0,
0
};
static int free_temp_string(vpiHandle obj)
{
struct __vpiStringConst*rfp = (struct __vpiStringConst*)obj;
assert(obj->vpi_type->type_code == vpiConstant);
free(rfp->value);
free(rfp);
return 1;
}
static const struct __vpirt vpip_string_temp_rt = {
vpiConstant,
string_get,
0,
string_value,
0,
0,
0,
0,
free_temp_string
};
vpiHandle vpip_make_string_const(char*text, bool persistent_flag)
{
struct __vpiStringConst*obj;
obj = (struct __vpiStringConst*)
malloc(sizeof (struct __vpiStringConst));
obj->base.vpi_type = persistent_flag
? &vpip_string_rt
: &vpip_string_temp_rt;
obj->value = text;
return &obj->base;
}
2003-03-11 00:37:07 +01:00
struct __vpiStringParam : public __vpiStringConst {
const char*basename;
struct __vpiScope* scope;
2003-03-11 00:37:07 +01:00
};
static char* string_param_get_str(int code, vpiHandle obj)
{
struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj;
2003-03-13 05:59:21 +01:00
char *rbuf = need_result_buf(strlen(rfp->basename) + 1, RBUF_STR);
2003-03-11 00:37:07 +01:00
assert(obj->vpi_type->type_code == vpiParameter);
switch (code) {
case vpiName:
2003-03-13 05:59:21 +01:00
strcpy(rbuf, rfp->basename);
return rbuf;
default:
return 0;
}
}
static vpiHandle string_param_handle(int code, vpiHandle obj)
{
struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj;
assert(obj->vpi_type->type_code == vpiParameter);
switch (code) {
case vpiScope:
return &rfp->scope->base;
2003-03-11 00:37:07 +01:00
default:
return 0;
}
}
static const struct __vpirt vpip_string_param_rt = {
vpiParameter,
string_get,
string_param_get_str,
string_value,
0,
string_param_handle,
2003-03-11 00:37:07 +01:00
0,
0,
0
};
vpiHandle vpip_make_string_param(char*name, char*text)
{
struct __vpiStringParam*obj;
obj = (struct __vpiStringParam*)
malloc(sizeof (struct __vpiStringParam));
obj->base.vpi_type = &vpip_string_param_rt;
obj->value = text;
obj->basename = name;
obj->scope = vpip_peek_current_scope();
2003-03-11 00:37:07 +01:00
return &obj->base;
}
static int binary_get(int code, vpiHandle ref)
{
struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
switch (code) {
case vpiConstType:
return vpiBinaryConst;
case vpiSigned:
return rfp->signed_flag? 1 : 0;
case vpiSize:
return rfp->nbits;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiBinaryConst\n", code);
assert(0);
return 0;
}
}
2002-04-28 01:26:24 +02:00
static void binary_vpiStringVal(struct __vpiBinaryConst*rfp, p_vpi_value vp)
{
unsigned nchar = rfp->nbits / 8;
unsigned tail = rfp->nbits%8;
2003-03-13 05:59:21 +01:00
char*rbuf = need_result_buf(nchar + 1, RBUF_VAL);
char*cp = rbuf;
2002-04-28 01:26:24 +02:00
if (tail > 0) {
char char_val = 0;
for (unsigned idx = rfp->nbits-tail; idx < rfp->nbits; idx += 1) {
unsigned nibble = idx/4;
unsigned shift = 2 * (idx%4);
unsigned val = (rfp->bits[nibble] >> shift) & 3;
if (val & 1)
char_val |= 1 << idx;
}
if (char_val != 0)
*cp++ = char_val;
}
for (unsigned idx = 0 ; idx < nchar ; idx += 1) {
unsigned bit = (nchar - idx - 1) * 8;
unsigned nibble = bit/4;
unsigned vall = rfp->bits[nibble+0];
unsigned valh = rfp->bits[nibble+1];
char char_val = 0;
if (vall&0x01) char_val |= 0x01;
if (vall&0x04) char_val |= 0x02;
if (vall&0x10) char_val |= 0x04;
if (vall&0x40) char_val |= 0x08;
if (valh&0x01) char_val |= 0x10;
if (valh&0x04) char_val |= 0x20;
if (valh&0x10) char_val |= 0x40;
if (valh&0x40) char_val |= 0x80;
if (char_val != 0)
*cp++ = char_val;
}
*cp = 0;
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
2002-04-28 01:26:24 +02:00
}
static int bits2int(struct __vpiBinaryConst*rfp)
{
unsigned val = 0;
unsigned bit_val = 0;
unsigned bit_limit = rfp->nbits;
if (bit_limit > 8*sizeof(val))
bit_limit = 8*sizeof(val);
for (unsigned idx = 0 ; idx < bit_limit ; idx += 1) {
unsigned nibble = idx/4;
unsigned shift = 2 * (idx%4);
bit_val = (rfp->bits[nibble] >> shift) & 3;
if (bit_val > 1) {
return 0;
} else {
val |= bit_val << idx;
}
}
/* sign extend */
if (rfp->signed_flag && bit_val) {
for (unsigned idx = rfp->nbits; idx <sizeof(val)*8; idx++)
{
val |= bit_val << idx;
}
}
return val;
}
static void binary_value(vpiHandle ref, p_vpi_value vp)
{
assert(ref->vpi_type->type_code == vpiConstant);
2003-03-13 05:59:21 +01:00
struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref;
char*rbuf = 0;
switch (vp->format) {
case vpiObjTypeVal:
2003-03-13 05:59:21 +01:00
case vpiBinStrVal: {
rbuf = need_result_buf(rfp->nbits + 1, RBUF_VAL);
for (unsigned idx = 0 ; idx < rfp->nbits ; idx += 1) {
unsigned nibble = idx/4;
unsigned shift = 2 * (idx%4);
unsigned val = (rfp->bits[nibble] >> shift) & 3;
2003-03-13 05:59:21 +01:00
rbuf[rfp->nbits-idx-1] = "01xz"[val];
}
2003-03-13 05:59:21 +01:00
rbuf[rfp->nbits] = 0;
vp->value.str = rbuf;
break;
2003-03-13 05:59:21 +01:00
}
case vpiDecStrVal: {
unsigned wid = rfp->nbits;
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(rfp->nbits + 1, RBUF_VAL);
unsigned char*tmp = new unsigned char[wid];
for (unsigned idx = 0 ; idx < wid ; idx += 1)
tmp[idx] = (rfp->bits[idx/4] >> 2*(idx%4)) & 3;
2003-03-13 05:59:21 +01:00
vpip_bits_to_dec_str(tmp, wid, rbuf, wid + 1,
rfp->signed_flag);
delete[]tmp;
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
}
2002-04-28 00:36:39 +02:00
case vpiHexStrVal: {
unsigned nchar = (rfp->nbits+3)/4;
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(nchar + 1, RBUF_VAL);
2002-04-28 00:36:39 +02:00
for (unsigned idx = 0 ; idx < rfp->nbits ; idx += 4) {
unsigned nibble = idx/4;
unsigned vals = rfp->bits[nibble];
if (vals == 0xff) {
2003-03-13 05:59:21 +01:00
rbuf[nchar-idx/4-1] = 'z';
2002-04-28 00:36:39 +02:00
} else if (vals == 0xaa) {
2003-03-13 05:59:21 +01:00
rbuf[nchar-idx/4-1] = 'x';
2002-04-28 00:36:39 +02:00
} else if (vals & 0xaa) {
2003-03-13 05:59:21 +01:00
rbuf[nchar-idx/4-1] = 'X';
2002-04-28 00:36:39 +02:00
} else {
unsigned val = vals&1;
if (vals&0x04) val |= 2;
if (vals&0x10) val |= 4;
if (vals&0x40) val |= 8;
2003-03-13 05:59:21 +01:00
rbuf[nchar-idx/4-1] = "0123456789abcdef"[val];
2002-04-28 00:36:39 +02:00
}
}
2003-03-13 05:59:21 +01:00
rbuf[nchar] = 0;
vp->value.str = rbuf;
2002-04-28 00:36:39 +02:00
break;
}
2003-05-30 06:22:13 +02:00
case vpiOctStrVal: {
unsigned nchar = (rfp->nbits+2)/3;
rbuf = need_result_buf(nchar + 1, RBUF_VAL);
vpip_bits_to_oct_str(rfp->bits, rfp->nbits,
rbuf, nchar+1, rfp->signed_flag);
vp->value.str = rbuf;
break;
}
2001-04-04 07:07:19 +02:00
case vpiIntVal: {
vp->value.integer = bits2int(rfp);
2001-04-04 07:07:19 +02:00
break;
}
2002-11-03 03:07:24 +01:00
case vpiVectorVal: {
unsigned int obit = 0;
unsigned hwid = (rfp->nbits - 1)/32 + 1;
2003-03-13 05:59:21 +01:00
rbuf = need_result_buf(hwid*sizeof(s_vpi_vecval), RBUF_VAL);
2002-11-03 03:07:24 +01:00
s_vpi_vecval *op = (p_vpi_vecval)rbuf;
vp->value.vector = op;
op->aval = op->bval = 0;
for (unsigned idx = 0 ; idx < rfp->nbits ; idx += 1) {
unsigned nibble = idx/4;
unsigned shift = 2 * (idx%4);
unsigned bit_val = (rfp->bits[nibble] >> shift) & 3;
switch (bit_val) {
case 0:
op->aval &= ~(1 << obit);
op->bval &= ~(1 << obit);
break;
case 1:
op->aval |= (1 << obit);
op->bval &= ~(1 << obit);
break;
case 2:
op->aval |= (1 << obit);
op->bval |= (1 << obit);
break;
case 3:
op->aval &= ~(1 << obit);
op->bval |= (1 << obit);
break;
}
obit++;
if (!(obit % 32)) {
op += 1;
2002-11-03 21:33:43 +01:00
if ((op - vp->value.vector) < (long)hwid)
2002-11-03 03:07:24 +01:00
op->aval = op->bval = 0;
obit = 0;
}
}
break;
}
case vpiRealVal:
vp->value.real = (double)bits2int(rfp);
break;
2002-04-28 01:26:24 +02:00
case vpiStringVal:
binary_vpiStringVal(rfp, vp);
break;
default:
fprintf(stderr, "vvp error: format %d not supported "
"by vpiBinaryConst\n", vp->format);
vp->format = vpiSuppressVal;
break;
}
}
static const struct __vpirt vpip_binary_rt = {
vpiConstant,
binary_get,
0,
binary_value,
0,
0,
0
};
/*
* Make a VPI constant from a vector string. The string is normally a
* ASCII string, with each letter a 4-value bit. The first character
* may be an 's' if the vector is signed.
*/
vpiHandle vpip_make_binary_const(unsigned wid, char*bits)
{
struct __vpiBinaryConst*obj;
obj = (struct __vpiBinaryConst*)
malloc(sizeof (struct __vpiBinaryConst));
obj->base.vpi_type = &vpip_binary_rt;
obj->signed_flag = 0;
obj->nbits = wid;
obj->bits = (unsigned char*)malloc((obj->nbits + 3) / 4);
memset(obj->bits, 0, (obj->nbits + 3) / 4);
const char*bp = bits;
if (*bp == 's') {
bp += 1;
obj->signed_flag = 1;
}
for (unsigned idx = 0 ; idx < obj->nbits ; idx += 1) {
unsigned nibble = idx / 4;
unsigned val = 0;
switch (bp[wid-idx-1]) {
case '0':
val = 0;
break;
case '1':
val = 1;
break;
case 'x':
val = 2;
break;
case 'z':
val = 3;
break;
}
obj->bits[nibble] |= val << (2 * (idx%4));
}
free(bits);
return &(obj->base);
}
static int dec_get(int code, vpiHandle ref)
{
switch (code) {
case vpiConstType:
return vpiDecConst;
case vpiSigned:
return 1;
case vpiSize:
return 32;
default:
fprintf(stderr, "vvp error: get %d not supported "
"by vpiDecConst\n", code);
assert(0);
return 0;
}
}
static void dec_value(vpiHandle ref, p_vpi_value vp)
{
struct __vpiDecConst*rfp = (struct __vpiDecConst*)ref;
assert(ref->vpi_type->type_code == vpiConstant);
2003-03-13 05:59:21 +01:00
char*rbuf = need_result_buf(64 + 1, RBUF_VAL);
char*cp = rbuf;
switch (vp->format) {
case vpiObjTypeVal:
case vpiIntVal: {
vp->value.integer = rfp->value;
break;
}
case vpiDecStrVal:
2003-03-13 05:59:21 +01:00
sprintf(rbuf, "%d", rfp->value);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiBinStrVal:
for(int bit=31; bit<=0;bit--){
*cp++ = "01"[ (rfp->value>>bit)&1 ];
}
*cp = 0;
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiHexStrVal:
2003-03-13 05:59:21 +01:00
sprintf(rbuf, "%08x", rfp->value);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
case vpiOctStrVal:
2003-03-13 05:59:21 +01:00
sprintf(rbuf, "%011x", rfp->value);
2003-03-13 05:59:21 +01:00
vp->value.str = rbuf;
break;
default:
fprintf(stderr, "vvp error (vpi_const.cc): format %d not supported "
"by vpiDecConst\n", vp->format);
vp->format = vpiSuppressVal;
break;
}
}
static const struct __vpirt vpip_dec_rt = {
vpiConstant,
dec_get,
0,
dec_value,
0,
0,
0
};
vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value)
{
obj->base.vpi_type = &vpip_dec_rt;
obj->value = value;
return &(obj->base);
}
vpiHandle vpip_make_dec_const(int value)
{
struct __vpiDecConst*obj;
obj = (struct __vpiDecConst*)
malloc(sizeof (struct __vpiDecConst));
return vpip_make_dec_const(obj, value);
}
/*
* $Log: vpi_const.cc,v $
* Revision 1.32 2004/10/04 01:10:59 steve
* Clean up spurious trailing white space.
*
2004-05-18 20:43:38 +02:00
* Revision 1.31 2004/05/18 18:43:38 steve
* Allow vpiParamter as a string type.
*
2003-05-30 06:22:13 +02:00
* Revision 1.30 2003/05/30 04:22:13 steve
* Add tf_strgetp functions.
*
* Revision 1.29 2003/05/29 03:46:21 steve
* Add tf_getp/putp support for integers
* and real valued arguments.
*
* Add tf_mipname function.
*
* Revision 1.28 2003/03/17 23:47:25 steve
* Make a safe copy of const string values.
*
2003-03-15 06:44:50 +01:00
* Revision 1.27 2003/03/15 05:44:50 steve
* Remove excess assignment.
*
* Revision 1.26 2003/03/14 05:02:13 steve
* Streamline parameter string value, get paramete scope.
*
2003-03-13 05:59:21 +01:00
* Revision 1.25 2003/03/13 04:59:21 steve
* Use rbufs instead of static buffers.
*
2003-03-11 00:37:07 +01:00
* Revision 1.24 2003/03/10 23:37:07 steve
* Direct support for string parameters.
*
* Revision 1.23 2003/03/10 19:14:27 steve
* More carful about shifting beyond word size.
*
* Revision 1.22 2003/02/24 06:35:45 steve
* Interactive task calls take string arguments.
*
2002-11-03 21:33:43 +01:00
* Revision 1.21 2002/11/03 20:33:43 steve
* Compiler error wrt ptrdiff_t.
*
2002-11-03 03:07:24 +01:00
* Revision 1.20 2002/11/03 02:07:24 steve
* Get VectorVals from constant values.
*
* Revision 1.19 2002/08/12 01:35:08 steve
* conditional ident string using autoconfig.
*
2002-06-23 20:23:09 +02:00
* Revision 1.18 2002/06/23 18:23:09 steve
* trivial performance boost.
*/