iverilog/vvp/vpi_scope.cc

418 lines
11 KiB
C++
Raw Normal View History

2001-03-18 01:37:55 +01:00
/*
* Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com)
2001-03-18 01:37:55 +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
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: vpi_scope.cc,v 1.36 2006/04/10 00:37:43 steve Exp $"
2001-03-18 01:37:55 +01:00
#endif
# include "compile.h"
# include "vpi_priv.h"
# include "symbols.h"
# include "statistics.h"
2001-09-15 20:27:04 +02:00
#ifdef HAVE_MALLOC_H
2001-03-18 01:37:55 +01:00
# include <malloc.h>
2001-09-15 20:27:04 +02:00
#endif
# include <string.h>
2001-09-15 20:27:04 +02:00
# include <stdlib.h>
2001-03-18 01:37:55 +01:00
# include <assert.h>
2002-01-06 01:48:39 +01:00
static vpiHandle *vpip_root_table_ptr = 0;
static unsigned vpip_root_table_cnt = 0;
vpiHandle vpip_make_root_iterator(void)
{
assert(vpip_root_table_ptr);
assert(vpip_root_table_cnt);
return vpip_make_iterator(vpip_root_table_cnt,
vpip_root_table_ptr, false);
2002-01-06 01:48:39 +01:00
}
void vpip_make_root_iterator(struct __vpiHandle**&table, unsigned&ntable)
{
table = vpip_root_table_ptr;
ntable = vpip_root_table_cnt;
}
static bool handle_is_scope(vpiHandle obj)
{
return (obj->vpi_type->type_code == vpiModule)
|| (obj->vpi_type->type_code == vpiFunction)
|| (obj->vpi_type->type_code == vpiTask)
|| (obj->vpi_type->type_code == vpiNamedBegin)
|| (obj->vpi_type->type_code == vpiNamedFork);
}
static int scope_get(int code, vpiHandle obj)
{
struct __vpiScope*ref = (struct __vpiScope*)obj;
assert(handle_is_scope(obj));
switch (code) {
case vpiTimeUnit:
return ref->time_units;
2003-05-27 18:22:10 +02:00
case vpiTimePrecision:
return ref->time_precision;
case vpiTopModule:
return 0x0 == ref->scope;
}
return 0;
}
static void construct_scope_fullname(struct __vpiScope*ref, char*buf)
{
if (ref->scope) {
construct_scope_fullname(ref->scope, buf);
strcat(buf, ".");
}
strcat(buf, ref->name);
}
static const char* scope_get_type(int code)
{
switch (code) {
case vpiModule:
return "vpiModule";
case vpiFunction:
return "vpiFunction";
case vpiTask:
return "vpiTask";
case vpiNamedBegin:
return "vpiNamedBegin";
case vpiNamedFork:
return "vpiNamedFork";
default:
fprintf(stderr, "ERROR: invalid code %d.", code);
assert(0);
}
}
static char* scope_get_str(int code, vpiHandle obj)
{
struct __vpiScope*ref = (struct __vpiScope*)obj;
char *rbuf;
assert(handle_is_scope(obj));
switch (code) {
case vpiFullName: {
char buf[4096];
buf[0] = 0;
construct_scope_fullname(ref, buf);
rbuf = need_result_buf(strlen(buf) + 1, RBUF_STR);
strcpy(rbuf, buf);
return rbuf;
}
case vpiName:
rbuf = need_result_buf(strlen(ref->name) + 1, RBUF_STR);
strcpy(rbuf, ref->name);
return rbuf;
case vpiDefName:
rbuf = need_result_buf(strlen(ref->tname) + 1, RBUF_STR);
strcpy(rbuf, ref->tname);
return rbuf;
case vpiType:
rbuf = need_result_buf(strlen(scope_get_type(code)) + 1, RBUF_STR);
strcpy(rbuf, scope_get_type(code));
return rbuf;
default:
fprintf(stderr, "ERROR: invalid code %d.", code);
assert(0);
return 0;
}
}
static vpiHandle scope_get_handle(int code, vpiHandle obj)
{
assert((obj->vpi_type->type_code == vpiModule)
|| (obj->vpi_type->type_code == vpiFunction)
|| (obj->vpi_type->type_code == vpiTask)
|| (obj->vpi_type->type_code == vpiNamedBegin)
|| (obj->vpi_type->type_code == vpiNamedFork));
struct __vpiScope*rfp = (struct __vpiScope*)obj;
switch (code) {
case vpiScope:
return &rfp->scope->base;
case vpiModule:
return &rfp->scope->base;
}
return 0;
}
/* compares vpiType's considering object classes */
static int compare_types(int code, int type)
2002-07-14 04:52:05 +02:00
{
/* NOTE: The Verilog VPI does not for any object support
vpiScope as an iterator parameter, so it is used here as a
means to scan everything in the *current* scope. */
if (code == vpiScope)
return 1;
if (code == type)
return 1;
if ( code == vpiInternalScope &&
(type == vpiModule ||
type == vpiFunction ||
type == vpiTask ||
type == vpiNamedBegin ||
type == vpiNamedFork) )
return 1;
if ( code == vpiVariables &&
(type == vpiIntegerVar ||
type == vpiTimeVar ||
type == vpiRealVar))
return 1;
return 0;
2002-07-14 04:52:05 +02:00
}
static vpiHandle module_iter_subset(int code, struct __vpiScope*ref)
{
unsigned mcnt = 0, ncnt = 0;
vpiHandle*args;
for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1)
2002-07-14 04:52:05 +02:00
if (compare_types(code, ref->intern[idx]->vpi_type->type_code))
mcnt += 1;
if (mcnt == 0)
return 0;
args = (vpiHandle*)calloc(mcnt, sizeof(vpiHandle));
for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1)
2002-07-14 04:52:05 +02:00
if (compare_types(code, ref->intern[idx]->vpi_type->type_code))
args[ncnt++] = ref->intern[idx];
assert(ncnt == mcnt);
return vpip_make_iterator(mcnt, args, true);
}
/*
* This function implements the vpi_iterate method for vpiModule and
* similar objects. The vpi_iterate allows the user to iterate over
* things that are contained in the scope object, by generating an
* iterator for the requested set of items.
*/
static vpiHandle module_iter(int code, vpiHandle obj)
{
struct __vpiScope*ref = (struct __vpiScope*)obj;
assert((obj->vpi_type->type_code == vpiModule)
|| (obj->vpi_type->type_code == vpiFunction)
|| (obj->vpi_type->type_code == vpiTask)
|| (obj->vpi_type->type_code == vpiNamedBegin)
|| (obj->vpi_type->type_code == vpiNamedFork));
return module_iter_subset(code, ref);
}
static const struct __vpirt vpip_scope_module_rt = {
vpiModule,
scope_get,
scope_get_str,
0,
0,
scope_get_handle,
module_iter
};
static const struct __vpirt vpip_scope_task_rt = {
vpiTask,
scope_get,
scope_get_str,
0,
0,
scope_get_handle,
module_iter
};
static const struct __vpirt vpip_scope_function_rt = {
vpiFunction,
scope_get,
scope_get_str,
0,
0,
scope_get_handle,
module_iter
};
static const struct __vpirt vpip_scope_begin_rt = {
vpiNamedBegin,
scope_get,
scope_get_str,
0,
0,
scope_get_handle,
module_iter
};
static const struct __vpirt vpip_scope_fork_rt = {
vpiNamedFork,
scope_get,
scope_get_str,
0,
0,
scope_get_handle,
module_iter
};
/*
* The current_scope is a compile time concept. As the vvp source is
* compiled, items that have scope are placed in the current
* scope. The ".scope" directives select the scope that is current.
*/
2001-03-18 01:37:55 +01:00
static struct __vpiScope*current_scope = 0;
static void attach_to_scope_(struct __vpiScope*scope, vpiHandle obj)
{
assert(scope);
unsigned idx = scope->nintern++;
if (scope->intern == 0)
scope->intern = (vpiHandle*)
malloc(sizeof(vpiHandle));
else
scope->intern = (vpiHandle*)
realloc(scope->intern, sizeof(vpiHandle)*scope->nintern);
scope->intern[idx] = obj;
}
/*
* When the compiler encounters a scope declaration, this function
* creates and initializes a __vpiScope object with the requested name
* and within the addressed parent. The label is used as a key in the
* symbol table and the name is used to construct the actual object.
*/
void
compile_scope_decl(char*label, char*type, char*name, char*tname, char*parent)
2001-03-18 01:37:55 +01:00
{
2001-04-18 06:21:23 +02:00
struct __vpiScope*scope = new struct __vpiScope;
count_vpi_scopes += 1;
if (strcmp(type,"module") == 0)
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_module_rt;
else if (strcmp(type,"function") == 0)
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_function_rt;
else if (strcmp(type,"task") == 0)
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_task_rt;
else if (strcmp(type,"fork") == 0)
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_fork_rt;
else if (strcmp(type,"begin") == 0)
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_begin_rt;
else if (strcmp(type,"generate") == 0)
scope->base.vpi_type = &vpip_scope_begin_rt;
else {
2001-11-02 06:43:11 +01:00
scope->base.vpi_type = &vpip_scope_module_rt;
assert(0);
}
2001-11-02 06:43:11 +01:00
assert(scope->base.vpi_type);
scope->name = vpip_name_string(name);
scope->tname = vpip_name_string(tname);
2001-03-18 01:37:55 +01:00
scope->intern = 0;
scope->nintern = 0;
2001-04-18 06:21:23 +02:00
scope->threads = 0;
2001-03-18 01:37:55 +01:00
current_scope = scope;
compile_vpi_symbol(label, &scope->base);
2001-03-18 01:37:55 +01:00
free(label);
free(type);
free(name);
2001-03-18 01:37:55 +01:00
if (parent) {
static vpiHandle obj;
compile_vpi_lookup(&obj, parent);
assert(obj);
struct __vpiScope*sp = (struct __vpiScope*) obj;
2001-03-18 01:37:55 +01:00
attach_to_scope_(sp, &scope->base);
scope->scope = (struct __vpiScope*)obj;
/* Inherit time units and precision from the parent scope. */
scope->time_units = sp->time_units;
scope->time_precision = sp->time_precision;
} else {
scope->scope = 0x0;
2002-01-06 01:48:39 +01:00
unsigned cnt = vpip_root_table_cnt + 1;
vpip_root_table_ptr = (vpiHandle*)
realloc(vpip_root_table_ptr, cnt * sizeof(vpiHandle));
vpip_root_table_ptr[vpip_root_table_cnt] = &scope->base;
vpip_root_table_cnt = cnt;
/* Root scopes inherit time_units and precision from the
system precision. */
scope->time_units = vpip_get_time_precision();
scope->time_precision = vpip_get_time_precision();
2001-03-18 01:37:55 +01:00
}
2005-04-28 06:59:53 +02:00
#if 0
functor_set_scope(&current_scope->base);
2005-04-28 06:59:53 +02:00
#endif
2001-03-18 01:37:55 +01:00
}
void compile_scope_recall(char*symbol)
{
compile_vpi_lookup((vpiHandle*)&current_scope, symbol);
assert(current_scope);
2005-04-28 06:59:53 +02:00
#if 0
functor_set_scope(&current_scope->base);
2005-04-28 06:59:53 +02:00
#endif
2001-03-18 01:37:55 +01:00
}
/*
* This function handles the ".timescale" directive in the vvp
* source. It sets in the current scope the specified units value.
*/
void compile_timescale(long units, long precision)
{
assert(current_scope);
current_scope->time_units = units;
current_scope->time_precision = precision;
}
2001-04-18 06:21:23 +02:00
struct __vpiScope* vpip_peek_current_scope(void)
2001-03-18 01:37:55 +01:00
{
2001-04-18 06:21:23 +02:00
return current_scope;
2001-03-18 01:37:55 +01:00
}
void vpip_attach_to_current_scope(vpiHandle obj)
{
attach_to_scope_(current_scope, obj);
}