1999-10-28 02:47:24 +02:00
|
|
|
/*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com)
|
1999-10-28 02:47:24 +02: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
|
|
|
|
|
*/
|
2000-02-23 03:56:53 +01:00
|
|
|
#if !defined(WINNT) && !defined(macintosh)
|
2000-07-26 05:53:11 +02:00
|
|
|
#ident "$Id: vpi_priv.c,v 1.8 2000/07/26 03:53:12 steve Exp $"
|
1999-10-28 02:47:24 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "vpi_priv.h"
|
|
|
|
|
# include <assert.h>
|
|
|
|
|
# include <stdarg.h>
|
|
|
|
|
# include <stdio.h>
|
|
|
|
|
# include <stdlib.h>
|
|
|
|
|
# include <string.h>
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Keep a list of vpi_systf_data structures. This list is searched
|
|
|
|
|
* forward whenever a function is invoked by name, and items are
|
|
|
|
|
* pushed in front of the list whenever they are registered. This
|
|
|
|
|
* allows entries to override older entries.
|
|
|
|
|
*/
|
|
|
|
|
struct systf_entry {
|
|
|
|
|
struct systf_entry* next;
|
|
|
|
|
s_vpi_systf_data systf_data;
|
|
|
|
|
};
|
|
|
|
|
|
2000-05-04 05:37:58 +02:00
|
|
|
static struct systf_entry*systf_func_list = 0;
|
|
|
|
|
static struct systf_entry*systf_task_list = 0;
|
1999-10-28 02:47:24 +02:00
|
|
|
|
|
|
|
|
/* This is the handle of the task currently being called. */
|
|
|
|
|
static struct __vpiSysTaskCall*vpip_cur_task;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void vpip_calltask(const char*fname, unsigned nparms, vpiHandle*parms)
|
|
|
|
|
{
|
|
|
|
|
struct systf_entry*idx;
|
|
|
|
|
struct __vpiSysTaskCall cur_task;
|
|
|
|
|
cur_task.base.vpi_type = &vpip_systask_rt;
|
2000-05-04 05:37:58 +02:00
|
|
|
cur_task.args = parms;
|
1999-10-28 02:47:24 +02:00
|
|
|
cur_task.nargs = nparms;
|
2000-05-04 05:37:58 +02:00
|
|
|
cur_task.res = 0;
|
|
|
|
|
cur_task.nres = 0;
|
1999-10-28 02:47:24 +02:00
|
|
|
|
|
|
|
|
vpip_cur_task = &cur_task;
|
|
|
|
|
|
|
|
|
|
/* Look for a systf function to invoke. */
|
2000-05-04 05:37:58 +02:00
|
|
|
for (idx = systf_task_list ; idx ; idx = idx->next)
|
1999-10-28 02:47:24 +02:00
|
|
|
if (strcmp(fname, idx->systf_data.tfname) == 0) {
|
|
|
|
|
cur_task.info = &idx->systf_data;
|
|
|
|
|
idx->systf_data.calltf(idx->systf_data.user_data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Finally, if nothing is found then something is not
|
|
|
|
|
right. Print out the function name all the parameters
|
|
|
|
|
passed, so that someone can deal with it. */
|
|
|
|
|
vpi_printf("Call %s\n", fname);
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-04 05:37:58 +02:00
|
|
|
/*
|
|
|
|
|
* System functions are kept in the same sort of table as the system
|
|
|
|
|
* tasks, and we call them in a similar manner.
|
|
|
|
|
*/
|
2000-05-07 20:20:07 +02:00
|
|
|
void vpip_callfunc(const char*fname, unsigned nres, vpip_bit_t*res,
|
|
|
|
|
unsigned nparms, vpiHandle*parms)
|
2000-05-04 05:37:58 +02:00
|
|
|
{
|
|
|
|
|
struct systf_entry*idx;
|
|
|
|
|
struct __vpiSysTaskCall cur_task;
|
|
|
|
|
cur_task.base.vpi_type = &vpip_sysfunc_rt;
|
2000-05-07 20:20:07 +02:00
|
|
|
cur_task.args = parms;
|
|
|
|
|
cur_task.nargs = nparms;
|
2000-05-04 05:37:58 +02:00
|
|
|
cur_task.res = res;
|
|
|
|
|
cur_task.nres = nres;
|
|
|
|
|
|
|
|
|
|
vpip_cur_task = &cur_task;
|
|
|
|
|
|
|
|
|
|
/* Look for a systf function to invoke. */
|
|
|
|
|
for (idx = systf_func_list ; idx ; idx = idx->next)
|
|
|
|
|
if (strcmp(fname, idx->systf_data.tfname) == 0) {
|
|
|
|
|
cur_task.info = &idx->systf_data;
|
|
|
|
|
idx->systf_data.calltf(idx->systf_data.user_data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Finally, if nothing is found then something is not
|
|
|
|
|
right. Print out the function name all the parameters
|
|
|
|
|
passed, so that someone can deal with it. */
|
|
|
|
|
vpi_printf("Call %s with width==%u\n", fname, nres);
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
|
|
|
|
|
int vpi_free_object(vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
free(ref);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-26 05:53:11 +02:00
|
|
|
static int vpip_get_global(int property)
|
|
|
|
|
{
|
|
|
|
|
switch (property) {
|
|
|
|
|
case vpiTimePrecision:
|
|
|
|
|
return vpip_simulation_obj.time_precision;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
int vpi_get(int property, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
if (property == vpiType)
|
|
|
|
|
return ref->vpi_type->type_code;
|
|
|
|
|
|
2000-07-26 05:53:11 +02:00
|
|
|
if (ref == 0)
|
|
|
|
|
return vpip_get_global(property);
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
if (ref->vpi_type->vpi_get_ == 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return (ref->vpi_type->vpi_get_)(property, ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char* vpi_get_str(int property, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
if (ref->vpi_type->vpi_get_str_ == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return (ref->vpi_type->vpi_get_str_)(property, ref);
|
|
|
|
|
}
|
|
|
|
|
|
2000-01-20 07:04:55 +01:00
|
|
|
void vpi_get_time(vpiHandle obj, s_vpi_time*t)
|
|
|
|
|
{
|
|
|
|
|
s_vpi_value value;
|
|
|
|
|
vpiHandle tm = vpip_sim_time();
|
|
|
|
|
value.format = vpiTimeVal;
|
|
|
|
|
vpi_get_value(tm, &value);
|
|
|
|
|
memcpy(t, value.value.time, sizeof (*t));
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
void vpi_get_value(vpiHandle expr, s_vpi_value*vp)
|
|
|
|
|
{
|
|
|
|
|
if (expr->vpi_type->vpi_get_value_) {
|
|
|
|
|
(expr->vpi_type->vpi_get_value_)(expr, vp);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vp->format = vpiSuppressVal;
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-15 05:01:14 +01:00
|
|
|
vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp,
|
|
|
|
|
s_vpi_time*tp, int flags)
|
|
|
|
|
{
|
|
|
|
|
if (obj->vpi_type->vpi_put_value_)
|
|
|
|
|
return (obj->vpi_type->vpi_put_value_)(obj, vp, tp, flags);
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
vpiHandle vpi_handle(int type, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
if (type == vpiSysTfCall) {
|
|
|
|
|
assert(ref == 0);
|
|
|
|
|
return &vpip_cur_task->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(ref->vpi_type->handle_);
|
|
|
|
|
return (ref->vpi_type->handle_)(type, ref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function asks the object to return an iterator for
|
|
|
|
|
* the specified reference. It is up to the iterate_ method to
|
|
|
|
|
* allocate a properly formed iterator.
|
|
|
|
|
*/
|
|
|
|
|
vpiHandle vpi_iterate(int type, vpiHandle ref)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->iterate_);
|
|
|
|
|
return (ref->vpi_type->iterate_)(type, ref);
|
|
|
|
|
}
|
|
|
|
|
|
2000-02-13 20:18:27 +01:00
|
|
|
vpiHandle vpi_handle_by_index(vpiHandle ref, int idx)
|
|
|
|
|
{
|
|
|
|
|
assert(ref->vpi_type->index_);
|
|
|
|
|
return (ref->vpi_type->index_)(ref, idx);
|
|
|
|
|
}
|
|
|
|
|
|
1999-10-28 02:47:24 +02:00
|
|
|
void vpi_printf(const char*fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
vprintf(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This function adds the information that the user supplies to a list
|
|
|
|
|
* that I keep.
|
|
|
|
|
*/
|
|
|
|
|
void vpi_register_systf(const struct t_vpi_systf_data*systf)
|
|
|
|
|
{
|
|
|
|
|
struct systf_entry*cur = calloc(1, sizeof(struct systf_entry));
|
|
|
|
|
cur->systf_data = *systf;
|
|
|
|
|
cur->systf_data.tfname = strdup(systf->tfname);
|
2000-05-04 05:37:58 +02:00
|
|
|
switch (systf->type) {
|
|
|
|
|
case vpiSysFunc:
|
|
|
|
|
cur->next = systf_func_list;
|
|
|
|
|
systf_func_list = cur;
|
|
|
|
|
break;
|
|
|
|
|
case vpiSysTask:
|
|
|
|
|
cur->next = systf_task_list;
|
|
|
|
|
systf_task_list = cur;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
1999-10-28 02:47:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: vpi_priv.c,v $
|
2000-07-26 05:53:11 +02:00
|
|
|
* Revision 1.8 2000/07/26 03:53:12 steve
|
|
|
|
|
* Make simulation precision available to VPI.
|
|
|
|
|
*
|
2000-05-07 20:20:07 +02:00
|
|
|
* Revision 1.7 2000/05/07 18:20:08 steve
|
|
|
|
|
* Import MCD support from Stephen Tell, and add
|
|
|
|
|
* system function parameter support to the IVL core.
|
|
|
|
|
*
|
2000-05-04 05:37:58 +02:00
|
|
|
* Revision 1.6 2000/05/04 03:37:59 steve
|
|
|
|
|
* Add infrastructure for system functions, move
|
|
|
|
|
* $time to that structure and add $random.
|
|
|
|
|
*
|
2000-02-23 03:56:53 +01:00
|
|
|
* Revision 1.5 2000/02/23 02:56:56 steve
|
|
|
|
|
* Macintosh compilers do not support ident.
|
|
|
|
|
*
|
2000-02-13 20:18:27 +01:00
|
|
|
* Revision 1.4 2000/02/13 19:18:28 steve
|
|
|
|
|
* Accept memory words as parameter to $display.
|
|
|
|
|
*
|
2000-01-20 07:04:55 +01:00
|
|
|
* Revision 1.3 2000/01/20 06:04:55 steve
|
|
|
|
|
* $dumpall checkpointing in VCD dump.
|
|
|
|
|
*
|
1999-12-15 05:01:14 +01:00
|
|
|
* Revision 1.2 1999/12/15 04:01:14 steve
|
|
|
|
|
* Add the VPI implementation of $readmemh.
|
|
|
|
|
*
|
1999-10-28 02:47:24 +02:00
|
|
|
* Revision 1.1 1999/10/28 00:47:25 steve
|
|
|
|
|
* Rewrite vvm VPI support to make objects more
|
|
|
|
|
* persistent, rewrite the simulation scheduler
|
|
|
|
|
* in C (to interface with VPI) and add VPI support
|
|
|
|
|
* for callbacks.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|