And the vvp_island infrastructure to the vvp runtime.
The vvp_island classes are added, as well as support for tranif nodes that use this concept. The result is a working implementation for tranif0 and tranif1. In the process, the symbol table functions were cleaned up and made into templates for better type safety, and the vvp_net_ptr_t was generalized so that it can be used by the branches in the island implementation. Also fix up the array handling to use the better symbol table support, and to remember to clear its own table when linking is done.
This commit is contained in:
parent
1be1f65f33
commit
052870c0e5
|
|
@ -79,7 +79,7 @@ O = main.o parse.o parse_misc.o lexor.o arith.o array.o bufif.o compile.o \
|
|||
concat.o \
|
||||
dff.o extend.o npmos.o part.o reduce.o resolv.o sfunc.o stop.o symbols.o \
|
||||
ufunc.o codes.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_net.o \
|
||||
vthread.o schedule.o statistics.o tables.o udp.o vvp_island.o vvp_net.o \
|
||||
event.o logic.o delay.o words.o $V
|
||||
|
||||
ifeq (@WIN32@,yes)
|
||||
|
|
|
|||
24
vvp/array.cc
24
vvp/array.cc
|
|
@ -30,7 +30,7 @@
|
|||
# include "compile.h"
|
||||
# include <assert.h>
|
||||
|
||||
static symbol_table_t array_table =0;
|
||||
static symbol_map_s<struct __vpiArray>* array_table =0;
|
||||
|
||||
class vvp_fun_arrayport;
|
||||
static void array_attach_port(vvp_array_t, vvp_fun_arrayport*);
|
||||
|
|
@ -40,8 +40,8 @@ vvp_array_t array_find(const char*label)
|
|||
if (array_table == 0)
|
||||
return 0;
|
||||
|
||||
symbol_value_t v = sym_get_value(array_table, label);
|
||||
return (vvp_array_t)v.ptr;
|
||||
vvp_array_t v = array_table->sym_get_value(label);
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -604,12 +604,10 @@ static vpiHandle vpip_make_array(char*label, const char*name,
|
|||
|
||||
/* Add this symbol to the array_symbols table for later lookup. */
|
||||
if (!array_table)
|
||||
array_table = new_symbol_table();
|
||||
array_table = new symbol_map_s<struct __vpiArray>;
|
||||
|
||||
assert(!array_find(label));
|
||||
symbol_value_t v;
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
array_table->sym_set_value(label, obj);
|
||||
|
||||
/* Add this into the table of VPI objects. This is used for
|
||||
contexts that try to look up VPI objects in
|
||||
|
|
@ -909,9 +907,7 @@ void compile_array_alias(char*label, char*name, char*src)
|
|||
|
||||
assert(array_table);
|
||||
assert(!array_find(label));
|
||||
symbol_value_t v;
|
||||
v.ptr = obj;
|
||||
sym_set_value(array_table, label, v);
|
||||
array_table->sym_set_value(label, obj);
|
||||
|
||||
compile_vpi_symbol(label, &obj->base);
|
||||
vpip_attach_to_current_scope(&obj->base);
|
||||
|
|
@ -936,3 +932,11 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr)
|
|||
|
||||
return &(obj->base);
|
||||
}
|
||||
|
||||
void compile_array_cleanup(void)
|
||||
{
|
||||
if (array_table) {
|
||||
delete array_table;
|
||||
array_table = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -645,6 +645,8 @@ void compile_cleanup(void)
|
|||
delete_symbol_table(sym_functors);
|
||||
sym_functors = 0;
|
||||
|
||||
compile_island_cleanup();
|
||||
|
||||
if (verbose_flag) {
|
||||
fprintf(stderr, " ... Compiletf functions\n");
|
||||
fflush(stderr);
|
||||
|
|
|
|||
|
|
@ -335,6 +335,8 @@ extern void compile_array_port(char*label, char*name, char*addr);
|
|||
/* Index is a constant address */
|
||||
extern void compile_array_port(char*label, char*name, long addr);
|
||||
|
||||
extern void compile_array_cleanup(void);
|
||||
|
||||
/*
|
||||
* Compile the .ufunc statement.
|
||||
*/
|
||||
|
|
@ -451,4 +453,14 @@ extern void compile_aliasw(char*label, char*array_symbol,
|
|||
unsigned long array_addr, int msb, int lsb,
|
||||
unsigned argc, struct symb_s*argv);
|
||||
|
||||
extern void compile_island(char*label, char*type);
|
||||
extern void compile_island_port(char*label, char*island, char*src);
|
||||
extern void compile_island_import(char*label, char*island, char*src);
|
||||
extern void compile_island_export(char*label, char*island);
|
||||
|
||||
extern void compile_island_tranif(int sense, char*island,
|
||||
char*ba, char*bb, char*src);
|
||||
|
||||
extern void compile_island_cleanup(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -124,8 +124,11 @@
|
|||
".dff" { return K_DFF; }
|
||||
".event" { return K_EVENT; }
|
||||
".event/or" { return K_EVENT_OR; }
|
||||
".export" { return K_EXPORT; }
|
||||
".extend/s" { return K_EXTEND_S; }
|
||||
".functor" { return K_FUNCTOR; }
|
||||
".import" { return K_IMPORT; }
|
||||
".island" { return K_ISLAND; }
|
||||
".modpath" { return K_MODPATH; }
|
||||
".net" { return K_NET; }
|
||||
".net8" { return K_NET8; }
|
||||
|
|
@ -138,6 +141,7 @@
|
|||
".part" { return K_PART; }
|
||||
".part/pv" { return K_PART_PV; }
|
||||
".part/v" { return K_PART_V; }
|
||||
".port" { return K_PORT; }
|
||||
".reduce/and" { return K_REDUCE_AND; }
|
||||
".reduce/or" { return K_REDUCE_OR; }
|
||||
".reduce/xor" { return K_REDUCE_XOR; }
|
||||
|
|
@ -153,6 +157,9 @@
|
|||
".shift/rs" { return K_SHIFTRS; }
|
||||
".thread" { return K_THREAD; }
|
||||
".timescale" { return K_TIMESCALE; }
|
||||
".tran" { return K_TRAN; }
|
||||
".tranif0" { return K_TRANIF0; }
|
||||
".tranif1" { return K_TRANIF1; }
|
||||
".ufunc" { return K_UFUNC; }
|
||||
".var" { return K_VAR; }
|
||||
".var/real" { return K_VAR_R; }
|
||||
|
|
|
|||
27
vvp/parse.y
27
vvp/parse.y
|
|
@ -74,13 +74,14 @@ static struct __vpiModPath*modpath_dst = 0;
|
|||
%token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R
|
||||
%token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S
|
||||
%token K_CONCAT K_DEBUG K_DELAY K_DFF
|
||||
%token K_EVENT K_EVENT_OR K_EXTEND_S K_FUNCTOR K_MODPATH K_NET K_NET_S K_NET_R
|
||||
%token K_EVENT K_EVENT_OR K_EXPORT K_EXTEND_S K_FUNCTOR K_IMPORT K_ISLAND
|
||||
%token K_MODPATH K_NET K_NET_S K_NET_R
|
||||
%token K_NET8 K_NET8_S
|
||||
%token K_PARAM_STR K_PARAM_L K_PARAM_REAL K_PART K_PART_PV
|
||||
%token K_PART_V K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
|
||||
%token K_PART_V K_PORT K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
|
||||
%token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT
|
||||
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
|
||||
%token K_THREAD K_TIMESCALE K_UFUNC
|
||||
%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_UFUNC
|
||||
%token K_UDP K_UDP_C K_UDP_S
|
||||
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
|
||||
%token K_disable K_fork
|
||||
|
|
@ -673,6 +674,26 @@ statement
|
|||
| T_LABEL K_PARAM_REAL T_STRING T_NUMBER T_NUMBER',' T_SYMBOL ';'
|
||||
{ compile_param_real($1, $3, $7, $4, $5); }
|
||||
|
||||
/* Islands */
|
||||
|
||||
| T_LABEL K_ISLAND T_SYMBOL ';'
|
||||
{ compile_island($1, $3); }
|
||||
|
||||
| T_LABEL K_PORT T_SYMBOL ',' T_SYMBOL ';'
|
||||
{ compile_island_port($1, $3, $5); }
|
||||
|
||||
| T_LABEL K_IMPORT T_SYMBOL ',' T_SYMBOL ';'
|
||||
{ compile_island_import($1, $3, $5); }
|
||||
|
||||
| T_LABEL K_EXPORT T_SYMBOL ';'
|
||||
{ compile_island_export($1, $3); }
|
||||
|
||||
| K_TRANIF0 T_SYMBOL ',' T_SYMBOL T_SYMBOL ',' T_SYMBOL ';'
|
||||
{ compile_island_tranif(0, $2, $4, $5, $7); }
|
||||
|
||||
| K_TRANIF1 T_SYMBOL ',' T_SYMBOL T_SYMBOL ',' T_SYMBOL ';'
|
||||
{ compile_island_tranif(1, $2, $4, $5, $7); }
|
||||
|
||||
/* Oh and by the way, empty statements are OK as well. */
|
||||
|
||||
| ';'
|
||||
|
|
|
|||
151
vvp/symbols.cc
151
vvp/symbols.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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
|
||||
|
|
@ -16,9 +16,6 @@
|
|||
* 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: symbols.cc,v 1.12 2004/10/04 01:10:59 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "symbols.h"
|
||||
# include <string.h>
|
||||
|
|
@ -42,26 +39,20 @@ struct key_strings {
|
|||
char data[64*1024 - sizeof(struct key_strings*)];
|
||||
};
|
||||
|
||||
struct symbol_table_s {
|
||||
struct tree_node_*root;
|
||||
struct key_strings*str_chunk;
|
||||
unsigned str_used;
|
||||
};
|
||||
|
||||
static char*key_strdup(struct symbol_table_s*tab, const char*str)
|
||||
char*symbol_table_s::key_strdup_(const char*str)
|
||||
{
|
||||
unsigned len = strlen(str);
|
||||
assert( (len+1) <= sizeof tab->str_chunk->data );
|
||||
assert( (len+1) <= sizeof str_chunk->data );
|
||||
|
||||
if ( (len+1) > (sizeof tab->str_chunk->data - tab->str_used) ) {
|
||||
if ( (len+1) > (sizeof str_chunk->data - str_used) ) {
|
||||
key_strings*tmp = new key_strings;
|
||||
tmp->next = tab->str_chunk;
|
||||
tab->str_chunk = tmp;
|
||||
tab->str_used = 0;
|
||||
tmp->next = str_chunk;
|
||||
str_chunk = tmp;
|
||||
str_used = 0;
|
||||
}
|
||||
|
||||
char*res = tab->str_chunk->data + tab->str_used;
|
||||
tab->str_used += len + 1;
|
||||
char*res = str_chunk->data + str_used;
|
||||
str_used += len + 1;
|
||||
strcpy(res, str);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -111,19 +102,16 @@ static inline char* node_last_key(struct tree_node_*node)
|
|||
* a root node, and initializing the pointers and members of the root
|
||||
* node.
|
||||
*/
|
||||
symbol_table_t new_symbol_table(void)
|
||||
symbol_table_s::symbol_table_s()
|
||||
{
|
||||
symbol_table_t tbl = new struct symbol_table_s;
|
||||
tbl->root = new struct tree_node_;
|
||||
tbl->root->leaf_flag = false;
|
||||
tbl->root->count = 0;
|
||||
tbl->root->parent = 0;
|
||||
root = new struct tree_node_;
|
||||
root->leaf_flag = false;
|
||||
root->count = 0;
|
||||
root->parent = 0;
|
||||
|
||||
tbl->str_chunk = new key_strings;
|
||||
tbl->str_chunk->next = 0;
|
||||
tbl->str_used = 0;
|
||||
|
||||
return tbl;
|
||||
str_chunk = new key_strings;
|
||||
str_chunk->next = 0;
|
||||
str_used = 0;
|
||||
}
|
||||
|
||||
static void delete_symbol_node(struct tree_node_*cur)
|
||||
|
|
@ -136,18 +124,6 @@ static void delete_symbol_node(struct tree_node_*cur)
|
|||
delete cur;
|
||||
}
|
||||
|
||||
void delete_symbol_table(symbol_table_t tab)
|
||||
{
|
||||
delete_symbol_node(tab->root);
|
||||
while (tab->str_chunk) {
|
||||
key_strings*tmp = tab->str_chunk;
|
||||
tab->str_chunk = tmp->next;
|
||||
delete tmp;
|
||||
}
|
||||
|
||||
delete tab;
|
||||
}
|
||||
|
||||
/* Do as split_leaf_ does, but for nodes. */
|
||||
static void split_node_(struct tree_node_*cur)
|
||||
{
|
||||
|
|
@ -286,7 +262,7 @@ static struct tree_node_* split_leaf_(struct tree_node_*cur)
|
|||
* true.
|
||||
*/
|
||||
|
||||
static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
||||
symbol_value_t symbol_table_s::find_value_(struct tree_node_*cur,
|
||||
const char*key, symbol_value_t val,
|
||||
bool force_flag)
|
||||
{
|
||||
|
|
@ -297,7 +273,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
|||
/* If we run out of keys in the leaf, then add
|
||||
this at the end of the leaf. */
|
||||
if (idx == cur->count) {
|
||||
cur->leaf[idx].key = key_strdup(tbl, key);
|
||||
cur->leaf[idx].key = key_strdup_(key);
|
||||
cur->leaf[idx].val = val;
|
||||
cur->count += 1;
|
||||
if (cur->count == leaf_width)
|
||||
|
|
@ -323,7 +299,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
|||
for (unsigned tmp = cur->count; tmp > idx; tmp -= 1)
|
||||
cur->leaf[tmp] = cur->leaf[tmp-1];
|
||||
|
||||
cur->leaf[idx].key = key_strdup(tbl, key);
|
||||
cur->leaf[idx].key = key_strdup_(key);
|
||||
cur->leaf[idx].val = val;
|
||||
cur->count += 1;
|
||||
if (cur->count == leaf_width)
|
||||
|
|
@ -343,17 +319,17 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
|||
for (;;) {
|
||||
int rc = strcmp(key, node_last_key(cur->child[idx]));
|
||||
if (rc == 0) {
|
||||
return find_value_(tbl, cur->child[idx],
|
||||
return find_value_(cur->child[idx],
|
||||
key, val, force_flag);
|
||||
}
|
||||
|
||||
if (rc > 0) {
|
||||
min = idx + 1;
|
||||
if (min == cur->count)
|
||||
return find_value_(tbl, cur->child[idx],
|
||||
return find_value_(cur->child[idx],
|
||||
key, val, force_flag);
|
||||
if (min == max)
|
||||
return find_value_(tbl, cur->child[max],
|
||||
return find_value_(cur->child[max],
|
||||
key, val, force_flag);
|
||||
|
||||
idx = min + (max-min)/2;
|
||||
|
|
@ -361,7 +337,7 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
|||
} else {
|
||||
max = idx;
|
||||
if (idx == min)
|
||||
return find_value_(tbl, cur->child[idx],
|
||||
return find_value_(cur->child[idx],
|
||||
key, val, force_flag);
|
||||
idx = min + (max-min)/2;
|
||||
}
|
||||
|
|
@ -375,90 +351,57 @@ static symbol_value_t find_value_(symbol_table_t tbl, struct tree_node_*cur,
|
|||
}
|
||||
}
|
||||
|
||||
void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val)
|
||||
void symbol_table_s::sym_set_value(const char*key, symbol_value_t val)
|
||||
{
|
||||
if (tbl->root->count == 0) {
|
||||
if (root->count == 0) {
|
||||
/* Handle the special case that this is the very first
|
||||
value in the symbol table. Create the first leaf node
|
||||
and initialize the pointers. */
|
||||
struct tree_node_*cur = new struct tree_node_;
|
||||
cur->leaf_flag = true;
|
||||
cur->parent = tbl->root;
|
||||
cur->parent = root;
|
||||
cur->count = 1;
|
||||
cur->leaf[0].key = key_strdup(tbl, key);
|
||||
cur->leaf[0].key = key_strdup_(key);
|
||||
cur->leaf[0].val = val;
|
||||
|
||||
tbl->root->count = 1;
|
||||
tbl->root->child[0] = cur;
|
||||
root->count = 1;
|
||||
root->child[0] = cur;
|
||||
} else {
|
||||
find_value_(tbl, tbl->root, key, val, true);
|
||||
find_value_(root, key, val, true);
|
||||
}
|
||||
}
|
||||
|
||||
symbol_value_t sym_get_value(symbol_table_t tbl, const char*key)
|
||||
symbol_value_t symbol_table_s::sym_get_value(const char*key)
|
||||
{
|
||||
symbol_value_t def;
|
||||
def.num = 0;
|
||||
|
||||
if (tbl->root->count == 0) {
|
||||
if (root->count == 0) {
|
||||
/* Handle the special case that this is the very first
|
||||
value in the symbol table. Create the first leaf node
|
||||
and initialize the pointers. */
|
||||
struct tree_node_*cur = new struct tree_node_;
|
||||
cur->leaf_flag = true;
|
||||
cur->parent = tbl->root;
|
||||
cur->parent = root;
|
||||
cur->count = 1;
|
||||
cur->leaf[0].key = key_strdup(tbl, key);
|
||||
cur->leaf[0].key = key_strdup_(key);
|
||||
cur->leaf[0].val = def;
|
||||
|
||||
tbl->root->count = 1;
|
||||
tbl->root->child[0] = cur;
|
||||
root->count = 1;
|
||||
root->child[0] = cur;
|
||||
return cur->leaf[0].val;
|
||||
} else {
|
||||
return find_value_(tbl, tbl->root, key, def, false);
|
||||
return find_value_(root, key, def, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* $Log: symbols.cc,v $
|
||||
* Revision 1.12 2004/10/04 01:10:59 steve
|
||||
* Clean up spurious trailing white space.
|
||||
*
|
||||
* Revision 1.11 2003/02/09 23:33:26 steve
|
||||
* Spelling fixes.
|
||||
*
|
||||
* Revision 1.10 2002/08/12 01:35:08 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.9 2002/07/15 00:21:42 steve
|
||||
* Fix initialization of symbol table string heap.
|
||||
*
|
||||
* Revision 1.8 2002/07/09 03:20:51 steve
|
||||
* Fix split of root btree node.
|
||||
*
|
||||
* Revision 1.7 2002/07/05 04:40:59 steve
|
||||
* Symbol table uses more efficient key string allocator,
|
||||
* and remove all the symbol tables after compile is done.
|
||||
*
|
||||
* Revision 1.6 2002/07/05 02:50:58 steve
|
||||
* Remove the vpi object symbol table after compile.
|
||||
*
|
||||
* Revision 1.5 2002/05/29 05:37:35 steve
|
||||
* Use binary search to speed up deep lookups.
|
||||
*
|
||||
* Revision 1.4 2001/11/02 04:48:03 steve
|
||||
* Implement split_node for symbol table (hendrik)
|
||||
*
|
||||
* Revision 1.3 2001/05/09 04:23:19 steve
|
||||
* Now that the interactive debugger exists,
|
||||
* there is no use for the output dump.
|
||||
*
|
||||
* Revision 1.2 2001/03/18 00:37:55 steve
|
||||
* Add support for vpi scopes.
|
||||
*
|
||||
* Revision 1.1 2001/03/11 00:29:39 steve
|
||||
* Add the vvp engine to cvs.
|
||||
*
|
||||
*/
|
||||
symbol_table_s::~symbol_table_s()
|
||||
{
|
||||
delete_symbol_node(root);
|
||||
while (str_chunk) {
|
||||
key_strings*tmp = str_chunk;
|
||||
str_chunk = tmp->next;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef __symbols_H
|
||||
#define __symbols_H
|
||||
/*
|
||||
* Copyright (c) 2001 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2001-2008 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
|
||||
|
|
@ -18,9 +18,6 @@
|
|||
* 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: symbols.h,v 1.5 2004/12/11 02:31:30 steve Exp $"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The symbol_table_t is intended as a means to hold and quickly index
|
||||
|
|
@ -46,7 +43,7 @@
|
|||
* try to look inside. The actual implementation is given in the
|
||||
* symbols.cc source file.
|
||||
*/
|
||||
typedef struct symbol_table_s *symbol_table_t;
|
||||
typedef class symbol_table_s *symbol_table_t;
|
||||
|
||||
typedef struct symbol_value_s {
|
||||
union {
|
||||
|
|
@ -56,6 +53,32 @@ typedef struct symbol_value_s {
|
|||
};
|
||||
} symbol_value_t;
|
||||
|
||||
|
||||
class symbol_table_s {
|
||||
public:
|
||||
explicit symbol_table_s();
|
||||
virtual ~symbol_table_s();
|
||||
|
||||
// This method locates the value in the symbol table and sets its
|
||||
// value. If the key doesn't yet exist, create it.
|
||||
void sym_set_value(const char*key, symbol_value_t val);
|
||||
|
||||
// This method locates the value in the symbol table and returns
|
||||
// it. If the value does not exist, create it, initialize it with
|
||||
// zero and return the zero value.
|
||||
symbol_value_t sym_get_value(const char*key);
|
||||
|
||||
private:
|
||||
struct tree_node_*root;
|
||||
struct key_strings*str_chunk;
|
||||
unsigned str_used;
|
||||
|
||||
symbol_value_t find_value_(struct tree_node_*cur,
|
||||
const char*key, symbol_value_t val,
|
||||
bool force_flag);
|
||||
char*key_strdup_(const char*str);
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a new symbol table or release an existing one. A new symbol
|
||||
* table has no keys and no values. As a symbol table is built up, it
|
||||
|
|
@ -63,41 +86,32 @@ typedef struct symbol_value_s {
|
|||
* the delete_symbol_table method will delete the table, including all
|
||||
* the space for the keys.
|
||||
*/
|
||||
extern symbol_table_t new_symbol_table(void);
|
||||
extern void delete_symbol_table(symbol_table_t tbl);
|
||||
inline symbol_table_t new_symbol_table(void) { return new symbol_table_s; }
|
||||
inline void delete_symbol_table(symbol_table_t tbl) { delete tbl; }
|
||||
|
||||
// These are obsolete, and here only to support older code.
|
||||
inline void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val)
|
||||
{ tbl->sym_set_value(key, val); }
|
||||
|
||||
inline symbol_value_t sym_get_value(symbol_table_t tbl, const char*key)
|
||||
{ return tbl->sym_get_value(key); }
|
||||
|
||||
/*
|
||||
* This method locates the value in the symbol table and sets its
|
||||
* value. If the key doesn't yet exist, create it.
|
||||
* This template is a type-safe interface to the symbol table.
|
||||
*/
|
||||
void sym_set_value(symbol_table_t tbl, const char*key, symbol_value_t val);
|
||||
template <class T> class symbol_map_s : private symbol_table_s {
|
||||
|
||||
/*
|
||||
* This method locates the value in the symbol table and returns
|
||||
* it. If the value does not exist, create it, initialize it with
|
||||
* zero and return the zero value.
|
||||
*/
|
||||
symbol_value_t sym_get_value(symbol_table_t tbl, const char*key);
|
||||
public:
|
||||
void sym_set_value(const char*key, T*val)
|
||||
{ symbol_value_t tmp;
|
||||
tmp.ptr = val;
|
||||
symbol_table_s::sym_set_value(key, tmp);
|
||||
}
|
||||
|
||||
T* sym_get_value(const char*key)
|
||||
{ symbol_value_t val = symbol_table_s::sym_get_value(key);
|
||||
return reinterpret_cast<T*>(val.ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* $Log: symbols.h,v $
|
||||
* Revision 1.5 2004/12/11 02:31:30 steve
|
||||
* Rework of internals to carry vectors through nexus instead
|
||||
* of single bits. Make the ivl, tgt-vvp and vvp initial changes
|
||||
* down this path.
|
||||
*
|
||||
* Revision 1.4 2002/08/12 01:35:08 steve
|
||||
* conditional ident string using autoconfig.
|
||||
*
|
||||
* Revision 1.3 2001/05/09 04:23:19 steve
|
||||
* Now that the interactive debugger exists,
|
||||
* there is no use for the output dump.
|
||||
*
|
||||
* Revision 1.2 2001/03/18 00:37:55 steve
|
||||
* Add support for vpi scopes.
|
||||
*
|
||||
* Revision 1.1 2001/03/11 00:29:39 steve
|
||||
* Add the vvp engine to cvs.
|
||||
*
|
||||
*/
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* Copyright (c) 2008 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 "vvp_island.h"
|
||||
# include "compile.h"
|
||||
# include "symbols.h"
|
||||
# include "schedule.h"
|
||||
# include <iostream>
|
||||
# include <list>
|
||||
# include <assert.h>
|
||||
# include <stdlib.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Islands are mutually connected bidirectional meshes that have a
|
||||
* discipline other then the implicit ddiscipline of the rest of the
|
||||
* run time.
|
||||
*
|
||||
* In the vvp input, an island is created with this record:
|
||||
*
|
||||
* <label> .island ;
|
||||
*
|
||||
* The <label> is the name given to the island. Records after this
|
||||
* build up the contents of the island. Ports are created like this:
|
||||
*
|
||||
* <label> .port <island>, <src> ;
|
||||
* <label> .import <island>, <src> ;
|
||||
* <label> .export <island> ;
|
||||
*
|
||||
* The .port, .import and .export records create I/O, input and output
|
||||
* ports. The <label> is the name that branches within the island can
|
||||
* use to link to the port, and the <island> is the label for the
|
||||
* island. The input and I/O ports have a <src> label that links to the
|
||||
* source net from the ddiscrete domain.
|
||||
*
|
||||
* Branches within the island may only reference labels within the
|
||||
* island. This keeps the nets of the ocean of digital away from the
|
||||
* branches of analog within the island.
|
||||
*/
|
||||
|
||||
class vvp_island_branch;
|
||||
class vvp_island_node;
|
||||
|
||||
class vvp_island : private vvp_gen_event_s {
|
||||
|
||||
public:
|
||||
vvp_island();
|
||||
virtual ~vvp_island();
|
||||
|
||||
// Ports call this method to flag that something happened at
|
||||
// the input. The island will use this to create an active
|
||||
// event. The run_run() method will then be called by the
|
||||
// scheduler to process whatever happened.
|
||||
void flag_island();
|
||||
|
||||
// This is the method that is called, eventually, to process
|
||||
// whatever happened. The derived island class implements this
|
||||
// method to give the island its character.
|
||||
virtual void run_island() =0;
|
||||
|
||||
protected:
|
||||
// The base class collects a list of all the braches in the
|
||||
// island. The derived island class can access this list for
|
||||
// scanning the mesh.
|
||||
vvp_island_branch*branches_;
|
||||
|
||||
public: /* These methods are used during linking. */
|
||||
|
||||
// Add a port to the island. The key is added to the island
|
||||
// ports symbol table.
|
||||
void add_port(const char*key, vvp_net_t*net);
|
||||
// Add a branch to the island.
|
||||
void add_branch(vvp_island_branch*branch, const char*pa, const char*pb);
|
||||
|
||||
vvp_net_t* find_port(const char*key);
|
||||
|
||||
// Call this method when linking is done.
|
||||
void compile_cleanup(void);
|
||||
|
||||
private:
|
||||
void run_run();
|
||||
bool flagged_;
|
||||
|
||||
private:
|
||||
// During link, the vvp_island keeps these symbol tables for
|
||||
// mapping labels local to the island. When linking is done,
|
||||
// the compile_cleanup() method removes these tables.
|
||||
symbol_map_s<vvp_net_t>*ports_;
|
||||
symbol_map_s<vvp_island_branch>*anodes_;
|
||||
symbol_map_s<vvp_island_branch>*bnodes_;
|
||||
};
|
||||
|
||||
/*
|
||||
* An island port is a functor that connects to the ddiscrete
|
||||
* discipline outside the island. (There is also a vvp_net_t object
|
||||
* that refers to this port.) When data comes to the port from outside,
|
||||
* it is collected and saved, and the island is notified. When code
|
||||
* inside the island sends data out of the island, it uses the "out"
|
||||
* pointer from the vvp_net_t that refers to this object.
|
||||
*/
|
||||
|
||||
class vvp_island_port : public vvp_net_fun_t {
|
||||
|
||||
public:
|
||||
explicit vvp_island_port(vvp_island*ip);
|
||||
~vvp_island_port();
|
||||
|
||||
virtual void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit);
|
||||
virtual void recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t bit);
|
||||
|
||||
vvp_vector8_t invalue;
|
||||
|
||||
private:
|
||||
vvp_island*island_;
|
||||
|
||||
private: // not imlemented
|
||||
vvp_island_port(const vvp_island_port&);
|
||||
vvp_island_port& operator = (const vvp_island_port&);
|
||||
};
|
||||
|
||||
/*
|
||||
* Branches are connected together to form a mesh of brances. Each
|
||||
* endpoint (there are two) connects circularly to other branch
|
||||
* endpoints that are connected together. This list of endpoints forms
|
||||
* a node. Thus it is possible for branches to fully specify the mesh
|
||||
* of the island.
|
||||
*/
|
||||
|
||||
typedef vvp_sub_pointer_t<vvp_island_branch> vvp_branch_ptr_t;
|
||||
|
||||
struct vvp_island_branch {
|
||||
virtual ~vvp_island_branch();
|
||||
// Keep a list of branches in the island.
|
||||
vvp_island_branch*next_branch;
|
||||
// branch mesh connectivity. There is a pointer for each end
|
||||
// that participates in a circular list.
|
||||
vvp_sub_pointer_t<vvp_island_branch> link[2];
|
||||
// Port connections
|
||||
vvp_net_t*a;
|
||||
vvp_net_t*b;
|
||||
|
||||
// Behavior. (This stuff should be moved to a derived
|
||||
// class. The members here are specific to the tran island
|
||||
// class.)
|
||||
bool run_test_enabled();
|
||||
void run_resolution();
|
||||
bool active_high;
|
||||
bool enabled_flag;
|
||||
vvp_net_t*en;
|
||||
int flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementations...
|
||||
*/
|
||||
vvp_island::vvp_island()
|
||||
{
|
||||
flagged_ = false;
|
||||
branches_ = 0;
|
||||
ports_ = 0;
|
||||
anodes_ = 0;
|
||||
bnodes_ = 0;
|
||||
}
|
||||
|
||||
vvp_island::~vvp_island()
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void vvp_island::flag_island()
|
||||
{
|
||||
if (flagged_ == true)
|
||||
return;
|
||||
|
||||
schedule_generic(this, 0, false, false);
|
||||
flagged_ = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method handles the callback from the scheduler. It does basic
|
||||
* housecleaning and calles the run_island() method implemented by the
|
||||
* derived class.
|
||||
*/
|
||||
void vvp_island::run_run()
|
||||
{
|
||||
flagged_ = false;
|
||||
run_island();
|
||||
}
|
||||
|
||||
|
||||
void vvp_island::add_port(const char*key, vvp_net_t*net)
|
||||
{
|
||||
if (ports_ == 0)
|
||||
ports_ = new symbol_map_s<vvp_net_t>;
|
||||
|
||||
ports_->sym_set_value(key, net);
|
||||
}
|
||||
|
||||
void vvp_island::add_branch(vvp_island_branch*branch, const char*pa, const char*pb)
|
||||
{
|
||||
branch->a = ports_->sym_get_value(pa);
|
||||
branch->b = ports_->sym_get_value(pb);
|
||||
|
||||
vvp_branch_ptr_t ptra (branch, 0);
|
||||
vvp_branch_ptr_t ptrb (branch, 1);
|
||||
if (anodes_ == 0)
|
||||
anodes_ = new symbol_map_s<vvp_island_branch>;
|
||||
if (bnodes_ == 0)
|
||||
bnodes_ = new symbol_map_s<vvp_island_branch>;
|
||||
|
||||
if (vvp_island_branch*cur = anodes_->sym_get_value(pa)) {
|
||||
branch->link[0] = cur->link[0];
|
||||
cur->link[0] = ptra;
|
||||
} else {
|
||||
branch->link[0] = ptra;
|
||||
anodes_->sym_set_value(pa, branch);
|
||||
}
|
||||
|
||||
if (vvp_island_branch*cur = bnodes_->sym_get_value(pb)) {
|
||||
branch->link[1] = cur->link[1];
|
||||
cur->link[1] = ptrb;
|
||||
} else {
|
||||
branch->link[1] = ptrb;
|
||||
bnodes_->sym_set_value(pb, branch);
|
||||
}
|
||||
|
||||
branch->next_branch = branches_;
|
||||
branches_ = branch;
|
||||
}
|
||||
|
||||
vvp_net_t* vvp_island::find_port(const char*key)
|
||||
{
|
||||
return ports_->sym_get_value(key);
|
||||
}
|
||||
|
||||
void vvp_island::compile_cleanup()
|
||||
{
|
||||
if (ports_) {
|
||||
delete ports_;
|
||||
ports_ = 0;
|
||||
}
|
||||
if (anodes_) {
|
||||
delete anodes_;
|
||||
anodes_ = 0;
|
||||
}
|
||||
if (bnodes_) {
|
||||
delete bnodes_;
|
||||
bnodes_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vvp_island_port::vvp_island_port(vvp_island*ip)
|
||||
: island_(ip)
|
||||
{
|
||||
}
|
||||
|
||||
vvp_island_port::~vvp_island_port()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_island_port::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit)
|
||||
{
|
||||
recv_vec8(port, vvp_vector8_t(bit, 6, 6));
|
||||
}
|
||||
|
||||
void vvp_island_port::recv_vec8(vvp_net_ptr_t port, const vvp_vector8_t bit)
|
||||
{
|
||||
invalue = bit;
|
||||
island_->flag_island();
|
||||
}
|
||||
|
||||
vvp_island_branch::~vvp_island_branch()
|
||||
{
|
||||
}
|
||||
|
||||
/* **** TRANIF SUPPORT **** */
|
||||
|
||||
class vvp_island_tran : public vvp_island {
|
||||
|
||||
public:
|
||||
void run_island();
|
||||
};
|
||||
|
||||
void vvp_island_tran::run_island()
|
||||
{
|
||||
// Test to see if any of the branches are enabled.
|
||||
bool runable = false;
|
||||
for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch) {
|
||||
runable |= cur->run_test_enabled();
|
||||
}
|
||||
if (runable == false)
|
||||
return;
|
||||
|
||||
for (vvp_island_branch*cur = branches_ ; cur ; cur = cur->next_branch)
|
||||
cur->run_resolution();
|
||||
}
|
||||
|
||||
bool vvp_island_branch::run_test_enabled()
|
||||
{
|
||||
flags = 0;
|
||||
|
||||
vvp_island_port*ep = dynamic_cast<vvp_island_port*> (en->fun);
|
||||
|
||||
// If there is no ep port (no "enabled" input) then this is a
|
||||
// tran branch. Assume it is always enabled.
|
||||
if (ep == 0) {
|
||||
enabled_flag = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
enabled_flag = false;
|
||||
vvp_bit4_t enable_val = ep->invalue.value(0).value();
|
||||
|
||||
if (active_high==true && enable_val != BIT4_1)
|
||||
return false;
|
||||
|
||||
if (active_high==false && enable_val != BIT4_0)
|
||||
return false;
|
||||
|
||||
enabled_flag = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void collect_connections(list<vvp_net_t*>&connections, vvp_branch_ptr_t cur)
|
||||
{
|
||||
vvp_island_branch*ptr = cur.ptr();
|
||||
unsigned ab = cur.port();
|
||||
unsigned other_ab = ab^1;
|
||||
|
||||
int ab_mask = 1 << ab;
|
||||
|
||||
if ( (ptr->flags&ab_mask) != 0)
|
||||
return;
|
||||
|
||||
ptr->flags |= ab_mask;
|
||||
connections.push_back( ab? ptr->b : ptr->a );
|
||||
|
||||
if (ptr->enabled_flag)
|
||||
collect_connections(connections, vvp_branch_ptr_t(ptr, other_ab));
|
||||
collect_connections(connections, ptr->link[ab]);
|
||||
}
|
||||
|
||||
void vvp_island_branch::run_resolution()
|
||||
{
|
||||
if ( (flags&1) == 0) {
|
||||
list<vvp_net_t*>collection;
|
||||
collect_connections(collection, vvp_branch_ptr_t(this, 0));
|
||||
vvp_vector8_t tmp;
|
||||
for (list<vvp_net_t*>::iterator cur = collection.begin()
|
||||
; cur != collection.end() ; cur ++ ) {
|
||||
vvp_island_port*fun = dynamic_cast<vvp_island_port*>((*cur)->fun);
|
||||
if (tmp.size() == 0)
|
||||
tmp = fun->invalue;
|
||||
else if (fun->invalue.size() != 0)
|
||||
tmp = resolve(tmp, fun->invalue);
|
||||
}
|
||||
|
||||
for (list<vvp_net_t*>::iterator cur = collection.begin()
|
||||
; cur != collection.end() ; cur ++ )
|
||||
vvp_send_vec8((*cur)->out, tmp);
|
||||
}
|
||||
|
||||
if ( (flags&2) == 0) {
|
||||
list<vvp_net_t*>collection;
|
||||
collect_connections(collection, vvp_branch_ptr_t(this, 1));
|
||||
vvp_vector8_t tmp;
|
||||
for (list<vvp_net_t*>::iterator cur = collection.begin()
|
||||
; cur != collection.end() ; cur ++ ) {
|
||||
vvp_island_port*fun = dynamic_cast<vvp_island_port*>((*cur)->fun);
|
||||
if (tmp.size() == 0)
|
||||
tmp = fun->invalue;
|
||||
else if (fun->invalue.size() != 0)
|
||||
tmp = resolve(tmp, fun->invalue);
|
||||
}
|
||||
|
||||
for (list<vvp_net_t*>::iterator cur = collection.begin()
|
||||
; cur != collection.end() ; cur ++ )
|
||||
vvp_send_vec8((*cur)->out, tmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* **** COMPILE/LINK SUPPORT **** */
|
||||
|
||||
/*
|
||||
* We need to keep an island symbol table to make island labels to
|
||||
* islands, and we need a list of the islands that we can run through
|
||||
* during cleanup. After linking is done, the compile_island_cleanup() is
|
||||
* called to erase both.
|
||||
*/
|
||||
static list<vvp_island*> island_list;
|
||||
static symbol_map_s<vvp_island>* island_table = 0;
|
||||
|
||||
void compile_island(char*label, char*type)
|
||||
{
|
||||
if (island_table == 0)
|
||||
island_table = new symbol_map_s<vvp_island>;
|
||||
|
||||
vvp_island*use_island = 0;
|
||||
|
||||
if (strcmp(type,"tran") == 0) {
|
||||
use_island = new vvp_island_tran;
|
||||
} else {
|
||||
assert(0);
|
||||
}
|
||||
|
||||
island_table->sym_set_value(label, use_island);
|
||||
free(label);
|
||||
free(type);
|
||||
}
|
||||
|
||||
void compile_island_port(char*label, char*island, char*src)
|
||||
{
|
||||
assert(island_table);
|
||||
vvp_island*use_island = island_table->sym_get_value(island);
|
||||
assert(use_island);
|
||||
free(island);
|
||||
|
||||
vvp_net_t*net = new vvp_net_t;
|
||||
vvp_island_port*fun = new vvp_island_port(use_island);
|
||||
net->fun = fun;
|
||||
|
||||
// Get the source from outside the island
|
||||
input_connect(net, 0, src);
|
||||
|
||||
// Define the functor outside the island.
|
||||
define_functor_symbol(label, net);
|
||||
|
||||
// Also define it inside the island.
|
||||
use_island->add_port(label, net);
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
void compile_island_export(char*label, char*island)
|
||||
{
|
||||
fprintf(stderr, "XXXX %s .export %s;\n", label, island);
|
||||
free(label);
|
||||
free(island);
|
||||
}
|
||||
|
||||
void compile_island_import(char*label, char*island, char*src)
|
||||
{
|
||||
assert(island_table);
|
||||
vvp_island*use_island = island_table->sym_get_value(island);
|
||||
assert(use_island);
|
||||
free(island);
|
||||
|
||||
vvp_net_t*net = new vvp_net_t;
|
||||
vvp_island_port*fun = new vvp_island_port(use_island);
|
||||
net->fun = fun;
|
||||
|
||||
// Get the source from outside the island
|
||||
input_connect(net, 0, src);
|
||||
|
||||
// Define the functor only inside the island.
|
||||
use_island->add_port(label, net);
|
||||
|
||||
free(label);
|
||||
}
|
||||
|
||||
void compile_island_tranif(int sense, char*island, char*pa, char*pb, char*pe)
|
||||
{
|
||||
assert(island_table);
|
||||
vvp_island*use_island = island_table->sym_get_value(island);
|
||||
assert(use_island);
|
||||
free(island);
|
||||
|
||||
vvp_island_branch*br = new vvp_island_branch;
|
||||
if (sense)
|
||||
br->active_high = true;
|
||||
else
|
||||
br->active_high = false;
|
||||
|
||||
br->en = use_island->find_port(pe);
|
||||
assert(br->en);
|
||||
|
||||
use_island->add_branch(br, pa, pb);
|
||||
|
||||
free(pa);
|
||||
free(pb);
|
||||
free(pe);
|
||||
}
|
||||
|
||||
void compile_island_cleanup(void)
|
||||
{
|
||||
// Call the per-island cleanup to get rid of local symbol tables.
|
||||
for (list<vvp_island*>::iterator cur = island_list.begin()
|
||||
; cur != island_list.end() ; cur ++ ) {
|
||||
(*cur)->compile_cleanup();
|
||||
}
|
||||
|
||||
island_list.clear();
|
||||
|
||||
// Remove the island symbol table itself.
|
||||
if (island_table) {
|
||||
delete island_table;
|
||||
island_table = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef __vvp_island_H
|
||||
#define __vvp_island_H
|
||||
/*
|
||||
* Copyright (c) 2008 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 "config.h"
|
||||
# include "vvp_net.h"
|
||||
# include <assert.h>
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -37,7 +37,6 @@ class vvp_scalar_t;
|
|||
|
||||
/* Basic netlist types. */
|
||||
class vvp_net_t;
|
||||
class vvp_net_ptr_t;
|
||||
class vvp_net_fun_t;
|
||||
|
||||
/* Core net function types. */
|
||||
|
|
@ -605,77 +604,45 @@ inline void vvp_vector8_t::set_bit(unsigned idx, vvp_scalar_t val)
|
|||
* the vvp_net_t. Use this pointer to point only to the inputs of
|
||||
* vvp_net_t objects. To point to vvp_net_t objects as a whole, use
|
||||
* vvp_net_t* pointers.
|
||||
*/
|
||||
class vvp_net_ptr_t {
|
||||
|
||||
public:
|
||||
vvp_net_ptr_t();
|
||||
vvp_net_ptr_t(vvp_net_t*ptr, unsigned port);
|
||||
~vvp_net_ptr_t() { }
|
||||
|
||||
vvp_net_t* ptr();
|
||||
const vvp_net_t* ptr() const;
|
||||
unsigned port() const;
|
||||
|
||||
bool nil() const;
|
||||
|
||||
bool operator == (vvp_net_ptr_t that) const;
|
||||
bool operator != (vvp_net_ptr_t that) const;
|
||||
|
||||
private:
|
||||
unsigned long bits_;
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Alert! Ugly details. Protective clothing recommended!
|
||||
* The vvp_net_ptr_t encodes the bits of a C pointer, and two bits of
|
||||
* port identifier into an unsigned long. This works only if vvp_net_t*
|
||||
* values are always aligned on 4-byte boundaries.
|
||||
*/
|
||||
template <class T> class vvp_sub_pointer_t {
|
||||
|
||||
inline vvp_net_ptr_t::vvp_net_ptr_t()
|
||||
{
|
||||
bits_ = 0;
|
||||
}
|
||||
public:
|
||||
vvp_sub_pointer_t() : bits_(0) { }
|
||||
|
||||
inline vvp_net_ptr_t::vvp_net_ptr_t(vvp_net_t*ptr, unsigned port)
|
||||
{
|
||||
vvp_sub_pointer_t(T*ptr, unsigned port)
|
||||
{
|
||||
bits_ = reinterpret_cast<unsigned long> (ptr);
|
||||
assert( (bits_ & 3) == 0 );
|
||||
assert( (port & ~3) == 0 );
|
||||
bits_ |= port;
|
||||
}
|
||||
}
|
||||
|
||||
inline vvp_net_t* vvp_net_ptr_t::ptr()
|
||||
{
|
||||
return reinterpret_cast<vvp_net_t*> (bits_ & ~3UL);
|
||||
}
|
||||
~vvp_sub_pointer_t() { }
|
||||
|
||||
inline const vvp_net_t* vvp_net_ptr_t::ptr() const
|
||||
{
|
||||
return reinterpret_cast<const vvp_net_t*> (bits_ & ~3UL);
|
||||
}
|
||||
T* ptr()
|
||||
{ return reinterpret_cast<T*> (bits_ & ~3UL); }
|
||||
|
||||
inline unsigned vvp_net_ptr_t::port() const
|
||||
{
|
||||
return bits_ & 3;
|
||||
}
|
||||
const T* ptr() const
|
||||
{ return reinterpret_cast<const T*> (bits_ & ~3UL); }
|
||||
|
||||
inline bool vvp_net_ptr_t::nil() const
|
||||
{
|
||||
return bits_ == 0;
|
||||
}
|
||||
unsigned port() const { return bits_ & 3; }
|
||||
|
||||
inline bool vvp_net_ptr_t::operator == (vvp_net_ptr_t that) const
|
||||
{
|
||||
return bits_ == that.bits_;
|
||||
}
|
||||
bool nil() const { return bits_ == 0; }
|
||||
|
||||
inline bool vvp_net_ptr_t::operator != (vvp_net_ptr_t that) const
|
||||
{
|
||||
return bits_ != that.bits_;
|
||||
}
|
||||
bool operator == (vvp_sub_pointer_t that) const { return bits_ == that.bits_; }
|
||||
bool operator != (vvp_sub_pointer_t that) const { return bits_ != that.bits_; }
|
||||
|
||||
private:
|
||||
unsigned long bits_;
|
||||
};
|
||||
|
||||
typedef vvp_sub_pointer_t<vvp_net_t> vvp_net_ptr_t;
|
||||
|
||||
/*
|
||||
* This is the basic unit of netlist connectivity. It is a fan-in of
|
||||
|
|
|
|||
Loading…
Reference in New Issue