Rework vcd id-mapping for scalability

Huge designs have huge sets of unique nexus ids. Use more efficient
algorithms to map them and detect aliases.
This commit is contained in:
Stephen Williams 2010-01-06 10:46:39 -08:00
parent 3cef85b06b
commit 53ec59a97f
4 changed files with 83 additions and 96 deletions

View File

@ -33,6 +33,7 @@ includedir = $(prefix)/include
vpidir = $(libdir)/ivl$(suffix)
CC = @CC@
CXX = @CXX@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
@ -54,11 +55,15 @@ dep:
$(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
%.o: %.cc vpi_config.h
$(CXX) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o
mv $*.d dep
# Object files for system.vpi
O = sys_table.o sys_convert.o sys_deposit.o sys_display.o sys_fileio.o \
sys_finish.o sys_icarus.o sys_plusargs.o sys_random.o sys_random_mti.o \
sys_readmem.o sys_readmem_lex.o sys_scanf.o sys_sdf.o \
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o \
sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o vcd_priv2.o \
mt19937int.o sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o \
vams_simparam.o

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2010 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
@ -135,89 +135,6 @@ void vcd_names_sort(struct vcd_names_list_s*tab)
}
}
/*
Nexus Id cache
In structural models, many signals refer to the same nexus.
Some structural models also have very many signals. This cache
saves nexus_id - vcd_id pairs, and reuses the vcd_id when a signal
refers to a nexus that is already dumped.
The new signal will be listed as a $var, but no callback
will be installed. This saves considerable CPU time and leads
to smaller VCD files.
The _vpiNexusId is a private (int) property of IVL simulators.
*/
struct vcd_id_s
{
const char *id;
struct vcd_id_s *next;
int nex;
};
static __inline__ unsigned ihash(int nex)
{
unsigned a = nex;
a ^= a>>16;
a ^= a>>8;
return a & 0xff;
}
static struct vcd_id_s **vcd_ids = 0;
const char *find_nexus_ident(int nex)
{
struct vcd_id_s *bucket;
if (!vcd_ids) {
vcd_ids = (struct vcd_id_s **)
calloc(256, sizeof(struct vcd_id_s*));
assert(vcd_ids);
}
bucket = vcd_ids[ihash(nex)];
while (bucket) {
if (nex == bucket->nex)
return bucket->id;
bucket = bucket->next;
}
return 0;
}
void set_nexus_ident(int nex, const char *id)
{
struct vcd_id_s *bucket;
assert(vcd_ids);
bucket = (struct vcd_id_s *) malloc(sizeof(struct vcd_id_s));
bucket->next = vcd_ids[ihash(nex)];
bucket->id = id;
bucket->nex = nex;
vcd_ids[ihash(nex)] = bucket;
}
void nexus_ident_delete()
{
unsigned idx;
if (vcd_ids == 0) return;
for (idx = 0 ; idx < 256; idx++) {
struct vcd_id_s *cur, *tmp;
for (cur = vcd_ids[idx]; cur; cur = tmp) {
tmp = cur->next;
free(cur);
}
}
free(vcd_ids);
vcd_ids = 0;
}
/*
* Since the compiletf routines are all the same they are located here,
* so we only need a single copy. Some are generic enough they can use

View File

@ -1,7 +1,7 @@
#ifndef __vcd_priv_H
#define __vcd_priv_H
/*
* Copyright (c) 2003-2009 Stephen Williams (steve@icarus.com)
* Copyright (c) 2003-2010 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
@ -21,10 +21,16 @@
#include "vpi_user.h"
extern int is_escaped_id(const char *name);
#ifdef __cplusplus
# define EXTERN extern "C"
#else
# define EXTERN extern
#endif
EXTERN int is_escaped_id(const char *name);
struct vcd_names_s;
extern struct stringheap_s name_heap;
EXTERN struct stringheap_s name_heap;
struct vcd_names_list_s {
struct vcd_names_s *vcd_names_list;
@ -32,21 +38,23 @@ struct vcd_names_list_s {
int listed_names, sorted_names;
};
extern void vcd_names_add(struct vcd_names_list_s*tab, const char *name);
EXTERN void vcd_names_add(struct vcd_names_list_s*tab, const char *name);
extern const char *vcd_names_search(struct vcd_names_list_s*tab,
EXTERN const char *vcd_names_search(struct vcd_names_list_s*tab,
const char *key);
extern void vcd_names_sort(struct vcd_names_list_s*tab);
EXTERN void vcd_names_sort(struct vcd_names_list_s*tab);
extern void vcd_names_delete();
EXTERN void vcd_names_delete();
extern const char*find_nexus_ident(int nex);
extern void set_nexus_ident(int nex, const char *id);
EXTERN const char*find_nexus_ident(int nex);
EXTERN void set_nexus_ident(int nex, const char *id);
extern void nexus_ident_delete();
EXTERN void nexus_ident_delete();
/* The compiletf routines are common for the VCD, LXT and LXT2 dumpers. */
extern PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
EXTERN PLI_INT32 sys_dumpvars_compiletf(PLI_BYTE8 *name);
#undef EXTERN
#endif

57
vpi/vcd_priv2.cc Normal file
View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2010 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
*/
# include "vcd_priv.h"
# include <map>
/*
Nexus Id cache
In structural models, many signals refer to the same nexus.
Some structural models also have very many signals. This cache
saves nexus_id - vcd_id pairs, and reuses the vcd_id when a signal
refers to a nexus that is already dumped.
The new signal will be listed as a $var, but no callback
will be installed. This saves considerable CPU time and leads
to smaller VCD files.
The _vpiNexusId is a private (int) property of IVL simulators.
*/
static std::map<int,const char*> nexus_ident_map;
extern "C" const char*find_nexus_ident(int nex)
{
std::map<int,const char*>::const_iterator cur = nexus_ident_map.find(nex);
if (cur == nexus_ident_map.end())
return 0;
else
return cur->second;
}
extern "C" void set_nexus_ident(int nex, const char*id)
{
nexus_ident_map[nex] = id;
}
extern "C" void nexus_ident_delete()
{
nexus_ident_map.clear();
}