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:
parent
2e05f7f7ec
commit
2563e2b717
|
|
@ -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 \
|
||||
|
|
|
|||
25
elab_net.cc
25
elab_net.cc
|
|
@ -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
|
||||
|
|
|
|||
17
netmisc.h
17
netmisc.h
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
178
t-vvm.cc
|
|
@ -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
49
vvm.txt
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
147
vvm/vvm.h
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
180
vvm/vvm_gates.h
180
vvm/vvm_gates.h
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue