Revise the VVM backend to use nexus objects so that

drivers and resolution functions can be used, and
 the t-vvm module doesn't need to write a zillion
 output functions.
This commit is contained in:
steve 2000-03-16 19:03:03 +00:00
parent 2e05f7f7ec
commit 2563e2b717
16 changed files with 1104 additions and 303 deletions

View File

@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.38 2000/03/12 17:09:40 steve Exp $"
#ident "$Id: Makefile.in,v 1.39 2000/03/16 19:03:03 steve Exp $"
#
#
SHELL = /bin/sh
@ -72,7 +72,7 @@ FF = nobufz.o nodangle.o propinit.o synth.o xnfio.o xnfsyn.o
O = main.o cprop.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
elab_net.o elab_pexpr.o elab_scope.o emit.o eval.o eval_tree.o \
expr_synth.o functor.o lexor.o lexor_keyword.o mangle.o netlist.o \
net_design.o pad_to_width.o \
net_design.o nexus_from_link.o pad_to_width.o \
parse.o parse_misc.o pform.o pform_dump.o \
set_width.o \
verinum.o verireal.o target.o targets.o Module.o PDelays.o PExpr.o PGate.o \

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: elab_net.cc,v 1.24 2000/03/08 04:36:53 steve Exp $"
#ident "$Id: elab_net.cc,v 1.25 2000/03/16 19:03:03 steve Exp $"
#endif
# include "PExpr.h"
@ -546,8 +546,17 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, const string&path,
1+lsig->pin_count(), NetLogic::OR);
for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx += 1)
connect(gate_t->pin(idx+1), lsig->pin(idx));
connect(gate->pin(1), gate_t->pin(0));
/* The reduced logical value is a new nexus, create a
temporary signal to represent it. */
NetNet*tmp = new NetTmp(des->local_symbol(path));
connect(gate->pin(1), tmp->pin(0));
des->add_node(gate_t);
des->add_signal(tmp);
} else {
connect(gate->pin(1), lsig->pin(0));
}
@ -559,7 +568,15 @@ NetNet* PEBinary::elaborate_net_log_(Design*des, const string&path,
for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx += 1)
connect(gate_t->pin(idx+1), rsig->pin(idx));
connect(gate->pin(2), gate_t->pin(0));
/* The reduced logical value is a new nexus, create a
temporary signal to represent it. */
NetNet*tmp = new NetTmp(des->local_symbol(path));
connect(gate->pin(2), tmp->pin(0));
des->add_node(gate_t);
des->add_signal(tmp);
} else {
connect(gate->pin(2), rsig->pin(0));
}
@ -1336,6 +1353,12 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path,
/*
* $Log: elab_net.cc,v $
* Revision 1.25 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.24 2000/03/08 04:36:53 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: netmisc.h,v 1.3 2000/02/23 02:56:55 steve Exp $"
#ident "$Id: netmisc.h,v 1.4 2000/03/16 19:03:03 steve Exp $"
#endif
# include "netlist.h"
@ -33,8 +33,23 @@
extern NetExpr*pad_to_width(NetExpr*expr, unsigned wid);
extern NetNet*pad_to_width(Design*des, const string&p, NetNet*n, unsigned w);
/*
* This function chooses a nexus name for the link. The algorithm is
* such that any signal in the link will have the same nexus name, and
* signals that are not connected together will have a different nexus
* name.
*/
extern string nexus_from_link(const NetObj::Link*lnk);
/*
* $Log: netmisc.h,v $
* Revision 1.4 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.3 2000/02/23 02:56:55 steve
* Macintosh compilers do not support ident.
*

91
nexus_from_link.cc Normal file
View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2000 Stephen Williams (steve@.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
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: nexus_from_link.cc,v 1.1 2000/03/16 19:03:03 steve Exp $"
#endif
# include "netmisc.h"
# include <strstream>
# include <string>
# include <typeinfo>
string nexus_from_link(const NetObj::Link*lnk)
{
const NetNet*sig = dynamic_cast<const NetNet*>(lnk->get_obj());
unsigned pin = lnk->get_pin();
for (const NetObj::Link*cur = lnk->next_link()
; cur != lnk ; cur = cur->next_link()) {
const NetNet*cursig = dynamic_cast<const NetNet*>(cur->get_obj());
if (cursig == 0)
continue;
if (sig == 0) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if ((cursig->pin_count() == 1) && (sig->pin_count() > 1))
continue;
if ((cursig->pin_count() > 1) && (sig->pin_count() == 1)) {
sig = cursig;
pin = cur->get_pin();
continue;
}
if (cursig->local_flag() && !sig->local_flag())
continue;
if (cursig->name() < sig->name())
continue;
sig = cursig;
pin = cur->get_pin();
}
if (sig == 0) {
const NetObj*obj = lnk->get_obj();
pin = lnk->get_pin();
cerr << "internal error: No signal for nexus of " <<
obj->name() << " pin " << pin << " (type=" <<
typeid(*obj).name() << ")?" << endl;
}
assert(sig);
ostrstream tmp;
tmp << sig->name();
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
tmp << ends;
return tmp.str();
}
/*
* $Log: nexus_from_link.cc,v $
* Revision 1.1 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
*/

178
t-vvm.cc
View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: t-vvm.cc,v 1.107 2000/03/08 04:36:54 steve Exp $"
#ident "$Id: t-vvm.cc,v 1.108 2000/03/16 19:03:03 steve Exp $"
#endif
# include <iostream>
@ -28,6 +28,7 @@
# include <typeinfo>
# include <unistd.h>
# include "netlist.h"
# include "netmisc.h"
# include "target.h"
// Comparison for use in sorting algorithms.
@ -134,6 +135,7 @@ class target_vvm : public target_t {
// of things that may be scanned multiple times.
map<string,bool>esignal_printed_flag;
map<string,bool>pevent_printed_flag;
map<string,bool>nexus_printed_flag;
// String constants that are made into vpiHandles have th
// handle name mapped by this.
@ -656,7 +658,9 @@ void target_vvm::start_design(ostream&os, const Design*mod)
start_code.open(start_code_name, ios::in | ios::out | ios::trunc);
os << "# include \"vvm.h\"" << endl;
os << "# include \"vvm_nexus.h\"" << endl;
os << "# include \"vvm_gates.h\"" << endl;
os << "# include \"vvm_signal.h\"" << endl;
os << "# include \"vvm_func.h\"" << endl;
os << "# include \"vvm_calltf.h\"" << endl;
os << "# include \"vvm_thread.h\"" << endl;
@ -667,11 +671,6 @@ void target_vvm::start_design(ostream&os, const Design*mod)
string_counter = 1;
number_counter = 1;
#if 0
os << "static struct __vpiStringConst string_table[];" << endl;
os << "static struct __vpiNumberConst number_table[];" << endl;
#endif
init_code << "static void design_init()" << endl;
init_code << "{" << endl;
init_code << " vpip_init_simulation();"
@ -802,6 +801,19 @@ bool target_vvm::process(ostream&os, const NetProcTop*top)
void target_vvm::signal(ostream&os, const NetNet*sig)
{
string net_name = mangle(sig->name());
for (unsigned idx = 0 ; idx < sig->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&sig->pin(idx)));
if (! nexus_printed_flag[nexus]) {
nexus_printed_flag[nexus] = true;
os << "vvm_nexus_wire " << nexus << "_nex;" << endl;
}
init_code << " " << nexus << "_nex.connect(&" <<
net_name << ", " << idx << ");" << endl;
}
os << "static vvm_bitset_t<" << sig->pin_count() << "> " <<
net_name<< "_bits; /* " << sig->name() <<
" */" << endl;
@ -1005,21 +1017,44 @@ void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate)
os << "static vvm_add_sub<" << gate->width() << "> " <<
mangle(gate->name()) << ";" << endl;
/* Connect the DataA inputs. */
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
unsigned pin = gate->pin_DataA(idx).get_pin();
string nexus = mangle(nexus_from_link(&gate->pin(pin)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", " <<
mangle(gate->name()) << ".key_DataA(" << idx <<
"));" << endl;
}
/* Connect the DataB inputs. */
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
unsigned pin = gate->pin_DataB(idx).get_pin();
string nexus = mangle(nexus_from_link(&gate->pin(pin)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", " <<
mangle(gate->name()) << ".key_DataB(" << idx <<
"));" << endl;
}
/* Connect the outputs of the adder. */
for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) {
unsigned pin = gate->pin_Result(idx).get_pin();
string outfun = defn_gate_outputfun_(os, gate, pin);
init_code << " " << mangle(gate->name()) <<
".config_rout(" << idx << ", &" << outfun << ");" << endl;
emit_gate_outputfun_(gate, pin);
string nexus = mangle(nexus_from_link(&gate->pin(pin)));
init_code << " " << nexus << "_nex.connect(" <<
mangle(gate->name()) << ".config_rout(" << idx <<
"));" << endl;
}
// Connect the carry output if necessary.
if (gate->pin_Cout().is_linked()) {
unsigned pin = gate->pin_Cout().get_pin();
string outfun = defn_gate_outputfun_(os, gate, pin);
init_code << " " << mangle(gate->name()) <<
".config_cout(&" << outfun << ");" << endl;
emit_gate_outputfun_(gate, pin);
string nexus = mangle(nexus_from_link(&gate->pin(pin)));
init_code << " " << nexus << "_nex.connect(" <<
mangle(gate->name()) << ".config_cout());" << endl;
}
if (gate->attribute("LPM_Direction") == "ADD") {
@ -1153,55 +1188,70 @@ void target_vvm::lpm_ram_dq(ostream&os, const NetRamDq*ram)
void target_vvm::logic(ostream&os, const NetLogic*gate)
{
string outfun = defn_gate_outputfun_(os, gate, 0);
/* Draw the definition of the gate object. The exact type to
use depends on the gate type. Whatever the type, the basic
format is the same for all the boolean gates. */
switch (gate->type()) {
case NetLogic::AND:
os << "static vvm_and" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_and" << "<" << gate->pin_count()-1 << "> ";
break;
case NetLogic::BUF:
os << "static vvm_buf<" << gate->rise_time() << "> ";
os << "static vvm_buf ";
break;
case NetLogic::BUFIF0:
os << "static vvm_bufif0<" << gate->rise_time() << "> ";
os << "static vvm_bufif0 ";
break;
case NetLogic::BUFIF1:
os << "static vvm_bufif1<" << gate->rise_time() << "> ";
os << "static vvm_bufif1 ";
break;
case NetLogic::NAND:
os << "static vvm_nand" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_nand" << "<" << gate->pin_count()-1 << "> ";
break;
case NetLogic::NOR:
os << "static vvm_nor" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_nor" << "<" << gate->pin_count()-1 << "> ";
break;
case NetLogic::NOT:
os << "static vvm_not" << "<" << gate->rise_time() << "> ";
os << "static vvm_not ";
break;
case NetLogic::OR:
os << "static vvm_or" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_or" << "<" << gate->pin_count()-1 << "> ";
break;
case NetLogic::XNOR:
os << "static vvm_xnor" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_xnor" << "<" << gate->pin_count()-1 << "> ";
break;
case NetLogic::XOR:
os << "static vvm_xor" << "<" << gate->pin_count()-1 <<
"," << gate->rise_time() << "> ";
os << "static vvm_xor" << "<" << gate->pin_count()-1 << "> ";
break;
default:
os << "#error \"internal ivl error:bad gate type for " <<
gate->name() << "\"" << endl;
}
os << mangle(gate->name()) << "(&" << outfun << ");" << endl;
os << mangle(gate->name()) << " (" << gate->rise_time() << ");" << endl;
emit_gate_outputfun_(gate, 0);
/* Write the code to invoke startup for this object. */
start_code << " " << mangle(gate->name()) << ".start();" << endl;
/* Connect the output and all the inputs of the gate to the
nexus objects, one bit at a time. */
init_code << " // Connect inputs to gate " << gate->name()
<< "." << endl;
{ string nexus = mangle(nexus_from_link(&gate->pin(0)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ");" << endl;
}
for (unsigned idx = 1 ; idx < gate->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&gate->pin(idx)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", " << (idx-1) << ");" << endl;
}
}
void target_vvm::bufz(ostream&os, const NetBUFZ*gate)
@ -1296,6 +1346,7 @@ void target_vvm::udp(ostream&os, const NetUDP*gate)
*/
void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
{
#ifdef REMOVE_ME_WHEN_NB_ASSIGN_IS_DONE
const string name = mangle(net->name());
unsigned iwid = net->pin_count();
os << "class " << name << " : public vvm_event {" << endl;
@ -1381,22 +1432,32 @@ void target_vvm::net_assign_nb(ostream&os, const NetAssignNB*net)
}
}
delayed << "}" << endl;
#endif
}
void target_vvm::net_case_cmp(ostream&os, const NetCaseCmp*gate)
{
const NetObj::Link&lnk = gate->pin(0);
os << "static void " << mangle(gate->name()) <<
"_output_" << lnk.get_name() << "_" << lnk.get_inst() <<
"(vpip_bit_t);" << endl;
string nexus;
assert(gate->pin_count() == 3);
os << "static vvm_eeq" << "<" << gate->rise_time() << "> "
<< mangle(gate->name()) << "(&" << mangle(gate->name()) <<
"_output_" << lnk.get_name() << "_" << lnk.get_inst() << ");" << endl;
os << "static vvm_eeq " << mangle(gate->name()) << "(" <<
gate->rise_time() << ");" << endl;
/* Connect the output pin */
nexus = mangle(nexus_from_link(&gate->pin(0)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ");" << endl;
/* Connect the first input */
nexus = mangle(nexus_from_link(&gate->pin(1)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", 0);" << endl;
/* Connect the second input */
nexus = mangle(nexus_from_link(&gate->pin(2)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", 1);" << endl;
emit_gate_outputfun_(gate, 0);
start_code << " " << mangle(gate->name()) << ".start();" << endl;
}
@ -1449,6 +1510,16 @@ void target_vvm::net_event(ostream&os, const NetNEvent*gate)
break;
}
os << ");" << endl;
/* Connect this device as a receiver to the nexus that is my
source. Write the connect calls into the init code. */
for (unsigned idx = 0 ; idx < gate->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&gate->pin(idx)));
init_code << " " << nexus << "_nex.connect(&" <<
mangle(gate->name()) << ", " << idx << ");" << endl;
}
}
void target_vvm::start_process(ostream&os, const NetProcTop*proc)
@ -1531,6 +1602,7 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
defn << " }" << endl;
} else {
#if 0
/* Not only is the lvalue signal assigned to, send the
bits to all the other pins that are connected to this
signal. */
@ -1562,6 +1634,13 @@ void target_vvm::proc_assign(ostream&os, const NetAssign*net)
", " << rval << "[" << idx << "]);" << endl;
}
}
#else
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&net->pin(idx)));
defn << " " << nexus << "_nex.reg_assign(" <<
rval << "[" << idx << "]);" << endl;
}
#endif
}
}
@ -1607,9 +1686,18 @@ void target_vvm::proc_assign_nb(ostream&os, const NetAssignNB*net)
<< "-> schedule(" << net->rise_time() << ");" << endl;
} else {
const unsigned long delay = net->rise_time();
for (unsigned idx = 0 ; idx < net->pin_count() ; idx += 1) {
string nexus = mangle(nexus_from_link(&net->pin(idx)));
defn << " vvm_delayed_assign(" << nexus <<
"_nex, " << rval << "[" << idx << "], " <<
delay << ");" << endl;
}
#ifdef REMOVE_ME_WHEN_NB_ASSIGN_IS_DONE
defn << " (new " << mangle(net->name()) << "("
<< rval << ")) -> schedule(" << net->rise_time() <<
");" << endl;
#endif
}
}
@ -2174,6 +2262,12 @@ extern const struct target tgt_vvm = {
};
/*
* $Log: t-vvm.cc,v $
* Revision 1.108 2000/03/16 19:03:03 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.107 2000/03/08 04:36:54 steve
* Redesign the implementation of scopes and parameters.
* I now generate the scopes and notice the parameters

49
vvm.txt
View File

@ -27,6 +27,47 @@ On any system, the compiled program requires that the VPI_MODULE_PATH
be set to a ':' separated list of directories to search for vpi files,
the system.vpi file in particular. This is a run time requirement.
NEXUS, GATES AND DRIVERS
The vvm library allows the user (the t-vvm code generator from its
point of view) to build up a netlist of gates that operate like
hardware components. The basic unit of connectivity in the vvm_nexus
class.
A vvm_nexus object represents a nexus of a netlist: that is, a point
where drivers and receivers are connected together. The nexus class
defines the sub-classes (not derived classes) driver_t and recvr_t
that objects and code use to connect to the nexus. The nexus also has
a reg_assign() method for simulating procedural assignment.
The driver_t class is a means to drive (as opposed to assign) a value
onto the nexus. Gates with outputs have drive_t objects that they can
connect to exactly one nexus.
The recvr_t class is where the nexus delivers the resolved
value. Receiver objects are actually able to represent many pins of a
device, although a nexus is connected to only one. This is managed by
passing to the nexus a pointer to the object and a key that the
receiver uses to identify the pin. This is done so that the gate class
can derive from the recvr_t class and support multiple input pins.
The vvm_nexus class connects to any number of drivers and any number
of receivers. This is how fan-in and fan-out are achieved in a design
under test. When a connected driver gets a new value, the vvm_nexus
object scans all the drivers and collects the values that are being
driven. It passes the set to a resolution function that calculates the
actual value that the vvm_nexus will take, then passes that value to
all the receivers.
If there are no drivers, the vvm_nexus can also receive a value from
procedural assignment, via the reg_assign() method. When assigned in
this manner, the vvm_nexus simply takes the value given to it and
passes it to all the receivers. The vvm_nexus holds the last value
assigned, and does not perform any resolution.
The vvm/vvm_nexus.h header file describes the vvm_nexus and related
classes.
ATTRIBUTES
(none)
@ -110,8 +151,14 @@ bits are at:
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
$Id: vvm.txt,v 1.4 1999/12/30 17:37:14 steve Exp $
$Id: vvm.txt,v 1.5 2000/03/16 19:03:04 steve Exp $
$Log: vvm.txt,v $
Revision 1.5 2000/03/16 19:03:04 steve
Revise the VVM backend to use nexus objects so that
drivers and resolution functions can be used, and
the t-vvm module doesn't need to write a zillion
output functions.
Revision 1.4 1999/12/30 17:37:14 steve
Remove the now useless sigfold functor.

View File

@ -18,7 +18,7 @@
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA
#
#ident "$Id: Makefile.in,v 1.20 2000/03/13 00:02:34 steve Exp $"
#ident "$Id: Makefile.in,v 1.21 2000/03/16 19:03:04 steve Exp $"
#
#
SHELL = /bin/sh
@ -59,7 +59,7 @@ all: libvvm.a
mv $*.d dep
O = vvm_bit.o vvm_calltf.o vvm_event.o vvm_func.o vvm_gates.o vvm_mult.o \
vvm_pevent.o vvm_thread.o vpip.o
vvm_nexus.o vvm_pevent.o vvm_signal.o vvm_thread.o vpip.o
P = vpi_callback.o \
vpi_const.o vpi_iter.o vpi_memory.o vpi_null.o \
@ -80,6 +80,8 @@ install: all installdirs $(libdir)/libvvm.a \
$(includedir)/vpi_priv.h \
$(includedir)/vvm_func.h \
$(includedir)/vvm_gates.h \
$(includedir)/vvm_nexus.h \
$(includedir)/vvm_signal.h \
$(includedir)/vvm_thread.h \
$(includedir)/vvm_calltf.h
@ -98,6 +100,12 @@ $(includedir)/vvm_func.h: $(srcdir)/vvm_func.h
$(includedir)/vvm_gates.h: $(srcdir)/vvm_gates.h
$(INSTALL_DATA) $(srcdir)/vvm_gates.h $(includedir)/vvm_gates.h
$(includedir)/vvm_nexus.h: $(srcdir)/vvm_nexus.h
$(INSTALL_DATA) $(srcdir)/vvm_nexus.h $(includedir)/vvm_nexus.h
$(includedir)/vvm_signal.h: $(srcdir)/vvm_signal.h
$(INSTALL_DATA) $(srcdir)/vvm_signal.h $(includedir)/vvm_signal.h
$(includedir)/vvm_thread.h: $(srcdir)/vvm_thread.h
$(INSTALL_DATA) $(srcdir)/vvm_thread.h $(includedir)/vvm_thread.h
@ -113,6 +121,8 @@ uninstall:
rm -f $(includedir)/vvm_calltf.h
rm -f $(includedir)/vvm_func.h
rm -f $(includedir)/vvm_gates.h
rm -f $(includedir)/vvm_nexus.h
rm -f $(includedir)/vvm_signal.h
rm -f $(includedir)/vvm_thread.h
rm -f $(includedir)/vpi_priv.h

147
vvm/vvm.h
View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm.h,v 1.32 2000/03/13 00:02:34 steve Exp $"
#ident "$Id: vvm.h,v 1.33 2000/03/16 19:03:04 steve Exp $"
#endif
# include <cassert>
@ -110,46 +110,6 @@ class vvm_bits_t {
extern ostream& operator << (ostream&os, vpip_bit_t);
extern ostream& operator << (ostream&os, const vvm_bits_t&str);
/*
* The vvm_bitset_t is a fixed width array-like set of vpip_bit_t
* items. A number is often times made up of bit sets instead of
* single bits. The fixed array is used when possible because of the
* more thorough type checking and (hopefully) better optimization.
*/
template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
public:
vvm_bitset_t()
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[idx] = Vz;
}
vvm_bitset_t(const vvm_bits_t&that)
{ unsigned wid = WIDTH;
if (that.get_width() < WIDTH)
wid = that.get_width();
for (unsigned idx = 0 ; idx < wid ; idx += 1)
bits[idx] = that.get_bit(idx);
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
bits[idx] = V0;
}
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
{ for (unsigned idx = 0; idx < WIDTH; idx += 1)
bits[idx] = that.bits[idx];
}
vpip_bit_t operator[] (unsigned idx) const { return bits[idx]; }
vpip_bit_t&operator[] (unsigned idx) { return bits[idx]; }
unsigned get_width() const { return WIDTH; }
vpip_bit_t get_bit(unsigned idx) const { return bits[idx]; }
public:
vpip_bit_t bits[WIDTH];
};
/*
* Verilog events (update events and nonblocking assign) are derived
* from this abstract class so that the simulation engine can treat
@ -175,107 +135,14 @@ class vvm_event {
};
/*
* The vvm_signal_t template is the real object that handles the
* receiving of assignments and doing whatever is done. It also
* connects VPI to the C++/vvm design.
*/
template <unsigned WIDTH> class vvm_signal_t : public __vpiSignal {
public:
vvm_signal_t(vvm_bitset_t<WIDTH>*b)
{ bits = b->bits;
nbits = WIDTH;
}
~vvm_signal_t() { }
void init_P(unsigned idx, vpip_bit_t val)
{ bits[idx] = val; }
void set_P(unsigned idx, vpip_bit_t val)
{ bits[idx] = val;
vpip_run_value_changes(this);
}
void set_P(const vvm_bitset_t<WIDTH>&val)
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
set(sim, idx, val[idx]);
}
};
struct vvm_ram_callback {
vvm_ram_callback();
virtual ~vvm_ram_callback();
virtual void handle_write(unsigned idx) =0;
vvm_ram_callback*next_;
};
template <unsigned WIDTH, unsigned SIZE>
class vvm_memory_t : public __vpiMemory {
public:
vvm_memory_t()
{ cb_list_ = 0;
}
void set_word(unsigned addr,
const vvm_bitset_t<WIDTH>&val)
{ unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(addr);
}
void set_word(unsigned addr,
const vpip_bit_t val[WIDTH])
{ unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(addr);
}
vvm_bitset_t<WIDTH> get_word(unsigned addr) const
{ vvm_bitset_t<WIDTH> val;
unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
val[idx] = bits[base+idx];
return val;
}
void set_callback(vvm_ram_callback*ram)
{ ram->next_ = cb_list_;
cb_list_ = ram;
}
class assign_nb : public vvm_event {
public:
assign_nb(vvm_memory_t<WIDTH,SIZE>&m, unsigned i,
const vvm_bitset_t<WIDTH>&v)
: mem_(m), index_(i), val_(v) { }
void event_function() { mem_.set_word(index_, val_); }
private:
vvm_memory_t<WIDTH,SIZE>&mem_;
unsigned index_;
vvm_bitset_t<WIDTH> val_;
};
private:
vvm_ram_callback*cb_list_;
void call_list_(unsigned idx)
{ for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_)
cur->handle_write(idx);
}
};
/*
* $Log: vvm.h,v $
* Revision 1.33 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.32 2000/03/13 00:02:34 steve
* Remove unneeded templates.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_bit.cc,v 1.8 2000/02/23 02:56:56 steve Exp $"
#ident "$Id: vvm_bit.cc,v 1.9 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm.h"
@ -88,14 +88,6 @@ unsigned vvm_bits_t::as_unsigned() const
return result;
}
vvm_ram_callback::vvm_ram_callback()
{
}
vvm_ram_callback::~vvm_ram_callback()
{
}
vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
{
unsigned li, ri, ci;
@ -142,6 +134,12 @@ vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
/*
* $Log: vvm_bit.cc,v $
* Revision 1.9 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.8 2000/02/23 02:56:56 steve
* Macintosh compilers do not support ident.
*
@ -153,25 +151,5 @@ vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry)
*
* Revision 1.5 1999/11/21 00:13:09 steve
* Support memories in continuous assignments.
*
* Revision 1.4 1999/11/01 02:07:41 steve
* Add the synth functor to do generic synthesis
* and add the LPM_FF device to handle rows of
* flip-flops.
*
* Revision 1.3 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.
*
* Revision 1.2 1998/11/10 00:48:31 steve
* Add support it vvm target for level-sensitive
* triggers (i.e. the Verilog wait).
* Fix display of $time is format strings.
*
* Revision 1.1 1998/11/09 23:44:10 steve
* Add vvm library.
*
*/

View File

@ -19,10 +19,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_func.h,v 1.21 2000/03/13 00:02:34 steve Exp $"
#ident "$Id: vvm_func.h,v 1.22 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_signal.h"
/*
* Implement the unary NOT operator in the verilog way. This takes a
@ -297,6 +298,12 @@ vvm_bitset_t<W> vvm_ternary(vpip_bit_t c, const vvm_bitset_t<W>&t,
/*
* $Log: vvm_func.h,v $
* Revision 1.22 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.21 2000/03/13 00:02:34 steve
* Remove unneeded templates.
*

View File

@ -23,12 +23,12 @@
* Picture Elements, Inc., 777 Panoramic Way, Berkeley, CA 94704.
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_gates.cc,v 1.6 2000/02/24 01:56:28 steve Exp $"
#ident "$Id: vvm_gates.cc,v 1.7 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm_gates.h"
vvm_out_event::vvm_out_event(vpip_bit_t v, action_t o)
vvm_out_event::vvm_out_event(vpip_bit_t v, vvm_nexus::drive_t*o)
: output_(o), val_(v)
{
}
@ -39,11 +39,11 @@ vvm_out_event::~vvm_out_event()
void vvm_out_event::event_function()
{
output_(val_);
output_->set_value(val_);
}
vvm_1bit_out::vvm_1bit_out(vvm_out_event::action_t o, unsigned d)
: output_(o), delay_(d)
vvm_1bit_out::vvm_1bit_out(unsigned d)
: delay_(d)
{
}
@ -53,7 +53,7 @@ vvm_1bit_out::~vvm_1bit_out()
void vvm_1bit_out::output(vpip_bit_t val)
{
vvm_event*ev = new vvm_out_event(val, output_);
vvm_event*ev = new vvm_out_event(val, this);
ev -> schedule(delay_);
}
@ -140,9 +140,50 @@ void compute_mux(vpip_bit_t*out, unsigned wid,
}
}
vvm_eeq::vvm_eeq(unsigned long d)
: vvm_1bit_out(d)
{
}
vvm_eeq::~vvm_eeq()
{
}
void vvm_eeq::init_I(unsigned idx, vpip_bit_t val)
{
input_[idx] = val;
}
void vvm_eeq::start()
{
output(compute_());
}
void vvm_eeq::take_value(unsigned key, vpip_bit_t val)
{
if (input_[key] == val)
return;
input_[key] = val;
output(compute_());
}
vpip_bit_t vvm_eeq::compute_() const
{
vpip_bit_t outval = V0;
if (input_[0] == input_[1])
outval = V1;
return outval;
}
/*
* $Log: vvm_gates.cc,v $
* Revision 1.7 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.6 2000/02/24 01:56:28 steve
* change not to v_not.
*

View File

@ -19,10 +19,11 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_gates.h,v 1.37 2000/02/23 04:43:43 steve Exp $"
#ident "$Id: vvm_gates.h,v 1.38 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_signal.h"
# include <assert.h>
extern vpip_bit_t compute_nand(const vpip_bit_t*inp, unsigned count);
@ -36,6 +37,8 @@ extern void compute_mux(vpip_bit_t*out, unsigned wid,
const vpip_bit_t*sel, unsigned swid,
const vpip_bit_t*dat, unsigned size);
/*
* A vvm gate is constructed with an input width and an output
* function. The input width represents all the input signals that go
@ -47,27 +50,26 @@ extern void compute_mux(vpip_bit_t*out, unsigned wid,
class vvm_out_event : public vvm_event {
public:
typedef void (*action_t)(vpip_bit_t);
typedef void (*action_t)(vpip_bit_t); // XXXX Remove me!
vvm_out_event(vpip_bit_t v, action_t o);
vvm_out_event(vpip_bit_t v, vvm_nexus::drive_t*o);
~vvm_out_event();
void event_function();
private:
const action_t output_;
vvm_nexus::drive_t*output_;
const vpip_bit_t val_;
};
class vvm_1bit_out {
class vvm_1bit_out : public vvm_nexus::drive_t {
public:
vvm_1bit_out(vvm_out_event::action_t, unsigned delay);
vvm_1bit_out(unsigned delay);
~vvm_1bit_out();
void output(vpip_bit_t);
private:
vvm_out_event::action_t output_;
unsigned delay_;
};
@ -78,21 +80,25 @@ class vvm_1bit_out {
* subtractor, the device works by adding the 2s complement of
* DataB.
*/
template <unsigned WIDTH> class vvm_add_sub {
template <unsigned WIDTH> class vvm_add_sub : public vvm_nexus::recvr_t {
public:
vvm_add_sub() : ndir_(V0), co_(0) { }
vvm_add_sub() : ndir_(V0) { }
void config_rout(unsigned idx, vvm_out_event::action_t a)
{ o_[idx] = a;
r_[idx] = Vx;
vvm_nexus::drive_t* config_rout(unsigned idx)
{ r_[idx] = Vx;
assert(idx < WIDTH);
return ro_+idx;
}
void config_cout(vvm_out_event::action_t a)
{ co_ = a;
c_ = Vx;
vvm_nexus::drive_t* config_cout()
{ c_ = Vx;
return &co_;
}
unsigned key_DataA(unsigned idx) const { return idx; }
unsigned key_DataB(unsigned idx) const { return idx|0x10000; }
void init_DataA(unsigned idx, vpip_bit_t val)
{ a_[idx] = val;
}
@ -116,6 +122,12 @@ template <unsigned WIDTH> class vvm_add_sub {
compute_();
}
private:
void take_value(unsigned key, vpip_bit_t val)
{ if (key&0x10000) set_DataB(key&0xffff, val);
else set_DataA(key&0xffff, val);
}
private:
vpip_bit_t a_[WIDTH];
vpip_bit_t b_[WIDTH];
@ -126,8 +138,8 @@ template <unsigned WIDTH> class vvm_add_sub {
// and 1 for subtract.
vpip_bit_t ndir_;
vvm_out_event::action_t o_[WIDTH];
vvm_out_event::action_t co_;
vvm_nexus::drive_t ro_[WIDTH];
vvm_nexus::drive_t co_;
void compute_()
{ vpip_bit_t carry = ndir_;
@ -136,21 +148,20 @@ template <unsigned WIDTH> class vvm_add_sub {
val = add_with_carry(a_[idx], b_[idx] ^ ndir_, carry);
if (val == r_[idx]) continue;
r_[idx] = val;
if (o_[idx] == 0) continue;
vvm_event*ev = new vvm_out_event(val, o_[idx]);
vvm_event*ev = new vvm_out_event(val, ro_+idx);
ev->schedule();
}
if (co_ && (carry != c_))
(new vvm_out_event(carry, co_)) -> schedule();
if (carry != c_)
(new vvm_out_event(carry, &co_)) -> schedule();
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_and : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_and : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_and(vvm_out_event::action_t o)
: vvm_1bit_out(o, DELAY) { }
explicit vvm_and(unsigned d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
@ -158,6 +169,9 @@ class vvm_and : private vvm_1bit_out {
void start()
{ output(compute_and(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
@ -495,12 +509,12 @@ template <unsigned WIDTH, unsigned SIZE, unsigned SELWID> class vvm_mux {
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_or : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_or : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_or(vvm_out_event::action_t o)
: vvm_1bit_out(o,DELAY) { }
explicit vvm_or(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
@ -508,6 +522,9 @@ class vvm_or : private vvm_1bit_out {
void start()
{ output(compute_or(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
@ -519,12 +536,12 @@ class vvm_or : private vvm_1bit_out {
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nor : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_nor : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_nor(vvm_out_event::action_t o)
: vvm_1bit_out(o, DELAY) { }
explicit vvm_nor(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
@ -532,6 +549,9 @@ class vvm_nor : private vvm_1bit_out {
void start()
{ output(compute_nor(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
@ -539,7 +559,6 @@ class vvm_nor : private vvm_1bit_out {
output(compute_nor(input_,WIDTH));
}
private:
vpip_bit_t input_[WIDTH];
};
@ -688,12 +707,12 @@ template <unsigned long DELAY> class vvm_bufif1 {
}
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_nand : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_nand : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_nand(vvm_out_event::action_t o)
: vvm_1bit_out(o, DELAY) { }
explicit vvm_nand(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
@ -701,6 +720,9 @@ class vvm_nand : private vvm_1bit_out {
void start()
{ output(compute_nand(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val) return;
input_[idx] = val;
@ -714,33 +736,39 @@ class vvm_nand : private vvm_1bit_out {
/*
* Simple inverter buffer.
*/
template <unsigned long DELAY> class vvm_not : private vvm_1bit_out {
class vvm_not : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_not(vvm_out_event::action_t o)
: vvm_1bit_out(o, DELAY) { }
explicit vvm_not(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned, vpip_bit_t) { }
void start() { }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned, vpip_bit_t val)
{ output(v_not(val)); }
private:
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xnor : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_xnor : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_xnor(vvm_out_event::action_t o)
: vvm_1bit_out(o,DELAY) { }
explicit vvm_xnor(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val) { input_[idx] = val; }
void start()
{ output(compute_xnor(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
@ -752,12 +780,12 @@ class vvm_xnor : private vvm_1bit_out {
vpip_bit_t input_[WIDTH];
};
template <unsigned WIDTH, unsigned long DELAY>
class vvm_xor : private vvm_1bit_out {
template <unsigned WIDTH>
class vvm_xor : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_xor(vvm_out_event::action_t o)
: vvm_1bit_out(o,DELAY) { }
explicit vvm_xor(unsigned long d)
: vvm_1bit_out(d) { }
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
@ -765,6 +793,9 @@ class vvm_xor : private vvm_1bit_out {
void start()
{ output(compute_xor(input_,WIDTH)); }
private:
void take_value(unsigned key, vpip_bit_t val) { set_I(key, val); }
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
@ -779,38 +810,22 @@ class vvm_xor : private vvm_1bit_out {
* This gate has only 3 pins, the output at pin 0 and two inputs. The
* output is 1 or 0 if the two inputs are exactly equal or not.
*/
template <unsigned long DELAY> class vvm_eeq {
class vvm_eeq : public vvm_1bit_out, public vvm_nexus::recvr_t {
public:
explicit vvm_eeq(vvm_out_event::action_t o)
: output_(o) { }
explicit vvm_eeq(unsigned long d);
~vvm_eeq();
void init_I(unsigned idx, vpip_bit_t val)
{ input_[idx] = val; }
void init_I(unsigned idx, vpip_bit_t val);
void start()
{ vvm_event*ev = new vvm_out_event(compute_(), output_);
ev->schedule(DELAY);
}
void set_I(unsigned idx, vpip_bit_t val)
{ if (input_[idx] == val)
return;
input_[idx] = val;
start();
}
void start();
private:
void take_value(unsigned key, vpip_bit_t val);
vpip_bit_t compute_() const
{ vpip_bit_t outval = V0;
if (input_[0] == input_[1])
outval = V1;
return outval;
}
vpip_bit_t compute_() const;
vpip_bit_t input_[2];
vvm_out_event::action_t output_;
};
/*
@ -916,7 +931,7 @@ class vvm_sync {
vvm_sync& operator= (const vvm_sync&);
};
template <unsigned WIDTH> class vvm_pevent {
template <unsigned WIDTH> class vvm_pevent : public vvm_nexus::recvr_t {
public:
enum EDGE { ANYEDGE, POSEDGE, NEGEDGE };
@ -928,6 +943,14 @@ template <unsigned WIDTH> class vvm_pevent {
vvm_bitset_t<WIDTH> get() const { return value_; }
void init_P(int idx, vpip_bit_t val)
{ assert(idx < WIDTH);
value_[idx] = val;
}
private:
void take_value(unsigned key, vpip_bit_t val) { set_P(key, val); }
void set_P(unsigned idx, vpip_bit_t val)
{ if (value_[idx] == val) return;
switch (edge_) {
@ -946,11 +969,6 @@ template <unsigned WIDTH> class vvm_pevent {
value_[idx] = val;
}
void init_P(int idx, vpip_bit_t val)
{ assert(idx < WIDTH);
value_[idx] = val;
}
private:
vvm_sync*target_;
vvm_bitset_t<WIDTH> value_;
@ -963,6 +981,12 @@ template <unsigned WIDTH> class vvm_pevent {
/*
* $Log: vvm_gates.h,v $
* Revision 1.38 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
* Revision 1.37 2000/02/23 04:43:43 steve
* Some compilers do not accept the not symbol.
*

235
vvm/vvm_nexus.cc Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (c) 2000 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
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_nexus.cc,v 1.1 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm_nexus.h"
# include <assert.h>
vvm_nexus::vvm_nexus()
{
drivers_ = 0;
recvrs_ = 0;
ival_ = 0;
nival_ = 0;
}
vvm_nexus::~vvm_nexus()
{
assert(drivers_ == 0);
/* assert(recvrs_ == 0); XXXX I really should make a point to
guarantee that all the receivers that I refer to are gone,
but since I know for now that this destructor is only
called when the simulation exist, nevermind. */
}
/*
* Connect a driver to this nexus. The driver needs to know who I am
* (and can only be connected to one nexus) and also I need to keep a
* list of all the drivers connected to me. Arranging the list
* pointers accordingly. Also, keep track of the number of drivers I
* have connected to me, and maintain the ival_ array so that I do not
* need to manage the array at run time.
*/
void vvm_nexus::connect(vvm_nexus::drive_t*drv)
{
// Link the driver into my list of drivers.
assert(drv->nexus_ == 0);
drv->nexus_ = this;
drv->next_ = drivers_;
drivers_ = drv;
nival_ += 1;
if (ival_) delete[]ival_;
ival_ = new vpip_bit_t[nival_];
}
/*
* Connect this receiver to me. Receivers are handled a little
* differently from drivers, a receiver is fully specified by the
* pointer to the receiver AS WELL AS a magic key value. This allows a
* gate to me a receiver with many different input pins.
*/
void vvm_nexus::connect(vvm_nexus::recvr_t*rcv, unsigned key)
{
recvr_cell*cur = new recvr_cell;
cur->dev = rcv;
cur->key = key;
cur->next = recvrs_;
recvrs_ = cur;
}
void vvm_nexus::disconnect(vvm_nexus::drive_t*drv)
{
drive_t*cur = drivers_;
drivers_ = 0;
while (cur) {
drive_t*tmp = cur;
cur = cur->next_;
if (tmp != drv) {
tmp->next_ = drivers_;
drivers_ = tmp;
}
}
}
/*
* This method disconnects a receiver completely by removing every
* access to it. (Remember that a recvr_t object may be connected many
* times with different keys.)
*/
void vvm_nexus::disconnect(vvm_nexus::recvr_t*rcv)
{
recvr_cell*cur = recvrs_;
recvrs_ = 0;
while (cur) {
recvr_cell*tmp = cur;
cur = tmp->next;
if (tmp->dev == rcv) {
delete tmp;
} else {
tmp->next = recvrs_;
recvrs_ = tmp;
}
}
}
/*
* Reg assign (or procedural assignment) does not use the concept of
* drivers. Instead, I skip the resolution function, save the value
* for myself and pass the value to the receivers.
*/
void vvm_nexus::reg_assign(vpip_bit_t val)
{
assert(drivers_ == 0);
value_ = val;
for (recvr_cell*cur = recvrs_; cur ; cur = cur->next)
cur->dev->take_value(cur->key, value_);
}
/*
* This method is invoked when something interesting happens at one of
* the drivers. It collects all the driver values, resolves them into
* a signal value, and passed them to all the connected
* receivers. This is the workhorse of the nexus object.
*/
void vvm_nexus::run_values()
{
/* Collect the values from all the signal drivers. We should
have exactly the right size ival_ array for the number of
drives. */
unsigned idx = 0;
for (drive_t*cur = drivers_; cur ; cur = cur->next_) {
assert(idx < nival_);
ival_[idx++] = cur->peek_value();
}
assert(idx == nival_);
/* Use the resolution function to generate the settled value
for this nexus. */
vpip_bit_t val = resolution_function(ival_, nival_);
if (value_ == val) return;
value_ = val;
/* Now deliver that output value to all the receivers
connected to this nexus. */
for (recvr_cell*cur = recvrs_; cur ; cur = cur->next)
cur->dev->take_value(cur->key, value_);
}
vvm_nexus::drive_t::drive_t()
{
nexus_ = 0;
}
vvm_nexus::drive_t::~drive_t()
{
if (nexus_) nexus_->disconnect(this);
}
vpip_bit_t vvm_nexus::drive_t::peek_value() const
{
return value_;
}
void vvm_nexus::drive_t::set_value(vpip_bit_t val)
{
if (val == value_) return;
value_ = val;
if (nexus_) nexus_->run_values();
}
vvm_nexus::recvr_t::recvr_t()
{
}
vvm_nexus::recvr_t::~recvr_t()
{
}
vvm_nexus_wire::vvm_nexus_wire()
{
}
vvm_nexus_wire::~vvm_nexus_wire()
{
}
vpip_bit_t vvm_nexus_wire::resolution_function(const vpip_bit_t*bits,
unsigned nbits) const
{
if (nbits == 0) return Vz;
return bits[0];
}
class delayed_assign_event : public vvm_event {
public:
delayed_assign_event(vvm_nexus&l, vpip_bit_t r)
: l_val_(l), r_val_(r) { }
void event_function() { l_val_.reg_assign(r_val_); }
private:
vvm_nexus& l_val_;
vpip_bit_t r_val_;
};
void vvm_delayed_assign(vvm_nexus&l_val, vpip_bit_t r_val,
unsigned long delay)
{
delayed_assign_event*ev = new delayed_assign_event(l_val, r_val);
ev->schedule(delay);
}
/*
* $Log: vvm_nexus.cc,v $
* Revision 1.1 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
*/

154
vvm/vvm_nexus.h Normal file
View File

@ -0,0 +1,154 @@
#ifndef __vvm_vvm_nexus_H
#define __vvm_vvm_nexus_H
/*
* Copyright (c) 2000 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
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_nexus.h,v 1.1 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm.h"
/*
* The nexus class represents a connection point for drivers and
* receivers of signals. The signal carries a single bit, has drivers,
* has fan_out and has a current value. Classes derive from the nexus
* in order to provide specific kinds of N-driver resolution.
*
* The driver_t and recvr_t classes are the means to connect to a
* nexus. In general, other then to connect the drivers and receivers,
* there should be no cause to manipulate the nexus object directly.
*
* The driver_t class represents a driver on the nexus. There can be
* any number of drivers on a nexus, so long as the
* recolution_function can handle the situation. The drivers are
* normally members of some gate object somewhere. When the driver
* receives a value, it saves the value in itself and tells the
* connected nexus that something has changed.
*
* The nexus object, when it notices that one of its drivers changed,
* collects the values of the drivers and passes the set to the
* resolution function. The resolution function calculates what the
* value of the nexus should be given the values driving it.
*
* When the value of the nexus is ready, it scans the list of
* connected receivers and passes the new value out. The receiver is
* actually a pointer to the recvr_t object and a key. This is so the
* receiver object can receive many different pins worth of data. The
* idea is that a gate can be a single recvr_t object, and the key can
* be used and the number of the affected pin.
*/
class vvm_nexus {
public:
class drive_t {
friend class ::vvm_nexus;
public:
drive_t();
~drive_t();
vpip_bit_t peek_value() const;
void set_value(vpip_bit_t);
private:
vpip_bit_t value_;
vvm_nexus*nexus_;
drive_t*next_;
private: // not implemented
drive_t(const drive_t&);
drive_t& operator= (const drive_t&);
};
class recvr_t {
friend class ::vvm_nexus;
public:
recvr_t();
virtual ~recvr_t() =0;
virtual void take_value(unsigned key, vpip_bit_t val) =0;
private: // not implemented
recvr_t(const recvr_t&);
recvr_t& operator= (const recvr_t&);
};
public:
vvm_nexus();
virtual ~vvm_nexus() =0;
// These methods support connecting the receiver and driver to
// the nexus.
void connect(drive_t*drv);
void connect(recvr_t*rcv, unsigned key);
void disconnect(drive_t*drv);
void disconnect(recvr_t*rcv);
// If there are no drivers to this nexus, this can be used to
// to procedural assignments to the node, as if it where a reg.
void reg_assign(vpip_bit_t val);
// The run_values() method collects all the current driver
// values and, with the aid of the resolution_function,
// generates the current value for the nexus. It also passes
// that value on to the receuvers.
void run_values();
virtual vpip_bit_t resolution_function(const vpip_bit_t*, unsigned) const =0;
private:
vpip_bit_t value_;
drive_t*drivers_;
struct recvr_cell {
recvr_t *dev;
unsigned key;
recvr_cell*next;
} *recvrs_;
vpip_bit_t*ival_;
unsigned nival_;
private: // not implemented
vvm_nexus(const vvm_nexus&);
vvm_nexus& operator= (const vvm_nexus&);
};
class vvm_nexus_wire : public vvm_nexus {
public:
vvm_nexus_wire();
~vvm_nexus_wire();
vpip_bit_t resolution_function(const vpip_bit_t*, unsigned) const;
};
/*
* This function arranges for a non-blocking reg_assign to a nexus. It
* creates all the events needed to make it happen after the specified
* delay.
*/
void vvm_delayed_assign(vvm_nexus&l_val, vpip_bit_t r_val,
unsigned long delay);
/*
* $Log: vvm_nexus.h,v $
* Revision 1.1 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
*/
#endif

42
vvm/vvm_signal.cc Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2000 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
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_signal.cc,v 1.1 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm_signal.h"
vvm_ram_callback::vvm_ram_callback()
{
}
vvm_ram_callback::~vvm_ram_callback()
{
}
/*
* $Log: vvm_signal.cc,v $
* Revision 1.1 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
*/

173
vvm/vvm_signal.h Normal file
View File

@ -0,0 +1,173 @@
#ifndef __vvm_vvm_signal_H
#define __vvm_vvm_signal_H
/*
* Copyright (c) 2000 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
*/
#if !defined(WINNT) && !defined(macintosh)
#ident "$Id: vvm_signal.h,v 1.1 2000/03/16 19:03:04 steve Exp $"
#endif
# include "vvm.h"
# include "vvm_nexus.h"
/*
* The vvm_bitset_t is a fixed width array-like set of vpip_bit_t
* items. A number is often times made up of bit sets instead of
* single bits. The fixed array is used when possible because of the
* more thorough type checking and (hopefully) better optimization.
*/
template <unsigned WIDTH> class vvm_bitset_t : public vvm_bits_t {
public:
vvm_bitset_t()
{ for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[idx] = Vz;
}
vvm_bitset_t(const vvm_bits_t&that)
{ unsigned wid = WIDTH;
if (that.get_width() < WIDTH)
wid = that.get_width();
for (unsigned idx = 0 ; idx < wid ; idx += 1)
bits[idx] = that.get_bit(idx);
for (unsigned idx = wid ; idx < WIDTH ; idx += 1)
bits[idx] = V0;
}
vvm_bitset_t(const vvm_bitset_t<WIDTH>&that)
{ for (unsigned idx = 0; idx < WIDTH; idx += 1)
bits[idx] = that.bits[idx];
}
vpip_bit_t operator[] (unsigned idx) const { return bits[idx]; }
vpip_bit_t&operator[] (unsigned idx) { return bits[idx]; }
unsigned get_width() const { return WIDTH; }
vpip_bit_t get_bit(unsigned idx) const { return bits[idx]; }
public:
vpip_bit_t bits[WIDTH];
};
/*
* The vvm_signal_t template is the real object that handles the
* receiving of assignments and doing whatever is done. It also
* connects VPI to the C++/vvm design.
*/
template <unsigned WIDTH>
class vvm_signal_t : public __vpiSignal, public vvm_nexus::recvr_t {
public:
vvm_signal_t(vvm_bitset_t<WIDTH>*b)
{ bits = b->bits;
nbits = WIDTH;
}
~vvm_signal_t() { }
void init_P(unsigned idx, vpip_bit_t val)
{ bits[idx] = val; }
void set_P(unsigned idx, vpip_bit_t val)
{ bits[idx] = val;
vpip_run_value_changes(this);
}
void take_value(unsigned key, vpip_bit_t val) { set_P(key, val); }
};
struct vvm_ram_callback {
vvm_ram_callback();
virtual ~vvm_ram_callback();
virtual void handle_write(unsigned idx) =0;
vvm_ram_callback*next_;
};
template <unsigned WIDTH, unsigned SIZE>
class vvm_memory_t : public __vpiMemory {
public:
vvm_memory_t()
{ cb_list_ = 0;
}
void set_word(unsigned addr,
const vvm_bitset_t<WIDTH>&val)
{ unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(addr);
}
void set_word(unsigned addr,
const vpip_bit_t val[WIDTH])
{ unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
bits[base+idx] = val[idx];
call_list_(addr);
}
vvm_bitset_t<WIDTH> get_word(unsigned addr) const
{ vvm_bitset_t<WIDTH> val;
unsigned base = WIDTH * addr;
assert(addr < size);
for (unsigned idx = 0 ; idx < WIDTH ; idx += 1)
val[idx] = bits[base+idx];
return val;
}
void set_callback(vvm_ram_callback*ram)
{ ram->next_ = cb_list_;
cb_list_ = ram;
}
class assign_nb : public vvm_event {
public:
assign_nb(vvm_memory_t<WIDTH,SIZE>&m, unsigned i,
const vvm_bitset_t<WIDTH>&v)
: mem_(m), index_(i), val_(v) { }
void event_function() { mem_.set_word(index_, val_); }
private:
vvm_memory_t<WIDTH,SIZE>&mem_;
unsigned index_;
vvm_bitset_t<WIDTH> val_;
};
private:
vvm_ram_callback*cb_list_;
void call_list_(unsigned idx)
{ for (vvm_ram_callback*cur = cb_list_; cur; cur = cur->next_)
cur->handle_write(idx);
}
};
/*
* $Log: vvm_signal.h,v $
* Revision 1.1 2000/03/16 19:03:04 steve
* Revise the VVM backend to use nexus objects so that
* drivers and resolution functions can be used, and
* the t-vvm module doesn't need to write a zillion
* output functions.
*
*/
#endif