2001-03-16 02:44:34 +01:00
|
|
|
/*
|
2014-06-30 05:38:23 +02:00
|
|
|
* Copyright (c) 2001-2014 Stephen Williams (steve@icarus.com)
|
2001-03-16 02:44:34 +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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2001-03-16 02:44:34 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This file keeps the table of system/task definitions. This table is
|
|
|
|
|
* built up before the input source file is parsed, and is used by the
|
|
|
|
|
* compiler when %vpi_call statements are encountered.
|
|
|
|
|
*/
|
2001-05-20 02:46:12 +02:00
|
|
|
# include "vpi_priv.h"
|
|
|
|
|
# include "vthread.h"
|
2007-07-25 03:24:24 +02:00
|
|
|
# include "compile.h"
|
2009-01-30 02:23:09 +01:00
|
|
|
# include "config.h"
|
|
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2009-01-24 01:04:44 +01:00
|
|
|
# include "vvp_cleanup.h"
|
2009-01-30 02:23:09 +01:00
|
|
|
#endif
|
2012-10-23 02:20:43 +02:00
|
|
|
# include <iostream>
|
2010-05-31 22:12:06 +02:00
|
|
|
# include <cstdio>
|
|
|
|
|
# include <cstdlib>
|
|
|
|
|
# include <cstring>
|
|
|
|
|
# include <cassert>
|
2010-10-24 00:52:56 +02:00
|
|
|
# include "ivl_alloc.h"
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
using namespace std;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
inline __vpiUserSystf::__vpiUserSystf()
|
2012-01-20 23:15:26 +01:00
|
|
|
{ }
|
2012-01-19 19:16:39 +01:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
int __vpiUserSystf::get_type_code(void) const
|
|
|
|
|
{ return vpiUserSystf; }
|
|
|
|
|
|
|
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
static vpiHandle systask_handle(int type, vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2001-03-18 01:37:55 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case vpiScope:
|
2012-01-19 19:16:39 +01:00
|
|
|
return rfp->scope;
|
2009-01-16 20:09:48 +01:00
|
|
|
|
2010-04-11 23:28:45 +02:00
|
|
|
case vpiUserSystf:
|
|
|
|
|
/* Assert that vpiUserDefn is true! */
|
2010-04-12 08:39:08 +02:00
|
|
|
assert(rfp->defn->is_user_defn);
|
2012-01-19 19:16:39 +01:00
|
|
|
return rfp->defn;
|
2010-04-11 23:28:45 +02:00
|
|
|
|
2001-03-18 01:37:55 +01:00
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
};
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2004-02-18 03:51:59 +01:00
|
|
|
static int systask_get(int type, vpiHandle ref)
|
2003-03-14 06:00:44 +01:00
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2003-03-14 06:00:44 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
2009-01-16 20:09:48 +01:00
|
|
|
/* This is not the correct way to get this information, but
|
|
|
|
|
* some of the code that implements the acc and tf routines
|
|
|
|
|
* use this method so we will keep it in for now. */
|
2003-03-14 06:00:44 +01:00
|
|
|
case vpiTimeUnit:
|
|
|
|
|
return rfp->scope->time_units;
|
2009-01-16 20:09:48 +01:00
|
|
|
case vpiTimePrecision:
|
|
|
|
|
return rfp->scope->time_precision;
|
2008-01-01 18:45:02 +01:00
|
|
|
|
|
|
|
|
case vpiLineNo:
|
2008-04-30 03:58:25 +02:00
|
|
|
return rfp->lineno;
|
2008-01-01 18:45:02 +01:00
|
|
|
|
2010-04-11 23:28:45 +02:00
|
|
|
case vpiUserDefn:
|
2010-04-12 08:39:08 +02:00
|
|
|
return rfp->defn->is_user_defn;
|
2010-04-11 23:28:45 +02:00
|
|
|
|
2003-03-14 06:00:44 +01:00
|
|
|
default:
|
|
|
|
|
return vpiUndefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-04-12 06:33:39 +02:00
|
|
|
// support getting vpiSize for a system function call
|
|
|
|
|
static int sysfunc_get(int type, vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2007-04-12 06:33:39 +02:00
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case vpiSize:
|
2014-01-21 04:07:11 +01:00
|
|
|
assert(0); // This should be handled by derived classes
|
|
|
|
|
return 0;
|
2008-01-01 18:45:02 +01:00
|
|
|
|
|
|
|
|
case vpiLineNo:
|
2008-04-30 03:58:25 +02:00
|
|
|
return rfp->lineno;
|
2008-01-01 18:45:02 +01:00
|
|
|
|
2010-04-11 23:28:45 +02:00
|
|
|
case vpiUserDefn:
|
2010-04-12 08:39:08 +02:00
|
|
|
return rfp->defn->is_user_defn;
|
2010-04-11 23:28:45 +02:00
|
|
|
|
2007-04-12 06:33:39 +02:00
|
|
|
default:
|
|
|
|
|
return vpiUndefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-03 04:27:35 +01:00
|
|
|
/*
|
|
|
|
|
* the get_str function only needs to support vpiName
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static char *systask_get_str(int type, vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2003-03-03 04:27:35 +01:00
|
|
|
|
|
|
|
|
switch (type) {
|
2008-01-01 18:45:02 +01:00
|
|
|
case vpiFile:
|
|
|
|
|
assert(rfp->file_idx < file_names.size());
|
|
|
|
|
return simple_set_rbuf_str(file_names[rfp->file_idx]);
|
2003-03-03 04:27:35 +01:00
|
|
|
|
|
|
|
|
case vpiName:
|
2007-12-19 00:11:50 +01:00
|
|
|
return simple_set_rbuf_str(rfp->defn->info.tfname);
|
2003-03-03 04:27:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
/*
|
|
|
|
|
* the iter function only supports getting an iterator of the
|
|
|
|
|
* arguments. This works equally well for tasks and functions.
|
|
|
|
|
*/
|
2010-10-11 06:52:26 +02:00
|
|
|
static vpiHandle systask_iter(int, vpiHandle ref)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
if (rfp->nargs == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2002-05-03 17:44:11 +02:00
|
|
|
return vpip_make_iterator(rfp->nargs, rfp->args, false);
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct systask_def : public __vpiSysTaskCall {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline systask_def() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiSysTaskCall; }
|
2012-01-20 20:39:48 +01:00
|
|
|
int vpi_get(int code) { return systask_get(code, this); }
|
|
|
|
|
char*vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
|
|
|
vpiHandle vpi_handle(int code) { return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code){ return systask_iter(code, this); }
|
2012-01-20 00:04:51 +01:00
|
|
|
};
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2008-03-11 05:54:58 +01:00
|
|
|
static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
|
2006-06-18 06:15:50 +02:00
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2006-06-18 06:15:50 +02:00
|
|
|
|
2008-05-28 00:11:17 +02:00
|
|
|
rfp->put_value = true;
|
|
|
|
|
|
|
|
|
|
double val;
|
2006-06-18 06:15:50 +02:00
|
|
|
switch (vp->format) {
|
|
|
|
|
|
|
|
|
|
case vpiRealVal:
|
|
|
|
|
val = vp->value.real;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2009-12-10 21:53:58 +01:00
|
|
|
val = 0.0;
|
|
|
|
|
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
2006-06-18 06:15:50 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2009-04-04 05:40:26 +02:00
|
|
|
rfp->fnet->send_real(val, vthread_get_wt_context());
|
2006-06-18 06:15:50 +02:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int)
|
2010-06-09 20:56:00 +02:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct sysfunc_real : public __vpiSysTaskCall {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline sysfunc_real() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiSysFuncCall; }
|
2012-01-20 20:39:48 +01:00
|
|
|
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
|
|
|
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
2012-10-23 02:20:43 +02:00
|
|
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
2012-01-20 20:39:48 +01:00
|
|
|
vpiHandle vpi_handle(int code)
|
|
|
|
|
{ return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code)
|
|
|
|
|
{ return systask_iter(code, this); }
|
2012-10-23 02:20:43 +02:00
|
|
|
|
|
|
|
|
double return_value_;
|
2012-01-20 00:04:51 +01:00
|
|
|
};
|
2003-01-27 01:14:37 +01:00
|
|
|
|
2012-10-23 02:20:43 +02:00
|
|
|
vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
|
|
|
|
|
{
|
|
|
|
|
put_value = true;
|
|
|
|
|
|
|
|
|
|
return_value_ = 0.0;
|
|
|
|
|
switch (vp->format) {
|
|
|
|
|
case vpiRealVal:
|
|
|
|
|
return_value_ = vp->value.real;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-04 23:06:58 +01:00
|
|
|
class sysfunc_vec4 : public __vpiSysTaskCall {
|
|
|
|
|
public:
|
2015-10-22 11:45:31 +02:00
|
|
|
explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
|
2014-01-04 23:06:58 +01:00
|
|
|
int get_type_code(void) const { return vpiSysFuncCall; }
|
2014-01-15 02:10:03 +01:00
|
|
|
int vpi_get(int code);
|
2014-01-04 23:06:58 +01:00
|
|
|
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
|
|
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
|
|
|
|
vpiHandle vpi_handle(int code)
|
|
|
|
|
{ return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code)
|
|
|
|
|
{ return systask_iter(code, this); }
|
|
|
|
|
|
|
|
|
|
inline const vvp_vector4_t& return_value() const { return return_value_; }
|
|
|
|
|
|
|
|
|
|
private:
|
2014-01-14 18:22:23 +01:00
|
|
|
vpiHandle put_value_scalar_(p_vpi_value vp);
|
2014-01-04 23:06:58 +01:00
|
|
|
vpiHandle put_value_int_(p_vpi_value vp);
|
2014-01-14 18:22:23 +01:00
|
|
|
vpiHandle put_value_string_(p_vpi_value vp);
|
|
|
|
|
vpiHandle put_value_vector_(p_vpi_value vp);
|
2014-01-05 21:04:16 +01:00
|
|
|
vpiHandle put_value_time_(p_vpi_value vp);
|
2014-01-04 23:06:58 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
vvp_vector4_t return_value_;
|
|
|
|
|
};
|
|
|
|
|
|
2014-01-15 02:10:03 +01:00
|
|
|
int sysfunc_vec4::vpi_get(int code)
|
|
|
|
|
{
|
|
|
|
|
switch (code) {
|
|
|
|
|
case vpiSize:
|
|
|
|
|
return return_value_.size();
|
|
|
|
|
|
|
|
|
|
case vpiLineNo:
|
|
|
|
|
return lineno;
|
|
|
|
|
|
|
|
|
|
case vpiUserDefn:
|
|
|
|
|
return defn->is_user_defn;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return vpiUndefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-14 18:22:23 +01:00
|
|
|
vpiHandle sysfunc_vec4::put_value_scalar_(p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
switch (vp->value.scalar) {
|
|
|
|
|
case vpi0:
|
|
|
|
|
return_value_.set_bit(0, BIT4_0);
|
|
|
|
|
break;
|
|
|
|
|
case vpi1:
|
|
|
|
|
return_value_.set_bit(0, BIT4_1);
|
|
|
|
|
break;
|
|
|
|
|
case vpiX:
|
|
|
|
|
return_value_.set_bit(0, BIT4_X);
|
|
|
|
|
break;
|
|
|
|
|
case vpiZ:
|
|
|
|
|
return_value_.set_bit(0, BIT4_Z);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Unsupported value %d.\n", (int)vp->value.scalar);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-04 23:06:58 +01:00
|
|
|
vpiHandle sysfunc_vec4::put_value_int_(p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
long tmp = vp->value.integer;
|
|
|
|
|
unsigned width = return_value_.size();
|
|
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
|
|
|
return_value_.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
|
|
|
|
tmp >>= 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-14 18:22:23 +01:00
|
|
|
vpiHandle sysfunc_vec4::put_value_string_(p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
size_t slen = strlen(vp->value.str);
|
|
|
|
|
unsigned wid = return_value_.size();
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
|
|
|
|
|
unsigned cidx = idx / 8;
|
|
|
|
|
// If wider then the string, then pad with zero.
|
|
|
|
|
if (cidx >= slen) {
|
|
|
|
|
return_value_.set_bit(idx, BIT4_0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put the end of the string in the LSB of the vector
|
|
|
|
|
char use_char = vp->value.str[slen - 1 - cidx];
|
|
|
|
|
|
|
|
|
|
if ((use_char >> (idx % 8)) & 1)
|
|
|
|
|
return_value_.set_bit(idx, BIT4_1);
|
|
|
|
|
else
|
|
|
|
|
return_value_.set_bit(idx, BIT4_0);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle sysfunc_vec4::put_value_vector_(p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned width = return_value_.size();
|
|
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
|
|
|
unsigned word = idx / 32;
|
|
|
|
|
unsigned bidx = idx % 32;
|
|
|
|
|
|
|
|
|
|
unsigned long aval = vp->value.vector[word].aval >> bidx;
|
|
|
|
|
unsigned long bval = vp->value.vector[word].bval >> bidx;
|
|
|
|
|
|
|
|
|
|
int bit = (aval&1) | ((bval<<1)&2);
|
|
|
|
|
vvp_bit4_t bit4;
|
|
|
|
|
|
|
|
|
|
switch (bit) {
|
|
|
|
|
case 0:
|
|
|
|
|
bit4 = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
bit4 = BIT4_1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
bit4 = BIT4_Z;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
bit4 = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
bit4 = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return_value_.set_bit(idx, bit4);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-05 21:04:16 +01:00
|
|
|
vpiHandle sysfunc_vec4::put_value_time_(p_vpi_value vp)
|
|
|
|
|
{
|
|
|
|
|
unsigned width = return_value_.size();
|
|
|
|
|
long tmp = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < width ; idx += 1) {
|
|
|
|
|
if (idx == 0)
|
|
|
|
|
tmp = vp->value.time->low;
|
|
|
|
|
else if (idx == 32)
|
|
|
|
|
tmp = vp->value.time->high;
|
|
|
|
|
else if (idx == 64)
|
|
|
|
|
tmp = 0;
|
|
|
|
|
|
|
|
|
|
return_value_.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
|
|
|
|
tmp >>= 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-04 23:06:58 +01:00
|
|
|
vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int)
|
|
|
|
|
{
|
|
|
|
|
put_value = true;
|
|
|
|
|
|
|
|
|
|
switch (vp->format) {
|
2014-01-14 18:22:23 +01:00
|
|
|
case vpiScalarVal:
|
|
|
|
|
return put_value_scalar_(vp);
|
2014-01-04 23:06:58 +01:00
|
|
|
case vpiIntVal:
|
|
|
|
|
return put_value_int_(vp);
|
2014-01-14 18:22:23 +01:00
|
|
|
case vpiStringVal:
|
|
|
|
|
return put_value_string_(vp);
|
|
|
|
|
case vpiVectorVal:
|
|
|
|
|
return put_value_vector_(vp);
|
2014-01-05 21:04:16 +01:00
|
|
|
case vpiTimeVal:
|
|
|
|
|
return put_value_time_(vp);
|
2014-01-04 23:06:58 +01:00
|
|
|
default:
|
2014-01-14 18:22:23 +01:00
|
|
|
fprintf(stderr, "Unsupported format %d setting sysfunc vec4 value.\n", (int)vp->format);
|
2014-01-04 23:06:58 +01:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct sysfunc_4net : public __vpiSysTaskCall {
|
2015-10-22 11:45:31 +02:00
|
|
|
explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiSysFuncCall; }
|
2014-01-21 04:07:11 +01:00
|
|
|
int vpi_get(int code);
|
2012-01-20 20:39:48 +01:00
|
|
|
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
2014-01-21 04:07:11 +01:00
|
|
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
2012-01-20 20:39:48 +01:00
|
|
|
vpiHandle vpi_handle(int code)
|
|
|
|
|
{ return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code)
|
|
|
|
|
{ return systask_iter(code, this); }
|
2014-01-21 04:07:11 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
unsigned vwid_;
|
2012-01-20 00:04:51 +01:00
|
|
|
};
|
2006-06-18 06:15:50 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct sysfunc_rnet : public __vpiSysTaskCall {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline sysfunc_rnet() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiSysFuncCall; }
|
2012-01-20 20:39:48 +01:00
|
|
|
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
|
|
|
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
|
|
|
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
|
|
|
|
{ return sysfunc_put_rnet_value(this, val, flags); }
|
|
|
|
|
vpiHandle vpi_handle(int code)
|
|
|
|
|
{ return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code)
|
|
|
|
|
{ return systask_iter(code, this); }
|
2012-01-20 00:04:51 +01:00
|
|
|
};
|
2006-06-18 06:15:50 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
struct sysfunc_no : public __vpiSysTaskCall {
|
2012-01-20 23:15:26 +01:00
|
|
|
inline sysfunc_no() { }
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const { return vpiSysFuncCall; }
|
2012-01-20 20:39:48 +01:00
|
|
|
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
|
|
|
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
|
|
|
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
|
|
|
|
{ return sysfunc_put_no_value(this, val, flags); }
|
|
|
|
|
vpiHandle vpi_handle(int code)
|
|
|
|
|
{ return systask_handle(code, this); }
|
|
|
|
|
vpiHandle vpi_iterate(int code)
|
|
|
|
|
{ return systask_iter(code, this); }
|
2012-01-20 00:04:51 +01:00
|
|
|
};
|
2010-06-09 20:56:00 +02:00
|
|
|
|
2014-01-21 04:07:11 +01:00
|
|
|
|
|
|
|
|
// support getting vpiSize for a system function call
|
|
|
|
|
int sysfunc_4net::vpi_get(int code)
|
|
|
|
|
{
|
|
|
|
|
switch (code) {
|
|
|
|
|
case vpiSize:
|
|
|
|
|
return vwid_;
|
|
|
|
|
|
|
|
|
|
case vpiLineNo:
|
|
|
|
|
return lineno;
|
|
|
|
|
|
|
|
|
|
case vpiUserDefn:
|
|
|
|
|
return defn->is_user_defn;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return vpiUndefined;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int)
|
|
|
|
|
{
|
|
|
|
|
put_value = true;
|
|
|
|
|
|
|
|
|
|
vvp_vector4_t val (vwid_);
|
|
|
|
|
|
|
|
|
|
switch (vp->format) {
|
|
|
|
|
|
|
|
|
|
case vpiScalarVal: {
|
|
|
|
|
switch(vp->value.scalar) {
|
|
|
|
|
case vpi0:
|
|
|
|
|
val.set_bit(0, BIT4_0);
|
|
|
|
|
break;
|
|
|
|
|
case vpi1:
|
|
|
|
|
val.set_bit(0, BIT4_1);
|
|
|
|
|
break;
|
|
|
|
|
case vpiX:
|
|
|
|
|
val.set_bit(0, BIT4_X);
|
|
|
|
|
break;
|
|
|
|
|
case vpiZ:
|
|
|
|
|
val.set_bit(0, BIT4_Z);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "Unsupported bit value %d.\n",
|
|
|
|
|
(int)vp->value.scalar);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case vpiIntVal: {
|
|
|
|
|
long tmp = vp->value.integer;
|
|
|
|
|
for (unsigned idx = 0 ; idx < vwid_ ; idx += 1) {
|
|
|
|
|
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
|
|
|
|
tmp >>= 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case vpiTimeVal: {
|
|
|
|
|
unsigned long tmp = vp->value.time->low;
|
|
|
|
|
for (unsigned idx = 0 ; idx < vwid_ ; idx += 1) {
|
|
|
|
|
val.set_bit(idx, (tmp&1)? BIT4_1 : BIT4_0);
|
|
|
|
|
|
|
|
|
|
if (idx == 31)
|
|
|
|
|
tmp = vp->value.time->high;
|
|
|
|
|
else
|
|
|
|
|
tmp >>= 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case vpiVectorVal:
|
|
|
|
|
|
|
|
|
|
for (unsigned wdx = 0 ; wdx < vwid_ ; wdx += 32) {
|
|
|
|
|
unsigned word = wdx / 32;
|
|
|
|
|
unsigned long aval = vp->value.vector[word].aval;
|
|
|
|
|
unsigned long bval = vp->value.vector[word].bval;
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; (wdx+idx) < vwid_ && idx < 32;
|
|
|
|
|
idx += 1) {
|
|
|
|
|
int bit = (aval&1) | ((bval<<1)&2);
|
|
|
|
|
vvp_bit4_t bit4;
|
|
|
|
|
|
|
|
|
|
switch (bit) {
|
|
|
|
|
case 0:
|
|
|
|
|
bit4 = BIT4_0;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
bit4 = BIT4_1;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
bit4 = BIT4_Z;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
bit4 = BIT4_X;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
bit4 = BIT4_X;
|
|
|
|
|
fprintf(stderr, "Unsupported bit value %d.\n",
|
|
|
|
|
bit);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
val.set_bit(wdx+idx, bit4);
|
|
|
|
|
|
|
|
|
|
aval >>= 1;
|
|
|
|
|
bval >>= 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "XXXX format=%d, vwid_=%u\n", (int)vp->format, vwid_);
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fnet->send_vec4(val, vthread_get_wt_context());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-01-01 18:45:02 +01:00
|
|
|
/* **** Manipulate the internal data structures. **** */
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
/*
|
|
|
|
|
* We keep a table of all the __vpiUserSystf objects that are created
|
|
|
|
|
* so that the user can iterate over them. The def_table is an array
|
|
|
|
|
* of pointers to __vpiUserSystf objects. This table can be searched
|
|
|
|
|
* by name using the vpi_find_systf function, and they can be
|
|
|
|
|
* collected into an iterator using the vpip_make_systf_iterator function.
|
|
|
|
|
*/
|
2001-03-16 02:44:34 +01:00
|
|
|
static struct __vpiUserSystf**def_table = 0;
|
|
|
|
|
static unsigned def_count = 0;
|
|
|
|
|
|
|
|
|
|
static struct __vpiUserSystf* allocate_def(void)
|
|
|
|
|
{
|
|
|
|
|
if (def_table == 0) {
|
|
|
|
|
def_table = (struct __vpiUserSystf**)
|
|
|
|
|
malloc(sizeof (struct __vpiUserSystf*));
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
def_table[0] = new __vpiUserSystf;
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
def_count = 1;
|
|
|
|
|
return def_table[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def_table = (struct __vpiUserSystf**)
|
|
|
|
|
realloc(def_table, (def_count+1)*sizeof (struct __vpiUserSystf*));
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
def_table[def_count] = new __vpiUserSystf;
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
return def_table[def_count++];
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2009-01-24 01:04:44 +01:00
|
|
|
void def_table_delete(void)
|
|
|
|
|
{
|
|
|
|
|
for (unsigned idx = 0; idx < def_count; idx += 1) {
|
|
|
|
|
free(const_cast<char *>(def_table[idx]->info.tfname));
|
2012-01-19 19:16:39 +01:00
|
|
|
delete def_table[idx];
|
2009-01-24 01:04:44 +01:00
|
|
|
}
|
|
|
|
|
free(def_table);
|
|
|
|
|
def_table = 0;
|
|
|
|
|
def_count = 0;
|
|
|
|
|
}
|
2009-01-30 02:23:09 +01:00
|
|
|
#endif
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSystfIterator : public __vpiHandle {
|
|
|
|
|
__vpiSystfIterator();
|
2012-01-20 00:04:51 +01:00
|
|
|
int get_type_code(void) const;
|
2012-01-20 20:39:48 +01:00
|
|
|
vpiHandle vpi_index(int idx);
|
2012-01-20 23:15:26 +01:00
|
|
|
free_object_fun_t free_object_fun(void);
|
2012-01-20 00:04:51 +01:00
|
|
|
|
2010-04-12 08:39:08 +02:00
|
|
|
unsigned next;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static vpiHandle systf_iterator_scan(vpiHandle ref, int)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref);
|
2010-04-12 08:39:08 +02:00
|
|
|
|
|
|
|
|
if (obj->next >= def_count) {
|
|
|
|
|
vpi_free_object(ref);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned use_index = obj->next;
|
|
|
|
|
while (!def_table[use_index]->is_user_defn) {
|
|
|
|
|
obj->next += 1;
|
|
|
|
|
use_index = obj->next;
|
|
|
|
|
if (obj->next >= def_count) {
|
|
|
|
|
vpi_free_object(ref);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
obj->next += 1;
|
2012-01-19 19:16:39 +01:00
|
|
|
return def_table[use_index];
|
2010-04-12 08:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int systf_iterator_free_object(vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref);
|
|
|
|
|
delete obj;
|
2010-04-12 08:39:08 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
inline __vpiSystfIterator::__vpiSystfIterator()
|
2012-01-20 23:15:26 +01:00
|
|
|
{ }
|
2010-04-12 08:39:08 +02:00
|
|
|
|
2012-01-20 00:04:51 +01:00
|
|
|
int __vpiSystfIterator::get_type_code(void) const
|
|
|
|
|
{ return vpiIterator; }
|
|
|
|
|
|
2012-01-20 20:39:48 +01:00
|
|
|
vpiHandle __vpiSystfIterator::vpi_index(int idx)
|
|
|
|
|
{ return systf_iterator_scan(this, idx); }
|
|
|
|
|
|
2012-01-20 23:15:26 +01:00
|
|
|
__vpiHandle::free_object_fun_t __vpiSystfIterator::free_object_fun(void)
|
|
|
|
|
{ return &systf_iterator_free_object; }
|
|
|
|
|
|
2010-04-12 08:39:08 +02:00
|
|
|
vpiHandle vpip_make_systf_iterator(void)
|
|
|
|
|
{
|
|
|
|
|
/* Check to see if there are any user defined functions. */
|
|
|
|
|
bool have_user_defn = false;
|
|
|
|
|
unsigned idx;
|
|
|
|
|
for (idx = 0; idx < def_count; idx += 1) {
|
|
|
|
|
if (def_table[idx]->is_user_defn) {
|
|
|
|
|
have_user_defn = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!have_user_defn) return 0;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSystfIterator*res = new __vpiSystfIterator;
|
2010-04-12 08:39:08 +02:00
|
|
|
res->next = idx;
|
2012-01-19 19:16:39 +01:00
|
|
|
return res;
|
2010-04-12 08:39:08 +02:00
|
|
|
}
|
|
|
|
|
|
2006-06-18 06:15:50 +02:00
|
|
|
struct __vpiUserSystf* vpip_find_systf(const char*name)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
|
|
|
|
for (unsigned idx = 0 ; idx < def_count ; idx += 1)
|
|
|
|
|
if (strcmp(def_table[idx]->info.tfname, name) == 0)
|
|
|
|
|
return def_table[idx];
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-12 08:39:08 +02:00
|
|
|
void vpip_make_systf_system_defined(vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref);
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiUserSystf*obj = dynamic_cast<__vpiUserSystf*>(ref);
|
|
|
|
|
assert(obj);
|
2010-04-12 08:39:08 +02:00
|
|
|
obj->is_user_defn = false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-08 04:12:39 +02:00
|
|
|
/*
|
|
|
|
|
* To get better error message we need to cache the vpi_call fail
|
|
|
|
|
* information so that we can print the file name.
|
|
|
|
|
*/
|
|
|
|
|
enum vpi_call_error_type {VPI_CALL_NO_DEF, VPI_CALL_TASK_AS_FUNC,
|
2010-06-09 20:56:00 +02:00
|
|
|
VPI_CALL_FUNC_AS_TASK, VPI_CALL_FUNC_AS_TASK_WARN};
|
2010-06-08 04:12:39 +02:00
|
|
|
typedef struct vpi_call_error {
|
|
|
|
|
vpi_call_error_type type;
|
|
|
|
|
char *name;
|
|
|
|
|
long file_idx;
|
|
|
|
|
long lineno;
|
|
|
|
|
} vpi_call_error_s, *vpi_call_error_p;
|
|
|
|
|
|
|
|
|
|
static vpi_call_error_p vpi_call_error_lst = NULL;
|
|
|
|
|
static unsigned vpi_call_error_num = 0;
|
|
|
|
|
|
|
|
|
|
static void add_vpi_call_error(vpi_call_error_type type, const char *name,
|
|
|
|
|
long file_idx, long lineno)
|
|
|
|
|
{
|
|
|
|
|
vpi_call_error_lst = (vpi_call_error_p)
|
|
|
|
|
realloc((void *)vpi_call_error_lst,
|
|
|
|
|
(vpi_call_error_num + 1) *
|
|
|
|
|
sizeof(vpi_call_error_s));
|
|
|
|
|
vpi_call_error_lst[vpi_call_error_num].type = type;
|
|
|
|
|
vpi_call_error_lst[vpi_call_error_num].name = strdup(name);
|
|
|
|
|
vpi_call_error_lst[vpi_call_error_num].file_idx = file_idx;
|
|
|
|
|
vpi_call_error_lst[vpi_call_error_num].lineno = lineno;
|
|
|
|
|
vpi_call_error_num += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void print_vpi_call_errors()
|
|
|
|
|
{
|
|
|
|
|
for (unsigned idx = 0; idx < vpi_call_error_num; idx += 1) {
|
|
|
|
|
switch (vpi_call_error_lst[idx].type) {
|
|
|
|
|
case VPI_CALL_NO_DEF:
|
|
|
|
|
fprintf(stderr, "%s:%d: Error: System task/function %s() is "
|
|
|
|
|
"not defined by any module.\n",
|
|
|
|
|
file_names[vpi_call_error_lst[idx].file_idx],
|
2010-06-09 20:56:00 +02:00
|
|
|
(int)vpi_call_error_lst[idx].lineno,
|
2010-06-08 04:12:39 +02:00
|
|
|
vpi_call_error_lst[idx].name);
|
|
|
|
|
break;
|
|
|
|
|
case VPI_CALL_TASK_AS_FUNC:
|
|
|
|
|
fprintf(stderr, "%s:%d: Error: %s() is a system task, it "
|
|
|
|
|
"cannot be called as a function.\n",
|
|
|
|
|
file_names[vpi_call_error_lst[idx].file_idx],
|
2010-06-09 20:56:00 +02:00
|
|
|
(int)vpi_call_error_lst[idx].lineno,
|
2010-06-08 04:12:39 +02:00
|
|
|
vpi_call_error_lst[idx].name);
|
|
|
|
|
break;
|
|
|
|
|
case VPI_CALL_FUNC_AS_TASK:
|
|
|
|
|
fprintf(stderr, "%s:%d: Error: %s() is a system function, it "
|
|
|
|
|
"cannot be called as a task.\n",
|
|
|
|
|
file_names[vpi_call_error_lst[idx].file_idx],
|
2010-06-09 20:56:00 +02:00
|
|
|
(int)vpi_call_error_lst[idx].lineno,
|
|
|
|
|
vpi_call_error_lst[idx].name);
|
|
|
|
|
break;
|
|
|
|
|
case VPI_CALL_FUNC_AS_TASK_WARN:
|
|
|
|
|
fprintf(stderr, "%s:%d: Warning: Calling system function "
|
|
|
|
|
"%s() as a task.\n",
|
|
|
|
|
file_names[vpi_call_error_lst[idx].file_idx],
|
|
|
|
|
(int)vpi_call_error_lst[idx].lineno,
|
2010-06-08 04:12:39 +02:00
|
|
|
vpi_call_error_lst[idx].name);
|
2010-06-09 20:56:00 +02:00
|
|
|
fprintf(stderr, "%s:%d: The functions return "
|
|
|
|
|
"value will be ignored.\n",
|
|
|
|
|
file_names[vpi_call_error_lst[idx].file_idx],
|
|
|
|
|
(int)vpi_call_error_lst[idx].lineno);
|
2010-06-08 04:12:39 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
free(vpi_call_error_lst[idx].name);
|
|
|
|
|
}
|
|
|
|
|
free(vpi_call_error_lst);
|
2011-05-22 15:26:08 +02:00
|
|
|
fflush(stderr);
|
2010-06-08 04:12:39 +02:00
|
|
|
}
|
|
|
|
|
|
2010-10-11 06:52:26 +02:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2010-06-15 04:29:38 +02:00
|
|
|
static void cleanup_vpi_call_args(unsigned argc, vpiHandle*argv)
|
|
|
|
|
{
|
|
|
|
|
if (argc) {
|
2013-01-04 02:49:29 +01:00
|
|
|
/* Since this is just being used to cleanup the arguments a
|
|
|
|
|
* system task definition can be used. */
|
|
|
|
|
struct __vpiSysTaskCall*obj = new systask_def;
|
2010-06-15 04:29:38 +02:00
|
|
|
obj->nargs = argc;
|
|
|
|
|
obj->args = argv;
|
2013-01-04 02:49:29 +01:00
|
|
|
vpi_call_delete(obj);
|
2010-06-15 04:29:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
2010-10-11 06:52:26 +02:00
|
|
|
#endif
|
2010-06-15 04:29:38 +02:00
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
/*
|
|
|
|
|
* A vpi_call is actually built up into a vpiSysTaskCall VPI object
|
|
|
|
|
* that refers back to the vpiUserSystf VPI object that is the
|
|
|
|
|
* definition. So this function is called by the compiler when a
|
|
|
|
|
* %vpi_call statement is encountered. Create here a vpiHandle that
|
|
|
|
|
* describes the call, and return it. The %vpi_call instruction will
|
|
|
|
|
* store this handle for when it is executed.
|
|
|
|
|
*/
|
2014-01-04 23:06:58 +01:00
|
|
|
vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_width,
|
2012-02-12 22:21:30 +01:00
|
|
|
vvp_net_t*fnet,
|
2010-06-09 20:56:00 +02:00
|
|
|
bool func_as_task_err, bool func_as_task_warn,
|
2008-01-01 18:45:02 +01:00
|
|
|
unsigned argc, vpiHandle*argv,
|
2014-01-04 23:06:58 +01:00
|
|
|
unsigned vec4_stack, unsigned real_stack, unsigned string_stack,
|
2008-04-30 03:58:25 +02:00
|
|
|
long file_idx, long lineno)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
2010-06-09 20:56:00 +02:00
|
|
|
assert(!(func_as_task_err && func_as_task_warn));
|
|
|
|
|
|
2001-05-20 02:46:12 +02:00
|
|
|
struct __vpiUserSystf*defn = vpip_find_systf(name);
|
|
|
|
|
if (defn == 0) {
|
2010-06-08 04:12:39 +02:00
|
|
|
add_vpi_call_error(VPI_CALL_NO_DEF, name, file_idx, lineno);
|
2010-10-11 06:52:26 +02:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2010-06-15 04:29:38 +02:00
|
|
|
cleanup_vpi_call_args(argc, argv);
|
2010-10-11 06:52:26 +02:00
|
|
|
#endif
|
2001-03-22 23:38:13 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2001-05-20 02:46:12 +02:00
|
|
|
switch (defn->info.type) {
|
|
|
|
|
case vpiSysTask:
|
2014-01-04 23:06:58 +01:00
|
|
|
if (val_code != 0 || fnet != 0) {
|
2010-06-08 04:12:39 +02:00
|
|
|
add_vpi_call_error(VPI_CALL_TASK_AS_FUNC, name, file_idx,
|
|
|
|
|
lineno);
|
2010-10-11 06:52:26 +02:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2010-06-15 04:29:38 +02:00
|
|
|
cleanup_vpi_call_args(argc, argv);
|
2010-10-11 06:52:26 +02:00
|
|
|
#endif
|
2001-08-03 08:50:44 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2001-05-20 02:46:12 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case vpiSysFunc:
|
2014-01-04 23:06:58 +01:00
|
|
|
if (val_code == 0 && fnet == 0) {
|
2010-06-09 20:56:00 +02:00
|
|
|
if (func_as_task_err) {
|
|
|
|
|
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK,
|
|
|
|
|
name, file_idx, lineno);
|
2010-10-11 06:52:26 +02:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
2010-06-15 04:29:38 +02:00
|
|
|
cleanup_vpi_call_args(argc, argv);
|
2010-10-11 06:52:26 +02:00
|
|
|
#endif
|
2010-06-09 20:56:00 +02:00
|
|
|
return 0;
|
|
|
|
|
} else if (func_as_task_warn) {
|
|
|
|
|
add_vpi_call_error(VPI_CALL_FUNC_AS_TASK_WARN,
|
|
|
|
|
name, file_idx, lineno);
|
|
|
|
|
}
|
2001-08-03 08:50:44 +02:00
|
|
|
}
|
2001-05-20 02:46:12 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2010-06-09 20:56:00 +02:00
|
|
|
fprintf(stderr, "Unsupported vpi_call type %d.\n",
|
2010-06-08 04:12:39 +02:00
|
|
|
(int)defn->info.type);
|
2001-05-20 02:46:12 +02:00
|
|
|
assert(0);
|
2001-08-03 08:50:44 +02:00
|
|
|
}
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*obj = 0;
|
2001-05-20 02:46:12 +02:00
|
|
|
|
2001-08-03 08:50:44 +02:00
|
|
|
switch (defn->info.type) {
|
|
|
|
|
case vpiSysTask:
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new systask_def;
|
2001-08-03 08:50:44 +02:00
|
|
|
break;
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2001-08-03 08:50:44 +02:00
|
|
|
case vpiSysFunc:
|
2014-01-04 23:06:58 +01:00
|
|
|
if (fnet && val_code == -vpiRealVal) {
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new sysfunc_rnet;
|
2003-01-27 01:14:37 +01:00
|
|
|
|
2014-01-21 04:07:11 +01:00
|
|
|
} else if (fnet && val_code == -vpiVectorVal) {
|
|
|
|
|
obj = new sysfunc_4net(return_width);
|
2003-01-27 01:14:37 +01:00
|
|
|
|
2014-01-04 23:06:58 +01:00
|
|
|
} else if (val_code == -vpiRealVal) {
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new sysfunc_real;
|
2003-01-27 01:14:37 +01:00
|
|
|
|
2014-01-04 23:06:58 +01:00
|
|
|
} else if (val_code == -vpiVectorVal) {
|
|
|
|
|
obj = new sysfunc_vec4(return_width);
|
|
|
|
|
|
|
|
|
|
} else if (val_code == 0 && fnet == 0) {
|
2012-01-20 00:04:51 +01:00
|
|
|
obj = new sysfunc_no;
|
2010-06-09 20:56:00 +02:00
|
|
|
|
2006-06-18 06:15:50 +02:00
|
|
|
} else {
|
2014-01-04 23:06:58 +01:00
|
|
|
fprintf(stderr, "XXXX fnet=%p, val_code=%d\n", fnet, val_code);
|
2006-06-18 06:15:50 +02:00
|
|
|
assert(0);
|
2003-01-27 01:14:37 +01:00
|
|
|
}
|
2001-08-03 08:50:44 +02:00
|
|
|
break;
|
2001-05-20 02:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj->scope = vpip_peek_current_scope();
|
|
|
|
|
obj->defn = defn;
|
|
|
|
|
obj->nargs = argc;
|
|
|
|
|
obj->args = argv;
|
2014-01-04 23:06:58 +01:00
|
|
|
obj->vec4_stack = vec4_stack;
|
2012-10-23 02:20:43 +02:00
|
|
|
obj->real_stack = real_stack;
|
|
|
|
|
obj->string_stack = string_stack;
|
2006-06-18 06:15:50 +02:00
|
|
|
obj->fnet = fnet;
|
2008-01-01 18:45:02 +01:00
|
|
|
obj->file_idx = (unsigned) file_idx;
|
2008-04-30 03:58:25 +02:00
|
|
|
obj->lineno = (unsigned) lineno;
|
2008-01-01 18:45:02 +01:00
|
|
|
obj->userdata = 0;
|
2008-05-28 00:11:17 +02:00
|
|
|
obj->put_value = false;
|
2001-05-20 02:46:12 +02:00
|
|
|
|
2007-07-25 03:24:24 +02:00
|
|
|
compile_compiletf(obj);
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return obj;
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2009-01-30 02:23:09 +01:00
|
|
|
#ifdef CHECK_WITH_VALGRIND
|
|
|
|
|
void vpi_call_delete(vpiHandle item)
|
|
|
|
|
{
|
2012-01-20 00:04:51 +01:00
|
|
|
struct __vpiSysTaskCall*obj = dynamic_cast<__vpiSysTaskCall*>(item);
|
2010-06-15 04:29:38 +02:00
|
|
|
/* The object can be NULL if there was an error. */
|
|
|
|
|
if (!obj) return;
|
2009-01-30 02:23:09 +01:00
|
|
|
for (unsigned arg = 0; arg < obj->nargs; arg += 1) {
|
2012-10-09 03:52:24 +02:00
|
|
|
switch (obj->args[arg]->get_type_code()) {
|
2009-01-30 02:23:09 +01:00
|
|
|
case vpiConstant:
|
|
|
|
|
switch (vpi_get(_vpiFromThr, obj->args[arg])) {
|
|
|
|
|
case _vpiNoThr:
|
|
|
|
|
constant_delete(obj->args[arg]);
|
2012-12-18 20:08:30 +01:00
|
|
|
break;
|
|
|
|
|
case _vpiString:
|
|
|
|
|
thread_string_delete(obj->args[arg]);
|
2009-01-30 02:23:09 +01:00
|
|
|
break;
|
|
|
|
|
case _vpiVThr:
|
|
|
|
|
thread_vthr_delete(obj->args[arg]);
|
|
|
|
|
break;
|
|
|
|
|
case _vpiWord:
|
|
|
|
|
thread_word_delete(obj->args[arg]);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2009-02-03 00:44:50 +01:00
|
|
|
assert(0);
|
2009-01-30 02:23:09 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case vpiMemoryWord:
|
2013-01-02 01:52:50 +01:00
|
|
|
switch (vpi_get(_vpiFromThr, obj->args[arg])) {
|
|
|
|
|
case _vpi_at_A:
|
2009-01-30 02:23:09 +01:00
|
|
|
A_delete(obj->args[arg]);
|
2013-01-02 01:52:50 +01:00
|
|
|
break;
|
|
|
|
|
case _vpi_at_APV:
|
|
|
|
|
APV_delete(obj->args[arg]);
|
|
|
|
|
break;
|
2009-01-30 02:23:09 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case vpiPartSelect:
|
|
|
|
|
assert(vpi_get(_vpiFromThr, obj->args[arg]) == _vpi_at_PV);
|
|
|
|
|
PV_delete(obj->args[arg]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(obj->args);
|
|
|
|
|
delete obj;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2001-03-16 02:44:34 +01:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function is used by the %vpi_call instruction to actually
|
|
|
|
|
* place the call to the system task/function. For now, only support
|
|
|
|
|
* calls to system tasks.
|
|
|
|
|
*/
|
2001-05-10 02:26:53 +02:00
|
|
|
|
|
|
|
|
vthread_t vpip_current_vthread;
|
|
|
|
|
|
|
|
|
|
void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
2001-05-10 02:26:53 +02:00
|
|
|
vpip_current_vthread = thr;
|
|
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
vpip_cur_task = dynamic_cast<__vpiSysTaskCall*>(ref);
|
2001-03-16 02:44:34 +01:00
|
|
|
|
2002-05-18 04:34:11 +02:00
|
|
|
if (vpip_cur_task->defn->info.calltf) {
|
|
|
|
|
assert(vpi_mode_flag == VPI_MODE_NONE);
|
|
|
|
|
vpi_mode_flag = VPI_MODE_CALLTF;
|
2008-05-28 00:11:17 +02:00
|
|
|
vpip_cur_task->put_value = false;
|
2002-05-09 05:34:31 +02:00
|
|
|
vpip_cur_task->defn->info.calltf(vpip_cur_task->defn->info.user_data);
|
2002-05-18 04:34:11 +02:00
|
|
|
vpi_mode_flag = VPI_MODE_NONE;
|
2008-05-28 00:11:17 +02:00
|
|
|
/* If the function call did not set a value then put a
|
|
|
|
|
* default value (0). */
|
2012-01-19 19:16:39 +01:00
|
|
|
if (ref->get_type_code() == vpiSysFuncCall &&
|
2008-05-28 00:11:17 +02:00
|
|
|
!vpip_cur_task->put_value) {
|
|
|
|
|
s_vpi_value val;
|
2014-01-21 04:07:11 +01:00
|
|
|
val.format = vpiIntVal;
|
|
|
|
|
val.value.integer = 0;
|
2008-05-28 00:11:17 +02:00
|
|
|
vpi_put_value(ref, &val, 0, vpiNoDelay);
|
|
|
|
|
}
|
2013-05-18 22:22:44 +02:00
|
|
|
}
|
2014-01-04 23:06:58 +01:00
|
|
|
if (vpip_cur_task->vec4_stack > 0)
|
|
|
|
|
vthread_pop_vec4(thr, vpip_cur_task->vec4_stack);
|
2013-05-18 22:22:44 +02:00
|
|
|
if (vpip_cur_task->real_stack > 0)
|
|
|
|
|
vthread_pop_real(thr, vpip_cur_task->real_stack);
|
|
|
|
|
if (vpip_cur_task->string_stack > 0)
|
|
|
|
|
vthread_pop_str(thr, vpip_cur_task->string_stack);
|
|
|
|
|
|
|
|
|
|
/* If the function has a real value, then push the value
|
|
|
|
|
to the thread stack. */
|
|
|
|
|
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
|
|
|
|
|
vthread_push_real(thr, func_real->return_value_);
|
2002-05-18 04:34:11 +02:00
|
|
|
}
|
2014-01-04 23:06:58 +01:00
|
|
|
if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) {
|
|
|
|
|
vthread_push_vec4(thr, func_vec4->return_value());
|
|
|
|
|
}
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is the entry function that a VPI module uses to hook a new
|
|
|
|
|
* task/function into the simulator. The function creates a new
|
|
|
|
|
* __vpi_userSystf to represent the definition for the calls that come
|
|
|
|
|
* to pass later.
|
|
|
|
|
*/
|
2010-04-11 23:28:45 +02:00
|
|
|
vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss)
|
2001-03-16 02:44:34 +01:00
|
|
|
{
|
|
|
|
|
struct __vpiUserSystf*cur = allocate_def();
|
2002-06-02 21:05:50 +02:00
|
|
|
assert(ss);
|
2001-06-25 05:12:06 +02:00
|
|
|
switch (ss->type) {
|
|
|
|
|
case vpiSysTask:
|
|
|
|
|
case vpiSysFunc:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2009-12-10 21:53:58 +01:00
|
|
|
fprintf(stderr, "Unsupported type %d.\n", (int)ss->type);
|
2001-06-25 05:12:06 +02:00
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
|
2001-03-16 02:44:34 +01:00
|
|
|
cur->info = *ss;
|
|
|
|
|
cur->info.tfname = strdup(ss->tfname);
|
2010-04-12 08:39:08 +02:00
|
|
|
cur->is_user_defn = true;
|
2010-04-11 23:28:45 +02:00
|
|
|
|
2012-01-19 19:16:39 +01:00
|
|
|
return cur;
|
2001-03-16 02:44:34 +01:00
|
|
|
}
|
|
|
|
|
|
2004-02-18 03:51:59 +01:00
|
|
|
PLI_INT32 vpi_put_userdata(vpiHandle ref, void*data)
|
2003-01-09 05:09:44 +01:00
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
|
|
|
|
if (rfp == 0)
|
2006-09-23 00:33:00 +02:00
|
|
|
return 0;
|
|
|
|
|
|
2003-01-09 05:09:44 +01:00
|
|
|
rfp->userdata = data;
|
2006-09-23 00:33:00 +02:00
|
|
|
return 1;
|
2003-01-09 05:09:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* vpi_get_userdata(vpiHandle ref)
|
|
|
|
|
{
|
2012-01-19 19:16:39 +01:00
|
|
|
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
|
|
|
|
assert(rfp);
|
2003-01-09 05:09:44 +01:00
|
|
|
|
|
|
|
|
return rfp->userdata;
|
|
|
|
|
}
|